@nitrostack/widgets 1.0.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 +136 -0
- package/dist/hooks/index.d.ts +7 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/use-display-mode.d.ts +11 -0
- package/dist/hooks/use-display-mode.d.ts.map +1 -0
- package/dist/hooks/use-display-mode.js +12 -0
- package/dist/hooks/use-max-height.d.ts +10 -0
- package/dist/hooks/use-max-height.d.ts.map +1 -0
- package/dist/hooks/use-max-height.js +12 -0
- package/dist/hooks/use-openai-global.d.ts +12 -0
- package/dist/hooks/use-openai-global.d.ts.map +1 -0
- package/dist/hooks/use-openai-global.js +31 -0
- package/dist/hooks/use-theme.d.ts +10 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/hooks/use-theme.js +11 -0
- package/dist/hooks/use-widget-state.d.ts +18 -0
- package/dist/hooks/use-widget-state.d.ts.map +1 -0
- package/dist/hooks/use-widget-state.js +26 -0
- package/dist/hooks/useWidgetSDK.d.ts +49 -0
- package/dist/hooks/useWidgetSDK.d.ts.map +1 -0
- package/dist/hooks/useWidgetSDK.js +69 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/metadata.d.ts +53 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +28 -0
- package/dist/runtime/WidgetLayout.d.ts +32 -0
- package/dist/runtime/WidgetLayout.d.ts.map +1 -0
- package/dist/runtime/WidgetLayout.js +143 -0
- package/dist/runtime/widget-polyfill.d.ts +2 -0
- package/dist/runtime/widget-polyfill.d.ts.map +1 -0
- package/dist/runtime/widget-polyfill.js +27 -0
- package/dist/sdk.d.ts +117 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +232 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/utils/media-queries.d.ts +34 -0
- package/dist/utils/media-queries.d.ts.map +1 -0
- package/dist/utils/media-queries.js +41 -0
- package/dist/withToolData.d.ts +19 -0
- package/dist/withToolData.d.ts.map +1 -0
- package/dist/withToolData.js +227 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# @nitrostack/widgets
|
|
2
|
+
|
|
3
|
+
Lightweight widget utilities for building interactive UI components in NitroStack MCP servers.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @nitrostack/widgets
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **OpenAI ChatGPT Compatible** - Works with OpenAI's widget format
|
|
14
|
+
- **React Hooks** - Easy-to-use hooks for widget state management
|
|
15
|
+
- **Theme Support** - Automatic dark/light mode detection
|
|
16
|
+
- **Type Safe** - Full TypeScript support
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { useWidgetSDK, useTheme, WidgetLayout } from '@nitrostack/widgets';
|
|
22
|
+
|
|
23
|
+
export default function MyWidget() {
|
|
24
|
+
const sdk = useWidgetSDK();
|
|
25
|
+
const { isDark } = useTheme();
|
|
26
|
+
|
|
27
|
+
// Access tool output data
|
|
28
|
+
const data = sdk.getOutput();
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<WidgetLayout>
|
|
32
|
+
<div style={{ background: isDark ? '#1a1a1a' : '#ffffff' }}>
|
|
33
|
+
<h1>Hello from Widget!</h1>
|
|
34
|
+
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
35
|
+
</div>
|
|
36
|
+
</WidgetLayout>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Hooks
|
|
42
|
+
|
|
43
|
+
### `useWidgetSDK()`
|
|
44
|
+
|
|
45
|
+
Main SDK hook providing access to all widget functionality:
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
const sdk = useWidgetSDK();
|
|
49
|
+
|
|
50
|
+
// Get tool output data
|
|
51
|
+
const data = sdk.getOutput();
|
|
52
|
+
|
|
53
|
+
// Call another tool
|
|
54
|
+
const result = await sdk.callTool('tool_name', { param: 'value' });
|
|
55
|
+
|
|
56
|
+
// Update widget state
|
|
57
|
+
sdk.setState({ count: 1 });
|
|
58
|
+
const state = sdk.getState();
|
|
59
|
+
|
|
60
|
+
// Theme
|
|
61
|
+
const isDark = sdk.isDarkMode();
|
|
62
|
+
|
|
63
|
+
// Display mode
|
|
64
|
+
const mode = sdk.getDisplayMode(); // 'split' | 'fullscreen'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `useTheme()`
|
|
68
|
+
|
|
69
|
+
Access current theme:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
const { isDark, theme } = useTheme();
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `useWidgetState(initialState)`
|
|
76
|
+
|
|
77
|
+
Persistent widget state:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
const [state, setState] = useWidgetState({ count: 0 });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `useMaxHeight()`
|
|
84
|
+
|
|
85
|
+
Get maximum available height for the widget:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
const maxHeight = useMaxHeight(); // e.g., '600px'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `useDisplayMode()`
|
|
92
|
+
|
|
93
|
+
Get current display mode:
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
const displayMode = useDisplayMode(); // 'split' | 'fullscreen'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Components
|
|
100
|
+
|
|
101
|
+
### `WidgetLayout`
|
|
102
|
+
|
|
103
|
+
Wrapper component that handles theme and polyfills:
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { WidgetLayout } from '@nitrostack/widgets';
|
|
107
|
+
|
|
108
|
+
export default function Page() {
|
|
109
|
+
return (
|
|
110
|
+
<WidgetLayout>
|
|
111
|
+
<YourWidgetContent />
|
|
112
|
+
</WidgetLayout>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Utilities
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import {
|
|
121
|
+
prefersReducedMotion,
|
|
122
|
+
isPrimarilyTouchDevice,
|
|
123
|
+
isHoverAvailable,
|
|
124
|
+
prefersDarkColorScheme,
|
|
125
|
+
} from '@nitrostack/widgets';
|
|
126
|
+
|
|
127
|
+
// Check user preferences
|
|
128
|
+
if (prefersReducedMotion()) {
|
|
129
|
+
// Disable animations
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
Apache-2.0
|
|
136
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { useOpenAiGlobal } from './use-openai-global.js';
|
|
2
|
+
export { useWidgetState } from './use-widget-state.js';
|
|
3
|
+
export { useTheme } from './use-theme.js';
|
|
4
|
+
export { useMaxHeight } from './use-max-height.js';
|
|
5
|
+
export { useDisplayMode } from './use-display-mode.js';
|
|
6
|
+
export { useWidgetSDK } from './useWidgetSDK.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useOpenAiGlobal } from './use-openai-global.js';
|
|
2
|
+
export { useWidgetState } from './use-widget-state.js';
|
|
3
|
+
export { useTheme } from './use-theme.js';
|
|
4
|
+
export { useMaxHeight } from './use-max-height.js';
|
|
5
|
+
export { useDisplayMode } from './use-display-mode.js';
|
|
6
|
+
export { useWidgetSDK } from './useWidgetSDK.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type DisplayMode } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to get the current display mode
|
|
4
|
+
* Returns 'inline' | 'pip' | 'fullscreen'
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const displayMode = useDisplayMode();
|
|
8
|
+
* const isFullscreen = displayMode === 'fullscreen';
|
|
9
|
+
*/
|
|
10
|
+
export declare const useDisplayMode: () => DisplayMode | null;
|
|
11
|
+
//# sourceMappingURL=use-display-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-display-mode.d.ts","sourceRoot":"","sources":["../../src/hooks/use-display-mode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAO,WAAW,GAAG,IAE/C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useOpenAiGlobal } from './use-openai-global.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to get the current display mode
|
|
4
|
+
* Returns 'inline' | 'pip' | 'fullscreen'
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const displayMode = useDisplayMode();
|
|
8
|
+
* const isFullscreen = displayMode === 'fullscreen';
|
|
9
|
+
*/
|
|
10
|
+
export const useDisplayMode = () => {
|
|
11
|
+
return useOpenAiGlobal('displayMode');
|
|
12
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook to get the maximum available height for the widget
|
|
3
|
+
* Useful for responsive layouts
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const maxHeight = useMaxHeight();
|
|
7
|
+
* return <div style={{ maxHeight }}>{content}</div>;
|
|
8
|
+
*/
|
|
9
|
+
export declare const useMaxHeight: () => number | null;
|
|
10
|
+
//# sourceMappingURL=use-max-height.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-max-height.d.ts","sourceRoot":"","sources":["../../src/hooks/use-max-height.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,QAAO,MAAM,GAAG,IAExC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useOpenAiGlobal } from './use-openai-global.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to get the maximum available height for the widget
|
|
4
|
+
* Useful for responsive layouts
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const maxHeight = useMaxHeight();
|
|
8
|
+
* return <div style={{ maxHeight }}>{content}</div>;
|
|
9
|
+
*/
|
|
10
|
+
export const useMaxHeight = () => {
|
|
11
|
+
return useOpenAiGlobal('maxHeight');
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type OpenAiGlobals } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to subscribe to a specific property of window.openai
|
|
4
|
+
* Automatically re-renders when the property changes
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const theme = useOpenAiGlobal('theme');
|
|
8
|
+
* const locale = useOpenAiGlobal('locale');
|
|
9
|
+
* const maxHeight = useOpenAiGlobal('maxHeight');
|
|
10
|
+
*/
|
|
11
|
+
export declare function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K] | null;
|
|
12
|
+
//# sourceMappingURL=use-openai-global.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-openai-global.d.ts","sourceRoot":"","sources":["../../src/hooks/use-openai-global.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,KAAK,aAAa,EACrB,MAAM,aAAa,CAAC;AAErB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,aAAa,EACzD,GAAG,EAAE,CAAC,GACP,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CA2BzB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
import { SET_GLOBALS_EVENT_TYPE, } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hook to subscribe to a specific property of window.openai
|
|
5
|
+
* Automatically re-renders when the property changes
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const theme = useOpenAiGlobal('theme');
|
|
9
|
+
* const locale = useOpenAiGlobal('locale');
|
|
10
|
+
* const maxHeight = useOpenAiGlobal('maxHeight');
|
|
11
|
+
*/
|
|
12
|
+
export function useOpenAiGlobal(key) {
|
|
13
|
+
return useSyncExternalStore((onChange) => {
|
|
14
|
+
if (typeof window === 'undefined') {
|
|
15
|
+
return () => { };
|
|
16
|
+
}
|
|
17
|
+
const handleSetGlobal = (event) => {
|
|
18
|
+
const value = event.detail.globals[key];
|
|
19
|
+
if (value === undefined) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
onChange();
|
|
23
|
+
};
|
|
24
|
+
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {
|
|
25
|
+
passive: true,
|
|
26
|
+
});
|
|
27
|
+
return () => {
|
|
28
|
+
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
29
|
+
};
|
|
30
|
+
}, () => typeof window !== 'undefined' ? window.openai?.[key] ?? null : null, () => typeof window !== 'undefined' ? window.openai?.[key] ?? null : null);
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Theme } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to get the current theme ('light' | 'dark')
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const theme = useTheme();
|
|
7
|
+
* const bgColor = theme === 'dark' ? '#000' : '#fff';
|
|
8
|
+
*/
|
|
9
|
+
export declare const useTheme: () => Theme | null;
|
|
10
|
+
//# sourceMappingURL=use-theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-theme.d.ts","sourceRoot":"","sources":["../../src/hooks/use-theme.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,QAAO,KAAK,GAAG,IAEnC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useOpenAiGlobal } from './use-openai-global.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to get the current theme ('light' | 'dark')
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const theme = useTheme();
|
|
7
|
+
* const bgColor = theme === 'dark' ? '#000' : '#fff';
|
|
8
|
+
*/
|
|
9
|
+
export const useTheme = () => {
|
|
10
|
+
return useOpenAiGlobal('theme');
|
|
11
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type SetStateAction } from 'react';
|
|
2
|
+
import type { UnknownObject } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Hook for managing widget state with automatic persistence
|
|
5
|
+
* State is scoped to the widget instance (message_id/widgetId)
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const [state, setState] = useWidgetState(() => ({
|
|
9
|
+
* selectedItems: [],
|
|
10
|
+
* viewMode: 'grid'
|
|
11
|
+
* }));
|
|
12
|
+
*
|
|
13
|
+
* // Update state (automatically persists)
|
|
14
|
+
* setState({ ...state, viewMode: 'list' });
|
|
15
|
+
*/
|
|
16
|
+
export declare function useWidgetState<T extends UnknownObject>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
|
|
17
|
+
export declare function useWidgetState<T extends UnknownObject>(defaultState?: T | (() => T | null) | null): readonly [T | null, (state: SetStateAction<T | null>) => void];
|
|
18
|
+
//# sourceMappingURL=use-widget-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-widget-state.d.ts","sourceRoot":"","sources":["../../src/hooks/use-widget-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAE9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,aAAa,EAClD,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAC5B,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACpD,wBAAgB,cAAc,CAAC,CAAC,SAAS,aAAa,EAClD,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,GAC3C,SAAS,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useOpenAiGlobal } from './use-openai-global.js';
|
|
3
|
+
export function useWidgetState(defaultState) {
|
|
4
|
+
const widgetStateFromWindow = useOpenAiGlobal('widgetState');
|
|
5
|
+
const [widgetState, _setWidgetState] = useState(() => {
|
|
6
|
+
if (widgetStateFromWindow != null) {
|
|
7
|
+
return widgetStateFromWindow;
|
|
8
|
+
}
|
|
9
|
+
return typeof defaultState === 'function'
|
|
10
|
+
? defaultState()
|
|
11
|
+
: defaultState ?? null;
|
|
12
|
+
});
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
_setWidgetState(widgetStateFromWindow);
|
|
15
|
+
}, [widgetStateFromWindow]);
|
|
16
|
+
const setWidgetState = useCallback((state) => {
|
|
17
|
+
_setWidgetState((prevState) => {
|
|
18
|
+
const newState = typeof state === 'function' ? state(prevState) : state;
|
|
19
|
+
if (newState != null && window.openai?.setWidgetState) {
|
|
20
|
+
window.openai.setWidgetState(newState);
|
|
21
|
+
}
|
|
22
|
+
return newState;
|
|
23
|
+
});
|
|
24
|
+
}, []);
|
|
25
|
+
return [widgetState, setWidgetState];
|
|
26
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hook to access the Widget SDK
|
|
3
|
+
*/
|
|
4
|
+
import { WidgetSDK } from '../sdk.js';
|
|
5
|
+
/**
|
|
6
|
+
* Hook to access the Widget SDK instance
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const { callTool, requestFullscreen, getTheme } = useWidgetSDK();
|
|
11
|
+
*
|
|
12
|
+
* // Call a tool
|
|
13
|
+
* await callTool('show_pizza_shop', { shopId: '123' });
|
|
14
|
+
*
|
|
15
|
+
* // Request fullscreen
|
|
16
|
+
* await requestFullscreen();
|
|
17
|
+
*
|
|
18
|
+
* // Get theme
|
|
19
|
+
* const theme = getTheme();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function useWidgetSDK(): {
|
|
23
|
+
sdk: WidgetSDK;
|
|
24
|
+
isReady: boolean;
|
|
25
|
+
setState: (state: Record<string, unknown>) => Promise<void>;
|
|
26
|
+
getState: () => Record<string, unknown> | null;
|
|
27
|
+
callTool: (name: string, args?: Record<string, unknown>) => Promise<import("../types.js").CallToolResponse>;
|
|
28
|
+
requestFullscreen: () => Promise<void>;
|
|
29
|
+
requestInline: () => Promise<void>;
|
|
30
|
+
requestPip: () => Promise<void>;
|
|
31
|
+
requestDisplayMode: (mode: import("../types.js").DisplayMode) => Promise<{
|
|
32
|
+
mode: import("../types.js").DisplayMode;
|
|
33
|
+
}>;
|
|
34
|
+
requestClose: () => void;
|
|
35
|
+
openExternal: (url: string) => void;
|
|
36
|
+
sendFollowUpMessage: (prompt: string) => Promise<void>;
|
|
37
|
+
getToolInput: <T = unknown>() => T | null;
|
|
38
|
+
getToolOutput: <T = unknown>() => T | null;
|
|
39
|
+
getOutput: <T = unknown>() => T | null;
|
|
40
|
+
getToolResponseMetadata: <T = unknown>() => T | null;
|
|
41
|
+
getTheme: () => "light" | "dark";
|
|
42
|
+
getMaxHeight: () => number;
|
|
43
|
+
getDisplayMode: () => import("../types.js").DisplayMode;
|
|
44
|
+
getUserAgent: () => import("../types.js").UserAgent | null;
|
|
45
|
+
getLocale: () => string;
|
|
46
|
+
getSafeArea: () => import("../types.js").SafeArea | null;
|
|
47
|
+
isDarkMode: () => boolean;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=useWidgetSDK.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWidgetSDK.d.ts","sourceRoot":"","sources":["../../src/hooks/useWidgetSDK.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAgB,SAAS,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;EAwD3B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React hook to access the Widget SDK
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
import { getWidgetSDK } from '../sdk.js';
|
|
6
|
+
/**
|
|
7
|
+
* Hook to access the Widget SDK instance
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const { callTool, requestFullscreen, getTheme } = useWidgetSDK();
|
|
12
|
+
*
|
|
13
|
+
* // Call a tool
|
|
14
|
+
* await callTool('show_pizza_shop', { shopId: '123' });
|
|
15
|
+
*
|
|
16
|
+
* // Request fullscreen
|
|
17
|
+
* await requestFullscreen();
|
|
18
|
+
*
|
|
19
|
+
* // Get theme
|
|
20
|
+
* const theme = getTheme();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function useWidgetSDK() {
|
|
24
|
+
const [sdk] = useState(() => getWidgetSDK());
|
|
25
|
+
const [isReady, setIsReady] = useState(sdk.isReady());
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (isReady)
|
|
28
|
+
return;
|
|
29
|
+
const checkReady = () => setIsReady(true);
|
|
30
|
+
window.addEventListener('openai:ready', checkReady);
|
|
31
|
+
// Check immediately in case it's already ready
|
|
32
|
+
if (sdk.isReady()) {
|
|
33
|
+
setIsReady(true);
|
|
34
|
+
}
|
|
35
|
+
return () => window.removeEventListener('openai:ready', checkReady);
|
|
36
|
+
}, [sdk, isReady]);
|
|
37
|
+
return {
|
|
38
|
+
// SDK instance
|
|
39
|
+
sdk,
|
|
40
|
+
isReady,
|
|
41
|
+
// State management
|
|
42
|
+
setState: sdk.setState.bind(sdk),
|
|
43
|
+
getState: sdk.getState.bind(sdk),
|
|
44
|
+
// Tool calling
|
|
45
|
+
callTool: sdk.callTool.bind(sdk),
|
|
46
|
+
// Display controls
|
|
47
|
+
requestFullscreen: sdk.requestFullscreen.bind(sdk),
|
|
48
|
+
requestInline: sdk.requestInline.bind(sdk),
|
|
49
|
+
requestPip: sdk.requestPip.bind(sdk),
|
|
50
|
+
requestDisplayMode: sdk.requestDisplayMode.bind(sdk),
|
|
51
|
+
requestClose: sdk.requestClose.bind(sdk),
|
|
52
|
+
// Navigation
|
|
53
|
+
openExternal: sdk.openExternal.bind(sdk),
|
|
54
|
+
sendFollowUpMessage: sdk.sendFollowUpMessage.bind(sdk),
|
|
55
|
+
// Data access
|
|
56
|
+
getToolInput: sdk.getToolInput.bind(sdk),
|
|
57
|
+
getToolOutput: sdk.getToolOutput.bind(sdk),
|
|
58
|
+
getOutput: sdk.getOutput.bind(sdk),
|
|
59
|
+
getToolResponseMetadata: sdk.getToolResponseMetadata.bind(sdk),
|
|
60
|
+
getTheme: sdk.getTheme.bind(sdk),
|
|
61
|
+
getMaxHeight: sdk.getMaxHeight.bind(sdk),
|
|
62
|
+
getDisplayMode: sdk.getDisplayMode.bind(sdk),
|
|
63
|
+
getUserAgent: sdk.getUserAgent.bind(sdk),
|
|
64
|
+
getLocale: sdk.getLocale.bind(sdk),
|
|
65
|
+
getSafeArea: sdk.getSafeArea.bind(sdk),
|
|
66
|
+
// Convenience
|
|
67
|
+
isDarkMode: sdk.isDarkMode.bind(sdk),
|
|
68
|
+
};
|
|
69
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NitroStack Widgets Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for building Next.js widgets
|
|
5
|
+
* that integrate with NitroStack tools and are compatible with OpenAI ChatGPT.
|
|
6
|
+
*/
|
|
7
|
+
export { WidgetSDK, getWidgetSDK } from './sdk.js';
|
|
8
|
+
export { WidgetLayout, type WidgetLayoutProps } from './runtime/WidgetLayout.js';
|
|
9
|
+
export { withToolData, type ToolOutputWrapper } from './withToolData.js';
|
|
10
|
+
export { defineWidgetMetadata, type WidgetMetadata, type WidgetExample, type WidgetManifest } from './metadata.js';
|
|
11
|
+
export type { UnknownObject, Theme, SafeAreaInsets, SafeArea, DeviceType, UserAgent, DisplayMode, RequestDisplayMode, CallToolResponse, CallTool, OpenAiGlobals, OpenAiAPI, SetGlobalsEvent, } from './types.js';
|
|
12
|
+
export { SET_GLOBALS_EVENT_TYPE } from './types.js';
|
|
13
|
+
export { useOpenAiGlobal, useWidgetState, useTheme, useMaxHeight, useDisplayMode, useWidgetSDK, } from './hooks/index.js';
|
|
14
|
+
export { prefersReducedMotion, isPrimarilyTouchDevice, isHoverAvailable, prefersDarkColorScheme, } from './utils/media-queries.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAGnH,YAAY,EACR,aAAa,EACb,KAAK,EACL,cAAc,EACd,QAAQ,EACR,UAAU,EACV,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,aAAa,EACb,SAAS,EACT,eAAe,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAGpD,OAAO,EACH,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,YAAY,GACf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACH,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,GACzB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NitroStack Widgets Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for building Next.js widgets
|
|
5
|
+
* that integrate with NitroStack tools and are compatible with OpenAI ChatGPT.
|
|
6
|
+
*/
|
|
7
|
+
// Widget SDK - Clean abstraction layer
|
|
8
|
+
export { WidgetSDK, getWidgetSDK } from './sdk.js';
|
|
9
|
+
export { WidgetLayout } from './runtime/WidgetLayout.js';
|
|
10
|
+
// Legacy exports (backward compatibility)
|
|
11
|
+
export { withToolData } from './withToolData.js';
|
|
12
|
+
export { defineWidgetMetadata } from './metadata.js';
|
|
13
|
+
export { SET_GLOBALS_EVENT_TYPE } from './types.js';
|
|
14
|
+
// OpenAI SDK compatibility - Hooks
|
|
15
|
+
export { useOpenAiGlobal, useWidgetState, useTheme, useMaxHeight, useDisplayMode, useWidgetSDK, // New clean SDK hook
|
|
16
|
+
} from './hooks/index.js';
|
|
17
|
+
// OpenAI SDK compatibility - Utilities
|
|
18
|
+
export { prefersReducedMotion, isPrimarilyTouchDevice, isHoverAvailable, prefersDarkColorScheme, } from './utils/media-queries.js';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Metadata System
|
|
3
|
+
*
|
|
4
|
+
* Allows frontend developers to define widget examples independently
|
|
5
|
+
* from backend tool definitions.
|
|
6
|
+
*/
|
|
7
|
+
export interface WidgetExample {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
data: Record<string, any>;
|
|
11
|
+
}
|
|
12
|
+
export interface WidgetMetadata {
|
|
13
|
+
/** Widget URI/route (e.g., '/calculator-result') */
|
|
14
|
+
uri: string;
|
|
15
|
+
/** Widget display name */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Widget description */
|
|
18
|
+
description: string;
|
|
19
|
+
/** Example data for preview/testing */
|
|
20
|
+
examples: WidgetExample[];
|
|
21
|
+
/** Optional tags for categorization */
|
|
22
|
+
tags?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Define widget metadata with type safety
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* export const metadata = defineWidgetMetadata({
|
|
30
|
+
* uri: '/calculator-result',
|
|
31
|
+
* name: 'Calculator Result',
|
|
32
|
+
* description: 'Displays calculation results',
|
|
33
|
+
* examples: [
|
|
34
|
+
* {
|
|
35
|
+
* name: 'Addition Example',
|
|
36
|
+
* description: 'Shows addition result',
|
|
37
|
+
* data: { result: 8, operation: 'add', a: 5, b: 3 }
|
|
38
|
+
* }
|
|
39
|
+
* ]
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function defineWidgetMetadata(metadata: WidgetMetadata): WidgetMetadata;
|
|
44
|
+
/**
|
|
45
|
+
* Widget manifest structure
|
|
46
|
+
* Generated during widget build process
|
|
47
|
+
*/
|
|
48
|
+
export interface WidgetManifest {
|
|
49
|
+
version: string;
|
|
50
|
+
widgets: WidgetMetadata[];
|
|
51
|
+
generatedAt: string;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IAEZ,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IAEb,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IAEpB,uCAAuC;IACvC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAE1B,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc,CAE7E;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Metadata System
|
|
3
|
+
*
|
|
4
|
+
* Allows frontend developers to define widget examples independently
|
|
5
|
+
* from backend tool definitions.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Define widget metadata with type safety
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* export const metadata = defineWidgetMetadata({
|
|
13
|
+
* uri: '/calculator-result',
|
|
14
|
+
* name: 'Calculator Result',
|
|
15
|
+
* description: 'Displays calculation results',
|
|
16
|
+
* examples: [
|
|
17
|
+
* {
|
|
18
|
+
* name: 'Addition Example',
|
|
19
|
+
* description: 'Shows addition result',
|
|
20
|
+
* data: { result: 8, operation: 'add', a: 5, b: 3 }
|
|
21
|
+
* }
|
|
22
|
+
* ]
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function defineWidgetMetadata(metadata) {
|
|
27
|
+
return metadata;
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget Layout Component
|
|
3
|
+
*
|
|
4
|
+
* Handles all the RPC setup and window.openai initialization automatically.
|
|
5
|
+
* Developers just wrap their widget content with this component.
|
|
6
|
+
*/
|
|
7
|
+
import { type ReactNode } from 'react';
|
|
8
|
+
export interface WidgetLayoutProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Optional callback when SDK is ready
|
|
12
|
+
*/
|
|
13
|
+
onReady?: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Widget Layout component that sets up the widget runtime
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* export default function RootLayout({ children }) {
|
|
21
|
+
* return (
|
|
22
|
+
* <html lang="en">
|
|
23
|
+
* <body>
|
|
24
|
+
* <WidgetLayout>{children}</WidgetLayout>
|
|
25
|
+
* </body>
|
|
26
|
+
* </html>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function WidgetLayout({ children, onReady }: WidgetLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
//# sourceMappingURL=WidgetLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetLayout.d.ts","sourceRoot":"","sources":["../../src/runtime/WidgetLayout.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAc,EAAa,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,iBAAiB,2CA8IpE"}
|