@happyvertical/smrt-svelte 0.51.39 → 0.53.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 +214 -1
- package/agents/components.md +8 -1
- package/agents/workspace.md +24 -0
- package/dist/Provider.svelte +19 -15
- package/dist/Provider.svelte.d.ts +2 -2
- package/dist/Provider.svelte.d.ts.map +1 -1
- package/dist/__tests__/provider-mode-harness.svelte +14 -0
- package/dist/__tests__/provider-mode-harness.svelte.d.ts +11 -0
- package/dist/__tests__/provider-mode-harness.svelte.d.ts.map +1 -0
- package/dist/__tests__/provider-mode-probe.svelte +13 -0
- package/dist/__tests__/provider-mode-probe.svelte.d.ts +8 -0
- package/dist/__tests__/provider-mode-probe.svelte.d.ts.map +1 -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/FileUpload.svelte +120 -16
- package/dist/components/forms/FileUpload.svelte.d.ts +7 -1
- package/dist/components/forms/FileUpload.svelte.d.ts.map +1 -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__/FileUpload.native-form.test.js +249 -0
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte +24 -0
- package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts +10 -0
- package/dist/components/forms/__tests__/FileUploadReset.fixture.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 +597 -0
- package/dist/components/workspace/__tests__/AdminShell.test.js +257 -1
- package/dist/components/workspace/__tests__/TenantNav.test.js +115 -0
- package/dist/components/workspace/__tests__/WorkspaceAccountMenu.test.js +6 -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-state.test.js +25 -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 +1099 -59
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +44 -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 +116 -13
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -2
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte +16 -2
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.svelte.d.ts +2 -0
- package/dist/components/workspace/admin-shell/WorkspaceAccountMenu.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 +57 -1
- package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/state.svelte.js +156 -6
- package/dist/components/workspace/admin-shell/types.d.ts +115 -1
- 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.forms.d.ts +3 -0
- package/dist/i18n/strings.forms.d.ts.map +1 -1
- package/dist/i18n/strings.forms.js +3 -0
- package/dist/i18n/strings.workspace.d.ts +14 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -1
- package/dist/i18n/strings.workspace.js +14 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/provider-mode.test.js +86 -0
- package/dist/state/app-state.svelte.d.ts.map +1 -1
- package/dist/state/app-state.svelte.js +8 -8
- 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 +17 -17
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileUpload native-form wiring (#3260).
|
|
3
|
+
*
|
|
4
|
+
* jsdom has no `DataTransfer` constructor, so these tests cover attribute
|
|
5
|
+
* forwarding, the visually-hidden (not `hidden`) input, the required-error
|
|
6
|
+
* announcement, and the no-DataTransfer fallback. The DataTransfer path and the
|
|
7
|
+
* `new FormData(form)` post are proven in a real browser by
|
|
8
|
+
* `e2e/file-upload.spec.ts`; the form-reset cases below also run the mirror
|
|
9
|
+
* against a jsdom `DataTransfer` stand-in.
|
|
10
|
+
*/
|
|
11
|
+
import { expectNoA11yViolations } from '@happyvertical/smrt-ui/test-support/a11y';
|
|
12
|
+
import { fireEvent, render, screen } from '@testing-library/svelte';
|
|
13
|
+
import userEvent from '@testing-library/user-event';
|
|
14
|
+
import { tick } from 'svelte';
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
16
|
+
import FileUpload from '../FileUpload.svelte';
|
|
17
|
+
import FileUploadResetFixture from './FileUploadReset.fixture.svelte';
|
|
18
|
+
function fileInput(container) {
|
|
19
|
+
const input = container.querySelector('input[type="file"]');
|
|
20
|
+
if (!input)
|
|
21
|
+
throw new Error('file input not found');
|
|
22
|
+
return input;
|
|
23
|
+
}
|
|
24
|
+
const txt = (name, size = 4) => new File(['a'.repeat(size)], name, { type: 'text/plain' });
|
|
25
|
+
describe('FileUpload — native form wiring', () => {
|
|
26
|
+
it('forwards name, capture and required to the file input', () => {
|
|
27
|
+
const { container } = render(FileUpload, {
|
|
28
|
+
props: { name: 'photo', capture: 'environment', required: true },
|
|
29
|
+
});
|
|
30
|
+
const input = fileInput(container);
|
|
31
|
+
expect(input).toHaveAttribute('name', 'photo');
|
|
32
|
+
expect(input).toHaveAttribute('capture', 'environment');
|
|
33
|
+
expect(input).toBeRequired();
|
|
34
|
+
});
|
|
35
|
+
it('omits name, capture and required by default', () => {
|
|
36
|
+
const { container } = render(FileUpload);
|
|
37
|
+
const input = fileInput(container);
|
|
38
|
+
expect(input).not.toHaveAttribute('name');
|
|
39
|
+
expect(input).not.toHaveAttribute('capture');
|
|
40
|
+
expect(input).not.toBeRequired();
|
|
41
|
+
});
|
|
42
|
+
it('keeps the input focusable for native validation but out of the a11y tree and tab order', () => {
|
|
43
|
+
const { container } = render(FileUpload, { props: { required: true } });
|
|
44
|
+
const input = fileInput(container);
|
|
45
|
+
// `hidden` would make the control unfocusable, so the browser could not
|
|
46
|
+
// show its required bubble and would silently block the submit.
|
|
47
|
+
expect(input).not.toHaveAttribute('hidden');
|
|
48
|
+
expect(input).toHaveClass('file-upload__input');
|
|
49
|
+
expect(input).toHaveAttribute('aria-hidden', 'true');
|
|
50
|
+
expect(input).toHaveAttribute('tabindex', '-1');
|
|
51
|
+
// Not nested inside the role="button" drop zone (nested-interactive).
|
|
52
|
+
expect(screen.getByRole('button').contains(input)).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
it('announces a failed required check through the error live region', async () => {
|
|
55
|
+
const { container } = render(FileUpload, { props: { required: true } });
|
|
56
|
+
const input = fileInput(container);
|
|
57
|
+
expect(input.checkValidity()).toBe(false);
|
|
58
|
+
await fireEvent(input, new Event('invalid'));
|
|
59
|
+
expect(screen.getByRole('alert').textContent?.trim()).not.toBe('');
|
|
60
|
+
});
|
|
61
|
+
it('is axe-clean with name, capture and required', async () => {
|
|
62
|
+
const { container } = render(FileUpload, {
|
|
63
|
+
props: {
|
|
64
|
+
label: 'Mill cert photo',
|
|
65
|
+
name: 'photo',
|
|
66
|
+
capture: 'environment',
|
|
67
|
+
required: true,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
await expectNoA11yViolations(container);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('FileUpload — fallback without the DataTransfer constructor', () => {
|
|
74
|
+
it('runs in an environment without DataTransfer', () => {
|
|
75
|
+
expect(typeof globalThis.DataTransfer).toBe('undefined');
|
|
76
|
+
});
|
|
77
|
+
it('keeps the native selection when it matches the accepted list', async () => {
|
|
78
|
+
const { container } = render(FileUpload, { props: { name: 'doc' } });
|
|
79
|
+
const input = fileInput(container);
|
|
80
|
+
await userEvent.upload(input, txt('a.txt'));
|
|
81
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
82
|
+
expect(input.files).toHaveLength(1);
|
|
83
|
+
expect(input.files?.[0].name).toBe('a.txt');
|
|
84
|
+
});
|
|
85
|
+
it('clears the input when a file is removed, so it never posts', async () => {
|
|
86
|
+
const { container } = render(FileUpload, { props: { name: 'doc' } });
|
|
87
|
+
const input = fileInput(container);
|
|
88
|
+
await userEvent.upload(input, txt('a.txt'));
|
|
89
|
+
await userEvent.click(screen.getByRole('button', { name: /remove a\.txt/i }));
|
|
90
|
+
expect(input.files).toHaveLength(0);
|
|
91
|
+
});
|
|
92
|
+
it('clears the input when the pick is rejected, so it never posts', async () => {
|
|
93
|
+
const { container } = render(FileUpload, {
|
|
94
|
+
props: { name: 'doc', maxSize: 1 },
|
|
95
|
+
});
|
|
96
|
+
const input = fileInput(container);
|
|
97
|
+
await userEvent.upload(input, txt('big.txt'));
|
|
98
|
+
expect(screen.queryByText('big.txt')).not.toBeInTheDocument();
|
|
99
|
+
expect(input.files).toHaveLength(0);
|
|
100
|
+
});
|
|
101
|
+
it('clears the input when an accumulated list no longer matches it', async () => {
|
|
102
|
+
const { container } = render(FileUpload, {
|
|
103
|
+
props: { name: 'doc', multiple: true },
|
|
104
|
+
});
|
|
105
|
+
const input = fileInput(container);
|
|
106
|
+
await userEvent.upload(input, txt('a.txt'));
|
|
107
|
+
await userEvent.upload(input, txt('b.txt'));
|
|
108
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
109
|
+
expect(screen.getByText('b.txt')).toBeInTheDocument();
|
|
110
|
+
expect(input.files).toHaveLength(0);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* A real jsdom `FileList` holding `files`: jsdom's `input.files` setter only
|
|
115
|
+
* accepts genuine instances and has no constructor, so the list comes from a
|
|
116
|
+
* detached input and is filled through its implementation object (mirrors
|
|
117
|
+
* smrt-ui's capture test environment).
|
|
118
|
+
*/
|
|
119
|
+
function createFileList(files) {
|
|
120
|
+
const implOf = (wrapper, guard) => {
|
|
121
|
+
const holder = wrapper;
|
|
122
|
+
const key = Object.getOwnPropertySymbols(wrapper).find((s) => guard(holder[s]));
|
|
123
|
+
if (!key)
|
|
124
|
+
throw new Error('jsdom wrapper has no implementation symbol');
|
|
125
|
+
return holder[key];
|
|
126
|
+
};
|
|
127
|
+
const list = document.createElement('input');
|
|
128
|
+
list.type = 'file';
|
|
129
|
+
const fileList = list.files;
|
|
130
|
+
const impl = implOf(fileList, Array.isArray);
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
impl.push(implOf(file, (v) => typeof v === 'object' && v !== null));
|
|
133
|
+
}
|
|
134
|
+
return fileList;
|
|
135
|
+
}
|
|
136
|
+
/** Browser-shaped `DataTransfer` for jsdom: `items.add()` plus a real `files`. */
|
|
137
|
+
class TestDataTransfer {
|
|
138
|
+
#files = [];
|
|
139
|
+
items = {
|
|
140
|
+
add: (file) => {
|
|
141
|
+
this.#files.push(file);
|
|
142
|
+
return null;
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
get files() {
|
|
146
|
+
return createFileList(this.#files);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A reset of the owning form (#3260): SvelteKit `enhance`'s `update()` after a
|
|
151
|
+
* success, `createFormRetry()`'s conditional reset, a reset button and
|
|
152
|
+
* `form.reset()` all empty a native file input, so the list must empty with
|
|
153
|
+
* it. jsdom's reset does not empty file inputs (browsers do), so these
|
|
154
|
+
* assertions prove the component empties its own input.
|
|
155
|
+
*/
|
|
156
|
+
describe.each([
|
|
157
|
+
['the DataTransfer mirror', true],
|
|
158
|
+
['the no-DataTransfer fallback', false],
|
|
159
|
+
])('FileUpload — form reset with %s', (_label, withDataTransfer) => {
|
|
160
|
+
beforeEach(() => {
|
|
161
|
+
if (withDataTransfer)
|
|
162
|
+
vi.stubGlobal('DataTransfer', TestDataTransfer);
|
|
163
|
+
});
|
|
164
|
+
afterEach(() => {
|
|
165
|
+
vi.unstubAllGlobals();
|
|
166
|
+
});
|
|
167
|
+
function mount(props = {}) {
|
|
168
|
+
const onchange = vi.fn();
|
|
169
|
+
const result = render(FileUploadResetFixture, {
|
|
170
|
+
props: { onchange, ...props },
|
|
171
|
+
});
|
|
172
|
+
const form = result.container.querySelector('form');
|
|
173
|
+
const bound = () => screen.getByTestId('bound').getAttribute('data-files');
|
|
174
|
+
return {
|
|
175
|
+
...result,
|
|
176
|
+
form,
|
|
177
|
+
onchange,
|
|
178
|
+
bound,
|
|
179
|
+
input: fileInput(result.container),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function pick(input, files) {
|
|
183
|
+
input.files = createFileList(files);
|
|
184
|
+
await fireEvent.change(input);
|
|
185
|
+
}
|
|
186
|
+
/** Names of the non-empty `doc` entries a native submit would post. */
|
|
187
|
+
const posted = (form) => new FormData(form).getAll('doc')
|
|
188
|
+
.filter((file) => file.name !== '')
|
|
189
|
+
.map((file) => file.name);
|
|
190
|
+
it('form.reset() empties the list, its error and what posts', async () => {
|
|
191
|
+
const { form, input, onchange, bound } = mount({ maxSize: 10 });
|
|
192
|
+
await pick(input, [txt('a.txt'), txt('big.txt', 50)]);
|
|
193
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
194
|
+
expect(bound()).toBe('a.txt');
|
|
195
|
+
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
196
|
+
if (withDataTransfer)
|
|
197
|
+
expect(posted(form)).toEqual(['a.txt']);
|
|
198
|
+
form.reset();
|
|
199
|
+
await tick();
|
|
200
|
+
expect(screen.queryByText('a.txt')).not.toBeInTheDocument();
|
|
201
|
+
expect(screen.queryByRole('alert')).not.toBeInTheDocument();
|
|
202
|
+
expect(onchange).toHaveBeenLastCalledWith([]);
|
|
203
|
+
expect(bound()).toBe('');
|
|
204
|
+
expect(input.files).toHaveLength(0);
|
|
205
|
+
expect(posted(form)).toEqual([]);
|
|
206
|
+
// The next pick posts alone; the reset list is never re-mirrored.
|
|
207
|
+
await pick(input, [txt('b.txt')]);
|
|
208
|
+
expect(screen.getByText('b.txt')).toBeInTheDocument();
|
|
209
|
+
expect(screen.queryByText('a.txt')).not.toBeInTheDocument();
|
|
210
|
+
expect(posted(form)).toEqual(['b.txt']);
|
|
211
|
+
});
|
|
212
|
+
it('a reset button empties the list and required blocks again', async () => {
|
|
213
|
+
const { form, input } = mount({ required: true });
|
|
214
|
+
await pick(input, [txt('a.txt')]);
|
|
215
|
+
expect(input.checkValidity()).toBe(true);
|
|
216
|
+
await fireEvent.click(screen.getByRole('button', { name: 'Reset form' }));
|
|
217
|
+
expect(screen.queryByText('a.txt')).not.toBeInTheDocument();
|
|
218
|
+
expect(posted(form)).toEqual([]);
|
|
219
|
+
expect(input.validity.valueMissing).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
it('empties the list even while disabled, as it empties a disabled input', async () => {
|
|
222
|
+
const { form, input, rerender, bound } = mount();
|
|
223
|
+
await pick(input, [txt('a.txt')]);
|
|
224
|
+
await rerender({ disabled: true });
|
|
225
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
226
|
+
form.reset();
|
|
227
|
+
await tick();
|
|
228
|
+
expect(screen.queryByText('a.txt')).not.toBeInTheDocument();
|
|
229
|
+
expect(bound()).toBe('');
|
|
230
|
+
expect(input.files).toHaveLength(0);
|
|
231
|
+
});
|
|
232
|
+
it('does not report an empty list that was already empty', async () => {
|
|
233
|
+
const { form, onchange } = mount();
|
|
234
|
+
form.reset();
|
|
235
|
+
await tick();
|
|
236
|
+
expect(onchange).not.toHaveBeenCalled();
|
|
237
|
+
});
|
|
238
|
+
it('ignores the reset of another form', async () => {
|
|
239
|
+
const { input, onchange } = mount();
|
|
240
|
+
await pick(input, [txt('a.txt')]);
|
|
241
|
+
onchange.mockClear();
|
|
242
|
+
const other = document.createElement('form');
|
|
243
|
+
document.body.append(other);
|
|
244
|
+
other.reset();
|
|
245
|
+
await tick();
|
|
246
|
+
expect(screen.getByText('a.txt')).toBeInTheDocument();
|
|
247
|
+
expect(onchange).not.toHaveBeenCalled();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import FileUpload from '../FileUpload.svelte';
|
|
3
|
+
|
|
4
|
+
let {
|
|
5
|
+
disabled = false,
|
|
6
|
+
required = false,
|
|
7
|
+
maxSize,
|
|
8
|
+
onchange,
|
|
9
|
+
}: {
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
maxSize?: number;
|
|
13
|
+
onchange?: (files: File[]) => void;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
let files = $state<File[]>([]);
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<!-- A plain form with a bound list and a native reset button (#3260). -->
|
|
20
|
+
<form>
|
|
21
|
+
<FileUpload name="doc" multiple {disabled} {required} {maxSize} {onchange} bind:files />
|
|
22
|
+
<output data-testid="bound" data-files={files.map((file) => file.name).join(',')}></output>
|
|
23
|
+
<button type="reset">Reset form</button>
|
|
24
|
+
</form>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
disabled?: boolean;
|
|
3
|
+
required?: boolean;
|
|
4
|
+
maxSize?: number;
|
|
5
|
+
onchange?: (files: File[]) => void;
|
|
6
|
+
};
|
|
7
|
+
declare const FileUploadReset: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type FileUploadReset = ReturnType<typeof FileUploadReset>;
|
|
9
|
+
export default FileUploadReset;
|
|
10
|
+
//# sourceMappingURL=FileUploadReset.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileUploadReset.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/__tests__/FileUploadReset.fixture.svelte.ts"],"names":[],"mappings":"AAKC,KAAK,gBAAgB,GAAI;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;CACpC,CAAC;AAuBF,QAAA,MAAM,eAAe,sDAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { createControlInteractionRegistry } from '@happyvertical/smrt-ui/forms';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/svelte';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { tick } from 'svelte';
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
vi.mock('../../../hooks/useAppState.svelte.js', () => ({
|
|
7
|
+
useAppState: () => ({ state: { mode: 'default' }, setMode: vi.fn() }),
|
|
8
|
+
}));
|
|
9
|
+
vi.mock('../../../hooks/useSTT.svelte.js', () => ({
|
|
10
|
+
useSTT: () => ({
|
|
11
|
+
isListening: false,
|
|
12
|
+
lastResult: '',
|
|
13
|
+
isReady: false,
|
|
14
|
+
adapterType: null,
|
|
15
|
+
initialize: vi.fn(),
|
|
16
|
+
start: vi.fn(),
|
|
17
|
+
stop: vi.fn(),
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
import Fixture from './form-with-ui-controls.fixture.svelte';
|
|
21
|
+
function captureTools() {
|
|
22
|
+
const registered = [];
|
|
23
|
+
document.modelContext = {
|
|
24
|
+
async registerTool(tool) {
|
|
25
|
+
registered.push(tool);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
return registered;
|
|
29
|
+
}
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
delete document.modelContext;
|
|
32
|
+
});
|
|
33
|
+
describe('rich Form: native attributes, enhance, and smrt-ui controls', () => {
|
|
34
|
+
it('passes native form attributes and attachments through to <form>', async () => {
|
|
35
|
+
const attach = vi.fn();
|
|
36
|
+
render(Fixture, { props: { attach } });
|
|
37
|
+
const form = screen.getByTestId('network-form');
|
|
38
|
+
expect(form.tagName).toBe('FORM');
|
|
39
|
+
expect(form).toHaveAttribute('enctype', 'multipart/form-data');
|
|
40
|
+
expect(form).toHaveAttribute('novalidate');
|
|
41
|
+
expect(form).toHaveAttribute('method', 'POST');
|
|
42
|
+
expect(form).toHaveAttribute('action', '?/create');
|
|
43
|
+
expect(form).toHaveAccessibleName('Set up your network');
|
|
44
|
+
expect(attach).toHaveBeenCalledWith(form);
|
|
45
|
+
});
|
|
46
|
+
it('applies an enhance action to the form and tears it down on unmount', () => {
|
|
47
|
+
const destroy = vi.fn();
|
|
48
|
+
const enhance = vi.fn(() => ({ destroy }));
|
|
49
|
+
const { unmount } = render(Fixture, { props: { enhance } });
|
|
50
|
+
expect(enhance).toHaveBeenCalledWith(screen.getByTestId('network-form'));
|
|
51
|
+
unmount();
|
|
52
|
+
expect(destroy).toHaveBeenCalledTimes(1);
|
|
53
|
+
});
|
|
54
|
+
it('lets an enhanced submit through without preventing it', async () => {
|
|
55
|
+
let submitted;
|
|
56
|
+
const enhance = (form) => {
|
|
57
|
+
const listener = (event) => {
|
|
58
|
+
submitted = event;
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
};
|
|
61
|
+
form.addEventListener('submit', listener);
|
|
62
|
+
return { destroy: () => form.removeEventListener('submit', listener) };
|
|
63
|
+
};
|
|
64
|
+
render(Fixture, { props: { enhance } });
|
|
65
|
+
await userEvent.click(screen.getByRole('button', { name: 'Create' }));
|
|
66
|
+
expect(submitted).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
it('describes smrt-ui controls and rich fields in one stage-only tool', async () => {
|
|
69
|
+
const registered = captureTools();
|
|
70
|
+
render(Fixture);
|
|
71
|
+
await tick();
|
|
72
|
+
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(0));
|
|
73
|
+
const tool = registered.at(-1);
|
|
74
|
+
expect(tool.name).toBe('setup-network_stage_changes');
|
|
75
|
+
expect(tool.inputSchema).toMatchObject({
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
tagline: { type: 'string', title: 'Tagline' },
|
|
79
|
+
name: { type: 'string', title: 'Network name' },
|
|
80
|
+
kind: { type: 'string', title: 'Kind of network' },
|
|
81
|
+
town: {
|
|
82
|
+
type: 'string',
|
|
83
|
+
title: 'Home town',
|
|
84
|
+
enum: ['lacombe', 'blackfalds'],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
it('stages smrt-ui control proposals for review and never writes them', async () => {
|
|
90
|
+
const registered = captureTools();
|
|
91
|
+
const registry = createControlInteractionRegistry();
|
|
92
|
+
render(Fixture, { props: { interactionRegistry: registry } });
|
|
93
|
+
await tick();
|
|
94
|
+
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(0));
|
|
95
|
+
const tool = registered.at(-1);
|
|
96
|
+
const result = await tool.execute({
|
|
97
|
+
name: 'Central Alberta News',
|
|
98
|
+
town: 'blackfalds',
|
|
99
|
+
tagline: 'Local first',
|
|
100
|
+
});
|
|
101
|
+
expect(result).toBe('Staged 3 changes for review');
|
|
102
|
+
expect(screen.getByRole('textbox', { name: 'Network name' })).toHaveValue('');
|
|
103
|
+
await waitFor(() => expect(screen.getByRole('region', { name: 'Review proposed changes' })).toBeInTheDocument());
|
|
104
|
+
expect(registry.get({ formId: 'setup-network', controlId: 'name' })?.state.staged
|
|
105
|
+
?.value).toBe('Central Alberta News');
|
|
106
|
+
expect(screen.queryByText(/setup-network\//)).not.toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
it('marks a staged smrt-ui proposal stale when the person types over it', async () => {
|
|
109
|
+
const registered = captureTools();
|
|
110
|
+
const registry = createControlInteractionRegistry();
|
|
111
|
+
render(Fixture, { props: { interactionRegistry: registry } });
|
|
112
|
+
await tick();
|
|
113
|
+
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(0));
|
|
114
|
+
await registered.at(-1).execute({ name: 'Proposed' });
|
|
115
|
+
await userEvent.type(screen.getByRole('textbox', { name: 'Network name' }), 'Mine');
|
|
116
|
+
await waitFor(() => expect(registry.get({ formId: 'setup-network', controlId: 'name' })?.state
|
|
117
|
+
.staged?.stale).toBe(true));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
@@ -1251,7 +1251,9 @@ describe('Form WebMCP staged-edit intent', () => {
|
|
|
1251
1251
|
const fullname = screen.getByRole('textbox', { name: 'Full name' });
|
|
1252
1252
|
expect(fullname).toHaveAttribute('data-smrt-subject-type', 'person');
|
|
1253
1253
|
expect(fullname).toHaveAttribute('data-smrt-subject-id', 'person-1');
|
|
1254
|
-
|
|
1254
|
+
// The review names the field, not the registry subject (plain labels).
|
|
1255
|
+
expect(await screen.findByRole('button', { name: 'Apply Full name' })).toBeInTheDocument();
|
|
1256
|
+
expect(screen.queryByText(/person:person-1/)).not.toBeInTheDocument();
|
|
1255
1257
|
await view.rerender({
|
|
1256
1258
|
webmcp: true,
|
|
1257
1259
|
showAge: false,
|
|
@@ -1263,12 +1265,12 @@ describe('Form WebMCP staged-edit intent', () => {
|
|
|
1263
1265
|
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(_regLenBefore));
|
|
1264
1266
|
expect(await registered.at(-1)?.execute({ fullname: 'Grace' })).toBe('Staged 1 change for review');
|
|
1265
1267
|
expect(fullname).toHaveAttribute('data-smrt-subject-id', 'person-2');
|
|
1266
|
-
expect(await screen.
|
|
1268
|
+
expect(await screen.findByRole('button', { name: 'Apply Full name' })).toBeInTheDocument();
|
|
1267
1269
|
await userEvent.click(screen.getByRole('button', { name: 'Mutate subject' }));
|
|
1268
1270
|
await tick();
|
|
1269
1271
|
expect(await registered.at(-1)?.execute({ fullname: 'Katherine' })).toBe('Staged 1 change for review');
|
|
1270
1272
|
expect(fullname).toHaveAttribute('data-smrt-subject-id', 'person-mutated');
|
|
1271
|
-
expect(await screen.
|
|
1273
|
+
expect(await screen.findByRole('button', { name: 'Apply Full name' })).toBeInTheDocument();
|
|
1272
1274
|
});
|
|
1273
1275
|
it('publishes money in integer minor units and applies cents without rescaling', async () => {
|
|
1274
1276
|
const registered = [];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createControlInteractionRegistry } from '@happyvertical/smrt-ui/forms';
|
|
2
|
+
import { render, screen, waitFor } from '@testing-library/svelte';
|
|
3
|
+
import { tick } from 'svelte';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import Fixture from './form-scope.fixture.svelte';
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
delete document.modelContext;
|
|
8
|
+
});
|
|
9
|
+
describe('FormScope', () => {
|
|
10
|
+
it('registers a stage-only tool for the smrt-ui controls inside a plain container', async () => {
|
|
11
|
+
const registered = [];
|
|
12
|
+
document.modelContext = {
|
|
13
|
+
async registerTool(tool) {
|
|
14
|
+
registered.push(tool);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
const registry = createControlInteractionRegistry();
|
|
18
|
+
const { container, rerender } = render(Fixture, {
|
|
19
|
+
props: { interactionRegistry: registry },
|
|
20
|
+
});
|
|
21
|
+
expect(container.querySelector('form')).toBeNull();
|
|
22
|
+
await tick();
|
|
23
|
+
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(0));
|
|
24
|
+
const tool = registered.at(-1);
|
|
25
|
+
expect(tool.name).toBe('new_site_stage_changes');
|
|
26
|
+
expect(Object.keys(tool.inputSchema.properties).sort()).toEqual([
|
|
27
|
+
'name',
|
|
28
|
+
'town',
|
|
29
|
+
]);
|
|
30
|
+
const result = JSON.parse(await tool.execute({ name: 'Lacombe News', key: 'x' }));
|
|
31
|
+
expect(result).toMatchObject({ ok: true, staged: 1, skipped: ['key'] });
|
|
32
|
+
expect(screen.getByRole('textbox', { name: 'Site name' })).toHaveValue('');
|
|
33
|
+
await waitFor(() => expect(screen.getByRole('region', { name: 'Review proposed changes' })).toBeInTheDocument());
|
|
34
|
+
const before = registered.length;
|
|
35
|
+
await rerender({ interactionRegistry: registry, showTown: false });
|
|
36
|
+
await vi.waitFor(() => expect(registered.length).toBeGreaterThan(before));
|
|
37
|
+
expect(Object.keys(registered.at(-1).inputSchema.properties)).toEqual(['name']);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
type ControlInteractionRegistry,
|
|
4
|
+
FormGroup,
|
|
5
|
+
Input,
|
|
6
|
+
} from '@happyvertical/smrt-ui/forms';
|
|
7
|
+
import FormScope from '../FormScope.svelte';
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
interactionRegistry = undefined,
|
|
11
|
+
showTown = true,
|
|
12
|
+
}: {
|
|
13
|
+
interactionRegistry?: ControlInteractionRegistry;
|
|
14
|
+
showTown?: boolean;
|
|
15
|
+
} = $props();
|
|
16
|
+
let name = $state('');
|
|
17
|
+
let town = $state('');
|
|
18
|
+
let secret = $state('');
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<FormScope formId="new-site" purpose="Start a new town site" {interactionRegistry}>
|
|
22
|
+
<div class="wizard">
|
|
23
|
+
<FormGroup label="Site name" id="site-name"><Input name="name" bind:value={name} /></FormGroup>
|
|
24
|
+
{#if showTown}
|
|
25
|
+
<FormGroup label="Town" id="site-town"><Input name="town" bind:value={town} /></FormGroup>
|
|
26
|
+
{/if}
|
|
27
|
+
<FormGroup label="Access key" id="site-key"><Input name="key" type="password" bind:value={secret} /></FormGroup>
|
|
28
|
+
<button type="button">Continue</button>
|
|
29
|
+
</div>
|
|
30
|
+
</FormScope>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ControlInteractionRegistry } from '@happyvertical/smrt-ui/forms';
|
|
2
|
+
import FormScope from '../FormScope.svelte';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
interactionRegistry?: ControlInteractionRegistry;
|
|
5
|
+
showTown?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const FormScope: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type FormScope = ReturnType<typeof FormScope>;
|
|
9
|
+
export default FormScope;
|
|
10
|
+
//# sourceMappingURL=form-scope.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-scope.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/__tests__/form-scope.fixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,0BAA0B,EAGhC,MAAM,8BAA8B,CAAC;AACtC,OAAO,SAAS,MAAM,qBAAqB,CAAC;AAE3C,KAAK,gBAAgB,GAAI;IACxB,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA2BF,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/** Rich Form hosting smrt-ui primitives, native attributes, and `enhance`. */
|
|
3
|
+
import {
|
|
4
|
+
Combobox,
|
|
5
|
+
type ControlInteractionRegistry,
|
|
6
|
+
FormGroup,
|
|
7
|
+
Input,
|
|
8
|
+
Select,
|
|
9
|
+
} from '@happyvertical/smrt-ui/forms';
|
|
10
|
+
import type { Attachment } from 'svelte/attachments';
|
|
11
|
+
import Form, { type FormEnhance } from '../Form.svelte';
|
|
12
|
+
import TextInput from '../TextInput.svelte';
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
enhance = undefined,
|
|
16
|
+
attach = undefined,
|
|
17
|
+
interactionRegistry = undefined,
|
|
18
|
+
nameValue = $bindable(''),
|
|
19
|
+
}: {
|
|
20
|
+
enhance?: FormEnhance;
|
|
21
|
+
attach?: Attachment<HTMLFormElement>;
|
|
22
|
+
interactionRegistry?: ControlInteractionRegistry;
|
|
23
|
+
nameValue?: string;
|
|
24
|
+
} = $props();
|
|
25
|
+
let kind = $state('news');
|
|
26
|
+
let town = $state('lacombe');
|
|
27
|
+
let tagline = $state('');
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
{#if attach}
|
|
31
|
+
<Form
|
|
32
|
+
formId="setup-network"
|
|
33
|
+
webmcp
|
|
34
|
+
method="POST"
|
|
35
|
+
action="?/create"
|
|
36
|
+
enctype="multipart/form-data"
|
|
37
|
+
novalidate
|
|
38
|
+
aria-label="Set up your network"
|
|
39
|
+
data-testid="network-form"
|
|
40
|
+
{enhance}
|
|
41
|
+
{interactionRegistry}
|
|
42
|
+
{@attach attach}
|
|
43
|
+
>
|
|
44
|
+
{@render fields()}
|
|
45
|
+
</Form>
|
|
46
|
+
{:else}
|
|
47
|
+
<Form
|
|
48
|
+
formId="setup-network"
|
|
49
|
+
webmcp
|
|
50
|
+
method="POST"
|
|
51
|
+
action="?/create"
|
|
52
|
+
enctype="multipart/form-data"
|
|
53
|
+
novalidate
|
|
54
|
+
aria-label="Set up your network"
|
|
55
|
+
data-testid="network-form"
|
|
56
|
+
{enhance}
|
|
57
|
+
{interactionRegistry}
|
|
58
|
+
>
|
|
59
|
+
{@render fields()}
|
|
60
|
+
</Form>
|
|
61
|
+
{/if}
|
|
62
|
+
|
|
63
|
+
{#snippet fields()}
|
|
64
|
+
<FormGroup label="Network name" id="name">
|
|
65
|
+
<Input name="name" bind:value={nameValue} />
|
|
66
|
+
</FormGroup>
|
|
67
|
+
<FormGroup label="Kind of network" id="kind">
|
|
68
|
+
<Select name="kind" bind:value={kind}>
|
|
69
|
+
<option value="news">News</option>
|
|
70
|
+
<option value="aggregator">Roundup</option>
|
|
71
|
+
</Select>
|
|
72
|
+
</FormGroup>
|
|
73
|
+
<Combobox
|
|
74
|
+
name="town"
|
|
75
|
+
label="Home town"
|
|
76
|
+
options={[
|
|
77
|
+
{ value: 'lacombe', label: 'Lacombe' },
|
|
78
|
+
{ value: 'blackfalds', label: 'Blackfalds' },
|
|
79
|
+
]}
|
|
80
|
+
bind:value={town}
|
|
81
|
+
/>
|
|
82
|
+
<TextInput name="tagline" label="Tagline" bind:value={tagline} />
|
|
83
|
+
<button type="submit">Create</button>
|
|
84
|
+
{/snippet}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Rich Form hosting smrt-ui primitives, native attributes, and `enhance`. */
|
|
2
|
+
import { type ControlInteractionRegistry } from '@happyvertical/smrt-ui/forms';
|
|
3
|
+
import type { Attachment } from 'svelte/attachments';
|
|
4
|
+
import { type FormEnhance } from '../Form.svelte';
|
|
5
|
+
type $$ComponentProps = {
|
|
6
|
+
enhance?: FormEnhance;
|
|
7
|
+
attach?: Attachment<HTMLFormElement>;
|
|
8
|
+
interactionRegistry?: ControlInteractionRegistry;
|
|
9
|
+
nameValue?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const FormWithUiControls: import("svelte").Component<$$ComponentProps, {}, "nameValue">;
|
|
12
|
+
type FormWithUiControls = ReturnType<typeof FormWithUiControls>;
|
|
13
|
+
export default FormWithUiControls;
|
|
14
|
+
//# sourceMappingURL=form-with-ui-controls.fixture.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-with-ui-controls.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/__tests__/form-with-ui-controls.fixture.svelte.ts"],"names":[],"mappings":"AAGA,8EAA8E;AAC9E,OAAO,EAEL,KAAK,0BAA0B,EAIhC,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAa,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGvD,KAAK,gBAAgB,GAAI;IACxB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,UAAU,CAAC,eAAe,CAAC,CAAC;IACrC,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAiDF,QAAA,MAAM,kBAAkB,+DAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
|
|
@@ -16,6 +16,7 @@ export { default as DateTimeInput } from './DateTimeInput.svelte';
|
|
|
16
16
|
export { default as FileUpload } from './FileUpload.svelte';
|
|
17
17
|
export { default as Form } from './Form.svelte';
|
|
18
18
|
export { default as FormMicButton } from './FormMicButton.svelte';
|
|
19
|
+
export { default as FormScope } from './FormScope.svelte';
|
|
19
20
|
export { default as MeasurementInput } from './MeasurementInput.svelte';
|
|
20
21
|
export { default as MoneyInput } from './MoneyInput.svelte';
|
|
21
22
|
export { default as NumberInput } from './NumberInput.svelte';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACL,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EACV,YAAY,EACZ,cAAc,EACd,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACL,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EACV,YAAY,EACZ,cAAc,EACd,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -18,6 +18,7 @@ export { default as DateTimeInput } from './DateTimeInput.svelte';
|
|
|
18
18
|
export { default as FileUpload } from './FileUpload.svelte';
|
|
19
19
|
export { default as Form } from './Form.svelte';
|
|
20
20
|
export { default as FormMicButton } from './FormMicButton.svelte';
|
|
21
|
+
export { default as FormScope } from './FormScope.svelte';
|
|
21
22
|
export { default as MeasurementInput } from './MeasurementInput.svelte';
|
|
22
23
|
export { default as MoneyInput } from './MoneyInput.svelte';
|
|
23
24
|
export { default as NumberInput } from './NumberInput.svelte';
|