@happyvertical/smrt-svelte 0.51.39 → 0.52.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/AGENTS.md +3 -0
- package/README.md +167 -1
- package/agents/workspace.md +24 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts +11 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts.map +1 -1
- package/dist/browser-ai/adapters/stt/browser-speech.js +20 -4
- package/dist/browser-ai/adapters/stt/browser-speech.test.js +113 -0
- package/dist/browser-ai/adapters/stt/dictation-source.d.ts +3 -0
- package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/dictation-source.js +38 -0
- package/dist/browser-ai/adapters/stt/dictation-source.test.js +52 -0
- package/dist/browser-ai/adapters/stt/index.d.ts +2 -1
- package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
- package/dist/browser-ai/adapters/stt/index.js +2 -1
- package/dist/components/forms/Form.svelte +118 -8
- package/dist/components/forms/Form.svelte.d.ts +18 -2
- package/dist/components/forms/Form.svelte.d.ts.map +1 -1
- package/dist/components/forms/FormScope.svelte +202 -0
- package/dist/components/forms/FormScope.svelte.d.ts +22 -0
- package/dist/components/forms/FormScope.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/Form.ui-controls.test.js +119 -0
- package/dist/components/forms/__tests__/Form.webmcp.test.js +5 -3
- package/dist/components/forms/__tests__/FormScope.test.js +39 -0
- package/dist/components/forms/__tests__/form-scope.fixture.svelte +30 -0
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte +84 -0
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts +14 -0
- package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/index.d.ts +1 -0
- package/dist/components/forms/index.d.ts.map +1 -1
- package/dist/components/forms/index.js +1 -0
- package/dist/components/workspace/README.md +11 -0
- package/dist/components/workspace/__tests__/AdminShell.responsive.test.js +586 -0
- package/dist/components/workspace/__tests__/AdminShell.test.js +85 -0
- package/dist/components/workspace/__tests__/TenantNav.test.js +49 -0
- package/dist/components/workspace/__tests__/admin-shell-header-overflow.test.js +25 -0
- package/dist/components/workspace/__tests__/admin-shell-mobile.test.js +217 -0
- package/dist/components/workspace/__tests__/admin-shell-page-contracts.test.js +30 -0
- package/dist/components/workspace/__tests__/admin-shell-responsive-state.test.js +184 -0
- package/dist/components/workspace/__tests__/admin-shell-theme-hooks.test.js +36 -0
- package/dist/components/workspace/__tests__/shell-chrome-components.test.js +108 -0
- package/dist/components/workspace/admin-shell/AdminShell.svelte +998 -40
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +42 -1
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte +170 -0
- package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte.d.ts +11 -0
- package/dist/components/workspace/admin-shell/PhoneBottomBar.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/PhoneTopBar.svelte +93 -0
- package/dist/components/workspace/admin-shell/PhoneTopBar.svelte.d.ts +11 -0
- package/dist/components/workspace/admin-shell/PhoneTopBar.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellNavToggle.svelte +88 -0
- package/dist/components/workspace/admin-shell/ShellNavToggle.svelte.d.ts +14 -0
- package/dist/components/workspace/admin-shell/ShellNavToggle.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellTitle.svelte +42 -0
- package/dist/components/workspace/admin-shell/ShellTitle.svelte.d.ts +11 -0
- package/dist/components/workspace/admin-shell/ShellTitle.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/TenantNav.svelte +46 -1
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/mobile-shell-dom.d.ts +37 -0
- package/dist/components/workspace/admin-shell/mobile-shell-dom.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/mobile-shell-dom.js +150 -0
- package/dist/components/workspace/admin-shell/mobile-shell.d.ts +191 -0
- package/dist/components/workspace/admin-shell/mobile-shell.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/mobile-shell.js +165 -0
- package/dist/components/workspace/admin-shell/settings.d.ts +27 -2
- package/dist/components/workspace/admin-shell/settings.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/settings.js +84 -2
- package/dist/components/workspace/admin-shell/state.svelte.d.ts +55 -1
- package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/state.svelte.js +149 -6
- package/dist/components/workspace/admin-shell/types.d.ts +97 -0
- package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/types.js +13 -0
- package/dist/components/workspace/index.d.ts +11 -4
- package/dist/components/workspace/index.d.ts.map +1 -1
- package/dist/components/workspace/index.js +12 -3
- package/dist/i18n/strings.workspace.d.ts +10 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -1
- package/dist/i18n/strings.workspace.js +10 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/web/__tests__/assistant-dock.integration.svelte.test.js +2 -2
- package/dist/web/__tests__/list-sort-surface.fixture.svelte +41 -0
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts +15 -0
- package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/list-sort-surface.svelte.test.js +59 -0
- package/dist/web/__tests__/surfaces.child.fixture.svelte +69 -0
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts +16 -0
- package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/surfaces.fixture.svelte +26 -0
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts +18 -0
- package/dist/web/__tests__/surfaces.fixture.svelte.d.ts.map +1 -0
- package/dist/web/__tests__/surfaces.svelte.test.js +140 -0
- package/dist/web/__tests__/webmcp-ui.test.js +18 -0
- package/dist/web/index.d.ts +4 -1
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +4 -1
- package/dist/web/link-surface.svelte.d.ts +14 -0
- package/dist/web/link-surface.svelte.d.ts.map +1 -0
- package/dist/web/link-surface.svelte.js +49 -0
- package/dist/web/list-surface.svelte.d.ts +80 -0
- package/dist/web/list-surface.svelte.d.ts.map +1 -0
- package/dist/web/list-surface.svelte.js +309 -0
- package/dist/web/step-surface.svelte.d.ts +17 -0
- package/dist/web/step-surface.svelte.d.ts.map +1 -0
- package/dist/web/step-surface.svelte.js +56 -0
- package/dist/web/webmcp-ui-context.d.ts +7 -0
- package/dist/web/webmcp-ui-context.d.ts.map +1 -1
- package/dist/web/webmcp-ui-context.js +10 -0
- package/dist/web/webmcp-ui.d.ts.map +1 -1
- package/dist/web/webmcp-ui.js +16 -3
- package/package.json +16 -16
package/dist/index.d.ts
CHANGED
|
@@ -21,5 +21,5 @@ export { type UseViewIntentOptions, useViewIntent, type ViewIntentIdentity, } fr
|
|
|
21
21
|
export { useWebMcpTool, type WebMcpToolSpec } from './web/webmcp.svelte.js';
|
|
22
22
|
export type { WebMcpProviderConfig, WebMcpUiProviderConfig, } from './web/webmcp-provider.js';
|
|
23
23
|
export { type RegisterWebMcpUiToolsOptions, registerWebMcpUiTools, } from './web/webmcp-ui.js';
|
|
24
|
-
export { useWebMcpUi, type WebMcpUiContext, } from './web/webmcp-ui-context.js';
|
|
24
|
+
export { tryUseWebMcpUi, useWebMcpUi, type WebMcpUiContext, } from './web/webmcp-ui-context.js';
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAGH,cAAc,6BAA6B,CAAC;AAE5C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,mBAAmB,CAAC;AAElC,cAAc,kBAAkB,CAAC;AAEjC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAExD,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,KAAK,oBAAoB,EACzB,aAAa,EACb,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,WAAW,EACX,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAGH,cAAc,6BAA6B,CAAC;AAE5C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,mBAAmB,CAAC;AAElC,cAAc,kBAAkB,CAAC;AAEjC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAExD,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,KAAK,oBAAoB,EACzB,aAAa,EACb,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,WAAW,EACX,KAAK,eAAe,GACrB,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -30,4 +30,4 @@ export { useViewIntent, } from './web/view-intent.svelte.js';
|
|
|
30
30
|
// Opt-in browser WebMCP lifecycle primitive.
|
|
31
31
|
export { useWebMcpTool } from './web/webmcp.svelte.js';
|
|
32
32
|
export { registerWebMcpUiTools, } from './web/webmcp-ui.js';
|
|
33
|
-
export { useWebMcpUi, } from './web/webmcp-ui-context.js';
|
|
33
|
+
export { tryUseWebMcpUi, useWebMcpUi, } from './web/webmcp-ui-context.js';
|
|
@@ -98,7 +98,7 @@ describe('AssistantDock integration (#2904)', () => {
|
|
|
98
98
|
const transport = createInMemoryAssistantTransport();
|
|
99
99
|
render(AssistantDock, { props: { transport, registry } });
|
|
100
100
|
await waitFor(() => {
|
|
101
|
-
expect(screen.getByText(/
|
|
101
|
+
expect(screen.getByText(/Nothing on this page can be changed from the chat/i)).toBeInTheDocument();
|
|
102
102
|
});
|
|
103
103
|
});
|
|
104
104
|
it('discovers a mounted surface via the registry and renders a sent conversation', async () => {
|
|
@@ -114,7 +114,7 @@ describe('AssistantDock integration (#2904)', () => {
|
|
|
114
114
|
});
|
|
115
115
|
render(AssistantDock, { props: { transport, registry } });
|
|
116
116
|
await waitFor(() => {
|
|
117
|
-
expect(screen.queryByText(/
|
|
117
|
+
expect(screen.queryByText(/Nothing on this page can be changed from the chat/i)).not.toBeInTheDocument();
|
|
118
118
|
});
|
|
119
119
|
const thread = await transport.createThread('Order question');
|
|
120
120
|
// Drive the same controller the component owns internally by exercising
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
DataSurfaceRegistry,
|
|
4
|
+
ListSort,
|
|
5
|
+
} from '@happyvertical/smrt-ui/data';
|
|
6
|
+
import { useListSurface } from '../list-surface.svelte.js';
|
|
7
|
+
|
|
8
|
+
let {
|
|
9
|
+
registry,
|
|
10
|
+
rows,
|
|
11
|
+
sort = $bindable({ columnId: 'published', direction: 'desc' }),
|
|
12
|
+
deny = false,
|
|
13
|
+
}: {
|
|
14
|
+
registry: DataSurfaceRegistry;
|
|
15
|
+
rows: Array<{ id: string; title: string; published: string }>;
|
|
16
|
+
sort?: ListSort;
|
|
17
|
+
deny?: boolean;
|
|
18
|
+
} = $props();
|
|
19
|
+
|
|
20
|
+
useListSurface(
|
|
21
|
+
() => ({
|
|
22
|
+
surfaceId: 'stories-ui',
|
|
23
|
+
label: 'Stories',
|
|
24
|
+
description: 'Stories on this page',
|
|
25
|
+
columns: [
|
|
26
|
+
{ id: 'id', label: 'ID', rowKey: true },
|
|
27
|
+
{ id: 'title', label: 'Title', sortable: true },
|
|
28
|
+
{ id: 'published', label: 'Published', sortable: true },
|
|
29
|
+
],
|
|
30
|
+
rows,
|
|
31
|
+
sort,
|
|
32
|
+
onSort: (next) => {
|
|
33
|
+
if (deny) return false;
|
|
34
|
+
sort = next;
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
registry,
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<p data-testid="sort">{sort.columnId}:{sort.direction}</p>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DataSurfaceRegistry, ListSort } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
registry: DataSurfaceRegistry;
|
|
4
|
+
rows: Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
published: string;
|
|
8
|
+
}>;
|
|
9
|
+
sort?: ListSort;
|
|
10
|
+
deny?: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare const ListSortSurface: import("svelte").Component<$$ComponentProps, {}, "sort">;
|
|
13
|
+
type ListSortSurface = ReturnType<typeof ListSortSurface>;
|
|
14
|
+
export default ListSortSurface;
|
|
15
|
+
//# sourceMappingURL=list-sort-surface.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sort-surface.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../src/web/__tests__/list-sort-surface.fixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,QAAQ,EACT,MAAM,6BAA6B,CAAC;AAGpC,KAAK,gBAAgB,GAAI;IACxB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAqCF,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createDataSurfaceRegistry } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
import { render, screen } from '@testing-library/svelte';
|
|
3
|
+
import { tick } from 'svelte';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import Fixture from './list-sort-surface.fixture.svelte';
|
|
6
|
+
const rows = [
|
|
7
|
+
{ id: 's1', title: 'Budget passes', published: '2026-09-01' },
|
|
8
|
+
{ id: 's2', title: 'Arena opens', published: '2026-09-20' },
|
|
9
|
+
];
|
|
10
|
+
const identity = { surfaceId: 'stories-ui', kind: 'list' };
|
|
11
|
+
let sequence = 0;
|
|
12
|
+
function setSorting(expectedRevision, sorting) {
|
|
13
|
+
sequence += 1;
|
|
14
|
+
return {
|
|
15
|
+
version: 1,
|
|
16
|
+
commandId: `sort-${sequence}`,
|
|
17
|
+
identity,
|
|
18
|
+
expectedRevision,
|
|
19
|
+
controlId: 'set-sorting',
|
|
20
|
+
payload: { sorting },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
describe('useListSurface sorting', () => {
|
|
24
|
+
it('reports the page sort and applies an agent sort through onSort', async () => {
|
|
25
|
+
const registry = createDataSurfaceRegistry();
|
|
26
|
+
render(Fixture, { props: { registry, rows } });
|
|
27
|
+
await tick();
|
|
28
|
+
const before = registry.inspect(identity);
|
|
29
|
+
expect([...(before?.descriptor.query.sortableColumnIds ?? [])].sort()).toEqual(['published', 'title']);
|
|
30
|
+
expect(before?.descriptor.controls.map((control) => control.id)).toContain('set-sorting');
|
|
31
|
+
expect(before?.state.sort).toEqual({
|
|
32
|
+
columnId: 'published',
|
|
33
|
+
direction: 'desc',
|
|
34
|
+
});
|
|
35
|
+
const result = await registry.execute(setSorting(before?.revision ?? 0, [
|
|
36
|
+
{ columnId: 'title', direction: 'asc' },
|
|
37
|
+
]));
|
|
38
|
+
expect(result.ok).toBe(true);
|
|
39
|
+
await tick();
|
|
40
|
+
expect(screen.getByTestId('sort').textContent).toBe('title:asc');
|
|
41
|
+
expect(registry.inspect(identity)?.state.sort).toEqual({
|
|
42
|
+
columnId: 'title',
|
|
43
|
+
direction: 'asc',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('refuses unsortable columns, multiple rules, and a denied onSort', async () => {
|
|
47
|
+
const registry = createDataSurfaceRegistry();
|
|
48
|
+
render(Fixture, { props: { registry, rows, deny: true } });
|
|
49
|
+
await tick();
|
|
50
|
+
const revision = () => registry.inspect(identity)?.revision ?? 0;
|
|
51
|
+
expect((await registry.execute(setSorting(revision(), [{ columnId: 'id', direction: 'asc' }]))).ok).toBe(false);
|
|
52
|
+
expect((await registry.execute(setSorting(revision(), [
|
|
53
|
+
{ columnId: 'title', direction: 'asc' },
|
|
54
|
+
{ columnId: 'published', direction: 'desc' },
|
|
55
|
+
]))).ok).toBe(false);
|
|
56
|
+
expect((await registry.execute(setSorting(revision(), [{ columnId: 'title', direction: 'asc' }]))).ok).toBe(false);
|
|
57
|
+
expect(screen.getByTestId('sort').textContent).toBe('published:desc');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useLinkSurface } from '../link-surface.svelte.js';
|
|
3
|
+
import { useListSurface } from '../list-surface.svelte.js';
|
|
4
|
+
import { useStepSurface } from '../step-surface.svelte.js';
|
|
5
|
+
import { tryUseWebMcpUi } from '../webmcp-ui-context.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
rows,
|
|
9
|
+
step = $bindable('town'),
|
|
10
|
+
navigate,
|
|
11
|
+
onContext,
|
|
12
|
+
create,
|
|
13
|
+
}: {
|
|
14
|
+
rows: Array<{ id: string; title: string; status: string; token: string }>;
|
|
15
|
+
step?: string;
|
|
16
|
+
navigate: (href: string) => void;
|
|
17
|
+
onContext?: (enabled: boolean) => void;
|
|
18
|
+
create: () => void;
|
|
19
|
+
} = $props();
|
|
20
|
+
|
|
21
|
+
onContext?.(tryUseWebMcpUi() !== null);
|
|
22
|
+
|
|
23
|
+
useListSurface(() => ({
|
|
24
|
+
surfaceId: 'articles-ui',
|
|
25
|
+
label: 'Articles',
|
|
26
|
+
description: 'Articles on this page',
|
|
27
|
+
columns: [
|
|
28
|
+
{ id: 'id', label: 'ID', rowKey: true },
|
|
29
|
+
{ id: 'title', label: 'Title', searchable: true },
|
|
30
|
+
{ id: 'status', label: 'Status', status: true },
|
|
31
|
+
],
|
|
32
|
+
rows,
|
|
33
|
+
maxRows: 2,
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
useLinkSurface(() => ({
|
|
37
|
+
surfaceId: 'site-sections-ui',
|
|
38
|
+
label: 'Site sections',
|
|
39
|
+
description: 'Pages in this site',
|
|
40
|
+
links: [
|
|
41
|
+
{ id: 'events', label: 'Events', href: '/s/events' },
|
|
42
|
+
{ id: 'articles', label: 'Articles', href: '/s/articles' },
|
|
43
|
+
],
|
|
44
|
+
navigate,
|
|
45
|
+
state: { active: 'articles' },
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
useStepSurface(() => ({
|
|
49
|
+
surfaceId: 'new-site-steps',
|
|
50
|
+
label: 'New site',
|
|
51
|
+
description: 'Start a new town site',
|
|
52
|
+
steps: [
|
|
53
|
+
{ id: 'town', label: 'Your town', complete: step !== 'town' },
|
|
54
|
+
{ id: 'features', label: 'Features' },
|
|
55
|
+
],
|
|
56
|
+
current: step,
|
|
57
|
+
next: () => {
|
|
58
|
+
step = 'features';
|
|
59
|
+
},
|
|
60
|
+
nextWrites: step === 'features',
|
|
61
|
+
showNext: () => document.getElementById('create')?.focus(),
|
|
62
|
+
back: () => {
|
|
63
|
+
step = 'town';
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<p data-testid="step">{step}</p>
|
|
69
|
+
<button id="create" type="button" onclick={create}>Create site</button>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
rows: Array<{
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
status: string;
|
|
6
|
+
token: string;
|
|
7
|
+
}>;
|
|
8
|
+
step?: string;
|
|
9
|
+
navigate: (href: string) => void;
|
|
10
|
+
onContext?: (enabled: boolean) => void;
|
|
11
|
+
create: () => void;
|
|
12
|
+
};
|
|
13
|
+
declare const Surfaces: import("svelte").Component<$$ComponentProps, {}, "step">;
|
|
14
|
+
type Surfaces = ReturnType<typeof Surfaces>;
|
|
15
|
+
export default Surfaces;
|
|
16
|
+
//# sourceMappingURL=surfaces.child.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surfaces.child.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../src/web/__tests__/surfaces.child.fixture.svelte.ts"],"names":[],"mappings":"AAQC,KAAK,gBAAgB,GAAI;IACxB,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAmEF,QAAA,MAAM,QAAQ,0DAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DataSurfaceRegistry } from '@happyvertical/smrt-ui/data';
|
|
3
|
+
import Provider from '../../Provider.svelte';
|
|
4
|
+
import Child from './surfaces.child.fixture.svelte';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
dataSurfaceRegistry,
|
|
8
|
+
withProvider = true,
|
|
9
|
+
...childProps
|
|
10
|
+
}: {
|
|
11
|
+
dataSurfaceRegistry: DataSurfaceRegistry;
|
|
12
|
+
withProvider?: boolean;
|
|
13
|
+
rows: Array<{ id: string; title: string; status: string; token: string }>;
|
|
14
|
+
navigate: (href: string) => void;
|
|
15
|
+
onContext?: (enabled: boolean) => void;
|
|
16
|
+
create: () => void;
|
|
17
|
+
} = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
{#if withProvider}
|
|
21
|
+
<Provider webmcp={{ ui: { dataSurfaceRegistry } }}>
|
|
22
|
+
<Child {...childProps} />
|
|
23
|
+
</Provider>
|
|
24
|
+
{:else}
|
|
25
|
+
<Child {...childProps} />
|
|
26
|
+
{/if}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DataSurfaceRegistry } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
dataSurfaceRegistry: DataSurfaceRegistry;
|
|
4
|
+
withProvider?: boolean;
|
|
5
|
+
rows: Array<{
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
status: string;
|
|
9
|
+
token: string;
|
|
10
|
+
}>;
|
|
11
|
+
navigate: (href: string) => void;
|
|
12
|
+
onContext?: (enabled: boolean) => void;
|
|
13
|
+
create: () => void;
|
|
14
|
+
};
|
|
15
|
+
declare const Surfaces: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
16
|
+
type Surfaces = ReturnType<typeof Surfaces>;
|
|
17
|
+
export default Surfaces;
|
|
18
|
+
//# sourceMappingURL=surfaces.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surfaces.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../src/web/__tests__/surfaces.fixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAItE,KAAK,gBAAgB,GAAI;IACxB,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAuBF,QAAA,MAAM,QAAQ,sDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { createDataSurfaceRegistry } from '@happyvertical/smrt-ui/data';
|
|
2
|
+
import { render, screen } from '@testing-library/svelte';
|
|
3
|
+
import { tick } from 'svelte';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import Fixture from './surfaces.fixture.svelte';
|
|
6
|
+
const rows = [
|
|
7
|
+
{
|
|
8
|
+
id: 'a1',
|
|
9
|
+
title: 'Council approves budget',
|
|
10
|
+
status: 'published',
|
|
11
|
+
token: 's3cret',
|
|
12
|
+
},
|
|
13
|
+
{ id: 'a2', title: 'Café opens downtown', status: 'draft', token: 's3cret' },
|
|
14
|
+
{
|
|
15
|
+
id: 'a3',
|
|
16
|
+
title: 'Council meeting moved',
|
|
17
|
+
status: 'review',
|
|
18
|
+
token: 's3cret',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
let sequence = 0;
|
|
22
|
+
function command(identity, controlId, expectedRevision, payload) {
|
|
23
|
+
sequence += 1;
|
|
24
|
+
return {
|
|
25
|
+
version: 1,
|
|
26
|
+
commandId: `cmd-${sequence}`,
|
|
27
|
+
identity,
|
|
28
|
+
expectedRevision,
|
|
29
|
+
controlId,
|
|
30
|
+
...(payload === undefined ? {} : { payload: payload }),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
delete document.modelContext;
|
|
35
|
+
});
|
|
36
|
+
describe('surface hooks on the Provider registry', () => {
|
|
37
|
+
it('tryUseWebMcpUi is null without a Provider and the hooks register nothing', () => {
|
|
38
|
+
const registry = createDataSurfaceRegistry();
|
|
39
|
+
const onContext = vi.fn();
|
|
40
|
+
render(Fixture, {
|
|
41
|
+
props: {
|
|
42
|
+
dataSurfaceRegistry: registry,
|
|
43
|
+
withProvider: false,
|
|
44
|
+
rows,
|
|
45
|
+
navigate: vi.fn(),
|
|
46
|
+
onContext,
|
|
47
|
+
create: vi.fn(),
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
expect(onContext).toHaveBeenCalledWith(false);
|
|
51
|
+
expect(registry.list()).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
it('useListSurface publishes projected rows and finds rows by title across all rows', async () => {
|
|
54
|
+
const registry = createDataSurfaceRegistry();
|
|
55
|
+
const onContext = vi.fn();
|
|
56
|
+
const view = render(Fixture, {
|
|
57
|
+
props: {
|
|
58
|
+
dataSurfaceRegistry: registry,
|
|
59
|
+
rows,
|
|
60
|
+
navigate: vi.fn(),
|
|
61
|
+
onContext,
|
|
62
|
+
create: vi.fn(),
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
await tick();
|
|
66
|
+
expect(onContext).toHaveBeenCalledWith(true);
|
|
67
|
+
const identity = { surfaceId: 'articles-ui', kind: 'list' };
|
|
68
|
+
const before = registry.inspect(identity);
|
|
69
|
+
expect(before?.state.rows).toEqual([
|
|
70
|
+
{ id: 'a1', title: 'Council approves budget', status: 'published' },
|
|
71
|
+
{ id: 'a2', title: 'Café opens downtown', status: 'draft' },
|
|
72
|
+
]);
|
|
73
|
+
expect(before?.state.rowsTruncated).toBe(true);
|
|
74
|
+
expect(JSON.stringify(before?.state)).not.toContain('s3cret');
|
|
75
|
+
expect(before?.descriptor.query.searchableColumnIds).toEqual(['title']);
|
|
76
|
+
const found = await registry.execute(command(identity, 'find', before?.revision ?? 0, { text: 'MEETING' }));
|
|
77
|
+
expect(found.ok).toBe(true);
|
|
78
|
+
const after = registry.inspect(identity);
|
|
79
|
+
expect(after?.state.rows).toEqual([
|
|
80
|
+
{ id: 'a3', title: 'Council meeting moved', status: 'review' },
|
|
81
|
+
]);
|
|
82
|
+
expect(after?.state.find).toEqual({ text: 'MEETING', matches: 1 });
|
|
83
|
+
const accent = await registry.execute(command(identity, 'find', after?.revision ?? 0, 'cafe'));
|
|
84
|
+
expect(accent.ok).toBe(true);
|
|
85
|
+
expect(registry.inspect(identity)?.state.rows).toEqual([
|
|
86
|
+
{ id: 'a2', title: 'Café opens downtown', status: 'draft' },
|
|
87
|
+
]);
|
|
88
|
+
const cleared = await registry.execute(command(identity, 'find', registry.inspect(identity)?.revision ?? 0, {
|
|
89
|
+
text: '',
|
|
90
|
+
}));
|
|
91
|
+
expect(cleared.ok).toBe(true);
|
|
92
|
+
expect(registry.inspect(identity)?.state.find).toBeUndefined();
|
|
93
|
+
// Table commands stay refused: the page's own controls own its state.
|
|
94
|
+
const refused = await registry.execute(command(identity, 'set-search', registry.inspect(identity)?.revision ?? 0, {
|
|
95
|
+
search: 'x',
|
|
96
|
+
}));
|
|
97
|
+
expect(refused.ok).toBe(false);
|
|
98
|
+
view.unmount();
|
|
99
|
+
expect(registry.list()).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
it('useLinkSurface navigates to a published link', async () => {
|
|
102
|
+
const registry = createDataSurfaceRegistry();
|
|
103
|
+
const navigate = vi.fn();
|
|
104
|
+
render(Fixture, {
|
|
105
|
+
props: { dataSurfaceRegistry: registry, rows, navigate, create: vi.fn() },
|
|
106
|
+
});
|
|
107
|
+
await tick();
|
|
108
|
+
const identity = { surfaceId: 'site-sections-ui', kind: 'list' };
|
|
109
|
+
const snapshot = registry.inspect(identity);
|
|
110
|
+
expect(snapshot?.state.active).toBe('articles');
|
|
111
|
+
const result = await registry.execute(command(identity, 'open', snapshot?.revision ?? 0, { target: 'events' }));
|
|
112
|
+
expect(result.ok).toBe(true);
|
|
113
|
+
expect(navigate).toHaveBeenCalledWith('/s/events');
|
|
114
|
+
});
|
|
115
|
+
it('useStepSurface moves a wizard forward and leaves the writing step to the person', async () => {
|
|
116
|
+
const registry = createDataSurfaceRegistry();
|
|
117
|
+
const create = vi.fn();
|
|
118
|
+
render(Fixture, {
|
|
119
|
+
props: { dataSurfaceRegistry: registry, rows, navigate: vi.fn(), create },
|
|
120
|
+
});
|
|
121
|
+
await tick();
|
|
122
|
+
const identity = { surfaceId: 'new-site-steps', kind: 'custom' };
|
|
123
|
+
const first = registry.inspect(identity);
|
|
124
|
+
expect(first?.state.current).toBe('town');
|
|
125
|
+
expect((await registry.execute(command(identity, 'next', first?.revision ?? 0)))
|
|
126
|
+
.ok).toBe(true);
|
|
127
|
+
await tick();
|
|
128
|
+
expect(screen.getByTestId('step')).toHaveTextContent('features');
|
|
129
|
+
const second = registry.inspect(identity);
|
|
130
|
+
expect(second?.state).toMatchObject({
|
|
131
|
+
current: 'features',
|
|
132
|
+
nextWrites: true,
|
|
133
|
+
});
|
|
134
|
+
expect((await registry.execute(command(identity, 'next', second?.revision ?? 0)))
|
|
135
|
+
.ok).toBe(true);
|
|
136
|
+
expect(create).not.toHaveBeenCalled();
|
|
137
|
+
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'Create site' }));
|
|
138
|
+
expect(registry.inspect(identity)?.state.awaitingPerson).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createDataSurfaceRegistry, } from '@happyvertical/smrt-ui/data';
|
|
2
2
|
import { createControlInteractionRegistry, } from '@happyvertical/smrt-ui/forms';
|
|
3
3
|
import { registerWebMcpBespokeTool, WebMcpToolNameCollisionError, } from '@happyvertical/smrt-web';
|
|
4
|
+
import { isWebMcpProposalTool } from '@happyvertical/smrt-web/webmcp-tool-names';
|
|
4
5
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
6
|
import { registerWebMcpUiTools } from '../webmcp-ui.js';
|
|
6
7
|
function modelContext() {
|
|
@@ -207,6 +208,10 @@ describe('registerWebMcpUiTools', () => {
|
|
|
207
208
|
focus: () => {
|
|
208
209
|
throw new Error('never-serialize-this cannot be focused');
|
|
209
210
|
},
|
|
211
|
+
// An agent's `focus` reveals instead of moving keyboard focus.
|
|
212
|
+
reveal: () => {
|
|
213
|
+
throw new Error('never-serialize-this cannot be revealed');
|
|
214
|
+
},
|
|
210
215
|
});
|
|
211
216
|
registerWebMcpUiTools({
|
|
212
217
|
controlRegistry: controls,
|
|
@@ -702,4 +707,17 @@ describe('cross-path tool-name lock (#2613)', () => {
|
|
|
702
707
|
expect(registered).toHaveLength(19);
|
|
703
708
|
bespokeDisposer();
|
|
704
709
|
});
|
|
710
|
+
it('brands every fixed UI tool as proposal-only for the in-page assistant', () => {
|
|
711
|
+
const browser = modelContext();
|
|
712
|
+
const dispose = registerWebMcpUiTools({
|
|
713
|
+
controlRegistry: createControlInteractionRegistry(),
|
|
714
|
+
dataSurfaceRegistry: createDataSurfaceRegistry(),
|
|
715
|
+
document: browser.document,
|
|
716
|
+
});
|
|
717
|
+
expect(browser.registered).toHaveLength(6);
|
|
718
|
+
for (const tool of browser.registered) {
|
|
719
|
+
expect(isWebMcpProposalTool(tool.execute)).toBe(true);
|
|
720
|
+
}
|
|
721
|
+
dispose();
|
|
722
|
+
});
|
|
705
723
|
});
|
package/dist/web/index.d.ts
CHANGED
|
@@ -15,11 +15,14 @@
|
|
|
15
15
|
* @packageDocumentation
|
|
16
16
|
*/
|
|
17
17
|
export { type ActivityFeedHandle, type ActivityFeedMap, type ActivityFeedOptions, activityFeed, type ShellActivityInput, } from './activity-feed.svelte.js';
|
|
18
|
+
export { type UseLinkSurfaceOptions, useLinkSurface, } from './link-surface.svelte.js';
|
|
18
19
|
export { type ListDataSurfaceContext, type ListDataSurfaceContextPatch, type ListDataSurfaceControlResult, type ListDataSurfaceHandle, type MountListDataSurfaceOptions, mountListDataSurface, } from './list-data-surface.svelte.js';
|
|
20
|
+
export { findListRows, type ListSurfaceColumn, type ListSurfaceOptions, listSurfaceDescriptor, projectListRows, useListSurface, } from './list-surface.svelte.js';
|
|
19
21
|
export { type LiveCollection, type LiveCollectionMutation, type LiveCollectionOptions, type LiveCollectionStatus, liveCollection, } from './live-collection.svelte.js';
|
|
20
22
|
export { type RemoteQueryBinding, remoteQuery, } from './remote-query.svelte.js';
|
|
23
|
+
export { type UseStepSurfaceOptions, useStepSurface, } from './step-surface.svelte.js';
|
|
21
24
|
export { type UpdateAvailableView, type UseUpdateAvailableOptions, useUpdateAvailable, } from './update-available.svelte.js';
|
|
22
25
|
export type { WebMcpProviderConfig, WebMcpUiProviderConfig, } from './webmcp-provider.js';
|
|
23
26
|
export { type RegisterWebMcpUiToolsOptions, registerWebMcpUiTools, } from './webmcp-ui.js';
|
|
24
|
-
export { useWebMcpUi, type WebMcpUiContext, } from './webmcp-ui-context.js';
|
|
27
|
+
export { tryUseWebMcpUi, useWebMcpUi, type WebMcpUiContext, } from './webmcp-ui-context.js';
|
|
25
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/web/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/web/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,qBAAqB,EAC1B,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,oBAAoB,GACrB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,qBAAqB,EACrB,eAAe,EACf,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,qBAAqB,EAC1B,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,kBAAkB,GACnB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,4BAA4B,EACjC,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,cAAc,EACd,WAAW,EACX,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC"}
|
package/dist/web/index.js
CHANGED
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
* @packageDocumentation
|
|
16
16
|
*/
|
|
17
17
|
export { activityFeed, } from './activity-feed.svelte.js';
|
|
18
|
+
export { useLinkSurface, } from './link-surface.svelte.js';
|
|
18
19
|
export { mountListDataSurface, } from './list-data-surface.svelte.js';
|
|
20
|
+
export { findListRows, listSurfaceDescriptor, projectListRows, useListSurface, } from './list-surface.svelte.js';
|
|
19
21
|
export { liveCollection, } from './live-collection.svelte.js';
|
|
20
22
|
export { remoteQuery, } from './remote-query.svelte.js';
|
|
23
|
+
export { useStepSurface, } from './step-surface.svelte.js';
|
|
21
24
|
export { useUpdateAvailable, } from './update-available.svelte.js';
|
|
22
25
|
export { registerWebMcpUiTools, } from './webmcp-ui.js';
|
|
23
|
-
export { useWebMcpUi, } from './webmcp-ui-context.js';
|
|
26
|
+
export { tryUseWebMcpUi, useWebMcpUi, } from './webmcp-ui-context.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useLinkSurface` — mount a navigation list (a menu, a tab row, a section
|
|
3
|
+
* list) on the nearest `<Provider webmcp>` data-surface registry for the
|
|
4
|
+
* calling component's lifetime, so an agent can move the person between
|
|
5
|
+
* pages. See `registerLinkSurface` in `@happyvertical/smrt-ui/data`.
|
|
6
|
+
*
|
|
7
|
+
* Re-mounts when the identity (surface id + kind + subject) changes and
|
|
8
|
+
* publishes link/state changes as new revisions. A no-op without a WebMCP
|
|
9
|
+
* Provider (nothing could dispatch to it). Call during component init.
|
|
10
|
+
*/
|
|
11
|
+
import { type DataSurfaceRegistry, type LinkSurfaceOptions } from '@happyvertical/smrt-ui/data';
|
|
12
|
+
export type UseLinkSurfaceOptions = Omit<LinkSurfaceOptions, 'registry'>;
|
|
13
|
+
export declare function useLinkSurface(getOptions: () => UseLinkSurfaceOptions | null, registry?: DataSurfaceRegistry): void;
|
|
14
|
+
//# sourceMappingURL=link-surface.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-surface.svelte.d.ts","sourceRoot":"","sources":["../../src/web/link-surface.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,kBAAkB,EAExB,MAAM,6BAA6B,CAAC;AAIrC,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;AAEzE,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,qBAAqB,GAAG,IAAI,EAC9C,QAAQ,CAAC,EAAE,mBAAmB,GAC7B,IAAI,CAuCN"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useLinkSurface` — mount a navigation list (a menu, a tab row, a section
|
|
3
|
+
* list) on the nearest `<Provider webmcp>` data-surface registry for the
|
|
4
|
+
* calling component's lifetime, so an agent can move the person between
|
|
5
|
+
* pages. See `registerLinkSurface` in `@happyvertical/smrt-ui/data`.
|
|
6
|
+
*
|
|
7
|
+
* Re-mounts when the identity (surface id + kind + subject) changes and
|
|
8
|
+
* publishes link/state changes as new revisions. A no-op without a WebMCP
|
|
9
|
+
* Provider (nothing could dispatch to it). Call during component init.
|
|
10
|
+
*/
|
|
11
|
+
import { registerLinkSurface, } from '@happyvertical/smrt-ui/data';
|
|
12
|
+
import { onDestroy } from 'svelte';
|
|
13
|
+
import { tryGetWebMcpUiContext } from './webmcp-ui-context.js';
|
|
14
|
+
export function useLinkSurface(getOptions, registry) {
|
|
15
|
+
const uiContext = tryGetWebMcpUiContext();
|
|
16
|
+
let handle = null;
|
|
17
|
+
let mountedKey = null;
|
|
18
|
+
let mountedRegistry = null;
|
|
19
|
+
const teardown = () => {
|
|
20
|
+
handle?.destroy();
|
|
21
|
+
handle = null;
|
|
22
|
+
mountedKey = null;
|
|
23
|
+
mountedRegistry = null;
|
|
24
|
+
};
|
|
25
|
+
$effect(() => {
|
|
26
|
+
const options = getOptions();
|
|
27
|
+
const resolved = registry ??
|
|
28
|
+
(uiContext?.enabled ? uiContext.dataSurfaceRegistry : undefined);
|
|
29
|
+
if (!resolved || !options) {
|
|
30
|
+
teardown();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const key = JSON.stringify([
|
|
34
|
+
options.surfaceId,
|
|
35
|
+
options.kind ?? 'list',
|
|
36
|
+
options.subject ?? null,
|
|
37
|
+
(options.controls ?? []).map((control) => control.id),
|
|
38
|
+
]);
|
|
39
|
+
if (key !== mountedKey || resolved !== mountedRegistry) {
|
|
40
|
+
teardown();
|
|
41
|
+
handle = registerLinkSurface({ ...options, registry: resolved });
|
|
42
|
+
mountedKey = key;
|
|
43
|
+
mountedRegistry = resolved;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
handle?.update({ links: options.links, state: options.state });
|
|
47
|
+
});
|
|
48
|
+
onDestroy(teardown);
|
|
49
|
+
}
|