@noodleseed/one 0.104.2 → 0.105.1
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/react-widget-build.d.ts.map +1 -1
- package/dist/react-widget-build.js +53 -2
- package/dist/react-widget-build.js.map +1 -1
- package/dist/widget-focused-template.d.ts +2 -2
- package/dist/widget-focused-template.d.ts.map +1 -1
- package/dist/widget-focused-template.js +7 -3
- package/dist/widget-focused-template.js.map +1 -1
- package/dist/widget-showcase-template.d.ts +2 -2
- package/dist/widget-showcase-template.d.ts.map +1 -1
- package/dist/widget-showcase-template.js +8 -4
- package/dist/widget-showcase-template.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +2 -2
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +5 -4
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/form-components.d.ts +10 -1
- package/node_modules/@noodle-borg/authoring/dist/react/form-components.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/form-components.js +11 -0
- package/node_modules/@noodle-borg/authoring/dist/react/form-components.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts +3 -0
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.js +10 -1
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts +2 -2
- package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/index.js +2 -2
- package/node_modules/@noodle-borg/authoring/dist/react/index.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.js +1 -0
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/widget/action-wiring-bootstrap.d.ts +1 -1
- package/node_modules/@noodle-borg/protocol/dist/widget/action-wiring-bootstrap.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/widget/action-wiring-bootstrap.js +1 -6
- package/node_modules/@noodle-borg/protocol/dist/widget/action-wiring-bootstrap.js.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/widget/bootstrap.js +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.d.ts.map +1 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +5 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-widget-build.d.ts","sourceRoot":"","sources":["../src/react-widget-build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"react-widget-build.d.ts","sourceRoot":"","sources":["../src/react-widget-build.ts"],"names":[],"mappings":"AA2BA,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC,OAAO,CAAC,MAAM,CAAC,CAsBjB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
|
-
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import ts from 'typescript';
|
|
6
7
|
export async function buildReactWidgetViews(manifestJson, options) {
|
|
7
8
|
const manifest = JSON.parse(manifestJson);
|
|
8
9
|
const widgets = manifest.widgets ?? [];
|
|
@@ -40,7 +41,7 @@ async function buildReactWidgetHtml(input) {
|
|
|
40
41
|
mode: 'production',
|
|
41
42
|
define: { 'process.env.NODE_ENV': JSON.stringify('production') },
|
|
42
43
|
esbuild: { jsxDev: false },
|
|
43
|
-
plugins: [reactSourceAliasPlugin()],
|
|
44
|
+
plugins: [portableReactWidgetAuthoringPlugin(input.rootDir), reactSourceAliasPlugin()],
|
|
44
45
|
resolve: {
|
|
45
46
|
alias: [
|
|
46
47
|
{ find: /^react$/, replacement: resolvePackageModule('react', input.rootDir) },
|
|
@@ -211,6 +212,56 @@ function reactSourceAliasPlugin() {
|
|
|
211
212
|
},
|
|
212
213
|
};
|
|
213
214
|
}
|
|
215
|
+
function portableReactWidgetAuthoringPlugin(rootDir) {
|
|
216
|
+
const projectRoot = resolve(rootDir);
|
|
217
|
+
return {
|
|
218
|
+
name: 'noodle-portable-react-widget-authoring',
|
|
219
|
+
enforce: 'pre',
|
|
220
|
+
transform(source, id) {
|
|
221
|
+
const filename = id.split('?', 1)[0];
|
|
222
|
+
if (filename === undefined || !/\.[cm]?[jt]sx$/i.test(filename))
|
|
223
|
+
return null;
|
|
224
|
+
const projectPath = relative(projectRoot, filename);
|
|
225
|
+
if (projectPath.startsWith('..') || isAbsolute(projectPath))
|
|
226
|
+
return null;
|
|
227
|
+
const sourceFile = ts.createSourceFile(filename, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
228
|
+
let unsafeForm;
|
|
229
|
+
let implicitButton;
|
|
230
|
+
const visit = (node) => {
|
|
231
|
+
if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
232
|
+
const tagName = node.tagName.getText(sourceFile);
|
|
233
|
+
if (unsafeForm === undefined && tagName === 'form') {
|
|
234
|
+
const attributes = node.attributes.properties.filter(ts.isJsxAttribute);
|
|
235
|
+
const attributeNames = new Set(attributes.map((attribute) => attribute.name.getText(sourceFile)));
|
|
236
|
+
if (!attributeNames.has('onSubmit') ||
|
|
237
|
+
['action', 'method', 'target'].some((name) => attributeNames.has(name))) {
|
|
238
|
+
unsafeForm = node;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (implicitButton === undefined &&
|
|
243
|
+
tagName === 'button' &&
|
|
244
|
+
!node.attributes.properties.some((attribute) => ts.isJsxAttribute(attribute) && attribute.name.getText(sourceFile) === 'type')) {
|
|
245
|
+
implicitButton = node;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
ts.forEachChild(node, visit);
|
|
250
|
+
};
|
|
251
|
+
visit(sourceFile);
|
|
252
|
+
const invalidNode = unsafeForm ?? implicitButton;
|
|
253
|
+
if (invalidNode === undefined)
|
|
254
|
+
return null;
|
|
255
|
+
const position = sourceFile.getLineAndCharacterOfPosition(invalidNode.getStart(sourceFile));
|
|
256
|
+
if (unsafeForm === undefined) {
|
|
257
|
+
throw new Error(`${projectPath}:${position.line + 1}:${position.character + 1} must give every native <button> an explicit type="button" or type="submit". ` +
|
|
258
|
+
'Use type="button" for standalone MCP App actions and type="submit" only inside a guarded form.');
|
|
259
|
+
}
|
|
260
|
+
throw new Error(`${projectPath}:${position.line + 1}:${position.character + 1} must use the portable <Form> component or give the native <form> an onSubmit handler that calls preventDefault() before an explicit MCP tool call. ` +
|
|
261
|
+
'Omit action, method, and target so the widget never relies on browser navigation.');
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
214
265
|
function packageRoot() {
|
|
215
266
|
return resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
216
267
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-widget-build.js","sourceRoot":"","sources":["../src/react-widget-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"react-widget-build.js","sourceRoot":"","sources":["../src/react-widget-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Focused production starter for `noodle init --template widget`. */
|
|
2
|
-
export declare const widgetFocusedHelpers = "import type { ServerDefinition } from '@noodleseed/one';\nimport { generateHelpers } from '@noodleseed/one/react';\n\nexport { Action, ActionBar, AsyncBoundary, Feedback, Field, Flow, Frame, Region, Select } from '@noodleseed/one/react';\nexport const { useCallTool, useLayout, useToolInfo, useViewState } = generateHelpers<ServerDefinition>();\n";
|
|
3
|
-
export declare const widgetFocusedView = "import '@noodleseed/one/react/styles.css';\nimport {\n Action,\n ActionBar,\n AsyncBoundary,\n Feedback,\n Field,\n Flow,\n Frame,\n Region,\n Select,\n useCallTool,\n useLayout,\n useToolInfo,\n useViewState,\n} from '../helpers.js';\n\ntype Preferences = { readonly channel: 'email' | 'sms'; readonly summary: string };\n\nfunction isPreferences(value: unknown): value is Preferences {\n if (value === null || typeof value !== 'object') return false;\n const candidate = value as Partial<Preferences>;\n return (\n (candidate.channel === 'email' || candidate.channel === 'sms') &&\n typeof candidate.summary === 'string' &&\n candidate.summary.trim().length > 0\n );\n}\n\nfunction preferenceStatus(status: 'loading' | 'error', message: string) {\n return (\n <Frame displayMode=\"auto\" title=\"Notification preferences\">\n <Feedback status={status}>{message}</Feedback>\n </Frame>\n );\n}\n\nexport default function PreferencesCard() {\n const layout = useLayout();\n const toolInfo = useToolInfo('show_preferences');\n const isPending = Object.keys(toolInfo).length === 0;\n const shown = isPreferences(toolInfo.structuredContent)\n ? toolInfo.structuredContent\n : undefined;\n const save = useCallTool('save_preferences');\n const [channel, setChannel] = useViewState('channel', shown?.channel ?? 'email');\n const saved = save.data?.structuredContent as Preferences | undefined;\n\n if (isPending) return preferenceStatus('loading', 'Loading preferences\u2026');\n if (toolInfo.isError) return preferenceStatus('error', 'Could not load preferences.');\n if (!shown) return preferenceStatus('error', 'The preference result was incomplete.');\n\n return (\n <Frame\n className={layout.theme === 'dark' ? 'dark' : ''}\n displayMode=\"auto\"\n title=\"Notification preferences\"\n subtitle=\"Choose where concise updates should arrive.\"\n data-llm={saved?.summary ?? `Notification channel: ${channel}`}\n >\n <Flow variant=\"stack\" density={layout.displayMode === 'inline' ? 'compact' : 'comfortable'}>\n <AsyncBoundary\n state={save}\n loading=\"Saving your preference\u2026\"\n error={(error) => `Could not save: ${error.message}`}\n >\n {saved?.summary ? <Feedback status=\"success\">{saved.summary}</Feedback> : null}\n <Region title=\"Delivery channel\" description=\"You can change this later.\">\n <Field label=\"Channel\" detail=\"Email is the safe default for this starter.\">\n <Select\n value={channel}\n onChange={(event) => setChannel(event.currentTarget.value as 'email' | 'sms')}\n options={[{ value: 'email', label: 'Email' }, { value: 'sms', label: 'SMS' }]}\n />\n </Field>\n </Region>\n <ActionBar>\n <Action\n variant=\"primary\"\n pending={save.isPending}\n pendingLabel=\"Saving\u2026\"\n onClick={() => save.callTool({ channel })}\n >\n Save preference\n </Action>\n {save.status === 'error' ? <Action onClick={save.reset}>Try again</Action> : null}\n </ActionBar>\n </AsyncBoundary>\n </Flow>\n </Frame>\n );\n}\n";
|
|
2
|
+
export declare const widgetFocusedHelpers = "import type { ServerDefinition } from '@noodleseed/one';\nimport { generateHelpers } from '@noodleseed/one/react';\n\nexport { Action, ActionBar, AsyncBoundary, Feedback, Field, Flow, Frame, Region, Select } from '@noodleseed/one/react';\nexport const { useCallTool, useLayout, useToolInfo, useViewState, useWidgetReady } = generateHelpers<ServerDefinition>();\n";
|
|
3
|
+
export declare const widgetFocusedView = "import '@noodleseed/one/react/styles.css';\nimport {\n Action,\n ActionBar,\n AsyncBoundary,\n Feedback,\n Field,\n Flow,\n Frame,\n Region,\n Select,\n useCallTool,\n useLayout,\n useToolInfo,\n useViewState,\n useWidgetReady,\n} from '../helpers.js';\n\ntype Preferences = { readonly channel: 'email' | 'sms'; readonly summary: string };\n\nfunction isPreferences(value: unknown): value is Preferences {\n if (value === null || typeof value !== 'object') return false;\n const candidate = value as Partial<Preferences>;\n return (\n (candidate.channel === 'email' || candidate.channel === 'sms') &&\n typeof candidate.summary === 'string' &&\n candidate.summary.trim().length > 0\n );\n}\n\nfunction preferenceStatus(status: 'loading' | 'error', message: string) {\n return (\n <Frame displayMode=\"auto\" title=\"Notification preferences\">\n <Feedback status={status}>{message}</Feedback>\n </Frame>\n );\n}\n\nexport default function PreferencesCard() {\n const ready = useWidgetReady();\n const layout = useLayout();\n const toolInfo = useToolInfo('show_preferences');\n const isPending = !ready || Object.keys(toolInfo).length === 0;\n const shown = isPreferences(toolInfo.structuredContent)\n ? toolInfo.structuredContent\n : undefined;\n const save = useCallTool('save_preferences');\n const [channel, setChannel] = useViewState('channel', shown?.channel ?? 'email');\n const saved = save.data?.structuredContent as Preferences | undefined;\n\n if (isPending) return preferenceStatus('loading', 'Loading preferences\u2026');\n if (toolInfo.isError) return preferenceStatus('error', 'Could not load preferences.');\n if (!shown) return preferenceStatus('error', 'The preference result was incomplete.');\n\n return (\n <Frame\n className={layout.theme === 'dark' ? 'dark' : ''}\n displayMode=\"auto\"\n title=\"Notification preferences\"\n subtitle=\"Choose where concise updates should arrive.\"\n data-llm={saved?.summary ?? `Notification channel: ${channel}`}\n >\n <Flow variant=\"stack\" density={layout.displayMode === 'inline' ? 'compact' : 'comfortable'}>\n <AsyncBoundary\n state={save}\n loading=\"Saving your preference\u2026\"\n error={(error) => `Could not save: ${error.message}`}\n >\n {saved?.summary ? <Feedback status=\"success\">{saved.summary}</Feedback> : null}\n <Region title=\"Delivery channel\" description=\"You can change this later.\">\n <Field label=\"Channel\" detail=\"Email is the safe default for this starter.\">\n <Select\n value={channel}\n onChange={(event) => setChannel(event.currentTarget.value as 'email' | 'sms')}\n options={[{ value: 'email', label: 'Email' }, { value: 'sms', label: 'SMS' }]}\n />\n </Field>\n </Region>\n <ActionBar>\n <Action\n type=\"button\"\n variant=\"primary\"\n disabled={!ready}\n pending={save.isPending}\n pendingLabel=\"Saving\u2026\"\n onClick={() => save.callTool({ channel })}\n >\n Save preference\n </Action>\n {save.status === 'error' ? <Action type=\"button\" onClick={save.reset}>Try again</Action> : null}\n </ActionBar>\n </AsyncBoundary>\n </Flow>\n </Frame>\n );\n}\n";
|
|
4
4
|
//# sourceMappingURL=widget-focused-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-focused-template.d.ts","sourceRoot":"","sources":["../src/widget-focused-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"widget-focused-template.d.ts","sourceRoot":"","sources":["../src/widget-focused-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,+WAKhC,CAAC;AAEF,eAAO,MAAM,iBAAiB,i6GAgG7B,CAAC"}
|
|
@@ -3,7 +3,7 @@ export const widgetFocusedHelpers = `import type { ServerDefinition } from '@noo
|
|
|
3
3
|
import { generateHelpers } from '@noodleseed/one/react';
|
|
4
4
|
|
|
5
5
|
export { Action, ActionBar, AsyncBoundary, Feedback, Field, Flow, Frame, Region, Select } from '@noodleseed/one/react';
|
|
6
|
-
export const { useCallTool, useLayout, useToolInfo, useViewState } = generateHelpers<ServerDefinition>();
|
|
6
|
+
export const { useCallTool, useLayout, useToolInfo, useViewState, useWidgetReady } = generateHelpers<ServerDefinition>();
|
|
7
7
|
`;
|
|
8
8
|
export const widgetFocusedView = `import '@noodleseed/one/react/styles.css';
|
|
9
9
|
import {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
useLayout,
|
|
21
21
|
useToolInfo,
|
|
22
22
|
useViewState,
|
|
23
|
+
useWidgetReady,
|
|
23
24
|
} from '../helpers.js';
|
|
24
25
|
|
|
25
26
|
type Preferences = { readonly channel: 'email' | 'sms'; readonly summary: string };
|
|
@@ -43,9 +44,10 @@ function preferenceStatus(status: 'loading' | 'error', message: string) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export default function PreferencesCard() {
|
|
47
|
+
const ready = useWidgetReady();
|
|
46
48
|
const layout = useLayout();
|
|
47
49
|
const toolInfo = useToolInfo('show_preferences');
|
|
48
|
-
const isPending = Object.keys(toolInfo).length === 0;
|
|
50
|
+
const isPending = !ready || Object.keys(toolInfo).length === 0;
|
|
49
51
|
const shown = isPreferences(toolInfo.structuredContent)
|
|
50
52
|
? toolInfo.structuredContent
|
|
51
53
|
: undefined;
|
|
@@ -83,14 +85,16 @@ export default function PreferencesCard() {
|
|
|
83
85
|
</Region>
|
|
84
86
|
<ActionBar>
|
|
85
87
|
<Action
|
|
88
|
+
type="button"
|
|
86
89
|
variant="primary"
|
|
90
|
+
disabled={!ready}
|
|
87
91
|
pending={save.isPending}
|
|
88
92
|
pendingLabel="Saving…"
|
|
89
93
|
onClick={() => save.callTool({ channel })}
|
|
90
94
|
>
|
|
91
95
|
Save preference
|
|
92
96
|
</Action>
|
|
93
|
-
{save.status === 'error' ? <Action onClick={save.reset}>Try again</Action> : null}
|
|
97
|
+
{save.status === 'error' ? <Action type="button" onClick={save.reset}>Try again</Action> : null}
|
|
94
98
|
</ActionBar>
|
|
95
99
|
</AsyncBoundary>
|
|
96
100
|
</Flow>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-focused-template.js","sourceRoot":"","sources":["../src/widget-focused-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;CAKnC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG
|
|
1
|
+
{"version":3,"file":"widget-focused-template.js","sourceRoot":"","sources":["../src/widget-focused-template.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;CAKnC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGhC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Generated source files for the developer-facing React design-system showcase. */
|
|
2
|
-
export declare const widgetShowcaseHelpers = "import type { ServerDefinition } from '@noodleseed/one';\nimport { generateHelpers } from '@noodleseed/one/react';\n\nexport type { CallToolState, HandoffController } from '@noodleseed/one/react';\nexport {\n Action,\n ActionBar,\n AppShell,\n AsyncBoundary,\n Avatar,\n AvatarGroup,\n Checkbox,\n ChoiceGroup,\n Collection,\n DataCard,\n DataList,\n EmptyState,\n ErrorState,\n ExpandButton,\n Fact,\n Feedback,\n Field,\n Flow,\n Frame,\n FullscreenShell,\n HandoffButton,\n InlineCard,\n InlineCarousel,\n InlineList,\n Input,\n LoadingState,\n Menu,\n Overlay,\n Popover,\n QuantityStepper,\n RadioGroup,\n Region,\n SegmentedControl,\n Select,\n ShellHeader,\n ShellNav,\n Slider,\n Spinner,\n StatusBadge,\n SubmitButton,\n Switch,\n Textarea,\n Tooltip,\n View,\n ViewNav,\n ViewStack,\n} from '@noodleseed/one/react';\n\nexport type AppType = ServerDefinition;\n\nexport const {\n useAppFlow,\n useCallTool,\n useHandoff,\n useLayout,\n useToolInfo,\n useViewState,\n} = generateHelpers<AppType>();\n";
|
|
2
|
+
export declare const widgetShowcaseHelpers = "import type { ServerDefinition } from '@noodleseed/one';\nimport { generateHelpers } from '@noodleseed/one/react';\n\nexport type { CallToolState, HandoffController } from '@noodleseed/one/react';\nexport {\n Action,\n ActionBar,\n AppShell,\n AsyncBoundary,\n Avatar,\n AvatarGroup,\n Checkbox,\n ChoiceGroup,\n Collection,\n DataCard,\n DataList,\n EmptyState,\n ErrorState,\n ExpandButton,\n Fact,\n Feedback,\n Field,\n Flow,\n Form,\n Frame,\n FullscreenShell,\n HandoffButton,\n InlineCard,\n InlineCarousel,\n InlineList,\n Input,\n LoadingState,\n Menu,\n Overlay,\n Popover,\n QuantityStepper,\n RadioGroup,\n Region,\n SegmentedControl,\n Select,\n ShellHeader,\n ShellNav,\n Slider,\n Spinner,\n StatusBadge,\n SubmitButton,\n Switch,\n Textarea,\n Tooltip,\n View,\n ViewNav,\n ViewStack,\n} from '@noodleseed/one/react';\n\nexport type AppType = ServerDefinition;\n\nexport const {\n useAppFlow,\n useCallTool,\n useHandoff,\n useLayout,\n useToolInfo,\n useViewState,\n useWidgetReady,\n} = generateHelpers<AppType>();\n";
|
|
3
3
|
export declare const widgetShowcaseView = "import '@noodleseed/one/react/styles.css';\nimport { useState } from 'react';\nimport {\n AppShell,\n Frame,\n FullscreenShell,\n SegmentedControl,\n StatusBadge,\n View,\n ViewNav,\n ViewStack,\n useAppFlow,\n useLayout,\n useToolInfo,\n} from '../helpers.js';\nimport {\n DataSection,\n FeedbackSection,\n FormsSection,\n FoundationsSection,\n LayoutSection,\n OverlaysSection,\n} from './showcase-sections.js';\n\ntype GalleryView = 'foundations' | 'forms' | 'data' | 'feedback' | 'overlays' | 'layouts';\ntype ShellPreview = 'frame' | 'app-shell' | 'fullscreen';\n\nconst galleryViews: readonly GalleryView[] = [\n 'foundations',\n 'forms',\n 'data',\n 'feedback',\n 'overlays',\n 'layouts',\n];\n\nconst navigation = [\n { view: 'foundations' as const, label: 'Foundations' },\n { view: 'forms' as const, label: 'Forms' },\n { view: 'data' as const, label: 'Data display' },\n { view: 'feedback' as const, label: 'Feedback' },\n { view: 'overlays' as const, label: 'Overlays' },\n { view: 'layouts' as const, label: 'Layouts' },\n];\n\ntype ShowcaseInfo = {\n readonly title?: string;\n readonly version?: string;\n readonly description?: string;\n};\n\nexport default function DesignSystemShowcase() {\n const layout = useLayout();\n const info = (useToolInfo('show_design_system').structuredContent ?? {}) as ShowcaseInfo;\n const flow = useAppFlow<GalleryView>({\n key: 'design_system_showcase',\n initialView: 'foundations',\n views: galleryViews,\n });\n const [shell, setShell] = useState<ShellPreview>('frame');\n\n const content = (\n <>\n <SegmentedControl\n aria-label=\"Preview shell\"\n name=\"preview-shell\"\n value={shell}\n onValueChange={(value) => setShell(value as ShellPreview)}\n options={[\n { value: 'frame', label: 'Frame' },\n { value: 'app-shell', label: 'AppShell' },\n { value: 'fullscreen', label: 'FullscreenShell' },\n ]}\n />\n\n <ViewNav\n activeView={flow.activeView}\n items={navigation}\n onNavigate={flow.navigate}\n variant=\"segmented\"\n aria-label=\"Design-system categories\"\n />\n\n <ViewStack flow={flow}>\n <View name=\"foundations\"><FoundationsSection /></View>\n <View name=\"forms\"><FormsSection /></View>\n <View name=\"data\"><DataSection /></View>\n <View name=\"feedback\"><FeedbackSection /></View>\n <View name=\"overlays\"><OverlaysSection /></View>\n <View name=\"layouts\"><LayoutSection /></View>\n </ViewStack>\n </>\n );\n\n const title = info.title ?? 'Noodle React design system';\n const subtitle = info.description ?? 'Interactive reference for every public component family.';\n const badge = <StatusBadge tone=\"info\">v{info.version ?? 'local'}</StatusBadge>;\n const common = {\n className: layout.theme === 'dark' ? 'dark' : '',\n 'data-llm': 'Developer-facing Noodle React design-system component showcase',\n };\n\n if (shell === 'app-shell') {\n return <AppShell {...common} title={title} subtitle={subtitle} badge={badge} displayMode=\"auto\" footer=\"Host-neutral MCP Apps components\">{content}</AppShell>;\n }\n if (shell === 'fullscreen') {\n return <FullscreenShell {...common} title={title} subtitle={subtitle} toolbar={badge} footer=\"Use the shell switcher to return to an inline preview.\">{content}</FullscreenShell>;\n }\n return <Frame {...common} title={title} subtitle={subtitle} status={badge} footer=\"Reference implementation, not a product UX prescription.\">{content}</Frame>;\n}\n";
|
|
4
|
-
export declare const widgetShowcaseSections = "import { useState } from 'react';\nimport {\n Action,\n ActionBar,\n AsyncBoundary,\n Avatar,\n AvatarGroup,\n Checkbox,\n ChoiceGroup,\n Collection,\n DataCard,\n DataList,\n EmptyState,\n ErrorState,\n ExpandButton,\n Fact,\n Feedback,\n Field,\n Flow,\n HandoffButton,\n InlineCard,\n InlineCarousel,\n InlineList,\n Input,\n LoadingState,\n Menu,\n Overlay,\n Popover,\n QuantityStepper,\n RadioGroup,\n Region,\n SegmentedControl,\n Select,\n ShellHeader,\n ShellNav,\n Slider,\n Spinner,\n StatusBadge,\n SubmitButton,\n Switch,\n Textarea,\n Tooltip,\n useCallTool,\n useHandoff,\n useViewState,\n} from '../helpers.js';\n\nexport function FoundationsSection() {\n const handoff = useHandoff();\n return (\n <Flow variant=\"stack\">\n <Region title=\"Actions\" description=\"Button, link, pending, disabled, handoff, and display-mode actions.\">\n <ActionBar>\n <Action variant=\"primary\">Primary</Action>\n <Action variant=\"secondary\">Secondary</Action>\n <Action variant=\"quiet\">Quiet</Action>\n <Action variant=\"danger\">Danger</Action>\n <Action pending pendingLabel=\"Working\u2026\">Pending</Action>\n <Action disabled>Disabled</Action>\n <Action as=\"a\" href=\"https://modelcontextprotocol.io\" external>External link</Action>\n <ExpandButton>Request fullscreen</ExpandButton>\n <HandoffButton handoff={handoff} target=\"https://example.com\" disabled>Handoff</HandoffButton>\n </ActionBar>\n </Region>\n\n <Region title=\"Status badges\" description=\"Semantic tones remain host-adaptive.\">\n <Flow variant=\"cluster\">\n <StatusBadge>Neutral</StatusBadge>\n <StatusBadge tone=\"success\">Success</StatusBadge>\n <StatusBadge tone=\"warning\">Warning</StatusBadge>\n <StatusBadge tone=\"danger\">Danger</StatusBadge>\n <StatusBadge tone=\"info\">Info</StatusBadge>\n </Flow>\n </Region>\n\n <Region title=\"Avatars\" description=\"Image-free fallbacks and overflow grouping.\">\n <AvatarGroup max={3}>\n <Avatar name=\"Ada Lovelace\" size={40} />\n <Avatar name=\"Grace Hopper\" size={40} />\n <Avatar name=\"Alan Turing\" size={40} />\n <Avatar name=\"Katherine Johnson\" size={40} />\n </AvatarGroup>\n </Region>\n </Flow>\n );\n}\n\nexport function FormsSection() {\n const demo = useCallTool('run_component_demo');\n const [email, setEmail] = useViewState('showcase_email', 'ada@example.com');\n const [notes, setNotes] = useState('Host-neutral controls with native semantics.');\n const [selectValue, setSelectValue] = useState('comfortable');\n const [radioValue, setRadioValue] = useState('daily');\n const [switchValue, setSwitchValue] = useState(true);\n const [sliderValue, setSliderValue] = useState(60);\n const [segmentValue, setSegmentValue] = useState('preview');\n const [choices, setChoices] = useState<readonly string[]>(['forms']);\n const [quantity, setQuantity] = useState(2);\n\n return (\n <form onSubmit={(event) => {\n event.preventDefault();\n void demo.callTool({ component: 'Form controls', value: email }).catch(() => undefined);\n }}>\n <Flow variant=\"stack\">\n <Region title=\"Text controls\" description=\"Labels, descriptions, errors, refs, and native form behavior.\">\n <Flow variant=\"grid\">\n <Field label=\"Email\" detail=\"Field connects every accessible relationship.\" required>\n <Input name=\"email\" type=\"email\" value={email} onChange={(event) => setEmail(event.currentTarget.value)} />\n </Field>\n <Field label=\"Notes\">\n <Textarea name=\"notes\" value={notes} onChange={(event) => setNotes(event.currentTarget.value)} />\n </Field>\n <Field label=\"Density\">\n <Select name=\"density\" value={selectValue} onChange={(event) => setSelectValue(event.currentTarget.value)} options={[\n { value: 'compact', label: 'Compact' },\n { value: 'comfortable', label: 'Comfortable' },\n ]} />\n </Field>\n </Flow>\n </Region>\n\n <Region title=\"Choice controls\" description=\"Native checkbox, radio, switch, range, and segmented interaction.\">\n <Flow variant=\"grid\">\n <Checkbox name=\"updates\" defaultChecked label=\"Checkbox\" />\n <Switch name=\"enabled\" checked={switchValue} onCheckedChange={setSwitchValue} label=\"Switch\" />\n <Field label=\"Cadence\" group required>\n <RadioGroup name=\"cadence\" value={radioValue} onValueChange={setRadioValue} options={[\n { value: 'daily', label: 'Daily' },\n { value: 'weekly', label: 'Weekly' },\n ]} />\n </Field>\n <Field label=\"Volume\">\n <Slider aria-label=\"Volume\" name=\"volume\" min={0} max={100} value={sliderValue} onChange={(event) => setSliderValue(Number(event.currentTarget.value))} />\n </Field>\n <Field label=\"Mode\" group>\n <SegmentedControl name=\"mode\" value={segmentValue} onValueChange={setSegmentValue} options={[\n { value: 'preview', label: 'Preview' },\n { value: 'code', label: 'Code' },\n ]} />\n </Field>\n </Flow>\n </Region>\n\n <Region title=\"Composite controls\" description=\"Controlled multi-choice and quantity patterns.\">\n <Flow variant=\"cluster\">\n <ChoiceGroup values={['forms', 'data', 'overlays']} selected={choices} onChange={setChoices} labelFor={(value) => value} />\n <QuantityStepper value={quantity} min={0} max={5} onChange={setQuantity} />\n </Flow>\n </Region>\n\n <ActionBar>\n <SubmitButton pending={demo.isPending} pendingLabel=\"Running demo\u2026\">Run form demo</SubmitButton>\n <Action type=\"reset\" variant=\"quiet\">Native reset</Action>\n </ActionBar>\n </Flow>\n </form>\n );\n}\n\nexport function DataSection() {\n const cards = [\n { id: 'alpha', title: 'Alpha', description: 'Ready for review', meta: '12 items' },\n { id: 'beta', title: 'Beta', description: 'Needs attention', meta: '4 items' },\n { id: 'gamma', title: 'Gamma', description: 'Recently updated', meta: '8 items' },\n ];\n return (\n <Flow variant=\"stack\">\n <Region title=\"Facts\" description=\"Compact label/value summaries with semantic tone.\">\n <Flow variant=\"grid\">\n <Fact label=\"Latency\" value=\"42 ms\" detail=\"p95\" />\n <Fact label=\"Success\" value=\"99.9%\" tone=\"success\" trend=\"+0.4%\" />\n <Fact label=\"Budget\" value=\"72%\" tone=\"warning\" detail=\"monthly\" />\n <Fact label=\"Errors\" value=\"3\" tone=\"danger\" detail=\"last hour\" />\n </Flow>\n </Region>\n\n <Region title=\"Collections\" description=\"List, grid, and selected repeated-data treatments.\">\n <Collection variant=\"grid\" selectionMode=\"single\">\n {cards.map((card, index) => <Collection.Item key={card.id} as=\"button\" type=\"button\" selected={index === 0} title={card.title} description={card.description} meta={card.meta} badge={<StatusBadge tone={index === 1 ? 'warning' : 'success'}>{index === 1 ? 'Review' : 'Ready'}</StatusBadge>} />)}\n </Collection>\n </Region>\n\n <Region title=\"DataCard and DataList\">\n <DataList>\n <DataCard as=\"article\"><strong>DataCard</strong><p>Low-level content card for application-specific composition.</p></DataCard>\n <DataCard as=\"button\" type=\"button\"><strong>Interactive DataCard</strong><p>Uses native button behavior.</p></DataCard>\n </DataList>\n </Region>\n </Flow>\n );\n}\n\nexport function FeedbackSection() {\n const demo = useCallTool('run_component_demo');\n return (\n <Flow variant=\"stack\">\n <Region title=\"Feedback states\" description=\"Loading, empty, error, success, partial, permission, and unsupported.\">\n <Flow variant=\"grid\">\n <Feedback status=\"loading\" description=\"Fetching the latest result\u2026\" />\n <Feedback status=\"empty\" description=\"Try changing the filters.\" />\n <Feedback status=\"error\" description=\"The request could not be completed.\" />\n <Feedback status=\"success\" description=\"Everything is up to date.\" />\n <Feedback status=\"partial\" description=\"Some sources are still pending.\" />\n <Feedback status=\"permission-denied\" description=\"Reconnect the required account.\" />\n <Feedback status=\"unsupported\" description=\"This host does not expose that capability.\" />\n </Flow>\n </Region>\n\n <Region title=\"State wrappers\">\n <Flow variant=\"grid\">\n <LoadingState><Spinner label=\"Loading state\" /> LoadingState</LoadingState>\n <EmptyState>EmptyState</EmptyState>\n <ErrorState>ErrorState</ErrorState>\n </Flow>\n </Region>\n\n <Region title=\"AsyncBoundary\" actions={<Action onClick={() => void demo.callTool({ component: 'AsyncBoundary', value: 'demo' }).catch(() => undefined)}>Run tool</Action>}>\n <AsyncBoundary state={demo} loading=\"Calling the app-only demo tool\u2026\" error={(error) => error.message} empty=\"No tool result yet\" isEmpty={demo.isIdle}>\n <Feedback status=\"success\" description={String(demo.structuredContent ? 'The demo tool returned structured content.' : 'Complete.')} />\n </AsyncBoundary>\n </Region>\n </Flow>\n );\n}\n\nexport function OverlaysSection() {\n const [overlay, setOverlay] = useState<'modal' | 'sheet' | undefined>();\n const [activity, setActivity] = useState('No overlay action selected.');\n return (\n <Flow variant=\"stack\">\n <Region title=\"Anchored overlays\" description=\"Focus, keyboard behavior, dismissal, portals, and collision are Radix-backed.\">\n <ActionBar>\n <Tooltip content=\"Tooltip content\"><Action>Tooltip</Action></Tooltip>\n <Popover trigger=\"Popover\" triggerLabel=\"Open popover\"><Flow variant=\"stack\"><strong>Popover content</strong><Action onClick={() => setActivity('Popover action selected.')}>Select</Action></Flow></Popover>\n <Menu trigger=\"Menu\" triggerLabel=\"Open menu\" items={[\n { label: 'Rename', onSelect: () => setActivity('Rename selected.') },\n { label: 'Archive', onSelect: () => setActivity('Archive selected.') },\n 'separator',\n { label: 'Delete', danger: true, onSelect: () => setActivity('Delete selected.') },\n ]} />\n </ActionBar>\n <Feedback status=\"partial\" title=\"Interaction log\" description={activity} />\n </Region>\n\n <Region title=\"Dialog and sheet\">\n <ActionBar>\n <Action onClick={() => setOverlay('modal')}>Open modal</Action>\n <Action onClick={() => setOverlay('sheet')}>Open sheet</Action>\n </ActionBar>\n <Overlay open={overlay !== undefined} onOpenChange={(open) => { if (!open) setOverlay(undefined); }} mode={overlay ?? 'modal'} title={overlay === 'sheet' ? 'Sheet example' : 'Modal example'} description=\"Escape, outside click, and the close button dismiss this surface.\">\n <Action variant=\"primary\" onClick={() => setOverlay(undefined)}>Complete</Action>\n <Menu trigger=\"Nested menu\" items={[{ label: 'Nested action' }]} />\n </Overlay>\n </Region>\n\n <Overlay mode=\"detail\" open title=\"Detail overlay\" description=\"Detail mode remains an inline named region.\">\n Use detail mode when content belongs in the document flow rather than a modal layer.\n </Overlay>\n </Flow>\n );\n}\n\nexport function LayoutSection() {\n const [shellView, setShellView] = useState('overview');\n const carouselItems = [\n { id: 'one', title: 'First card' },\n { id: 'two', title: 'Second card' },\n { id: 'three', title: 'Third card' },\n ];\n return (\n <Flow variant=\"stack\">\n <Region title=\"ShellHeader and ShellNav\">\n <ShellHeader title=\"Application shell\" subtitle=\"Header composition\" badge={<StatusBadge tone=\"success\">Live</StatusBadge>} />\n <ShellNav activeView={shellView} onNavigate={setShellView} items={[\n { view: 'overview', label: 'Overview' },\n { view: 'activity', label: 'Activity' },\n { view: 'settings', label: 'Settings' },\n ]} />\n </Region>\n\n <Region title=\"Flow variants\" description=\"Stack, cluster, split, grid, and sidebar compositions share one primitive.\">\n <Flow variant=\"split\"><InlineCard title=\"Split A\" description=\"First column\" /><InlineCard title=\"Split B\" description=\"Second column\" /></Flow>\n <Flow variant=\"sidebar\"><InlineCard title=\"Sidebar\" description=\"Supporting rail\" /><InlineCard title=\"Content\" description=\"Primary area\" /></Flow>\n </Region>\n\n <Region title=\"InlineCard\">\n <InlineCard title=\"Compact inline surface\" description=\"A host-blending card with two actions.\" primaryAction={<Action variant=\"primary\">Primary</Action>} secondaryAction={<Action variant=\"quiet\">Secondary</Action>}>InlineCard content</InlineCard>\n </Region>\n\n <Region title=\"InlineList\">\n <InlineList items={carouselItems.map((item, index) => ({ id: item.id, title: item.title, description: 'List item description', meta: String(index + 1), action: <Action variant=\"quiet\">Open</Action> }))} />\n </Region>\n\n <Region title=\"InlineCarousel\">\n <InlineCarousel items={carouselItems}>{(item) => <InlineCard title={item.title} description=\"Horizontally scrollable item\" />}</InlineCarousel>\n </Region>\n </Flow>\n );\n}\n";
|
|
4
|
+
export declare const widgetShowcaseSections = "import { useState } from 'react';\nimport {\n Action,\n ActionBar,\n AsyncBoundary,\n Avatar,\n AvatarGroup,\n Checkbox,\n ChoiceGroup,\n Collection,\n DataCard,\n DataList,\n EmptyState,\n ErrorState,\n ExpandButton,\n Fact,\n Feedback,\n Field,\n Flow,\n Form,\n HandoffButton,\n InlineCard,\n InlineCarousel,\n InlineList,\n Input,\n LoadingState,\n Menu,\n Overlay,\n Popover,\n QuantityStepper,\n RadioGroup,\n Region,\n SegmentedControl,\n Select,\n ShellHeader,\n ShellNav,\n Slider,\n Spinner,\n StatusBadge,\n SubmitButton,\n Switch,\n Textarea,\n Tooltip,\n useCallTool,\n useHandoff,\n useViewState,\n useWidgetReady,\n} from '../helpers.js';\n\nexport function FoundationsSection() {\n const handoff = useHandoff();\n return (\n <Flow variant=\"stack\">\n <Region title=\"Actions\" description=\"Button, link, pending, disabled, handoff, and display-mode actions.\">\n <ActionBar>\n <Action variant=\"primary\">Primary</Action>\n <Action variant=\"secondary\">Secondary</Action>\n <Action variant=\"quiet\">Quiet</Action>\n <Action variant=\"danger\">Danger</Action>\n <Action pending pendingLabel=\"Working\u2026\">Pending</Action>\n <Action disabled>Disabled</Action>\n <Action as=\"a\" href=\"https://modelcontextprotocol.io\" external>External link</Action>\n <ExpandButton>Request fullscreen</ExpandButton>\n <HandoffButton handoff={handoff} target=\"https://example.com\" disabled>Handoff</HandoffButton>\n </ActionBar>\n </Region>\n\n <Region title=\"Status badges\" description=\"Semantic tones remain host-adaptive.\">\n <Flow variant=\"cluster\">\n <StatusBadge>Neutral</StatusBadge>\n <StatusBadge tone=\"success\">Success</StatusBadge>\n <StatusBadge tone=\"warning\">Warning</StatusBadge>\n <StatusBadge tone=\"danger\">Danger</StatusBadge>\n <StatusBadge tone=\"info\">Info</StatusBadge>\n </Flow>\n </Region>\n\n <Region title=\"Avatars\" description=\"Image-free fallbacks and overflow grouping.\">\n <AvatarGroup max={3}>\n <Avatar name=\"Ada Lovelace\" size={40} />\n <Avatar name=\"Grace Hopper\" size={40} />\n <Avatar name=\"Alan Turing\" size={40} />\n <Avatar name=\"Katherine Johnson\" size={40} />\n </AvatarGroup>\n </Region>\n </Flow>\n );\n}\n\nexport function FormsSection() {\n const ready = useWidgetReady();\n const demo = useCallTool('run_component_demo');\n const [email, setEmail] = useViewState('showcase_email', 'ada@example.com');\n const [notes, setNotes] = useState('Host-neutral controls with native semantics.');\n const [selectValue, setSelectValue] = useState('comfortable');\n const [radioValue, setRadioValue] = useState('daily');\n const [switchValue, setSwitchValue] = useState(true);\n const [sliderValue, setSliderValue] = useState(60);\n const [segmentValue, setSegmentValue] = useState('preview');\n const [choices, setChoices] = useState<readonly string[]>(['forms']);\n const [quantity, setQuantity] = useState(2);\n\n return (\n <Form onSubmit={() => {\n void demo.callTool({ component: 'Form controls', value: email }).catch(() => undefined);\n }}>\n <Flow variant=\"stack\">\n <Region title=\"Text controls\" description=\"Labels, descriptions, errors, refs, and native form behavior.\">\n <Flow variant=\"grid\">\n <Field label=\"Email\" detail=\"Field connects every accessible relationship.\" required>\n <Input name=\"email\" type=\"email\" value={email} onChange={(event) => setEmail(event.currentTarget.value)} />\n </Field>\n <Field label=\"Notes\">\n <Textarea name=\"notes\" value={notes} onChange={(event) => setNotes(event.currentTarget.value)} />\n </Field>\n <Field label=\"Density\">\n <Select name=\"density\" value={selectValue} onChange={(event) => setSelectValue(event.currentTarget.value)} options={[\n { value: 'compact', label: 'Compact' },\n { value: 'comfortable', label: 'Comfortable' },\n ]} />\n </Field>\n </Flow>\n </Region>\n\n <Region title=\"Choice controls\" description=\"Native checkbox, radio, switch, range, and segmented interaction.\">\n <Flow variant=\"grid\">\n <Checkbox name=\"updates\" defaultChecked label=\"Checkbox\" />\n <Switch name=\"enabled\" checked={switchValue} onCheckedChange={setSwitchValue} label=\"Switch\" />\n <Field label=\"Cadence\" group required>\n <RadioGroup name=\"cadence\" value={radioValue} onValueChange={setRadioValue} options={[\n { value: 'daily', label: 'Daily' },\n { value: 'weekly', label: 'Weekly' },\n ]} />\n </Field>\n <Field label=\"Volume\">\n <Slider aria-label=\"Volume\" name=\"volume\" min={0} max={100} value={sliderValue} onChange={(event) => setSliderValue(Number(event.currentTarget.value))} />\n </Field>\n <Field label=\"Mode\" group>\n <SegmentedControl name=\"mode\" value={segmentValue} onValueChange={setSegmentValue} options={[\n { value: 'preview', label: 'Preview' },\n { value: 'code', label: 'Code' },\n ]} />\n </Field>\n </Flow>\n </Region>\n\n <Region title=\"Composite controls\" description=\"Controlled multi-choice and quantity patterns.\">\n <Flow variant=\"cluster\">\n <ChoiceGroup values={['forms', 'data', 'overlays']} selected={choices} onChange={setChoices} labelFor={(value) => value} />\n <QuantityStepper value={quantity} min={0} max={5} onChange={setQuantity} />\n </Flow>\n </Region>\n\n <ActionBar>\n <SubmitButton disabled={!ready} pending={demo.isPending} pendingLabel=\"Running demo\u2026\">Run form demo</SubmitButton>\n <Action type=\"reset\" variant=\"quiet\">Native reset</Action>\n </ActionBar>\n </Flow>\n </Form>\n );\n}\n\nexport function DataSection() {\n const cards = [\n { id: 'alpha', title: 'Alpha', description: 'Ready for review', meta: '12 items' },\n { id: 'beta', title: 'Beta', description: 'Needs attention', meta: '4 items' },\n { id: 'gamma', title: 'Gamma', description: 'Recently updated', meta: '8 items' },\n ];\n return (\n <Flow variant=\"stack\">\n <Region title=\"Facts\" description=\"Compact label/value summaries with semantic tone.\">\n <Flow variant=\"grid\">\n <Fact label=\"Latency\" value=\"42 ms\" detail=\"p95\" />\n <Fact label=\"Success\" value=\"99.9%\" tone=\"success\" trend=\"+0.4%\" />\n <Fact label=\"Budget\" value=\"72%\" tone=\"warning\" detail=\"monthly\" />\n <Fact label=\"Errors\" value=\"3\" tone=\"danger\" detail=\"last hour\" />\n </Flow>\n </Region>\n\n <Region title=\"Collections\" description=\"List, grid, and selected repeated-data treatments.\">\n <Collection variant=\"grid\" selectionMode=\"single\">\n {cards.map((card, index) => <Collection.Item key={card.id} as=\"button\" type=\"button\" selected={index === 0} title={card.title} description={card.description} meta={card.meta} badge={<StatusBadge tone={index === 1 ? 'warning' : 'success'}>{index === 1 ? 'Review' : 'Ready'}</StatusBadge>} />)}\n </Collection>\n </Region>\n\n <Region title=\"DataCard and DataList\">\n <DataList>\n <DataCard as=\"article\"><strong>DataCard</strong><p>Low-level content card for application-specific composition.</p></DataCard>\n <DataCard as=\"button\" type=\"button\"><strong>Interactive DataCard</strong><p>Uses native button behavior.</p></DataCard>\n </DataList>\n </Region>\n </Flow>\n );\n}\n\nexport function FeedbackSection() {\n const demo = useCallTool('run_component_demo');\n return (\n <Flow variant=\"stack\">\n <Region title=\"Feedback states\" description=\"Loading, empty, error, success, partial, permission, and unsupported.\">\n <Flow variant=\"grid\">\n <Feedback status=\"loading\" description=\"Fetching the latest result\u2026\" />\n <Feedback status=\"empty\" description=\"Try changing the filters.\" />\n <Feedback status=\"error\" description=\"The request could not be completed.\" />\n <Feedback status=\"success\" description=\"Everything is up to date.\" />\n <Feedback status=\"partial\" description=\"Some sources are still pending.\" />\n <Feedback status=\"permission-denied\" description=\"Reconnect the required account.\" />\n <Feedback status=\"unsupported\" description=\"This host does not expose that capability.\" />\n </Flow>\n </Region>\n\n <Region title=\"State wrappers\">\n <Flow variant=\"grid\">\n <LoadingState><Spinner label=\"Loading state\" /> LoadingState</LoadingState>\n <EmptyState>EmptyState</EmptyState>\n <ErrorState>ErrorState</ErrorState>\n </Flow>\n </Region>\n\n <Region title=\"AsyncBoundary\" actions={<Action onClick={() => void demo.callTool({ component: 'AsyncBoundary', value: 'demo' }).catch(() => undefined)}>Run tool</Action>}>\n <AsyncBoundary state={demo} loading=\"Calling the app-only demo tool\u2026\" error={(error) => error.message} empty=\"No tool result yet\" isEmpty={demo.isIdle}>\n <Feedback status=\"success\" description={String(demo.structuredContent ? 'The demo tool returned structured content.' : 'Complete.')} />\n </AsyncBoundary>\n </Region>\n </Flow>\n );\n}\n\nexport function OverlaysSection() {\n const [overlay, setOverlay] = useState<'modal' | 'sheet' | undefined>();\n const [activity, setActivity] = useState('No overlay action selected.');\n return (\n <Flow variant=\"stack\">\n <Region title=\"Anchored overlays\" description=\"Focus, keyboard behavior, dismissal, portals, and collision are Radix-backed.\">\n <ActionBar>\n <Tooltip content=\"Tooltip content\"><Action>Tooltip</Action></Tooltip>\n <Popover trigger=\"Popover\" triggerLabel=\"Open popover\"><Flow variant=\"stack\"><strong>Popover content</strong><Action onClick={() => setActivity('Popover action selected.')}>Select</Action></Flow></Popover>\n <Menu trigger=\"Menu\" triggerLabel=\"Open menu\" items={[\n { label: 'Rename', onSelect: () => setActivity('Rename selected.') },\n { label: 'Archive', onSelect: () => setActivity('Archive selected.') },\n 'separator',\n { label: 'Delete', danger: true, onSelect: () => setActivity('Delete selected.') },\n ]} />\n </ActionBar>\n <Feedback status=\"partial\" title=\"Interaction log\" description={activity} />\n </Region>\n\n <Region title=\"Dialog and sheet\">\n <ActionBar>\n <Action onClick={() => setOverlay('modal')}>Open modal</Action>\n <Action onClick={() => setOverlay('sheet')}>Open sheet</Action>\n </ActionBar>\n <Overlay open={overlay !== undefined} onOpenChange={(open) => { if (!open) setOverlay(undefined); }} mode={overlay ?? 'modal'} title={overlay === 'sheet' ? 'Sheet example' : 'Modal example'} description=\"Escape, outside click, and the close button dismiss this surface.\">\n <Action variant=\"primary\" onClick={() => setOverlay(undefined)}>Complete</Action>\n <Menu trigger=\"Nested menu\" items={[{ label: 'Nested action' }]} />\n </Overlay>\n </Region>\n\n <Overlay mode=\"detail\" open title=\"Detail overlay\" description=\"Detail mode remains an inline named region.\">\n Use detail mode when content belongs in the document flow rather than a modal layer.\n </Overlay>\n </Flow>\n );\n}\n\nexport function LayoutSection() {\n const [shellView, setShellView] = useState('overview');\n const carouselItems = [\n { id: 'one', title: 'First card' },\n { id: 'two', title: 'Second card' },\n { id: 'three', title: 'Third card' },\n ];\n return (\n <Flow variant=\"stack\">\n <Region title=\"ShellHeader and ShellNav\">\n <ShellHeader title=\"Application shell\" subtitle=\"Header composition\" badge={<StatusBadge tone=\"success\">Live</StatusBadge>} />\n <ShellNav activeView={shellView} onNavigate={setShellView} items={[\n { view: 'overview', label: 'Overview' },\n { view: 'activity', label: 'Activity' },\n { view: 'settings', label: 'Settings' },\n ]} />\n </Region>\n\n <Region title=\"Flow variants\" description=\"Stack, cluster, split, grid, and sidebar compositions share one primitive.\">\n <Flow variant=\"split\"><InlineCard title=\"Split A\" description=\"First column\" /><InlineCard title=\"Split B\" description=\"Second column\" /></Flow>\n <Flow variant=\"sidebar\"><InlineCard title=\"Sidebar\" description=\"Supporting rail\" /><InlineCard title=\"Content\" description=\"Primary area\" /></Flow>\n </Region>\n\n <Region title=\"InlineCard\">\n <InlineCard title=\"Compact inline surface\" description=\"A host-blending card with two actions.\" primaryAction={<Action variant=\"primary\">Primary</Action>} secondaryAction={<Action variant=\"quiet\">Secondary</Action>}>InlineCard content</InlineCard>\n </Region>\n\n <Region title=\"InlineList\">\n <InlineList items={carouselItems.map((item, index) => ({ id: item.id, title: item.title, description: 'List item description', meta: String(index + 1), action: <Action variant=\"quiet\">Open</Action> }))} />\n </Region>\n\n <Region title=\"InlineCarousel\">\n <InlineCarousel items={carouselItems}>{(item) => <InlineCard title={item.title} description=\"Horizontally scrollable item\" />}</InlineCarousel>\n </Region>\n </Flow>\n );\n}\n";
|
|
5
5
|
//# sourceMappingURL=widget-showcase-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-showcase-template.d.ts","sourceRoot":"","sources":["../src/widget-showcase-template.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"widget-showcase-template.d.ts","sourceRoot":"","sources":["../src/widget-showcase-template.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,eAAO,MAAM,qBAAqB,qkCAiEjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,sjHA8G9B,CAAC;AAEF,eAAO,MAAM,sBAAsB,w0bA8SlC,CAAC"}
|
|
@@ -22,6 +22,7 @@ export {
|
|
|
22
22
|
Feedback,
|
|
23
23
|
Field,
|
|
24
24
|
Flow,
|
|
25
|
+
Form,
|
|
25
26
|
Frame,
|
|
26
27
|
FullscreenShell,
|
|
27
28
|
HandoffButton,
|
|
@@ -61,6 +62,7 @@ export const {
|
|
|
61
62
|
useLayout,
|
|
62
63
|
useToolInfo,
|
|
63
64
|
useViewState,
|
|
65
|
+
useWidgetReady,
|
|
64
66
|
} = generateHelpers<AppType>();
|
|
65
67
|
`;
|
|
66
68
|
export const widgetShowcaseView = `import '@noodleseed/one/react/styles.css';
|
|
@@ -193,6 +195,7 @@ import {
|
|
|
193
195
|
Feedback,
|
|
194
196
|
Field,
|
|
195
197
|
Flow,
|
|
198
|
+
Form,
|
|
196
199
|
HandoffButton,
|
|
197
200
|
InlineCard,
|
|
198
201
|
InlineCarousel,
|
|
@@ -219,6 +222,7 @@ import {
|
|
|
219
222
|
useCallTool,
|
|
220
223
|
useHandoff,
|
|
221
224
|
useViewState,
|
|
225
|
+
useWidgetReady,
|
|
222
226
|
} from '../helpers.js';
|
|
223
227
|
|
|
224
228
|
export function FoundationsSection() {
|
|
@@ -262,6 +266,7 @@ export function FoundationsSection() {
|
|
|
262
266
|
}
|
|
263
267
|
|
|
264
268
|
export function FormsSection() {
|
|
269
|
+
const ready = useWidgetReady();
|
|
265
270
|
const demo = useCallTool('run_component_demo');
|
|
266
271
|
const [email, setEmail] = useViewState('showcase_email', 'ada@example.com');
|
|
267
272
|
const [notes, setNotes] = useState('Host-neutral controls with native semantics.');
|
|
@@ -274,8 +279,7 @@ export function FormsSection() {
|
|
|
274
279
|
const [quantity, setQuantity] = useState(2);
|
|
275
280
|
|
|
276
281
|
return (
|
|
277
|
-
<
|
|
278
|
-
event.preventDefault();
|
|
282
|
+
<Form onSubmit={() => {
|
|
279
283
|
void demo.callTool({ component: 'Form controls', value: email }).catch(() => undefined);
|
|
280
284
|
}}>
|
|
281
285
|
<Flow variant="stack">
|
|
@@ -326,11 +330,11 @@ export function FormsSection() {
|
|
|
326
330
|
</Region>
|
|
327
331
|
|
|
328
332
|
<ActionBar>
|
|
329
|
-
<SubmitButton pending={demo.isPending} pendingLabel="Running demo…">Run form demo</SubmitButton>
|
|
333
|
+
<SubmitButton disabled={!ready} pending={demo.isPending} pendingLabel="Running demo…">Run form demo</SubmitButton>
|
|
330
334
|
<Action type="reset" variant="quiet">Native reset</Action>
|
|
331
335
|
</ActionBar>
|
|
332
336
|
</Flow>
|
|
333
|
-
</
|
|
337
|
+
</Form>
|
|
334
338
|
);
|
|
335
339
|
}
|
|
336
340
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-showcase-template.js","sourceRoot":"","sources":["../src/widget-showcase-template.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,MAAM,CAAC,MAAM,qBAAqB,GAAG
|
|
1
|
+
{"version":3,"file":"widget-showcase-template.js","sourceRoot":"","sources":["../src/widget-showcase-template.ts"],"names":[],"mappings":"AAAA,oFAAoF;AAEpF,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiEpC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8GjC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8SrC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-notes.d.ts","sourceRoot":"","sources":["../../src/curated/hook-notes.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"hook-notes.d.ts","sourceRoot":"","sources":["../../src/curated/hook-notes.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA2B7C,CAAC"}
|
|
@@ -17,5 +17,6 @@ export const HOOK_NOTES = {
|
|
|
17
17
|
useSendFollowUpMessage: 'Send a follow-up prompt to the model from a user interaction: `send({ prompt })` — trigger only from an explicit user action.',
|
|
18
18
|
useUpdateModelContext: 'Publish one compact, cohesive author-selected text/structured snapshot through the standard MCP Apps model-context channel; each call replaces the prior snapshot, so include every still-relevant field and check `useLayout().supports?.modelContext` first.',
|
|
19
19
|
useWidgetLifecycle: 'Calling the hook auto-publishes `mounted` and listens for host `cancelled`/`dismissed`; use its publisher for author-owned `submitted` or app milestones, include a complete safe replacement snapshot, and pair explicit submit/cancel with `useSendFollowUpMessage` when an immediate reply is wanted.',
|
|
20
|
+
useWidgetReady: 'Report when the standard MCP Apps bridge has connected; keep tool-backed controls disabled (or render loading) until this returns `true`.',
|
|
20
21
|
};
|
|
21
22
|
//# sourceMappingURL=hook-notes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-notes.js","sourceRoot":"","sources":["../../src/curated/hook-notes.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,EAAE;AACF,mGAAmG;AACnG,gGAAgG;AAChG,iGAAiG;AACjG,yEAAyE;AAEzE,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,WAAW,EACT,gPAAgP;IAClP,WAAW,EACT,4KAA4K;IAC9K,YAAY,EACV,uHAAuH;IACzH,UAAU,EACR,0HAA0H;IAC5H,UAAU,EACR,6IAA6I;IAC/I,SAAS,EACP,wKAAwK;IAC1K,WAAW,EACT,mUAAmU;IACrU,qBAAqB,EACnB,qHAAqH;IACvH,eAAe,EACb,8IAA8I;IAChJ,sBAAsB,EACpB,+HAA+H;IACjI,qBAAqB,EACnB,gQAAgQ;IAClQ,kBAAkB,EAChB,0SAA0S;
|
|
1
|
+
{"version":3,"file":"hook-notes.js","sourceRoot":"","sources":["../../src/curated/hook-notes.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,EAAE;AACF,mGAAmG;AACnG,gGAAgG;AAChG,iGAAiG;AACjG,yEAAyE;AAEzE,MAAM,CAAC,MAAM,UAAU,GAA2B;IAChD,WAAW,EACT,gPAAgP;IAClP,WAAW,EACT,4KAA4K;IAC9K,YAAY,EACV,uHAAuH;IACzH,UAAU,EACR,0HAA0H;IAC5H,UAAU,EACR,6IAA6I;IAC/I,SAAS,EACP,wKAAwK;IAC1K,WAAW,EACT,mUAAmU;IACrU,qBAAqB,EACnB,qHAAqH;IACvH,eAAe,EACb,8IAA8I;IAChJ,sBAAsB,EACpB,+HAA+H;IACjI,qBAAqB,EACnB,gQAAgQ;IAClQ,kBAAkB,EAChB,0SAA0S;IAC5S,cAAc,EACZ,2IAA2I;CAC9I,CAAC"}
|