sunpeak 0.2.3 → 0.2.5

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React3 from 'react';
2
- import { useSyncExternalStore, useCallback, useMemo, useState, useEffect } from 'react';
2
+ import { useSyncExternalStore, useMemo, useState, useEffect, useCallback, useLayoutEffect } from 'react';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
  import { Slot } from '@radix-ui/react-slot';
5
5
  import { cva } from 'class-variance-authority';
@@ -51,49 +51,120 @@ var SetGlobalsEvent = class extends CustomEvent {
51
51
  }
52
52
  };
53
53
 
54
- // src/types/simulator.ts
55
- var SCREEN_WIDTHS = {
56
- "mobile-s": 375,
57
- "mobile-l": 425,
58
- tablet: 768,
59
- full: 1024
54
+ // src/providers/openai.ts
55
+ function isOpenAiAvailable() {
56
+ return typeof window !== "undefined" && window.openai != null;
57
+ }
58
+ var OpenAiProvider = class {
59
+ constructor() {
60
+ __publicField(this, "id", "openai");
61
+ }
62
+ getGlobal(key) {
63
+ if (typeof window === "undefined" || !window.openai) {
64
+ return null;
65
+ }
66
+ return window.openai[key] ?? null;
67
+ }
68
+ subscribe(key, onChange) {
69
+ if (typeof window === "undefined") {
70
+ return () => {
71
+ };
72
+ }
73
+ const handleEvent = (event) => {
74
+ if (event.detail.globals[key] !== void 0) {
75
+ onChange();
76
+ }
77
+ };
78
+ window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleEvent, {
79
+ passive: true
80
+ });
81
+ return () => {
82
+ window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleEvent);
83
+ };
84
+ }
85
+ getAPI() {
86
+ if (typeof window === "undefined" || !window.openai) {
87
+ return null;
88
+ }
89
+ const api = window.openai;
90
+ return {
91
+ callTool: api.callTool?.bind(api),
92
+ sendFollowUpMessage: api.sendFollowUpMessage?.bind(api),
93
+ openExternal: api.openExternal?.bind(api),
94
+ requestDisplayMode: api.requestDisplayMode?.bind(api),
95
+ requestModal: api.requestModal?.bind(api),
96
+ notifyIntrinsicHeight: api.notifyIntrinsicHeight?.bind(api),
97
+ setWidgetState: api.setWidgetState?.bind(api)
98
+ };
99
+ }
60
100
  };
101
+ var openAiProvider = null;
102
+ function getOpenAiProvider() {
103
+ if (!openAiProvider) {
104
+ openAiProvider = new OpenAiProvider();
105
+ }
106
+ return openAiProvider;
107
+ }
108
+
109
+ // src/providers/index.ts
110
+ var cachedProvider = null;
111
+ var detectionComplete = false;
112
+ function getProvider() {
113
+ if (detectionComplete) {
114
+ return cachedProvider;
115
+ }
116
+ if (isOpenAiAvailable()) {
117
+ cachedProvider = getOpenAiProvider();
118
+ }
119
+ detectionComplete = true;
120
+ return cachedProvider;
121
+ }
122
+ function isProviderAvailable() {
123
+ return getProvider() !== null;
124
+ }
125
+ function getGlobal(key) {
126
+ const provider = getProvider();
127
+ return provider?.getGlobal(key) ?? null;
128
+ }
129
+ function subscribeToGlobal(key, onChange) {
130
+ const provider = getProvider();
131
+ return provider?.subscribe(key, onChange) ?? (() => {
132
+ });
133
+ }
134
+ function getAPI() {
135
+ const provider = getProvider();
136
+ return provider?.getAPI() ?? null;
137
+ }
138
+ function resetProviderCache() {
139
+ cachedProvider = null;
140
+ detectionComplete = false;
141
+ }
61
142
 
62
- // src/hooks/use-openai-global.ts
63
- function useOpenAiGlobal(key) {
143
+ // src/hooks/use-widget-global.ts
144
+ function useWidgetGlobal(key) {
64
145
  return useSyncExternalStore(
65
- (onChange) => {
66
- if (typeof window === "undefined") {
67
- return () => {
68
- };
69
- }
70
- const handleSetGlobal = (event) => {
71
- const value = event.detail.globals[key];
72
- if (value === void 0) {
73
- return;
74
- }
75
- onChange();
76
- };
77
- window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {
78
- passive: true
79
- });
80
- return () => {
81
- window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
82
- };
83
- },
84
- () => window.openai?.[key] ?? null,
85
- () => window.openai?.[key] ?? null
146
+ (onChange) => subscribeToGlobal(key, onChange),
147
+ () => getGlobal(key),
148
+ () => getGlobal(key)
86
149
  );
87
150
  }
151
+ function useWidgetAPI() {
152
+ return useMemo(() => getAPI(), []);
153
+ }
88
154
 
89
155
  // src/hooks/use-display-mode.ts
90
156
  var useDisplayMode = () => {
91
- return useOpenAiGlobal("displayMode");
157
+ return useWidgetGlobal("displayMode");
158
+ };
159
+
160
+ // src/hooks/use-locale.ts
161
+ var useLocale = () => {
162
+ return useWidgetGlobal("locale");
92
163
  };
93
164
 
94
165
  // src/hooks/use-max-height.ts
95
166
  var useMaxHeight = () => {
96
- return useOpenAiGlobal("maxHeight");
167
+ return useWidgetGlobal("maxHeight");
97
168
  };
98
169
  var MOBILE_BREAKPOINT = 768;
99
170
  function useIsMobile() {
@@ -110,26 +181,84 @@ function useIsMobile() {
110
181
  return !!isMobile;
111
182
  }
112
183
 
184
+ // src/hooks/use-safe-area.ts
185
+ var useSafeArea = () => {
186
+ return useWidgetGlobal("safeArea");
187
+ };
188
+
113
189
  // src/hooks/use-theme.ts
114
190
  var useTheme = () => {
115
- return useOpenAiGlobal("theme");
191
+ return useWidgetGlobal("theme");
116
192
  };
117
- function useWidgetState() {
118
- const widgetState = useOpenAiGlobal("widgetState");
119
- const setWidgetState = useOpenAiGlobal("setWidgetState");
120
- const setter = useCallback(
121
- async (state) => {
122
- if (setWidgetState) {
123
- await setWidgetState(state);
124
- }
193
+
194
+ // src/hooks/use-tool-input.ts
195
+ function useToolInput() {
196
+ return useWidgetGlobal("toolInput");
197
+ }
198
+
199
+ // src/hooks/use-tool-response-metadata.ts
200
+ function useToolResponseMetadata() {
201
+ return useWidgetGlobal("toolResponseMetadata");
202
+ }
203
+
204
+ // src/hooks/use-user-agent.ts
205
+ var useUserAgent = () => {
206
+ return useWidgetGlobal("userAgent");
207
+ };
208
+
209
+ // src/hooks/use-view.ts
210
+ function useView() {
211
+ return useWidgetGlobal("view");
212
+ }
213
+
214
+ // src/hooks/use-widget-props.ts
215
+ function useWidgetProps(defaultState) {
216
+ const props = useWidgetGlobal("toolOutput");
217
+ const fallback = typeof defaultState === "function" ? defaultState() : defaultState ?? null;
218
+ return props ?? fallback;
219
+ }
220
+ function useWidgetState(defaultState) {
221
+ const widgetStateFromProvider = useWidgetGlobal("widgetState");
222
+ const api = useWidgetAPI();
223
+ const [widgetState, _setWidgetState] = useState(() => {
224
+ if (widgetStateFromProvider != null) {
225
+ return widgetStateFromProvider;
226
+ }
227
+ return typeof defaultState === "function" ? defaultState() : defaultState ?? null;
228
+ });
229
+ useEffect(() => {
230
+ _setWidgetState(widgetStateFromProvider);
231
+ }, [widgetStateFromProvider]);
232
+ const setWidgetState = useCallback(
233
+ (state) => {
234
+ _setWidgetState((prevState) => {
235
+ const newState = typeof state === "function" ? state(prevState) : state;
236
+ if (newState != null && api?.setWidgetState) {
237
+ api.setWidgetState(newState);
238
+ }
239
+ return newState;
240
+ });
125
241
  },
126
- [setWidgetState]
242
+ [api]
127
243
  );
128
- return useMemo(() => [widgetState, setter], [widgetState, setter]);
244
+ return [widgetState, setWidgetState];
129
245
  }
130
246
  function cn(...inputs) {
131
247
  return twMerge(clsx(inputs));
132
248
  }
249
+
250
+ // src/lib/media-queries.ts
251
+ function matchMediaQuery(query) {
252
+ return window.matchMedia(query).matches;
253
+ }
254
+ function createMediaQueryFn(query) {
255
+ return () => matchMediaQuery(query);
256
+ }
257
+ var prefersReducedMotion = createMediaQueryFn(
258
+ "(prefers-reduced-motion: reduce)"
259
+ );
260
+ var isPrimarilyTouchDevice = createMediaQueryFn("(pointer: coarse)");
261
+ var isHoverAvailable = createMediaQueryFn("(hover: hover)");
133
262
  function Sheet({ ...props }) {
134
263
  return /* @__PURE__ */ jsx(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
135
264
  }
@@ -622,14 +751,22 @@ var Label2 = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
622
751
  }
623
752
  ));
624
753
  Label2.displayName = LabelPrimitive.Root.displayName;
754
+
755
+ // src/types/simulator.ts
756
+ var SCREEN_WIDTHS = {
757
+ "mobile-s": 375,
758
+ "mobile-l": 425,
759
+ tablet: 768,
760
+ full: 1024
761
+ };
625
762
  function Conversation({
626
763
  children,
627
764
  screenWidth,
628
- displayMode,
629
765
  appName = "ChatGPT",
630
766
  appIcon,
631
767
  userMessage = "Show me some interesting places to visit."
632
768
  }) {
769
+ const displayMode = useDisplayMode() ?? "inline";
633
770
  const containerWidth = screenWidth === "full" ? "100%" : `${SCREEN_WIDTHS[screenWidth]}px`;
634
771
  if (displayMode === "fullscreen") {
635
772
  return /* @__PURE__ */ jsx(SidebarInset, { className: "flex flex-col bg-background", children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", children }) });
@@ -737,6 +874,7 @@ var MockOpenAI = class {
737
874
  right: 0
738
875
  }
739
876
  });
877
+ __publicField(this, "view", null);
740
878
  __publicField(this, "toolInput", {});
741
879
  __publicField(this, "toolOutput", null);
742
880
  __publicField(this, "toolResponseMetadata", null);
@@ -757,6 +895,14 @@ var MockOpenAI = class {
757
895
  this.setDisplayMode(args.mode);
758
896
  return { mode: args.mode };
759
897
  }
898
+ async requestModal(args) {
899
+ console.log("Mock requestModal:", args);
900
+ this.view = { mode: args.mode, params: args.params };
901
+ this.emitUpdate({ view: this.view });
902
+ }
903
+ notifyIntrinsicHeight(height) {
904
+ console.log("Mock notifyIntrinsicHeight:", height);
905
+ }
760
906
  async setWidgetState(state) {
761
907
  this.widgetState = state;
762
908
  this.emitUpdate({ widgetState: state });
@@ -769,33 +915,76 @@ var MockOpenAI = class {
769
915
  this.displayMode = displayMode;
770
916
  this.emitUpdate({ displayMode });
771
917
  }
918
+ setToolOutput(toolOutput) {
919
+ this.toolOutput = toolOutput;
920
+ this.emitUpdate({ toolOutput });
921
+ }
922
+ setWidgetStateExternal(widgetState) {
923
+ this.widgetState = widgetState;
924
+ this.emitUpdate({ widgetState });
925
+ }
772
926
  emitUpdate(globals) {
773
927
  if (typeof window !== "undefined") {
774
- const event = new CustomEvent(SET_GLOBALS_EVENT_TYPE, {
775
- detail: { globals }
928
+ queueMicrotask(() => {
929
+ const event = new CustomEvent(SET_GLOBALS_EVENT_TYPE, {
930
+ detail: { globals }
931
+ });
932
+ window.dispatchEvent(event);
776
933
  });
777
- window.dispatchEvent(event);
778
934
  }
779
935
  }
780
936
  };
781
- function initMockOpenAI() {
937
+ function initMockOpenAI(initialData) {
782
938
  if (typeof window !== "undefined") {
783
939
  const mock = new MockOpenAI();
940
+ if (initialData?.theme !== void 0) {
941
+ mock.theme = initialData.theme;
942
+ }
943
+ if (initialData?.displayMode !== void 0) {
944
+ mock.displayMode = initialData.displayMode;
945
+ }
946
+ if (initialData?.toolOutput !== void 0) {
947
+ mock.toolOutput = initialData.toolOutput;
948
+ }
949
+ if (initialData?.widgetState !== void 0) {
950
+ mock.widgetState = initialData.widgetState;
951
+ }
784
952
  window.openai = mock;
785
953
  return mock;
786
954
  }
787
955
  return new MockOpenAI();
788
956
  }
957
+ var DEFAULT_THEME = "dark";
958
+ var DEFAULT_DISPLAY_MODE = "inline";
789
959
  function ChatGPTSimulator({
790
960
  children,
791
961
  appName,
792
962
  appIcon,
793
- userMessage
963
+ userMessage,
964
+ toolOutput = null,
965
+ widgetState = null
794
966
  }) {
795
- const [theme, setTheme] = useState("dark");
796
- const [displayMode, setDisplayMode] = useState("inline");
797
- const [screenWidth, setScreenWidth] = useState("full");
798
- const mock = useMemo(() => initMockOpenAI(), []);
967
+ const [screenWidth, setScreenWidth] = React3.useState("full");
968
+ const mock = useMemo(
969
+ () => initMockOpenAI({
970
+ theme: DEFAULT_THEME,
971
+ displayMode: DEFAULT_DISPLAY_MODE
972
+ }),
973
+ []
974
+ );
975
+ const theme = useTheme() ?? DEFAULT_THEME;
976
+ const displayMode = useDisplayMode() ?? DEFAULT_DISPLAY_MODE;
977
+ useLayoutEffect(() => {
978
+ if (mock && typeof window !== "undefined") {
979
+ window.openai = mock;
980
+ if (toolOutput !== void 0) {
981
+ mock.setToolOutput(toolOutput);
982
+ }
983
+ if (widgetState !== void 0) {
984
+ mock.setWidgetStateExternal(widgetState);
985
+ }
986
+ }
987
+ }, [mock, toolOutput, widgetState]);
799
988
  useEffect(() => {
800
989
  return () => {
801
990
  if (typeof window !== "undefined") {
@@ -803,31 +992,13 @@ function ChatGPTSimulator({
803
992
  }
804
993
  };
805
994
  }, []);
806
- useEffect(() => {
807
- if (mock) {
808
- mock.setTheme(theme);
809
- }
810
- }, [mock, theme]);
811
- useEffect(() => {
812
- if (mock) {
813
- mock.setDisplayMode(displayMode);
814
- }
815
- }, [mock, displayMode]);
816
995
  return /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs(SidebarProvider, { defaultOpen: true, children: [
817
996
  /* @__PURE__ */ jsx(Sidebar, { children: /* @__PURE__ */ jsx(SidebarContent, { children: /* @__PURE__ */ jsxs(SidebarGroup, { children: [
818
997
  /* @__PURE__ */ jsx(SidebarGroupLabel, { className: "text-md", children: "Controls" }),
819
998
  /* @__PURE__ */ jsxs(SidebarGroupContent, { className: "space-y-4", children: [
820
999
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
821
- /* @__PURE__ */ jsx(Label2, { htmlFor: "app-ui-select", className: "text-xs", children: "App UI" }),
822
- /* @__PURE__ */ jsxs(Select, { value: "carousel", onValueChange: () => {
823
- }, children: [
824
- /* @__PURE__ */ jsx(SelectTrigger, { id: "app-ui-select", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
825
- /* @__PURE__ */ jsx(SelectContent, { children: /* @__PURE__ */ jsx(SelectItem, { value: "carousel", children: "Carousel" }) })
826
- ] })
827
- ] }),
828
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
829
- /* @__PURE__ */ jsx(Label2, { htmlFor: "theme-select", className: "text-xs", children: "Color Scheme" }),
830
- /* @__PURE__ */ jsxs(Select, { value: theme, onValueChange: (value) => setTheme(value), children: [
1000
+ /* @__PURE__ */ jsx(Label2, { htmlFor: "theme-select", className: "text-xs", children: "Theme" }),
1001
+ /* @__PURE__ */ jsxs(Select, { value: theme, onValueChange: (value) => mock.setTheme(value), children: [
831
1002
  /* @__PURE__ */ jsx(SelectTrigger, { id: "theme-select", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
832
1003
  /* @__PURE__ */ jsxs(SelectContent, { children: [
833
1004
  /* @__PURE__ */ jsx(SelectItem, { value: "light", children: "Light" }),
@@ -837,7 +1008,7 @@ function ChatGPTSimulator({
837
1008
  ] }),
838
1009
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
839
1010
  /* @__PURE__ */ jsx(Label2, { htmlFor: "display-mode-select", className: "text-xs", children: "Display Mode" }),
840
- /* @__PURE__ */ jsxs(Select, { value: displayMode, onValueChange: (value) => setDisplayMode(value), children: [
1011
+ /* @__PURE__ */ jsxs(Select, { value: displayMode, onValueChange: (value) => mock.setDisplayMode(value), children: [
841
1012
  /* @__PURE__ */ jsx(SelectTrigger, { id: "display-mode-select", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
842
1013
  /* @__PURE__ */ jsxs(SelectContent, { children: [
843
1014
  /* @__PURE__ */ jsx(SelectItem, { value: "inline", children: "Inline" }),
@@ -864,7 +1035,6 @@ function ChatGPTSimulator({
864
1035
  Conversation,
865
1036
  {
866
1037
  screenWidth,
867
- displayMode,
868
1038
  appName,
869
1039
  appIcon,
870
1040
  userMessage,
@@ -874,6 +1044,6 @@ function ChatGPTSimulator({
874
1044
  ] }) });
875
1045
  }
876
1046
 
877
- export { ChatGPTSimulator, SCREEN_WIDTHS, SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent, ThemeProvider, cn, initMockOpenAI, useDisplayMode, useIsMobile, useMaxHeight, useOpenAiGlobal, useTheme, useThemeContext, useWidgetState };
1047
+ export { ChatGPTSimulator, SCREEN_WIDTHS, SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent, ThemeProvider, cn, getAPI, getGlobal, getOpenAiProvider, getProvider, initMockOpenAI, isHoverAvailable, isOpenAiAvailable, isPrimarilyTouchDevice, isProviderAvailable, prefersReducedMotion, resetProviderCache, subscribeToGlobal, useDisplayMode, useIsMobile, useLocale, useMaxHeight, useSafeArea, useTheme, useThemeContext, useToolInput, useToolResponseMetadata, useUserAgent, useView, useWidgetAPI, useWidgetGlobal, useWidgetProps, useWidgetState };
878
1048
  //# sourceMappingURL=index.js.map
879
1049
  //# sourceMappingURL=index.js.map