@finsweet/webflow-apps-utils 1.0.3 → 1.0.5

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 (116) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/providers/GlobalProvider.stories.d.ts +5 -0
  4. package/dist/providers/GlobalProvider.stories.js +419 -0
  5. package/dist/providers/GlobalProviderDemo.svelte +266 -0
  6. package/dist/providers/GlobalProviderDemo.svelte.d.ts +3 -0
  7. package/dist/providers/configuratorUtils.d.ts +11 -14
  8. package/dist/providers/configuratorUtils.js +68 -115
  9. package/dist/providers/index.d.ts +1 -1
  10. package/dist/providers/index.js +1 -1
  11. package/dist/router/Router.stories.d.ts +6 -0
  12. package/dist/router/Router.stories.js +564 -0
  13. package/dist/router/examples/RouterExample.svelte +271 -0
  14. package/dist/router/examples/RouterExample.svelte.d.ts +18 -0
  15. package/dist/router/examples/index.d.ts +4 -0
  16. package/dist/router/examples/index.js +4 -0
  17. package/dist/router/examples/pages/AboutPage.svelte +568 -0
  18. package/dist/router/examples/pages/AboutPage.svelte.d.ts +13 -0
  19. package/dist/router/examples/pages/HomePage.svelte +200 -0
  20. package/dist/router/examples/pages/HomePage.svelte.d.ts +14 -0
  21. package/dist/router/examples/pages/NotFoundPage.svelte +307 -0
  22. package/dist/router/examples/pages/NotFoundPage.svelte.d.ts +17 -0
  23. package/dist/router/hooks.svelte.d.ts +2 -2
  24. package/dist/router/index.d.ts +3 -0
  25. package/dist/router/index.js +3 -0
  26. package/dist/router/{Link.svelte → providers/Link.svelte} +1 -1
  27. package/dist/router/{Route.svelte → providers/Route.svelte} +1 -1
  28. package/dist/router/{Route.svelte.d.ts → providers/Route.svelte.d.ts} +1 -1
  29. package/dist/router/{Router.svelte → providers/RouterProvider.svelte} +22 -5
  30. package/dist/router/{Router.svelte.d.ts → providers/RouterProvider.svelte.d.ts} +8 -4
  31. package/dist/router/providers/index.d.ts +3 -0
  32. package/dist/router/providers/index.js +3 -0
  33. package/dist/router/{index.svelte.d.ts → router.svelte.d.ts} +1 -3
  34. package/dist/router/{index.svelte.js → router.svelte.js} +1 -4
  35. package/dist/stores/forms/Form.stories.d.ts +5 -0
  36. package/dist/stores/forms/Form.stories.js +342 -0
  37. package/dist/stores/forms/FormDemo.svelte +545 -0
  38. package/dist/stores/forms/FormDemo.svelte.d.ts +18 -0
  39. package/dist/stores/forms.d.ts +41 -4
  40. package/dist/stores/forms.js +86 -32
  41. package/dist/types/customCode.d.ts +1 -1
  42. package/dist/types/window.d.ts +1 -0
  43. package/dist/ui/components/button/Button.svelte +1 -1
  44. package/dist/ui/components/copy-text/CopyText.stories.d.ts +70 -0
  45. package/dist/ui/components/copy-text/CopyText.stories.js +241 -0
  46. package/dist/ui/components/copy-text/CopyText.svelte +247 -0
  47. package/dist/ui/components/copy-text/CopyText.svelte.d.ts +4 -0
  48. package/dist/ui/components/copy-text/index.d.ts +2 -0
  49. package/dist/ui/components/copy-text/index.js +1 -0
  50. package/dist/ui/components/copy-text/types.d.ts +52 -0
  51. package/dist/ui/components/copy-text/types.js +1 -0
  52. package/dist/ui/components/index.d.ts +1 -0
  53. package/dist/ui/components/index.js +1 -0
  54. package/dist/ui/components/input/Input.stories.d.ts +9 -0
  55. package/dist/ui/components/input/Input.stories.js +78 -0
  56. package/dist/ui/components/input/Input.svelte +39 -3
  57. package/dist/ui/components/input/types.d.ts +6 -0
  58. package/dist/ui/components/layout/Layout.svelte +45 -64
  59. package/dist/ui/components/layout/Layout.svelte.d.ts +26 -3
  60. package/dist/ui/components/layout/examples/ExampleLayout.svelte +32 -27
  61. package/dist/ui/components/layout/index.d.ts +1 -1
  62. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte +20 -0
  63. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte.d.ts +7 -0
  64. package/dist/ui/components/layout/types.d.ts +1 -10
  65. package/dist/ui/components/notification/Notification.stories.svelte +12 -1
  66. package/dist/ui/components/notification/Notification.svelte +10 -5
  67. package/dist/ui/components/notification/Notification.svelte.d.ts +1 -1
  68. package/dist/ui/components/notification/types.d.ts +1 -1
  69. package/dist/ui/components/section/Section.svelte +8 -4
  70. package/dist/ui/components/section/types.d.ts +8 -0
  71. package/dist/ui/components/text/Text.stories.svelte +67 -1
  72. package/dist/ui/components/text/Text.svelte +209 -8
  73. package/dist/ui/components/text/types.d.ts +4 -0
  74. package/dist/ui/index.css +6 -2
  75. package/dist/utils/animations/factory.d.ts +7 -0
  76. package/dist/utils/animations/factory.js +101 -0
  77. package/dist/utils/animations/index.d.ts +7 -0
  78. package/dist/utils/animations/index.js +62 -0
  79. package/dist/utils/animations/types.d.ts +39 -0
  80. package/dist/utils/animations/types.js +1 -0
  81. package/dist/utils/custom-code/configs.d.ts +22 -0
  82. package/dist/utils/custom-code/configs.js +40 -0
  83. package/dist/utils/custom-code/index.d.ts +1 -0
  84. package/dist/utils/custom-code/index.js +1 -0
  85. package/dist/utils/diff-mapper/DiffMapper.stories.d.ts +5 -0
  86. package/dist/utils/diff-mapper/DiffMapper.stories.js +185 -0
  87. package/dist/utils/diff-mapper/DiffMapperDemo.svelte +351 -0
  88. package/dist/utils/diff-mapper/DiffMapperDemo.svelte.d.ts +18 -0
  89. package/dist/utils/diff-mapper/deepDiffMapper.d.ts +31 -0
  90. package/dist/utils/diff-mapper/deepDiffMapper.js +264 -0
  91. package/dist/utils/diff-mapper/index.d.ts +1 -0
  92. package/dist/utils/diff-mapper/index.js +1 -0
  93. package/dist/utils/helpers/capitalizeFirstLetter.d.ts +4 -0
  94. package/dist/utils/helpers/capitalizeFirstLetter.js +9 -0
  95. package/dist/utils/helpers/getTimeNow.d.ts +4 -0
  96. package/dist/utils/helpers/getTimeNow.js +8 -0
  97. package/dist/utils/helpers/index.d.ts +4 -0
  98. package/dist/utils/helpers/index.js +4 -0
  99. package/dist/utils/helpers/minifyCode.d.ts +10 -0
  100. package/dist/utils/helpers/minifyCode.js +73 -0
  101. package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -1
  102. package/dist/utils/helpers/objectsToModuleExports.js +1 -0
  103. package/dist/utils/helpers/toHumanReadableList.d.ts +4 -0
  104. package/dist/utils/helpers/toHumanReadableList.js +11 -0
  105. package/dist/utils/index.d.ts +2 -0
  106. package/dist/utils/index.js +2 -0
  107. package/dist/utils/webflow-canvas/getAllChildren.d.ts +16 -0
  108. package/dist/utils/webflow-canvas/getAllChildren.js +65 -0
  109. package/dist/utils/webflow-canvas/getElementClassList.d.ts +9 -0
  110. package/dist/utils/webflow-canvas/getElementClassList.js +19 -0
  111. package/dist/utils/webflow-canvas/index.d.ts +2 -0
  112. package/dist/utils/webflow-canvas/index.js +2 -0
  113. package/package.json +6 -1
  114. package/dist/providers/GlobalProvider.mdx +0 -322
  115. package/dist/router/README.md +0 -397
  116. /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
@@ -0,0 +1,545 @@
1
+ <script lang="ts">
2
+ import { FormValidator } from '../forms';
3
+
4
+ interface DemoFormData {
5
+ name: string;
6
+ instance: string;
7
+ class: string;
8
+ }
9
+
10
+ // Demo state
11
+ let existingInstances = ['fs-slider-1', 'fs-slider-2', 'fs-tabs-1'];
12
+ let isEditMode = false;
13
+ let currentInstance = 'fs-slider-1';
14
+ let classValidationEnabled = true;
15
+ let refreshTrigger = 0;
16
+
17
+ // Create form validator
18
+ const formValidator = new FormValidator<DemoFormData>(
19
+ 'demo-form',
20
+ {
21
+ name: 'New Component',
22
+ instance: 'fs-component',
23
+ class: 'fs-component'
24
+ },
25
+ { existingInstances }
26
+ );
27
+
28
+ // Subscribe to form state using derived stores
29
+ const formValues = formValidator.values;
30
+ const formErrors = formValidator.errors;
31
+ const formTouched = formValidator.touched;
32
+ const formIsValid = formValidator.isValid;
33
+ const formIsDirty = formValidator.isDirty;
34
+ const formIsSubmitting = formValidator.isSubmitting;
35
+
36
+ function forceRefresh() {
37
+ refreshTrigger++;
38
+ }
39
+
40
+ function generateNewNames() {
41
+ const generated = FormValidator.generateNames(existingInstances, 'demo', 'Demo Component');
42
+ formValidator.setFields(generated);
43
+ forceRefresh();
44
+ }
45
+
46
+ function toggleEditMode() {
47
+ isEditMode = !isEditMode;
48
+ if (isEditMode) {
49
+ formValidator.ignoreInstanceValidation(currentInstance, existingInstances);
50
+ formValidator.setFields({
51
+ name: currentInstance,
52
+ instance: currentInstance,
53
+ class: currentInstance
54
+ });
55
+ } else {
56
+ formValidator.validateWithInstances(existingInstances);
57
+ }
58
+ forceRefresh();
59
+ }
60
+
61
+ function toggleClassValidation() {
62
+ classValidationEnabled = !classValidationEnabled;
63
+ formValidator.enableClassValidation(classValidationEnabled);
64
+ forceRefresh();
65
+ }
66
+
67
+ function addExistingInstance() {
68
+ const newInstance = `fs-new-${Date.now()}`;
69
+ existingInstances = [...existingInstances, newInstance];
70
+ formValidator.validateWithInstances(existingInstances);
71
+ forceRefresh();
72
+ }
73
+
74
+ function resetForm() {
75
+ formValidator.reset();
76
+ isEditMode = false;
77
+ forceRefresh();
78
+ }
79
+
80
+ function submitForm(event: SubmitEvent) {
81
+ event.preventDefault();
82
+ if (!$formIsValid) return;
83
+
84
+ formValidator.setSubmitting(true);
85
+
86
+ // Simulate submission
87
+ setTimeout(() => {
88
+ formValidator.setSubmitting(false);
89
+ console.log('Form submitted:', $formValues);
90
+ forceRefresh();
91
+ }, 1000);
92
+ }
93
+
94
+ function handleClassInput(e: Event) {
95
+ const target = e.target as HTMLInputElement;
96
+ const sanitized = FormValidator.sanitizeClassName(target.value);
97
+ formValidator.setField('class', sanitized);
98
+ forceRefresh();
99
+ }
100
+ </script>
101
+
102
+ {#key refreshTrigger}
103
+ <div class="demo-container">
104
+ <h3>Form Validation System Demo</h3>
105
+
106
+ <div class="demo-controls">
107
+ <div class="control-section">
108
+ <h4>Demo Controls</h4>
109
+ <div class="button-group">
110
+ <button onclick={generateNewNames} class="btn btn--secondary"> Generate Names </button>
111
+ <button onclick={toggleEditMode} class="btn btn--secondary">
112
+ {isEditMode ? 'Exit Edit Mode' : 'Enter Edit Mode'}
113
+ </button>
114
+ <button onclick={toggleClassValidation} class="btn btn--secondary">
115
+ {classValidationEnabled ? 'Disable' : 'Enable'} Class Validation
116
+ </button>
117
+ <button onclick={addExistingInstance} class="btn btn--secondary">
118
+ Add Existing Instance
119
+ </button>
120
+ <button onclick={resetForm} class="btn btn--secondary"> Reset Form </button>
121
+ </div>
122
+ </div>
123
+
124
+ <div class="status-section">
125
+ <h4>Form Status</h4>
126
+ <div class="status-grid">
127
+ <div class="status-item">
128
+ <span>Valid:</span>
129
+ <strong class="status-{$formIsValid}">{$formIsValid ? 'YES' : 'NO'}</strong>
130
+ </div>
131
+ <div class="status-item">
132
+ <span>Dirty:</span>
133
+ <strong class="status-{$formIsDirty}">{$formIsDirty ? 'YES' : 'NO'}</strong>
134
+ </div>
135
+ <div class="status-item">
136
+ <span>Submitting:</span>
137
+ <strong class="status-{$formIsSubmitting}">{$formIsSubmitting ? 'YES' : 'NO'}</strong>
138
+ </div>
139
+ <div class="status-item">
140
+ <span>Edit Mode:</span>
141
+ <strong class="status-{isEditMode}">{isEditMode ? 'ON' : 'OFF'}</strong>
142
+ </div>
143
+ <div class="status-item">
144
+ <span>Class Validation:</span>
145
+ <strong class="status-{classValidationEnabled}"
146
+ >{classValidationEnabled ? 'ON' : 'OFF'}</strong
147
+ >
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+
153
+ <form class="demo-form" onsubmit={submitForm}>
154
+ <div class="form-section">
155
+ <h4>Component Form</h4>
156
+
157
+ <div class="field">
158
+ <label for="name">Component Name</label>
159
+ <input
160
+ id="name"
161
+ type="text"
162
+ value={$formValues.name}
163
+ oninput={(e) => {
164
+ const target = e.target as HTMLInputElement;
165
+ formValidator.setField('name', target.value);
166
+ forceRefresh();
167
+ }}
168
+ class:error={($formErrors.name?.length || 0) > 0}
169
+ placeholder="Enter component name"
170
+ />
171
+ {#if $formErrors.name?.length > 0}
172
+ <span class="error">{$formErrors.name[0]}</span>
173
+ {/if}
174
+ </div>
175
+
176
+ <div class="field">
177
+ <label for="instance">Instance Name</label>
178
+ <input
179
+ id="instance"
180
+ type="text"
181
+ value={$formValues.instance}
182
+ oninput={(e) => {
183
+ const target = e.target as HTMLInputElement;
184
+ formValidator.setField('instance', target.value);
185
+ forceRefresh();
186
+ }}
187
+ class:error={($formErrors.instance?.length || 0) > 0}
188
+ placeholder="Enter instance name (must be unique)"
189
+ />
190
+ {#if $formErrors.instance?.length > 0}
191
+ <span class="error">{$formErrors.instance[0]}</span>
192
+ {/if}
193
+ </div>
194
+
195
+ <div class="field">
196
+ <label for="class">CSS Class Name</label>
197
+ <input
198
+ id="class"
199
+ type="text"
200
+ value={$formValues.class}
201
+ oninput={handleClassInput}
202
+ class:error={($formErrors.class?.length || 0) > 0}
203
+ placeholder="Enter CSS class name"
204
+ disabled={!classValidationEnabled}
205
+ />
206
+ {#if $formErrors.class?.length > 0}
207
+ <span class="error">{$formErrors.class[0]}</span>
208
+ {/if}
209
+ {#if !classValidationEnabled}
210
+ <span class="helper">Class validation is disabled</span>
211
+ {/if}
212
+ </div>
213
+
214
+ <button
215
+ type="submit"
216
+ disabled={!$formIsValid || $formIsSubmitting}
217
+ class="btn btn--primary"
218
+ >
219
+ {#if $formIsSubmitting}
220
+ Submitting...
221
+ {:else if isEditMode}
222
+ Update Component
223
+ {:else}
224
+ Create Component
225
+ {/if}
226
+ </button>
227
+ </div>
228
+ </form>
229
+
230
+ <div class="debug-section">
231
+ <h4>Debug Information</h4>
232
+
233
+ <div class="debug-grid">
234
+ <div class="debug-item">
235
+ <h5>Existing Instances</h5>
236
+ <code>{JSON.stringify(existingInstances, null, 2)}</code>
237
+ </div>
238
+
239
+ <div class="debug-item">
240
+ <h5>Form Values</h5>
241
+ <code>{JSON.stringify($formValues, null, 2)}</code>
242
+ </div>
243
+
244
+ <div class="debug-item">
245
+ <h5>Form Errors</h5>
246
+ <code>{JSON.stringify($formErrors, null, 2)}</code>
247
+ </div>
248
+
249
+ <div class="debug-item">
250
+ <h5>Touched Fields</h5>
251
+ <code>{JSON.stringify($formTouched, null, 2)}</code>
252
+ </div>
253
+ </div>
254
+ </div>
255
+
256
+ <div class="examples-section">
257
+ <h4>Static Method Examples</h4>
258
+
259
+ <div class="example">
260
+ <h5>FormValidator.generateNames()</h5>
261
+ <button
262
+ onclick={() => {
263
+ const result = FormValidator.generateNames(existingInstances, 'test', 'Test Component');
264
+ console.log('Generated names:', result);
265
+ }}
266
+ class="btn btn--secondary"
267
+ >
268
+ Generate Test Names (check console)
269
+ </button>
270
+ </div>
271
+
272
+ <div class="example">
273
+ <h5>FormValidator.sanitizeClassName()</h5>
274
+ <div class="sanitize-demo">
275
+ <input
276
+ type="text"
277
+ placeholder="Enter invalid class name"
278
+ oninput={(e) => {
279
+ const target = e.target as HTMLInputElement;
280
+ const sanitized = FormValidator.sanitizeClassName(target.value);
281
+ const output = target.nextElementSibling as HTMLElement;
282
+ if (output) output.textContent = sanitized;
283
+ }}
284
+ />
285
+ <span class="sanitized-output">Sanitized output will appear here</span>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+ {/key}
291
+
292
+ <style>
293
+ .demo-container {
294
+ padding: 1.5rem;
295
+ max-width: 800px;
296
+ margin: 0 auto;
297
+ background: var(--background1);
298
+ color: var(--text1);
299
+ font-family: var(--font-stack);
300
+ }
301
+
302
+ .demo-controls {
303
+ display: grid;
304
+ grid-template-columns: 1fr 1fr;
305
+ gap: 1.5rem;
306
+ margin-bottom: 2rem;
307
+ }
308
+
309
+ .control-section,
310
+ .status-section {
311
+ padding: 1rem;
312
+ border: 1px solid var(--border2);
313
+ border-radius: var(--border-radius);
314
+ background: var(--background2);
315
+ }
316
+
317
+ .control-section h4,
318
+ .status-section h4,
319
+ .form-section h4,
320
+ .debug-section h4,
321
+ .examples-section h4 {
322
+ margin: 0 0 1rem 0;
323
+ color: var(--text1);
324
+ font-size: var(--font-size-large);
325
+ font-weight: var(--font-weight-medium);
326
+ }
327
+
328
+ .button-group {
329
+ display: flex;
330
+ flex-wrap: wrap;
331
+ gap: 0.5rem;
332
+ }
333
+
334
+ .status-grid {
335
+ display: grid;
336
+ grid-template-columns: 1fr 1fr;
337
+ gap: 0.5rem;
338
+ }
339
+
340
+ .status-item {
341
+ display: flex;
342
+ justify-content: space-between;
343
+ padding: 0.25rem 0;
344
+ font-size: var(--font-size-small);
345
+ }
346
+
347
+ .demo-form {
348
+ margin-bottom: 2rem;
349
+ }
350
+
351
+ .form-section {
352
+ padding: 1rem;
353
+ border: 1px solid var(--border2);
354
+ border-radius: var(--border-radius);
355
+ background: var(--background2);
356
+ }
357
+
358
+ .field {
359
+ margin-bottom: 1rem;
360
+ }
361
+
362
+ label {
363
+ display: block;
364
+ margin-bottom: 0.25rem;
365
+ font-size: var(--font-size-small);
366
+ font-weight: var(--font-weight-medium);
367
+ color: var(--text1);
368
+ }
369
+
370
+ input {
371
+ width: 100%;
372
+ padding: var(--padding-small);
373
+ border: 1px solid var(--border2);
374
+ border-radius: var(--border-radius);
375
+ background: var(--background1);
376
+ color: var(--text1);
377
+ font-size: var(--font-size-small);
378
+ font-family: var(--font-stack);
379
+ }
380
+
381
+ input:focus {
382
+ outline: none;
383
+ border-color: var(--actionPrimaryBackground);
384
+ }
385
+
386
+ input.error {
387
+ border-color: var(--redText);
388
+ }
389
+
390
+ input:disabled {
391
+ opacity: 0.6;
392
+ cursor: not-allowed;
393
+ }
394
+
395
+ .error {
396
+ color: var(--redText);
397
+ font-size: var(--font-size-tiny);
398
+ margin-top: 0.25rem;
399
+ display: block;
400
+ }
401
+
402
+ .helper {
403
+ color: var(--text3);
404
+ font-size: var(--font-size-tiny);
405
+ margin-top: 0.25rem;
406
+ display: block;
407
+ }
408
+
409
+ .btn {
410
+ padding: var(--padding-small) var(--padding-regular);
411
+ border: none;
412
+ border-radius: var(--border-radius);
413
+ cursor: pointer;
414
+ font-size: var(--font-size-small);
415
+ font-weight: var(--font-weight-normal);
416
+ font-family: var(--font-stack);
417
+ transition: all 0.2s ease;
418
+ }
419
+
420
+ .btn--primary {
421
+ background: var(--actionPrimaryBackground);
422
+ color: var(--actionPrimaryText);
423
+ box-shadow: var(--boxShadows-action-colored);
424
+ }
425
+
426
+ .btn--primary:hover:not(:disabled) {
427
+ background: var(--actionPrimaryBackgroundHover);
428
+ color: var(--actionPrimaryTextHover);
429
+ }
430
+
431
+ .btn--secondary {
432
+ background: var(--actionSecondaryBackground);
433
+ color: var(--actionSecondaryText);
434
+ box-shadow: var(--boxShadows-action-secondary);
435
+ }
436
+
437
+ .btn--secondary:hover:not(:disabled) {
438
+ background: var(--actionSecondaryBackgroundHover);
439
+ color: var(--actionSecondaryTextHover);
440
+ }
441
+
442
+ .btn:disabled {
443
+ opacity: 0.6;
444
+ cursor: not-allowed;
445
+ }
446
+
447
+ .status-true {
448
+ color: var(--greenText);
449
+ font-weight: var(--font-weight-medium);
450
+ }
451
+
452
+ .status-false {
453
+ color: var(--redText);
454
+ font-weight: var(--font-weight-medium);
455
+ }
456
+
457
+ .debug-section {
458
+ margin-bottom: 2rem;
459
+ padding: 1rem;
460
+ border: 1px solid var(--border2);
461
+ border-radius: var(--border-radius);
462
+ background: var(--background2);
463
+ }
464
+
465
+ .debug-grid {
466
+ display: grid;
467
+ grid-template-columns: 1fr 1fr;
468
+ gap: 1rem;
469
+ }
470
+
471
+ .debug-item h5 {
472
+ margin: 0 0 0.5rem 0;
473
+ font-size: var(--font-size-small);
474
+ font-weight: var(--font-weight-medium);
475
+ color: var(--text2);
476
+ }
477
+
478
+ .examples-section {
479
+ padding: 1rem;
480
+ border: 1px solid var(--border2);
481
+ border-radius: var(--border-radius);
482
+ background: var(--background2);
483
+ }
484
+
485
+ .example {
486
+ margin-bottom: 1rem;
487
+ }
488
+
489
+ .example h5 {
490
+ margin: 0 0 0.5rem 0;
491
+ font-size: var(--font-size-small);
492
+ font-weight: var(--font-weight-medium);
493
+ color: var(--text2);
494
+ }
495
+
496
+ .sanitize-demo {
497
+ display: flex;
498
+ gap: 0.5rem;
499
+ align-items: center;
500
+ }
501
+
502
+ .sanitize-demo input {
503
+ flex: 1;
504
+ }
505
+
506
+ .sanitized-output {
507
+ flex: 1;
508
+ padding: var(--padding-small);
509
+ background: var(--background3);
510
+ border: 1px solid var(--border2);
511
+ border-radius: var(--border-radius);
512
+ font-family: monospace;
513
+ font-size: var(--font-size-tiny);
514
+ color: var(--text3);
515
+ }
516
+
517
+ code {
518
+ background: var(--background3);
519
+ border: 1px solid var(--border2);
520
+ padding: var(--padding-tiny);
521
+ border-radius: var(--border-radius);
522
+ font-family: monospace;
523
+ font-size: var(--font-size-tiny);
524
+ color: var(--text2);
525
+ display: block;
526
+ white-space: pre-wrap;
527
+ max-height: 150px;
528
+ overflow-y: auto;
529
+ }
530
+
531
+ @media (max-width: 768px) {
532
+ .demo-controls {
533
+ grid-template-columns: 1fr;
534
+ }
535
+
536
+ .debug-grid {
537
+ grid-template-columns: 1fr;
538
+ }
539
+
540
+ .sanitize-demo {
541
+ flex-direction: column;
542
+ align-items: stretch;
543
+ }
544
+ }
545
+ </style>
@@ -0,0 +1,18 @@
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 FormDemo: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type FormDemo = InstanceType<typeof FormDemo>;
18
+ export default FormDemo;
@@ -8,7 +8,7 @@ interface FormState<T> {
8
8
  isSubmitting: boolean;
9
9
  }
10
10
  /**
11
- * Creates a form validation utility with Zod
11
+ * Creates a form validation utility with Svelte 5 reactive stores
12
12
  * @param identifier - Unique identifier for the form
13
13
  * @param options - Configuration options
14
14
  */
@@ -18,12 +18,18 @@ export declare class FormValidator<T extends {
18
18
  class: string;
19
19
  }> {
20
20
  private schema;
21
- private store;
22
- form: ReturnType<typeof derived<typeof this.store, FormState<T>>>;
21
+ private _store;
23
22
  private instancesSet;
24
23
  private initialValues;
25
24
  private identifier;
26
25
  private currentInstanceToIgnore;
26
+ private classValidationEnabled;
27
+ readonly values: ReturnType<typeof derived<typeof this._store, T>>;
28
+ readonly errors: ReturnType<typeof derived<typeof this._store, Record<keyof T, string[]>>>;
29
+ readonly touched: ReturnType<typeof derived<typeof this._store, Record<keyof T, boolean>>>;
30
+ readonly isValid: ReturnType<typeof derived<typeof this._store, boolean>>;
31
+ readonly isDirty: ReturnType<typeof derived<typeof this._store, boolean>>;
32
+ readonly isSubmitting: ReturnType<typeof derived<typeof this._store, boolean>>;
27
33
  /**
28
34
  * Generates unique name, instance, and class based on solution name and existing instances
29
35
  * @param existingInstances - Array of existing instance names
@@ -65,6 +71,11 @@ export declare class FormValidator<T extends {
65
71
  * Reset the form to initial values
66
72
  */
67
73
  reset(): void;
74
+ /**
75
+ * Enable or disable class name validation
76
+ * @param enabled - Whether to enable class validation
77
+ */
78
+ enableClassValidation(enabled: boolean): void;
68
79
  /**
69
80
  * Validate the form values
70
81
  */
@@ -74,10 +85,36 @@ export declare class FormValidator<T extends {
74
85
  */
75
86
  setSubmitting(isSubmitting: boolean): void;
76
87
  /**
77
- * Get the current state of the form
88
+ * Get the current state of the form (for legacy compatibility)
78
89
  */
79
90
  getState(): FormState<T>;
80
91
  }
92
+ /**
93
+ * Setup form hook
94
+ */
95
+ export declare function createForm<T extends {
96
+ name: string;
97
+ instance: string;
98
+ class: string;
99
+ }>(identifier: string, initialValues: T, options?: {
100
+ existingInstances?: string[];
101
+ enableClassValidation?: boolean;
102
+ }): {
103
+ values: import("svelte/store").Readable<T>;
104
+ errors: import("svelte/store").Readable<Record<keyof T, string[]>>;
105
+ touched: import("svelte/store").Readable<Record<keyof T, boolean>>;
106
+ isValid: import("svelte/store").Readable<boolean>;
107
+ isDirty: import("svelte/store").Readable<boolean>;
108
+ isSubmitting: import("svelte/store").Readable<boolean>;
109
+ setField: <K extends keyof T>(field: K, value: T[K]) => void;
110
+ setFields: (values: Partial<T>) => void;
111
+ reset: () => void;
112
+ enableClassValidation: (enabled: boolean) => void;
113
+ ignoreInstanceValidation: (instanceValue: string, existingInstances: string[]) => void;
114
+ setSubmitting: (isSubmitting: boolean) => void;
115
+ validate: () => void;
116
+ getState: () => FormState<T>;
117
+ };
81
118
  /**
82
119
  * Get a form by its identifier
83
120
  */