@happyvertical/smrt-fields 0.40.59 → 0.40.61

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 (184) hide show
  1. package/AGENTS.md +58 -12
  2. package/README.md +90 -2
  3. package/dist/__smrt-register__.d.ts +2 -0
  4. package/dist/__smrt-register__.d.ts.map +1 -0
  5. package/dist/cache.d.ts +18 -0
  6. package/dist/cache.d.ts.map +1 -0
  7. package/dist/collections/FieldPolicyCollection.d.ts +95 -0
  8. package/dist/collections/FieldPolicyCollection.d.ts.map +1 -0
  9. package/dist/field-definitions.d.ts +77 -0
  10. package/dist/field-definitions.d.ts.map +1 -0
  11. package/dist/field-policy-resolver.d.ts +46 -0
  12. package/dist/field-policy-resolver.d.ts.map +1 -0
  13. package/dist/index.d.ts +9 -532
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +752 -55
  16. package/dist/index.js.map +1 -1
  17. package/dist/manifest.json +45 -3
  18. package/dist/models/FieldPolicy.d.ts +163 -0
  19. package/dist/models/FieldPolicy.d.ts.map +1 -0
  20. package/dist/permissions.d.ts +9 -0
  21. package/dist/permissions.d.ts.map +1 -0
  22. package/dist/playground.d.ts +2 -0
  23. package/dist/playground.d.ts.map +1 -0
  24. package/dist/playground.js +39 -0
  25. package/dist/playground.js.map +1 -0
  26. package/dist/settings-catalog.d.ts +73 -0
  27. package/dist/settings-catalog.d.ts.map +1 -0
  28. package/dist/smrt-knowledge.json +50 -7
  29. package/dist/svelte/__tests__/FieldPolicyControlPanel.test.js +223 -0
  30. package/dist/svelte/__tests__/FieldPolicyGear.test.js +503 -0
  31. package/dist/svelte/__tests__/FormHelp.test.js +138 -0
  32. package/dist/svelte/__tests__/ModeUX.test.js +109 -0
  33. package/dist/svelte/__tests__/ObjectForm.test.js +556 -0
  34. package/dist/svelte/__tests__/ObjectFormGeneratedApi.integration.test.js +436 -0
  35. package/dist/svelte/__tests__/PolicyField.test.js +373 -0
  36. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte +30 -0
  37. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte.d.ts +9 -0
  38. package/dist/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte.d.ts.map +1 -0
  39. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte +33 -0
  40. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte.d.ts +10 -0
  41. package/dist/svelte/__tests__/fixtures/DomPrefillFixture.svelte.d.ts.map +1 -0
  42. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte +19 -0
  43. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte.d.ts +10 -0
  44. package/dist/svelte/__tests__/fixtures/FormHelpFixture.svelte.d.ts.map +1 -0
  45. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte +18 -0
  46. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte.d.ts +11 -0
  47. package/dist/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte.d.ts.map +1 -0
  48. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte +11 -0
  49. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte.d.ts +19 -0
  50. package/dist/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte.d.ts.map +1 -0
  51. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte +18 -0
  52. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte.d.ts +8 -0
  53. package/dist/svelte/__tests__/fixtures/ModeSwitchFixture.svelte.d.ts.map +1 -0
  54. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte +24 -0
  55. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte.d.ts +13 -0
  56. package/dist/svelte/__tests__/fixtures/NoIdFixture.svelte.d.ts.map +1 -0
  57. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte +20 -0
  58. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts +11 -0
  59. package/dist/svelte/__tests__/fixtures/ObjectFormActionsFixture.svelte.d.ts.map +1 -0
  60. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte +17 -0
  61. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte.d.ts +10 -0
  62. package/dist/svelte/__tests__/fixtures/ObjectFormFixture.svelte.d.ts.map +1 -0
  63. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte +25 -0
  64. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte.d.ts +10 -0
  65. package/dist/svelte/__tests__/fixtures/ObjectFormRegistryFixture.svelte.d.ts.map +1 -0
  66. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte +34 -0
  67. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte.d.ts +10 -0
  68. package/dist/svelte/__tests__/fixtures/ObjectFormSnippetFixture.svelte.d.ts.map +1 -0
  69. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte +29 -0
  70. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte.d.ts +11 -0
  71. package/dist/svelte/__tests__/fixtures/ObjectFormSourceFixture.svelte.d.ts.map +1 -0
  72. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte +33 -0
  73. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte.d.ts +9 -0
  74. package/dist/svelte/__tests__/fixtures/ObjectFormSourceSnippetFixture.svelte.d.ts.map +1 -0
  75. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte +40 -0
  76. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte.d.ts +8 -0
  77. package/dist/svelte/__tests__/fixtures/PolicyDataTableFixture.svelte.d.ts.map +1 -0
  78. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte +26 -0
  79. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte.d.ts +13 -0
  80. package/dist/svelte/__tests__/fixtures/PrefillFixture.svelte.d.ts.map +1 -0
  81. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte +39 -0
  82. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte.d.ts +17 -0
  83. package/dist/svelte/__tests__/fixtures/ProviderFieldFixture.svelte.d.ts.map +1 -0
  84. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte +15 -0
  85. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte.d.ts +5 -0
  86. package/dist/svelte/__tests__/fixtures/RegistryInput.svelte.d.ts.map +1 -0
  87. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte +29 -0
  88. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte.d.ts +14 -0
  89. package/dist/svelte/__tests__/fixtures/RevealPrefillFixture.svelte.d.ts.map +1 -0
  90. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte +24 -0
  91. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte.d.ts +14 -0
  92. package/dist/svelte/__tests__/fixtures/SettingsCatalogStub.svelte.d.ts.map +1 -0
  93. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte +28 -0
  94. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte.d.ts +13 -0
  95. package/dist/svelte/__tests__/fixtures/SnippetFixture.svelte.d.ts.map +1 -0
  96. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte +14 -0
  97. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte.d.ts +19 -0
  98. package/dist/svelte/__tests__/fixtures/ToggleModeButton.svelte.d.ts.map +1 -0
  99. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte +25 -0
  100. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte.d.ts +14 -0
  101. package/dist/svelte/__tests__/fixtures/TooltipFixture.svelte.d.ts.map +1 -0
  102. package/dist/svelte/__tests__/settings-catalog.test.js +161 -0
  103. package/dist/svelte/components/AdvancedFields.svelte +49 -0
  104. package/dist/svelte/components/AdvancedFields.svelte.d.ts +17 -0
  105. package/dist/svelte/components/AdvancedFields.svelte.d.ts.map +1 -0
  106. package/dist/svelte/components/FieldInput.svelte +159 -0
  107. package/dist/svelte/components/FieldInput.svelte.d.ts +5 -0
  108. package/dist/svelte/components/FieldInput.svelte.d.ts.map +1 -0
  109. package/dist/svelte/components/FieldPolicyControlPanel.svelte +261 -0
  110. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts +26 -0
  111. package/dist/svelte/components/FieldPolicyControlPanel.svelte.d.ts.map +1 -0
  112. package/dist/svelte/components/FieldPolicyEditor.svelte +417 -0
  113. package/dist/svelte/components/FieldPolicyEditor.svelte.d.ts +18 -0
  114. package/dist/svelte/components/FieldPolicyEditor.svelte.d.ts.map +1 -0
  115. package/dist/svelte/components/FieldPolicyGearButton.svelte +17 -0
  116. package/dist/svelte/components/FieldPolicyGearButton.svelte.d.ts +8 -0
  117. package/dist/svelte/components/FieldPolicyGearButton.svelte.d.ts.map +1 -0
  118. package/dist/svelte/components/FieldPolicyGearProvider.svelte +135 -0
  119. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts +17 -0
  120. package/dist/svelte/components/FieldPolicyGearProvider.svelte.d.ts.map +1 -0
  121. package/dist/svelte/components/FieldPolicyProvider.svelte +89 -0
  122. package/dist/svelte/components/FieldPolicyProvider.svelte.d.ts +35 -0
  123. package/dist/svelte/components/FieldPolicyProvider.svelte.d.ts.map +1 -0
  124. package/dist/svelte/components/FormHelp.svelte +157 -0
  125. package/dist/svelte/components/FormHelp.svelte.d.ts +15 -0
  126. package/dist/svelte/components/FormHelp.svelte.d.ts.map +1 -0
  127. package/dist/svelte/components/ModeSwitch.svelte +47 -0
  128. package/dist/svelte/components/ModeSwitch.svelte.d.ts +10 -0
  129. package/dist/svelte/components/ModeSwitch.svelte.d.ts.map +1 -0
  130. package/dist/svelte/components/ObjectForm.svelte +351 -0
  131. package/dist/svelte/components/ObjectForm.svelte.d.ts +40 -0
  132. package/dist/svelte/components/ObjectForm.svelte.d.ts.map +1 -0
  133. package/dist/svelte/components/ObjectFormSourceProvider.svelte +18 -0
  134. package/dist/svelte/components/ObjectFormSourceProvider.svelte.d.ts +11 -0
  135. package/dist/svelte/components/ObjectFormSourceProvider.svelte.d.ts.map +1 -0
  136. package/dist/svelte/components/PolicyField.svelte +338 -0
  137. package/dist/svelte/components/PolicyField.svelte.d.ts +80 -0
  138. package/dist/svelte/components/PolicyField.svelte.d.ts.map +1 -0
  139. package/dist/svelte/context.svelte.d.ts +54 -0
  140. package/dist/svelte/context.svelte.d.ts.map +1 -0
  141. package/dist/svelte/context.svelte.js +55 -0
  142. package/dist/svelte/data-table.d.ts +17 -0
  143. package/dist/svelte/data-table.d.ts.map +1 -0
  144. package/dist/svelte/data-table.js +19 -0
  145. package/dist/svelte/field-policy-editor.d.ts +81 -0
  146. package/dist/svelte/field-policy-editor.d.ts.map +1 -0
  147. package/dist/svelte/field-policy-editor.js +120 -0
  148. package/dist/svelte/gear-context.svelte.d.ts +14 -0
  149. package/dist/svelte/gear-context.svelte.d.ts.map +1 -0
  150. package/dist/svelte/gear-context.svelte.js +15 -0
  151. package/dist/svelte/index.d.ts +58 -0
  152. package/dist/svelte/index.d.ts.map +1 -0
  153. package/dist/svelte/index.js +38 -0
  154. package/dist/svelte/input-registry.d.ts +21 -0
  155. package/dist/svelte/input-registry.d.ts.map +1 -0
  156. package/dist/svelte/input-registry.js +26 -0
  157. package/dist/svelte/object-form-source-context.svelte.d.ts +4 -0
  158. package/dist/svelte/object-form-source-context.svelte.d.ts.map +1 -0
  159. package/dist/svelte/object-form-source-context.svelte.js +8 -0
  160. package/dist/svelte/object-form-source.svelte.d.ts +18 -0
  161. package/dist/svelte/object-form-source.svelte.d.ts.map +1 -0
  162. package/dist/svelte/object-form-source.svelte.js +99 -0
  163. package/dist/svelte/object-form.d.ts +6 -0
  164. package/dist/svelte/object-form.d.ts.map +1 -0
  165. package/dist/svelte/object-form.js +38 -0
  166. package/dist/svelte/playground/FieldPolicyFormPreview.svelte +212 -0
  167. package/dist/svelte/playground/FieldPolicyFormPreview.svelte.d.ts +4 -0
  168. package/dist/svelte/playground/FieldPolicyFormPreview.svelte.d.ts.map +1 -0
  169. package/dist/svelte/playground/ObjectFormPreview.svelte +129 -0
  170. package/dist/svelte/playground/ObjectFormPreview.svelte.d.ts +4 -0
  171. package/dist/svelte/playground/ObjectFormPreview.svelte.d.ts.map +1 -0
  172. package/dist/svelte/playground.d.ts +20 -0
  173. package/dist/svelte/playground.d.ts.map +1 -0
  174. package/dist/svelte/playground.js +38 -0
  175. package/dist/svelte/settings-catalog.d.ts +54 -0
  176. package/dist/svelte/settings-catalog.d.ts.map +1 -0
  177. package/dist/svelte/settings-catalog.js +116 -0
  178. package/dist/svelte/types.d.ts +101 -0
  179. package/dist/svelte/types.d.ts.map +1 -0
  180. package/dist/svelte/types.js +4 -0
  181. package/dist/types.d.ts +276 -203
  182. package/dist/types.d.ts.map +1 -0
  183. package/dist/types.js.map +1 -1
  184. package/package.json +33 -8
@@ -0,0 +1,373 @@
1
+ // @vitest-environment jsdom
2
+ /**
3
+ * Component tests for FieldPolicyProvider + PolicyField (#2048).
4
+ *
5
+ * Covers the acceptance criteria:
6
+ * - PolicyField adoption with no layout change; unwrapped fields keep working
7
+ * - Basic mode hides advanced-tier fields; disclosure reveals them
8
+ * - Required-with-default fields prefill; loaded-record edits never overwritten
9
+ * - Help hint renders from resolved help (manifest description → org override)
10
+ * - Graceful degradation outside a Provider
11
+ * - Snippet escape hatch
12
+ * - a11y (axe-clean)
13
+ */
14
+ import { expectNoA11yViolations, render, screen, userEvent, } from '@happyvertical/smrt-vitest/svelte';
15
+ import { tick } from 'svelte';
16
+ import { describe, expect, it } from 'vitest';
17
+ import FieldPolicyProvider from '../components/FieldPolicyProvider.svelte';
18
+ import PolicyField from '../components/PolicyField.svelte';
19
+ import DomPrefillFixture from './fixtures/DomPrefillFixture.svelte';
20
+ import GracefulDegradeFixture from './fixtures/GracefulDegradeFixture.svelte';
21
+ import NoIdFixture from './fixtures/NoIdFixture.svelte';
22
+ import PrefillFixture from './fixtures/PrefillFixture.svelte';
23
+ import ProviderFieldFixture from './fixtures/ProviderFieldFixture.svelte';
24
+ import RevealPrefillFixture from './fixtures/RevealPrefillFixture.svelte';
25
+ import SnippetFixture from './fixtures/SnippetFixture.svelte';
26
+ import TooltipFixture from './fixtures/TooltipFixture.svelte';
27
+ function makePolicy(overrides = {}) {
28
+ return {
29
+ objectRef: '@test:Widget',
30
+ fields: {
31
+ name: {
32
+ fieldName: 'name',
33
+ hasDefault: false,
34
+ defaultValue: undefined,
35
+ visibility: 'basic',
36
+ help: 'The widget name',
37
+ label: 'Name',
38
+ order: 1,
39
+ group: null,
40
+ locked: false,
41
+ required: true,
42
+ },
43
+ sku: {
44
+ fieldName: 'sku',
45
+ hasDefault: true,
46
+ defaultValue: 'WIDG-001',
47
+ visibility: 'basic',
48
+ help: null,
49
+ label: 'SKU',
50
+ order: 2,
51
+ group: null,
52
+ locked: false,
53
+ required: false,
54
+ },
55
+ wholesalePrice: {
56
+ fieldName: 'wholesalePrice',
57
+ hasDefault: true,
58
+ defaultValue: 0,
59
+ visibility: 'advanced',
60
+ help: 'Price for wholesale customers',
61
+ label: 'Wholesale Price',
62
+ order: 3,
63
+ group: 'pricing',
64
+ locked: false,
65
+ required: false,
66
+ },
67
+ internalNotes: {
68
+ fieldName: 'internalNotes',
69
+ hasDefault: false,
70
+ defaultValue: undefined,
71
+ visibility: 'hidden',
72
+ help: 'Internal only',
73
+ label: 'Internal Notes',
74
+ order: 4,
75
+ group: null,
76
+ locked: false,
77
+ required: false,
78
+ },
79
+ },
80
+ ...overrides,
81
+ };
82
+ }
83
+ describe('FieldPolicyProvider + PolicyField', () => {
84
+ it('renders basic fields in basic mode', () => {
85
+ const policy = makePolicy();
86
+ render(ProviderFieldFixture, {
87
+ props: { policy, mode: 'basic' },
88
+ });
89
+ expect(screen.getByRole('textbox', { name: /Name/ })).toBeInTheDocument();
90
+ expect(screen.getByRole('textbox', { name: /SKU/ })).toBeInTheDocument();
91
+ });
92
+ it('hides advanced fields in basic mode', () => {
93
+ const policy = makePolicy();
94
+ render(ProviderFieldFixture, {
95
+ props: { policy, mode: 'basic' },
96
+ });
97
+ // wholesalePrice is type=number → role is spinbutton, not textbox
98
+ expect(screen.queryByRole('spinbutton', { name: /Wholesale Price/ })).not.toBeInTheDocument();
99
+ });
100
+ it('reveals advanced fields in advanced mode', async () => {
101
+ const policy = makePolicy();
102
+ render(ProviderFieldFixture, {
103
+ props: { policy, mode: 'advanced' },
104
+ });
105
+ // Wait for the provider's mode-sync $effect to flush (the untrack() seed
106
+ // reflects the requested mode on first paint, but $effect reactivity in
107
+ // jsdom needs a tick for the DOM to settle).
108
+ await tick();
109
+ // wholesalePrice is type=number → role is spinbutton, not textbox
110
+ expect(screen.getByRole('spinbutton', { name: /Wholesale Price/ })).toBeInTheDocument();
111
+ });
112
+ it('never renders hidden-tier fields', () => {
113
+ const policy = makePolicy();
114
+ render(ProviderFieldFixture, {
115
+ props: { policy, mode: 'advanced' },
116
+ });
117
+ expect(screen.queryByText('Internal Notes')).not.toBeInTheDocument();
118
+ });
119
+ it('renders help hint from resolved help text', () => {
120
+ const policy = makePolicy();
121
+ render(ProviderFieldFixture, {
122
+ props: { policy, mode: 'basic' },
123
+ });
124
+ expect(screen.getByText('The widget name')).toBeInTheDocument();
125
+ });
126
+ it('renders required marker for required fields', () => {
127
+ const policy = makePolicy();
128
+ render(ProviderFieldFixture, {
129
+ props: { policy, mode: 'basic' },
130
+ });
131
+ const nameField = screen.getByText('Name').closest('.policy-field');
132
+ expect(nameField?.querySelector('.policy-field__required')).not.toBeNull();
133
+ });
134
+ it('does not render required marker for optional fields', () => {
135
+ const policy = makePolicy();
136
+ render(ProviderFieldFixture, {
137
+ props: { policy, mode: 'basic' },
138
+ });
139
+ const skuField = screen.getByText('SKU').closest('.policy-field');
140
+ expect(skuField?.querySelector('.policy-field__required')).toBeNull();
141
+ });
142
+ it('exposes default value via snippet props for prefill signal', () => {
143
+ const policy = makePolicy();
144
+ render(PrefillFixture, {
145
+ props: { policy, mode: 'basic' },
146
+ });
147
+ // The fixture renders the default value text from snippet props
148
+ expect(screen.getByText('Default: WIDG-001')).toBeInTheDocument();
149
+ });
150
+ it('degrades gracefully outside a Provider (renders children verbatim)', () => {
151
+ render(GracefulDegradeFixture);
152
+ // Should render the input even without a provider
153
+ expect(screen.getByRole('textbox')).toBeInTheDocument();
154
+ });
155
+ it('snippet escape hatch receives resolved policy data', () => {
156
+ const policy = makePolicy();
157
+ render(SnippetFixture, {
158
+ props: { policy, mode: 'basic' },
159
+ });
160
+ expect(screen.getByTestId('field-label')).toHaveTextContent('Name');
161
+ expect(screen.getByTestId('field-help')).toHaveTextContent('The widget name');
162
+ expect(screen.getByTestId('field-required')).toHaveTextContent('true');
163
+ });
164
+ it('helpDensity tooltip attaches help to the label title and hides the hint', () => {
165
+ const policy = makePolicy();
166
+ render(TooltipFixture, {
167
+ props: { policy, helpDensity: 'tooltip' },
168
+ });
169
+ // Help moves to the label's title attribute
170
+ const label = screen.getByText('Name').closest('label');
171
+ expect(label).not.toBeNull();
172
+ expect(label?.getAttribute('title')).toBe('The widget name');
173
+ // The help text is no longer rendered as visible text content
174
+ expect(screen.queryByText('The widget name')).not.toBeInTheDocument();
175
+ // No visible hint element (query the component's stable class rather than
176
+ // a role — `<p>` has no ARIA role, so a role query is unreliable).
177
+ expect(document.querySelectorAll('.policy-field__hint').length).toBe(0);
178
+ });
179
+ it('links the help hint to the input via aria-describedby', async () => {
180
+ const policy = makePolicy();
181
+ render(ProviderFieldFixture, {
182
+ props: { policy, mode: 'basic' },
183
+ });
184
+ await tick();
185
+ // `name` has resolved help rendered as the hint paragraph #name-help —
186
+ // the input must reference it for screen readers.
187
+ const input = screen.getByRole('textbox', { name: /Name/ });
188
+ expect(input.getAttribute('aria-describedby')).toBe('name-help');
189
+ expect(document.getElementById('name-help')).not.toBeNull();
190
+ // `sku` has no resolved help → no hint id, no dangling aria reference.
191
+ const skuInput = screen.getByRole('textbox', { name: /SKU/ });
192
+ expect(skuInput.hasAttribute('aria-describedby')).toBe(false);
193
+ });
194
+ it('associates the label with the wrapped control via for/id', async () => {
195
+ const policy = makePolicy();
196
+ render(ProviderFieldFixture, {
197
+ props: { policy, mode: 'basic' },
198
+ });
199
+ await tick();
200
+ // The fixture inputs carry id={name} — the label's `for` must match it so
201
+ // the accessible name comes from the rendered label.
202
+ const label = screen.getByText('Name').closest('label');
203
+ expect(label?.getAttribute('for')).toBe('name');
204
+ expect(document.getElementById('name')).not.toBeNull();
205
+ const skuLabel = screen.getByText('SKU').closest('label');
206
+ expect(skuLabel?.getAttribute('for')).toBe('sku');
207
+ });
208
+ it('assigns an id to a wrapped control that has none (for never dangles)', async () => {
209
+ const policy = makePolicy();
210
+ render(NoIdFixture, { props: { policy, mode: 'basic' } });
211
+ await tick();
212
+ const label = screen.getByText('Name').closest('label');
213
+ const forTarget = label?.getAttribute('for');
214
+ expect(forTarget).toBe('name');
215
+ // The wrapper must have given the id-less control an id the label hits.
216
+ expect(document.getElementById(forTarget)).not.toBeNull();
217
+ });
218
+ it('helpDensity tooltip falls back to a visible hint when there is no label', () => {
219
+ // Policy with no resolved label → label === null → help must still render
220
+ const policy = makePolicy({
221
+ fields: {
222
+ name: {
223
+ fieldName: 'name',
224
+ hasDefault: false,
225
+ defaultValue: undefined,
226
+ visibility: 'basic',
227
+ help: 'Orphan help text',
228
+ label: null,
229
+ order: 1,
230
+ group: null,
231
+ locked: false,
232
+ required: false,
233
+ },
234
+ },
235
+ });
236
+ render(TooltipFixture, {
237
+ props: { policy, helpDensity: 'tooltip' },
238
+ });
239
+ expect(screen.getByText('Orphan help text')).toBeInTheDocument();
240
+ });
241
+ it('mode toggle reveals advanced fields', async () => {
242
+ const policy = makePolicy();
243
+ render(ProviderFieldFixture, {
244
+ props: { policy, mode: 'basic' },
245
+ });
246
+ // Advanced field not visible initially
247
+ expect(screen.queryByRole('spinbutton', { name: /Wholesale/ })).not.toBeInTheDocument();
248
+ // Toggle mode (the fixture's button calls modeStore.toggle() via context)
249
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
250
+ expect(screen.getByRole('spinbutton', { name: /Wholesale Price/ })).toBeInTheDocument();
251
+ });
252
+ it('is axe-clean', async () => {
253
+ const policy = makePolicy();
254
+ const { container } = render(ProviderFieldFixture, {
255
+ props: { policy, mode: 'basic' },
256
+ });
257
+ await expectNoA11yViolations(container);
258
+ });
259
+ });
260
+ describe('PolicyField default prefill (new records only)', () => {
261
+ it('prefills an empty input with the resolved default for a new record', async () => {
262
+ const policy = makePolicy();
263
+ render(DomPrefillFixture, {
264
+ props: { policy, isNewRecord: true, skuValue: '' },
265
+ });
266
+ await tick();
267
+ // The sku field has a resolved default of 'WIDG-001'; the empty input
268
+ // should be prefilled with it.
269
+ const input = screen.getByRole('textbox', {
270
+ name: /SKU/,
271
+ });
272
+ expect(input.value).toBe('WIDG-001');
273
+ // The bound state should pick up the prefilled value too
274
+ expect(screen.getByTestId('sku-state')).toHaveTextContent('WIDG-001');
275
+ });
276
+ it('does NOT clobber a loaded record with an existing value', async () => {
277
+ const policy = makePolicy();
278
+ render(DomPrefillFixture, {
279
+ props: { policy, isNewRecord: true, skuValue: 'EXISTING-999' },
280
+ });
281
+ await tick();
282
+ // The input already has a value (loaded record); the default must NOT
283
+ // overwrite it.
284
+ const input = screen.getByRole('textbox', {
285
+ name: /SKU/,
286
+ });
287
+ expect(input.value).toBe('EXISTING-999');
288
+ expect(screen.getByTestId('sku-state')).toHaveTextContent('EXISTING-999');
289
+ });
290
+ it('does NOT prefill when isNewRecord is false', async () => {
291
+ const policy = makePolicy();
292
+ render(DomPrefillFixture, {
293
+ props: { policy, isNewRecord: false, skuValue: '' },
294
+ });
295
+ await tick();
296
+ // isNewRecord=false → no prefill even though the field is empty and has a
297
+ // resolved default.
298
+ const input = screen.getByRole('textbox', {
299
+ name: /SKU/,
300
+ });
301
+ expect(input.value).toBe('');
302
+ });
303
+ });
304
+ describe('PolicyField prefill on reveal (advanced-tier fields)', () => {
305
+ it('prefills an advanced field when the mode switch reveals it', async () => {
306
+ const policy = makePolicy();
307
+ render(RevealPrefillFixture, {
308
+ props: { policy, isNewRecord: true },
309
+ });
310
+ await tick();
311
+ // Hidden in basic mode: no input to prefill yet.
312
+ expect(screen.queryByRole('spinbutton', { name: /Wholesale Price/ })).not.toBeInTheDocument();
313
+ // Reveal the advanced tier.
314
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
315
+ await tick();
316
+ // wholesalePrice resolves default 0 — a legitimate integer default that
317
+ // must survive the undefined/null guards.
318
+ const input = screen.getByRole('spinbutton', {
319
+ name: /Wholesale Price/,
320
+ });
321
+ expect(input.value).toBe('0');
322
+ // The bound state picked up the prefilled value via the dispatched event.
323
+ expect(screen.getByTestId('wholesale-state')).toHaveTextContent('0');
324
+ });
325
+ it('does NOT prefill a revealed advanced field when isNewRecord is false', async () => {
326
+ const policy = makePolicy();
327
+ render(RevealPrefillFixture, {
328
+ props: { policy, isNewRecord: false },
329
+ });
330
+ await tick();
331
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
332
+ await tick();
333
+ const input = screen.getByRole('spinbutton', {
334
+ name: /Wholesale Price/,
335
+ });
336
+ expect(input.value).toBe('');
337
+ });
338
+ it('prefills only once — a deliberately cleared input is never re-filled', async () => {
339
+ const policy = makePolicy();
340
+ render(RevealPrefillFixture, {
341
+ props: { policy, isNewRecord: true },
342
+ });
343
+ await tick();
344
+ // Reveal → prefill runs once.
345
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
346
+ await tick();
347
+ const input = screen.getByRole('spinbutton', {
348
+ name: /Wholesale Price/,
349
+ });
350
+ expect(input.value).toBe('0');
351
+ // The user deliberately clears the field.
352
+ await userEvent.clear(input);
353
+ await tick();
354
+ // Hide and reveal again: the one-shot guard must prevent a re-prefill.
355
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
356
+ await userEvent.click(screen.getByRole('button', { name: 'Toggle Mode' }));
357
+ await tick();
358
+ const revealed = screen.getByRole('spinbutton', {
359
+ name: /Wholesale Price/,
360
+ });
361
+ expect(revealed.value).toBe('');
362
+ });
363
+ });
364
+ describe('PolicyField standalone', () => {
365
+ it('renders without a provider (no crash)', () => {
366
+ render(PolicyField, {
367
+ props: { name: 'test' },
368
+ target: document.body,
369
+ });
370
+ // No label wrapping since no context, just children area
371
+ // Should not throw
372
+ });
373
+ });
@@ -0,0 +1,30 @@
1
+ <script lang="ts">
2
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
3
+ import AdvancedFields from '../../components/AdvancedFields.svelte';
4
+ import FieldPolicyProvider from '../../components/FieldPolicyProvider.svelte';
5
+ import PolicyField from '../../components/PolicyField.svelte';
6
+
7
+ let {
8
+ policy,
9
+ mode = 'advanced',
10
+ }: {
11
+ policy: ResolvedObjectFieldPolicy;
12
+ mode?: 'basic' | 'advanced';
13
+ } = $props();
14
+ </script>
15
+
16
+ <FieldPolicyProvider {policy} {mode}>
17
+ <PolicyField name="name">
18
+ <input id="name" name="name" type="text" />
19
+ </PolicyField>
20
+ <AdvancedFields>
21
+ <PolicyField name="secretKey">
22
+ <input id="secretKey" name="secretKey" type="text" />
23
+ </PolicyField>
24
+ {#if policy.fields.another}
25
+ <PolicyField name="another">
26
+ <input id="another" name="another" type="text" />
27
+ </PolicyField>
28
+ {/if}
29
+ </AdvancedFields>
30
+ </FieldPolicyProvider>
@@ -0,0 +1,9 @@
1
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
2
+ type $$ComponentProps = {
3
+ policy: ResolvedObjectFieldPolicy;
4
+ mode?: 'basic' | 'advanced';
5
+ };
6
+ declare const AdvancedFieldsFixture: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type AdvancedFieldsFixture = ReturnType<typeof AdvancedFieldsFixture>;
8
+ export default AdvancedFieldsFixture;
9
+ //# sourceMappingURL=AdvancedFieldsFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdvancedFieldsFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/AdvancedFieldsFixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAKlE,KAAK,gBAAgB,GAAI;IACxB,MAAM,EAAE,yBAAyB,CAAC;IAClC,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;CAC7B,CAAC;AA+BF,QAAA,MAAM,qBAAqB,sDAAwC,CAAC;AACpE,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACtE,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Test fixture: PolicyField with bind:value inputs to verify prefill.
4
+ * - New record with default → input prefilled from resolved default
5
+ * - Loaded record with existing value → input NOT clobbered by default
6
+ */
7
+ import { untrack } from 'svelte';
8
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
9
+ import FieldPolicyProvider from '../../components/FieldPolicyProvider.svelte';
10
+ import PolicyField from '../../components/PolicyField.svelte';
11
+
12
+ let {
13
+ policy,
14
+ isNewRecord = true,
15
+ skuValue = '',
16
+ }: {
17
+ policy: ResolvedObjectFieldPolicy;
18
+ isNewRecord?: boolean;
19
+ skuValue?: string;
20
+ } = $props();
21
+
22
+ // Seed the bound value once from the prop (untrack makes the one-shot capture
23
+ // explicit, mirroring ThemeProvider's SSR-seeding pattern — a loaded record's
24
+ // existing value must never be re-synced from the prop).
25
+ let sku = $state(untrack(() => skuValue));
26
+ </script>
27
+
28
+ <FieldPolicyProvider {policy} mode="basic">
29
+ <PolicyField name="sku" {isNewRecord}>
30
+ <input id="sku" name="sku" type="text" bind:value={sku} />
31
+ </PolicyField>
32
+ <div data-testid="sku-state">{sku}</div>
33
+ </FieldPolicyProvider>
@@ -0,0 +1,10 @@
1
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
2
+ type $$ComponentProps = {
3
+ policy: ResolvedObjectFieldPolicy;
4
+ isNewRecord?: boolean;
5
+ skuValue?: string;
6
+ };
7
+ declare const DomPrefillFixture: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type DomPrefillFixture = ReturnType<typeof DomPrefillFixture>;
9
+ export default DomPrefillFixture;
10
+ //# sourceMappingURL=DomPrefillFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DomPrefillFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/DomPrefillFixture.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAIlE,KAAK,gBAAgB,GAAI;IACxB,MAAM,EAAE,yBAAyB,CAAC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AA6BF,QAAA,MAAM,iBAAiB,sDAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
3
+ import FieldPolicyProvider from '../../components/FieldPolicyProvider.svelte';
4
+ import FormHelp from '../../components/FormHelp.svelte';
5
+
6
+ let {
7
+ policy,
8
+ objectDescription,
9
+ mode = 'basic',
10
+ }: {
11
+ policy: ResolvedObjectFieldPolicy;
12
+ objectDescription?: string;
13
+ mode?: 'basic' | 'advanced';
14
+ } = $props();
15
+ </script>
16
+
17
+ <FieldPolicyProvider {policy} {mode}>
18
+ <FormHelp {objectDescription} />
19
+ </FieldPolicyProvider>
@@ -0,0 +1,10 @@
1
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
2
+ type $$ComponentProps = {
3
+ policy: ResolvedObjectFieldPolicy;
4
+ objectDescription?: string;
5
+ mode?: 'basic' | 'advanced';
6
+ };
7
+ declare const FormHelpFixture: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type FormHelpFixture = ReturnType<typeof FormHelpFixture>;
9
+ export default FormHelpFixture;
10
+ //# sourceMappingURL=FormHelpFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormHelpFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/FormHelpFixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAIlE,KAAK,gBAAgB,GAAI;IACxB,MAAM,EAAE,yBAAyB,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;CAC7B,CAAC;AAmBF,QAAA,MAAM,eAAe,sDAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import FieldPolicyGearButton from '../../components/FieldPolicyGearButton.svelte';
3
+ import FieldPolicyGearProvider from '../../components/FieldPolicyGearProvider.svelte';
4
+ import type { FieldPolicyEditorAdapter } from '../../field-policy-editor.js';
5
+ import type { ObjectFormFieldDefinition } from '../../types.js';
6
+
7
+ interface Props {
8
+ objectRef: string;
9
+ fields: Record<string, ObjectFormFieldDefinition>;
10
+ adapter: FieldPolicyEditorAdapter;
11
+ }
12
+
13
+ let { objectRef, fields, adapter }: Props = $props();
14
+ </script>
15
+
16
+ <FieldPolicyGearProvider {objectRef} {fields} {adapter}>
17
+ <FieldPolicyGearButton />
18
+ </FieldPolicyGearProvider>
@@ -0,0 +1,11 @@
1
+ import type { FieldPolicyEditorAdapter } from '../../field-policy-editor.js';
2
+ import type { ObjectFormFieldDefinition } from '../../types.js';
3
+ interface Props {
4
+ objectRef: string;
5
+ fields: Record<string, ObjectFormFieldDefinition>;
6
+ adapter: FieldPolicyEditorAdapter;
7
+ }
8
+ declare const GeneratedApiGearFixture: import("svelte").Component<Props, {}, "">;
9
+ type GeneratedApiGearFixture = ReturnType<typeof GeneratedApiGearFixture>;
10
+ export default GeneratedApiGearFixture;
11
+ //# sourceMappingURL=GeneratedApiGearFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeneratedApiGearFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/GeneratedApiGearFixture.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAGhE,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;IAClD,OAAO,EAAE,wBAAwB,CAAC;CACnC;AAiBD,QAAA,MAAM,uBAAuB,2CAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Test fixture: PolicyField rendered WITHOUT a FieldPolicyProvider.
4
+ * Verifies graceful degradation — children render verbatim.
5
+ */
6
+ import PolicyField from '../../components/PolicyField.svelte';
7
+ </script>
8
+
9
+ <PolicyField name="standalone">
10
+ <input type="text" />
11
+ </PolicyField>
@@ -0,0 +1,19 @@
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: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const GracefulDegradeFixture: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type GracefulDegradeFixture = InstanceType<typeof GracefulDegradeFixture>;
18
+ export default GracefulDegradeFixture;
19
+ //# sourceMappingURL=GracefulDegradeFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GracefulDegradeFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/GracefulDegradeFixture.svelte.ts"],"names":[],"mappings":"AAoBA,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;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;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,sBAAsB;;kBAA+E,CAAC;AAC1F,KAAK,sBAAsB,GAAG,YAAY,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC5E,eAAe,sBAAsB,CAAC"}
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
3
+ import FieldPolicyProvider from '../../components/FieldPolicyProvider.svelte';
4
+ import ModeSwitch from '../../components/ModeSwitch.svelte';
5
+ import PolicyField from '../../components/PolicyField.svelte';
6
+
7
+ let { policy }: { policy: ResolvedObjectFieldPolicy } = $props();
8
+ </script>
9
+
10
+ <FieldPolicyProvider {policy} mode="basic">
11
+ <ModeSwitch />
12
+ <PolicyField name="name">
13
+ <input id="name" name="name" type="text" />
14
+ </PolicyField>
15
+ <PolicyField name="secretKey">
16
+ <input id="secretKey" name="secretKey" type="text" />
17
+ </PolicyField>
18
+ </FieldPolicyProvider>
@@ -0,0 +1,8 @@
1
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
2
+ type $$ComponentProps = {
3
+ policy: ResolvedObjectFieldPolicy;
4
+ };
5
+ declare const ModeSwitchFixture: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type ModeSwitchFixture = ReturnType<typeof ModeSwitchFixture>;
7
+ export default ModeSwitchFixture;
8
+ //# sourceMappingURL=ModeSwitchFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModeSwitchFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/ModeSwitchFixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAKlE,KAAK,gBAAgB,GAAI;IAAE,MAAM,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAsBhE,QAAA,MAAM,iBAAiB,sDAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Test fixture: PolicyField wrapping a control with NO id attribute — the
4
+ * wrapper must assign one so the label's `for` never dangles.
5
+ */
6
+
7
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
8
+ import FieldPolicyProvider from '../../components/FieldPolicyProvider.svelte';
9
+ import PolicyField from '../../components/PolicyField.svelte';
10
+
11
+ let {
12
+ policy,
13
+ mode = 'basic',
14
+ }: {
15
+ policy: ResolvedObjectFieldPolicy;
16
+ mode?: 'basic' | 'advanced';
17
+ } = $props();
18
+ </script>
19
+
20
+ <FieldPolicyProvider {policy} {mode}>
21
+ <PolicyField name="name">
22
+ <input type="text" />
23
+ </PolicyField>
24
+ </FieldPolicyProvider>
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Test fixture: PolicyField wrapping a control with NO id attribute — the
3
+ * wrapper must assign one so the label's `for` never dangles.
4
+ */
5
+ import type { ResolvedObjectFieldPolicy } from '../../../types.js';
6
+ type $$ComponentProps = {
7
+ policy: ResolvedObjectFieldPolicy;
8
+ mode?: 'basic' | 'advanced';
9
+ };
10
+ declare const NoIdFixture: import("svelte").Component<$$ComponentProps, {}, "">;
11
+ type NoIdFixture = ReturnType<typeof NoIdFixture>;
12
+ export default NoIdFixture;
13
+ //# sourceMappingURL=NoIdFixture.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoIdFixture.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/__tests__/fixtures/NoIdFixture.svelte.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAIlE,KAAK,gBAAgB,GAAI;IACxB,MAAM,EAAE,yBAAyB,CAAC;IAClC,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;CAC7B,CAAC;AAsBF,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}