@happyvertical/smrt-products 0.30.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 (147) hide show
  1. package/AGENTS.md +122 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +115 -0
  5. package/dist/lib/__smrt-register__.d.ts +2 -0
  6. package/dist/lib/__smrt-register__.d.ts.map +1 -0
  7. package/dist/lib/app/main.d.ts +6 -0
  8. package/dist/lib/app/main.d.ts.map +1 -0
  9. package/dist/lib/chunks/ProductAssetCollection-DFPXN43q.js +64 -0
  10. package/dist/lib/chunks/ProductAssetCollection-DFPXN43q.js.map +1 -0
  11. package/dist/lib/chunks/ProductForm-DHeb2L24.js +371 -0
  12. package/dist/lib/chunks/ProductForm-DHeb2L24.js.map +1 -0
  13. package/dist/lib/chunks/Sku-DUKtbYWT.js +511 -0
  14. package/dist/lib/chunks/Sku-DUKtbYWT.js.map +1 -0
  15. package/dist/lib/chunks/SkuCollection-C0tdkEdL.js +160 -0
  16. package/dist/lib/chunks/SkuCollection-C0tdkEdL.js.map +1 -0
  17. package/dist/lib/chunks/__smrt-register__-BIgFaVKn.js +5 -0
  18. package/dist/lib/chunks/__smrt-register__-BIgFaVKn.js.map +1 -0
  19. package/dist/lib/chunks/index-i3-ci1FB.js +6 -0
  20. package/dist/lib/chunks/index-i3-ci1FB.js.map +1 -0
  21. package/dist/lib/chunks/product-store.svelte-Dayd5n3W.js +132 -0
  22. package/dist/lib/chunks/product-store.svelte-Dayd5n3W.js.map +1 -0
  23. package/dist/lib/client.d.ts +9 -0
  24. package/dist/lib/client.d.ts.map +1 -0
  25. package/dist/lib/collections.d.ts +2 -0
  26. package/dist/lib/collections.d.ts.map +1 -0
  27. package/dist/lib/collections.js +12 -0
  28. package/dist/lib/collections.js.map +1 -0
  29. package/dist/lib/components.d.ts +2 -0
  30. package/dist/lib/components.d.ts.map +1 -0
  31. package/dist/lib/components.js +6 -0
  32. package/dist/lib/components.js.map +1 -0
  33. package/dist/lib/generated.d.ts +2 -0
  34. package/dist/lib/generated.d.ts.map +1 -0
  35. package/dist/lib/generated.js +5 -0
  36. package/dist/lib/generated.js.map +1 -0
  37. package/dist/lib/index.d.ts +14 -0
  38. package/dist/lib/index.d.ts.map +1 -0
  39. package/dist/lib/index.js +228 -0
  40. package/dist/lib/index.js.map +1 -0
  41. package/dist/lib/lib/collections/CategoryCollection.d.ts +20 -0
  42. package/dist/lib/lib/collections/CategoryCollection.d.ts.map +1 -0
  43. package/dist/lib/lib/collections/MaterialCollection.d.ts +20 -0
  44. package/dist/lib/lib/collections/MaterialCollection.d.ts.map +1 -0
  45. package/dist/lib/lib/collections/ProductAssetCollection.d.ts +16 -0
  46. package/dist/lib/lib/collections/ProductAssetCollection.d.ts.map +1 -0
  47. package/dist/lib/lib/collections/ProductCollection.d.ts +12 -0
  48. package/dist/lib/lib/collections/ProductCollection.d.ts.map +1 -0
  49. package/dist/lib/lib/collections/ProductVariantCollection.d.ts +10 -0
  50. package/dist/lib/lib/collections/ProductVariantCollection.d.ts.map +1 -0
  51. package/dist/lib/lib/collections/SkuCollection.d.ts +31 -0
  52. package/dist/lib/lib/collections/SkuCollection.d.ts.map +1 -0
  53. package/dist/lib/lib/collections/index.d.ts +7 -0
  54. package/dist/lib/lib/collections/index.d.ts.map +1 -0
  55. package/dist/lib/lib/components/ProductCard.svelte +173 -0
  56. package/dist/lib/lib/components/ProductCard.svelte.d.ts +10 -0
  57. package/dist/lib/lib/components/ProductCard.svelte.d.ts.map +1 -0
  58. package/dist/lib/lib/components/ProductForm.svelte +289 -0
  59. package/dist/lib/lib/components/ProductForm.svelte.d.ts +11 -0
  60. package/dist/lib/lib/components/ProductForm.svelte.d.ts.map +1 -0
  61. package/dist/lib/lib/components/TestComponent.svelte +25 -0
  62. package/dist/lib/lib/components/TestComponent.svelte.d.ts +7 -0
  63. package/dist/lib/lib/components/TestComponent.svelte.d.ts.map +1 -0
  64. package/dist/lib/lib/components/auto-generated/AutoForm.svelte +240 -0
  65. package/dist/lib/lib/components/auto-generated/AutoForm.svelte.d.ts +13 -0
  66. package/dist/lib/lib/components/auto-generated/AutoForm.svelte.d.ts.map +1 -0
  67. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte +205 -0
  68. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte.d.ts +14 -0
  69. package/dist/lib/lib/components/auto-generated/FieldRenderer.svelte.d.ts.map +1 -0
  70. package/dist/lib/lib/components/index.d.ts +12 -0
  71. package/dist/lib/lib/components/index.d.ts.map +1 -0
  72. package/dist/lib/lib/components/index.js +11 -0
  73. package/dist/lib/lib/features/CategoryManager.svelte +80 -0
  74. package/dist/lib/lib/features/CategoryManager.svelte.d.ts +7 -0
  75. package/dist/lib/lib/features/CategoryManager.svelte.d.ts.map +1 -0
  76. package/dist/lib/lib/features/ProductCatalog.svelte +299 -0
  77. package/dist/lib/lib/features/ProductCatalog.svelte.d.ts +8 -0
  78. package/dist/lib/lib/features/ProductCatalog.svelte.d.ts.map +1 -0
  79. package/dist/lib/lib/federation-entry.d.ts +11 -0
  80. package/dist/lib/lib/federation-entry.d.ts.map +1 -0
  81. package/dist/lib/lib/generated/index.d.ts +2 -0
  82. package/dist/lib/lib/generated/index.d.ts.map +1 -0
  83. package/dist/lib/lib/i18n.d.ts +79 -0
  84. package/dist/lib/lib/i18n.d.ts.map +1 -0
  85. package/dist/lib/lib/index.d.ts +20 -0
  86. package/dist/lib/lib/index.d.ts.map +1 -0
  87. package/dist/lib/lib/mock-smrt-client.d.ts +40 -0
  88. package/dist/lib/lib/mock-smrt-client.d.ts.map +1 -0
  89. package/dist/lib/lib/mock-smrt-client.js +129 -0
  90. package/dist/lib/lib/mock-smrt-client.js.map +1 -0
  91. package/dist/lib/lib/models/Category.d.ts +38 -0
  92. package/dist/lib/lib/models/Category.d.ts.map +1 -0
  93. package/dist/lib/lib/models/Material.d.ts +22 -0
  94. package/dist/lib/lib/models/Material.d.ts.map +1 -0
  95. package/dist/lib/lib/models/Product.d.ts +57 -0
  96. package/dist/lib/lib/models/Product.d.ts.map +1 -0
  97. package/dist/lib/lib/models/ProductAsset.d.ts +17 -0
  98. package/dist/lib/lib/models/ProductAsset.d.ts.map +1 -0
  99. package/dist/lib/lib/models/ProductVariant.d.ts +51 -0
  100. package/dist/lib/lib/models/ProductVariant.d.ts.map +1 -0
  101. package/dist/lib/lib/models/Sku.d.ts +79 -0
  102. package/dist/lib/lib/models/Sku.d.ts.map +1 -0
  103. package/dist/lib/lib/models/index.d.ts +15 -0
  104. package/dist/lib/lib/models/index.d.ts.map +1 -0
  105. package/dist/lib/lib/models/types.d.ts +41 -0
  106. package/dist/lib/lib/models/types.d.ts.map +1 -0
  107. package/dist/lib/lib/stores/index.d.ts +8 -0
  108. package/dist/lib/lib/stores/index.d.ts.map +1 -0
  109. package/dist/lib/lib/stores/index.js +7 -0
  110. package/dist/lib/lib/stores/product-store.client.svelte.d.ts +45 -0
  111. package/dist/lib/lib/stores/product-store.client.svelte.d.ts.map +1 -0
  112. package/dist/lib/lib/stores/product-store.client.svelte.js +147 -0
  113. package/dist/lib/lib/stores/product-store.svelte.d.ts +29 -0
  114. package/dist/lib/lib/stores/product-store.svelte.d.ts.map +1 -0
  115. package/dist/lib/lib/stores/product-store.svelte.js +144 -0
  116. package/dist/lib/lib/types.d.ts +43 -0
  117. package/dist/lib/lib/types.d.ts.map +1 -0
  118. package/dist/lib/lib/utils/index.d.ts +10 -0
  119. package/dist/lib/lib/utils/index.d.ts.map +1 -0
  120. package/dist/lib/main.d.ts +5 -0
  121. package/dist/lib/main.d.ts.map +1 -0
  122. package/dist/lib/manifest.json +3758 -0
  123. package/dist/lib/mcp.d.ts +14 -0
  124. package/dist/lib/mcp.d.ts.map +1 -0
  125. package/dist/lib/models.d.ts +2 -0
  126. package/dist/lib/models.d.ts.map +1 -0
  127. package/dist/lib/models.js +12 -0
  128. package/dist/lib/models.js.map +1 -0
  129. package/dist/lib/native-api-server.d.ts +7 -0
  130. package/dist/lib/native-api-server.d.ts.map +1 -0
  131. package/dist/lib/server.d.ts +11 -0
  132. package/dist/lib/server.d.ts.map +1 -0
  133. package/dist/lib/simple-api-server.d.ts +7 -0
  134. package/dist/lib/simple-api-server.d.ts.map +1 -0
  135. package/dist/lib/simple-server.d.ts +6 -0
  136. package/dist/lib/simple-server.d.ts.map +1 -0
  137. package/dist/lib/smrt-knowledge.json +1584 -0
  138. package/dist/lib/smrt-products.css +233 -0
  139. package/dist/lib/stores.d.ts +2 -0
  140. package/dist/lib/stores.d.ts.map +1 -0
  141. package/dist/lib/stores.js +6 -0
  142. package/dist/lib/stores.js.map +1 -0
  143. package/dist/lib/utils.d.ts +2 -0
  144. package/dist/lib/utils.d.ts.map +1 -0
  145. package/dist/lib/utils.js +27 -0
  146. package/dist/lib/utils.js.map +1 -0
  147. package/package.json +127 -0
@@ -0,0 +1,289 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import { M } from '../i18n.js';
4
+ import type { ProductData } from '../types';
5
+
6
+ const { t } = useI18n();
7
+
8
+ interface Props {
9
+ product?: Partial<ProductData>;
10
+ onSubmit: (product: Partial<ProductData>) => void;
11
+ onCancel?: () => void;
12
+ loading?: boolean;
13
+ }
14
+
15
+ const { product = {}, onSubmit, onCancel, loading = false }: Props = $props();
16
+
17
+ const formData = $state({
18
+ name: product.name || '',
19
+ description: product.description || '',
20
+ price: product.price || 0,
21
+ inStock: product.inStock ?? true,
22
+ category: product.category || '',
23
+ tags: product.tags?.join(', ') || '',
24
+ });
25
+
26
+ let errors = $state<Record<string, string>>({});
27
+
28
+ function validateForm() {
29
+ errors = {};
30
+
31
+ if (!formData.name.trim()) {
32
+ errors.name = 'Product name is required';
33
+ }
34
+
35
+ if (formData.price < 0) {
36
+ errors.price = 'Price must be non-negative';
37
+ }
38
+
39
+ return Object.keys(errors).length === 0;
40
+ }
41
+
42
+ function _handleSubmit(event: Event) {
43
+ event.preventDefault();
44
+
45
+ if (!validateForm()) {
46
+ return;
47
+ }
48
+
49
+ const productData: Partial<ProductData> = {
50
+ ...product,
51
+ name: formData.name.trim(),
52
+ description: formData.description.trim() || undefined,
53
+ price: formData.price,
54
+ inStock: formData.inStock,
55
+ category: formData.category.trim(),
56
+ tags: formData.tags
57
+ ? formData.tags
58
+ .split(',')
59
+ .map((tag) => tag.trim())
60
+ .filter(Boolean)
61
+ : [],
62
+ };
63
+
64
+ onSubmit(productData);
65
+ }
66
+ </script>
67
+
68
+ <form onsubmit={handleSubmit} class="product-form">
69
+ <div class="form-group">
70
+ <label for="name">{t(M['products.product_form.name_label'])}</label>
71
+ <input
72
+ id="name"
73
+ type="text"
74
+ bind:value={formData.name}
75
+ disabled={loading}
76
+ class="form-input"
77
+ class:error={errors.name}
78
+ placeholder={t(M['products.product_form.name_placeholder'])}
79
+ />
80
+ {#if errors.name}
81
+ <span class="error-message">{errors.name}</span>
82
+ {/if}
83
+ </div>
84
+
85
+ <div class="form-group">
86
+ <label for="description">Description</label>
87
+ <textarea
88
+ id="description"
89
+ bind:value={formData.description}
90
+ disabled={loading}
91
+ class="form-textarea"
92
+ placeholder={t(M['products.product_form.description_placeholder'])}
93
+ rows="3"
94
+ ></textarea>
95
+ </div>
96
+
97
+ <div class="form-row">
98
+ <div class="form-group">
99
+ <label for="price">Price *</label>
100
+ <input
101
+ id="price"
102
+ type="number"
103
+ step="0.01"
104
+ min="0"
105
+ bind:value={formData.price}
106
+ disabled={loading}
107
+ class="form-input"
108
+ class:error={errors.price}
109
+ placeholder="0.00"
110
+ />
111
+ {#if errors.price}
112
+ <span class="error-message">{errors.price}</span>
113
+ {/if}
114
+ </div>
115
+
116
+ <div class="form-group">
117
+ <label for="category">Category</label>
118
+ <input
119
+ id="category"
120
+ type="text"
121
+ bind:value={formData.category}
122
+ disabled={loading}
123
+ class="form-input"
124
+ placeholder={t(M['products.product_form.category_placeholder'])}
125
+ />
126
+ </div>
127
+ </div>
128
+
129
+ <div class="form-group">
130
+ <label for="tags">Tags</label>
131
+ <input
132
+ id="tags"
133
+ type="text"
134
+ bind:value={formData.tags}
135
+ disabled={loading}
136
+ class="form-input"
137
+ placeholder={t(M['products.product_form.tags_placeholder'])}
138
+ />
139
+ <small class="form-hint">{t(M['products.product_form.tags_hint'])}</small>
140
+ </div>
141
+
142
+ <div class="form-group">
143
+ <label class="checkbox-label">
144
+ <input
145
+ type="checkbox"
146
+ bind:checked={formData.inStock}
147
+ disabled={loading}
148
+ class="form-checkbox"
149
+ />
150
+ {t(M['products.product_form.in_stock_label'])}
151
+ </label>
152
+ </div>
153
+
154
+ <div class="form-actions">
155
+ {#if onCancel}
156
+ <button type="button" onclick={onCancel} disabled={loading} class="cancel-btn">
157
+ Cancel
158
+ </button>
159
+ {/if}
160
+
161
+ <button type="submit" disabled={loading} class="submit-btn">
162
+ {#if loading}
163
+ Saving...
164
+ {:else}
165
+ {product.id ? 'Update Product' : 'Create Product'}
166
+ {/if}
167
+ </button>
168
+ </div>
169
+ </form>
170
+
171
+ <style>
172
+ .product-form {
173
+ max-width: 500px;
174
+ padding: 1.5rem;
175
+ background: white;
176
+ border-radius: var(--smrt-radius-md, 8px);
177
+ border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);
178
+ }
179
+
180
+ .form-group {
181
+ margin-bottom: 1rem;
182
+ }
183
+
184
+ .form-row {
185
+ display: grid;
186
+ grid-template-columns: 1fr 1fr;
187
+ gap: 1rem;
188
+ }
189
+
190
+ label {
191
+ display: block;
192
+ margin-bottom: 0.25rem;
193
+ font-weight: var(--smrt-typography-weight-medium, 500);
194
+ color: var(--smrt-color-on-surface, #374151);
195
+ font-size: var(--smrt-typography-label-large-size, 0.875rem);
196
+ }
197
+
198
+ .form-input, .form-textarea {
199
+ width: 100%;
200
+ padding: 0.5rem;
201
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
202
+ border-radius: var(--smrt-radius-sm, 4px);
203
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
204
+ transition: border-color 0.2s;
205
+ }
206
+
207
+ .form-input:focus, .form-textarea:focus {
208
+ outline: none;
209
+ border-color: var(--smrt-color-primary, #3b82f6);
210
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);
211
+ }
212
+
213
+ .form-input.error {
214
+ border-color: var(--smrt-color-error, #dc2626);
215
+ }
216
+
217
+ .form-textarea {
218
+ resize: vertical;
219
+ min-height: 80px;
220
+ }
221
+
222
+ .checkbox-label {
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 0.5rem;
226
+ cursor: pointer;
227
+ }
228
+
229
+ .form-checkbox {
230
+ width: auto;
231
+ }
232
+
233
+ .form-hint {
234
+ color: var(--smrt-color-on-surface-variant, #6b7280);
235
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
236
+ margin-top: 0.25rem;
237
+ }
238
+
239
+ .error-message {
240
+ color: var(--smrt-color-error, #dc2626);
241
+ font-size: var(--smrt-typography-label-medium-size, 0.75rem);
242
+ margin-top: 0.25rem;
243
+ display: block;
244
+ }
245
+
246
+ .form-actions {
247
+ display: flex;
248
+ gap: 0.75rem;
249
+ justify-content: flex-end;
250
+ margin-top: 1.5rem;
251
+ padding-top: 1rem;
252
+ border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);
253
+ }
254
+
255
+ .cancel-btn, .submit-btn {
256
+ padding: 0.5rem 1rem;
257
+ border-radius: var(--smrt-radius-sm, 4px);
258
+ font-size: var(--smrt-typography-label-large-size, 0.875rem);
259
+ font-weight: var(--smrt-typography-weight-medium, 500);
260
+ cursor: pointer;
261
+ border: 1px solid;
262
+ transition: all 0.2s;
263
+ }
264
+
265
+ .cancel-btn {
266
+ background: white;
267
+ border-color: var(--smrt-color-outline-variant, #d1d5db);
268
+ color: var(--smrt-color-on-surface, #374151);
269
+ }
270
+
271
+ .cancel-btn:hover:not(:disabled) {
272
+ background: var(--smrt-color-surface-container-low, #f9fafb);
273
+ }
274
+
275
+ .submit-btn {
276
+ background: var(--smrt-color-primary, #3b82f6);
277
+ border-color: var(--smrt-color-primary, #3b82f6);
278
+ color: var(--smrt-color-on-primary, white);
279
+ }
280
+
281
+ .submit-btn:hover:not(:disabled) {
282
+ background: var(--smrt-color-primary, #2563eb);
283
+ }
284
+
285
+ .submit-btn:disabled, .cancel-btn:disabled {
286
+ opacity: 0.5;
287
+ cursor: not-allowed;
288
+ }
289
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { ProductData } from '../types';
2
+ interface Props {
3
+ product?: Partial<ProductData>;
4
+ onSubmit: (product: Partial<ProductData>) => void;
5
+ onCancel?: () => void;
6
+ loading?: boolean;
7
+ }
8
+ declare const ProductForm: import("svelte").Component<Props, {}, "">;
9
+ type ProductForm = ReturnType<typeof ProductForm>;
10
+ export default ProductForm;
11
+ //# sourceMappingURL=ProductForm.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductForm.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/ProductForm.svelte"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,UAAU,KAAK;IACb,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA0HD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
+ import { M } from '../i18n.js';
4
+
5
+ interface Props {
6
+ message?: string;
7
+ }
8
+
9
+ const { message = 'Hello Federation!' }: Props = $props();
10
+ const { t } = useI18n();
11
+ </script>
12
+
13
+ <div class="test-component">
14
+ <h3>{t(M['products.test_component.title'])}</h3>
15
+ <p>{message}</p>
16
+ </div>
17
+
18
+ <style>
19
+ .test-component {
20
+ padding: 1rem;
21
+ border: 1px solid var(--smrt-color-outline-variant, #ccc);
22
+ border-radius: var(--smrt-radius-sm, 4px);
23
+ background: var(--smrt-color-surface-container-low, #f9f9f9);
24
+ }
25
+ </style>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ message?: string;
3
+ }
4
+ declare const TestComponent: import("svelte").Component<Props, {}, "">;
5
+ type TestComponent = ReturnType<typeof TestComponent>;
6
+ export default TestComponent;
7
+ //# sourceMappingURL=TestComponent.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestComponent.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/TestComponent.svelte"],"names":[],"mappings":"AAOA,UAAU,KAAK;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAkBD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,240 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Auto-generated form component from SMRT object schema
4
+ * Demonstrates "Define Once, Consume Everywhere" - form is generated from Product class definition
5
+ */
6
+
7
+ import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
+ import { M } from '../../i18n.js';
9
+ import type { ProductData } from '../../types';
10
+
11
+ const { t } = useI18n();
12
+
13
+ interface Props {
14
+ data?: ProductData;
15
+ title?: string;
16
+ submitLabel?: string;
17
+ readonly?: boolean;
18
+ onSubmit?: (data: ProductData) => void;
19
+ onChange?: (data: ProductData) => void;
20
+ }
21
+
22
+ const {
23
+ data = {},
24
+ title = 'Product Information',
25
+ submitLabel = 'Save',
26
+ readonly = false,
27
+ onSubmit,
28
+ onChange,
29
+ }: Props = $props();
30
+
31
+ // Auto-generated field schema from Product class
32
+ // In a full implementation, this would be generated by the SMRT plugin
33
+ const fieldSchema = [
34
+ {
35
+ name: 'name',
36
+ type: 'string',
37
+ label: 'Product Name',
38
+ required: true,
39
+ placeholder: 'Enter product name',
40
+ },
41
+ {
42
+ name: 'description',
43
+ type: 'string',
44
+ label: 'Description',
45
+ placeholder: 'Product description',
46
+ },
47
+ {
48
+ name: 'category',
49
+ type: 'string',
50
+ label: 'Category',
51
+ placeholder: 'Product category',
52
+ },
53
+ {
54
+ name: 'manufacturer',
55
+ type: 'string',
56
+ label: 'Manufacturer',
57
+ placeholder: 'Manufacturer name',
58
+ },
59
+ {
60
+ name: 'model',
61
+ type: 'string',
62
+ label: 'Model',
63
+ placeholder: 'Product model',
64
+ },
65
+ {
66
+ name: 'specifications',
67
+ type: 'object',
68
+ label: 'Specifications',
69
+ placeholder: 'Technical specifications',
70
+ },
71
+ { name: 'tags', type: 'array', label: 'Tags', placeholder: 'Product tags' },
72
+ ] as const;
73
+
74
+ // Reactive form data
75
+ let formData = $state({ ...data });
76
+
77
+ // Update form data when props change
78
+ $effect(() => {
79
+ formData = { ...data };
80
+ });
81
+
82
+ function _updateField(fieldName: string, value: any) {
83
+ formData[fieldName as keyof ProductData] = value;
84
+
85
+ // Trigger change callback
86
+ if (onChange) {
87
+ onChange({ ...formData });
88
+ }
89
+ }
90
+
91
+ function _handleSubmit(event: Event) {
92
+ event.preventDefault();
93
+ if (onSubmit && !readonly) {
94
+ onSubmit({ ...formData });
95
+ }
96
+ }
97
+
98
+ function _getFieldType(
99
+ name: string,
100
+ ): 'string' | 'number' | 'boolean' | 'array' | 'object' {
101
+ const field = fieldSchema.find((f) => f.name === name);
102
+ return field?.type || 'string';
103
+ }
104
+ </script>
105
+
106
+ <div class="auto-form">
107
+ <header class="form-header">
108
+ <h2 class="form-title">{title}</h2>
109
+ <div class="form-subtitle">
110
+ {t(M['products.auto_form.subtitle'])}
111
+ </div>
112
+ </header>
113
+
114
+ <form class="form-content" onsubmit={handleSubmit}>
115
+ {#each fieldSchema as field}
116
+ <FieldRenderer
117
+ fieldName={field.name}
118
+ fieldType={field.type}
119
+ value={formData[field.name]}
120
+ label={field.label}
121
+ placeholder={field.placeholder}
122
+ required={field.required || false}
123
+ {readonly}
124
+ onUpdate={(value) => updateField(field.name, value)}
125
+ />
126
+ {/each}
127
+
128
+ {#if !readonly}
129
+ <div class="form-actions">
130
+ <button type="submit" class="submit-btn">
131
+ {submitLabel}
132
+ </button>
133
+ <button type="button" class="reset-btn" onclick={() => formData = {}}>
134
+ Reset
135
+ </button>
136
+ </div>
137
+ {/if}
138
+ </form>
139
+
140
+ <!-- Demo: Show current form state -->
141
+ <details class="form-debug">
142
+ <summary>{t(M['products.auto_form.debug_summary'])}</summary>
143
+ <pre>{JSON.stringify(formData, null, 2)}</pre>
144
+ </details>
145
+ </div>
146
+
147
+ <style>
148
+ .auto-form {
149
+ max-width: 600px;
150
+ margin: 0 auto;
151
+ padding: 1.5rem;
152
+ background: white;
153
+ border-radius: var(--smrt-radius-md, 8px);
154
+ box-shadow: var(--smrt-elevation-1, 0 1px 3px color-mix(in srgb, var(--smrt-color-shadow, #000) 10%, transparent));
155
+ }
156
+
157
+ .form-header {
158
+ margin-bottom: 2rem;
159
+ text-align: center;
160
+ }
161
+
162
+ .form-title {
163
+ font-size: var(--smrt-typography-headline-small-size, 1.5rem);
164
+ font-weight: var(--smrt-typography-weight-semibold, 600);
165
+ color: var(--smrt-color-on-surface, #1f2937);
166
+ margin: 0 0 0.5rem 0;
167
+ }
168
+
169
+ .form-subtitle {
170
+ font-size: var(--smrt-typography-body-medium-size, 0.875rem);
171
+ color: var(--smrt-color-on-surface-variant, #6b7280);
172
+ font-style: italic;
173
+ }
174
+
175
+ .form-content {
176
+ display: flex;
177
+ flex-direction: column;
178
+ gap: 1rem;
179
+ }
180
+
181
+ .form-actions {
182
+ display: flex;
183
+ gap: 0.75rem;
184
+ margin-top: 1.5rem;
185
+ padding-top: 1.5rem;
186
+ border-top: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
187
+ }
188
+
189
+ .submit-btn {
190
+ background: var(--smrt-color-primary, #3b82f6);
191
+ color: var(--smrt-color-on-primary, white);
192
+ border: none;
193
+ padding: 0.75rem 1.5rem;
194
+ border-radius: 0.375rem;
195
+ font-weight: var(--smrt-typography-weight-medium, 500);
196
+ cursor: pointer;
197
+ transition: background-color 0.2s;
198
+ }
199
+
200
+ .submit-btn:hover {
201
+ background: var(--smrt-color-primary, #2563eb);
202
+ }
203
+
204
+ .reset-btn {
205
+ background: var(--smrt-color-surface-container, #f3f4f6);
206
+ color: var(--smrt-color-on-surface, #374151);
207
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
208
+ padding: 0.75rem 1.5rem;
209
+ border-radius: 0.375rem;
210
+ font-weight: var(--smrt-typography-weight-medium, 500);
211
+ cursor: pointer;
212
+ transition: background-color 0.2s;
213
+ }
214
+
215
+ .reset-btn:hover {
216
+ background: var(--smrt-color-surface-container-high, #e5e7eb);
217
+ }
218
+
219
+ .form-debug {
220
+ margin-top: 2rem;
221
+ padding: 1rem;
222
+ background: var(--smrt-color-surface-container-low, #f9fafb);
223
+ border-radius: 0.375rem;
224
+ border: 1px solid var(--smrt-color-outline-variant, #e5e7eb);
225
+ }
226
+
227
+ .form-debug summary {
228
+ cursor: pointer;
229
+ font-weight: var(--smrt-typography-weight-medium, 500);
230
+ color: var(--smrt-color-on-surface, #374151);
231
+ }
232
+
233
+ .form-debug pre {
234
+ margin-top: 0.5rem;
235
+ font-size: var(--smrt-typography-body-small-size, 0.75rem);
236
+ color: var(--smrt-color-on-surface-variant, #6b7280);
237
+ white-space: pre-wrap;
238
+ word-break: break-word;
239
+ }
240
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { ProductData } from '../../types';
2
+ interface Props {
3
+ data?: ProductData;
4
+ title?: string;
5
+ submitLabel?: string;
6
+ readonly?: boolean;
7
+ onSubmit?: (data: ProductData) => void;
8
+ onChange?: (data: ProductData) => void;
9
+ }
10
+ declare const AutoForm: import("svelte").Component<Props, {}, "">;
11
+ type AutoForm = ReturnType<typeof AutoForm>;
12
+ export default AutoForm;
13
+ //# sourceMappingURL=AutoForm.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutoForm.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/AutoForm.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,UAAU,KAAK;IACb,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AAkID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}