@navai/voice-frontend 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { RealtimeAgent } from '@openai/agents/realtime';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { CSSProperties, ReactNode } from 'react';
2
4
 
3
5
  type NavaiFunctionPayload = Record<string, unknown>;
4
6
  type NavaiFunctionContext = {
@@ -130,4 +132,102 @@ type UseWebVoiceAgentResult = {
130
132
  };
131
133
  declare function useWebVoiceAgent(options: UseWebVoiceAgentOptions): UseWebVoiceAgentResult;
132
134
 
133
- export { type BuildNavaiAgentOptions, type BuildNavaiAgentResult, type CreateNavaiBackendClientOptions, type ExecuteNavaiBackendFunction, type ExecuteNavaiBackendFunctionInput, type NavaiBackendClient, type NavaiBackendFunctionDefinition, type NavaiFunctionContext, type NavaiFunctionDefinition, type NavaiFunctionModuleLoaders, type NavaiFunctionPayload, type NavaiFunctionsRegistry, type NavaiRoute, type ResolveNavaiFrontendRuntimeConfigOptions, type ResolveNavaiFrontendRuntimeConfigResult, type UseWebVoiceAgentOptions, type UseWebVoiceAgentResult, buildNavaiAgent, createNavaiBackendClient, getNavaiRoutePromptLines, loadNavaiFunctions, resolveNavaiFrontendRuntimeConfig, resolveNavaiRoute, useWebVoiceAgent };
135
+ type OrbProps = {
136
+ hue?: number;
137
+ autoHueShift?: boolean;
138
+ hueShiftMin?: number;
139
+ hueShiftMax?: number;
140
+ hueShiftHalfCycleSeconds?: number;
141
+ hoverIntensity?: number;
142
+ rotateOnHover?: boolean;
143
+ forceHoverState?: boolean;
144
+ enablePointerHover?: boolean;
145
+ backgroundColor?: string;
146
+ animate?: boolean;
147
+ };
148
+ declare function Orb({ hue, autoHueShift, hueShiftMin, hueShiftMax, hueShiftHalfCycleSeconds, hoverIntensity, rotateOnHover, forceHoverState, enablePointerHover, backgroundColor, animate }: OrbProps): react_jsx_runtime.JSX.Element;
149
+
150
+ type NavaiHeroOrbProps = {
151
+ className?: string;
152
+ backgroundColor?: string;
153
+ isAgentSpeaking?: boolean;
154
+ hoverIntensitySpeaking?: number;
155
+ hoverIntensityIdle?: number;
156
+ revealDelayMs?: number;
157
+ autoplayDelayMs?: number;
158
+ };
159
+ declare function clampNavaiOrbDelayMs(value: number, fallback: number): number;
160
+ declare function NavaiHeroOrb({ className, backgroundColor, isAgentSpeaking, hoverIntensitySpeaking, hoverIntensityIdle, revealDelayMs, autoplayDelayMs }: NavaiHeroOrbProps): react_jsx_runtime.JSX.Element | null;
161
+
162
+ type NavaiVoiceOrbThemeMode = "light" | "dark";
163
+ type NavaiVoiceOrbPlacement = "inline" | "bottom-right" | "bottom-left";
164
+ type NavaiWebVoiceAgentLike = Pick<UseWebVoiceAgentResult, "status" | "agentVoiceState" | "error" | "isConnecting" | "isConnected" | "isAgentSpeaking" | "start" | "stop">;
165
+ type NavaiVoiceOrbMessages = {
166
+ ariaStart: string;
167
+ ariaStop: string;
168
+ idle: string;
169
+ connecting: string;
170
+ listening: string;
171
+ speaking: string;
172
+ errorPrefix: string;
173
+ };
174
+ type NavaiVoiceOrbRuntimeSnapshot = {
175
+ status: UseWebVoiceAgentResult["status"];
176
+ agentVoiceState: UseWebVoiceAgentResult["agentVoiceState"];
177
+ isAgentSpeaking: boolean;
178
+ error: string | null;
179
+ };
180
+ type NavaiVoiceOrbBaseProps = {
181
+ className?: string;
182
+ style?: CSSProperties;
183
+ themeMode?: NavaiVoiceOrbThemeMode;
184
+ placement?: NavaiVoiceOrbPlacement;
185
+ backgroundColorLight?: string;
186
+ backgroundColorDark?: string;
187
+ showStatus?: boolean;
188
+ };
189
+
190
+ type NavaiMiniOrbDockProps = {
191
+ className?: string;
192
+ style?: CSSProperties;
193
+ themeMode?: NavaiVoiceOrbThemeMode;
194
+ placement?: NavaiVoiceOrbPlacement;
195
+ isActive?: boolean;
196
+ isConnected?: boolean;
197
+ isDisabled?: boolean;
198
+ isAgentSpeaking?: boolean;
199
+ animateOrb?: boolean;
200
+ backgroundColor?: string;
201
+ buttonAriaLabel: string;
202
+ buttonIcon?: ReactNode;
203
+ buttonType?: "button" | "submit" | "reset";
204
+ onButtonClick?: () => void;
205
+ statusMessage?: string;
206
+ isError?: boolean;
207
+ ariaMessage?: string;
208
+ };
209
+ declare function NavaiMiniOrbDock({ className, style, themeMode, placement, isActive, isConnected, isDisabled, isAgentSpeaking, animateOrb, backgroundColor, buttonAriaLabel, buttonIcon, buttonType, onButtonClick, statusMessage, isError, ariaMessage }: NavaiMiniOrbDockProps): react_jsx_runtime.JSX.Element;
210
+
211
+ type NavaiVoiceHeroOrbProps = Omit<NavaiHeroOrbProps, "backgroundColor" | "isAgentSpeaking"> & {
212
+ agent: NavaiWebVoiceAgentLike;
213
+ themeMode?: NavaiVoiceOrbThemeMode;
214
+ backgroundColorLight?: string;
215
+ backgroundColorDark?: string;
216
+ onRuntimeSnapshotChange?: (snapshot: NavaiVoiceOrbRuntimeSnapshot) => void;
217
+ };
218
+ declare function NavaiVoiceHeroOrb({ agent, themeMode, backgroundColorLight, backgroundColorDark, onRuntimeSnapshotChange, ...orbProps }: NavaiVoiceHeroOrbProps): react_jsx_runtime.JSX.Element;
219
+
220
+ declare function resolveNavaiVoiceOrbRuntimeSnapshot(agent: Pick<UseWebVoiceAgentResult, "status" | "agentVoiceState" | "isAgentSpeaking" | "error">): NavaiVoiceOrbRuntimeSnapshot;
221
+ type NavaiVoiceOrbDockProps = NavaiVoiceOrbBaseProps & {
222
+ agent: NavaiWebVoiceAgentLike;
223
+ messages?: Partial<NavaiVoiceOrbMessages>;
224
+ };
225
+ declare function NavaiVoiceOrbDock({ agent, className, style, themeMode, placement, backgroundColorLight, backgroundColorDark, showStatus, messages }: NavaiVoiceOrbDockProps): react_jsx_runtime.JSX.Element;
226
+
227
+ type NavaiVoiceOrbDockMicIconProps = {
228
+ isActive?: boolean;
229
+ size?: number;
230
+ };
231
+ declare function NavaiVoiceOrbDockMicIcon({ isActive, size }: NavaiVoiceOrbDockMicIconProps): react_jsx_runtime.JSX.Element;
232
+
233
+ export { type BuildNavaiAgentOptions, type BuildNavaiAgentResult, type CreateNavaiBackendClientOptions, type ExecuteNavaiBackendFunction, type ExecuteNavaiBackendFunctionInput, type NavaiBackendClient, type NavaiBackendFunctionDefinition, type NavaiFunctionContext, type NavaiFunctionDefinition, type NavaiFunctionModuleLoaders, type NavaiFunctionPayload, type NavaiFunctionsRegistry, NavaiHeroOrb, type NavaiHeroOrbProps, NavaiMiniOrbDock, type NavaiMiniOrbDockProps, type NavaiRoute, NavaiVoiceHeroOrb, type NavaiVoiceHeroOrbProps, type NavaiVoiceOrbBaseProps, NavaiVoiceOrbDock, NavaiVoiceOrbDockMicIcon, type NavaiVoiceOrbDockProps, type NavaiVoiceOrbMessages, type NavaiVoiceOrbPlacement, type NavaiVoiceOrbRuntimeSnapshot, type NavaiVoiceOrbThemeMode, type NavaiWebVoiceAgentLike, Orb, type OrbProps, type ResolveNavaiFrontendRuntimeConfigOptions, type ResolveNavaiFrontendRuntimeConfigResult, type UseWebVoiceAgentOptions, type UseWebVoiceAgentResult, buildNavaiAgent, clampNavaiOrbDelayMs, createNavaiBackendClient, getNavaiRoutePromptLines, loadNavaiFunctions, resolveNavaiFrontendRuntimeConfig, resolveNavaiRoute, resolveNavaiVoiceOrbRuntimeSnapshot, useWebVoiceAgent };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { RealtimeAgent } from '@openai/agents/realtime';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { CSSProperties, ReactNode } from 'react';
2
4
 
3
5
  type NavaiFunctionPayload = Record<string, unknown>;
4
6
  type NavaiFunctionContext = {
@@ -130,4 +132,102 @@ type UseWebVoiceAgentResult = {
130
132
  };
131
133
  declare function useWebVoiceAgent(options: UseWebVoiceAgentOptions): UseWebVoiceAgentResult;
132
134
 
133
- export { type BuildNavaiAgentOptions, type BuildNavaiAgentResult, type CreateNavaiBackendClientOptions, type ExecuteNavaiBackendFunction, type ExecuteNavaiBackendFunctionInput, type NavaiBackendClient, type NavaiBackendFunctionDefinition, type NavaiFunctionContext, type NavaiFunctionDefinition, type NavaiFunctionModuleLoaders, type NavaiFunctionPayload, type NavaiFunctionsRegistry, type NavaiRoute, type ResolveNavaiFrontendRuntimeConfigOptions, type ResolveNavaiFrontendRuntimeConfigResult, type UseWebVoiceAgentOptions, type UseWebVoiceAgentResult, buildNavaiAgent, createNavaiBackendClient, getNavaiRoutePromptLines, loadNavaiFunctions, resolveNavaiFrontendRuntimeConfig, resolveNavaiRoute, useWebVoiceAgent };
135
+ type OrbProps = {
136
+ hue?: number;
137
+ autoHueShift?: boolean;
138
+ hueShiftMin?: number;
139
+ hueShiftMax?: number;
140
+ hueShiftHalfCycleSeconds?: number;
141
+ hoverIntensity?: number;
142
+ rotateOnHover?: boolean;
143
+ forceHoverState?: boolean;
144
+ enablePointerHover?: boolean;
145
+ backgroundColor?: string;
146
+ animate?: boolean;
147
+ };
148
+ declare function Orb({ hue, autoHueShift, hueShiftMin, hueShiftMax, hueShiftHalfCycleSeconds, hoverIntensity, rotateOnHover, forceHoverState, enablePointerHover, backgroundColor, animate }: OrbProps): react_jsx_runtime.JSX.Element;
149
+
150
+ type NavaiHeroOrbProps = {
151
+ className?: string;
152
+ backgroundColor?: string;
153
+ isAgentSpeaking?: boolean;
154
+ hoverIntensitySpeaking?: number;
155
+ hoverIntensityIdle?: number;
156
+ revealDelayMs?: number;
157
+ autoplayDelayMs?: number;
158
+ };
159
+ declare function clampNavaiOrbDelayMs(value: number, fallback: number): number;
160
+ declare function NavaiHeroOrb({ className, backgroundColor, isAgentSpeaking, hoverIntensitySpeaking, hoverIntensityIdle, revealDelayMs, autoplayDelayMs }: NavaiHeroOrbProps): react_jsx_runtime.JSX.Element | null;
161
+
162
+ type NavaiVoiceOrbThemeMode = "light" | "dark";
163
+ type NavaiVoiceOrbPlacement = "inline" | "bottom-right" | "bottom-left";
164
+ type NavaiWebVoiceAgentLike = Pick<UseWebVoiceAgentResult, "status" | "agentVoiceState" | "error" | "isConnecting" | "isConnected" | "isAgentSpeaking" | "start" | "stop">;
165
+ type NavaiVoiceOrbMessages = {
166
+ ariaStart: string;
167
+ ariaStop: string;
168
+ idle: string;
169
+ connecting: string;
170
+ listening: string;
171
+ speaking: string;
172
+ errorPrefix: string;
173
+ };
174
+ type NavaiVoiceOrbRuntimeSnapshot = {
175
+ status: UseWebVoiceAgentResult["status"];
176
+ agentVoiceState: UseWebVoiceAgentResult["agentVoiceState"];
177
+ isAgentSpeaking: boolean;
178
+ error: string | null;
179
+ };
180
+ type NavaiVoiceOrbBaseProps = {
181
+ className?: string;
182
+ style?: CSSProperties;
183
+ themeMode?: NavaiVoiceOrbThemeMode;
184
+ placement?: NavaiVoiceOrbPlacement;
185
+ backgroundColorLight?: string;
186
+ backgroundColorDark?: string;
187
+ showStatus?: boolean;
188
+ };
189
+
190
+ type NavaiMiniOrbDockProps = {
191
+ className?: string;
192
+ style?: CSSProperties;
193
+ themeMode?: NavaiVoiceOrbThemeMode;
194
+ placement?: NavaiVoiceOrbPlacement;
195
+ isActive?: boolean;
196
+ isConnected?: boolean;
197
+ isDisabled?: boolean;
198
+ isAgentSpeaking?: boolean;
199
+ animateOrb?: boolean;
200
+ backgroundColor?: string;
201
+ buttonAriaLabel: string;
202
+ buttonIcon?: ReactNode;
203
+ buttonType?: "button" | "submit" | "reset";
204
+ onButtonClick?: () => void;
205
+ statusMessage?: string;
206
+ isError?: boolean;
207
+ ariaMessage?: string;
208
+ };
209
+ declare function NavaiMiniOrbDock({ className, style, themeMode, placement, isActive, isConnected, isDisabled, isAgentSpeaking, animateOrb, backgroundColor, buttonAriaLabel, buttonIcon, buttonType, onButtonClick, statusMessage, isError, ariaMessage }: NavaiMiniOrbDockProps): react_jsx_runtime.JSX.Element;
210
+
211
+ type NavaiVoiceHeroOrbProps = Omit<NavaiHeroOrbProps, "backgroundColor" | "isAgentSpeaking"> & {
212
+ agent: NavaiWebVoiceAgentLike;
213
+ themeMode?: NavaiVoiceOrbThemeMode;
214
+ backgroundColorLight?: string;
215
+ backgroundColorDark?: string;
216
+ onRuntimeSnapshotChange?: (snapshot: NavaiVoiceOrbRuntimeSnapshot) => void;
217
+ };
218
+ declare function NavaiVoiceHeroOrb({ agent, themeMode, backgroundColorLight, backgroundColorDark, onRuntimeSnapshotChange, ...orbProps }: NavaiVoiceHeroOrbProps): react_jsx_runtime.JSX.Element;
219
+
220
+ declare function resolveNavaiVoiceOrbRuntimeSnapshot(agent: Pick<UseWebVoiceAgentResult, "status" | "agentVoiceState" | "isAgentSpeaking" | "error">): NavaiVoiceOrbRuntimeSnapshot;
221
+ type NavaiVoiceOrbDockProps = NavaiVoiceOrbBaseProps & {
222
+ agent: NavaiWebVoiceAgentLike;
223
+ messages?: Partial<NavaiVoiceOrbMessages>;
224
+ };
225
+ declare function NavaiVoiceOrbDock({ agent, className, style, themeMode, placement, backgroundColorLight, backgroundColorDark, showStatus, messages }: NavaiVoiceOrbDockProps): react_jsx_runtime.JSX.Element;
226
+
227
+ type NavaiVoiceOrbDockMicIconProps = {
228
+ isActive?: boolean;
229
+ size?: number;
230
+ };
231
+ declare function NavaiVoiceOrbDockMicIcon({ isActive, size }: NavaiVoiceOrbDockMicIconProps): react_jsx_runtime.JSX.Element;
232
+
233
+ export { type BuildNavaiAgentOptions, type BuildNavaiAgentResult, type CreateNavaiBackendClientOptions, type ExecuteNavaiBackendFunction, type ExecuteNavaiBackendFunctionInput, type NavaiBackendClient, type NavaiBackendFunctionDefinition, type NavaiFunctionContext, type NavaiFunctionDefinition, type NavaiFunctionModuleLoaders, type NavaiFunctionPayload, type NavaiFunctionsRegistry, NavaiHeroOrb, type NavaiHeroOrbProps, NavaiMiniOrbDock, type NavaiMiniOrbDockProps, type NavaiRoute, NavaiVoiceHeroOrb, type NavaiVoiceHeroOrbProps, type NavaiVoiceOrbBaseProps, NavaiVoiceOrbDock, NavaiVoiceOrbDockMicIcon, type NavaiVoiceOrbDockProps, type NavaiVoiceOrbMessages, type NavaiVoiceOrbPlacement, type NavaiVoiceOrbRuntimeSnapshot, type NavaiVoiceOrbThemeMode, type NavaiWebVoiceAgentLike, Orb, type OrbProps, type ResolveNavaiFrontendRuntimeConfigOptions, type ResolveNavaiFrontendRuntimeConfigResult, type UseWebVoiceAgentOptions, type UseWebVoiceAgentResult, buildNavaiAgent, clampNavaiOrbDelayMs, createNavaiBackendClient, getNavaiRoutePromptLines, loadNavaiFunctions, resolveNavaiFrontendRuntimeConfig, resolveNavaiRoute, resolveNavaiVoiceOrbRuntimeSnapshot, useWebVoiceAgent };
package/dist/index.js CHANGED
@@ -1,3 +1,8 @@
1
+ import {
2
+ Orb,
3
+ useNavaiVoiceOrbStyles
4
+ } from "./chunk-KBBRQQLK.js";
5
+
1
6
  // src/agent.ts
2
7
  import { RealtimeAgent, tool } from "@openai/agents/realtime";
3
8
  import { z } from "zod";
@@ -880,12 +885,361 @@ function useWebVoiceAgent(options) {
880
885
  stop
881
886
  };
882
887
  }
888
+
889
+ // src/orb/NavaiHeroOrb.tsx
890
+ import { useEffect as useEffect3, useMemo as useMemo2, useState as useState3 } from "react";
891
+
892
+ // src/orb/dynamic.tsx
893
+ import { lazy, Suspense, useEffect as useEffect2, useState as useState2 } from "react";
894
+ import { jsx } from "react/jsx-runtime";
895
+ function dynamic(loader, options = {}) {
896
+ const { ssr = true, loading: LoadingComponent } = options;
897
+ const LazyComponent = lazy(async () => {
898
+ const loaded = await loader();
899
+ if (typeof loaded === "function") {
900
+ return { default: loaded };
901
+ }
902
+ return loaded;
903
+ });
904
+ function DynamicComponent(props) {
905
+ const [isClientReady, setIsClientReady] = useState2(ssr);
906
+ useEffect2(() => {
907
+ if (!ssr) {
908
+ setIsClientReady(true);
909
+ }
910
+ }, [ssr]);
911
+ if (!isClientReady) {
912
+ return null;
913
+ }
914
+ const fallback = LoadingComponent ? /* @__PURE__ */ jsx(LoadingComponent, {}) : null;
915
+ return /* @__PURE__ */ jsx(Suspense, { fallback, children: /* @__PURE__ */ jsx(LazyComponent, { ...props }) });
916
+ }
917
+ DynamicComponent.displayName = "DynamicComponent";
918
+ return DynamicComponent;
919
+ }
920
+
921
+ // src/orb/NavaiHeroOrb.tsx
922
+ import { jsx as jsx2 } from "react/jsx-runtime";
923
+ var Orb2 = dynamic(() => import("./Orb-B4OSC3XR.js"), {
924
+ ssr: false
925
+ });
926
+ var ORB_DELAY_MS_MIN = 0;
927
+ var ORB_DELAY_MS_MAX = 6e4;
928
+ var DEFAULT_AUTOPLAY_DELAY_MS = 9e3;
929
+ var DEFAULT_REVEAL_DELAY_MS = 5200;
930
+ function clampNavaiOrbDelayMs(value, fallback) {
931
+ const numericValue = Number.isFinite(value) ? value : fallback;
932
+ return Math.min(ORB_DELAY_MS_MAX, Math.max(ORB_DELAY_MS_MIN, numericValue));
933
+ }
934
+ function NavaiHeroOrb({
935
+ className = "",
936
+ backgroundColor = "#000000",
937
+ isAgentSpeaking = false,
938
+ hoverIntensitySpeaking = 0.66,
939
+ hoverIntensityIdle = 0.08,
940
+ revealDelayMs = DEFAULT_REVEAL_DELAY_MS,
941
+ autoplayDelayMs = DEFAULT_AUTOPLAY_DELAY_MS
942
+ }) {
943
+ useNavaiVoiceOrbStyles();
944
+ const resolvedRevealDelayMs = clampNavaiOrbDelayMs(revealDelayMs, DEFAULT_REVEAL_DELAY_MS);
945
+ const resolvedAutoplayDelayMs = clampNavaiOrbDelayMs(autoplayDelayMs, DEFAULT_AUTOPLAY_DELAY_MS);
946
+ const [isOrbReady, setIsOrbReady] = useState3(resolvedRevealDelayMs === 0);
947
+ const [isOrbAutoAnimating, setIsOrbAutoAnimating] = useState3(resolvedAutoplayDelayMs === 0);
948
+ useEffect3(() => {
949
+ if (typeof window === "undefined" || resolvedRevealDelayMs === 0) {
950
+ return;
951
+ }
952
+ const revealOrb = () => setIsOrbReady(true);
953
+ window.addEventListener("pointerdown", revealOrb, { passive: true, once: true });
954
+ window.addEventListener("touchstart", revealOrb, { passive: true, once: true });
955
+ window.addEventListener("keydown", revealOrb, { once: true });
956
+ const timeoutId = window.setTimeout(revealOrb, resolvedRevealDelayMs);
957
+ return () => {
958
+ window.removeEventListener("pointerdown", revealOrb);
959
+ window.removeEventListener("touchstart", revealOrb);
960
+ window.removeEventListener("keydown", revealOrb);
961
+ window.clearTimeout(timeoutId);
962
+ };
963
+ }, [resolvedRevealDelayMs]);
964
+ useEffect3(() => {
965
+ if (typeof window === "undefined" || resolvedAutoplayDelayMs === 0) {
966
+ return;
967
+ }
968
+ let started = false;
969
+ const startOrbAnimation = () => {
970
+ if (started) {
971
+ return;
972
+ }
973
+ started = true;
974
+ setIsOrbAutoAnimating(true);
975
+ };
976
+ if (navigator.userActivation?.hasBeenActive) {
977
+ startOrbAnimation();
978
+ }
979
+ window.addEventListener("pointerdown", startOrbAnimation, { passive: true, once: true });
980
+ window.addEventListener("touchstart", startOrbAnimation, { passive: true, once: true });
981
+ window.addEventListener("keydown", startOrbAnimation, { once: true });
982
+ const timeoutId = window.setTimeout(startOrbAnimation, resolvedAutoplayDelayMs);
983
+ return () => {
984
+ window.removeEventListener("pointerdown", startOrbAnimation);
985
+ window.removeEventListener("touchstart", startOrbAnimation);
986
+ window.removeEventListener("keydown", startOrbAnimation);
987
+ window.clearTimeout(timeoutId);
988
+ };
989
+ }, [resolvedAutoplayDelayMs]);
990
+ const orbHoverIntensity = useMemo2(() => {
991
+ return isAgentSpeaking ? hoverIntensitySpeaking : hoverIntensityIdle;
992
+ }, [hoverIntensityIdle, hoverIntensitySpeaking, isAgentSpeaking]);
993
+ if (!isOrbReady) {
994
+ return null;
995
+ }
996
+ return /* @__PURE__ */ jsx2("div", { className: ["navai-voice-orb-hero", className].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx2(
997
+ Orb2,
998
+ {
999
+ hoverIntensity: orbHoverIntensity,
1000
+ rotateOnHover: true,
1001
+ forceHoverState: isAgentSpeaking,
1002
+ enablePointerHover: false,
1003
+ animate: isAgentSpeaking || isOrbAutoAnimating,
1004
+ backgroundColor
1005
+ }
1006
+ ) });
1007
+ }
1008
+
1009
+ // src/orb/NavaiMiniOrbDock.tsx
1010
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1011
+ var Orb3 = dynamic(() => import("./Orb-B4OSC3XR.js"), {
1012
+ ssr: false
1013
+ });
1014
+ function NavaiMiniOrbDock({
1015
+ className = "",
1016
+ style,
1017
+ themeMode = "dark",
1018
+ placement = "bottom-right",
1019
+ isActive = false,
1020
+ isConnected = false,
1021
+ isDisabled = false,
1022
+ isAgentSpeaking = false,
1023
+ animateOrb = true,
1024
+ backgroundColor = "#060914",
1025
+ buttonAriaLabel,
1026
+ buttonIcon,
1027
+ buttonType = "button",
1028
+ onButtonClick,
1029
+ statusMessage = "",
1030
+ isError = false,
1031
+ ariaMessage = ""
1032
+ }) {
1033
+ useNavaiVoiceOrbStyles();
1034
+ const dockClassName = ["navai-voice-orb-dock", `is-${placement}`, themeMode === "light" ? "is-light" : "", className].filter(Boolean).join(" ");
1035
+ const shouldHighlightOrb = isAgentSpeaking || isActive;
1036
+ const orbHoverIntensity = isAgentSpeaking ? 0.66 : 0.08;
1037
+ return /* @__PURE__ */ jsxs("aside", { className: dockClassName, style, children: [
1038
+ /* @__PURE__ */ jsxs("div", { className: "navai-voice-orb-wrap", children: [
1039
+ /* @__PURE__ */ jsx3("div", { className: ["navai-voice-orb-surface", shouldHighlightOrb ? "is-highlighted" : ""].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx3(
1040
+ Orb3,
1041
+ {
1042
+ hoverIntensity: orbHoverIntensity,
1043
+ rotateOnHover: true,
1044
+ forceHoverState: isAgentSpeaking,
1045
+ enablePointerHover: false,
1046
+ animate: animateOrb,
1047
+ backgroundColor
1048
+ }
1049
+ ) }),
1050
+ /* @__PURE__ */ jsx3("div", { className: ["navai-voice-orb-button-shell", isConnected ? "is-active" : ""].filter(Boolean).join(" "), children: /* @__PURE__ */ jsx3(
1051
+ "button",
1052
+ {
1053
+ type: buttonType,
1054
+ className: [
1055
+ "navai-voice-orb-button",
1056
+ isConnected ? "is-active" : "",
1057
+ isActive && !isConnected ? "is-connecting" : ""
1058
+ ].filter(Boolean).join(" "),
1059
+ onClick: onButtonClick,
1060
+ disabled: isDisabled,
1061
+ "aria-label": buttonAriaLabel,
1062
+ children: buttonIcon
1063
+ }
1064
+ ) })
1065
+ ] }),
1066
+ statusMessage ? /* @__PURE__ */ jsx3("p", { className: ["navai-voice-orb-status", isError ? "is-error" : ""].filter(Boolean).join(" "), role: "status", children: statusMessage }) : null,
1067
+ /* @__PURE__ */ jsx3("span", { className: "navai-voice-orb-live", "aria-live": "polite", children: ariaMessage })
1068
+ ] });
1069
+ }
1070
+
1071
+ // src/orb/NavaiVoiceHeroOrb.tsx
1072
+ import { useEffect as useEffect4 } from "react";
1073
+
1074
+ // src/orb/NavaiVoiceOrbDock.tsx
1075
+ import { useCallback as useCallback2, useMemo as useMemo3 } from "react";
1076
+
1077
+ // src/orb/NavaiVoiceOrbDockMicIcon.tsx
1078
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1079
+ function NavaiVoiceOrbDockMicIcon({
1080
+ isActive = false,
1081
+ size = 20
1082
+ }) {
1083
+ return /* @__PURE__ */ jsxs2(
1084
+ "svg",
1085
+ {
1086
+ width: size,
1087
+ height: size,
1088
+ viewBox: "0 0 24 24",
1089
+ fill: "none",
1090
+ stroke: "currentColor",
1091
+ strokeWidth: "2",
1092
+ strokeLinecap: "round",
1093
+ strokeLinejoin: "round",
1094
+ "aria-hidden": "true",
1095
+ className: ["navai-voice-orb-icon", isActive ? "is-pulsing" : ""].filter(Boolean).join(" "),
1096
+ children: [
1097
+ /* @__PURE__ */ jsx4("path", { d: "M12 3a3 3 0 0 0-3 3v6a3 3 0 1 0 6 0V6a3 3 0 0 0-3-3Z" }),
1098
+ /* @__PURE__ */ jsx4("path", { d: "M19 10v2a7 7 0 1 1-14 0v-2" }),
1099
+ /* @__PURE__ */ jsx4("path", { d: "M12 19v3" })
1100
+ ]
1101
+ }
1102
+ );
1103
+ }
1104
+
1105
+ // src/orb/NavaiVoiceOrbDockSpinnerIcon.tsx
1106
+ import { jsx as jsx5 } from "react/jsx-runtime";
1107
+ function NavaiVoiceOrbDockSpinnerIcon({
1108
+ size = 20
1109
+ }) {
1110
+ const style = {
1111
+ width: size,
1112
+ height: size
1113
+ };
1114
+ return /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "navai-voice-orb-spinner", style });
1115
+ }
1116
+
1117
+ // src/orb/NavaiVoiceOrbDock.tsx
1118
+ import { jsx as jsx6 } from "react/jsx-runtime";
1119
+ var DEFAULT_MESSAGES = {
1120
+ ariaStart: "Activate NAVAI voice",
1121
+ ariaStop: "Deactivate NAVAI voice",
1122
+ idle: "NAVAI ready to start.",
1123
+ connecting: "Connecting NAVAI voice...",
1124
+ listening: "NAVAI is listening.",
1125
+ speaking: "NAVAI is speaking.",
1126
+ errorPrefix: "NAVAI error"
1127
+ };
1128
+ function resolveNavaiVoiceOrbRuntimeSnapshot(agent) {
1129
+ return {
1130
+ status: agent.status,
1131
+ agentVoiceState: agent.agentVoiceState,
1132
+ isAgentSpeaking: agent.isAgentSpeaking,
1133
+ error: agent.error
1134
+ };
1135
+ }
1136
+ function resolveStatusMessage(runtimeSnapshot, messages) {
1137
+ if (runtimeSnapshot.error) {
1138
+ return `${messages.errorPrefix}: ${runtimeSnapshot.error}`;
1139
+ }
1140
+ if (runtimeSnapshot.isAgentSpeaking) {
1141
+ return messages.speaking;
1142
+ }
1143
+ if (runtimeSnapshot.status === "connecting") {
1144
+ return messages.connecting;
1145
+ }
1146
+ if (runtimeSnapshot.status === "connected") {
1147
+ return messages.listening;
1148
+ }
1149
+ return messages.idle;
1150
+ }
1151
+ function NavaiVoiceOrbDock({
1152
+ agent,
1153
+ className,
1154
+ style,
1155
+ themeMode = "dark",
1156
+ placement = "bottom-right",
1157
+ backgroundColorLight = "#f4f6fb",
1158
+ backgroundColorDark = "#060914",
1159
+ showStatus = true,
1160
+ messages
1161
+ }) {
1162
+ const resolvedMessages = useMemo3(() => ({ ...DEFAULT_MESSAGES, ...messages }), [messages]);
1163
+ const runtimeSnapshot = useMemo3(() => resolveNavaiVoiceOrbRuntimeSnapshot(agent), [agent]);
1164
+ const statusMessage = showStatus ? resolveStatusMessage(runtimeSnapshot, resolvedMessages) : "";
1165
+ const isError = runtimeSnapshot.status === "error" || Boolean(runtimeSnapshot.error);
1166
+ const isConnecting = runtimeSnapshot.status === "connecting";
1167
+ const isActive = runtimeSnapshot.status === "connecting" || runtimeSnapshot.status === "connected";
1168
+ const isDisabled = agent.isConnecting;
1169
+ const shouldAnimateOrb = runtimeSnapshot.status !== "error";
1170
+ const handleToggle = useCallback2(() => {
1171
+ if (agent.isConnecting) {
1172
+ return;
1173
+ }
1174
+ if (agent.isConnected) {
1175
+ agent.stop();
1176
+ return;
1177
+ }
1178
+ void agent.start();
1179
+ }, [agent]);
1180
+ return /* @__PURE__ */ jsx6(
1181
+ NavaiMiniOrbDock,
1182
+ {
1183
+ className,
1184
+ style,
1185
+ themeMode,
1186
+ placement,
1187
+ isActive,
1188
+ isConnected: agent.isConnected,
1189
+ isDisabled,
1190
+ isAgentSpeaking: agent.isAgentSpeaking,
1191
+ animateOrb: shouldAnimateOrb,
1192
+ backgroundColor: themeMode === "light" ? backgroundColorLight : backgroundColorDark,
1193
+ buttonAriaLabel: isConnecting ? resolvedMessages.connecting : agent.isConnected ? resolvedMessages.ariaStop : resolvedMessages.ariaStart,
1194
+ buttonIcon: isConnecting ? /* @__PURE__ */ jsx6(NavaiVoiceOrbDockSpinnerIcon, {}) : /* @__PURE__ */ jsx6(NavaiVoiceOrbDockMicIcon, { isActive: agent.isConnected || agent.isAgentSpeaking }),
1195
+ onButtonClick: handleToggle,
1196
+ statusMessage,
1197
+ isError,
1198
+ ariaMessage: statusMessage
1199
+ }
1200
+ );
1201
+ }
1202
+
1203
+ // src/orb/NavaiVoiceHeroOrb.tsx
1204
+ import { jsx as jsx7 } from "react/jsx-runtime";
1205
+ function NavaiVoiceHeroOrb({
1206
+ agent,
1207
+ themeMode = "dark",
1208
+ backgroundColorLight = "#ffffff",
1209
+ backgroundColorDark = "#000000",
1210
+ onRuntimeSnapshotChange,
1211
+ ...orbProps
1212
+ }) {
1213
+ const runtimeSnapshot = resolveNavaiVoiceOrbRuntimeSnapshot(agent);
1214
+ useEffect4(() => {
1215
+ if (typeof onRuntimeSnapshotChange === "function") {
1216
+ onRuntimeSnapshotChange(runtimeSnapshot);
1217
+ }
1218
+ }, [onRuntimeSnapshotChange, runtimeSnapshot]);
1219
+ return /* @__PURE__ */ jsx7(
1220
+ NavaiHeroOrb,
1221
+ {
1222
+ ...orbProps,
1223
+ isAgentSpeaking: runtimeSnapshot.isAgentSpeaking,
1224
+ backgroundColor: themeMode === "light" ? backgroundColorLight : backgroundColorDark,
1225
+ className: themeMode === "light" ? "is-light" : ""
1226
+ }
1227
+ );
1228
+ }
883
1229
  export {
1230
+ NavaiHeroOrb,
1231
+ NavaiMiniOrbDock,
1232
+ NavaiVoiceHeroOrb,
1233
+ NavaiVoiceOrbDock,
1234
+ NavaiVoiceOrbDockMicIcon,
1235
+ Orb,
884
1236
  buildNavaiAgent,
1237
+ clampNavaiOrbDelayMs,
885
1238
  createNavaiBackendClient,
886
1239
  getNavaiRoutePromptLines,
887
1240
  loadNavaiFunctions,
888
1241
  resolveNavaiFrontendRuntimeConfig,
889
1242
  resolveNavaiRoute,
1243
+ resolveNavaiVoiceOrbRuntimeSnapshot,
890
1244
  useWebVoiceAgent
891
1245
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navai/voice-frontend",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Frontend helpers to build OpenAI Realtime voice agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -32,6 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@openai/agents": "^0.4.14",
35
+ "ogl": "^1.0.11",
35
36
  "zod": "^4.0.0"
36
37
  },
37
38
  "peerDependencies": {