udp-stencil-component-library 26.3.0-beta.21 → 26.3.0-beta.22

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.
@@ -13,7 +13,6 @@ const UdpFluentNumberInput = class {
13
13
  this.valueChanged = index.createEvent(this, "valueChanged", 7);
14
14
  this.inputBlur = index.createEvent(this, "inputBlur", 7);
15
15
  this.inputFocus = index.createEvent(this, "inputFocus", 7);
16
- this.liveValue = null;
17
16
  /** Whether to include error padding below the input. */
18
17
  this.includeErrorPadding = true;
19
18
  /** Whether the input is required for form submission. */
@@ -30,51 +29,75 @@ const UdpFluentNumberInput = class {
30
29
  this.appearance = 'outline';
31
30
  /** The size of the input control. */
32
31
  this.controlSize = 'medium';
32
+ this.handleKeyDown = (ev) => {
33
+ var _a, _b, _c, _d, _e;
34
+ const { key, ctrlKey, metaKey } = ev;
35
+ if (ctrlKey || metaKey)
36
+ return;
37
+ if (['Backspace', 'Delete', 'Tab', 'Enter', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(key))
38
+ return;
39
+ if (key === 'ArrowUp' || key === 'ArrowDown') {
40
+ this.handleStep(key === 'ArrowUp' ? 1 : -1);
41
+ ev.preventDefault();
42
+ return;
43
+ }
44
+ // Block scientific notation keys not useful in a form number input
45
+ if (key === 'e' || key === 'E' || key === '+') {
46
+ ev.preventDefault();
47
+ return;
48
+ }
49
+ // Block decimal point for integer-only inputs, or if one already exists
50
+ if (key === '.') {
51
+ if (this.decimals === 0) {
52
+ ev.preventDefault();
53
+ return;
54
+ }
55
+ const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
56
+ if (nativeInput === null || nativeInput === void 0 ? void 0 : nativeInput.value.includes('.'))
57
+ ev.preventDefault();
58
+ return;
59
+ }
60
+ // For digit keys, enforce decimal place limit
61
+ if (/^\d$/.test(key)) {
62
+ if (this.decimals != null && this.decimals > 0) {
63
+ const nativeInput = (_d = (_c = this.internalInput) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('input');
64
+ if (nativeInput) {
65
+ const value = nativeInput.value;
66
+ const dotIndex = value.indexOf('.');
67
+ if (dotIndex !== -1) {
68
+ const cursorAfterDot = ((_e = nativeInput.selectionEnd) !== null && _e !== void 0 ? _e : value.length) > dotIndex;
69
+ const decimalsFilled = value.length - dotIndex - 1 >= this.decimals;
70
+ if (cursorAfterDot && decimalsFilled)
71
+ ev.preventDefault();
72
+ }
73
+ }
74
+ }
75
+ return;
76
+ }
77
+ // Allow minus sign for negative numbers; block everything else (letters, etc.)
78
+ if (key !== '-')
79
+ ev.preventDefault();
80
+ };
33
81
  this.handleInput = (ev) => {
34
82
  ev.stopPropagation();
35
83
  const target = ev.target;
36
- this.liveValue = target.value;
37
84
  this.valueChanged.emit(target.value);
38
85
  };
39
86
  this.handleBlur = () => {
40
- var _a, _b;
41
- if (this.decimals != null && this.internalInput) {
42
- const raw = parseFloat((_b = (_a = this.liveValue) !== null && _a !== void 0 ? _a : this.value) !== null && _b !== void 0 ? _b : '');
43
- if (!isNaN(raw)) {
44
- const formatted = raw.toFixed(this.decimals);
45
- this.internalInput.value = formatted;
46
- this.liveValue = formatted;
47
- this.valueChanged.emit(formatted);
48
- }
49
- }
50
87
  this.inputBlur.emit();
51
88
  };
52
89
  }
90
+ // Sync controlled value updates to the inner input without going through the render
91
+ // cycle — avoids FAST's setter resetting cursor on unrelated re-renders (e.g. error prop).
92
+ onValuePropChange(newValue) {
93
+ if (this.internalInput) {
94
+ this.internalInput.value = newValue !== null && newValue !== void 0 ? newValue : '';
95
+ }
96
+ }
53
97
  componentDidLoad() {
54
98
  if (this.internalInput && this.value != null) {
55
99
  this.internalInput.value = this.value;
56
100
  }
57
- this.applyNumberAttrs();
58
- }
59
- componentDidUpdate() {
60
- this.applyNumberAttrs();
61
- }
62
- // fluent-text-input doesn't proxy min/max/step to its inner <input>, so we set them directly.
63
- // We also set inputmode="decimal" so mobile keyboards show a numeric pad.
64
- // NOTE: we do NOT forward type="number" to fluent-text-input because FAST's inputHandler
65
- // reads input.value and writes it back via its setter. For type="number" in Chrome, this
66
- // resets the cursor to position 0 whenever an intermediate decimal value (e.g. "3.") causes
67
- // the browser's value-sanitisation to return the previous valid number ("3"), scrambling
68
- // subsequent keystrokes into the wrong order (e.g. "3.14159" → "141593").
69
- applyNumberAttrs() {
70
- var _a, _b, _c, _d, _e;
71
- const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
72
- if (!nativeInput)
73
- return;
74
- nativeInput.setAttribute('inputmode', 'decimal');
75
- nativeInput.min = (_c = this.min) !== null && _c !== void 0 ? _c : '';
76
- nativeInput.max = (_d = this.max) !== null && _d !== void 0 ? _d : '';
77
- nativeInput.step = (_e = this.step) !== null && _e !== void 0 ? _e : '';
78
101
  }
79
102
  /** Selects the text in the input. */
80
103
  select() {
@@ -82,17 +105,41 @@ const UdpFluentNumberInput = class {
82
105
  (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.select();
83
106
  return Promise.resolve();
84
107
  }
108
+ handleStep(direction) {
109
+ var _a, _b, _c;
110
+ const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
111
+ if (!nativeInput)
112
+ return;
113
+ const rawStep = this.step != null && this.step !== '' ? parseFloat(this.step) : 1;
114
+ const stepSize = isNaN(rawStep) ? 1 : rawStep;
115
+ const current = parseFloat(nativeInput.value);
116
+ const base = isNaN(current) ? 0 : current;
117
+ const next = base + direction * stepSize;
118
+ const stepStr = (_c = this.step) !== null && _c !== void 0 ? _c : '1';
119
+ const dotIdx = stepStr.indexOf('.');
120
+ const decimalPlaces = dotIdx !== -1 ? stepStr.length - dotIdx - 1 : 0;
121
+ const newValue = next.toFixed(decimalPlaces);
122
+ if (this.internalInput) {
123
+ this.internalInput.value = newValue;
124
+ }
125
+ this.valueChanged.emit(newValue);
126
+ }
85
127
  render() {
86
128
  const hasError = !!this.error;
87
129
  const message = this.error || this.hint;
88
130
  const noMessage = !message && !this.includeErrorPadding;
89
- return (index.h(index.Host, { key: 'f87601660bf0d04ca3a617768a6178a9b83b3c39', class: { 'has-error': hasError } }, index.h("fluent-field", { key: '0a6bfa77b060b198f431cfd01dce8626d22b795c', class: { 'no-message': noMessage } }, index.h("fluent-text-input", { key: '70ee74cccec3b0223e4c36f6bec74a167dd66d8b', ref: el => (this.internalInput = el), slot: "input", class: { 'no-label': !this.label }, name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, disabled: this.disabled, readonly: this.readonly, autofocus: this.autofocus, autocomplete: this.autocomplete, spellcheck: "false", appearance: this.appearance, controlSize: this.controlSize, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: () => this.inputFocus.emit(), onInvalid: (e) => e.preventDefault() }, index.h("slot", { key: '72120dfefa9008c4283629e119887ff3e32d3894', slot: "start", name: "start" }), index.h("slot", { key: '3df3db74bd839bab72aa758468359451e0019c0b', slot: "end", name: "end" }), this.label && (index.h("fluent-label", { key: '9e4ad92775c6af795ffc5762b5f8045cd327ea6d', required: this.required, disabled: this.disabled }, this.label, this.popupHint && (index.h("udp-tooltip", { key: '97261e93f5652e11beb4c92aad11ab1e6e76c877', content: this.popupHint, positioning: "above" }, index.h("udp-fluent-icon", { key: '30894a2646b319aaccd96618aa6d5a8f5509769b', name: "info", size: "xs", class: "popup-hint-icon" })))))), index.h("udp-text", { key: '34ba101a49953809cb238f2b1c1cb4709661707a', slot: "message", variant: "caption1", class: {
131
+ return (index.h(index.Host, { key: '8fe6b1f30e3ae0e1fa0fcef60388fe9ac41e55ed', class: { 'has-error': hasError } }, index.h("fluent-field", { key: '62ed363518afcefd52cda47fcbee9d3182dd0f1f', class: { 'no-message': noMessage } }, index.h("fluent-text-input", { key: '13c9ddb85fa5c3ac57571cac56e71e5af7e2a6cf', ref: el => (this.internalInput = el), slot: "input", class: { 'no-label': !this.label }, name: this.name, placeholder: this.placeholder, required: this.required, disabled: this.disabled, readonly: this.readonly, autofocus: this.autofocus, autocomplete: this.autocomplete, spellcheck: "false", appearance: this.appearance, controlSize: this.controlSize, onKeyDown: this.handleKeyDown, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: () => this.inputFocus.emit(), onInvalid: (e) => e.preventDefault() }, index.h("slot", { key: '6c4c74028fb7a5abd3e996d007a882150a672046', slot: "start", name: "start" }), index.h("slot", { key: '595ecd9f02687596909ec11e47f45c52844f202e', slot: "end", name: "end" }), this.label && (index.h("fluent-label", { key: '3c6c1ae1b635700288624a6f636c07b2cce1e92f', required: this.required, disabled: this.disabled }, this.label, this.popupHint && (index.h("udp-tooltip", { key: 'fc613dd974b0bd1c5c07a4f420d81807f445351b', content: this.popupHint, positioning: "above" }, index.h("udp-fluent-icon", { key: '25b5ab4f00ab5ab26cdf83aa341280a82bc733fb', name: "info", size: "xs", class: "popup-hint-icon" })))))), index.h("udp-text", { key: 'a07ad42598cca494bdab27923967eb6d7262ea4e', slot: "message", variant: "caption1", class: {
90
132
  message: true,
91
133
  error: hasError,
92
134
  includeErrorPadding: this.includeErrorPadding,
93
135
  } }, message))));
94
136
  }
95
137
  static get delegatesFocus() { return true; }
138
+ static get watchers() { return {
139
+ "value": [{
140
+ "onValuePropChange": 0
141
+ }]
142
+ }; }
96
143
  };
97
144
  UdpFluentNumberInput.style = udpFluentNumberInputCss();
98
145
 
@@ -3,14 +3,14 @@ import "@fluentui/web-components/text-input.js";
3
3
  import "@fluentui/web-components/field.js";
4
4
  import "@fluentui/web-components/label.js";
5
5
  /**
6
- * Number input component with min/max/step constraints and decimal capping.
6
+ * Number input component with keystroke filtering, decimal place capping, and arrow-key stepping.
7
+ * Min/max range constraints are handled at the form level by the consumer.
7
8
  *
8
9
  * @slot start - Content to be displayed at the start of the input.
9
10
  * @slot end - Content to be displayed at the end of the input.
10
11
  */
11
12
  export class UdpFluentNumberInput {
12
13
  constructor() {
13
- this.liveValue = null;
14
14
  /** Whether to include error padding below the input. */
15
15
  this.includeErrorPadding = true;
16
16
  /** Whether the input is required for form submission. */
@@ -27,51 +27,75 @@ export class UdpFluentNumberInput {
27
27
  this.appearance = 'outline';
28
28
  /** The size of the input control. */
29
29
  this.controlSize = 'medium';
30
+ this.handleKeyDown = (ev) => {
31
+ var _a, _b, _c, _d, _e;
32
+ const { key, ctrlKey, metaKey } = ev;
33
+ if (ctrlKey || metaKey)
34
+ return;
35
+ if (['Backspace', 'Delete', 'Tab', 'Enter', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(key))
36
+ return;
37
+ if (key === 'ArrowUp' || key === 'ArrowDown') {
38
+ this.handleStep(key === 'ArrowUp' ? 1 : -1);
39
+ ev.preventDefault();
40
+ return;
41
+ }
42
+ // Block scientific notation keys not useful in a form number input
43
+ if (key === 'e' || key === 'E' || key === '+') {
44
+ ev.preventDefault();
45
+ return;
46
+ }
47
+ // Block decimal point for integer-only inputs, or if one already exists
48
+ if (key === '.') {
49
+ if (this.decimals === 0) {
50
+ ev.preventDefault();
51
+ return;
52
+ }
53
+ const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
54
+ if (nativeInput === null || nativeInput === void 0 ? void 0 : nativeInput.value.includes('.'))
55
+ ev.preventDefault();
56
+ return;
57
+ }
58
+ // For digit keys, enforce decimal place limit
59
+ if (/^\d$/.test(key)) {
60
+ if (this.decimals != null && this.decimals > 0) {
61
+ const nativeInput = (_d = (_c = this.internalInput) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('input');
62
+ if (nativeInput) {
63
+ const value = nativeInput.value;
64
+ const dotIndex = value.indexOf('.');
65
+ if (dotIndex !== -1) {
66
+ const cursorAfterDot = ((_e = nativeInput.selectionEnd) !== null && _e !== void 0 ? _e : value.length) > dotIndex;
67
+ const decimalsFilled = value.length - dotIndex - 1 >= this.decimals;
68
+ if (cursorAfterDot && decimalsFilled)
69
+ ev.preventDefault();
70
+ }
71
+ }
72
+ }
73
+ return;
74
+ }
75
+ // Allow minus sign for negative numbers; block everything else (letters, etc.)
76
+ if (key !== '-')
77
+ ev.preventDefault();
78
+ };
30
79
  this.handleInput = (ev) => {
31
80
  ev.stopPropagation();
32
81
  const target = ev.target;
33
- this.liveValue = target.value;
34
82
  this.valueChanged.emit(target.value);
35
83
  };
36
84
  this.handleBlur = () => {
37
- var _a, _b;
38
- if (this.decimals != null && this.internalInput) {
39
- const raw = parseFloat((_b = (_a = this.liveValue) !== null && _a !== void 0 ? _a : this.value) !== null && _b !== void 0 ? _b : '');
40
- if (!isNaN(raw)) {
41
- const formatted = raw.toFixed(this.decimals);
42
- this.internalInput.value = formatted;
43
- this.liveValue = formatted;
44
- this.valueChanged.emit(formatted);
45
- }
46
- }
47
85
  this.inputBlur.emit();
48
86
  };
49
87
  }
88
+ // Sync controlled value updates to the inner input without going through the render
89
+ // cycle — avoids FAST's setter resetting cursor on unrelated re-renders (e.g. error prop).
90
+ onValuePropChange(newValue) {
91
+ if (this.internalInput) {
92
+ this.internalInput.value = newValue !== null && newValue !== void 0 ? newValue : '';
93
+ }
94
+ }
50
95
  componentDidLoad() {
51
96
  if (this.internalInput && this.value != null) {
52
97
  this.internalInput.value = this.value;
53
98
  }
54
- this.applyNumberAttrs();
55
- }
56
- componentDidUpdate() {
57
- this.applyNumberAttrs();
58
- }
59
- // fluent-text-input doesn't proxy min/max/step to its inner <input>, so we set them directly.
60
- // We also set inputmode="decimal" so mobile keyboards show a numeric pad.
61
- // NOTE: we do NOT forward type="number" to fluent-text-input because FAST's inputHandler
62
- // reads input.value and writes it back via its setter. For type="number" in Chrome, this
63
- // resets the cursor to position 0 whenever an intermediate decimal value (e.g. "3.") causes
64
- // the browser's value-sanitisation to return the previous valid number ("3"), scrambling
65
- // subsequent keystrokes into the wrong order (e.g. "3.14159" → "141593").
66
- applyNumberAttrs() {
67
- var _a, _b, _c, _d, _e;
68
- const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
69
- if (!nativeInput)
70
- return;
71
- nativeInput.setAttribute('inputmode', 'decimal');
72
- nativeInput.min = (_c = this.min) !== null && _c !== void 0 ? _c : '';
73
- nativeInput.max = (_d = this.max) !== null && _d !== void 0 ? _d : '';
74
- nativeInput.step = (_e = this.step) !== null && _e !== void 0 ? _e : '';
75
99
  }
76
100
  /** Selects the text in the input. */
77
101
  select() {
@@ -79,11 +103,30 @@ export class UdpFluentNumberInput {
79
103
  (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.select();
80
104
  return Promise.resolve();
81
105
  }
106
+ handleStep(direction) {
107
+ var _a, _b, _c;
108
+ const nativeInput = (_b = (_a = this.internalInput) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('input');
109
+ if (!nativeInput)
110
+ return;
111
+ const rawStep = this.step != null && this.step !== '' ? parseFloat(this.step) : 1;
112
+ const stepSize = isNaN(rawStep) ? 1 : rawStep;
113
+ const current = parseFloat(nativeInput.value);
114
+ const base = isNaN(current) ? 0 : current;
115
+ const next = base + direction * stepSize;
116
+ const stepStr = (_c = this.step) !== null && _c !== void 0 ? _c : '1';
117
+ const dotIdx = stepStr.indexOf('.');
118
+ const decimalPlaces = dotIdx !== -1 ? stepStr.length - dotIdx - 1 : 0;
119
+ const newValue = next.toFixed(decimalPlaces);
120
+ if (this.internalInput) {
121
+ this.internalInput.value = newValue;
122
+ }
123
+ this.valueChanged.emit(newValue);
124
+ }
82
125
  render() {
83
126
  const hasError = !!this.error;
84
127
  const message = this.error || this.hint;
85
128
  const noMessage = !message && !this.includeErrorPadding;
86
- return (h(Host, { key: 'f87601660bf0d04ca3a617768a6178a9b83b3c39', class: { 'has-error': hasError } }, h("fluent-field", { key: '0a6bfa77b060b198f431cfd01dce8626d22b795c', class: { 'no-message': noMessage } }, h("fluent-text-input", { key: '70ee74cccec3b0223e4c36f6bec74a167dd66d8b', ref: el => (this.internalInput = el), slot: "input", class: { 'no-label': !this.label }, name: this.name, value: this.value, placeholder: this.placeholder, required: this.required, disabled: this.disabled, readonly: this.readonly, autofocus: this.autofocus, autocomplete: this.autocomplete, spellcheck: "false", appearance: this.appearance, controlSize: this.controlSize, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: () => this.inputFocus.emit(), onInvalid: (e) => e.preventDefault() }, h("slot", { key: '72120dfefa9008c4283629e119887ff3e32d3894', slot: "start", name: "start" }), h("slot", { key: '3df3db74bd839bab72aa758468359451e0019c0b', slot: "end", name: "end" }), this.label && (h("fluent-label", { key: '9e4ad92775c6af795ffc5762b5f8045cd327ea6d', required: this.required, disabled: this.disabled }, this.label, this.popupHint && (h("udp-tooltip", { key: '97261e93f5652e11beb4c92aad11ab1e6e76c877', content: this.popupHint, positioning: "above" }, h("udp-fluent-icon", { key: '30894a2646b319aaccd96618aa6d5a8f5509769b', name: "info", size: "xs", class: "popup-hint-icon" })))))), h("udp-text", { key: '34ba101a49953809cb238f2b1c1cb4709661707a', slot: "message", variant: "caption1", class: {
129
+ return (h(Host, { key: '8fe6b1f30e3ae0e1fa0fcef60388fe9ac41e55ed', class: { 'has-error': hasError } }, h("fluent-field", { key: '62ed363518afcefd52cda47fcbee9d3182dd0f1f', class: { 'no-message': noMessage } }, h("fluent-text-input", { key: '13c9ddb85fa5c3ac57571cac56e71e5af7e2a6cf', ref: el => (this.internalInput = el), slot: "input", class: { 'no-label': !this.label }, name: this.name, placeholder: this.placeholder, required: this.required, disabled: this.disabled, readonly: this.readonly, autofocus: this.autofocus, autocomplete: this.autocomplete, spellcheck: "false", appearance: this.appearance, controlSize: this.controlSize, onKeyDown: this.handleKeyDown, onInput: this.handleInput, onBlur: this.handleBlur, onFocus: () => this.inputFocus.emit(), onInvalid: (e) => e.preventDefault() }, h("slot", { key: '6c4c74028fb7a5abd3e996d007a882150a672046', slot: "start", name: "start" }), h("slot", { key: '595ecd9f02687596909ec11e47f45c52844f202e', slot: "end", name: "end" }), this.label && (h("fluent-label", { key: '3c6c1ae1b635700288624a6f636c07b2cce1e92f', required: this.required, disabled: this.disabled }, this.label, this.popupHint && (h("udp-tooltip", { key: 'fc613dd974b0bd1c5c07a4f420d81807f445351b', content: this.popupHint, positioning: "above" }, h("udp-fluent-icon", { key: '25b5ab4f00ab5ab26cdf83aa341280a82bc733fb', name: "info", size: "xs", class: "popup-hint-icon" })))))), h("udp-text", { key: 'a07ad42598cca494bdab27923967eb6d7262ea4e', slot: "message", variant: "caption1", class: {
87
130
  message: true,
88
131
  error: hasError,
89
132
  includeErrorPadding: this.includeErrorPadding,
@@ -397,44 +440,6 @@ export class UdpFluentNumberInput {
397
440
  "attribute": "control-size",
398
441
  "defaultValue": "'medium'"
399
442
  },
400
- "min": {
401
- "type": "string",
402
- "mutable": false,
403
- "complexType": {
404
- "original": "string",
405
- "resolved": "string",
406
- "references": {}
407
- },
408
- "required": false,
409
- "optional": false,
410
- "docs": {
411
- "tags": [],
412
- "text": "Minimum allowed value. Enforced by the browser via native input constraints."
413
- },
414
- "getter": false,
415
- "setter": false,
416
- "reflect": false,
417
- "attribute": "min"
418
- },
419
- "max": {
420
- "type": "string",
421
- "mutable": false,
422
- "complexType": {
423
- "original": "string",
424
- "resolved": "string",
425
- "references": {}
426
- },
427
- "required": false,
428
- "optional": false,
429
- "docs": {
430
- "tags": [],
431
- "text": "Maximum allowed value. Enforced by the browser via native input constraints."
432
- },
433
- "getter": false,
434
- "setter": false,
435
- "reflect": false,
436
- "attribute": "max"
437
- },
438
443
  "step": {
439
444
  "type": "string",
440
445
  "mutable": false,
@@ -447,7 +452,7 @@ export class UdpFluentNumberInput {
447
452
  "optional": false,
448
453
  "docs": {
449
454
  "tags": [],
450
- "text": "Step increment for the spinner (e.g. \"0.5\", \"0.01\", \"1\")."
455
+ "text": "Step increment for arrow-key stepping (e.g. \"0.5\", \"0.01\", \"1\"). Defaults to 1 if omitted."
451
456
  },
452
457
  "getter": false,
453
458
  "setter": false,
@@ -466,7 +471,7 @@ export class UdpFluentNumberInput {
466
471
  "optional": false,
467
472
  "docs": {
468
473
  "tags": [],
469
- "text": "Maximum number of decimal places. On blur, the value is rounded to this precision."
474
+ "text": "Maximum number of decimal places allowed. Digits beyond this limit are blocked at the keystroke level."
470
475
  },
471
476
  "getter": false,
472
477
  "setter": false,
@@ -544,4 +549,10 @@ export class UdpFluentNumberInput {
544
549
  }
545
550
  };
546
551
  }
552
+ static get watchers() {
553
+ return [{
554
+ "propName": "value",
555
+ "methodName": "onValuePropChange"
556
+ }];
557
+ }
547
558
  }
@@ -1,2 +1,2 @@
1
1
  import "../stencil-library/stencil-library.css";
2
- import{p as t,H as e,c as o,h as i,d as s,t as l}from"./index2.js";import"@fluentui/web-components/text-input.js";import"@fluentui/web-components/field.js";import"@fluentui/web-components/label.js";import{d as n}from"./udp-fluent-icon2.js";import{d as a}from"./udp-text2.js";import{d as r}from"./udp-tooltip2.js";const u=t(class extends e{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.valueChanged=o(this,"valueChanged",7),this.inputBlur=o(this,"inputBlur",7),this.inputFocus=o(this,"inputFocus",7),this.liveValue=null,this.includeErrorPadding=!0,this.required=!1,this.disabled=!1,this.readonly=!1,this.autofocus=!1,this.autocomplete="off",this.appearance="outline",this.controlSize="medium",this.handleInput=t=>{t.stopPropagation();const e=t.target;this.liveValue=e.value,this.valueChanged.emit(e.value)},this.handleBlur=()=>{var t,e;if(null!=this.decimals&&this.internalInput){const o=parseFloat(null!==(e=null!==(t=this.liveValue)&&void 0!==t?t:this.value)&&void 0!==e?e:"");if(!isNaN(o)){const t=o.toFixed(this.decimals);this.internalInput.value=t,this.liveValue=t,this.valueChanged.emit(t)}}this.inputBlur.emit()}}componentDidLoad(){this.internalInput&&null!=this.value&&(this.internalInput.value=this.value),this.applyNumberAttrs()}componentDidUpdate(){this.applyNumberAttrs()}applyNumberAttrs(){var t,e,o,i,s;const l=null===(e=null===(t=this.internalInput)||void 0===t?void 0:t.shadowRoot)||void 0===e?void 0:e.querySelector("input");l&&(l.setAttribute("inputmode","decimal"),l.min=null!==(o=this.min)&&void 0!==o?o:"",l.max=null!==(i=this.max)&&void 0!==i?i:"",l.step=null!==(s=this.step)&&void 0!==s?s:"")}select(){var t;return null===(t=this.internalInput)||void 0===t||t.select(),Promise.resolve()}render(){const t=!!this.error,e=this.error||this.hint;return i(s,{key:"f87601660bf0d04ca3a617768a6178a9b83b3c39",class:{"has-error":t}},i("fluent-field",{key:"0a6bfa77b060b198f431cfd01dce8626d22b795c",class:{"no-message":!e&&!this.includeErrorPadding}},i("fluent-text-input",{key:"70ee74cccec3b0223e4c36f6bec74a167dd66d8b",ref:t=>this.internalInput=t,slot:"input",class:{"no-label":!this.label},name:this.name,value:this.value,placeholder:this.placeholder,required:this.required,disabled:this.disabled,readonly:this.readonly,autofocus:this.autofocus,autocomplete:this.autocomplete,spellcheck:"false",appearance:this.appearance,controlSize:this.controlSize,onInput:this.handleInput,onBlur:this.handleBlur,onFocus:()=>this.inputFocus.emit(),onInvalid:t=>t.preventDefault()},i("slot",{key:"72120dfefa9008c4283629e119887ff3e32d3894",slot:"start",name:"start"}),i("slot",{key:"3df3db74bd839bab72aa758468359451e0019c0b",slot:"end",name:"end"}),this.label&&i("fluent-label",{key:"9e4ad92775c6af795ffc5762b5f8045cd327ea6d",required:this.required,disabled:this.disabled},this.label,this.popupHint&&i("udp-tooltip",{key:"97261e93f5652e11beb4c92aad11ab1e6e76c877",content:this.popupHint,positioning:"above"},i("udp-fluent-icon",{key:"30894a2646b319aaccd96618aa6d5a8f5509769b",name:"info",size:"xs",class:"popup-hint-icon"})))),i("udp-text",{key:"34ba101a49953809cb238f2b1c1cb4709661707a",slot:"message",variant:"caption1",class:{message:!0,error:t,includeErrorPadding:this.includeErrorPadding}},e)))}static get delegatesFocus(){return!0}static get style(){return"fluent-text-input[disabled]::part(control){color:var(--colorNeutralForegroundDisabled);-webkit-text-fill-color:var(--colorNeutralForegroundDisabled)}fluent-text-input[disabled]::part(root){background-color:var(--colorNeutralBackgroundDisabled)}fluent-label[disabled]{color:var(--colorNeutralForeground1)}fluent-text-input::part(control):-webkit-autofill,fluent-text-input::part(control):-webkit-autofill:hover,fluent-text-input::part(control):-webkit-autofill:focus,fluent-text-input::part(control):-webkit-autofill:active{-webkit-box-shadow:0 0 0 30px var(--colorNeutralBackground1) inset !important;-webkit-text-fill-color:var(--colorNeutralForeground1) !important;transition:background-color 5000s ease-in-out 0s}:host{display:block;width:100%}fluent-field{width:100%}fluent-text-input{width:100%;max-width:100%}.message{color:var(--colorNeutralForeground3)}.message.includeErrorPadding{min-height:var(--lineHeightBase200)}.message.error{color:var(--colorPaletteRedForeground1)}.popup-hint-icon{margin-left:2px}fluent-text-input.no-label::part(label){display:none}fluent-field.no-message::part(message){display:none}:host(.has-error) fluent-text-input::part(root){border-color:var(--colorPaletteRedBorder2)}:host(.has-error:focus-within) fluent-text-input::part(root){border-color:var(--colorNeutralStroke1)}"}},[273,"udp-fluent-number-input",{value:[1],name:[1],label:[1],hint:[1],popupHint:[1,"popup-hint"],error:[1],includeErrorPadding:[4,"include-error-padding"],placeholder:[1],required:[4],disabled:[4],readonly:[4],autofocus:[4],autocomplete:[1],appearance:[1],controlSize:[1,"control-size"],min:[1],max:[1],step:[1],decimals:[2],select:[64]}]),d=u,c=function(){"undefined"!=typeof customElements&&["udp-fluent-number-input","udp-fluent-icon","udp-text","udp-tooltip"].forEach((t=>{switch(t){case"udp-fluent-number-input":customElements.get(l(t))||customElements.define(l(t),u);break;case"udp-fluent-icon":customElements.get(l(t))||n();break;case"udp-text":customElements.get(l(t))||a();break;case"udp-tooltip":customElements.get(l(t))||r()}}))};export{d as UdpFluentNumberInput,c as defineCustomElement}
2
+ import{p as t,H as e,c as o,h as i,d as s,t as l}from"./index2.js";import"@fluentui/web-components/text-input.js";import"@fluentui/web-components/field.js";import"@fluentui/web-components/label.js";import{d as r}from"./udp-fluent-icon2.js";import{d as n}from"./udp-text2.js";import{d as a}from"./udp-tooltip2.js";const u=t(class extends e{constructor(t){super(),!1!==t&&this.__registerHost(),this.__attachShadow(),this.valueChanged=o(this,"valueChanged",7),this.inputBlur=o(this,"inputBlur",7),this.inputFocus=o(this,"inputFocus",7),this.includeErrorPadding=!0,this.required=!1,this.disabled=!1,this.readonly=!1,this.autofocus=!1,this.autocomplete="off",this.appearance="outline",this.controlSize="medium",this.handleKeyDown=t=>{var e,o,i,s,l;const{key:r,ctrlKey:n,metaKey:a}=t;if(!n&&!a&&!["Backspace","Delete","Tab","Enter","ArrowLeft","ArrowRight","Home","End"].includes(r)){if("ArrowUp"===r||"ArrowDown"===r)return this.handleStep("ArrowUp"===r?1:-1),void t.preventDefault();if("e"!==r&&"E"!==r&&"+"!==r)if("."!==r)if(/^\d$/.test(r)){if(null!=this.decimals&&this.decimals>0){const e=null===(s=null===(i=this.internalInput)||void 0===i?void 0:i.shadowRoot)||void 0===s?void 0:s.querySelector("input");if(e){const o=e.value,i=o.indexOf(".");-1!==i&&(null!==(l=e.selectionEnd)&&void 0!==l?l:o.length)>i&&o.length-i-1>=this.decimals&&t.preventDefault()}}}else"-"!==r&&t.preventDefault();else{if(0===this.decimals)return void t.preventDefault();const i=null===(o=null===(e=this.internalInput)||void 0===e?void 0:e.shadowRoot)||void 0===o?void 0:o.querySelector("input");(null==i?void 0:i.value.includes("."))&&t.preventDefault()}else t.preventDefault()}},this.handleInput=t=>{t.stopPropagation(),this.valueChanged.emit(t.target.value)},this.handleBlur=()=>{this.inputBlur.emit()}}onValuePropChange(t){this.internalInput&&(this.internalInput.value=null!=t?t:"")}componentDidLoad(){this.internalInput&&null!=this.value&&(this.internalInput.value=this.value)}select(){var t;return null===(t=this.internalInput)||void 0===t||t.select(),Promise.resolve()}handleStep(t){var e,o,i;const s=null===(o=null===(e=this.internalInput)||void 0===e?void 0:e.shadowRoot)||void 0===o?void 0:o.querySelector("input");if(!s)return;const l=null!=this.step&&""!==this.step?parseFloat(this.step):1,r=isNaN(l)?1:l,n=parseFloat(s.value),a=(isNaN(n)?0:n)+t*r,u=null!==(i=this.step)&&void 0!==i?i:"1",d=u.indexOf("."),c=a.toFixed(-1!==d?u.length-d-1:0);this.internalInput&&(this.internalInput.value=c),this.valueChanged.emit(c)}render(){const t=!!this.error,e=this.error||this.hint;return i(s,{key:"8fe6b1f30e3ae0e1fa0fcef60388fe9ac41e55ed",class:{"has-error":t}},i("fluent-field",{key:"62ed363518afcefd52cda47fcbee9d3182dd0f1f",class:{"no-message":!e&&!this.includeErrorPadding}},i("fluent-text-input",{key:"13c9ddb85fa5c3ac57571cac56e71e5af7e2a6cf",ref:t=>this.internalInput=t,slot:"input",class:{"no-label":!this.label},name:this.name,placeholder:this.placeholder,required:this.required,disabled:this.disabled,readonly:this.readonly,autofocus:this.autofocus,autocomplete:this.autocomplete,spellcheck:"false",appearance:this.appearance,controlSize:this.controlSize,onKeyDown:this.handleKeyDown,onInput:this.handleInput,onBlur:this.handleBlur,onFocus:()=>this.inputFocus.emit(),onInvalid:t=>t.preventDefault()},i("slot",{key:"6c4c74028fb7a5abd3e996d007a882150a672046",slot:"start",name:"start"}),i("slot",{key:"595ecd9f02687596909ec11e47f45c52844f202e",slot:"end",name:"end"}),this.label&&i("fluent-label",{key:"3c6c1ae1b635700288624a6f636c07b2cce1e92f",required:this.required,disabled:this.disabled},this.label,this.popupHint&&i("udp-tooltip",{key:"fc613dd974b0bd1c5c07a4f420d81807f445351b",content:this.popupHint,positioning:"above"},i("udp-fluent-icon",{key:"25b5ab4f00ab5ab26cdf83aa341280a82bc733fb",name:"info",size:"xs",class:"popup-hint-icon"})))),i("udp-text",{key:"a07ad42598cca494bdab27923967eb6d7262ea4e",slot:"message",variant:"caption1",class:{message:!0,error:t,includeErrorPadding:this.includeErrorPadding}},e)))}static get delegatesFocus(){return!0}static get watchers(){return{value:[{onValuePropChange:0}]}}static get style(){return"fluent-text-input[disabled]::part(control){color:var(--colorNeutralForegroundDisabled);-webkit-text-fill-color:var(--colorNeutralForegroundDisabled)}fluent-text-input[disabled]::part(root){background-color:var(--colorNeutralBackgroundDisabled)}fluent-label[disabled]{color:var(--colorNeutralForeground1)}fluent-text-input::part(control):-webkit-autofill,fluent-text-input::part(control):-webkit-autofill:hover,fluent-text-input::part(control):-webkit-autofill:focus,fluent-text-input::part(control):-webkit-autofill:active{-webkit-box-shadow:0 0 0 30px var(--colorNeutralBackground1) inset !important;-webkit-text-fill-color:var(--colorNeutralForeground1) !important;transition:background-color 5000s ease-in-out 0s}:host{display:block;width:100%}fluent-field{width:100%}fluent-text-input{width:100%;max-width:100%}.message{color:var(--colorNeutralForeground3)}.message.includeErrorPadding{min-height:var(--lineHeightBase200)}.message.error{color:var(--colorPaletteRedForeground1)}.popup-hint-icon{margin-left:2px}fluent-text-input.no-label::part(label){display:none}fluent-field.no-message::part(message){display:none}:host(.has-error) fluent-text-input::part(root){border-color:var(--colorPaletteRedBorder2)}:host(.has-error:focus-within) fluent-text-input::part(root){border-color:var(--colorNeutralStroke1)}"}},[273,"udp-fluent-number-input",{value:[1],name:[1],label:[1],hint:[1],popupHint:[1,"popup-hint"],error:[1],includeErrorPadding:[4,"include-error-padding"],placeholder:[1],required:[4],disabled:[4],readonly:[4],autofocus:[4],autocomplete:[1],appearance:[1],controlSize:[1,"control-size"],step:[1],decimals:[2],select:[64]},void 0,{value:[{onValuePropChange:0}]}]),d=u,c=function(){"undefined"!=typeof customElements&&["udp-fluent-number-input","udp-fluent-icon","udp-text","udp-tooltip"].forEach((t=>{switch(t){case"udp-fluent-number-input":customElements.get(l(t))||customElements.define(l(t),u);break;case"udp-fluent-icon":customElements.get(l(t))||r();break;case"udp-text":customElements.get(l(t))||n();break;case"udp-tooltip":customElements.get(l(t))||a()}}))};export{d as UdpFluentNumberInput,c as defineCustomElement}
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-06-09T22:54:43",
2
+ "timestamp": "2026-06-10T18:26:47",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.41.3",
@@ -52282,7 +52282,7 @@
52282
52282
  "encapsulation": "shadow",
52283
52283
  "tag": "udp-fluent-number-input",
52284
52284
  "readme": "# udp-fluent-number-input\n\n\n",
52285
- "docs": "Number input component with min/max/step constraints and decimal capping.",
52285
+ "docs": "Number input component with keystroke filtering, decimal place capping, and arrow-key stepping.\nMin/max range constraints are handled at the form level by the consumer.",
52286
52286
  "docsTags": [
52287
52287
  {
52288
52288
  "name": "slot",
@@ -52444,7 +52444,7 @@
52444
52444
  "mutable": false,
52445
52445
  "attr": "decimals",
52446
52446
  "reflectToAttr": false,
52447
- "docs": "Maximum number of decimal places. On blur, the value is rounded to this precision.",
52447
+ "docs": "Maximum number of decimal places allowed. Digits beyond this limit are blocked at the keystroke level.",
52448
52448
  "docsTags": [],
52449
52449
  "values": [
52450
52450
  {
@@ -52583,52 +52583,6 @@
52583
52583
  "getter": false,
52584
52584
  "setter": false
52585
52585
  },
52586
- {
52587
- "name": "max",
52588
- "type": "string",
52589
- "complexType": {
52590
- "original": "string",
52591
- "resolved": "string",
52592
- "references": {}
52593
- },
52594
- "mutable": false,
52595
- "attr": "max",
52596
- "reflectToAttr": false,
52597
- "docs": "Maximum allowed value. Enforced by the browser via native input constraints.",
52598
- "docsTags": [],
52599
- "values": [
52600
- {
52601
- "type": "string"
52602
- }
52603
- ],
52604
- "optional": false,
52605
- "required": false,
52606
- "getter": false,
52607
- "setter": false
52608
- },
52609
- {
52610
- "name": "min",
52611
- "type": "string",
52612
- "complexType": {
52613
- "original": "string",
52614
- "resolved": "string",
52615
- "references": {}
52616
- },
52617
- "mutable": false,
52618
- "attr": "min",
52619
- "reflectToAttr": false,
52620
- "docs": "Minimum allowed value. Enforced by the browser via native input constraints.",
52621
- "docsTags": [],
52622
- "values": [
52623
- {
52624
- "type": "string"
52625
- }
52626
- ],
52627
- "optional": false,
52628
- "required": false,
52629
- "getter": false,
52630
- "setter": false
52631
- },
52632
52586
  {
52633
52587
  "name": "name",
52634
52588
  "type": "string",
@@ -52767,7 +52721,7 @@
52767
52721
  "mutable": false,
52768
52722
  "attr": "step",
52769
52723
  "reflectToAttr": false,
52770
- "docs": "Step increment for the spinner (e.g. \"0.5\", \"0.01\", \"1\").",
52724
+ "docs": "Step increment for arrow-key stepping (e.g. \"0.5\", \"0.01\", \"1\"). Defaults to 1 if omitted.",
52771
52725
  "docsTags": [],
52772
52726
  "values": [
52773
52727
  {