@ctrliq/quantic-components 1.63.2 → 1.63.4

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.
@@ -15,6 +15,7 @@ import { LucideIconCircleAlert } from '../icon/__generated__/lucide/circle-alert
15
15
  import { NumberInputSize } from './index.constants';
16
16
  import { A11yAttributesMixin } from '../shared/a11y-attributes.mixin';
17
17
  import { event, prop } from '../shared/component-meta.decorators';
18
+ import { emitValueChanged } from '../shared/shared.utils';
18
19
  export { NumberInputSize } from './index.constants';
19
20
  LucideIconChevronUp.ensureDefined();
20
21
  LucideIconChevronDown.ensureDefined();
@@ -48,6 +49,7 @@ let NumberInput = class NumberInput extends A11yAttributesMixin(QuanticElement)
48
49
  if (changedProperties.has('value')) {
49
50
  this.updateValidity();
50
51
  }
52
+ emitValueChanged(this, changedProperties, this.value);
51
53
  }
52
54
  stepUp() {
53
55
  this.inputRef.value?.stepUp();
@@ -60,12 +62,6 @@ let NumberInput = class NumberInput extends A11yAttributesMixin(QuanticElement)
60
62
  syncValue() {
61
63
  const raw = this.inputRef.value?.valueAsNumber;
62
64
  this.value = raw !== undefined && !isNaN(raw) ? raw : null;
63
- this.updateValidity();
64
- this.dispatchEvent(new CustomEvent('value-changed', {
65
- detail: { value: this.value },
66
- bubbles: true,
67
- composed: true,
68
- }));
69
65
  }
70
66
  updateValidity() {
71
67
  const inputEl = this.inputRef.value;
@@ -417,7 +413,7 @@ __decorate([
417
413
  ], NumberInput.prototype, "invalid", void 0);
418
414
  NumberInput = __decorate([
419
415
  event('value-changed', {
420
- description: "Fired whenever the input's value is updated (on input, change, or stepper click).",
416
+ description: 'Fired whenever the value changes, from user input, stepper click, or a programmatic update. Not fired on initial render.',
421
417
  detail: '{ value: number | null }',
422
418
  }),
423
419
  event('input', { forwarded: true }),
@@ -4598,6 +4598,33 @@
4598
4598
  function compact(items) {
4599
4599
  return items.filter((item) => item != null && item !== '');
4600
4600
  }
4601
+ /**
4602
+ * Dispatches the standard `value-changed` event for a form control from its
4603
+ * `updated()` lifecycle, so it fires on real changes — user input *and*
4604
+ * programmatic `el.value = ...` updates — but not on the initial render.
4605
+ *
4606
+ * Lit records the old value as `undefined` for any change made before the first
4607
+ * update, so `changed.get(key) !== undefined` reliably skips initial hydration
4608
+ * even when the value was set imperatively beforehand.
4609
+ *
4610
+ * @example
4611
+ * updated(changed: Map<string, unknown>) {
4612
+ * if (changed.has('value')) {
4613
+ * this.internals.setFormValue(this.value);
4614
+ * this.updateValidity();
4615
+ * }
4616
+ * emitValueChanged(this, changed, this.value);
4617
+ * }
4618
+ */
4619
+ function emitValueChanged(host, changed, value, key = 'value') {
4620
+ if (changed.has(key) && changed.get(key) !== undefined) {
4621
+ host.dispatchEvent(new CustomEvent('value-changed', {
4622
+ detail: { value },
4623
+ bubbles: true,
4624
+ composed: true,
4625
+ }));
4626
+ }
4627
+ }
4601
4628
 
4602
4629
  const ComboboxSize = {
4603
4630
  ExtraSmall: 'xs',
@@ -4758,8 +4785,8 @@
4758
4785
  this._activeIndex = -1;
4759
4786
  this.cleanup?.();
4760
4787
  this.cleanup = undefined;
4761
- if (this.allowCustomValue && commit) {
4762
- this.commitCustomValue();
4788
+ if (commit && (this.allowCustomValue || !this._inputValue.trim())) {
4789
+ this.commitInputValue();
4763
4790
  }
4764
4791
  else {
4765
4792
  const selected = this.options.find((o) => o.value === this.value);
@@ -4767,7 +4794,7 @@
4767
4794
  selected?.label ?? (this.allowCustomValue ? this.value : '');
4768
4795
  }
4769
4796
  }
4770
- commitCustomValue() {
4797
+ commitInputValue() {
4771
4798
  const trimmed = this._inputValue.trim();
4772
4799
  this._inputValue = trimmed;
4773
4800
  if (trimmed === this.value)
@@ -4865,10 +4892,10 @@
4865
4892
  this.selectOption(opt);
4866
4893
  }
4867
4894
  }
4868
- else if (this.allowCustomValue && this._inputValue.trim()) {
4895
+ else if (this._open &&
4896
+ (this.allowCustomValue || !this._inputValue.trim())) {
4869
4897
  e.preventDefault();
4870
4898
  this.closeList(true);
4871
- this.commitCustomValue();
4872
4899
  }
4873
4900
  break;
4874
4901
  case 'Escape':
@@ -5399,7 +5426,7 @@
5399
5426
  ], exports.Combobox.prototype, "_activeIndex", void 0);
5400
5427
  exports.Combobox = __decorate([
5401
5428
  event('value-changed', {
5402
- description: 'Fired when the user selects an option from the list, or commits a custom value when allowCustomValue is enabled.',
5429
+ description: 'Fired when the user selects an option from the list, clears the field, or commits a custom value when allowCustomValue is enabled.',
5403
5430
  detail: '{ value: string }',
5404
5431
  }),
5405
5432
  event('input-changed', {
@@ -7350,18 +7377,10 @@
7350
7377
  this.updateValidity();
7351
7378
  this.lineCount = Math.max(1, this.value.split('\n').length);
7352
7379
  }
7380
+ emitValueChanged(this, changedProperties, this.value);
7353
7381
  }
7354
7382
  handleInput(e) {
7355
- const textarea = e.target;
7356
- this.value = textarea.value;
7357
- this.lineCount = Math.max(1, this.value.split('\n').length);
7358
- this.internals.setFormValue(this.value);
7359
- this.updateValidity();
7360
- this.dispatchEvent(new CustomEvent('value-changed', {
7361
- detail: { value: this.value },
7362
- bubbles: true,
7363
- composed: true,
7364
- }));
7383
+ this.value = e.target.value;
7365
7384
  }
7366
7385
  forwardNative(e) {
7367
7386
  const baseInit = {
@@ -7717,7 +7736,7 @@
7717
7736
  ], exports.CodeInput.prototype, "lineCount", void 0);
7718
7737
  exports.CodeInput = __decorate([
7719
7738
  event('value-changed', {
7720
- description: "Fired whenever the textarea's value is updated (on input).",
7739
+ description: 'Fired whenever the value changes, from user input or a programmatic update. Not fired on initial render.',
7721
7740
  detail: '{ value: string }',
7722
7741
  }),
7723
7742
  event('change', { forwarded: true }),
@@ -12289,6 +12308,7 @@
12289
12308
  this.internals.setFormValue(this.value);
12290
12309
  this.updateValidity();
12291
12310
  }
12311
+ emitValueChanged(this, changedProperties, this.value);
12292
12312
  }
12293
12313
  forwardNative(e) {
12294
12314
  const target = e.target;
@@ -12302,16 +12322,7 @@
12302
12322
  }
12303
12323
  }
12304
12324
  dispatchValueChanged(e) {
12305
- const inputEl = e.target;
12306
- this.value = inputEl.value;
12307
- // Update form value
12308
- this.internals.setFormValue(this.value);
12309
- this.updateValidity();
12310
- this.dispatchEvent(new CustomEvent('value-changed', {
12311
- detail: { value: this.value },
12312
- bubbles: true,
12313
- composed: true,
12314
- }));
12325
+ this.value = e.target.value;
12315
12326
  }
12316
12327
  formResetCallback() {
12317
12328
  this.value = '';
@@ -12611,7 +12622,7 @@
12611
12622
  ], exports.TextInput.prototype, "showPassword", void 0);
12612
12623
  exports.TextInput = __decorate([
12613
12624
  event('value-changed', {
12614
- description: 'Fired on every input and change event.',
12625
+ description: 'Fired whenever the value changes, from user input or a programmatic update. Not fired on initial render.',
12615
12626
  detail: '{ value: string }',
12616
12627
  }),
12617
12628
  event('input', { forwarded: true }),
@@ -12681,13 +12692,7 @@
12681
12692
  this._slottedOptions = [];
12682
12693
  }
12683
12694
  dispatchValueChanged(e) {
12684
- const selectEl = e.target;
12685
- this.value = selectEl.value;
12686
- this.dispatchEvent(new CustomEvent('value-changed', {
12687
- detail: { value: this.value },
12688
- bubbles: true,
12689
- composed: true,
12690
- }));
12695
+ this.value = e.target.value;
12691
12696
  }
12692
12697
  openDropdown(e) {
12693
12698
  if (!this.disabled) {
@@ -12706,6 +12711,7 @@
12706
12711
  select.value = option[1];
12707
12712
  }
12708
12713
  }
12714
+ emitValueChanged(this, changed, this.value);
12709
12715
  }
12710
12716
  forwardNative(e) {
12711
12717
  this.dispatchEvent(new Event(e.type, { bubbles: true, composed: true }));
@@ -12935,7 +12941,7 @@
12935
12941
  ], exports.Select.prototype, "invalid", void 0);
12936
12942
  exports.Select = __decorate([
12937
12943
  event('value-changed', {
12938
- description: "Fired whenever the input's value is updated (on input & change).",
12944
+ description: 'Fired whenever the value changes, from user selection or a programmatic update. Not fired on initial render.',
12939
12945
  detail: '{ value: string }',
12940
12946
  }),
12941
12947
  event('focus', { forwarded: true }),
@@ -62213,6 +62219,7 @@
62213
62219
  if (changedProperties.has('value')) {
62214
62220
  this.updateValidity();
62215
62221
  }
62222
+ emitValueChanged(this, changedProperties, this.value);
62216
62223
  }
62217
62224
  stepUp() {
62218
62225
  this.inputRef.value?.stepUp();
@@ -62225,12 +62232,6 @@
62225
62232
  syncValue() {
62226
62233
  const raw = this.inputRef.value?.valueAsNumber;
62227
62234
  this.value = raw !== undefined && !isNaN(raw) ? raw : null;
62228
- this.updateValidity();
62229
- this.dispatchEvent(new CustomEvent('value-changed', {
62230
- detail: { value: this.value },
62231
- bubbles: true,
62232
- composed: true,
62233
- }));
62234
62235
  }
62235
62236
  updateValidity() {
62236
62237
  const inputEl = this.inputRef.value;
@@ -62582,7 +62583,7 @@
62582
62583
  ], exports.NumberInput.prototype, "invalid", void 0);
62583
62584
  exports.NumberInput = __decorate([
62584
62585
  event('value-changed', {
62585
- description: "Fired whenever the input's value is updated (on input, change, or stepper click).",
62586
+ description: 'Fired whenever the value changes, from user input, stepper click, or a programmatic update. Not fired on initial render.',
62586
62587
  detail: '{ value: number | null }',
62587
62588
  }),
62588
62589
  event('input', { forwarded: true }),
@@ -68534,6 +68535,7 @@
68534
68535
  this.internals.setFormValue(this.value);
68535
68536
  this.updateValidity();
68536
68537
  }
68538
+ emitValueChanged(this, changedProperties, this.value);
68537
68539
  }
68538
68540
  forwardNative(e) {
68539
68541
  const target = e.target;
@@ -68541,15 +68543,7 @@
68541
68543
  this.dispatchEvent(new Event(e.type, { bubbles: true, composed: true }));
68542
68544
  }
68543
68545
  dispatchValueChanged(e) {
68544
- const textareaEl = e.target;
68545
- this.value = textareaEl.value;
68546
- this.internals.setFormValue(this.value);
68547
- this.updateValidity();
68548
- this.dispatchEvent(new CustomEvent('value-changed', {
68549
- detail: { value: this.value },
68550
- bubbles: true,
68551
- composed: true,
68552
- }));
68546
+ this.value = e.target.value;
68553
68547
  }
68554
68548
  formResetCallback() {
68555
68549
  this.value = '';
@@ -68810,7 +68804,7 @@
68810
68804
  ], exports.Textarea.prototype, "autoComplete", void 0);
68811
68805
  exports.Textarea = __decorate([
68812
68806
  event('value-changed', {
68813
- description: 'Fired on every input and change event.',
68807
+ description: 'Fired whenever the value changes, from user input or a programmatic update. Not fired on initial render.',
68814
68808
  detail: '{ value: string }',
68815
68809
  }),
68816
68810
  event('input', { forwarded: true }),