@texaryn/svelte 0.0.0-stage → 0.2.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +190 -0
  3. package/README.md +116 -2
  4. package/dist/components/ArrayControl.svelte +210 -0
  5. package/dist/components/ArrayControl.svelte.d.ts +8 -0
  6. package/dist/components/ArrayControl.svelte.d.ts.map +1 -0
  7. package/dist/components/DocumentList.svelte +22 -0
  8. package/dist/components/DocumentList.svelte.d.ts +9 -0
  9. package/dist/components/DocumentList.svelte.d.ts.map +1 -0
  10. package/dist/components/DocumentNode.svelte +68 -0
  11. package/dist/components/DocumentNode.svelte.d.ts +14 -0
  12. package/dist/components/DocumentNode.svelte.d.ts.map +1 -0
  13. package/dist/components/DocumentRoot.svelte +33 -0
  14. package/dist/components/DocumentRoot.svelte.d.ts +13 -0
  15. package/dist/components/DocumentRoot.svelte.d.ts.map +1 -0
  16. package/dist/components/DocumentTable.svelte +35 -0
  17. package/dist/components/DocumentTable.svelte.d.ts +9 -0
  18. package/dist/components/DocumentTable.svelte.d.ts.map +1 -0
  19. package/dist/components/ErrorSummary.svelte +41 -0
  20. package/dist/components/ErrorSummary.svelte.d.ts +21 -0
  21. package/dist/components/ErrorSummary.svelte.d.ts.map +1 -0
  22. package/dist/components/FieldErrors.svelte +12 -0
  23. package/dist/components/FieldErrors.svelte.d.ts +23 -0
  24. package/dist/components/FieldErrors.svelte.d.ts.map +1 -0
  25. package/dist/components/FieldWidget.svelte +109 -0
  26. package/dist/components/FieldWidget.svelte.d.ts +22 -0
  27. package/dist/components/FieldWidget.svelte.d.ts.map +1 -0
  28. package/dist/components/FormRoot.svelte +98 -0
  29. package/dist/components/FormRoot.svelte.d.ts +16 -0
  30. package/dist/components/FormRoot.svelte.d.ts.map +1 -0
  31. package/dist/components/NodeRenderer.svelte +19 -0
  32. package/dist/components/NodeRenderer.svelte.d.ts +8 -0
  33. package/dist/components/NodeRenderer.svelte.d.ts.map +1 -0
  34. package/dist/components/ObjectLayout.svelte +72 -0
  35. package/dist/components/ObjectLayout.svelte.d.ts +8 -0
  36. package/dist/components/ObjectLayout.svelte.d.ts.map +1 -0
  37. package/dist/context.d.ts +13 -0
  38. package/dist/context.d.ts.map +1 -0
  39. package/dist/context.js +12 -0
  40. package/dist/field-props.d.ts +20 -0
  41. package/dist/field-props.d.ts.map +1 -0
  42. package/dist/field-props.js +30 -0
  43. package/dist/field.d.ts +34 -0
  44. package/dist/field.d.ts.map +1 -0
  45. package/dist/field.js +116 -0
  46. package/dist/form.d.ts +17 -0
  47. package/dist/form.d.ts.map +1 -0
  48. package/dist/form.js +20 -0
  49. package/dist/index.d.ts +21 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +14 -0
  52. package/dist/registry.d.ts +4 -0
  53. package/dist/registry.d.ts.map +1 -0
  54. package/dist/registry.js +24 -0
  55. package/dist/store.d.ts +4 -0
  56. package/dist/store.d.ts.map +1 -0
  57. package/dist/store.js +7 -0
  58. package/dist/svelte.d.ts +5 -0
  59. package/dist/widget.d.ts +10 -0
  60. package/dist/widget.d.ts.map +1 -0
  61. package/dist/widget.js +1 -0
  62. package/package.json +68 -3
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import type { DocumentNode, DocumentRuntime } from '@texaryn/core'
3
+ import type { RendererRegistry } from '@texaryn/core'
4
+ import type { DocumentWidgetComponent } from '../widget.js'
5
+ import DocumentNodeView from './DocumentNode.svelte'
6
+
7
+ interface Props {
8
+ runtime: DocumentRuntime
9
+ registry?: RendererRegistry<DocumentWidgetComponent, DocumentNode>
10
+ onActionError?: (error: unknown) => void
11
+ children?: import('svelte').Snippet
12
+ }
13
+
14
+ let { runtime, registry, onActionError, children }: Props = $props()
15
+ let document = $state<import('@texaryn/core').UIDocumentV2 | undefined>()
16
+ $effect(() => {
17
+ const store = runtime.document
18
+ document = store.getSnapshot()
19
+ return store.subscribe(() => { document = store.getSnapshot() })
20
+ })
21
+ </script>
22
+
23
+ {#if document?.nodes[document.rootId]}
24
+ <DocumentNodeView
25
+ nodeId={document.rootId}
26
+ {runtime}
27
+ {document}
28
+ {registry}
29
+ {onActionError}
30
+ />
31
+ {/if}
32
+
33
+ {@render children?.()}
@@ -0,0 +1,13 @@
1
+ import type { DocumentNode, DocumentRuntime } from '@texaryn/core';
2
+ import type { RendererRegistry } from '@texaryn/core';
3
+ import type { DocumentWidgetComponent } from '../widget.js';
4
+ interface Props {
5
+ runtime: DocumentRuntime;
6
+ registry?: RendererRegistry<DocumentWidgetComponent, DocumentNode>;
7
+ onActionError?: (error: unknown) => void;
8
+ children?: import('svelte').Snippet;
9
+ }
10
+ declare const DocumentRoot: import("svelte").Component<Props, {}, "">;
11
+ type DocumentRoot = ReturnType<typeof DocumentRoot>;
12
+ export default DocumentRoot;
13
+ //# sourceMappingURL=DocumentRoot.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/DocumentRoot.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAIzD,UAAU,KAAK;IACb,OAAO,EAAE,eAAe,CAAA;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC,uBAAuB,EAAE,YAAY,CAAC,CAAA;IAClE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACxC,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAA;CACpC;AAyBH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import type { DocumentCollectionRow, DocumentRuntime, TableNode } from '@texaryn/core'
3
+
4
+ let { node, runtime }: { node: TableNode; runtime: DocumentRuntime } = $props()
5
+ let rows = $state<readonly DocumentCollectionRow[]>([])
6
+
7
+ $effect(() => {
8
+ const store = runtime.getCollection(node.id)
9
+ if (!store) {
10
+ rows = []
11
+ return
12
+ }
13
+ rows = store.getSnapshot()
14
+ return store.subscribe(() => { rows = store.getSnapshot() })
15
+ })
16
+ </script>
17
+
18
+ <table>
19
+ <thead>
20
+ <tr>
21
+ {#each node.columns as column (column.id)}
22
+ <th scope="col">{column.label}</th>
23
+ {/each}
24
+ </tr>
25
+ </thead>
26
+ <tbody>
27
+ {#each rows as row (row.id)}
28
+ <tr>
29
+ {#each node.columns as column, index (column.id)}
30
+ <td>{row.cells[index] === null ? '' : String(row.cells[index])}</td>
31
+ {/each}
32
+ </tr>
33
+ {/each}
34
+ </tbody>
35
+ </table>
@@ -0,0 +1,9 @@
1
+ import type { DocumentRuntime, TableNode } from '@texaryn/core';
2
+ type $$ComponentProps = {
3
+ node: TableNode;
4
+ runtime: DocumentRuntime;
5
+ };
6
+ declare const DocumentTable: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type DocumentTable = ReturnType<typeof DocumentTable>;
8
+ export default DocumentTable;
9
+ //# sourceMappingURL=DocumentTable.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentTable.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/DocumentTable.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAyB,eAAe,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEtF,KAAK,gBAAgB,GAAI;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAuCxE,QAAA,MAAM,aAAa,sDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,41 @@
1
+ <script lang="ts">
2
+ import { tick } from 'svelte'
3
+ import { createFailedSubmitTracker, visibleErrorLabel, visibleErrorMessages } from '@texaryn/core'
4
+ import type { VisibleError } from '@texaryn/core'
5
+ import { useFormContext } from '../context.js'
6
+ import { makeId } from '../field-props.js'
7
+
8
+ export let focus = true
9
+
10
+ const context = useFormContext()
11
+ const visibleErrors = context.form.visibleErrors
12
+ const submission = context.form.submission
13
+ const messages = context.messages
14
+ const tracker = createFailedSubmitTracker(context.form.runtime.submission.getSnapshot())
15
+ const headingId = makeId(context.idPrefix, 'error-summary', 'heading')
16
+ let container: HTMLDivElement | undefined
17
+
18
+ $: if (tracker.settle($submission, $visibleErrors)) {
19
+ void tick().then(() => {
20
+ if (focus && container?.isConnected) container.focus()
21
+ })
22
+ }
23
+
24
+ function details(entry: VisibleError): string {
25
+ return $messages.errorSummaryDetail({ messages: visibleErrorMessages(entry) })
26
+ }
27
+ </script>
28
+
29
+ {#if $visibleErrors.length > 0}
30
+ <div bind:this={container} role="group" tabindex="-1" aria-labelledby={headingId}>
31
+ <h2 id={headingId}>{$messages.errorSummaryHeading({ count: $visibleErrors.length })}</h2>
32
+ <ul>
33
+ {#each $visibleErrors as entry (entry.nodeId)}
34
+ <li>
35
+ <a href={`#${makeId(context.idPrefix, entry.nodeId, 'input')}`}>{visibleErrorLabel(entry)}</a>
36
+ {details(entry)}
37
+ </li>
38
+ {/each}
39
+ </ul>
40
+ </div>
41
+ {/if}
@@ -0,0 +1,21 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const ErrorSummary: $$__sveltets_2_IsomorphicComponent<{
15
+ focus?: boolean;
16
+ }, {
17
+ [evt: string]: CustomEvent<any>;
18
+ }, {}, {}, string>;
19
+ type ErrorSummary = InstanceType<typeof ErrorSummary>;
20
+ export default ErrorSummary;
21
+ //# sourceMappingURL=ErrorSummary.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorSummary.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ErrorSummary.svelte.ts"],"names":[],"mappings":"AAqDA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,YAAY;;;;kBAA+E,CAAC;AAChF,KAAK,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC;AACxD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ <script lang="ts">
2
+ import type { ValidationError } from '@texaryn/core'
3
+
4
+ export let id: string
5
+ export let errors: readonly ValidationError[] = []
6
+ </script>
7
+
8
+ <div {id} aria-live="polite" aria-atomic="true">
9
+ {#each errors as error, index (`${error.instancePointer}:${error.keyword}:${index}`)}
10
+ <div>{error.message ?? error.keyword}</div>
11
+ {/each}
12
+ </div>
@@ -0,0 +1,23 @@
1
+ import type { ValidationError } from '@texaryn/core';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const FieldErrors: $$__sveltets_2_IsomorphicComponent<{
16
+ id: string;
17
+ errors?: readonly ValidationError[];
18
+ }, {
19
+ [evt: string]: CustomEvent<any>;
20
+ }, {}, {}, string>;
21
+ type FieldErrors = InstanceType<typeof FieldErrors>;
22
+ export default FieldErrors;
23
+ //# sourceMappingURL=FieldErrors.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldErrors.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/FieldErrors.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAiBrD,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,WAAW;QAViC,MAAM;aAAW,SAAS,eAAe,EAAE;;;kBAUG,CAAC;AAC/E,KAAK,WAAW,GAAG,YAAY,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,109 @@
1
+ <script lang="ts">
2
+ import { writable } from 'svelte/store'
3
+ import type { FieldNode, UINode } from '@texaryn/core'
4
+ import { useFormContext } from '../context.js'
5
+ import { createFieldBinding, sameEnumValue } from '../field.js'
6
+ import FieldErrors from './FieldErrors.svelte'
7
+
8
+ export let node: UINode
9
+
10
+ const context = useFormContext()
11
+ const nodeId = writable(node.id)
12
+ $: nodeId.set(node.id)
13
+
14
+ const field = createFieldBinding(context.form, nodeId, context.idPrefix, context.messages)
15
+ const {
16
+ node: fieldNode,
17
+ value,
18
+ visibleErrors,
19
+ display,
20
+ label,
21
+ description,
22
+ labelFor,
23
+ descriptionId,
24
+ errorId,
25
+ aria,
26
+ messages,
27
+ } = field
28
+
29
+ $: enumOptions = ($fieldNode?.enumValues ?? []).map((entry, index) => ({
30
+ token: String(index),
31
+ value: entry.value,
32
+ title: entry.title ?? String(entry.value),
33
+ }))
34
+ $: selectedToken = enumOptions.find((option) => sameEnumValue(option.value, $value))?.token ?? ''
35
+
36
+ function handleInput(event: Event): void {
37
+ field.setRaw((event.currentTarget as HTMLInputElement | HTMLTextAreaElement).value)
38
+ }
39
+
40
+ function handleSelect(event: Event): void {
41
+ const select = event.currentTarget as HTMLSelectElement
42
+ if ($fieldNode?.readOnly) {
43
+ select.value = selectedToken
44
+ return
45
+ }
46
+ field.setRaw(select.value, select.value)
47
+ }
48
+
49
+ function handleCheckbox(event: Event): void {
50
+ const checkbox = event.currentTarget as HTMLInputElement
51
+ if ($fieldNode?.readOnly) {
52
+ checkbox.checked = Boolean($value)
53
+ return
54
+ }
55
+ field.setValue(checkbox.checked)
56
+ }
57
+
58
+ function handleBlur(): void {
59
+ field.onBlur()
60
+ }
61
+ </script>
62
+
63
+ {#if $fieldNode && $aria}
64
+ <div>
65
+ <label for={$labelFor}>
66
+ {#if $aria['aria-required'] && $messages.requiredIndicator().placement === 'before'}
67
+ {@const indicator = $messages.requiredIndicator()}
68
+ <span aria-hidden="true">{indicator.text} </span>
69
+ {/if}
70
+ {$label}
71
+ {#if $aria['aria-required'] && $messages.requiredIndicator().placement === 'after'}
72
+ {@const indicator = $messages.requiredIndicator()}
73
+ <span aria-hidden="true"> {indicator.text}</span>
74
+ {/if}
75
+ </label>
76
+
77
+ {#if $fieldNode.enumValues != null && $fieldNode.enumValues.length > 0}
78
+ <select {...$aria} value={selectedToken} on:change={handleSelect} on:blur={handleBlur}>
79
+ <option value=""></option>
80
+ {#each enumOptions as option (option.token)}
81
+ <option value={option.token}>{option.title}</option>
82
+ {/each}
83
+ </select>
84
+ {:else if $fieldNode.fieldType === 'boolean'}
85
+ <input
86
+ {...$aria}
87
+ type="checkbox"
88
+ checked={Boolean($value)}
89
+ on:change={handleCheckbox}
90
+ on:blur={handleBlur}
91
+ />
92
+ {:else if $fieldNode.widget === 'textarea'}
93
+ <textarea {...$aria} value={$display} on:input={handleInput} on:blur={handleBlur}></textarea>
94
+ {:else}
95
+ <input
96
+ {...$aria}
97
+ type={$fieldNode.fieldType === 'number' || $fieldNode.fieldType === 'integer' ? 'number' : 'text'}
98
+ value={$display}
99
+ on:input={handleInput}
100
+ on:blur={handleBlur}
101
+ />
102
+ {/if}
103
+
104
+ {#if $description}
105
+ <div id={$descriptionId}>{$description}</div>
106
+ {/if}
107
+ <FieldErrors id={$errorId} errors={$visibleErrors} />
108
+ </div>
109
+ {/if}
@@ -0,0 +1,22 @@
1
+ import type { UINode } from '@texaryn/core';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const FieldWidget: $$__sveltets_2_IsomorphicComponent<{
16
+ node: UINode;
17
+ }, {
18
+ [evt: string]: CustomEvent<any>;
19
+ }, {}, {}, string>;
20
+ type FieldWidget = InstanceType<typeof FieldWidget>;
21
+ export default FieldWidget;
22
+ //# sourceMappingURL=FieldWidget.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldWidget.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/FieldWidget.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,MAAM,EAAE,MAAM,eAAe,CAAA;AAyGtD,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,WAAW;UAVsB,MAAM;;;kBAUmD,CAAC;AAC/E,KAAK,WAAW,GAAG,YAAY,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import { onDestroy } from 'svelte'
3
+ import type { Snippet } from 'svelte'
4
+ import { englishMessages } from '@texaryn/core'
5
+ import type { FormMessages, RendererRegistry, UINode } from '@texaryn/core'
6
+ import { derived, get, writable } from 'svelte/store'
7
+ import type { SvelteFormBinding } from '../form.js'
8
+ import type { WidgetComponent } from '../widget.js'
9
+ import { provideFormContext } from '../context.js'
10
+ import { createDefaultRegistry } from '../registry.js'
11
+ import ErrorSummary from './ErrorSummary.svelte'
12
+ import NodeRenderer from './NodeRenderer.svelte'
13
+
14
+ interface Props {
15
+ form: SvelteFormBinding
16
+ registry?: RendererRegistry<WidgetComponent>
17
+ messages?: FormMessages
18
+ idPrefix?: string
19
+ destroyOnUnmount?: boolean
20
+ children?: Snippet
21
+ }
22
+
23
+ let {
24
+ form,
25
+ registry = createDefaultRegistry(),
26
+ messages = englishMessages,
27
+ idPrefix,
28
+ destroyOnUnmount = true,
29
+ children,
30
+ }: Props = $props()
31
+
32
+ function capture<T>(read: () => T): T {
33
+ return read()
34
+ }
35
+
36
+ const formStore = writable(capture(() => form))
37
+ const currentForm: SvelteFormBinding = {
38
+ get runtime() {
39
+ return get(formStore).runtime
40
+ },
41
+ document: derived(formStore, ($form, set) => $form.document.subscribe(set)),
42
+ data: derived(formStore, ($form, set) => $form.data.subscribe(set)),
43
+ submission: derived(formStore, ($form, set) => $form.submission.subscribe(set)),
44
+ visibleErrors: derived(formStore, ($form, set) => $form.visibleErrors.subscribe(set)),
45
+ dispatch: (command) => get(formStore).dispatch(command),
46
+ getNodeState: (nodeId) => get(formStore).getNodeState(nodeId),
47
+ }
48
+ const registryStore = writable(capture(() => registry))
49
+ const messagesStore = writable(capture(() => messages))
50
+ const generatedId = $props.id()
51
+ const generatedPrefix = `texaryn-${Array.from(generatedId, (char) => char.codePointAt(0)!.toString(36)).join('_')}`
52
+ const resolvedIdPrefix = capture(() => idPrefix ?? generatedPrefix)
53
+ const runtime = derived(formStore, ($form) => $form.runtime)
54
+ const context = {
55
+ form: currentForm,
56
+ registry: registryStore,
57
+ messages: messagesStore,
58
+ idPrefix: resolvedIdPrefix,
59
+ }
60
+ provideFormContext(context)
61
+
62
+ const document = currentForm.document
63
+ const rootNode = $derived($document.nodes[$document.rootId] as UINode | undefined)
64
+
65
+ let previousForm = capture(() => form)
66
+ $effect(() => {
67
+ registryStore.set(registry)
68
+ messagesStore.set(messages)
69
+ const nextForm = form
70
+ if (nextForm === previousForm) return
71
+
72
+ const replacedForm = previousForm
73
+ previousForm = nextForm
74
+ formStore.set(nextForm)
75
+ if (destroyOnUnmount && replacedForm.runtime !== nextForm.runtime) {
76
+ replacedForm.runtime.destroy()
77
+ }
78
+ })
79
+
80
+ onDestroy(() => {
81
+ if (destroyOnUnmount) get(formStore).runtime.destroy()
82
+ })
83
+
84
+ function handleSubmit(event: SubmitEvent): void {
85
+ event.preventDefault()
86
+ currentForm.dispatch({ type: 'Submit' })
87
+ }
88
+ </script>
89
+
90
+ <form onsubmit={handleSubmit}>
91
+ {#key $runtime}
92
+ <ErrorSummary />
93
+ {/key}
94
+ {#if rootNode}
95
+ <NodeRenderer node={rootNode} />
96
+ {/if}
97
+ {@render children?.()}
98
+ </form>
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { FormMessages, RendererRegistry } from '@texaryn/core';
3
+ import type { SvelteFormBinding } from '../form.js';
4
+ import type { WidgetComponent } from '../widget.js';
5
+ interface Props {
6
+ form: SvelteFormBinding;
7
+ registry?: RendererRegistry<WidgetComponent>;
8
+ messages?: FormMessages;
9
+ idPrefix?: string;
10
+ destroyOnUnmount?: boolean;
11
+ children?: Snippet;
12
+ }
13
+ declare const FormRoot: import("svelte").Component<Props, {}, "">;
14
+ type FormRoot = ReturnType<typeof FormRoot>;
15
+ export default FormRoot;
16
+ //# sourceMappingURL=FormRoot.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormRoot.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/FormRoot.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAU,MAAM,eAAe,CAAA;AAE3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAOjD,UAAU,KAAK;IACb,IAAI,EAAE,iBAAiB,CAAA;IACvB,QAAQ,CAAC,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAA;IAC5C,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AA8FH,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import type { UINode } from '@texaryn/core'
3
+ import { useFormContext } from '../context.js'
4
+ import type { WidgetComponent } from '../widget.js'
5
+
6
+ interface Props {
7
+ node: UINode
8
+ }
9
+
10
+ let { node }: Props = $props()
11
+ const context = useFormContext()
12
+ const registry = context.registry
13
+ const widget = $derived($registry.resolve(node) as WidgetComponent | undefined)
14
+ </script>
15
+
16
+ {#if node.visible && widget}
17
+ {@const Widget = widget}
18
+ <Widget {node} />
19
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { UINode } from '@texaryn/core';
2
+ interface Props {
3
+ node: UINode;
4
+ }
5
+ declare const NodeRenderer: import("svelte").Component<Props, {}, "">;
6
+ type NodeRenderer = ReturnType<typeof NodeRenderer>;
7
+ export default NodeRenderer;
8
+ //# sourceMappingURL=NodeRenderer.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeRenderer.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/NodeRenderer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAKzC,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAoBH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ import { objectChildKey } from '@texaryn/core'
3
+ import type { ContainerNode, UINode } from '@texaryn/core'
4
+ import { englishMessages } from '@texaryn/core'
5
+ import { useFormContext } from '../context.js'
6
+ import NodeRenderer from './NodeRenderer.svelte'
7
+
8
+ interface Props {
9
+ node: UINode
10
+ }
11
+
12
+ let { node }: Props = $props()
13
+ const context = useFormContext()
14
+ const document = context.form.document
15
+ const messages = context.messages
16
+ const current = $derived(($document.nodes[node.id] ?? node) as ContainerNode)
17
+ const nested = $derived(node.parentId !== null)
18
+ const title = $derived(current.annotations.title)
19
+ const children = $derived(
20
+ current.children
21
+ .map((id) => $document.nodes[id])
22
+ .filter((child): child is UINode => child != null),
23
+ )
24
+ const actions = $derived(firstTargets(current.boundaryTargets ?? []))
25
+
26
+ function firstTargets(targets: NonNullable<ContainerNode['boundaryTargets']>) {
27
+ const byReason = new Map<string, (typeof targets)[number]>()
28
+ for (const target of targets) {
29
+ if (!byReason.has(target.reason)) byReason.set(target.reason, target)
30
+ }
31
+ return [...byReason.values()]
32
+ }
33
+
34
+ function expand(target: (typeof actions)[number]): void {
35
+ context.form.dispatch({
36
+ type: 'ExpandBoundary',
37
+ containerId: current.id,
38
+ targetToken: target.token,
39
+ })
40
+ }
41
+
42
+ function expandMessage(target: (typeof actions)[number]) {
43
+ const makeMessage = $messages.expandBoundary ?? englishMessages.expandBoundary!
44
+ return makeMessage({
45
+ boundary: target.reason,
46
+ containerTitle: title,
47
+ position: 1,
48
+ count: 1,
49
+ })
50
+ }
51
+ </script>
52
+
53
+ {#snippet renderedChildren()}
54
+ {#each children as child (objectChildKey(child))}
55
+ <NodeRenderer node={child} />
56
+ {/each}
57
+ {#each actions as target (target.reason)}
58
+ {@const message = expandMessage(target)}
59
+ <button type="button" aria-label={message.accessibleName} onclick={() => expand(target)}>
60
+ {message.label}
61
+ </button>
62
+ {/each}
63
+ {/snippet}
64
+
65
+ {#if nested}
66
+ <fieldset role={title === undefined ? 'none' : undefined}>
67
+ {#if title !== undefined}<legend>{title}</legend>{/if}
68
+ <div>{@render renderedChildren()}</div>
69
+ </fieldset>
70
+ {:else}
71
+ <div>{@render renderedChildren()}</div>
72
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { UINode } from '@texaryn/core';
2
+ interface Props {
3
+ node: UINode;
4
+ }
5
+ declare const ObjectLayout: import("svelte").Component<Props, {}, "">;
6
+ type ObjectLayout = ReturnType<typeof ObjectLayout>;
7
+ export default ObjectLayout;
8
+ //# sourceMappingURL=ObjectLayout.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObjectLayout.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ObjectLayout.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAiB,MAAM,EAAE,MAAM,eAAe,CAAA;AAMxD,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAyEH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { FormMessages, RendererRegistry } from '@texaryn/core';
2
+ import type { Readable } from 'svelte/store';
3
+ import type { SvelteFormBinding } from './form.js';
4
+ import type { WidgetComponent } from './widget.js';
5
+ export interface SvelteFormContext {
6
+ form: SvelteFormBinding;
7
+ registry: Readable<RendererRegistry<WidgetComponent>>;
8
+ messages: Readable<FormMessages>;
9
+ idPrefix: string;
10
+ }
11
+ export declare function provideFormContext(context: SvelteFormContext): void;
12
+ export declare function useFormContext(): SvelteFormContext;
13
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/lib/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAIlD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,iBAAiB,CAAA;IACvB,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAA;IACrD,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;IAChC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAEnE;AAED,wBAAgB,cAAc,IAAI,iBAAiB,CAMlD"}
@@ -0,0 +1,12 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const FORM_CONTEXT = Symbol('texaryn.svelte.form');
3
+ export function provideFormContext(context) {
4
+ setContext(FORM_CONTEXT, context);
5
+ }
6
+ export function useFormContext() {
7
+ const context = getContext(FORM_CONTEXT);
8
+ if (!context) {
9
+ throw new Error('Svelte form widgets must be rendered below FormRoot');
10
+ }
11
+ return context;
12
+ }
@@ -0,0 +1,20 @@
1
+ import type { FieldNode, ValidationError } from '@texaryn/core';
2
+ export interface FieldAria {
3
+ id: string;
4
+ name: string;
5
+ disabled: boolean;
6
+ readonly?: boolean;
7
+ 'aria-readonly'?: true;
8
+ 'aria-required': boolean;
9
+ 'aria-invalid'?: boolean;
10
+ 'aria-describedby'?: string;
11
+ placeholder?: string;
12
+ }
13
+ export declare function makeId(idPrefix: string, nodeId: string, suffix: string): string;
14
+ export declare function fieldAria(node: FieldNode, state: {
15
+ disabled: boolean;
16
+ showErrors: boolean;
17
+ errors: readonly ValidationError[];
18
+ }, idPrefix: string, nativeReadOnly?: boolean): FieldAria;
19
+ export declare function fieldLabel(node: FieldNode): string;
20
+ //# sourceMappingURL=field-props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-props.d.ts","sourceRoot":"","sources":["../src/lib/field-props.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,IAAI,CAAA;IACtB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;CAAE,EACrF,QAAQ,EAAE,MAAM,EAChB,cAAc,UAAO,GACpB,SAAS,CAyBX;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAElD"}