sunpeak 0.1.0
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/README.md +109 -0
- package/dist/components.css +255 -0
- package/dist/design-systems/chatgpt.css +243 -0
- package/dist/index.cjs +730 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +344 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +571 -0
- package/dist/index.d.ts +571 -0
- package/dist/index.js +713 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/themes.css +344 -0
- package/dist/styles/themes.css.map +1 -0
- package/dist/styles/themes.d.cts +2 -0
- package/dist/styles/themes.d.ts +2 -0
- package/package.json +94 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var clsx = require('clsx');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
|
|
7
|
+
// src/components/Button/Button.tsx
|
|
8
|
+
var Button = ({
|
|
9
|
+
isPrimary = false,
|
|
10
|
+
onClick,
|
|
11
|
+
children,
|
|
12
|
+
className,
|
|
13
|
+
type = "button",
|
|
14
|
+
...props
|
|
15
|
+
}) => {
|
|
16
|
+
const buttonClasses = clsx.clsx(
|
|
17
|
+
"sp-button",
|
|
18
|
+
{
|
|
19
|
+
"sp-button-primary": isPrimary,
|
|
20
|
+
"sp-button-secondary": !isPrimary
|
|
21
|
+
},
|
|
22
|
+
className
|
|
23
|
+
);
|
|
24
|
+
const handleClick = (e) => {
|
|
25
|
+
e.stopPropagation();
|
|
26
|
+
onClick();
|
|
27
|
+
};
|
|
28
|
+
return /* @__PURE__ */ jsxRuntime.jsx("button", { className: buttonClasses, onClick: handleClick, type, ...props, children });
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// src/types/chatgpt.ts
|
|
32
|
+
var SET_GLOBALS_EVENT_TYPE = "chatgpt:set_globals";
|
|
33
|
+
|
|
34
|
+
// src/platforms/chatgpt.ts
|
|
35
|
+
var ChatGPTPlatformAdapter = class {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.name = "chatgpt";
|
|
38
|
+
}
|
|
39
|
+
isAvailable() {
|
|
40
|
+
return typeof window !== "undefined" && "openai" in window;
|
|
41
|
+
}
|
|
42
|
+
getGlobal(key) {
|
|
43
|
+
if (!this.isAvailable()) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return window.openai?.[key] ?? null;
|
|
47
|
+
}
|
|
48
|
+
getGlobals() {
|
|
49
|
+
if (!this.isAvailable()) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return window.openai ?? null;
|
|
53
|
+
}
|
|
54
|
+
subscribe(callback) {
|
|
55
|
+
if (typeof window === "undefined") {
|
|
56
|
+
return () => {
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const handleSetGlobal = (_event) => {
|
|
60
|
+
callback();
|
|
61
|
+
};
|
|
62
|
+
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {
|
|
63
|
+
passive: true
|
|
64
|
+
});
|
|
65
|
+
return () => {
|
|
66
|
+
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var chatgptPlatform = new ChatGPTPlatformAdapter();
|
|
71
|
+
|
|
72
|
+
// src/platforms/registry.ts
|
|
73
|
+
var DefaultPlatformRegistry = class {
|
|
74
|
+
constructor() {
|
|
75
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
76
|
+
this.register(chatgptPlatform);
|
|
77
|
+
}
|
|
78
|
+
register(adapter) {
|
|
79
|
+
this.adapters.set(adapter.name, adapter);
|
|
80
|
+
}
|
|
81
|
+
get(name) {
|
|
82
|
+
return this.adapters.get(name) ?? null;
|
|
83
|
+
}
|
|
84
|
+
detect() {
|
|
85
|
+
for (const adapter of this.adapters.values()) {
|
|
86
|
+
if (adapter.isAvailable()) {
|
|
87
|
+
return adapter;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
getAll() {
|
|
93
|
+
return Array.from(this.adapters.values());
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function createPlatformRegistry() {
|
|
97
|
+
return new DefaultPlatformRegistry();
|
|
98
|
+
}
|
|
99
|
+
var defaultPlatformRegistry = createPlatformRegistry();
|
|
100
|
+
var PlatformContext = react.createContext(null);
|
|
101
|
+
function PlatformProvider({ adapter, platform, children }) {
|
|
102
|
+
const resolvedAdapter = adapter ?? (platform ? defaultPlatformRegistry.get(platform) : null) ?? defaultPlatformRegistry.detect();
|
|
103
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PlatformContext.Provider, { value: { adapter: resolvedAdapter }, children });
|
|
104
|
+
}
|
|
105
|
+
function usePlatformContext() {
|
|
106
|
+
const context = react.useContext(PlatformContext);
|
|
107
|
+
if (!context) {
|
|
108
|
+
return {
|
|
109
|
+
adapter: defaultPlatformRegistry.detect()
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return context;
|
|
113
|
+
}
|
|
114
|
+
function usePlatform() {
|
|
115
|
+
const { adapter } = usePlatformContext();
|
|
116
|
+
return adapter;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/hooks/usePlatformGlobal.ts
|
|
120
|
+
function usePlatformGlobal(key) {
|
|
121
|
+
const platform = usePlatform();
|
|
122
|
+
return react.useSyncExternalStore(
|
|
123
|
+
(onChange) => {
|
|
124
|
+
if (!platform) {
|
|
125
|
+
return () => {
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return platform.subscribe(onChange);
|
|
129
|
+
},
|
|
130
|
+
() => platform?.getGlobal(key) ?? null,
|
|
131
|
+
() => platform?.getGlobal(key) ?? null
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/hooks/useDisplayMode.ts
|
|
136
|
+
var useDisplayMode = () => {
|
|
137
|
+
return usePlatformGlobal("displayMode");
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/hooks/useMaxHeight.ts
|
|
141
|
+
var useMaxHeight = () => {
|
|
142
|
+
return usePlatformGlobal("maxHeight");
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// src/hooks/useRequestDisplayMode.ts
|
|
146
|
+
function useRequestDisplayMode() {
|
|
147
|
+
const platform = usePlatform();
|
|
148
|
+
return async (args) => {
|
|
149
|
+
const globals = platform?.getGlobals();
|
|
150
|
+
if (globals?.requestDisplayMode) {
|
|
151
|
+
return await globals.requestDisplayMode(args);
|
|
152
|
+
}
|
|
153
|
+
console.warn("requestDisplayMode is not available on this platform");
|
|
154
|
+
return { mode: args.mode };
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/hooks/useColorScheme.ts
|
|
159
|
+
var useColorScheme = () => {
|
|
160
|
+
return usePlatformGlobal("colorScheme");
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/hooks/useWidgetProps.ts
|
|
164
|
+
function useWidgetProps(defaultState) {
|
|
165
|
+
const props = usePlatformGlobal("toolOutput");
|
|
166
|
+
const fallback = typeof defaultState === "function" ? defaultState() : defaultState ?? null;
|
|
167
|
+
return props ?? fallback;
|
|
168
|
+
}
|
|
169
|
+
function useWidgetState(defaultState) {
|
|
170
|
+
const widgetStateFromWindow = usePlatformGlobal("widgetState");
|
|
171
|
+
const platform = usePlatform();
|
|
172
|
+
const [widgetState, _setWidgetState] = react.useState(() => {
|
|
173
|
+
if (widgetStateFromWindow != null) {
|
|
174
|
+
return widgetStateFromWindow;
|
|
175
|
+
}
|
|
176
|
+
return typeof defaultState === "function" ? defaultState() : defaultState ?? null;
|
|
177
|
+
});
|
|
178
|
+
react.useEffect(() => {
|
|
179
|
+
_setWidgetState(widgetStateFromWindow);
|
|
180
|
+
}, [widgetStateFromWindow]);
|
|
181
|
+
const setWidgetState = react.useCallback(
|
|
182
|
+
(state) => {
|
|
183
|
+
_setWidgetState((prevState) => {
|
|
184
|
+
const newState = typeof state === "function" ? state(prevState) : state;
|
|
185
|
+
if (newState != null && platform) {
|
|
186
|
+
const globals = platform.getGlobals();
|
|
187
|
+
if (globals?.setWidgetState) {
|
|
188
|
+
globals.setWidgetState(newState);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return newState;
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
[platform]
|
|
195
|
+
);
|
|
196
|
+
return [widgetState, setWidgetState];
|
|
197
|
+
}
|
|
198
|
+
var Card = ({
|
|
199
|
+
children,
|
|
200
|
+
image,
|
|
201
|
+
imageAlt,
|
|
202
|
+
imageMaxWidth,
|
|
203
|
+
imageMaxHeight,
|
|
204
|
+
header,
|
|
205
|
+
metadata,
|
|
206
|
+
button1,
|
|
207
|
+
button2,
|
|
208
|
+
variant = "default",
|
|
209
|
+
maxWidth = 800,
|
|
210
|
+
className,
|
|
211
|
+
onClick,
|
|
212
|
+
id,
|
|
213
|
+
...props
|
|
214
|
+
}) => {
|
|
215
|
+
const requestDisplayMode = useRequestDisplayMode();
|
|
216
|
+
const displayMode = useDisplayMode();
|
|
217
|
+
const maxHeight = useMaxHeight();
|
|
218
|
+
const colorScheme = useColorScheme();
|
|
219
|
+
const [widgetState, setWidgetState] = useWidgetState({});
|
|
220
|
+
const isInline = displayMode !== "fullscreen" && displayMode !== "pip";
|
|
221
|
+
const cardClasses = clsx.clsx(
|
|
222
|
+
"sp-genai-app",
|
|
223
|
+
"sp-card",
|
|
224
|
+
"sp-select-none",
|
|
225
|
+
"sp-antialiased",
|
|
226
|
+
{
|
|
227
|
+
"sp-card-elevated": variant === "elevated",
|
|
228
|
+
"sp-card-bordered": variant === "bordered"
|
|
229
|
+
},
|
|
230
|
+
colorScheme && `sp-theme-${colorScheme}`,
|
|
231
|
+
className
|
|
232
|
+
);
|
|
233
|
+
const hasButtons = button1 || button2;
|
|
234
|
+
const handleCardClick = async (e) => {
|
|
235
|
+
onClick?.(e);
|
|
236
|
+
if (isInline && !e.defaultPrevented) {
|
|
237
|
+
try {
|
|
238
|
+
if (id) {
|
|
239
|
+
setWidgetState({ ...widgetState, selectedCardId: id });
|
|
240
|
+
}
|
|
241
|
+
await requestDisplayMode({ mode: "fullscreen" });
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error("Failed to request fullscreen mode:", error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
248
|
+
"div",
|
|
249
|
+
{
|
|
250
|
+
id,
|
|
251
|
+
className: cardClasses,
|
|
252
|
+
style: {
|
|
253
|
+
width: isInline ? "220px" : "100%",
|
|
254
|
+
maxWidth: isInline ? "220px" : `${maxWidth}px`,
|
|
255
|
+
maxHeight: maxHeight ? `${maxHeight}px` : void 0,
|
|
256
|
+
cursor: isInline ? "pointer" : "default",
|
|
257
|
+
overflow: "auto"
|
|
258
|
+
},
|
|
259
|
+
onClick: handleCardClick,
|
|
260
|
+
...props,
|
|
261
|
+
children: [
|
|
262
|
+
image && /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
263
|
+
"img",
|
|
264
|
+
{
|
|
265
|
+
src: image,
|
|
266
|
+
alt: imageAlt,
|
|
267
|
+
className: "sp-card-image",
|
|
268
|
+
loading: "lazy",
|
|
269
|
+
style: {
|
|
270
|
+
maxWidth: `${imageMaxWidth}px`,
|
|
271
|
+
maxHeight: `${imageMaxHeight}px`
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
) }),
|
|
275
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
276
|
+
"div",
|
|
277
|
+
{
|
|
278
|
+
style: {
|
|
279
|
+
display: "flex",
|
|
280
|
+
flexDirection: "column",
|
|
281
|
+
gap: isInline ? "12px" : "16px",
|
|
282
|
+
padding: isInline ? "16px" : "24px",
|
|
283
|
+
paddingTop: image ? isInline ? "12px" : "16px" : isInline ? "16px" : "24px",
|
|
284
|
+
flex: 1
|
|
285
|
+
},
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: isInline ? "4px" : "8px", flex: 1 }, children: [
|
|
288
|
+
header && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sp-card-header sp-truncate", children: header }),
|
|
289
|
+
metadata && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sp-card-metadata", children: metadata }),
|
|
290
|
+
children && /* @__PURE__ */ jsxRuntime.jsx(
|
|
291
|
+
"div",
|
|
292
|
+
{
|
|
293
|
+
className: "sp-card-description",
|
|
294
|
+
style: {
|
|
295
|
+
marginTop: metadata || header ? isInline ? "4px" : "8px" : "0",
|
|
296
|
+
WebkitLineClamp: isInline ? 2 : "unset"
|
|
297
|
+
},
|
|
298
|
+
children
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
] }),
|
|
302
|
+
hasButtons && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
|
|
303
|
+
button1 && /* @__PURE__ */ jsxRuntime.jsx(Button, { ...button1 }),
|
|
304
|
+
button2 && /* @__PURE__ */ jsxRuntime.jsx(Button, { ...button2 })
|
|
305
|
+
] })
|
|
306
|
+
]
|
|
307
|
+
}
|
|
308
|
+
)
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
var Carousel = ({
|
|
314
|
+
children,
|
|
315
|
+
gap = 16,
|
|
316
|
+
maxWidth = 800,
|
|
317
|
+
showArrows = true,
|
|
318
|
+
showEdgeGradients = true,
|
|
319
|
+
className,
|
|
320
|
+
...props
|
|
321
|
+
}) => {
|
|
322
|
+
const scrollRef = react.useRef(null);
|
|
323
|
+
const [canScrollLeft, setCanScrollLeft] = react.useState(false);
|
|
324
|
+
const [canScrollRight, setCanScrollRight] = react.useState(false);
|
|
325
|
+
const [isDragging, setIsDragging] = react.useState(false);
|
|
326
|
+
const [startX, setStartX] = react.useState(0);
|
|
327
|
+
const [scrollLeft, setScrollLeft] = react.useState(0);
|
|
328
|
+
const maxHeight = useMaxHeight();
|
|
329
|
+
const colorScheme = useColorScheme();
|
|
330
|
+
const checkScroll = () => {
|
|
331
|
+
const el = scrollRef.current;
|
|
332
|
+
if (!el) return;
|
|
333
|
+
setCanScrollLeft(el.scrollLeft > 0);
|
|
334
|
+
setCanScrollRight(el.scrollLeft < el.scrollWidth - el.clientWidth - 1);
|
|
335
|
+
};
|
|
336
|
+
react.useEffect(() => {
|
|
337
|
+
checkScroll();
|
|
338
|
+
const el = scrollRef.current;
|
|
339
|
+
if (!el) return;
|
|
340
|
+
el.addEventListener("scroll", checkScroll);
|
|
341
|
+
window.addEventListener("resize", checkScroll);
|
|
342
|
+
return () => {
|
|
343
|
+
el.removeEventListener("scroll", checkScroll);
|
|
344
|
+
window.removeEventListener("resize", checkScroll);
|
|
345
|
+
};
|
|
346
|
+
}, []);
|
|
347
|
+
const scroll = (direction) => {
|
|
348
|
+
const el = scrollRef.current;
|
|
349
|
+
if (!el) return;
|
|
350
|
+
const firstCard = el.children[0];
|
|
351
|
+
if (!firstCard) return;
|
|
352
|
+
const cardWidth = firstCard.offsetWidth;
|
|
353
|
+
const scrollAmount = cardWidth + gap;
|
|
354
|
+
const targetScroll = direction === "left" ? el.scrollLeft - scrollAmount : el.scrollLeft + scrollAmount;
|
|
355
|
+
el.scrollTo({
|
|
356
|
+
left: targetScroll,
|
|
357
|
+
behavior: "smooth"
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
const handleMouseDown = (e) => {
|
|
361
|
+
const el = scrollRef.current;
|
|
362
|
+
if (!el) return;
|
|
363
|
+
setIsDragging(true);
|
|
364
|
+
setStartX(e.pageX - el.offsetLeft);
|
|
365
|
+
setScrollLeft(el.scrollLeft);
|
|
366
|
+
};
|
|
367
|
+
const handleMouseMove = (e) => {
|
|
368
|
+
if (!isDragging) return;
|
|
369
|
+
e.preventDefault();
|
|
370
|
+
const el = scrollRef.current;
|
|
371
|
+
if (!el) return;
|
|
372
|
+
const x = e.pageX - el.offsetLeft;
|
|
373
|
+
const walk = (x - startX) * 2;
|
|
374
|
+
el.scrollLeft = scrollLeft - walk;
|
|
375
|
+
};
|
|
376
|
+
const handleMouseUpOrLeave = () => {
|
|
377
|
+
setIsDragging(false);
|
|
378
|
+
};
|
|
379
|
+
const containerClasses = clsx.clsx(
|
|
380
|
+
"sp-genai-app",
|
|
381
|
+
"sp-carousel",
|
|
382
|
+
"sp-antialiased",
|
|
383
|
+
colorScheme && `sp-theme-${colorScheme}`,
|
|
384
|
+
className
|
|
385
|
+
);
|
|
386
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
387
|
+
"div",
|
|
388
|
+
{
|
|
389
|
+
className: containerClasses,
|
|
390
|
+
style: {
|
|
391
|
+
maxHeight: maxHeight ? `${maxHeight}px` : void 0,
|
|
392
|
+
maxWidth: `${maxWidth}px`
|
|
393
|
+
},
|
|
394
|
+
...props,
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
397
|
+
"div",
|
|
398
|
+
{
|
|
399
|
+
ref: scrollRef,
|
|
400
|
+
className: "sp-carousel-scroll",
|
|
401
|
+
style: { gap: `${gap}px`, cursor: isDragging ? "grabbing" : "grab" },
|
|
402
|
+
onMouseDown: handleMouseDown,
|
|
403
|
+
onMouseMove: handleMouseMove,
|
|
404
|
+
onMouseUp: handleMouseUpOrLeave,
|
|
405
|
+
onMouseLeave: handleMouseUpOrLeave,
|
|
406
|
+
children
|
|
407
|
+
}
|
|
408
|
+
) }),
|
|
409
|
+
showEdgeGradients && canScrollLeft && /* @__PURE__ */ jsxRuntime.jsx(
|
|
410
|
+
"div",
|
|
411
|
+
{
|
|
412
|
+
className: "sp-carousel-edge sp-carousel-edge-left",
|
|
413
|
+
"aria-hidden": "true",
|
|
414
|
+
style: { opacity: canScrollLeft ? 1 : 0 }
|
|
415
|
+
}
|
|
416
|
+
),
|
|
417
|
+
showEdgeGradients && canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
|
|
418
|
+
"div",
|
|
419
|
+
{
|
|
420
|
+
className: "sp-carousel-edge sp-carousel-edge-right",
|
|
421
|
+
"aria-hidden": "true",
|
|
422
|
+
style: { opacity: canScrollRight ? 1 : 0 }
|
|
423
|
+
}
|
|
424
|
+
),
|
|
425
|
+
showArrows && canScrollLeft && /* @__PURE__ */ jsxRuntime.jsx(
|
|
426
|
+
"button",
|
|
427
|
+
{
|
|
428
|
+
"aria-label": "Previous",
|
|
429
|
+
className: "sp-carousel-nav-button sp-carousel-nav-button-prev",
|
|
430
|
+
onClick: () => scroll("left"),
|
|
431
|
+
type: "button",
|
|
432
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
433
|
+
"svg",
|
|
434
|
+
{
|
|
435
|
+
className: "sp-carousel-nav-icon",
|
|
436
|
+
viewBox: "0 0 24 24",
|
|
437
|
+
fill: "none",
|
|
438
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
439
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
440
|
+
"path",
|
|
441
|
+
{
|
|
442
|
+
d: "M15 18L9 12L15 6",
|
|
443
|
+
stroke: "currentColor",
|
|
444
|
+
strokeWidth: "1.5",
|
|
445
|
+
strokeLinecap: "round",
|
|
446
|
+
strokeLinejoin: "round"
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
}
|
|
450
|
+
)
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
showArrows && canScrollRight && /* @__PURE__ */ jsxRuntime.jsx(
|
|
454
|
+
"button",
|
|
455
|
+
{
|
|
456
|
+
"aria-label": "Next",
|
|
457
|
+
className: "sp-carousel-nav-button sp-carousel-nav-button-next",
|
|
458
|
+
onClick: () => scroll("right"),
|
|
459
|
+
type: "button",
|
|
460
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
461
|
+
"svg",
|
|
462
|
+
{
|
|
463
|
+
className: "sp-carousel-nav-icon",
|
|
464
|
+
viewBox: "0 0 24 24",
|
|
465
|
+
fill: "none",
|
|
466
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
467
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
468
|
+
"path",
|
|
469
|
+
{
|
|
470
|
+
d: "M9 18L15 12L9 6",
|
|
471
|
+
stroke: "currentColor",
|
|
472
|
+
strokeWidth: "1.5",
|
|
473
|
+
strokeLinecap: "round",
|
|
474
|
+
strokeLinejoin: "round"
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
}
|
|
478
|
+
)
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
};
|
|
485
|
+
function GenAI(renderFn) {
|
|
486
|
+
const GenAIComponent = (props = {}) => {
|
|
487
|
+
const maxHeight = useMaxHeight();
|
|
488
|
+
const colorScheme = useColorScheme();
|
|
489
|
+
const { className, maxWidth = 800, ...rest } = props;
|
|
490
|
+
const containerClasses = clsx.clsx(
|
|
491
|
+
"sp-genai-app",
|
|
492
|
+
"sp-antialiased",
|
|
493
|
+
colorScheme && `sp-theme-${colorScheme}`,
|
|
494
|
+
className
|
|
495
|
+
);
|
|
496
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
497
|
+
"div",
|
|
498
|
+
{
|
|
499
|
+
className: containerClasses,
|
|
500
|
+
style: {
|
|
501
|
+
maxWidth: `${maxWidth}px`,
|
|
502
|
+
maxHeight: maxHeight ? `${maxHeight}px` : void 0
|
|
503
|
+
},
|
|
504
|
+
...rest,
|
|
505
|
+
children: renderFn({ maxHeight, colorScheme })
|
|
506
|
+
}
|
|
507
|
+
);
|
|
508
|
+
};
|
|
509
|
+
GenAIComponent.displayName = "GenAI";
|
|
510
|
+
return GenAIComponent;
|
|
511
|
+
}
|
|
512
|
+
function ChatGPTSimulator({
|
|
513
|
+
children,
|
|
514
|
+
displayMode: initialDisplayMode = "inline",
|
|
515
|
+
colorScheme: initialColorScheme = "dark",
|
|
516
|
+
toolInput = {},
|
|
517
|
+
toolOutput = null,
|
|
518
|
+
widgetState: initialWidgetState = null,
|
|
519
|
+
userMessage = "Show me some recommendations",
|
|
520
|
+
showControls = true,
|
|
521
|
+
uiSimulations,
|
|
522
|
+
initialUISimulation
|
|
523
|
+
}) {
|
|
524
|
+
const [displayMode, setDisplayMode] = react.useState(initialDisplayMode);
|
|
525
|
+
const [widgetState, setWidgetStateInternal] = react.useState(
|
|
526
|
+
initialWidgetState
|
|
527
|
+
);
|
|
528
|
+
const [bodyWidth, setBodyWidth] = react.useState("100%");
|
|
529
|
+
const [selectedUISimulation, setSelectedUISimulation] = react.useState(
|
|
530
|
+
initialUISimulation || uiSimulations?.[0] || ""
|
|
531
|
+
);
|
|
532
|
+
const [viewportHeight, setViewportHeight] = react.useState(window.innerHeight);
|
|
533
|
+
const [colorScheme, setColorScheme] = react.useState(initialColorScheme);
|
|
534
|
+
react.useEffect(() => {
|
|
535
|
+
const handleSetGlobals = (event) => {
|
|
536
|
+
const customEvent = event;
|
|
537
|
+
if (customEvent.detail?.globals?.colorScheme) {
|
|
538
|
+
setColorScheme(customEvent.detail.globals.colorScheme);
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobals);
|
|
542
|
+
return () => window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobals);
|
|
543
|
+
}, []);
|
|
544
|
+
react.useEffect(() => {
|
|
545
|
+
const handleResize = () => {
|
|
546
|
+
setViewportHeight(window.innerHeight);
|
|
547
|
+
};
|
|
548
|
+
window.addEventListener("resize", handleResize);
|
|
549
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
550
|
+
}, []);
|
|
551
|
+
react.useEffect(() => {
|
|
552
|
+
const inputBarHeight = 80;
|
|
553
|
+
const openaiGlobals = {
|
|
554
|
+
colorScheme,
|
|
555
|
+
displayMode,
|
|
556
|
+
locale: "en-US",
|
|
557
|
+
maxHeight: displayMode === "fullscreen" ? viewportHeight - inputBarHeight : 600,
|
|
558
|
+
userAgent: {
|
|
559
|
+
device: { type: "desktop" },
|
|
560
|
+
capabilities: { hover: true, touch: false }
|
|
561
|
+
},
|
|
562
|
+
safeArea: {
|
|
563
|
+
insets: { top: 0, bottom: 0, left: 0, right: 0 }
|
|
564
|
+
},
|
|
565
|
+
toolInput,
|
|
566
|
+
toolOutput,
|
|
567
|
+
toolResponseMetadata: null,
|
|
568
|
+
widgetState,
|
|
569
|
+
setWidgetState: async (state) => {
|
|
570
|
+
console.log("[ChatGPT Simulator] setWidgetState called:", state);
|
|
571
|
+
setWidgetStateInternal(state);
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
const openaiAPI = {
|
|
575
|
+
callTool: async (name, args) => {
|
|
576
|
+
console.log("[ChatGPT Simulator] callTool called:", name, args);
|
|
577
|
+
return { result: "Mock tool result" };
|
|
578
|
+
},
|
|
579
|
+
sendFollowUpMessage: async (args) => {
|
|
580
|
+
console.log("[ChatGPT Simulator] sendFollowUpMessage called:", args);
|
|
581
|
+
},
|
|
582
|
+
openExternal: (payload) => {
|
|
583
|
+
console.log("[ChatGPT Simulator] openExternal called:", payload);
|
|
584
|
+
window.open(payload.href, "_blank");
|
|
585
|
+
},
|
|
586
|
+
requestDisplayMode: async (args) => {
|
|
587
|
+
console.log("[ChatGPT Simulator] requestDisplayMode called:", args);
|
|
588
|
+
setDisplayMode(args.mode);
|
|
589
|
+
return { mode: args.mode };
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
window.openai = { ...openaiGlobals, ...openaiAPI };
|
|
593
|
+
window.dispatchEvent(
|
|
594
|
+
new CustomEvent(SET_GLOBALS_EVENT_TYPE, {
|
|
595
|
+
detail: { globals: openaiGlobals }
|
|
596
|
+
})
|
|
597
|
+
);
|
|
598
|
+
return () => {
|
|
599
|
+
delete window.openai;
|
|
600
|
+
};
|
|
601
|
+
}, [colorScheme, displayMode, toolInput, toolOutput, widgetState, viewportHeight]);
|
|
602
|
+
react.useEffect(() => {
|
|
603
|
+
if (window.openai) {
|
|
604
|
+
const inputBarHeight = 80;
|
|
605
|
+
const calculatedMaxHeight = displayMode === "fullscreen" ? viewportHeight - inputBarHeight : 600;
|
|
606
|
+
window.openai.colorScheme = colorScheme;
|
|
607
|
+
window.openai.displayMode = displayMode;
|
|
608
|
+
window.openai.widgetState = widgetState;
|
|
609
|
+
window.openai.maxHeight = calculatedMaxHeight;
|
|
610
|
+
window.dispatchEvent(
|
|
611
|
+
new CustomEvent(SET_GLOBALS_EVENT_TYPE, {
|
|
612
|
+
detail: {
|
|
613
|
+
globals: { colorScheme, displayMode, widgetState, maxHeight: calculatedMaxHeight }
|
|
614
|
+
}
|
|
615
|
+
})
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
}, [colorScheme, displayMode, widgetState, viewportHeight]);
|
|
619
|
+
const isFullscreen = displayMode === "fullscreen";
|
|
620
|
+
const renderChildren = () => {
|
|
621
|
+
if (typeof children === "function") {
|
|
622
|
+
return children(selectedUISimulation);
|
|
623
|
+
}
|
|
624
|
+
return children;
|
|
625
|
+
};
|
|
626
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `chatgpt-simulator chatgpt-simulator--${colorScheme}`, "data-display-mode": displayMode, children: [
|
|
627
|
+
showControls && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatgpt-simulator__sidebar", children: [
|
|
628
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__sidebar-header", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Controls" }) }),
|
|
629
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatgpt-simulator__control-group", children: [
|
|
630
|
+
uiSimulations && uiSimulations.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
631
|
+
"App UI",
|
|
632
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
633
|
+
"select",
|
|
634
|
+
{
|
|
635
|
+
value: selectedUISimulation,
|
|
636
|
+
onChange: (e) => setSelectedUISimulation(e.target.value),
|
|
637
|
+
children: uiSimulations.map((simulation) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: simulation, children: simulation }, simulation))
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
642
|
+
"Color Scheme",
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsxs("select", { value: colorScheme, onChange: (e) => setColorScheme(e.target.value), children: [
|
|
644
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "light", children: "Light" }),
|
|
645
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "dark", children: "Dark" })
|
|
646
|
+
] })
|
|
647
|
+
] }),
|
|
648
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
649
|
+
"Display Mode",
|
|
650
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
651
|
+
"select",
|
|
652
|
+
{
|
|
653
|
+
value: displayMode,
|
|
654
|
+
onChange: (e) => setDisplayMode(e.target.value),
|
|
655
|
+
children: [
|
|
656
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "inline", children: "Inline" }),
|
|
657
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fullscreen", children: "Fullscreen" }),
|
|
658
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "pip", children: "Picture-in-Picture" })
|
|
659
|
+
]
|
|
660
|
+
}
|
|
661
|
+
)
|
|
662
|
+
] }),
|
|
663
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
664
|
+
"Body Width",
|
|
665
|
+
/* @__PURE__ */ jsxRuntime.jsxs("select", { value: bodyWidth, onChange: (e) => setBodyWidth(e.target.value), children: [
|
|
666
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "100%", children: "100% (Full)" }),
|
|
667
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "1024px", children: "1024px (Laptop)" }),
|
|
668
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "768px", children: "768px (Tablet)" }),
|
|
669
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "425px", children: "425px (Mobile L)" }),
|
|
670
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "320px", children: "320px (Mobile S)" })
|
|
671
|
+
] })
|
|
672
|
+
] })
|
|
673
|
+
] })
|
|
674
|
+
] }),
|
|
675
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatgpt-simulator__main", style: { width: bodyWidth, maxWidth: bodyWidth }, children: [
|
|
676
|
+
isFullscreen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
677
|
+
"button",
|
|
678
|
+
{
|
|
679
|
+
className: "chatgpt-simulator__close-button",
|
|
680
|
+
onClick: () => setDisplayMode("inline"),
|
|
681
|
+
"aria-label": "Exit fullscreen",
|
|
682
|
+
type: "button",
|
|
683
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5L15 15", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
684
|
+
}
|
|
685
|
+
),
|
|
686
|
+
!isFullscreen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__header", children: /* @__PURE__ */ jsxRuntime.jsx("h1", { children: "ChatGPT" }) }),
|
|
687
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "[--thread-content-max-width:40rem] thread-lg:[--thread-content-max-width:48rem] mx-auto max-w-[var(--thread-content-max-width)] flex-1 relative flex w-full min-w-0 flex-col", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-w-full flex-col grow", children: [
|
|
688
|
+
!isFullscreen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
689
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__message chatgpt-simulator__message--user", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__message-content", children: userMessage }) }),
|
|
690
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-8 relative flex w-full flex-col items-end gap-2 text-start break-words whitespace-normal", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full flex-col gap-1 empty:hidden first:pt-[1px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full break-words", children: [
|
|
691
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "chatgpt-simulator__app-title", children: [
|
|
692
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "chatgpt-simulator__app-icon", children: "\u2708\uFE0F" }),
|
|
693
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "chatgpt-simulator__app-name", children: "Splorin" })
|
|
694
|
+
] }),
|
|
695
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__component-slot", children: renderChildren() })
|
|
696
|
+
] }) }) })
|
|
697
|
+
] }),
|
|
698
|
+
isFullscreen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__fullscreen-content", children: renderChildren() })
|
|
699
|
+
] }) }),
|
|
700
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "chatgpt-simulator__input-container", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
701
|
+
"input",
|
|
702
|
+
{
|
|
703
|
+
type: "text",
|
|
704
|
+
className: "chatgpt-simulator__input",
|
|
705
|
+
placeholder: "Message ChatGPT",
|
|
706
|
+
disabled: true
|
|
707
|
+
}
|
|
708
|
+
) })
|
|
709
|
+
] })
|
|
710
|
+
] });
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
exports.Button = Button;
|
|
714
|
+
exports.Card = Card;
|
|
715
|
+
exports.Carousel = Carousel;
|
|
716
|
+
exports.ChatGPTSimulator = ChatGPTSimulator;
|
|
717
|
+
exports.GenAI = GenAI;
|
|
718
|
+
exports.PlatformProvider = PlatformProvider;
|
|
719
|
+
exports.chatgptPlatform = chatgptPlatform;
|
|
720
|
+
exports.createPlatformRegistry = createPlatformRegistry;
|
|
721
|
+
exports.useColorScheme = useColorScheme;
|
|
722
|
+
exports.useDisplayMode = useDisplayMode;
|
|
723
|
+
exports.useMaxHeight = useMaxHeight;
|
|
724
|
+
exports.usePlatform = usePlatform;
|
|
725
|
+
exports.usePlatformGlobal = usePlatformGlobal;
|
|
726
|
+
exports.useRequestDisplayMode = useRequestDisplayMode;
|
|
727
|
+
exports.useWidgetProps = useWidgetProps;
|
|
728
|
+
exports.useWidgetState = useWidgetState;
|
|
729
|
+
//# sourceMappingURL=index.cjs.map
|
|
730
|
+
//# sourceMappingURL=index.cjs.map
|