@melodicdev/components 1.5.13 → 1.6.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 (31) hide show
  1. package/assets/melodic-components.js +741 -423
  2. package/assets/melodic-components.js.map +1 -1
  3. package/assets/melodic-components.min.js +2081 -1760
  4. package/lib/components/data-display/badge/badge.styles.d.ts.map +1 -1
  5. package/lib/components/data-display/badge/badge.styles.js +11 -0
  6. package/lib/components/forms/autocomplete/autocomplete.component.d.ts.map +1 -1
  7. package/lib/components/forms/autocomplete/autocomplete.component.js +17 -0
  8. package/lib/components/forms/checkbox/checkbox.component.d.ts.map +1 -1
  9. package/lib/components/forms/checkbox/checkbox.component.js +8 -0
  10. package/lib/components/forms/date-picker/date-picker.component.d.ts.map +1 -1
  11. package/lib/components/forms/date-picker/date-picker.component.js +8 -0
  12. package/lib/components/forms/date-time-picker/date-time-picker.component.d.ts.map +1 -1
  13. package/lib/components/forms/date-time-picker/date-time-picker.component.js +8 -0
  14. package/lib/components/forms/input/input.component.d.ts.map +1 -1
  15. package/lib/components/forms/input/input.component.js +8 -0
  16. package/lib/components/forms/radio/radio-group.component.d.ts.map +1 -1
  17. package/lib/components/forms/radio/radio-group.component.js +8 -0
  18. package/lib/components/forms/select/select.component.d.ts.map +1 -1
  19. package/lib/components/forms/select/select.component.js +17 -0
  20. package/lib/components/forms/slider/slider.component.d.ts.map +1 -1
  21. package/lib/components/forms/slider/slider.component.js +8 -0
  22. package/lib/components/forms/textarea/textarea.component.d.ts.map +1 -1
  23. package/lib/components/forms/textarea/textarea.component.js +8 -0
  24. package/lib/components/forms/time-picker/time-picker.component.d.ts.map +1 -1
  25. package/lib/components/forms/time-picker/time-picker.component.js +8 -0
  26. package/lib/components/forms/toggle/toggle.component.d.ts.map +1 -1
  27. package/lib/components/forms/toggle/toggle.component.js +8 -0
  28. package/lib/forms-adapters.d.ts +2 -0
  29. package/lib/forms-adapters.d.ts.map +1 -0
  30. package/lib/forms-adapters.js +105 -0
  31. package/package.json +1 -1
@@ -315,6 +315,292 @@ var cacheCssSheet = (text) => {
315
315
  var hasCachedSheets = () => {
316
316
  return cachedCssSheets.length > 0;
317
317
  };
318
+ var activeEffect = null;
319
+ const setActiveEffect = (effect) => {
320
+ activeEffect = effect;
321
+ };
322
+ const getActiveEffect = () => activeEffect;
323
+ var SignalEffect = class {
324
+ constructor(execute) {
325
+ this.execute = execute;
326
+ this._dependencies = /* @__PURE__ */ new Set();
327
+ this._isRunning = false;
328
+ this._needsRerun = false;
329
+ this.run = () => {
330
+ if (this._isRunning) {
331
+ this._needsRerun = true;
332
+ return;
333
+ }
334
+ this._isRunning = true;
335
+ do {
336
+ this._needsRerun = false;
337
+ this._dependencies.forEach((signal$1) => {
338
+ signal$1.unsubscribe(this.run);
339
+ });
340
+ this._dependencies.clear();
341
+ const prevEffect = getActiveEffect();
342
+ setActiveEffect(this);
343
+ this.execute();
344
+ setActiveEffect(prevEffect);
345
+ } while (this._needsRerun);
346
+ this._isRunning = false;
347
+ };
348
+ }
349
+ addDependency(signal$1) {
350
+ this._dependencies.add(signal$1);
351
+ }
352
+ destroy() {
353
+ this._dependencies.forEach((signal$1) => {
354
+ signal$1.unsubscribe(this.run);
355
+ });
356
+ this._dependencies.clear();
357
+ }
358
+ };
359
+ function signal(initialValue) {
360
+ let value = initialValue;
361
+ const subscribers = /* @__PURE__ */ new Set();
362
+ const notify = () => {
363
+ [...subscribers].forEach((subscriber) => subscriber(value));
364
+ };
365
+ const read = (() => {
366
+ const activeEffect$1 = getActiveEffect();
367
+ if (activeEffect$1) {
368
+ activeEffect$1.addDependency(read);
369
+ subscribers.add(activeEffect$1.run);
370
+ }
371
+ return value;
372
+ });
373
+ read.set = (newValue) => {
374
+ if (value !== newValue) {
375
+ value = newValue;
376
+ notify();
377
+ }
378
+ };
379
+ read.update = (updater) => {
380
+ read.set(updater(value));
381
+ };
382
+ read.subscribe = (subscriber) => {
383
+ subscribers.add(subscriber);
384
+ return () => subscribers.delete(subscriber);
385
+ };
386
+ read.unsubscribe = (subscriber) => {
387
+ subscribers.delete(subscriber);
388
+ };
389
+ read.destroy = () => {
390
+ subscribers.clear();
391
+ };
392
+ Object.defineProperty(read, SIGNAL_MARKER, {
393
+ value: true,
394
+ enumerable: false,
395
+ configurable: false
396
+ });
397
+ return read;
398
+ }
399
+ function computed(computation) {
400
+ const computedSignal = signal(void 0);
401
+ const effect = new SignalEffect(() => {
402
+ computedSignal.set(computation());
403
+ });
404
+ effect.run();
405
+ const originalDestroy = computedSignal.destroy;
406
+ computedSignal.destroy = () => {
407
+ effect.destroy();
408
+ originalDestroy();
409
+ };
410
+ return computedSignal;
411
+ }
412
+ var globalMessages = {};
413
+ function registerDefaultMessages(messages) {
414
+ for (const code of Object.keys(messages)) globalMessages[code] = messages[code];
415
+ }
416
+ function setDefaultMessage(code, message) {
417
+ globalMessages[code] = message;
418
+ }
419
+ function getGlobalMessage(code) {
420
+ return globalMessages[code];
421
+ }
422
+ function resolveMessage(message, params) {
423
+ if (typeof message === "function") return message(params ?? {});
424
+ return message;
425
+ }
426
+ var AbstractControl = class {
427
+ constructor(initialValue, options = {}) {
428
+ this.parent = null;
429
+ this._validators = [];
430
+ this._asyncValidators = [];
431
+ this._touched = signal(false);
432
+ this._dirty = signal(false);
433
+ this._pending = signal(false);
434
+ this._ownDisabled = signal(false);
435
+ this._asyncValidationId = 0;
436
+ this.value = signal(initialValue);
437
+ this.errors = signal(null);
438
+ this._validators = options.validators ?? [];
439
+ this._asyncValidators = options.asyncValidators ?? [];
440
+ this._ownDisabled.set(options.disabled ?? false);
441
+ this.updateOn = options.updateOn ?? "change";
442
+ this.messages = options.messages ?? {};
443
+ }
444
+ initializeAggregates() {
445
+ this.dirty = computed(() => this.computeDirty());
446
+ this.touched = computed(() => this.computeTouched());
447
+ this.pending = computed(() => this.computePending());
448
+ this.disabled = computed(() => this.computeDisabled());
449
+ this.pristine = computed(() => !this.dirty());
450
+ this.untouched = computed(() => !this.touched());
451
+ this.enabled = computed(() => !this.disabled());
452
+ this.invalid = computed(() => this.errors() !== null || this.hasInvalidChild());
453
+ this.valid = computed(() => !this.invalid() && !this.pending());
454
+ this.state = computed(() => ({
455
+ dirty: this.dirty(),
456
+ touched: this.touched(),
457
+ pristine: !this.dirty(),
458
+ untouched: !this.touched(),
459
+ valid: !this.invalid() && !this.pending(),
460
+ invalid: this.invalid(),
461
+ pending: this.pending(),
462
+ disabled: this.disabled(),
463
+ enabled: !this.disabled()
464
+ }));
465
+ }
466
+ markAsTouched() {
467
+ this._touched.set(true);
468
+ if (this.updateOn === "blur") this.runValidation();
469
+ }
470
+ markAsUntouched() {
471
+ this._touched.set(false);
472
+ }
473
+ markAsDirty() {
474
+ this._dirty.set(true);
475
+ }
476
+ markAsPristine() {
477
+ this._dirty.set(false);
478
+ }
479
+ markAllAsTouched() {
480
+ this.markAsTouched();
481
+ }
482
+ markAllAsUntouched() {
483
+ this.markAsUntouched();
484
+ }
485
+ disable() {
486
+ this._ownDisabled.set(true);
487
+ }
488
+ enable() {
489
+ this._ownDisabled.set(false);
490
+ }
491
+ setValidators(validators) {
492
+ this._validators = validators;
493
+ this.runValidation();
494
+ }
495
+ addValidators(validators) {
496
+ this._validators = [...this._validators, ...validators];
497
+ this.runValidation();
498
+ }
499
+ removeValidators(validators) {
500
+ this._validators = this._validators.filter((v) => !validators.includes(v));
501
+ this.runValidation();
502
+ }
503
+ setAsyncValidators(validators) {
504
+ this._asyncValidators = validators;
505
+ this.runValidation();
506
+ }
507
+ async validate() {
508
+ await this.runValidation();
509
+ }
510
+ getError(code) {
511
+ return this.errors()?.[code] ?? null;
512
+ }
513
+ hasError(code) {
514
+ return this.errors()?.[code] !== void 0;
515
+ }
516
+ getErrorMessage(code) {
517
+ const error = this.getError(code);
518
+ if (!error) return "";
519
+ const params = error.params;
520
+ const localMessage = this.resolveFromChain(code);
521
+ if (localMessage !== void 0) return resolveMessage(localMessage, params);
522
+ const globalMessage = getGlobalMessage(code);
523
+ if (globalMessage !== void 0) return resolveMessage(globalMessage, params);
524
+ return code;
525
+ }
526
+ getFirstErrorMessage() {
527
+ const errors = this.errors();
528
+ if (!errors) return "";
529
+ const codes = Object.keys(errors);
530
+ if (codes.length === 0) return "";
531
+ return this.getErrorMessage(codes[0]);
532
+ }
533
+ resolveFromChain(code) {
534
+ let control = this;
535
+ while (control !== null) {
536
+ if (control.messages[code] !== void 0) return control.messages[code];
537
+ control = control.parent;
538
+ }
539
+ }
540
+ async runValidation() {
541
+ const value = this.value();
542
+ let errors = null;
543
+ for (const validator of this._validators) {
544
+ const result = validator(value);
545
+ if (result !== null) errors = {
546
+ ...errors ?? {},
547
+ ...result
548
+ };
549
+ }
550
+ if (errors !== null) {
551
+ this.errors.set(errors);
552
+ return;
553
+ }
554
+ if (this._asyncValidators.length > 0) {
555
+ const id = ++this._asyncValidationId;
556
+ this._pending.set(true);
557
+ try {
558
+ const results = await Promise.all(this._asyncValidators.map((v) => v(value)));
559
+ if (id !== this._asyncValidationId) return;
560
+ for (const result of results) if (result !== null) errors = {
561
+ ...errors ?? {},
562
+ ...result
563
+ };
564
+ } finally {
565
+ if (id === this._asyncValidationId) this._pending.set(false);
566
+ }
567
+ }
568
+ this.errors.set(errors);
569
+ }
570
+ computeDirty() {
571
+ return this._dirty();
572
+ }
573
+ computeTouched() {
574
+ return this._touched();
575
+ }
576
+ computePending() {
577
+ return this._pending();
578
+ }
579
+ computeDisabled() {
580
+ return this._ownDisabled();
581
+ }
582
+ hasInvalidChild() {
583
+ return false;
584
+ }
585
+ destroySignals() {
586
+ this.value.destroy();
587
+ this.errors.destroy();
588
+ this._touched.destroy();
589
+ this._dirty.destroy();
590
+ this._pending.destroy();
591
+ this._ownDisabled.destroy();
592
+ this.dirty.destroy();
593
+ this.touched.destroy();
594
+ this.pristine.destroy();
595
+ this.untouched.destroy();
596
+ this.valid.destroy();
597
+ this.invalid.destroy();
598
+ this.pending.destroy();
599
+ this.disabled.destroy();
600
+ this.enabled.destroy();
601
+ this.state.destroy();
602
+ }
603
+ };
318
604
  var ComponentBase = class extends HTMLElement {
319
605
  constructor(meta, component) {
320
606
  super();
@@ -400,6 +686,10 @@ var ComponentBase = class extends HTMLElement {
400
686
  this.subscribeToSignal(value);
401
687
  return false;
402
688
  }
689
+ if (value instanceof AbstractControl) {
690
+ this.subscribeToSignal(value.state);
691
+ return false;
692
+ }
403
693
  if (typeof value === "function") return false;
404
694
  return prop !== "elementRef" && prop !== "constructor";
405
695
  });
@@ -2419,120 +2709,26 @@ function routerLinkDirective(element, value, _) {
2419
2709
  window.open(buildFullPath(), "_blank");
2420
2710
  return;
2421
2711
  }
2422
- e.preventDefault();
2423
- const navOptions = {
2424
- data,
2425
- replace,
2426
- queryParams
2427
- };
2428
- router.navigate(href, navOptions);
2429
- };
2430
- const handleNavigation = () => {
2431
- updateActiveState();
2432
- };
2433
- element.addEventListener("click", handleClick);
2434
- window.addEventListener("NavigationEvent", handleNavigation);
2435
- updateActiveState();
2436
- return (() => {
2437
- element.removeEventListener("click", handleClick);
2438
- window.removeEventListener("NavigationEvent", handleNavigation);
2439
- });
2440
- }
2441
- registerAttributeDirective("routerLink", routerLinkDirective);
2442
- var activeEffect = null;
2443
- const setActiveEffect = (effect) => {
2444
- activeEffect = effect;
2445
- };
2446
- const getActiveEffect = () => activeEffect;
2447
- var SignalEffect = class {
2448
- constructor(execute) {
2449
- this.execute = execute;
2450
- this._dependencies = /* @__PURE__ */ new Set();
2451
- this._isRunning = false;
2452
- this._needsRerun = false;
2453
- this.run = () => {
2454
- if (this._isRunning) {
2455
- this._needsRerun = true;
2456
- return;
2457
- }
2458
- this._isRunning = true;
2459
- do {
2460
- this._needsRerun = false;
2461
- this._dependencies.forEach((signal$1) => {
2462
- signal$1.unsubscribe(this.run);
2463
- });
2464
- this._dependencies.clear();
2465
- const prevEffect = getActiveEffect();
2466
- setActiveEffect(this);
2467
- this.execute();
2468
- setActiveEffect(prevEffect);
2469
- } while (this._needsRerun);
2470
- this._isRunning = false;
2471
- };
2472
- }
2473
- addDependency(signal$1) {
2474
- this._dependencies.add(signal$1);
2475
- }
2476
- destroy() {
2477
- this._dependencies.forEach((signal$1) => {
2478
- signal$1.unsubscribe(this.run);
2479
- });
2480
- this._dependencies.clear();
2481
- }
2482
- };
2483
- function signal(initialValue) {
2484
- let value = initialValue;
2485
- const subscribers = /* @__PURE__ */ new Set();
2486
- const notify = () => {
2487
- [...subscribers].forEach((subscriber) => subscriber(value));
2488
- };
2489
- const read = (() => {
2490
- const activeEffect$1 = getActiveEffect();
2491
- if (activeEffect$1) {
2492
- activeEffect$1.addDependency(read);
2493
- subscribers.add(activeEffect$1.run);
2494
- }
2495
- return value;
2496
- });
2497
- read.set = (newValue) => {
2498
- if (value !== newValue) {
2499
- value = newValue;
2500
- notify();
2501
- }
2502
- };
2503
- read.update = (updater) => {
2504
- read.set(updater(value));
2505
- };
2506
- read.subscribe = (subscriber) => {
2507
- subscribers.add(subscriber);
2508
- return () => subscribers.delete(subscriber);
2509
- };
2510
- read.unsubscribe = (subscriber) => {
2511
- subscribers.delete(subscriber);
2712
+ e.preventDefault();
2713
+ const navOptions = {
2714
+ data,
2715
+ replace,
2716
+ queryParams
2717
+ };
2718
+ router.navigate(href, navOptions);
2512
2719
  };
2513
- read.destroy = () => {
2514
- subscribers.clear();
2720
+ const handleNavigation = () => {
2721
+ updateActiveState();
2515
2722
  };
2516
- Object.defineProperty(read, SIGNAL_MARKER, {
2517
- value: true,
2518
- enumerable: false,
2519
- configurable: false
2520
- });
2521
- return read;
2522
- }
2523
- function computed(computation) {
2524
- const computedSignal = signal(void 0);
2525
- const effect = new SignalEffect(() => {
2526
- computedSignal.set(computation());
2723
+ element.addEventListener("click", handleClick);
2724
+ window.addEventListener("NavigationEvent", handleNavigation);
2725
+ updateActiveState();
2726
+ return (() => {
2727
+ element.removeEventListener("click", handleClick);
2728
+ window.removeEventListener("NavigationEvent", handleNavigation);
2527
2729
  });
2528
- effect.run();
2529
- const originalDestroy = computedSignal.destroy;
2530
- computedSignal.destroy = () => {
2531
- effect.destroy();
2532
- originalDestroy();
2533
- };
2534
- return computedSignal;
2535
2730
  }
2731
+ registerAttributeDirective("routerLink", routerLinkDirective);
2536
2732
  const props = () => {
2537
2733
  return () => ({});
2538
2734
  };
@@ -3305,53 +3501,23 @@ var Directive = class {
3305
3501
  this.__directive = true;
3306
3502
  }
3307
3503
  };
3308
- const FORM_CONTROL_MARKER = Symbol("melodic.formControl");
3309
- var FormControl = class {
3504
+ var FormControl = class extends AbstractControl {
3310
3505
  constructor(initialValue, options = {}) {
3311
- this[FORM_CONTROL_MARKER] = true;
3312
- this._validators = [];
3313
- this._asyncValidators = [];
3314
- this._touched = signal(false);
3315
- this._dirty = signal(false);
3316
- this._pending = signal(false);
3317
- this._disabled = signal(false);
3318
- this._asyncValidationId = 0;
3506
+ super(initialValue, options);
3319
3507
  this.initialValue = initialValue;
3320
- this.value = signal(initialValue);
3321
- this.errors = signal(null);
3322
- this._validators = options.validators ?? [];
3323
- this._asyncValidators = options.asyncValidators ?? [];
3324
- this._disabled.set(options.disabled ?? false);
3325
- this.updateOn = options.updateOn ?? "input";
3326
- this.dirty = computed(() => this._dirty());
3327
- this.touched = computed(() => this._touched());
3328
- this.pristine = computed(() => !this._dirty());
3329
- this.pending = computed(() => this._pending());
3330
- this.disabled = computed(() => this._disabled());
3331
- this.valid = computed(() => this.errors() === null && !this._pending());
3332
- this.invalid = computed(() => this.errors() !== null);
3333
- this.state = computed(() => ({
3334
- dirty: this._dirty(),
3335
- touched: this._touched(),
3336
- pristine: !this._dirty(),
3337
- untouched: !this._touched(),
3338
- valid: this.errors() === null && !this._pending(),
3339
- invalid: this.errors() !== null,
3340
- pending: this._pending(),
3341
- disabled: this._disabled(),
3342
- enabled: !this._disabled()
3343
- }));
3508
+ this.initializeAggregates();
3344
3509
  this.runValidation();
3345
3510
  }
3346
3511
  setValue(value) {
3347
- if (this._disabled()) return;
3512
+ if (this._ownDisabled()) return;
3348
3513
  this.value.set(value);
3349
3514
  this._dirty.set(true);
3350
- if (this.updateOn === "input") this.runValidation();
3515
+ if (this.updateOn === "change") this.runValidation();
3351
3516
  }
3352
3517
  patchValue(value) {
3353
- if (typeof this.value() === "object" && this.value() !== null) this.setValue({
3354
- ...this.value(),
3518
+ const current = this.value();
3519
+ if (typeof current === "object" && current !== null && !Array.isArray(current)) this.setValue({
3520
+ ...current,
3355
3521
  ...value
3356
3522
  });
3357
3523
  else this.setValue(value);
@@ -3363,244 +3529,246 @@ var FormControl = class {
3363
3529
  this.errors.set(null);
3364
3530
  this.runValidation();
3365
3531
  }
3366
- markAsTouched() {
3532
+ destroy() {
3533
+ this.destroySignals();
3534
+ }
3535
+ };
3536
+ var FormGroup = class FormGroup extends AbstractControl {
3537
+ constructor(initialControls, options = {}) {
3538
+ super(FormGroup.computeValue(initialControls), options);
3539
+ this.controls = signal({ ...initialControls });
3540
+ for (const key of Object.keys(initialControls)) initialControls[key].parent = this;
3541
+ this.initializeAggregates();
3542
+ this._childValueEffect = new SignalEffect(() => {
3543
+ const controls = this.controls();
3544
+ for (const key of Object.keys(controls)) controls[key].value();
3545
+ this.value.set(FormGroup.computeValue(controls));
3546
+ this.runValidation();
3547
+ });
3548
+ this._childValueEffect.run();
3549
+ }
3550
+ get(name) {
3551
+ return this.controls()[name];
3552
+ }
3553
+ contains(name) {
3554
+ return name in this.controls();
3555
+ }
3556
+ addControl(name, control) {
3557
+ control.parent = this;
3558
+ this.controls.update((current) => ({
3559
+ ...current,
3560
+ [name]: control
3561
+ }));
3562
+ }
3563
+ removeControl(name) {
3564
+ const control = this.controls()[name];
3565
+ if (!control) return;
3566
+ control.parent = null;
3567
+ control.destroy();
3568
+ this.controls.update((current) => {
3569
+ const next = { ...current };
3570
+ delete next[name];
3571
+ return next;
3572
+ });
3573
+ }
3574
+ setValue(value) {
3575
+ if (this._ownDisabled()) return;
3576
+ const controls = this.controls();
3577
+ for (const key of Object.keys(value)) controls[key]?.setValue(value[key]);
3578
+ }
3579
+ patchValue(value) {
3580
+ if (this._ownDisabled()) return;
3581
+ const controls = this.controls();
3582
+ for (const key of Object.keys(value)) if (value[key] !== void 0) controls[key]?.setValue(value[key]);
3583
+ }
3584
+ reset(value) {
3585
+ const controls = this.controls();
3586
+ for (const key of Object.keys(controls)) {
3587
+ const resetValue = value?.[key];
3588
+ controls[key].reset(resetValue);
3589
+ }
3590
+ }
3591
+ markAllAsTouched() {
3367
3592
  this._touched.set(true);
3368
- if (this.updateOn === "blur") this.runValidation();
3593
+ const controls = this.controls();
3594
+ for (const key of Object.keys(controls)) controls[key].markAllAsTouched();
3369
3595
  }
3370
- markAsUntouched() {
3596
+ markAllAsUntouched() {
3371
3597
  this._touched.set(false);
3598
+ const controls = this.controls();
3599
+ for (const key of Object.keys(controls)) controls[key].markAllAsUntouched();
3372
3600
  }
3373
- markAsDirty() {
3601
+ markAllAsDirty() {
3374
3602
  this._dirty.set(true);
3603
+ const controls = this.controls();
3604
+ for (const key of Object.keys(controls)) {
3605
+ const child = controls[key];
3606
+ if ("markAllAsDirty" in child && typeof child.markAllAsDirty === "function") child.markAllAsDirty();
3607
+ else child.markAsDirty();
3608
+ }
3375
3609
  }
3376
- markAsPristine() {
3610
+ markAllAsPristine() {
3377
3611
  this._dirty.set(false);
3612
+ const controls = this.controls();
3613
+ for (const key of Object.keys(controls)) {
3614
+ const child = controls[key];
3615
+ if ("markAllAsPristine" in child && typeof child.markAllAsPristine === "function") child.markAllAsPristine();
3616
+ else child.markAsPristine();
3617
+ }
3378
3618
  }
3379
3619
  disable() {
3380
- this._disabled.set(true);
3620
+ this._ownDisabled.set(true);
3621
+ const controls = this.controls();
3622
+ for (const key of Object.keys(controls)) controls[key].disable();
3381
3623
  }
3382
3624
  enable() {
3383
- this._disabled.set(false);
3384
- }
3385
- setValidators(validators) {
3386
- this._validators = validators;
3387
- this.runValidation();
3388
- }
3389
- setAsyncValidators(validators) {
3390
- this._asyncValidators = validators;
3391
- this.runValidation();
3392
- }
3393
- addValidators(validators) {
3394
- this._validators = [...this._validators, ...validators];
3395
- this.runValidation();
3396
- }
3397
- removeValidators(validators) {
3398
- this._validators = this._validators.filter((v) => !validators.includes(v));
3399
- this.runValidation();
3625
+ this._ownDisabled.set(false);
3626
+ const controls = this.controls();
3627
+ for (const key of Object.keys(controls)) controls[key].enable();
3400
3628
  }
3401
3629
  async validate() {
3630
+ const controls = this.controls();
3631
+ await Promise.all(Object.keys(controls).map((key) => controls[key].validate()));
3402
3632
  await this.runValidation();
3403
3633
  }
3404
- getError(code) {
3405
- return this.errors()?.[code] ?? null;
3406
- }
3407
- hasError(code) {
3408
- return this.errors()?.[code] !== void 0;
3409
- }
3410
3634
  destroy() {
3411
- this.value.destroy();
3412
- this.errors.destroy();
3413
- this._touched.destroy();
3414
- this._dirty.destroy();
3415
- this._pending.destroy();
3416
- this._disabled.destroy();
3417
- }
3418
- async runValidation() {
3419
- const value = this.value();
3420
- let errors = null;
3421
- for (const validator of this._validators) {
3422
- const result = validator(value);
3423
- if (result !== null) errors = {
3424
- ...errors ?? {},
3425
- ...result
3426
- };
3427
- }
3428
- if (errors !== null) {
3429
- this.errors.set(errors);
3430
- return;
3431
- }
3432
- if (this._asyncValidators.length > 0) {
3433
- const validationId = ++this._asyncValidationId;
3434
- this._pending.set(true);
3435
- try {
3436
- const asyncResults = await Promise.all(this._asyncValidators.map((v) => v(value)));
3437
- if (validationId !== this._asyncValidationId) return;
3438
- for (const result of asyncResults) if (result !== null) errors = {
3439
- ...errors ?? {},
3440
- ...result
3441
- };
3442
- } finally {
3443
- if (validationId === this._asyncValidationId) this._pending.set(false);
3444
- }
3445
- }
3446
- this.errors.set(errors);
3635
+ this._childValueEffect.destroy();
3636
+ const controls = this.controls();
3637
+ for (const key of Object.keys(controls)) controls[key].destroy();
3638
+ this.destroySignals();
3639
+ this.controls.destroy();
3640
+ }
3641
+ computeDirty() {
3642
+ if (this._dirty()) return true;
3643
+ const controls = this.controls();
3644
+ return Object.keys(controls).some((key) => controls[key].dirty());
3645
+ }
3646
+ computeTouched() {
3647
+ if (this._touched()) return true;
3648
+ const controls = this.controls();
3649
+ return Object.keys(controls).some((key) => controls[key].touched());
3650
+ }
3651
+ computePending() {
3652
+ if (this._pending()) return true;
3653
+ const controls = this.controls();
3654
+ return Object.keys(controls).some((key) => controls[key].pending());
3655
+ }
3656
+ hasInvalidChild() {
3657
+ const controls = this.controls();
3658
+ return Object.keys(controls).some((key) => controls[key].invalid());
3659
+ }
3660
+ static computeValue(controls) {
3661
+ const result = {};
3662
+ for (const key of Object.keys(controls)) result[key] = controls[key].value();
3663
+ return result;
3447
3664
  }
3448
3665
  };
3449
- const FORM_GROUP_MARKER = Symbol("melodic.formGroup");
3450
- var FormGroup = class {
3451
- constructor(controls, options = {}) {
3452
- this[FORM_GROUP_MARKER] = true;
3453
- this._validators = [];
3454
- this._asyncValidators = [];
3455
- this._disabled = signal(false);
3456
- this._controlEffects = [];
3457
- this.controls = controls;
3458
- this._validators = options.validators ?? [];
3459
- this._asyncValidators = options.asyncValidators ?? [];
3460
- this._disabled.set(options.disabled ?? false);
3461
- this.value = computed(() => this.computeValue());
3462
- this.errors = signal(null);
3463
- this.setupControlWatchers();
3464
- this.valid = computed(() => {
3465
- if (this.errors() !== null) return false;
3466
- return Object.values(this.controls).every((control) => control.valid());
3467
- });
3468
- this.invalid = computed(() => !this.valid());
3469
- this.pending = computed(() => {
3470
- return Object.values(this.controls).some((control) => control.pending());
3471
- });
3472
- this.dirty = computed(() => {
3473
- return Object.values(this.controls).some((control) => control.dirty());
3474
- });
3475
- this.touched = computed(() => {
3476
- return Object.values(this.controls).some((control) => control.touched());
3666
+ var FormArray = class extends AbstractControl {
3667
+ constructor(initialControls, options = {}) {
3668
+ super(initialControls.map((c) => c.value()), options);
3669
+ this.controls = signal([...initialControls]);
3670
+ for (const control of initialControls) control.parent = this;
3671
+ this.initializeAggregates();
3672
+ this._childValueEffect = new SignalEffect(() => {
3673
+ const controls = this.controls();
3674
+ for (const control of controls) control.value();
3675
+ this.value.set(controls.map((c) => c.value()));
3676
+ this.runValidation();
3477
3677
  });
3478
- this.pristine = computed(() => !this.dirty());
3479
- this.disabled = computed(() => this._disabled());
3480
- this.runGroupValidation();
3678
+ this._childValueEffect.run();
3481
3679
  }
3482
- get(name) {
3483
- return this.controls[name];
3680
+ get length() {
3681
+ return this.controls().length;
3484
3682
  }
3485
- addControl(name, control) {
3486
- this.controls[name] = control;
3487
- this.setupControlWatcher(control);
3683
+ at(index) {
3684
+ return this.controls()[index];
3488
3685
  }
3489
- removeControl(name) {
3490
- delete this.controls[name];
3686
+ push(control) {
3687
+ control.parent = this;
3688
+ this.controls.update((current) => [...current, control]);
3491
3689
  }
3492
- contains(name) {
3493
- return name in this.controls;
3690
+ insert(index, control) {
3691
+ control.parent = this;
3692
+ this.controls.update((current) => {
3693
+ const next = [...current];
3694
+ next.splice(index, 0, control);
3695
+ return next;
3696
+ });
3697
+ }
3698
+ removeAt(index) {
3699
+ const control = this.controls()[index];
3700
+ if (!control) return;
3701
+ control.parent = null;
3702
+ control.destroy();
3703
+ this.controls.update((current) => current.filter((_, i) => i !== index));
3704
+ }
3705
+ clear() {
3706
+ const controls = this.controls();
3707
+ for (const control of controls) {
3708
+ control.parent = null;
3709
+ control.destroy();
3710
+ }
3711
+ this.controls.set([]);
3494
3712
  }
3495
3713
  setValue(value) {
3496
- Object.keys(value).forEach((key) => {
3497
- const control = this.controls[key];
3498
- if (control) control.setValue(value[key]);
3714
+ if (this._ownDisabled()) return;
3715
+ const controls = this.controls();
3716
+ value.forEach((v, i) => {
3717
+ controls[i]?.setValue(v);
3499
3718
  });
3500
3719
  }
3501
3720
  patchValue(value) {
3502
- Object.keys(value).forEach((key) => {
3503
- const control = this.controls[key];
3504
- if (control && value[key] !== void 0) control.setValue(value[key]);
3721
+ if (this._ownDisabled()) return;
3722
+ const controls = this.controls();
3723
+ value.forEach((v, i) => {
3724
+ if (v !== void 0) controls[i]?.setValue(v);
3505
3725
  });
3506
3726
  }
3507
3727
  reset(value) {
3508
- Object.keys(this.controls).forEach((key) => {
3509
- const control = this.controls[key];
3510
- const resetValue = value?.[key];
3511
- control.reset(resetValue);
3728
+ this.controls().forEach((control, i) => {
3729
+ control.reset(value?.[i]);
3512
3730
  });
3513
3731
  }
3514
3732
  markAllAsTouched() {
3515
- Object.values(this.controls).forEach((control) => {
3516
- control.markAsTouched();
3517
- });
3733
+ this._touched.set(true);
3734
+ for (const control of this.controls()) control.markAllAsTouched();
3518
3735
  }
3519
3736
  markAllAsUntouched() {
3520
- Object.values(this.controls).forEach((control) => {
3521
- control.markAsUntouched();
3522
- });
3523
- }
3524
- markAllAsDirty() {
3525
- Object.values(this.controls).forEach((control) => {
3526
- control.markAsDirty();
3527
- });
3528
- }
3529
- markAllAsPristine() {
3530
- Object.values(this.controls).forEach((control) => {
3531
- control.markAsPristine();
3532
- });
3737
+ this._touched.set(false);
3738
+ for (const control of this.controls()) control.markAllAsUntouched();
3533
3739
  }
3534
3740
  disable() {
3535
- this._disabled.set(true);
3536
- Object.values(this.controls).forEach((control) => {
3537
- control.disable();
3538
- });
3741
+ this._ownDisabled.set(true);
3742
+ for (const control of this.controls()) control.disable();
3539
3743
  }
3540
3744
  enable() {
3541
- this._disabled.set(false);
3542
- Object.values(this.controls).forEach((control) => {
3543
- control.enable();
3544
- });
3745
+ this._ownDisabled.set(false);
3746
+ for (const control of this.controls()) control.enable();
3545
3747
  }
3546
3748
  async validate() {
3547
- await Promise.all(Object.values(this.controls).map((control) => control.validate()));
3548
- await this.runGroupValidation();
3549
- }
3550
- setValidators(validators) {
3551
- this._validators = validators;
3552
- this.runGroupValidation();
3553
- }
3554
- getError(code) {
3555
- return this.errors()?.[code] ?? null;
3556
- }
3557
- hasError(code) {
3558
- return this.errors()?.[code] !== void 0;
3749
+ await Promise.all(this.controls().map((c) => c.validate()));
3750
+ await this.runValidation();
3559
3751
  }
3560
3752
  destroy() {
3561
- this._controlEffects.forEach((effect) => effect.destroy());
3562
- Object.values(this.controls).forEach((control) => {
3563
- control.destroy();
3564
- });
3753
+ this._childValueEffect.destroy();
3754
+ for (const control of this.controls()) control.destroy();
3755
+ this.destroySignals();
3756
+ this.controls.destroy();
3565
3757
  }
3566
- computeValue() {
3567
- const result = {};
3568
- Object.keys(this.controls).forEach((key) => {
3569
- result[key] = this.controls[key].value();
3570
- });
3571
- return result;
3758
+ computeDirty() {
3759
+ if (this._dirty()) return true;
3760
+ return this.controls().some((c) => c.dirty());
3572
3761
  }
3573
- setupControlWatchers() {
3574
- Object.keys(this.controls).forEach((key) => {
3575
- this.setupControlWatcher(this.controls[key]);
3576
- });
3762
+ computeTouched() {
3763
+ if (this._touched()) return true;
3764
+ return this.controls().some((c) => c.touched());
3577
3765
  }
3578
- setupControlWatcher(control) {
3579
- const effect = new SignalEffect(() => {
3580
- control.value();
3581
- this.runGroupValidation();
3582
- });
3583
- effect.run();
3584
- this._controlEffects.push(effect);
3766
+ computePending() {
3767
+ if (this._pending()) return true;
3768
+ return this.controls().some((c) => c.pending());
3585
3769
  }
3586
- async runGroupValidation() {
3587
- const value = this.computeValue();
3588
- let errors = null;
3589
- for (const validator of this._validators) {
3590
- const result = validator(value);
3591
- if (result !== null) errors = {
3592
- ...errors ?? {},
3593
- ...result
3594
- };
3595
- }
3596
- if (this._asyncValidators.length > 0 && errors === null) {
3597
- const asyncResults = await Promise.all(this._asyncValidators.map((v) => v(value)));
3598
- for (const result of asyncResults) if (result !== null) errors = {
3599
- ...errors ?? {},
3600
- ...result
3601
- };
3602
- }
3603
- this.errors.set(errors);
3770
+ hasInvalidChild() {
3771
+ return this.controls().some((c) => c.invalid());
3604
3772
  }
3605
3773
  };
3606
3774
  function createFormControl(initialValue, options) {
@@ -3609,19 +3777,32 @@ function createFormControl(initialValue, options) {
3609
3777
  function createFormGroup(controls, options) {
3610
3778
  return new FormGroup(controls, options);
3611
3779
  }
3780
+ function createFormArray(controls, options) {
3781
+ return new FormArray(controls, options);
3782
+ }
3783
+ registerDefaultMessages({
3784
+ required: "This field is required",
3785
+ minLength: (params) => `Minimum length is ${params.min} characters`,
3786
+ maxLength: (params) => `Maximum length is ${params.max} characters`,
3787
+ pattern: "Value does not match required pattern",
3788
+ email: "Please enter a valid email address",
3789
+ min: (params) => `Value must be at least ${params.min}`,
3790
+ max: (params) => `Value must be at most ${params.max}`,
3791
+ range: (params) => `Value must be between ${params.min} and ${params.max}`
3792
+ });
3793
+ var EMAIL_REGEX = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
3794
+ function isEmpty(value) {
3795
+ return value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0;
3796
+ }
3612
3797
  const Validators = {
3613
- required: (value) => {
3614
- return value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0 ? { required: {
3615
- code: "required",
3616
- message: "This field is required"
3617
- } } : null;
3798
+ required(value) {
3799
+ return isEmpty(value) ? { required: { code: "required" } } : null;
3618
3800
  },
3619
- minLength: (min) => {
3801
+ minLength(min) {
3620
3802
  return (value) => {
3621
3803
  if (!value || value.length === 0) return null;
3622
3804
  return value.length < min ? { minLength: {
3623
3805
  code: "minLength",
3624
- message: `Minimum length is ${min} characters`,
3625
3806
  params: {
3626
3807
  min,
3627
3808
  actual: value.length
@@ -3629,12 +3810,11 @@ const Validators = {
3629
3810
  } } : null;
3630
3811
  };
3631
3812
  },
3632
- maxLength: (max) => {
3813
+ maxLength(max) {
3633
3814
  return (value) => {
3634
3815
  if (!value) return null;
3635
3816
  return value.length > max ? { maxLength: {
3636
3817
  code: "maxLength",
3637
- message: `Maximum length is ${max} characters`,
3638
3818
  params: {
3639
3819
  max,
3640
3820
  actual: value.length
@@ -3642,29 +3822,24 @@ const Validators = {
3642
3822
  } } : null;
3643
3823
  };
3644
3824
  },
3645
- pattern: (regex) => {
3825
+ pattern(regex) {
3646
3826
  return (value) => {
3647
3827
  if (!value) return null;
3648
3828
  return !regex.test(value) ? { pattern: {
3649
3829
  code: "pattern",
3650
- message: "Value does not match required pattern",
3651
3830
  params: { pattern: regex.toString() }
3652
3831
  } } : null;
3653
3832
  };
3654
3833
  },
3655
- email: (value) => {
3834
+ email(value) {
3656
3835
  if (!value) return null;
3657
- return !/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value) ? { email: {
3658
- code: "email",
3659
- message: "Please enter a valid email address"
3660
- } } : null;
3836
+ return !EMAIL_REGEX.test(value) ? { email: { code: "email" } } : null;
3661
3837
  },
3662
- min: (minValue) => {
3838
+ min(minValue) {
3663
3839
  return (value) => {
3664
3840
  if (value === null || value === void 0) return null;
3665
3841
  return value < minValue ? { min: {
3666
3842
  code: "min",
3667
- message: `Value must be at least ${minValue}`,
3668
3843
  params: {
3669
3844
  min: minValue,
3670
3845
  actual: value
@@ -3672,12 +3847,11 @@ const Validators = {
3672
3847
  } } : null;
3673
3848
  };
3674
3849
  },
3675
- max: (maxValue) => {
3850
+ max(maxValue) {
3676
3851
  return (value) => {
3677
3852
  if (value === null || value === void 0) return null;
3678
3853
  return value > maxValue ? { max: {
3679
3854
  code: "max",
3680
- message: `Value must be at most ${maxValue}`,
3681
3855
  params: {
3682
3856
  max: maxValue,
3683
3857
  actual: value
@@ -3685,12 +3859,11 @@ const Validators = {
3685
3859
  } } : null;
3686
3860
  };
3687
3861
  },
3688
- range: (minValue, maxValue) => {
3862
+ range(minValue, maxValue) {
3689
3863
  return (value) => {
3690
3864
  if (value === null || value === void 0) return null;
3691
3865
  if (value < minValue || value > maxValue) return { range: {
3692
3866
  code: "range",
3693
- message: `Value must be between ${minValue} and ${maxValue}`,
3694
3867
  params: {
3695
3868
  min: minValue,
3696
3869
  max: maxValue,
@@ -3700,7 +3873,7 @@ const Validators = {
3700
3873
  return null;
3701
3874
  };
3702
3875
  },
3703
- compose: (...validators) => {
3876
+ compose(...validators) {
3704
3877
  return (value) => {
3705
3878
  let errors = null;
3706
3879
  for (const validator of validators) {
@@ -3713,7 +3886,7 @@ const Validators = {
3713
3886
  return errors;
3714
3887
  };
3715
3888
  },
3716
- composeAsync: (...validators) => {
3889
+ composeAsync(...validators) {
3717
3890
  return async (value) => {
3718
3891
  const results = await Promise.all(validators.map((v) => v(value)));
3719
3892
  let errors = null;
@@ -3725,56 +3898,99 @@ const Validators = {
3725
3898
  };
3726
3899
  }
3727
3900
  };
3728
- function createValidator(code, validationFn, message) {
3901
+ function createValidator(code, validationFn, defaultMessage) {
3902
+ if (defaultMessage !== void 0) setDefaultMessage(code, defaultMessage);
3729
3903
  return (value) => {
3730
3904
  if (validationFn(value)) return null;
3731
- return { [code]: {
3732
- code,
3733
- message: typeof message === "function" ? message(value) : message
3734
- } };
3905
+ return { [code]: { code } };
3735
3906
  };
3736
3907
  }
3737
- function createAsyncValidator(code, validationFn, message) {
3908
+ function createAsyncValidator(code, validationFn, defaultMessage) {
3909
+ if (defaultMessage !== void 0) setDefaultMessage(code, defaultMessage);
3738
3910
  return async (value) => {
3739
3911
  if (await validationFn(value)) return null;
3740
- return { [code]: {
3741
- code,
3742
- message: typeof message === "function" ? message(value) : message
3743
- } };
3912
+ return { [code]: { code } };
3744
3913
  };
3745
3914
  }
3746
- function isFormControl(value) {
3747
- return value !== null && typeof value === "object" && FORM_CONTROL_MARKER in value;
3915
+ var registry = [];
3916
+ function registerAdapter(predicate, adapter) {
3917
+ registry.unshift({
3918
+ predicate,
3919
+ adapter
3920
+ });
3921
+ }
3922
+ function getAdapter(element) {
3923
+ for (const entry of registry) if (entry.predicate(element)) return entry.adapter;
3748
3924
  }
3749
- function getInputType(element) {
3750
- const tagName = element.tagName.toLowerCase();
3751
- if (tagName === "select") return "select";
3752
- if (tagName === "textarea") return "textarea";
3753
- if (tagName === "input") {
3754
- const type = element.type.toLowerCase();
3755
- if (type === "checkbox") return "checkbox";
3756
- if (type === "radio") return "radio";
3757
- }
3758
- return "text";
3925
+ const textAdapter = {
3926
+ inputEvent: "input",
3927
+ blurEvent: "focusout",
3928
+ getValue(element) {
3929
+ return element.value ?? "";
3930
+ },
3931
+ setValue(element, value) {
3932
+ element.value = value !== null && value !== void 0 ? String(value) : "";
3933
+ },
3934
+ setDisabled(element, disabled) {
3935
+ if (disabled) element.setAttribute("disabled", "");
3936
+ else element.removeAttribute("disabled");
3937
+ }
3938
+ };
3939
+ const checkboxAdapter = {
3940
+ inputEvent: "change",
3941
+ blurEvent: "focusout",
3942
+ getValue(element) {
3943
+ return element.checked;
3944
+ },
3945
+ setValue(element, value) {
3946
+ element.checked = Boolean(value);
3947
+ },
3948
+ setDisabled(element, disabled) {
3949
+ if (disabled) element.setAttribute("disabled", "");
3950
+ else element.removeAttribute("disabled");
3951
+ }
3952
+ };
3953
+ const radioAdapter = {
3954
+ inputEvent: "change",
3955
+ blurEvent: "focusout",
3956
+ getValue(element) {
3957
+ const input = element;
3958
+ return input.checked ? input.value : "";
3959
+ },
3960
+ setValue(element, value) {
3961
+ const input = element;
3962
+ input.checked = input.value === value;
3963
+ },
3964
+ setDisabled(element, disabled) {
3965
+ if (disabled) element.setAttribute("disabled", "");
3966
+ else element.removeAttribute("disabled");
3967
+ }
3968
+ };
3969
+ function registerNativeAdapters() {
3970
+ registerAdapter((el) => el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT", textAdapter);
3971
+ registerAdapter((el) => el.tagName === "INPUT" && el.type === "radio", radioAdapter);
3972
+ registerAdapter((el) => el.tagName === "INPUT" && el.type === "checkbox", checkboxAdapter);
3759
3973
  }
3974
+ registerNativeAdapters();
3760
3975
  function formControlDirective(element, value, _) {
3761
- if (!isFormControl(value)) {
3762
- console.warn("formControl directive: value must be a FormControl");
3976
+ if (!(value instanceof AbstractControl)) {
3977
+ console.warn("formControl directive: value must be an AbstractControl");
3763
3978
  return;
3764
3979
  }
3765
3980
  const control = value;
3766
- const inputType = getInputType(element);
3981
+ const adapter = getAdapter(element);
3982
+ if (!adapter) {
3983
+ console.warn(`formControl directive: no adapter registered for <${element.tagName.toLowerCase()}>`);
3984
+ return;
3985
+ }
3767
3986
  const cleanupFns = [];
3768
- const setElementValue = (val) => {
3769
- if (inputType === "checkbox") element.checked = Boolean(val);
3770
- else if (inputType === "radio") element.checked = element.value === val;
3771
- else element.value = val !== null && val !== void 0 ? String(val) : "";
3987
+ const syncElementValue = (val) => {
3988
+ adapter.setValue(element, val);
3772
3989
  };
3773
- const setElementDisabled = (disabled) => {
3774
- if (disabled) element.setAttribute("disabled", "");
3775
- else element.removeAttribute("disabled");
3990
+ const syncDisabled = (disabled) => {
3991
+ adapter.setDisabled?.(element, disabled);
3776
3992
  };
3777
- const updateValidationClasses = () => {
3993
+ const syncClasses = () => {
3778
3994
  element.classList.toggle("mf-valid", control.valid());
3779
3995
  element.classList.toggle("mf-invalid", control.invalid());
3780
3996
  element.classList.toggle("mf-dirty", control.dirty());
@@ -3783,40 +3999,38 @@ function formControlDirective(element, value, _) {
3783
3999
  element.classList.toggle("mf-pending", control.pending());
3784
4000
  element.classList.toggle("mf-disabled", control.disabled());
3785
4001
  };
3786
- const handleInput = (e) => {
3787
- const target = e.target;
3788
- if (inputType === "checkbox") control.setValue(target.checked);
3789
- else if (inputType === "radio") {
3790
- if (target.checked) control.setValue(target.value);
3791
- } else control.setValue(target.value);
4002
+ const syncError = () => {
4003
+ if (!control.touched() || !control.errors()) {
4004
+ element.removeAttribute("error");
4005
+ return;
4006
+ }
4007
+ const message = control.getFirstErrorMessage();
4008
+ if (message) element.setAttribute("error", message);
4009
+ else element.removeAttribute("error");
4010
+ };
4011
+ const handleInput = (event) => {
4012
+ const target = event.target;
4013
+ if (target === element || element.contains(target)) control.setValue(adapter.getValue(element));
3792
4014
  };
3793
4015
  const handleBlur = () => {
3794
4016
  control.markAsTouched();
3795
4017
  };
3796
- setElementValue(control.value());
3797
- const unsubscribeValue = control.value.subscribe((newValue) => {
3798
- setElementValue(newValue);
3799
- });
3800
- cleanupFns.push(unsubscribeValue);
3801
- setElementDisabled(control.disabled());
3802
- const unsubscribeDisabled = control.disabled.subscribe((disabled) => {
3803
- setElementDisabled(disabled);
3804
- });
3805
- cleanupFns.push(unsubscribeDisabled);
3806
- const unsubscribeState = control.state.subscribe(() => {
3807
- updateValidationClasses();
3808
- });
3809
- cleanupFns.push(unsubscribeState);
3810
- updateValidationClasses();
3811
- const eventType = control.updateOn === "blur" ? "change" : "input";
3812
- element.addEventListener(eventType, handleInput);
3813
- element.addEventListener("blur", handleBlur);
4018
+ syncElementValue(control.value());
4019
+ syncDisabled(control.disabled());
4020
+ syncClasses();
4021
+ syncError();
4022
+ cleanupFns.push(control.value.subscribe((v) => syncElementValue(v)));
4023
+ cleanupFns.push(control.disabled.subscribe((d) => syncDisabled(d)));
4024
+ cleanupFns.push(control.state.subscribe(() => syncClasses()));
4025
+ cleanupFns.push(control.state.subscribe(() => syncError()));
4026
+ element.addEventListener(adapter.inputEvent, handleInput);
4027
+ element.addEventListener(adapter.blurEvent, handleBlur);
3814
4028
  element.setAttribute("data-form-control", "");
3815
4029
  return () => {
3816
- element.removeEventListener(eventType, handleInput);
3817
- element.removeEventListener("blur", handleBlur);
4030
+ element.removeEventListener(adapter.inputEvent, handleInput);
4031
+ element.removeEventListener(adapter.blurEvent, handleBlur);
3818
4032
  element.removeAttribute("data-form-control");
3819
- cleanupFns.forEach((fn) => fn());
4033
+ for (const fn of cleanupFns) fn();
3820
4034
  };
3821
4035
  }
3822
4036
  registerAttributeDirective("formControl", formControlDirective);
@@ -5984,6 +6198,17 @@ const inputStyles = () => css`
5984
6198
  flex-shrink: 0;
5985
6199
  }
5986
6200
  `;
6201
+ registerAdapter((el) => el.tagName === "ML-INPUT", {
6202
+ inputEvent: "ml:input",
6203
+ blurEvent: "focusout",
6204
+ getValue: (el) => el.value ?? "",
6205
+ setValue: (el, value) => {
6206
+ el.value = value !== null && value !== void 0 ? String(value) : "";
6207
+ },
6208
+ setDisabled: (el, disabled) => {
6209
+ el.disabled = disabled;
6210
+ }
6211
+ });
5987
6212
  var InputComponent = class InputComponent$1 {
5988
6213
  constructor() {
5989
6214
  this.type = "text";
@@ -6260,6 +6485,17 @@ const textareaStyles = () => css`
6260
6485
  font-size: var(--ml-text-base);
6261
6486
  }
6262
6487
  `;
6488
+ registerAdapter((el) => el.tagName === "ML-TEXTAREA", {
6489
+ inputEvent: "ml:input",
6490
+ blurEvent: "focusout",
6491
+ getValue: (el) => el.value ?? "",
6492
+ setValue: (el, value) => {
6493
+ el.value = value !== null && value !== void 0 ? String(value) : "";
6494
+ },
6495
+ setDisabled: (el, disabled) => {
6496
+ el.disabled = disabled;
6497
+ }
6498
+ });
6263
6499
  var TextareaComponent = class TextareaComponent$1 {
6264
6500
  constructor() {
6265
6501
  this.value = "";
@@ -6514,6 +6750,17 @@ const checkboxStyles = () => css`
6514
6750
  --ml-checkbox-label-line-height: 1.5rem;
6515
6751
  }
6516
6752
  `;
6753
+ registerAdapter((el) => el.tagName === "ML-CHECKBOX", {
6754
+ inputEvent: "ml:change",
6755
+ blurEvent: "focusout",
6756
+ getValue: (el) => Boolean(el.checked),
6757
+ setValue: (el, value) => {
6758
+ el.checked = Boolean(value);
6759
+ },
6760
+ setDisabled: (el, disabled) => {
6761
+ el.disabled = disabled;
6762
+ }
6763
+ });
6517
6764
  var CheckboxComponent = class CheckboxComponent$1 {
6518
6765
  constructor() {
6519
6766
  this.label = "";
@@ -6858,6 +7105,17 @@ const radioGroupStyles = () => css`
6858
7105
  color: var(--ml-color-danger);
6859
7106
  }
6860
7107
  `;
7108
+ registerAdapter((el) => el.tagName === "ML-RADIO-GROUP", {
7109
+ inputEvent: "ml:change",
7110
+ blurEvent: "focusout",
7111
+ getValue: (el) => el.value ?? "",
7112
+ setValue: (el, value) => {
7113
+ el.value = value !== null && value !== void 0 ? String(value) : "";
7114
+ },
7115
+ setDisabled: (el, disabled) => {
7116
+ el.disabled = disabled;
7117
+ }
7118
+ });
6861
7119
  var RadioGroupComponent = class RadioGroupComponent$1 {
6862
7120
  constructor() {
6863
7121
  this.label = "";
@@ -7549,6 +7807,17 @@ const toggleStyles = () => css`
7549
7807
  line-height: var(--ml-leading-tight);
7550
7808
  }
7551
7809
  `;
7810
+ registerAdapter((el) => el.tagName === "ML-TOGGLE", {
7811
+ inputEvent: "ml:change",
7812
+ blurEvent: "focusout",
7813
+ getValue: (el) => Boolean(el.checked),
7814
+ setValue: (el, value) => {
7815
+ el.checked = Boolean(value);
7816
+ },
7817
+ setDisabled: (el, disabled) => {
7818
+ el.disabled = disabled;
7819
+ }
7820
+ });
7552
7821
  var ToggleComponent = class ToggleComponent$1 {
7553
7822
  constructor() {
7554
7823
  this.label = "";
@@ -8115,6 +8384,22 @@ const selectStyles = () => css`
8115
8384
  pointer-events: none;
8116
8385
  }
8117
8386
  `;
8387
+ registerAdapter((el) => el.tagName === "ML-SELECT", {
8388
+ inputEvent: "ml:change",
8389
+ blurEvent: "focusout",
8390
+ getValue: (el) => {
8391
+ const e = el;
8392
+ return e.multiple ? e.values ?? [] : e.value ?? "";
8393
+ },
8394
+ setValue: (el, value) => {
8395
+ const e = el;
8396
+ if (Array.isArray(value)) e.values = value;
8397
+ else e.value = value !== null && value !== void 0 ? String(value) : "";
8398
+ },
8399
+ setDisabled: (el, disabled) => {
8400
+ el.disabled = disabled;
8401
+ }
8402
+ });
8118
8403
  var SelectComponent = class SelectComponent$1 {
8119
8404
  constructor() {
8120
8405
  this.label = "";
@@ -8687,6 +8972,17 @@ const sliderStyles = () => css`
8687
8972
  color: var(--ml-slider-error-color);
8688
8973
  }
8689
8974
  `;
8975
+ registerAdapter((el) => el.tagName === "ML-SLIDER", {
8976
+ inputEvent: "ml:input",
8977
+ blurEvent: "focusout",
8978
+ getValue: (el) => Number(el.value) || 0,
8979
+ setValue: (el, value) => {
8980
+ el.value = Number(value) || 0;
8981
+ },
8982
+ setDisabled: (el, disabled) => {
8983
+ el.disabled = disabled;
8984
+ }
8985
+ });
8690
8986
  var SliderComponent = class SliderComponent$1 {
8691
8987
  constructor() {
8692
8988
  this.label = "";
@@ -10229,6 +10525,17 @@ const datePickerStyles = () => css`
10229
10525
  color: var(--ml-date-picker-error-color);
10230
10526
  }
10231
10527
  `;
10528
+ registerAdapter((el) => el.tagName === "ML-DATE-PICKER", {
10529
+ inputEvent: "ml:select",
10530
+ blurEvent: "focusout",
10531
+ getValue: (el) => el.value ?? "",
10532
+ setValue: (el, value) => {
10533
+ el.value = value !== null && value !== void 0 ? String(value) : "";
10534
+ },
10535
+ setDisabled: (el, disabled) => {
10536
+ el.disabled = disabled;
10537
+ }
10538
+ });
10232
10539
  var DatePickerComponent = class DatePickerComponent$1 {
10233
10540
  constructor() {
10234
10541
  this.value = "";
@@ -12023,6 +12330,7 @@ const badgeStyles = () => css`
12023
12330
 
12024
12331
  /* ── Badge: dot ── */
12025
12332
  --ml-badge-dot-size: 0.375rem;
12333
+ --ml-badge-dot-size-xs: 0.3125rem;
12026
12334
  --ml-badge-dot-size-lg: 0.5rem;
12027
12335
 
12028
12336
  /* ── Badge: secondary variant ── */
@@ -12060,6 +12368,16 @@ const badgeStyles = () => css`
12060
12368
  height: var(--ml-badge-dot-size-lg);
12061
12369
  }
12062
12370
 
12371
+ .ml-badge--xs .ml-badge__dot {
12372
+ width: var(--ml-badge-dot-size-xs);
12373
+ height: var(--ml-badge-dot-size-xs);
12374
+ }
12375
+
12376
+ .ml-badge--xs {
12377
+ padding: 1px var(--ml-space-1-5);
12378
+ font-size: 0.6875rem;
12379
+ }
12380
+
12063
12381
  .ml-badge--sm {
12064
12382
  padding: 2px var(--ml-space-2);
12065
12383
  font-size: var(--ml-text-xs);
@@ -25225,6 +25543,6 @@ DashboardPageComponent = __decorate([MelodicComponent({
25225
25543
  "layout"
25226
25544
  ]
25227
25545
  })], DashboardPageComponent);
25228
- export { APP_CONFIG, AbortError, ActivityFeedComponent, ActivityFeedItemComponent, AlertComponent, AppShellComponent, AvatarComponent, BadgeComponent, BadgeGroupComponent, Binding, BreadcrumbComponent, BreadcrumbItemComponent, ButtonComponent, ButtonGroupComponent, ButtonGroupItemComponent, CalendarComponent, CalendarViewComponent, CardComponent, CheckboxComponent, ComponentBase, ComponentStateBaseService, ContainerComponent, DashboardPageComponent, DatePickerComponent, DialogComponent, DialogRef, DialogService, Directive, DividerComponent, DrawerComponent, DropdownComponent, DropdownGroupComponent, DropdownItemComponent, DropdownSeparatorComponent, EffectsBase, FORM_CONTROL_MARKER, FORM_GROUP_MARKER, FormControl, FormFieldComponent, FormGroup, HeroSectionComponent, HttpBaseError, HttpClient, HttpError, IconComponent, Inject, Injectable, InjectionEngine, Injector, InputComponent, ListComponent, ListItemComponent, LoginPageComponent, MelodicComponent, NetworkError, PageHeaderComponent, PaginationComponent, PopoverComponent, ProgressComponent, ROUTE_CONTEXT_EVENT, RX_ACTION_PROVIDERS, RX_EFFECTS_PROVIDERS, RX_INIT_STATE, RX_STATE_DEBUG, RadioCardComponent, RadioCardGroupComponent, RadioComponent, RadioGroupComponent, RouteContextEvent, RouteContextService, RouteMatcher, RouterLinkComponent, RouterOutletComponent, RouterService, SIGNAL_MARKER, SelectComponent, Service, SidebarComponent, SidebarGroupComponent, SidebarItemComponent, SignalEffect, SignalStoreService, SignupPageComponent, SliderComponent, SpinnerComponent, StackComponent, StepComponent, StepPanelComponent, StepsComponent, TabComponent, TabPanelComponent, TableComponent, TabsComponent, TagComponent, TemplateResult, TextareaComponent, ToastComponent, ToastContainerComponent, ToastService, ToggleComponent, TooltipComponent, Validators, VirtualScroller, activityFeedItemStyles, activityFeedItemTemplate, activityFeedStyles, activityFeedTemplate, allTokens, announce, appShellStyles, appShellTemplate, applyGlobalStyles, applyTheme, arrow, autoUpdate, baseThemeCss, bootstrap, borderTokens, breadcrumbItemStyles, breadcrumbItemTemplate, breadcrumbStyles, breadcrumbTemplate, breakpointTokens, breakpoints, buildPathFromRoute, calendarViewStyles, calendarViewTemplate, classMap, clickOutside, colorTokens, componentBaseStyles, computePosition, computed, containerStyles, containerTemplate, createAction, createAsyncValidator, createBrandTheme, createDeactivateGuard, createFocusTrap, createFormControl, createFormGroup, createGuard, createLiveRegion, createReducer, createResolver, createState, createTheme, createToken, createValidator, css, darkTheme, darkThemeCss, dashboardPageStyles, dashboardPageTemplate, defineConfig, directive, drawerStyles, drawerTemplate, dropdownGroupStyles, dropdownGroupTemplate, dropdownItemStyles, dropdownItemTemplate, dropdownSeparatorStyles, dropdownSeparatorTemplate, dropdownStyles, dropdownTemplate, environment, findRouteByName, flip, focusFirst, focusLast, focusTrap, focusVisible, formControlDirective, formFieldStyles, formFieldTemplate, getActiveEffect, getAttributeDirective, getEnvironment, getFirstFocusable, getFocusableElements, getLastFocusable, getRegisteredDirectives, getResolvedTheme, getTheme, getTokenKey, hasAttributeDirective, heroSectionStyles, heroSectionTemplate, html, injectTheme, isDirective, isFocusVisible, isSignal, lightTheme, lightThemeCss, listItemStyles, listItemTemplate, listStyles, listTemplate, loginPageStyles, loginPageTemplate, matchRouteTree, newID, offset, onAction, onThemeChange, pageHeaderStyles, pageHeaderTemplate, paginationStyles, paginationTemplate, portalDirective, primitiveColors, progressStyles, progressTemplate, props, provideConfig, provideHttp, provideRX, registerAttributeDirective, render, repeat, repeatRaw, resetStyles, routerLinkDirective, selectStyles, selectTemplate, setActiveEffect, shadowTokens, shift, sidebarGroupStyles, sidebarGroupTemplate, sidebarItemStyles, sidebarItemTemplate, sidebarStyles, sidebarTemplate, signal, signupPageStyles, signupPageTemplate, sliderStyles, sliderTemplate, spacingTokens, stepPanelStyles, stepPanelTemplate, stepStyles, stepTemplate, stepsStyles, stepsTemplate, styleMap, tabPanelStyles, tabPanelTemplate, tabStyles, tabTemplate, tableStyles, tableTemplate, tabsStyles, tabsTemplate, toastContainerStyles, toastContainerTemplate, toastStyles, toastTemplate, toggleTheme, tokensToCss, tooltipDirective, transitionTokens, typographyTokens, unregisterAttributeDirective, unsafeHTML, visuallyHiddenStyles, when };
25546
+ export { APP_CONFIG, AbortError, AbstractControl, ActivityFeedComponent, ActivityFeedItemComponent, AlertComponent, AppShellComponent, AvatarComponent, BadgeComponent, BadgeGroupComponent, Binding, BreadcrumbComponent, BreadcrumbItemComponent, ButtonComponent, ButtonGroupComponent, ButtonGroupItemComponent, CalendarComponent, CalendarViewComponent, CardComponent, CheckboxComponent, ComponentBase, ComponentStateBaseService, ContainerComponent, DashboardPageComponent, DatePickerComponent, DialogComponent, DialogRef, DialogService, Directive, DividerComponent, DrawerComponent, DropdownComponent, DropdownGroupComponent, DropdownItemComponent, DropdownSeparatorComponent, EffectsBase, FormArray, FormControl, FormFieldComponent, FormGroup, HeroSectionComponent, HttpBaseError, HttpClient, HttpError, IconComponent, Inject, Injectable, InjectionEngine, Injector, InputComponent, ListComponent, ListItemComponent, LoginPageComponent, MelodicComponent, NetworkError, PageHeaderComponent, PaginationComponent, PopoverComponent, ProgressComponent, ROUTE_CONTEXT_EVENT, RX_ACTION_PROVIDERS, RX_EFFECTS_PROVIDERS, RX_INIT_STATE, RX_STATE_DEBUG, RadioCardComponent, RadioCardGroupComponent, RadioComponent, RadioGroupComponent, RouteContextEvent, RouteContextService, RouteMatcher, RouterLinkComponent, RouterOutletComponent, RouterService, SIGNAL_MARKER, SelectComponent, Service, SidebarComponent, SidebarGroupComponent, SidebarItemComponent, SignalEffect, SignalStoreService, SignupPageComponent, SliderComponent, SpinnerComponent, StackComponent, StepComponent, StepPanelComponent, StepsComponent, TabComponent, TabPanelComponent, TableComponent, TabsComponent, TagComponent, TemplateResult, TextareaComponent, ToastComponent, ToastContainerComponent, ToastService, ToggleComponent, TooltipComponent, Validators, VirtualScroller, activityFeedItemStyles, activityFeedItemTemplate, activityFeedStyles, activityFeedTemplate, allTokens, announce, appShellStyles, appShellTemplate, applyGlobalStyles, applyTheme, arrow, autoUpdate, baseThemeCss, bootstrap, borderTokens, breadcrumbItemStyles, breadcrumbItemTemplate, breadcrumbStyles, breadcrumbTemplate, breakpointTokens, breakpoints, buildPathFromRoute, calendarViewStyles, calendarViewTemplate, checkboxAdapter, classMap, clickOutside, colorTokens, componentBaseStyles, computePosition, computed, containerStyles, containerTemplate, createAction, createAsyncValidator, createBrandTheme, createDeactivateGuard, createFocusTrap, createFormArray, createFormControl, createFormGroup, createGuard, createLiveRegion, createReducer, createResolver, createState, createTheme, createToken, createValidator, css, darkTheme, darkThemeCss, dashboardPageStyles, dashboardPageTemplate, defineConfig, directive, drawerStyles, drawerTemplate, dropdownGroupStyles, dropdownGroupTemplate, dropdownItemStyles, dropdownItemTemplate, dropdownSeparatorStyles, dropdownSeparatorTemplate, dropdownStyles, dropdownTemplate, environment, findRouteByName, flip, focusFirst, focusLast, focusTrap, focusVisible, formControlDirective, formFieldStyles, formFieldTemplate, getActiveEffect, getAdapter, getAttributeDirective, getEnvironment, getFirstFocusable, getFocusableElements, getGlobalMessage, getLastFocusable, getRegisteredDirectives, getResolvedTheme, getTheme, getTokenKey, hasAttributeDirective, heroSectionStyles, heroSectionTemplate, html, injectTheme, isDirective, isFocusVisible, isSignal, lightTheme, lightThemeCss, listItemStyles, listItemTemplate, listStyles, listTemplate, loginPageStyles, loginPageTemplate, matchRouteTree, newID, offset, onAction, onThemeChange, pageHeaderStyles, pageHeaderTemplate, paginationStyles, paginationTemplate, portalDirective, primitiveColors, progressStyles, progressTemplate, props, provideConfig, provideHttp, provideRX, radioAdapter, registerAdapter, registerAttributeDirective, registerDefaultMessages, render, repeat, repeatRaw, resetStyles, resolveMessage, routerLinkDirective, selectStyles, selectTemplate, setActiveEffect, setDefaultMessage, shadowTokens, shift, sidebarGroupStyles, sidebarGroupTemplate, sidebarItemStyles, sidebarItemTemplate, sidebarStyles, sidebarTemplate, signal, signupPageStyles, signupPageTemplate, sliderStyles, sliderTemplate, spacingTokens, stepPanelStyles, stepPanelTemplate, stepStyles, stepTemplate, stepsStyles, stepsTemplate, styleMap, tabPanelStyles, tabPanelTemplate, tabStyles, tabTemplate, tableStyles, tableTemplate, tabsStyles, tabsTemplate, textAdapter, toastContainerStyles, toastContainerTemplate, toastStyles, toastTemplate, toggleTheme, tokensToCss, tooltipDirective, transitionTokens, typographyTokens, unregisterAttributeDirective, unsafeHTML, visuallyHiddenStyles, when };
25229
25547
 
25230
25548
  //# sourceMappingURL=melodic-components.js.map