@nexbasira/react
v0.1.1
Published
React component + hook wrapping the NexBasira embed widget.
Maintainers
Readme
@nexbasira/react
React component + hook wrapping the @nexbasira/embed browser widget.
Thin by design — the iframe and postMessage plumbing live in @nexbasira/embed; this package just makes the widget feel native to a React app (mount, unmount, ref-based imperative access, fresh-closure callbacks).
Install
npm install @nexbasira/react @nexbasira/embed reactreact and @nexbasira/embed are peer dependencies — they aren't bundled.
Quick start (component)
import { NexBasiraSession } from "@nexbasira/react";
function InspectionPage({ joinUrl }: { joinUrl: string }) {
return (
<NexBasiraSession
sessionUrl={joinUrl}
height="720px"
onSessionComplete={(id) => {
console.log("inspection done:", id);
}}
/>
);
}sessionUrl is the field-join URL your backend mints via POST /v1/public/sessions/{id}/invites (or the SPA equivalent). Never embed an API secret in the URL.
Imperative control (ref)
import { useRef } from "react";
import { NexBasiraSession, type NexBasiraSessionHandle } from "@nexbasira/react";
function ToolbarHost({ joinUrl }: { joinUrl: string }) {
const session = useRef<NexBasiraSessionHandle>(null);
return (
<>
<button onClick={() => session.current?.requestSnapshot()}>
Capture
</button>
<NexBasiraSession ref={session} sessionUrl={joinUrl} />
</>
);
}Methods on the handle:
requestSnapshot()openWhiteboard()/closeWhiteboard()switchCamera()mute()/unmute()endSession()
Hook variant
Use this when <NexBasiraSession>'s wrapper <div> doesn't fit your layout, or when you want to share the widget handle across multiple components without prop-drilling refs.
import { useNexBasiraSession } from "@nexbasira/react";
function CustomLayout({ joinUrl }: { joinUrl: string }) {
const [containerRef, widget] = useNexBasiraSession({
sessionUrl: joinUrl,
onSessionComplete: (id) => navigate(`/inspections/${id}`),
});
return (
<div className="my-layout">
<header>
<button onClick={() => widget.current?.requestSnapshot()}>
Snap
</button>
</header>
<div ref={containerRef} style={{ flex: 1 }} />
</div>
);
}Lifecycle callbacks
Every callback supported by @nexbasira/embed is passed through unchanged:
| Prop | Fires when |
|---|---|
| onReady | The iframe finished loading + handshake completed. |
| onSessionJoined(id) | The field user joined the session. |
| onSessionComplete(id) | The session was closed (final state, recording paths queued). |
| onEvidenceAdded(ev) | A new evidence row was created (snapshot, whiteboard, etc.). |
| onWhiteboardOpened / onWhiteboardSaved(ev) | Whiteboard lifecycle. |
| onParticipantJoined(p) / onParticipantLeft(p) | Participant changes. |
| onError({message, code}) | Anything the iframe surfaces as an error. |
Callbacks are always re-read from the latest props on every re-render — closing over fresh state in your handlers works without remounting the iframe.
When the iframe rebuilds
The iframe is re-created only when sessionUrl changes. Every other prop (callbacks, width, height, expectedOrigin) is applied without remounting, so toolbars and overlays stay continuous through a session.
TypeScript
NexBasiraSessionProps, NexBasiraSessionHandle, EmbedOptions, and EmbedWidget are all exported. The component is a forwardRef, so useRef<NexBasiraSessionHandle>() gives you typed handle access.
License
MIT
