@happyvertical/smrt-products 0.34.6 → 0.34.7

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.
@@ -1,10 +1,11 @@
1
1
  import "svelte/internal/disclose-version";
2
2
  import * as $ from "svelte/internal/client";
3
3
  import { Button } from "@happyvertical/smrt-ui/ui";
4
+ import { Form, Input, Textarea } from "@happyvertical/smrt-ui/forms";
4
5
  import { defineMessages, useI18n } from "@happyvertical/smrt-ui/i18n";
5
6
  var root_1$1 = $.from_html(`<div class="product-manufacturer svelte-11ja2cl"> </div>`);
6
7
  var root_2$1 = $.from_html(`<div class="product-model svelte-11ja2cl"> </div>`);
7
- var root_3 = $.from_html(`<p class="product-description svelte-11ja2cl"> </p>`);
8
+ var root_3$1 = $.from_html(`<p class="product-description svelte-11ja2cl"> </p>`);
8
9
  var root_4 = $.from_html(`<div class="product-category svelte-11ja2cl"> </div>`);
9
10
  var root_6 = $.from_html(`<span class="tag svelte-11ja2cl"> </span>`);
10
11
  var root_5 = $.from_html(`<div class="product-tags svelte-11ja2cl"></div>`);
@@ -46,7 +47,7 @@ function ProductCard($$anchor, $$props) {
46
47
  var node_2 = $.sibling(node_1, 2);
47
48
  {
48
49
  var consequent_2 = ($$anchor2) => {
49
- var p = root_3();
50
+ var p = root_3$1();
50
51
  var text_3 = $.child(p, true);
51
52
  $.reset(p);
52
53
  $.template_effect(() => $.set_text(text_3, $$props.product.description));
@@ -224,9 +225,10 @@ const M = defineMessages({
224
225
  "products.product_catalog.create_first": "Create First Product",
225
226
  "products.product_catalog.no_match": "No products match your search criteria."
226
227
  });
227
- var root_1 = $.from_html(`<span class="error-message svelte-1hh5ovx"> </span>`);
228
228
  var root_2 = $.from_html(`<span class="error-message svelte-1hh5ovx"> </span>`);
229
- var root = $.from_html(`<form class="product-form svelte-1hh5ovx"><div class="form-group svelte-1hh5ovx"><label for="name" class="svelte-1hh5ovx"> </label> <input id="name" type="text"/> <!></div> <div class="form-group svelte-1hh5ovx"><label for="description" class="svelte-1hh5ovx">Description</label> <textarea id="description" class="form-textarea svelte-1hh5ovx" rows="3"></textarea></div> <div class="form-row svelte-1hh5ovx"><div class="form-group svelte-1hh5ovx"><label for="price" class="svelte-1hh5ovx">Price *</label> <input id="price" type="number" step="0.01" min="0" placeholder="0.00"/> <!></div> <div class="form-group svelte-1hh5ovx"><label for="category" class="svelte-1hh5ovx">Category</label> <input id="category" type="text" class="form-input svelte-1hh5ovx"/></div></div> <div class="form-group svelte-1hh5ovx"><label for="tags" class="svelte-1hh5ovx">Tags</label> <input id="tags" type="text" class="form-input svelte-1hh5ovx"/> <small class="form-hint svelte-1hh5ovx"> </small></div> <div class="form-group svelte-1hh5ovx"><label class="checkbox-label svelte-1hh5ovx"><input type="checkbox" class="form-checkbox svelte-1hh5ovx"/> </label></div> <div class="form-actions svelte-1hh5ovx"><!> <!></div></form>`);
229
+ var root_3 = $.from_html(`<span class="error-message svelte-1hh5ovx"> </span>`);
230
+ var root_1 = $.from_html(`<div class="form-group svelte-1hh5ovx"><label for="name" class="svelte-1hh5ovx"> </label> <!> <!></div> <div class="form-group svelte-1hh5ovx"><label for="description" class="svelte-1hh5ovx">Description</label> <!></div> <div class="form-row svelte-1hh5ovx"><div class="form-group svelte-1hh5ovx"><label for="price" class="svelte-1hh5ovx">Price *</label> <!> <!></div> <div class="form-group svelte-1hh5ovx"><label for="category" class="svelte-1hh5ovx">Category</label> <!></div></div> <div class="form-group svelte-1hh5ovx"><label for="tags" class="svelte-1hh5ovx">Tags</label> <!> <small class="form-hint svelte-1hh5ovx"> </small></div> <div class="form-group svelte-1hh5ovx"><label class="checkbox-label svelte-1hh5ovx"><input type="checkbox" class="form-checkbox svelte-1hh5ovx"/> </label></div> <div class="form-actions svelte-1hh5ovx"><!> <!></div>`, 1);
231
+ var root = $.from_html(`<div class="product-form-shell svelte-1hh5ovx"><!></div>`);
230
232
  function ProductForm($$anchor, $$props) {
231
233
  $.push($$props, true);
232
234
  const { t } = useI18n();
@@ -266,166 +268,250 @@ function ProductForm($$anchor, $$props) {
266
268
  };
267
269
  $$props.onSubmit(productData);
268
270
  }
269
- var form = root();
270
- var div = $.child(form);
271
- var label = $.child(div);
272
- var text = $.child(label, true);
273
- $.reset(label);
274
- var input = $.sibling(label, 2);
275
- $.remove_input_defaults(input);
276
- let classes;
277
- var node = $.sibling(input, 2);
278
- {
279
- var consequent = ($$anchor2) => {
280
- var span = root_1();
281
- var text_1 = $.child(span, true);
282
- $.reset(span);
283
- $.template_effect(() => $.set_text(text_1, $.get(errors).name));
284
- $.append($$anchor2, span);
285
- };
286
- $.if(node, ($$render) => {
287
- if ($.get(errors).name) $$render(consequent);
288
- });
289
- }
290
- $.reset(div);
291
- var div_1 = $.sibling(div, 2);
292
- var textarea = $.sibling($.child(div_1), 2);
293
- $.remove_textarea_child(textarea);
294
- $.reset(div_1);
295
- var div_2 = $.sibling(div_1, 2);
296
- var div_3 = $.child(div_2);
297
- var input_1 = $.sibling($.child(div_3), 2);
298
- $.remove_input_defaults(input_1);
299
- let classes_1;
300
- var node_1 = $.sibling(input_1, 2);
301
- {
302
- var consequent_1 = ($$anchor2) => {
303
- var span_1 = root_2();
304
- var text_2 = $.child(span_1, true);
305
- $.reset(span_1);
306
- $.template_effect(() => $.set_text(text_2, $.get(errors).price));
307
- $.append($$anchor2, span_1);
308
- };
309
- $.if(node_1, ($$render) => {
310
- if ($.get(errors).price) $$render(consequent_1);
311
- });
312
- }
313
- $.reset(div_3);
314
- var div_4 = $.sibling(div_3, 2);
315
- var input_2 = $.sibling($.child(div_4), 2);
316
- $.remove_input_defaults(input_2);
317
- $.reset(div_4);
318
- $.reset(div_2);
319
- var div_5 = $.sibling(div_2, 2);
320
- var input_3 = $.sibling($.child(div_5), 2);
321
- $.remove_input_defaults(input_3);
322
- var small = $.sibling(input_3, 2);
323
- var text_3 = $.child(small, true);
324
- $.reset(small);
325
- $.reset(div_5);
326
- var div_6 = $.sibling(div_5, 2);
327
- var label_1 = $.child(div_6);
328
- var input_4 = $.child(label_1);
329
- $.remove_input_defaults(input_4);
330
- var text_4 = $.sibling(input_4);
331
- $.reset(label_1);
332
- $.reset(div_6);
333
- var div_7 = $.sibling(div_6, 2);
334
- var node_2 = $.child(div_7);
335
- {
336
- var consequent_2 = ($$anchor2) => {
337
- Button($$anchor2, {
338
- type: "button",
339
- variant: "secondary",
340
- get onclick() {
341
- return $$props.onCancel;
342
- },
343
- get disabled() {
344
- return loading();
345
- },
346
- children: ($$anchor3, $$slotProps) => {
347
- $.next();
348
- var text_5 = $.text("Cancel");
349
- $.append($$anchor3, text_5);
350
- },
351
- $$slots: { default: true }
352
- });
353
- };
354
- $.if(node_2, ($$render) => {
355
- if ($$props.onCancel) $$render(consequent_2);
356
- });
357
- }
358
- var node_3 = $.sibling(node_2, 2);
359
- Button(node_3, {
360
- type: "submit",
361
- variant: "primary",
362
- get disabled() {
363
- return loading();
364
- },
271
+ var div = root();
272
+ var node = $.child(div);
273
+ Form(node, {
274
+ onsubmit: handleSubmit,
275
+ class: "product-form",
365
276
  children: ($$anchor2, $$slotProps) => {
366
- var fragment_1 = $.comment();
367
- var node_4 = $.first_child(fragment_1);
277
+ var fragment = root_1();
278
+ var div_1 = $.first_child(fragment);
279
+ var label = $.child(div_1);
280
+ var text = $.child(label, true);
281
+ $.reset(label);
282
+ var node_1 = $.sibling(label, 2);
368
283
  {
369
- var consequent_3 = ($$anchor3) => {
370
- var text_6 = $.text("Saving...");
371
- $.append($$anchor3, text_6);
284
+ let $0 = $.derived(() => $.get(errors).name ? "error" : "");
285
+ let $1 = $.derived(() => t(M["products.product_form.name_placeholder"]));
286
+ Input(node_1, {
287
+ id: "name",
288
+ type: "text",
289
+ get disabled() {
290
+ return loading();
291
+ },
292
+ get class() {
293
+ return $.get($0);
294
+ },
295
+ get placeholder() {
296
+ return $.get($1);
297
+ },
298
+ get value() {
299
+ return formData.name;
300
+ },
301
+ set value($$value) {
302
+ formData.name = $$value;
303
+ }
304
+ });
305
+ }
306
+ var node_2 = $.sibling(node_1, 2);
307
+ {
308
+ var consequent = ($$anchor3) => {
309
+ var span = root_2();
310
+ var text_1 = $.child(span, true);
311
+ $.reset(span);
312
+ $.template_effect(() => $.set_text(text_1, $.get(errors).name));
313
+ $.append($$anchor3, span);
372
314
  };
373
- var alternate = ($$anchor3) => {
374
- var text_7 = $.text();
375
- $.template_effect(() => $.set_text(text_7, product().id ? "Update Product" : "Create Product"));
376
- $.append($$anchor3, text_7);
315
+ $.if(node_2, ($$render) => {
316
+ if ($.get(errors).name) $$render(consequent);
317
+ });
318
+ }
319
+ $.reset(div_1);
320
+ var div_2 = $.sibling(div_1, 2);
321
+ var node_3 = $.sibling($.child(div_2), 2);
322
+ {
323
+ let $0 = $.derived(() => t(M["products.product_form.description_placeholder"]));
324
+ Textarea(node_3, {
325
+ id: "description",
326
+ get disabled() {
327
+ return loading();
328
+ },
329
+ get placeholder() {
330
+ return $.get($0);
331
+ },
332
+ rows: 3,
333
+ get value() {
334
+ return formData.description;
335
+ },
336
+ set value($$value) {
337
+ formData.description = $$value;
338
+ }
339
+ });
340
+ }
341
+ $.reset(div_2);
342
+ var div_3 = $.sibling(div_2, 2);
343
+ var div_4 = $.child(div_3);
344
+ var node_4 = $.sibling($.child(div_4), 2);
345
+ {
346
+ let $0 = $.derived(() => $.get(errors).price ? "error" : "");
347
+ Input(node_4, {
348
+ id: "price",
349
+ type: "number",
350
+ step: "0.01",
351
+ min: "0",
352
+ get disabled() {
353
+ return loading();
354
+ },
355
+ get class() {
356
+ return $.get($0);
357
+ },
358
+ placeholder: "0.00",
359
+ get value() {
360
+ return formData.price;
361
+ },
362
+ set value($$value) {
363
+ formData.price = $$value;
364
+ }
365
+ });
366
+ }
367
+ var node_5 = $.sibling(node_4, 2);
368
+ {
369
+ var consequent_1 = ($$anchor3) => {
370
+ var span_1 = root_3();
371
+ var text_2 = $.child(span_1, true);
372
+ $.reset(span_1);
373
+ $.template_effect(() => $.set_text(text_2, $.get(errors).price));
374
+ $.append($$anchor3, span_1);
375
+ };
376
+ $.if(node_5, ($$render) => {
377
+ if ($.get(errors).price) $$render(consequent_1);
378
+ });
379
+ }
380
+ $.reset(div_4);
381
+ var div_5 = $.sibling(div_4, 2);
382
+ var node_6 = $.sibling($.child(div_5), 2);
383
+ {
384
+ let $0 = $.derived(() => t(M["products.product_form.category_placeholder"]));
385
+ Input(node_6, {
386
+ id: "category",
387
+ type: "text",
388
+ get disabled() {
389
+ return loading();
390
+ },
391
+ get placeholder() {
392
+ return $.get($0);
393
+ },
394
+ get value() {
395
+ return formData.category;
396
+ },
397
+ set value($$value) {
398
+ formData.category = $$value;
399
+ }
400
+ });
401
+ }
402
+ $.reset(div_5);
403
+ $.reset(div_3);
404
+ var div_6 = $.sibling(div_3, 2);
405
+ var node_7 = $.sibling($.child(div_6), 2);
406
+ {
407
+ let $0 = $.derived(() => t(M["products.product_form.tags_placeholder"]));
408
+ Input(node_7, {
409
+ id: "tags",
410
+ type: "text",
411
+ get disabled() {
412
+ return loading();
413
+ },
414
+ get placeholder() {
415
+ return $.get($0);
416
+ },
417
+ get value() {
418
+ return formData.tags;
419
+ },
420
+ set value($$value) {
421
+ formData.tags = $$value;
422
+ }
423
+ });
424
+ }
425
+ var small = $.sibling(node_7, 2);
426
+ var text_3 = $.child(small, true);
427
+ $.reset(small);
428
+ $.reset(div_6);
429
+ var div_7 = $.sibling(div_6, 2);
430
+ var label_1 = $.child(div_7);
431
+ var input = $.child(label_1);
432
+ $.remove_input_defaults(input);
433
+ var text_4 = $.sibling(input);
434
+ $.reset(label_1);
435
+ $.reset(div_7);
436
+ var div_8 = $.sibling(div_7, 2);
437
+ var node_8 = $.child(div_8);
438
+ {
439
+ var consequent_2 = ($$anchor3) => {
440
+ Button($$anchor3, {
441
+ type: "button",
442
+ variant: "secondary",
443
+ get onclick() {
444
+ return $$props.onCancel;
445
+ },
446
+ get disabled() {
447
+ return loading();
448
+ },
449
+ children: ($$anchor4, $$slotProps2) => {
450
+ $.next();
451
+ var text_5 = $.text("Cancel");
452
+ $.append($$anchor4, text_5);
453
+ },
454
+ $$slots: { default: true }
455
+ });
377
456
  };
378
- $.if(node_4, ($$render) => {
379
- if (loading()) $$render(consequent_3);
380
- else $$render(alternate, -1);
457
+ $.if(node_8, ($$render) => {
458
+ if ($$props.onCancel) $$render(consequent_2);
381
459
  });
382
460
  }
383
- $.append($$anchor2, fragment_1);
461
+ var node_9 = $.sibling(node_8, 2);
462
+ Button(node_9, {
463
+ type: "submit",
464
+ variant: "primary",
465
+ get disabled() {
466
+ return loading();
467
+ },
468
+ children: ($$anchor3, $$slotProps2) => {
469
+ var fragment_2 = $.comment();
470
+ var node_10 = $.first_child(fragment_2);
471
+ {
472
+ var consequent_3 = ($$anchor4) => {
473
+ var text_6 = $.text("Saving...");
474
+ $.append($$anchor4, text_6);
475
+ };
476
+ var alternate = ($$anchor4) => {
477
+ var text_7 = $.text();
478
+ $.template_effect(() => $.set_text(text_7, product().id ? "Update Product" : "Create Product"));
479
+ $.append($$anchor4, text_7);
480
+ };
481
+ $.if(node_10, ($$render) => {
482
+ if (loading()) $$render(consequent_3);
483
+ else $$render(alternate, -1);
484
+ });
485
+ }
486
+ $.append($$anchor3, fragment_2);
487
+ },
488
+ $$slots: { default: true }
489
+ });
490
+ $.reset(div_8);
491
+ $.template_effect(
492
+ ($0, $1, $2) => {
493
+ $.set_text(text, $0);
494
+ $.set_text(text_3, $1);
495
+ input.disabled = loading();
496
+ $.set_text(text_4, ` ${$2 ?? ""}`);
497
+ },
498
+ [
499
+ () => t(M["products.product_form.name_label"]),
500
+ () => t(M["products.product_form.tags_hint"]),
501
+ () => t(M["products.product_form.in_stock_label"])
502
+ ]
503
+ );
504
+ $.bind_checked(input, () => formData.inStock, ($$value) => formData.inStock = $$value);
505
+ $.append($$anchor2, fragment);
384
506
  },
385
507
  $$slots: { default: true }
386
508
  });
387
- $.reset(div_7);
388
- $.reset(form);
389
- $.template_effect(
390
- ($0, $1, $2, $3, $4, $5, $6) => {
391
- $.set_text(text, $0);
392
- input.disabled = loading();
393
- classes = $.set_class(input, 1, "form-input svelte-1hh5ovx", null, classes, { error: $.get(errors).name });
394
- $.set_attribute(input, "placeholder", $1);
395
- textarea.disabled = loading();
396
- $.set_attribute(textarea, "placeholder", $2);
397
- input_1.disabled = loading();
398
- classes_1 = $.set_class(input_1, 1, "form-input svelte-1hh5ovx", null, classes_1, { error: $.get(errors).price });
399
- input_2.disabled = loading();
400
- $.set_attribute(input_2, "placeholder", $3);
401
- input_3.disabled = loading();
402
- $.set_attribute(input_3, "placeholder", $4);
403
- $.set_text(text_3, $5);
404
- input_4.disabled = loading();
405
- $.set_text(text_4, ` ${$6 ?? ""}`);
406
- },
407
- [
408
- () => t(M["products.product_form.name_label"]),
409
- () => t(M["products.product_form.name_placeholder"]),
410
- () => t(M["products.product_form.description_placeholder"]),
411
- () => t(M["products.product_form.category_placeholder"]),
412
- () => t(M["products.product_form.tags_placeholder"]),
413
- () => t(M["products.product_form.tags_hint"]),
414
- () => t(M["products.product_form.in_stock_label"])
415
- ]
416
- );
417
- $.event("submit", form, handleSubmit);
418
- $.bind_value(input, () => formData.name, ($$value) => formData.name = $$value);
419
- $.bind_value(textarea, () => formData.description, ($$value) => formData.description = $$value);
420
- $.bind_value(input_1, () => formData.price, ($$value) => formData.price = $$value);
421
- $.bind_value(input_2, () => formData.category, ($$value) => formData.category = $$value);
422
- $.bind_value(input_3, () => formData.tags, ($$value) => formData.tags = $$value);
423
- $.bind_checked(input_4, () => formData.inStock, ($$value) => formData.inStock = $$value);
424
- $.append($$anchor, form);
509
+ $.reset(div);
510
+ $.append($$anchor, div);
425
511
  $.pop();
426
512
  }
427
513
  export {
428
514
  ProductCard as P,
429
515
  ProductForm as a
430
516
  };
431
- //# sourceMappingURL=ProductForm-CukMCDEN.js.map
517
+ //# sourceMappingURL=ProductForm-BLRguem5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductForm-CukMCDEN.js","sources":["../../../src/lib/components/ProductCard.svelte","../../../src/lib/i18n.ts","../../../src/lib/components/ProductForm.svelte"],"sourcesContent":["<script lang=\"ts\">\nimport { Button } from '@happyvertical/smrt-ui/ui';\nimport type { ProductData } from '../types';\n\ninterface Props {\n product: ProductData;\n onEdit?: (product: ProductData) => void;\n onDelete?: (id: string) => void;\n}\n\nconst { product, onEdit, onDelete }: Props = $props();\n</script>\n\n<div class=\"product-card\">\n <div class=\"product-header\">\n <h3 class=\"product-name\">{product.name}</h3>\n {#if product.manufacturer}\n <div class=\"product-manufacturer\">{product.manufacturer}</div>\n {/if}\n </div>\n\n {#if product.model}\n <div class=\"product-model\">Model: {product.model}</div>\n {/if}\n\n {#if product.description}\n <p class=\"product-description\">{product.description}</p>\n {/if}\n\n <div class=\"product-meta\">\n {#if product.category}\n <div class=\"product-category\">Category: {product.category}</div>\n {/if}\n \n {#if product.tags && product.tags.length > 0}\n <div class=\"product-tags\">\n {#each product.tags as tag}\n <span class=\"tag\">{tag}</span>\n {/each}\n </div>\n {/if}\n </div>\n \n <div class=\"product-actions\">\n {#if onEdit}\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onclick={() => onEdit?.(product)}>\n Edit\n </Button>\n {/if}\n\n {#if onDelete}\n <Button type=\"button\" variant=\"danger\" size=\"sm\" onclick={() => onDelete?.(product.id)}>\n Delete\n </Button>\n {/if}\n </div>\n</div>\n\n<style>\n .product-card {\n border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);\n border-radius: var(--smrt-radius-md, 8px);\n padding: 1rem;\n background: var(--smrt-color-surface, #fff);\n box-shadow: var(--smrt-elevation-1, 0 1px 3px color-mix(in srgb, var(--smrt-color-shadow, #000) 10%, transparent));\n transition: box-shadow 0.2s;\n }\n\n .product-card:hover {\n box-shadow: var(--smrt-elevation-2, 0 4px 6px color-mix(in srgb, var(--smrt-color-shadow, #000) 10%, transparent));\n }\n \n .product-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.5rem;\n }\n \n .product-name {\n margin: 0;\n font-size: var(--smrt-typography-title-medium-size, 1.125rem);\n font-weight: var(--smrt-typography-weight-semibold, 600);\n color: var(--smrt-color-on-surface, #1f2937);\n }\n\n .product-manufacturer {\n font-size: var(--smrt-typography-title-small-size, 0.875rem);\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface-variant, #6b7280);\n }\n\n .product-model {\n font-size: var(--smrt-typography-body-medium-size, 0.875rem);\n color: var(--smrt-color-on-surface-variant, #6b7280);\n margin-bottom: 0.5rem;\n }\n\n .product-category {\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface, #374151);\n background: var(--smrt-color-surface-container, #f3f4f6);\n padding: 0.25rem 0.5rem;\n border-radius: var(--smrt-radius-sm, 4px);\n display: inline-block;\n margin-bottom: 0.5rem;\n }\n \n .product-description {\n margin: 0.5rem 0;\n color: var(--smrt-color-on-surface-variant, #6b7280);\n font-size: var(--smrt-typography-body-medium-size, 0.875rem);\n line-height: var(--smrt-typography-body-medium-line-height, 1.4);\n }\n \n .product-meta {\n margin: 0.75rem 0;\n }\n \n \n .product-tags {\n margin-top: 0.5rem;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n }\n \n .tag {\n background: var(--smrt-color-surface-container, #f3f4f6);\n color: var(--smrt-color-on-surface, #374151);\n padding: 0.125rem 0.5rem;\n border-radius: var(--smrt-radius-full, 9999px);\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n }\n\n .product-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 1rem;\n padding-top: 0.75rem;\n border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);\n }\n</style>","import { defineMessages } from '@happyvertical/smrt-ui/i18n';\n\nexport const M = defineMessages({\n // App\n 'products.app.categories_coming_soon': 'Category management coming soon...',\n 'products.app.analytics_coming_soon': 'Analytics dashboard coming soon...',\n\n // AppLayout\n 'products.app_layout.service_title': 'Product Service',\n 'products.app_layout.footer_copyright':\n '2024 SMRT Product Service - Auto-generated with ❤️',\n 'products.app_layout.api_docs': 'API Docs',\n 'products.app_layout.mcp_tools': 'MCP Tools',\n\n // DemoPage\n 'products.demo_page.title': 'SMRT Framework Demo',\n 'products.demo_page.subtitle':\n 'Define Once, Consume Everywhere - Progressive Customization',\n 'products.demo_page.custom_components_tab': 'Custom Components',\n 'products.demo_page.auto_generated_heading':\n 'Auto-Generated UI from SMRT Object',\n 'products.demo_page.auto_generated_description':\n 'This form is automatically generated from the Product class definition.\\n The field types, labels, and validation rules are inferred from the TypeScript schema.',\n 'products.demo_page.generated_form_heading': 'Generated Form',\n 'products.demo_page.auto_form_title': 'Auto-Generated Product Form',\n 'products.demo_page.generated_display_heading': 'Generated Display',\n 'products.demo_page.custom_components_heading':\n 'Custom Components with SMRT Integration',\n 'products.demo_page.custom_components_description':\n 'These are hand-crafted components that still leverage the SMRT data structure\\n but provide custom UI/UX for specific business requirements.',\n 'products.demo_page.custom_form_heading': 'Custom Form',\n 'products.demo_page.custom_display_heading': 'Custom Display',\n 'products.demo_page.progressive_heading': 'Progressive Customization',\n 'products.demo_page.progressive_description':\n 'Start with auto-generated components, then progressively customize as needed.\\n Both approaches use the same underlying SMRT Product model.',\n 'products.demo_page.feature_zero_config': '✅ Zero configuration',\n 'products.demo_page.feature_instant_ui': '✅ Instant UI from schema',\n 'products.demo_page.feature_type_safe': '✅ Type-safe by default',\n 'products.demo_page.feature_prototyping': '⚡ Perfect for prototyping',\n 'products.demo_page.custom_components_label': '🎨 Custom Components',\n 'products.demo_page.feature_tailored_ux': '✅ Tailored UX',\n 'products.demo_page.feature_business_workflows':\n '✅ Business-specific workflows',\n 'products.demo_page.feature_advanced_interactions':\n '✅ Advanced interactions',\n 'products.demo_page.simple_auto_form_title': 'Auto Form',\n 'products.demo_page.benefits_heading': 'SMRT Framework Benefits',\n 'products.demo_page.benefit_define_once_label': 'Define Once:',\n 'products.demo_page.benefit_define_once_text':\n 'Product class with @smrt decorator',\n 'products.demo_page.benefit_auto_generate_label': 'Auto-Generate:',\n 'products.demo_page.benefit_auto_generate_text':\n 'REST APIs, MCP tools, TypeScript clients, default UI',\n 'products.demo_page.benefit_progressive_label': 'Progressive Enhancement:',\n 'products.demo_page.benefit_progressive_text':\n 'Start with defaults, customize as needed',\n 'products.demo_page.benefit_type_safety_label': 'Type Safety:',\n 'products.demo_page.benefit_type_safety_text':\n 'End-to-end TypeScript integration',\n 'products.demo_page.benefit_multiple_consumption_label':\n 'Multiple Consumption:',\n 'products.demo_page.benefit_multiple_consumption_text':\n 'Library, federation, standalone',\n\n // ProductsPage\n 'products.products_page.description':\n 'Manage your product catalog with auto-generated CRUD operations, \\n real-time updates, and AI-powered tools via MCP.',\n 'products.products_page.auto_generated_text':\n 'REST API endpoints automatically created from @smrt() decorated Product class',\n 'products.products_page.ai_ready_heading': '🤖 AI Ready',\n 'products.products_page.ai_ready_text':\n 'MCP tools available for Claude and other AI models to interact with products',\n 'products.products_page.federatable_text':\n 'Components can be consumed by other applications via module federation',\n 'products.products_page.library_text':\n 'Install as NPM package: npm install @have/smrt-template',\n\n // ProductForm\n 'products.product_form.name_label': 'Product Name *',\n 'products.product_form.name_placeholder': 'Enter product name',\n 'products.product_form.description_placeholder':\n 'Product description (optional)',\n 'products.product_form.category_placeholder': 'Product category',\n 'products.product_form.tags_placeholder': 'tag1, tag2, tag3',\n 'products.product_form.tags_hint': 'Separate tags with commas',\n 'products.product_form.in_stock_label': 'In Stock',\n\n // TestComponent\n 'products.test_component.title': 'Test Component',\n\n // AutoForm\n 'products.auto_form.subtitle': 'Auto-generated from SMRT Product model',\n 'products.auto_form.debug_summary': 'Form Data (Debug)',\n\n // FieldRenderer\n 'products.field_renderer.array_hint': 'Enter values separated by commas',\n 'products.field_renderer.object_hint': 'Enter valid JSON',\n\n // CategoryManager\n 'products.category_manager.title': 'Category Manager',\n 'products.category_manager.subtitle': 'Manage product categories',\n 'products.category_manager.coming_soon':\n 'Category management feature coming soon...',\n 'products.category_manager.will_include': 'This will include:',\n 'products.category_manager.create_edit': 'Create and edit categories',\n 'products.category_manager.organize_hierarchy': 'Organize category hierarchy',\n 'products.category_manager.manage_permissions': 'Manage category permissions',\n 'products.category_manager.analytics': 'Category analytics',\n\n // ProductCatalog\n 'products.product_catalog.title': 'Product Catalog',\n 'products.product_catalog.in_stock': 'in stock',\n 'products.product_catalog.total_value': 'Total value:',\n 'products.product_catalog.search_placeholder': 'Search products...',\n 'products.product_catalog.all_categories': 'All Categories',\n 'products.product_catalog.add_product': 'Add Product',\n 'products.product_catalog.loading': 'Loading products...',\n 'products.product_catalog.empty':\n 'No products yet. Create your first product to get started!',\n 'products.product_catalog.create_first': 'Create First Product',\n 'products.product_catalog.no_match':\n 'No products match your search criteria.',\n});\n","<script lang=\"ts\">\nimport { useI18n } from '@happyvertical/smrt-ui/i18n';\nimport { Button } from '@happyvertical/smrt-ui/ui';\nimport { M } from '../i18n.js';\nimport type { ProductData } from '../types';\n\nconst { t } = useI18n();\n\ninterface Props {\n product?: Partial<ProductData>;\n onSubmit: (product: Partial<ProductData>) => void;\n onCancel?: () => void;\n loading?: boolean;\n}\n\nconst { product = {}, onSubmit, onCancel, loading = false }: Props = $props();\n\nconst formData = $state({\n name: product.name || '',\n description: product.description || '',\n price: product.price || 0,\n inStock: product.inStock ?? true,\n category: product.category || '',\n tags: product.tags?.join(', ') || '',\n});\n\nlet errors = $state<Record<string, string>>({});\n\nfunction validateForm() {\n errors = {};\n\n if (!formData.name.trim()) {\n errors.name = 'Product name is required';\n }\n\n if (formData.price < 0) {\n errors.price = 'Price must be non-negative';\n }\n\n return Object.keys(errors).length === 0;\n}\n\nfunction handleSubmit(event: Event) {\n event.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n const productData: Partial<ProductData> = {\n ...product,\n name: formData.name.trim(),\n description: formData.description.trim() || undefined,\n price: formData.price,\n inStock: formData.inStock,\n category: formData.category.trim(),\n tags: formData.tags\n ? formData.tags\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean)\n : [],\n };\n\n onSubmit(productData);\n}\n</script>\n\n<form onsubmit={handleSubmit} class=\"product-form\">\n <div class=\"form-group\">\n <label for=\"name\">{t(M['products.product_form.name_label'])}</label>\n <input\n id=\"name\"\n type=\"text\"\n bind:value={formData.name}\n disabled={loading}\n class=\"form-input\"\n class:error={errors.name}\n placeholder={t(M['products.product_form.name_placeholder'])}\n />\n {#if errors.name}\n <span class=\"error-message\">{errors.name}</span>\n {/if}\n </div>\n\n <div class=\"form-group\">\n <label for=\"description\">Description</label>\n <textarea\n id=\"description\"\n bind:value={formData.description}\n disabled={loading}\n class=\"form-textarea\"\n placeholder={t(M['products.product_form.description_placeholder'])}\n rows=\"3\"\n ></textarea>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"price\">Price *</label>\n <input\n id=\"price\"\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n bind:value={formData.price}\n disabled={loading}\n class=\"form-input\"\n class:error={errors.price}\n placeholder=\"0.00\"\n />\n {#if errors.price}\n <span class=\"error-message\">{errors.price}</span>\n {/if}\n </div>\n\n <div class=\"form-group\">\n <label for=\"category\">Category</label>\n <input\n id=\"category\"\n type=\"text\"\n bind:value={formData.category}\n disabled={loading}\n class=\"form-input\"\n placeholder={t(M['products.product_form.category_placeholder'])}\n />\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"tags\">Tags</label>\n <input\n id=\"tags\"\n type=\"text\"\n bind:value={formData.tags}\n disabled={loading}\n class=\"form-input\"\n placeholder={t(M['products.product_form.tags_placeholder'])}\n />\n <small class=\"form-hint\">{t(M['products.product_form.tags_hint'])}</small>\n </div>\n\n <div class=\"form-group\">\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n bind:checked={formData.inStock}\n disabled={loading}\n class=\"form-checkbox\"\n />\n {t(M['products.product_form.in_stock_label'])}\n </label>\n </div>\n\n <div class=\"form-actions\">\n {#if onCancel}\n <Button type=\"button\" variant=\"secondary\" onclick={onCancel} disabled={loading}>\n Cancel\n </Button>\n {/if}\n\n <Button type=\"submit\" variant=\"primary\" disabled={loading}>\n {#if loading}\n Saving...\n {:else}\n {product.id ? 'Update Product' : 'Create Product'}\n {/if}\n </Button>\n </div>\n</form>\n\n<style>\n .product-form {\n max-width: 500px;\n padding: 1.5rem;\n background: var(--smrt-color-surface, #fff);\n border-radius: var(--smrt-radius-md, 8px);\n border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);\n }\n \n .form-group {\n margin-bottom: 1rem;\n }\n \n .form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1rem;\n }\n \n label {\n display: block;\n margin-bottom: 0.25rem;\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface, #374151);\n font-size: var(--smrt-typography-label-large-size, 0.875rem);\n }\n\n .form-input, .form-textarea {\n width: 100%;\n padding: 0.5rem;\n border: 1px solid var(--smrt-color-outline-variant, #d1d5db);\n border-radius: var(--smrt-radius-sm, 4px);\n font-size: var(--smrt-typography-body-medium-size, 0.875rem);\n transition: border-color 0.2s;\n }\n\n .form-input:focus, .form-textarea:focus {\n outline: none;\n border-color: var(--smrt-color-primary, #3b82f6);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);\n }\n\n .form-input.error {\n border-color: var(--smrt-color-error, #dc2626);\n }\n \n .form-textarea {\n resize: vertical;\n min-height: 80px;\n }\n \n .checkbox-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n }\n \n .form-checkbox {\n width: auto;\n }\n \n .form-hint {\n color: var(--smrt-color-on-surface-variant, #6b7280);\n font-size: var(--smrt-typography-body-small-size, 0.75rem);\n margin-top: 0.25rem;\n }\n\n .error-message {\n color: var(--smrt-color-error, #dc2626);\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n margin-top: 0.25rem;\n display: block;\n }\n\n .form-actions {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-top: 1.5rem;\n padding-top: 1rem;\n border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);\n }\n</style>"],"names":["root","root_1","root_2","$$anchor"],"mappings":"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"}
1
+ {"version":3,"file":"ProductForm-BLRguem5.js","sources":["../../../src/lib/components/ProductCard.svelte","../../../src/lib/i18n.ts","../../../src/lib/components/ProductForm.svelte"],"sourcesContent":["<script lang=\"ts\">\nimport { Button } from '@happyvertical/smrt-ui/ui';\nimport type { ProductData } from '../types';\n\ninterface Props {\n product: ProductData;\n onEdit?: (product: ProductData) => void;\n onDelete?: (id: string) => void;\n}\n\nconst { product, onEdit, onDelete }: Props = $props();\n</script>\n\n<div class=\"product-card\">\n <div class=\"product-header\">\n <h3 class=\"product-name\">{product.name}</h3>\n {#if product.manufacturer}\n <div class=\"product-manufacturer\">{product.manufacturer}</div>\n {/if}\n </div>\n\n {#if product.model}\n <div class=\"product-model\">Model: {product.model}</div>\n {/if}\n\n {#if product.description}\n <p class=\"product-description\">{product.description}</p>\n {/if}\n\n <div class=\"product-meta\">\n {#if product.category}\n <div class=\"product-category\">Category: {product.category}</div>\n {/if}\n \n {#if product.tags && product.tags.length > 0}\n <div class=\"product-tags\">\n {#each product.tags as tag}\n <span class=\"tag\">{tag}</span>\n {/each}\n </div>\n {/if}\n </div>\n \n <div class=\"product-actions\">\n {#if onEdit}\n <Button type=\"button\" variant=\"secondary\" size=\"sm\" onclick={() => onEdit?.(product)}>\n Edit\n </Button>\n {/if}\n\n {#if onDelete}\n <Button type=\"button\" variant=\"danger\" size=\"sm\" onclick={() => onDelete?.(product.id)}>\n Delete\n </Button>\n {/if}\n </div>\n</div>\n\n<style>\n .product-card {\n border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);\n border-radius: var(--smrt-radius-md, 8px);\n padding: 1rem;\n background: var(--smrt-color-surface, #fff);\n box-shadow: var(--smrt-elevation-1, 0 1px 3px color-mix(in srgb, var(--smrt-color-shadow, #000) 10%, transparent));\n transition: box-shadow 0.2s;\n }\n\n .product-card:hover {\n box-shadow: var(--smrt-elevation-2, 0 4px 6px color-mix(in srgb, var(--smrt-color-shadow, #000) 10%, transparent));\n }\n \n .product-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.5rem;\n }\n \n .product-name {\n margin: 0;\n font-size: var(--smrt-typography-title-medium-size, 1.125rem);\n font-weight: var(--smrt-typography-weight-semibold, 600);\n color: var(--smrt-color-on-surface, #1f2937);\n }\n\n .product-manufacturer {\n font-size: var(--smrt-typography-title-small-size, 0.875rem);\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface-variant, #6b7280);\n }\n\n .product-model {\n font-size: var(--smrt-typography-body-medium-size, 0.875rem);\n color: var(--smrt-color-on-surface-variant, #6b7280);\n margin-bottom: 0.5rem;\n }\n\n .product-category {\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface, #374151);\n background: var(--smrt-color-surface-container, #f3f4f6);\n padding: 0.25rem 0.5rem;\n border-radius: var(--smrt-radius-sm, 4px);\n display: inline-block;\n margin-bottom: 0.5rem;\n }\n \n .product-description {\n margin: 0.5rem 0;\n color: var(--smrt-color-on-surface-variant, #6b7280);\n font-size: var(--smrt-typography-body-medium-size, 0.875rem);\n line-height: var(--smrt-typography-body-medium-line-height, 1.4);\n }\n \n .product-meta {\n margin: 0.75rem 0;\n }\n \n \n .product-tags {\n margin-top: 0.5rem;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n }\n \n .tag {\n background: var(--smrt-color-surface-container, #f3f4f6);\n color: var(--smrt-color-on-surface, #374151);\n padding: 0.125rem 0.5rem;\n border-radius: var(--smrt-radius-full, 9999px);\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n }\n\n .product-actions {\n display: flex;\n gap: 0.5rem;\n margin-top: 1rem;\n padding-top: 0.75rem;\n border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);\n }\n</style>","import { defineMessages } from '@happyvertical/smrt-ui/i18n';\n\nexport const M = defineMessages({\n // App\n 'products.app.categories_coming_soon': 'Category management coming soon...',\n 'products.app.analytics_coming_soon': 'Analytics dashboard coming soon...',\n\n // AppLayout\n 'products.app_layout.service_title': 'Product Service',\n 'products.app_layout.footer_copyright':\n '2024 SMRT Product Service - Auto-generated with ❤️',\n 'products.app_layout.api_docs': 'API Docs',\n 'products.app_layout.mcp_tools': 'MCP Tools',\n\n // DemoPage\n 'products.demo_page.title': 'SMRT Framework Demo',\n 'products.demo_page.subtitle':\n 'Define Once, Consume Everywhere - Progressive Customization',\n 'products.demo_page.custom_components_tab': 'Custom Components',\n 'products.demo_page.auto_generated_heading':\n 'Auto-Generated UI from SMRT Object',\n 'products.demo_page.auto_generated_description':\n 'This form is automatically generated from the Product class definition.\\n The field types, labels, and validation rules are inferred from the TypeScript schema.',\n 'products.demo_page.generated_form_heading': 'Generated Form',\n 'products.demo_page.auto_form_title': 'Auto-Generated Product Form',\n 'products.demo_page.generated_display_heading': 'Generated Display',\n 'products.demo_page.custom_components_heading':\n 'Custom Components with SMRT Integration',\n 'products.demo_page.custom_components_description':\n 'These are hand-crafted components that still leverage the SMRT data structure\\n but provide custom UI/UX for specific business requirements.',\n 'products.demo_page.custom_form_heading': 'Custom Form',\n 'products.demo_page.custom_display_heading': 'Custom Display',\n 'products.demo_page.progressive_heading': 'Progressive Customization',\n 'products.demo_page.progressive_description':\n 'Start with auto-generated components, then progressively customize as needed.\\n Both approaches use the same underlying SMRT Product model.',\n 'products.demo_page.feature_zero_config': '✅ Zero configuration',\n 'products.demo_page.feature_instant_ui': '✅ Instant UI from schema',\n 'products.demo_page.feature_type_safe': '✅ Type-safe by default',\n 'products.demo_page.feature_prototyping': '⚡ Perfect for prototyping',\n 'products.demo_page.custom_components_label': '🎨 Custom Components',\n 'products.demo_page.feature_tailored_ux': '✅ Tailored UX',\n 'products.demo_page.feature_business_workflows':\n '✅ Business-specific workflows',\n 'products.demo_page.feature_advanced_interactions':\n '✅ Advanced interactions',\n 'products.demo_page.simple_auto_form_title': 'Auto Form',\n 'products.demo_page.benefits_heading': 'SMRT Framework Benefits',\n 'products.demo_page.benefit_define_once_label': 'Define Once:',\n 'products.demo_page.benefit_define_once_text':\n 'Product class with @smrt decorator',\n 'products.demo_page.benefit_auto_generate_label': 'Auto-Generate:',\n 'products.demo_page.benefit_auto_generate_text':\n 'REST APIs, MCP tools, TypeScript clients, default UI',\n 'products.demo_page.benefit_progressive_label': 'Progressive Enhancement:',\n 'products.demo_page.benefit_progressive_text':\n 'Start with defaults, customize as needed',\n 'products.demo_page.benefit_type_safety_label': 'Type Safety:',\n 'products.demo_page.benefit_type_safety_text':\n 'End-to-end TypeScript integration',\n 'products.demo_page.benefit_multiple_consumption_label':\n 'Multiple Consumption:',\n 'products.demo_page.benefit_multiple_consumption_text':\n 'Library, federation, standalone',\n\n // ProductsPage\n 'products.products_page.description':\n 'Manage your product catalog with auto-generated CRUD operations, \\n real-time updates, and AI-powered tools via MCP.',\n 'products.products_page.auto_generated_text':\n 'REST API endpoints automatically created from @smrt() decorated Product class',\n 'products.products_page.ai_ready_heading': '🤖 AI Ready',\n 'products.products_page.ai_ready_text':\n 'MCP tools available for Claude and other AI models to interact with products',\n 'products.products_page.federatable_text':\n 'Components can be consumed by other applications via module federation',\n 'products.products_page.library_text':\n 'Install as NPM package: npm install @have/smrt-template',\n\n // ProductForm\n 'products.product_form.name_label': 'Product Name *',\n 'products.product_form.name_placeholder': 'Enter product name',\n 'products.product_form.description_placeholder':\n 'Product description (optional)',\n 'products.product_form.category_placeholder': 'Product category',\n 'products.product_form.tags_placeholder': 'tag1, tag2, tag3',\n 'products.product_form.tags_hint': 'Separate tags with commas',\n 'products.product_form.in_stock_label': 'In Stock',\n\n // TestComponent\n 'products.test_component.title': 'Test Component',\n\n // AutoForm\n 'products.auto_form.subtitle': 'Auto-generated from SMRT Product model',\n 'products.auto_form.debug_summary': 'Form Data (Debug)',\n\n // FieldRenderer\n 'products.field_renderer.array_hint': 'Enter values separated by commas',\n 'products.field_renderer.object_hint': 'Enter valid JSON',\n\n // CategoryManager\n 'products.category_manager.title': 'Category Manager',\n 'products.category_manager.subtitle': 'Manage product categories',\n 'products.category_manager.coming_soon':\n 'Category management feature coming soon...',\n 'products.category_manager.will_include': 'This will include:',\n 'products.category_manager.create_edit': 'Create and edit categories',\n 'products.category_manager.organize_hierarchy': 'Organize category hierarchy',\n 'products.category_manager.manage_permissions': 'Manage category permissions',\n 'products.category_manager.analytics': 'Category analytics',\n\n // ProductCatalog\n 'products.product_catalog.title': 'Product Catalog',\n 'products.product_catalog.in_stock': 'in stock',\n 'products.product_catalog.total_value': 'Total value:',\n 'products.product_catalog.search_placeholder': 'Search products...',\n 'products.product_catalog.all_categories': 'All Categories',\n 'products.product_catalog.add_product': 'Add Product',\n 'products.product_catalog.loading': 'Loading products...',\n 'products.product_catalog.empty':\n 'No products yet. Create your first product to get started!',\n 'products.product_catalog.create_first': 'Create First Product',\n 'products.product_catalog.no_match':\n 'No products match your search criteria.',\n});\n","<script lang=\"ts\">\nimport { Form, Input, Textarea } from '@happyvertical/smrt-ui/forms';\nimport { useI18n } from '@happyvertical/smrt-ui/i18n';\nimport { Button } from '@happyvertical/smrt-ui/ui';\nimport { M } from '../i18n.js';\nimport type { ProductData } from '../types';\n\nconst { t } = useI18n();\n\ninterface Props {\n product?: Partial<ProductData>;\n onSubmit: (product: Partial<ProductData>) => void;\n onCancel?: () => void;\n loading?: boolean;\n}\n\nconst { product = {}, onSubmit, onCancel, loading = false }: Props = $props();\n\nconst formData = $state({\n name: product.name || '',\n description: product.description || '',\n price: product.price || 0,\n inStock: product.inStock ?? true,\n category: product.category || '',\n tags: product.tags?.join(', ') || '',\n});\n\nlet errors = $state<Record<string, string>>({});\n\nfunction validateForm() {\n errors = {};\n\n if (!formData.name.trim()) {\n errors.name = 'Product name is required';\n }\n\n if (formData.price < 0) {\n errors.price = 'Price must be non-negative';\n }\n\n return Object.keys(errors).length === 0;\n}\n\nfunction handleSubmit(event: Event) {\n event.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n const productData: Partial<ProductData> = {\n ...product,\n name: formData.name.trim(),\n description: formData.description.trim() || undefined,\n price: formData.price,\n inStock: formData.inStock,\n category: formData.category.trim(),\n tags: formData.tags\n ? formData.tags\n .split(',')\n .map((tag) => tag.trim())\n .filter(Boolean)\n : [],\n };\n\n onSubmit(productData);\n}\n</script>\n\n<div class=\"product-form-shell\">\n <Form onsubmit={handleSubmit} class=\"product-form\">\n <div class=\"form-group\">\n <label for=\"name\">{t(M['products.product_form.name_label'])}</label>\n <Input\n id=\"name\"\n type=\"text\"\n bind:value={formData.name}\n disabled={loading}\n class={errors.name ? 'error' : ''}\n placeholder={t(M['products.product_form.name_placeholder'])}\n />\n {#if errors.name}\n <span class=\"error-message\">{errors.name}</span>\n {/if}\n </div>\n\n <div class=\"form-group\">\n <label for=\"description\">Description</label>\n <Textarea\n id=\"description\"\n bind:value={formData.description}\n disabled={loading}\n placeholder={t(M['products.product_form.description_placeholder'])}\n rows={3}\n ></Textarea>\n </div>\n\n <div class=\"form-row\">\n <div class=\"form-group\">\n <label for=\"price\">Price *</label>\n <Input\n id=\"price\"\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n bind:value={formData.price}\n disabled={loading}\n class={errors.price ? 'error' : ''}\n placeholder=\"0.00\"\n />\n {#if errors.price}\n <span class=\"error-message\">{errors.price}</span>\n {/if}\n </div>\n\n <div class=\"form-group\">\n <label for=\"category\">Category</label>\n <Input\n id=\"category\"\n type=\"text\"\n bind:value={formData.category}\n disabled={loading}\n placeholder={t(M['products.product_form.category_placeholder'])}\n />\n </div>\n </div>\n\n <div class=\"form-group\">\n <label for=\"tags\">Tags</label>\n <Input\n id=\"tags\"\n type=\"text\"\n bind:value={formData.tags}\n disabled={loading}\n placeholder={t(M['products.product_form.tags_placeholder'])}\n />\n <small class=\"form-hint\">{t(M['products.product_form.tags_hint'])}</small>\n </div>\n\n <div class=\"form-group\">\n <label class=\"checkbox-label\">\n <!-- raw-primitive-allow: native checkbox; no Provider-free checkbox primitive (Toggle is a switch with different semantics, CheckboxInput requires a Provider) -->\n <input\n type=\"checkbox\"\n bind:checked={formData.inStock}\n disabled={loading}\n class=\"form-checkbox\"\n />\n {t(M['products.product_form.in_stock_label'])}\n </label>\n </div>\n\n <div class=\"form-actions\">\n {#if onCancel}\n <Button type=\"button\" variant=\"secondary\" onclick={onCancel} disabled={loading}>\n Cancel\n </Button>\n {/if}\n\n <Button type=\"submit\" variant=\"primary\" disabled={loading}>\n {#if loading}\n Saving...\n {:else}\n {product.id ? 'Update Product' : 'Create Product'}\n {/if}\n </Button>\n </div>\n </Form>\n</div>\n\n<style>\n .product-form-shell :global(.product-form) {\n max-width: 500px;\n padding: 1.5rem;\n background: var(--smrt-color-surface, #fff);\n border-radius: var(--smrt-radius-md, 8px);\n border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);\n }\n\n .form-group {\n margin-bottom: 1rem;\n }\n\n .form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 1rem;\n }\n\n label {\n display: block;\n margin-bottom: 0.25rem;\n font-weight: var(--smrt-typography-weight-medium, 500);\n color: var(--smrt-color-on-surface, #374151);\n font-size: var(--smrt-typography-label-large-size, 0.875rem);\n }\n\n /* Error border on the migrated <Input>. The primitive renders the inner\n <input class=\"input error\"> inside its own component, so the scoped class\n can't reach it without :global (#1589). */\n .product-form-shell :global(.input.error) {\n border-color: var(--smrt-color-error, #dc2626);\n }\n\n .checkbox-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n }\n \n .form-checkbox {\n width: auto;\n }\n \n .form-hint {\n color: var(--smrt-color-on-surface-variant, #6b7280);\n font-size: var(--smrt-typography-body-small-size, 0.75rem);\n margin-top: 0.25rem;\n }\n\n .error-message {\n color: var(--smrt-color-error, #dc2626);\n font-size: var(--smrt-typography-label-medium-size, 0.75rem);\n margin-top: 0.25rem;\n display: block;\n }\n\n .form-actions {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-top: 1.5rem;\n padding-top: 1rem;\n border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);\n }\n</style>"],"names":["root","root_1","root_2","root_3","$$anchor"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { P, a } from "./chunks/ProductForm-CukMCDEN.js";
1
+ import { P, a } from "./chunks/ProductForm-BLRguem5.js";
2
2
  export {
3
3
  P as ProductCard,
4
4
  a as ProductForm
package/dist/lib/index.js CHANGED
@@ -6,7 +6,7 @@ import { default as default3 } from "@smrt/mcp";
6
6
  import { default as default4 } from "@smrt/routes";
7
7
  import { C, M, P, a, S } from "./chunks/SkuCollection-f_a3k93c.js";
8
8
  import { ProductAssetCollection } from "./chunks/ProductAssetCollection-B93HdSlX.js";
9
- import { P as P2, a as a2 } from "./chunks/ProductForm-CukMCDEN.js";
9
+ import { P as P2, a as a2 } from "./chunks/ProductForm-BLRguem5.js";
10
10
  import { a as a3 } from "./chunks/index-i3-ci1FB.js";
11
11
  import { P as Product, C as Category } from "./chunks/Sku-sl6xf1PR.js";
12
12
  import { M as M2, a as a4, b, c, S as S2 } from "./chunks/Sku-sl6xf1PR.js";
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { Form, Input, Textarea } from '@happyvertical/smrt-ui/forms';
2
3
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
4
  import { Button } from '@happyvertical/smrt-ui/ui';
4
5
  import { M } from '../i18n.js';
@@ -66,128 +67,126 @@ function handleSubmit(event: Event) {
66
67
  }
67
68
  </script>
68
69
 
69
- <form onsubmit={handleSubmit} class="product-form">
70
- <div class="form-group">
71
- <label for="name">{t(M['products.product_form.name_label'])}</label>
72
- <input
73
- id="name"
74
- type="text"
75
- bind:value={formData.name}
76
- disabled={loading}
77
- class="form-input"
78
- class:error={errors.name}
79
- placeholder={t(M['products.product_form.name_placeholder'])}
80
- />
81
- {#if errors.name}
82
- <span class="error-message">{errors.name}</span>
83
- {/if}
84
- </div>
85
-
86
- <div class="form-group">
87
- <label for="description">Description</label>
88
- <textarea
89
- id="description"
90
- bind:value={formData.description}
91
- disabled={loading}
92
- class="form-textarea"
93
- placeholder={t(M['products.product_form.description_placeholder'])}
94
- rows="3"
95
- ></textarea>
96
- </div>
97
-
98
- <div class="form-row">
70
+ <div class="product-form-shell">
71
+ <Form onsubmit={handleSubmit} class="product-form">
99
72
  <div class="form-group">
100
- <label for="price">Price *</label>
101
- <input
102
- id="price"
103
- type="number"
104
- step="0.01"
105
- min="0"
106
- bind:value={formData.price}
73
+ <label for="name">{t(M['products.product_form.name_label'])}</label>
74
+ <Input
75
+ id="name"
76
+ type="text"
77
+ bind:value={formData.name}
107
78
  disabled={loading}
108
- class="form-input"
109
- class:error={errors.price}
110
- placeholder="0.00"
79
+ class={errors.name ? 'error' : ''}
80
+ placeholder={t(M['products.product_form.name_placeholder'])}
111
81
  />
112
- {#if errors.price}
113
- <span class="error-message">{errors.price}</span>
82
+ {#if errors.name}
83
+ <span class="error-message">{errors.name}</span>
114
84
  {/if}
115
85
  </div>
116
86
 
117
87
  <div class="form-group">
118
- <label for="category">Category</label>
119
- <input
120
- id="category"
121
- type="text"
122
- bind:value={formData.category}
88
+ <label for="description">Description</label>
89
+ <Textarea
90
+ id="description"
91
+ bind:value={formData.description}
123
92
  disabled={loading}
124
- class="form-input"
125
- placeholder={t(M['products.product_form.category_placeholder'])}
126
- />
93
+ placeholder={t(M['products.product_form.description_placeholder'])}
94
+ rows={3}
95
+ ></Textarea>
96
+ </div>
97
+
98
+ <div class="form-row">
99
+ <div class="form-group">
100
+ <label for="price">Price *</label>
101
+ <Input
102
+ id="price"
103
+ type="number"
104
+ step="0.01"
105
+ min="0"
106
+ bind:value={formData.price}
107
+ disabled={loading}
108
+ class={errors.price ? 'error' : ''}
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
+ placeholder={t(M['products.product_form.category_placeholder'])}
124
+ />
125
+ </div>
127
126
  </div>
128
- </div>
129
-
130
- <div class="form-group">
131
- <label for="tags">Tags</label>
132
- <input
133
- id="tags"
134
- type="text"
135
- bind:value={formData.tags}
136
- disabled={loading}
137
- class="form-input"
138
- placeholder={t(M['products.product_form.tags_placeholder'])}
139
- />
140
- <small class="form-hint">{t(M['products.product_form.tags_hint'])}</small>
141
- </div>
142
-
143
- <div class="form-group">
144
- <label class="checkbox-label">
145
- <input
146
- type="checkbox"
147
- bind:checked={formData.inStock}
127
+
128
+ <div class="form-group">
129
+ <label for="tags">Tags</label>
130
+ <Input
131
+ id="tags"
132
+ type="text"
133
+ bind:value={formData.tags}
148
134
  disabled={loading}
149
- class="form-checkbox"
135
+ placeholder={t(M['products.product_form.tags_placeholder'])}
150
136
  />
151
- {t(M['products.product_form.in_stock_label'])}
152
- </label>
153
- </div>
154
-
155
- <div class="form-actions">
156
- {#if onCancel}
157
- <Button type="button" variant="secondary" onclick={onCancel} disabled={loading}>
158
- Cancel
159
- </Button>
160
- {/if}
137
+ <small class="form-hint">{t(M['products.product_form.tags_hint'])}</small>
138
+ </div>
161
139
 
162
- <Button type="submit" variant="primary" disabled={loading}>
163
- {#if loading}
164
- Saving...
165
- {:else}
166
- {product.id ? 'Update Product' : 'Create Product'}
140
+ <div class="form-group">
141
+ <label class="checkbox-label">
142
+ <!-- raw-primitive-allow: native checkbox; no Provider-free checkbox primitive (Toggle is a switch with different semantics, CheckboxInput requires a Provider) -->
143
+ <input
144
+ type="checkbox"
145
+ bind:checked={formData.inStock}
146
+ disabled={loading}
147
+ class="form-checkbox"
148
+ />
149
+ {t(M['products.product_form.in_stock_label'])}
150
+ </label>
151
+ </div>
152
+
153
+ <div class="form-actions">
154
+ {#if onCancel}
155
+ <Button type="button" variant="secondary" onclick={onCancel} disabled={loading}>
156
+ Cancel
157
+ </Button>
167
158
  {/if}
168
- </Button>
169
- </div>
170
- </form>
159
+
160
+ <Button type="submit" variant="primary" disabled={loading}>
161
+ {#if loading}
162
+ Saving...
163
+ {:else}
164
+ {product.id ? 'Update Product' : 'Create Product'}
165
+ {/if}
166
+ </Button>
167
+ </div>
168
+ </Form>
169
+ </div>
171
170
 
172
171
  <style>
173
- .product-form {
172
+ .product-form-shell :global(.product-form) {
174
173
  max-width: 500px;
175
174
  padding: 1.5rem;
176
175
  background: var(--smrt-color-surface, #fff);
177
176
  border-radius: var(--smrt-radius-md, 8px);
178
177
  border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);
179
178
  }
180
-
179
+
181
180
  .form-group {
182
181
  margin-bottom: 1rem;
183
182
  }
184
-
183
+
185
184
  .form-row {
186
185
  display: grid;
187
186
  grid-template-columns: 1fr 1fr;
188
187
  gap: 1rem;
189
188
  }
190
-
189
+
191
190
  label {
192
191
  display: block;
193
192
  margin-bottom: 0.25rem;
@@ -196,30 +195,13 @@ function handleSubmit(event: Event) {
196
195
  font-size: var(--smrt-typography-label-large-size, 0.875rem);
197
196
  }
198
197
 
199
- .form-input, .form-textarea {
200
- width: 100%;
201
- padding: 0.5rem;
202
- border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
203
- border-radius: var(--smrt-radius-sm, 4px);
204
- font-size: var(--smrt-typography-body-medium-size, 0.875rem);
205
- transition: border-color 0.2s;
206
- }
207
-
208
- .form-input:focus, .form-textarea:focus {
209
- outline: none;
210
- border-color: var(--smrt-color-primary, #3b82f6);
211
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);
212
- }
213
-
214
- .form-input.error {
198
+ /* Error border on the migrated <Input>. The primitive renders the inner
199
+ <input class="input error"> inside its own component, so the scoped class
200
+ can't reach it without :global (#1589). */
201
+ .product-form-shell :global(.input.error) {
215
202
  border-color: var(--smrt-color-error, #dc2626);
216
203
  }
217
-
218
- .form-textarea {
219
- resize: vertical;
220
- min-height: 80px;
221
- }
222
-
204
+
223
205
  .checkbox-label {
224
206
  display: flex;
225
207
  align-items: center;
@@ -1 +1 @@
1
- {"version":3,"file":"ProductForm.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/ProductForm.svelte"],"names":[],"mappings":"AAMA,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;AA2HD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"ProductForm.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/ProductForm.svelte"],"names":[],"mappings":"AAOA,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;AA+HD,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -4,6 +4,7 @@
4
4
  * Demonstrates "Define Once, Consume Everywhere" - form is generated from Product class definition
5
5
  */
6
6
 
7
+ import { Form } from '@happyvertical/smrt-ui/forms';
7
8
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
9
  import { Button } from '@happyvertical/smrt-ui/ui';
9
10
  import { M } from '../../i18n.js';
@@ -113,31 +114,33 @@ function _getFieldType(
113
114
  </div>
114
115
  </header>
115
116
 
116
- <form class="form-content" onsubmit={handleSubmit}>
117
- {#each fieldSchema as field}
118
- <FieldRenderer
119
- fieldName={field.name}
120
- fieldType={field.type}
121
- value={formData[field.name]}
122
- label={field.label}
123
- placeholder={field.placeholder}
124
- required={field.required || false}
125
- {readonly}
126
- onUpdate={(value) => updateField(field.name, value)}
127
- />
128
- {/each}
129
-
130
- {#if !readonly}
131
- <div class="form-actions">
132
- <Button type="submit" variant="primary">
133
- {submitLabel}
134
- </Button>
135
- <Button type="button" variant="secondary" onclick={() => formData = {}}>
136
- Reset
137
- </Button>
138
- </div>
139
- {/if}
140
- </form>
117
+ <div class="form-content-shell">
118
+ <Form class="form-content" onsubmit={handleSubmit}>
119
+ {#each fieldSchema as field}
120
+ <FieldRenderer
121
+ fieldName={field.name}
122
+ fieldType={field.type}
123
+ value={formData[field.name]}
124
+ label={field.label}
125
+ placeholder={field.placeholder}
126
+ required={field.required || false}
127
+ {readonly}
128
+ onUpdate={(value) => updateField(field.name, value)}
129
+ />
130
+ {/each}
131
+
132
+ {#if !readonly}
133
+ <div class="form-actions">
134
+ <Button type="submit" variant="primary">
135
+ {submitLabel}
136
+ </Button>
137
+ <Button type="button" variant="secondary" onclick={() => formData = {}}>
138
+ Reset
139
+ </Button>
140
+ </div>
141
+ {/if}
142
+ </Form>
143
+ </div>
141
144
 
142
145
  <!-- Demo: Show current form state -->
143
146
  <details class="form-debug">
@@ -174,7 +177,7 @@ function _getFieldType(
174
177
  font-style: italic;
175
178
  }
176
179
 
177
- .form-content {
180
+ .form-content-shell :global(.form-content) {
178
181
  display: flex;
179
182
  flex-direction: column;
180
183
  gap: 1rem;
@@ -1 +1 @@
1
- {"version":3,"file":"AutoForm.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/AutoForm.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/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;AAoID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"AutoForm.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/AutoForm.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/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;AAuID,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
@@ -4,6 +4,7 @@
4
4
  * This demonstrates the "Define Once, Consume Everywhere" vision
5
5
  */
6
6
 
7
+ import { Input, Textarea } from '@happyvertical/smrt-ui/forms';
7
8
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
9
  import { M } from '../../i18n.js';
9
10
 
@@ -92,10 +93,9 @@ function handleObjectInput(event: Event) {
92
93
  </label>
93
94
 
94
95
  {#if fieldType === 'string'}
95
- <input
96
+ <Input
96
97
  id={fieldId}
97
98
  type="text"
98
- class="field-input"
99
99
  {value}
100
100
  {placeholder}
101
101
  {readonly}
@@ -103,10 +103,9 @@ function handleObjectInput(event: Event) {
103
103
  oninput={handleStringInput}
104
104
  />
105
105
  {:else if fieldType === 'number'}
106
- <input
106
+ <Input
107
107
  id={fieldId}
108
108
  type="number"
109
- class="field-input"
110
109
  value={value || 0}
111
110
  {placeholder}
112
111
  {readonly}
@@ -114,6 +113,7 @@ function handleObjectInput(event: Event) {
114
113
  oninput={handleNumberInput}
115
114
  />
116
115
  {:else if fieldType === 'boolean'}
116
+ <!-- raw-primitive-allow: native checkbox; no Provider-free checkbox primitive (Toggle is a switch with different semantics, CheckboxInput requires a Provider) -->
117
117
  <input
118
118
  id={fieldId}
119
119
  type="checkbox"
@@ -123,26 +123,24 @@ function handleObjectInput(event: Event) {
123
123
  onchange={handleBooleanInput}
124
124
  />
125
125
  {:else if fieldType === 'array'}
126
- <textarea
126
+ <Textarea
127
127
  id={fieldId}
128
- class="field-textarea"
129
128
  value={Array.isArray(value) ? value.join(', ') : ''}
130
129
  placeholder={placeholder || 'Enter comma-separated values'}
131
130
  {readonly}
132
131
  {required}
133
132
  oninput={handleArrayInput}
134
- />
133
+ ></Textarea>
135
134
  <div class="field-hint">{t(M['products.field_renderer.array_hint'])}</div>
136
135
  {:else if fieldType === 'object'}
137
- <textarea
136
+ <Textarea
138
137
  id={fieldId}
139
- class="field-textarea"
140
138
  value={typeof value === 'object' ? JSON.stringify(value, null, 2) : '{}'}
141
139
  placeholder={placeholder || 'Enter JSON object'}
142
140
  {readonly}
143
141
  {required}
144
142
  oninput={handleObjectInput}
145
- />
143
+ ></Textarea>
146
144
  <div class="field-hint">{t(M['products.field_renderer.object_hint'])}</div>
147
145
  {/if}
148
146
  </div>
@@ -165,27 +163,6 @@ function handleObjectInput(event: Event) {
165
163
  color: var(--smrt-color-error, #dc2626);
166
164
  }
167
165
 
168
- .field-input,
169
- .field-textarea {
170
- padding: 0.5rem 0.75rem;
171
- border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
172
- border-radius: var(--smrt-radius-sm, 0.375rem);
173
- font-size: var(--smrt-typography-body-medium-size, 0.875rem);
174
- transition: border-color 0.2s, box-shadow 0.2s;
175
- }
176
-
177
- .field-input:focus,
178
- .field-textarea:focus {
179
- outline: none;
180
- border-color: var(--smrt-color-primary, #3b82f6);
181
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);
182
- }
183
-
184
- .field-textarea {
185
- min-height: 4rem;
186
- resize: vertical;
187
- }
188
-
189
166
  .field-checkbox {
190
167
  width: 1rem;
191
168
  height: 1rem;
@@ -196,10 +173,4 @@ function handleObjectInput(event: Event) {
196
173
  color: var(--smrt-color-on-surface-variant, #6b7280);
197
174
  font-style: italic;
198
175
  }
199
-
200
- .field-input:read-only,
201
- .field-textarea:read-only {
202
- background-color: var(--smrt-color-surface-container-low, #f9fafb);
203
- cursor: not-allowed;
204
- }
205
176
  </style>
@@ -1 +1 @@
1
- {"version":3,"file":"FieldRenderer.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/FieldRenderer.svelte.ts"],"names":[],"mappings":"AAWA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChE,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACjC;AAmGD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"FieldRenderer.svelte.d.ts","sourceRoot":"","sources":["../../../../../src/lib/components/auto-generated/FieldRenderer.svelte.ts"],"names":[],"mappings":"AAYA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IAChE,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CACjC;AAqGD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { Input, Select } from '@happyvertical/smrt-ui/forms';
2
3
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
4
  import { Button } from '@happyvertical/smrt-ui/ui';
4
5
  import { onMount } from 'svelte';
@@ -103,20 +104,20 @@ function handleCancelForm() {
103
104
 
104
105
  <div class="catalog-controls">
105
106
  <div class="search-filters">
106
- <input
107
+ <Input
107
108
  type="text"
108
109
  bind:value={searchQuery}
109
110
  placeholder={t(M['products.product_catalog.search_placeholder'])}
110
111
  aria-label={t(M['products.product_catalog.search_placeholder'])}
111
112
  class="search-input"
112
113
  />
113
-
114
- <select bind:value={selectedCategory} class="category-filter">
114
+
115
+ <Select bind:value={selectedCategory} class="category-filter">
115
116
  <option value="">{t(M['products.product_catalog.all_categories'])}</option>
116
117
  {#each productStore.categories as category}
117
118
  <option value={category}>{category}</option>
118
119
  {/each}
119
- </select>
120
+ </Select>
120
121
  </div>
121
122
 
122
123
  {#if !readonly && (showCreateForm || productStore.items.length === 0)}
@@ -224,20 +225,17 @@ function handleCancelForm() {
224
225
  gap: 0.75rem;
225
226
  flex: 1;
226
227
  }
227
-
228
- .search-input, .category-filter {
229
- padding: 0.5rem;
230
- border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
231
- border-radius: var(--smrt-radius-sm, 4px);
232
- font-size: var(--smrt-typography-body-medium-size, 0.875rem);
233
- }
234
-
235
- .search-input {
228
+
229
+ /* Layout sizing for the migrated <Input>/<Select>. The primitives render the
230
+ inner element with the forwarded class, so pierce with :global to keep the
231
+ flex sizing the old scoped rules supplied (#1589); padding/border/font come
232
+ from the primitives' tokenised styling now. */
233
+ .search-filters :global(.search-input) {
236
234
  flex: 1;
237
235
  max-width: 300px;
238
236
  }
239
-
240
- .category-filter {
237
+
238
+ .search-filters :global(.category-filter) {
241
239
  min-width: 150px;
242
240
  }
243
241
 
@@ -1 +1 @@
1
- {"version":3,"file":"ProductCatalog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/features/ProductCatalog.svelte"],"names":[],"mappings":"AAaA,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAoKD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"ProductCatalog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/features/ProductCatalog.svelte"],"names":[],"mappings":"AAcA,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAqKD,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "timestamp": 1782278452967,
3
+ "timestamp": 1782290137787,
4
4
  "packageName": "@happyvertical/smrt-products",
5
- "packageVersion": "0.34.6",
5
+ "packageVersion": "0.34.7",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-products:CategoryCollection": {
8
8
  "name": "categorycollection",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-06-24T05:20:53.581Z",
3
+ "generatedAt": "2026-06-24T08:35:38.290Z",
4
4
  "packageName": "@happyvertical/smrt-products",
5
- "packageVersion": "0.34.6",
5
+ "packageVersion": "0.34.7",
6
6
  "sourceManifestPath": "dist/lib/manifest.json",
7
7
  "agentDocPath": "AGENTS.md",
8
8
  "sourceHashes": {
9
- "manifest": "584ad2da857b7180b8a585c41e0975b7743a07f6ad3ffc172186e396cd814cb7",
10
- "packageJson": "5a90519cc03f1b0745852b4c8b691d0a03199722ab64cdf53425665e20be1ec5",
9
+ "manifest": "30f0edb5a8238da237d80fb012c320c04b2b4ac78e68481089a647961cfc66c4",
10
+ "packageJson": "393552fb22b0e6b9bbd15ef79cb29ab70be32c531d3ee31f357d1bab751cdc55",
11
11
  "agents": "4ca8837df73cf8b966b65cea639a058baa8f92ae536f3cd5036546fcbfeb37c8"
12
12
  },
13
13
  "exports": [
@@ -84,24 +84,24 @@
84
84
  border-top: 1px solid var(--smrt-color-outline-variant, #f3f4f6);
85
85
  }
86
86
 
87
- .product-form.svelte-1hh5ovx {
87
+ .product-form-shell.svelte-1hh5ovx .product-form {
88
88
  max-width: 500px;
89
89
  padding: 1.5rem;
90
90
  background: var(--smrt-color-surface, #fff);
91
91
  border-radius: var(--smrt-radius-md, 8px);
92
92
  border: 1px solid var(--smrt-color-outline-variant, #e2e8f0);
93
93
  }
94
-
94
+
95
95
  .form-group.svelte-1hh5ovx {
96
96
  margin-bottom: 1rem;
97
97
  }
98
-
98
+
99
99
  .form-row.svelte-1hh5ovx {
100
100
  display: grid;
101
101
  grid-template-columns: 1fr 1fr;
102
102
  gap: 1rem;
103
103
  }
104
-
104
+
105
105
  label.svelte-1hh5ovx {
106
106
  display: block;
107
107
  margin-bottom: 0.25rem;
@@ -110,30 +110,13 @@
110
110
  font-size: var(--smrt-typography-label-large-size, 0.875rem);
111
111
  }
112
112
 
113
- .form-input.svelte-1hh5ovx, .form-textarea.svelte-1hh5ovx {
114
- width: 100%;
115
- padding: 0.5rem;
116
- border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
117
- border-radius: var(--smrt-radius-sm, 4px);
118
- font-size: var(--smrt-typography-body-medium-size, 0.875rem);
119
- transition: border-color 0.2s;
120
- }
121
-
122
- .form-input.svelte-1hh5ovx:focus, .form-textarea.svelte-1hh5ovx:focus {
123
- outline: none;
124
- border-color: var(--smrt-color-primary, #3b82f6);
125
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--smrt-color-primary, #3b82f6) 10%, transparent);
126
- }
127
-
128
- .form-input.error.svelte-1hh5ovx {
113
+ /* Error border on the migrated <Input>. The primitive renders the inner
114
+ <input class="input error"> inside its own component, so the scoped class
115
+ can't reach it without :global (#1589). */
116
+ .product-form-shell.svelte-1hh5ovx .input.error {
129
117
  border-color: var(--smrt-color-error, #dc2626);
130
118
  }
131
-
132
- .form-textarea.svelte-1hh5ovx {
133
- resize: vertical;
134
- min-height: 80px;
135
- }
136
-
119
+
137
120
  .checkbox-label.svelte-1hh5ovx {
138
121
  display: flex;
139
122
  align-items: center;
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-products",
3
- "version": "0.34.6",
3
+ "version": "0.34.7",
4
4
  "description": "SMRT products module: triple-purpose microservice template for standalone apps, federated modules, and NPM libraries",
5
5
  "author": "HappyVertical",
6
6
  "type": "module",
7
- "smrtRawPrimitives": "strict-buttons",
7
+ "smrtRawPrimitives": "strict",
8
8
  "main": "dist/lib/index.js",
9
9
  "types": "dist/lib/index.d.ts",
10
10
  "files": [
@@ -55,11 +55,11 @@
55
55
  "@happyvertical/utils": "^0.74.7",
56
56
  "cors": "^2.8.5",
57
57
  "express": "^5.2.1",
58
- "@happyvertical/smrt-assets": "0.34.6",
59
- "@happyvertical/smrt-core": "0.34.6",
60
- "@happyvertical/smrt-scanner": "0.34.6",
61
- "@happyvertical/smrt-tenancy": "0.34.6",
62
- "@happyvertical/smrt-ui": "0.34.6"
58
+ "@happyvertical/smrt-assets": "0.34.7",
59
+ "@happyvertical/smrt-core": "0.34.7",
60
+ "@happyvertical/smrt-scanner": "0.34.7",
61
+ "@happyvertical/smrt-tenancy": "0.34.7",
62
+ "@happyvertical/smrt-ui": "0.34.7"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "svelte": "^5.46.4"
@@ -82,7 +82,7 @@
82
82
  "typescript": "^5.9.3",
83
83
  "vite": "^7.3.1",
84
84
  "vitest": "^4.0.17",
85
- "@happyvertical/smrt-vitest": "0.34.6"
85
+ "@happyvertical/smrt-vitest": "0.34.7"
86
86
  },
87
87
  "keywords": [
88
88
  "smrt",