@genesislcap/foundation-ui 14.482.0 → 14.482.1

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.
@@ -28,6 +28,7 @@ export declare class NumberField extends NumberField_base {
28
28
  stepUp(): void;
29
29
  stepDown(): void;
30
30
  hasSeparatorWithoutDecimals(): RegExp;
31
+ private restoreControlToCommittedValue;
31
32
  handleTextInput(): void;
32
33
  valueChanged(previous: any, next: any): void;
33
34
  handleBlur(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../src/number-field/number-field.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;;;;;;;;;;;AAkBrE;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,gBAA2B;IACpD,YAAY,EAAE,MAAM,CAAS;IACnC,OAAO,CAAC,mBAAmB;IAKA,QAAQ,EAAE,OAAO,CAAS;IAE/C,KAAK,EAAE,MAAM,CAAM;IACE,cAAc,EAAE,OAAO,CAAS;IACrD,MAAM,EAAE,MAAM,CAAW;IACJ,iBAAiB,EAAE,OAAO,CAAS;IACxD,qBAAqB,EAAE,MAAM,CAAuB;IAE1D,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAG/B;IAEF,MAAM,IAAI,IAAI;IAuCd,QAAQ,IAAI,IAAI;IA0ChB,2BAA2B;IAK3B,eAAe,IAAI,IAAI;IAoCvB,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IA+C5C,UAAU,IAAI,IAAI;CA4BnB;AAED,eAAO,MAAM,kCAAkC,EAAE,cAGhD,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAWpC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,oTAMhC,CAAC"}
1
+ {"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../../../src/number-field/number-field.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;;;;;;;;;;;AAoBrE;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,gBAA2B;IACpD,YAAY,EAAE,MAAM,CAAS;IACnC,OAAO,CAAC,mBAAmB;IAKA,QAAQ,EAAE,OAAO,CAAS;IAQrD,KAAK,EAAE,MAAM,CAAM;IACQ,cAAc,EAAE,OAAO,CAAS;IACrD,MAAM,EAAE,MAAM,CAAW;IACJ,iBAAiB,EAAE,OAAO,CAAS;IACxD,qBAAqB,EAAE,MAAM,CAAuB;IAE1D,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAG/B;IAEF,MAAM,IAAI,IAAI;IAuCd,QAAQ,IAAI,IAAI;IA0ChB,2BAA2B;IAK3B,OAAO,CAAC,8BAA8B;IAetC,eAAe,IAAI,IAAI;IA+DvB,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAqC5C,UAAU,IAAI,IAAI;CA4BnB;AAED,eAAO,MAAM,kCAAkC,EAAE,cAGhD,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAWpC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,oTAMhC,CAAC"}
@@ -1,6 +1,18 @@
1
1
  export declare const getSeparatorsFromParser: (value: string, locale: string) => {
2
2
  decimalSeparator: string;
3
3
  };
4
+ /**
5
+ * Strips locale grouping and normalizes the decimal separator to `.` without using `Number`
6
+ * (so integers beyond `Number.MAX_SAFE_INTEGER` keep every digit).
7
+ */
8
+ export declare const normalizeLocaleNumberString: (inputVal: string, locale: string) => string;
9
+ /** Counts locale decimal separator characters in the raw control text (ignores grouping). */
10
+ export declare const countLocaleDecimalSeparators: (input: string, locale: string) => number;
11
+ export declare const hasMultipleDecimalSeparators: (input: string, locale: string) => boolean;
12
+ /** True when the committed value is a whole number already using the full significant-digit budget. */
13
+ export declare const isIntegerAtMaximumInputPrecision: (value: string, locale: string, precision: number) => boolean;
14
+ /** User typed a decimal separator while the integer part is already at max precision. */
15
+ export declare const rejectsDecimalAtMaximumIntegerPrecision: (committedValue: string, controlText: string, locale: string, precision: number) => boolean;
4
16
  export declare const formatControlValue: (value: string, locale: string) => string;
5
17
  export declare const sanitiseInputVal: (inputVal: string, locale: string) => string;
6
18
  export declare const toIntlNumberFormat: (value: string, locale: string, options: Intl.NumberFormatOptions) => string;
@@ -22,7 +34,7 @@ export declare const preserveTrailingZerosAfterParse: (value: string, parsedValu
22
34
  * @returns The validated and formatted value
23
35
  */
24
36
  export declare const validateValue: (value: string | number, locale: string, withFormatting?: boolean, precision?: number) => string;
25
- export declare const validateInput: (value: string, locale: string, precision?: number) => string;
37
+ export declare const validateInput: (value: string, locale: string, precision?: number, committedValue?: string) => string;
26
38
  export declare const validateMinMax: (value: string, locale: string, withFormatting: boolean, min: number, max: number, precision?: number) => string;
27
39
  /**
28
40
  * Performs high precision addition using Pure JavaScript (NO BigInt needed!)
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/number-field/utils.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,EACb,QAAQ,MAAM,KACb;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAI5B,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MAWlE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,EAAE,QAAQ,MAAM,KAAG,MAEnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,SAAS,IAAI,CAAC,mBAAmB,KAChC,MAEF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,EACb,SAAS,IAAI,CAAC,mBAAmB,KAChC,MAyCF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,QAAQ,MAAM,KACb,MA+BF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,GAAG,MAAM,EACtB,QAAQ,MAAM,EACd,wBAAqB,EACrB,YAAY,MAAM,KACjB,MA8DF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,EAAE,YAAY,MAAM,KAAG,MAGjF,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,uBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,YAAY,MAAM,KACjB,MAaF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAyBvD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAyB5D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,KAAG,MAgDnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,KAAG,MA+CnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GAAI,OAAO,MAAM,GAAG,MAAM,KAAG,MA8BnE,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/number-field/utils.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,uBAAuB,GAClC,OAAO,MAAM,EACb,QAAQ,MAAM,KACb;IAAE,gBAAgB,EAAE,MAAM,CAAA;CAI5B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,EAAE,QAAQ,MAAM,KAAG,MAY9E,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,4BAA4B,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MAU5E,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,OAC5B,CAAC;AAElD,uGAAuG;AACvG,eAAO,MAAM,gCAAgC,GAC3C,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,WAAW,MAAM,KAChB,OAMF,CAAC;AAEF,yFAAyF;AACzF,eAAO,MAAM,uCAAuC,GAClD,gBAAgB,MAAM,EACtB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,WAAW,MAAM,KAChB,OAEoD,CAAC;AAqFxD,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MAWlE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,EAAE,QAAQ,MAAM,KAAG,MAOnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,SAAS,IAAI,CAAC,mBAAmB,KAChC,MAQF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,MAAM,EACb,SAAS,IAAI,CAAC,mBAAmB,KAChC,MAyCF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,QAAQ,MAAM,KACb,MA+BF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,GAAG,MAAM,EACtB,QAAQ,MAAM,EACd,wBAAqB,EACrB,YAAY,MAAM,KACjB,MAkEF,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,YAAY,MAAM,EAClB,iBAAiB,MAAM,KACtB,MAaF,CAAC;AAEF,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,uBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,YAAY,MAAM,KACjB,MAyBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAyBvD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAyB5D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,KAAG,MAgDnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,aAAa,MAAM,GAAG,MAAM,EAAE,MAAM,MAAM,KAAG,MA+CnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GAAI,OAAO,MAAM,GAAG,MAAM,KAAG,MA8BnE,CAAC"}
@@ -129,32 +129,23 @@ interface HTMLWCProps extends React.AriaAttributes {
129
129
  onInput?(e: Event): void;
130
130
  }
131
131
 
132
- export declare const AccordionItem: React.ForwardRefExoticComponent<
133
- React.PropsWithChildren<
134
- Omit<PublicOf<AccordionItemWC>, 'children' | 'style'> &
135
- HTMLWCProps & {
136
- }
137
- > & React.RefAttributes<AccordionItemWC>
138
- >;
139
- export type AccordionItemRef = AccordionItemWC;
140
-
141
- export declare const Accordion: React.ForwardRefExoticComponent<
132
+ export declare const ActionsMenu: React.ForwardRefExoticComponent<
142
133
  React.PropsWithChildren<
143
- Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
134
+ Omit<PublicOf<ActionsMenuWC>, 'children' | 'style'> &
144
135
  HTMLWCProps & {
145
136
  }
146
- > & React.RefAttributes<AccordionWC>
137
+ > & React.RefAttributes<ActionsMenuWC>
147
138
  >;
148
- export type AccordionRef = AccordionWC;
139
+ export type ActionsMenuRef = ActionsMenuWC;
149
140
 
150
- export declare const ActionsMenu: React.ForwardRefExoticComponent<
141
+ export declare const AccordionItem: React.ForwardRefExoticComponent<
151
142
  React.PropsWithChildren<
152
- Omit<PublicOf<ActionsMenuWC>, 'children' | 'style'> &
143
+ Omit<PublicOf<AccordionItemWC>, 'children' | 'style'> &
153
144
  HTMLWCProps & {
154
145
  }
155
- > & React.RefAttributes<ActionsMenuWC>
146
+ > & React.RefAttributes<AccordionItemWC>
156
147
  >;
157
- export type ActionsMenuRef = ActionsMenuWC;
148
+ export type AccordionItemRef = AccordionItemWC;
158
149
 
159
150
  export declare const AiCriteriaSearch: React.ForwardRefExoticComponent<
160
151
  React.PropsWithChildren<
@@ -176,6 +167,15 @@ export declare const AiIndicator: React.ForwardRefExoticComponent<
176
167
  >;
177
168
  export type AiIndicatorRef = AiIndicatorWC;
178
169
 
170
+ export declare const Accordion: React.ForwardRefExoticComponent<
171
+ React.PropsWithChildren<
172
+ Omit<PublicOf<AccordionWC>, 'children' | 'style'> &
173
+ HTMLWCProps & {
174
+ }
175
+ > & React.RefAttributes<AccordionWC>
176
+ >;
177
+ export type AccordionRef = AccordionWC;
178
+
179
179
  export declare const Anchor: React.ForwardRefExoticComponent<
180
180
  React.PropsWithChildren<
181
181
  Omit<PublicOf<AnchorWC>, 'children' | 'style'> &
@@ -5,7 +5,7 @@ import { DOM, attr } from '@microsoft/fast-element';
5
5
  import { AffixMixin } from '../_common';
6
6
  import { foundationNumberFieldStyles as styles } from './number-field.styles';
7
7
  import { foundationNumberFieldTemplate as template } from './number-field.template';
8
- import { applyDecimalPrecisionLimits, calculateAutoStepPrecision, decrementWithPrecision, formatControlValue, incrementWithPrecision, toIntlNumberFormat, validateInput, validateMinMax, } from './utils';
8
+ import { applyDecimalPrecisionLimits, calculateAutoStepPrecision, decrementWithPrecision, formatControlValue, incrementWithPrecision, toIntlNumberFormat, validateInput, validateMinMax, hasMultipleDecimalSeparators, rejectsDecimalAtMaximumIntegerPrecision, } from './utils';
9
9
  const MAX_DECIMAL_PLACES = 3;
10
10
  const MAX_INPUT_PRECISION = 12;
11
11
  /**
@@ -94,19 +94,50 @@ export class NumberField extends AffixMixin(FASTNumberField) {
94
94
  const regexString = `[.]$`;
95
95
  return new RegExp(regexString);
96
96
  }
97
+ restoreControlToCommittedValue() {
98
+ if (!this.control)
99
+ return;
100
+ const previousValue = this.value;
101
+ if (!previousValue) {
102
+ this.control.value = '';
103
+ this['isUserInput'] = false;
104
+ return;
105
+ }
106
+ this.control.value =
107
+ this.withFormatting && previousValue
108
+ ? toIntlNumberFormat(previousValue, this.locale, this.options)
109
+ : formatControlValue(String(previousValue), this.locale);
110
+ this['isUserInput'] = false;
111
+ }
97
112
  handleTextInput() {
98
113
  if (!this.control)
99
114
  return;
100
115
  if (this.control.value === '-' || this.control.value === '-0')
101
116
  return;
117
+ if (hasMultipleDecimalSeparators(this.control.value, this.locale)) {
118
+ this.restoreControlToCommittedValue();
119
+ return;
120
+ }
121
+ if (rejectsDecimalAtMaximumIntegerPrecision(this.value, this.control.value, this.locale, this.maximumInputPrecision)) {
122
+ this.restoreControlToCommittedValue();
123
+ return;
124
+ }
102
125
  this['isUserInput'] = true;
103
126
  if (this.withFormatting && !new NumberParser(this.locale).hasSeparator(this.control.value)) {
104
127
  DOM.queueUpdate(() => {
105
- const validValue = validateInput(this.control.value, this.locale, this.maximumInputPrecision);
106
- this.value = applyDecimalPrecisionLimits(validValue, this.options);
128
+ const previousValue = this.value;
129
+ const validValue = validateInput(this.control.value, this.locale, this.maximumInputPrecision, this.value);
130
+ if (!validValue && previousValue && this.control.value !== '') {
131
+ this.restoreControlToCommittedValue();
132
+ return;
133
+ }
107
134
  if (this.control) {
108
- this.control.value = applyDecimalPrecisionLimits(formatControlValue(validValue, this.locale), this.options);
135
+ const displayValue = this.withFormatting && validValue !== ''
136
+ ? toIntlNumberFormat(validValue, this.locale, this.options)
137
+ : formatControlValue(validValue, this.locale);
138
+ this.control.value = applyDecimalPrecisionLimits(displayValue, this.options);
109
139
  }
140
+ this.value = applyDecimalPrecisionLimits(validValue, this.options);
110
141
  this.$emit('input');
111
142
  });
112
143
  }
@@ -131,6 +162,9 @@ export class NumberField extends AffixMixin(FASTNumberField) {
131
162
  if (!this['isUserInput']) {
132
163
  this.value = validateMinMax(this.value, this.locale, false, this.min, this.max, this.maximumInputPrecision);
133
164
  DOM.queueUpdate(() => {
165
+ if (this['isUserInput']) {
166
+ return;
167
+ }
134
168
  if (this.control) {
135
169
  this.control.value =
136
170
  this.withFormatting && this.value
@@ -140,19 +174,8 @@ export class NumberField extends AffixMixin(FASTNumberField) {
140
174
  });
141
175
  return;
142
176
  }
143
- const value = next;
144
- DOM.queueUpdate(() => {
145
- if (!this.control)
146
- return;
147
- if (this.control.value === '' || this.value === '') {
148
- this.control.value = value;
149
- return;
150
- }
151
- this.control.value = formatControlValue(String(value), this.locale);
152
- this.value = this.withFormatting
153
- ? validateInput(this.control.value, this.locale, this.maximumInputPrecision)
154
- : this.control.value;
155
- });
177
+ // While the user is typing, handleTextInput (and handleBlur on exit) own value + display.
178
+ return;
156
179
  }
157
180
  }
158
181
  handleBlur() {
@@ -181,7 +204,12 @@ __decorate([
181
204
  attr({ mode: 'boolean' })
182
205
  ], NumberField.prototype, "hideStep", void 0);
183
206
  __decorate([
184
- attr
207
+ attr({
208
+ converter: {
209
+ fromView: (value) => (value === null || value === undefined ? '' : String(value)),
210
+ toView: (value) => value,
211
+ },
212
+ })
185
213
  ], NumberField.prototype, "value", void 0);
186
214
  __decorate([
187
215
  attr({ mode: 'boolean' })
@@ -9,6 +9,119 @@ export const getSeparatorsFromParser = (value, locale) => {
9
9
  const decimalSeparator = ((_a = parts.find((d) => d.type === 'decimal')) === null || _a === void 0 ? void 0 : _a.value) || '.';
10
10
  return { decimalSeparator };
11
11
  };
12
+ /**
13
+ * Strips locale grouping and normalizes the decimal separator to `.` without using `Number`
14
+ * (so integers beyond `Number.MAX_SAFE_INTEGER` keep every digit).
15
+ */
16
+ export const normalizeLocaleNumberString = (inputVal, locale) => {
17
+ var _a, _b, _c;
18
+ const parts = new Intl.NumberFormat(locale).formatToParts(FORMAT_TEST_NUMBER);
19
+ const groupChar = (_a = parts.find((d) => d.type === 'group')) === null || _a === void 0 ? void 0 : _a.value;
20
+ const decimalChar = (_c = (_b = parts.find((d) => d.type === 'decimal')) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : '.';
21
+ let normalized = inputVal.trim();
22
+ if (groupChar) {
23
+ normalized = normalized.split(groupChar).join('');
24
+ }
25
+ if (decimalChar !== '.') {
26
+ normalized = normalized.replace(decimalChar, '.');
27
+ }
28
+ return normalized;
29
+ };
30
+ /** Counts locale decimal separator characters in the raw control text (ignores grouping). */
31
+ export const countLocaleDecimalSeparators = (input, locale) => {
32
+ var _a, _b;
33
+ const parts = new Intl.NumberFormat(locale).formatToParts(FORMAT_TEST_NUMBER);
34
+ const decimalChar = (_b = (_a = parts.find((d) => d.type === 'decimal')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '.';
35
+ let count = 0;
36
+ for (const ch of input) {
37
+ if (ch === decimalChar) {
38
+ count += 1;
39
+ }
40
+ }
41
+ return count;
42
+ };
43
+ export const hasMultipleDecimalSeparators = (input, locale) => countLocaleDecimalSeparators(input, locale) > 1;
44
+ /** True when the committed value is a whole number already using the full significant-digit budget. */
45
+ export const isIntegerAtMaximumInputPrecision = (value, locale, precision) => {
46
+ const normalized = normalizeLocaleNumberString(String(value !== null && value !== void 0 ? value : ''), locale);
47
+ if (!normalized || !/^-?\d+$/.test(normalized)) {
48
+ return false;
49
+ }
50
+ return normalized.replace(/^-/, '').length >= precision;
51
+ };
52
+ /** User typed a decimal separator while the integer part is already at max precision. */
53
+ export const rejectsDecimalAtMaximumIntegerPrecision = (committedValue, controlText, locale, precision) => isIntegerAtMaximumInputPrecision(committedValue, locale, precision) &&
54
+ countLocaleDecimalSeparators(controlText, locale) > 0;
55
+ const SAFE_INTEGER_DIGIT_COUNT = 15;
56
+ /** Sample integer used only to read locale grouping separator from Intl. */
57
+ const LOCALE_GROUPING_PROBE = 1234567;
58
+ const DIGITS_PER_GROUP = 3;
59
+ const formatLargeIntegerString = (value, locale) => {
60
+ var _a, _b;
61
+ const negative = value.startsWith('-');
62
+ const digits = negative ? value.slice(1) : value;
63
+ const parts = new Intl.NumberFormat(locale).formatToParts(LOCALE_GROUPING_PROBE);
64
+ const group = (_b = (_a = parts.find((p) => p.type === 'group')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : ',';
65
+ const groups = [];
66
+ let rest = digits;
67
+ while (rest.length > DIGITS_PER_GROUP) {
68
+ groups.unshift(rest.slice(-DIGITS_PER_GROUP));
69
+ rest = rest.slice(0, -DIGITS_PER_GROUP);
70
+ }
71
+ groups.unshift(rest);
72
+ const formatted = groups.join(group);
73
+ return negative ? `-${formatted}` : formatted;
74
+ };
75
+ const hasLongIntegerPart = (value) => {
76
+ const unsigned = value.replace(/^-/, '');
77
+ const dotIndex = unsigned.indexOf('.');
78
+ const intPart = dotIndex === -1 ? unsigned : unsigned.slice(0, dotIndex);
79
+ return intPart.length > SAFE_INTEGER_DIGIT_COUNT;
80
+ };
81
+ const formatLongNumericStringForDisplay = (value, locale, options) => {
82
+ const negative = value.startsWith('-');
83
+ const unsigned = negative ? value.slice(1) : value;
84
+ const dotIndex = unsigned.indexOf('.');
85
+ const intDigits = dotIndex === -1 ? unsigned : unsigned.slice(0, dotIndex);
86
+ let decDigits = dotIndex === -1 ? '' : unsigned.slice(dotIndex + 1);
87
+ const minFractionDigits = options.minimumFractionDigits;
88
+ const maxFractionDigits = options.maximumFractionDigits;
89
+ if (maxFractionDigits !== undefined && decDigits.length > maxFractionDigits) {
90
+ decDigits = decDigits.slice(0, maxFractionDigits);
91
+ }
92
+ if (minFractionDigits !== undefined && decDigits.length < minFractionDigits) {
93
+ decDigits = decDigits.padEnd(minFractionDigits, '0');
94
+ }
95
+ const intValue = negative ? `-${intDigits}` : intDigits;
96
+ const formattedInt = formatLargeIntegerString(intValue, locale);
97
+ const { decimalSeparator } = getSeparatorsFromParser(value, locale);
98
+ if (dotIndex === -1) {
99
+ if (minFractionDigits !== undefined && minFractionDigits > 0) {
100
+ return `${formattedInt}${decimalSeparator}${'0'.repeat(minFractionDigits)}`;
101
+ }
102
+ return formattedInt;
103
+ }
104
+ if (maxFractionDigits === 0) {
105
+ return formattedInt;
106
+ }
107
+ return `${formattedInt}${decimalSeparator}${decDigits}`;
108
+ };
109
+ const clampIntegerStringToMinMax = (value, min, max) => {
110
+ let clamped = BigInt(value);
111
+ if (max !== undefined && !Number.isNaN(max)) {
112
+ const maxBig = BigInt(Math.trunc(max));
113
+ if (clamped > maxBig) {
114
+ clamped = maxBig;
115
+ }
116
+ }
117
+ if (min !== undefined && !Number.isNaN(min)) {
118
+ const minBig = BigInt(Math.trunc(min));
119
+ if (clamped < minBig) {
120
+ clamped = minBig;
121
+ }
122
+ }
123
+ return clamped.toString();
124
+ };
12
125
  export const formatControlValue = (value, locale) => {
13
126
  // Get locale-specific decimal separator
14
127
  const { decimalSeparator } = getSeparatorsFromParser(value, locale);
@@ -20,9 +133,20 @@ export const formatControlValue = (value, locale) => {
20
133
  return value.replace(/\./g, decimalSeparator);
21
134
  };
22
135
  export const sanitiseInputVal = (inputVal, locale) => {
136
+ const normalized = normalizeLocaleNumberString(String(inputVal), locale);
137
+ const digitCount = normalized.replace(/^-/, '').replace('.', '').length;
138
+ if (/^-?\d+(\.\d+)?$/.test(normalized) && digitCount > SAFE_INTEGER_DIGIT_COUNT) {
139
+ return normalized;
140
+ }
23
141
  return String(new NumberParser(locale).parse(String(inputVal)));
24
142
  };
25
143
  export const toIntlNumberFormat = (value, locale, options) => {
144
+ if (value === '') {
145
+ return '';
146
+ }
147
+ if (hasLongIntegerPart(value) && /^-?\d+(\.\d*)?$/.test(value)) {
148
+ return formatLongNumericStringForDisplay(value, locale, options);
149
+ }
26
150
  return Intl.NumberFormat(locale, options).format(Number(value));
27
151
  };
28
152
  /**
@@ -110,6 +234,9 @@ export const validateValue = (value, locale, withFormatting = true, precision) =
110
234
  }
111
235
  const stringValue = typeof value === 'number' ? value.toString() : value;
112
236
  const inputPrecision = precision !== null && precision !== void 0 ? precision : formattedInputPrecision;
237
+ if (hasMultipleDecimalSeparators(stringValue, locale)) {
238
+ return '';
239
+ }
113
240
  let cleanValue;
114
241
  if (withFormatting) {
115
242
  cleanValue = sanitiseInputVal(stringValue, locale);
@@ -159,12 +286,34 @@ export const validateValue = (value, locale, withFormatting = true, precision) =
159
286
  }
160
287
  return cleanValue;
161
288
  };
162
- export const validateInput = (value, locale, precision) => {
163
- const parsedValue = validateValue(value, locale, undefined, precision);
289
+ export const validateInput = (value, locale, precision, committedValue) => {
290
+ if (precision !== undefined && countLocaleDecimalSeparators(value, locale) > 0) {
291
+ const normalized = normalizeLocaleNumberString(value, locale);
292
+ const dotIdx = normalized.indexOf('.');
293
+ const integerPart = dotIdx === -1 ? normalized : normalized.slice(0, dotIdx);
294
+ const committed = committedValue !== undefined ? committedValue : integerPart;
295
+ if (rejectsDecimalAtMaximumIntegerPrecision(committed, value, locale, precision)) {
296
+ return '';
297
+ }
298
+ }
299
+ const parsedValue = validateValue(value, locale, true, precision);
164
300
  return preserveTrailingZerosAfterParse(value, parsedValue, locale);
165
301
  };
166
302
  export const validateMinMax = (value, locale, withFormatting = true, min, max, precision) => {
167
- let validValue = parseFloat(validateValue(value, locale, withFormatting, precision));
303
+ const validatedString = validateValue(value, locale, withFormatting, precision);
304
+ if (!validatedString) {
305
+ return '';
306
+ }
307
+ const digitCount = validatedString.replace(/^-/, '').replace('.', '').length;
308
+ if (/^-?\d+$/.test(validatedString) && digitCount > SAFE_INTEGER_DIGIT_COUNT) {
309
+ try {
310
+ return clampIntegerStringToMinMax(validatedString, min, max);
311
+ }
312
+ catch (_a) {
313
+ return validatedString;
314
+ }
315
+ }
316
+ let validValue = parseFloat(validatedString);
168
317
  if (isNaN(validValue)) {
169
318
  validValue = '';
170
319
  }
package/dist/react.cjs CHANGED
@@ -111,19 +111,14 @@ function _mergeRefs(...refs) {
111
111
  };
112
112
  }
113
113
 
114
- const AccordionItem = React.forwardRef(function AccordionItem(props, ref) {
115
- const { children, ...rest } = props;
116
- return React.createElement(customElements.getName(AccordionItemWC) ?? '%%prefix%%-accordion-item', { ...rest, ref }, children);
117
- });
118
-
119
- const Accordion = React.forwardRef(function Accordion(props, ref) {
114
+ const ActionsMenu = React.forwardRef(function ActionsMenu(props, ref) {
120
115
  const { children, ...rest } = props;
121
- return React.createElement(customElements.getName(AccordionWC) ?? '%%prefix%%-accordion', { ...rest, ref }, children);
116
+ return React.createElement(customElements.getName(ActionsMenuWC) ?? '%%prefix%%-actions-menu', { ...rest, ref }, children);
122
117
  });
123
118
 
124
- const ActionsMenu = React.forwardRef(function ActionsMenu(props, ref) {
119
+ const AccordionItem = React.forwardRef(function AccordionItem(props, ref) {
125
120
  const { children, ...rest } = props;
126
- return React.createElement(customElements.getName(ActionsMenuWC) ?? '%%prefix%%-actions-menu', { ...rest, ref }, children);
121
+ return React.createElement(customElements.getName(AccordionItemWC) ?? '%%prefix%%-accordion-item', { ...rest, ref }, children);
127
122
  });
128
123
 
129
124
  const AiCriteriaSearch = React.forwardRef(function AiCriteriaSearch(props, ref) {
@@ -153,6 +148,11 @@ const AiIndicator = React.forwardRef(function AiIndicator(props, ref) {
153
148
  return React.createElement(customElements.getName(AiIndicatorWC) ?? '%%prefix%%-ai-indicator', { ...rest, ref }, children);
154
149
  });
155
150
 
151
+ const Accordion = React.forwardRef(function Accordion(props, ref) {
152
+ const { children, ...rest } = props;
153
+ return React.createElement(customElements.getName(AccordionWC) ?? '%%prefix%%-accordion', { ...rest, ref }, children);
154
+ });
155
+
156
156
  const Anchor = React.forwardRef(function Anchor(props, ref) {
157
157
  const { children, ...rest } = props;
158
158
  return React.createElement(customElements.getName(AnchorWC) ?? '%%prefix%%-anchor', { ...rest, ref }, children);
@@ -1078,11 +1078,11 @@ const WeeklyRecurrence = React.forwardRef(function WeeklyRecurrence(props, ref)
1078
1078
  });
1079
1079
 
1080
1080
  module.exports = {
1081
- AccordionItem,
1082
- Accordion,
1083
1081
  ActionsMenu,
1082
+ AccordionItem,
1084
1083
  AiCriteriaSearch,
1085
1084
  AiIndicator,
1085
+ Accordion,
1086
1086
  Anchor,
1087
1087
  AnchoredRegion,
1088
1088
  Avatar,
package/dist/react.mjs CHANGED
@@ -109,19 +109,14 @@ function _mergeRefs(...refs) {
109
109
  };
110
110
  }
111
111
 
112
- export const AccordionItem = React.forwardRef(function AccordionItem(props, ref) {
113
- const { children, ...rest } = props;
114
- return React.createElement(customElements.getName(AccordionItemWC) ?? '%%prefix%%-accordion-item', { ...rest, ref }, children);
115
- });
116
-
117
- export const Accordion = React.forwardRef(function Accordion(props, ref) {
112
+ export const ActionsMenu = React.forwardRef(function ActionsMenu(props, ref) {
118
113
  const { children, ...rest } = props;
119
- return React.createElement(customElements.getName(AccordionWC) ?? '%%prefix%%-accordion', { ...rest, ref }, children);
114
+ return React.createElement(customElements.getName(ActionsMenuWC) ?? '%%prefix%%-actions-menu', { ...rest, ref }, children);
120
115
  });
121
116
 
122
- export const ActionsMenu = React.forwardRef(function ActionsMenu(props, ref) {
117
+ export const AccordionItem = React.forwardRef(function AccordionItem(props, ref) {
123
118
  const { children, ...rest } = props;
124
- return React.createElement(customElements.getName(ActionsMenuWC) ?? '%%prefix%%-actions-menu', { ...rest, ref }, children);
119
+ return React.createElement(customElements.getName(AccordionItemWC) ?? '%%prefix%%-accordion-item', { ...rest, ref }, children);
125
120
  });
126
121
 
127
122
  export const AiCriteriaSearch = React.forwardRef(function AiCriteriaSearch(props, ref) {
@@ -151,6 +146,11 @@ export const AiIndicator = React.forwardRef(function AiIndicator(props, ref) {
151
146
  return React.createElement(customElements.getName(AiIndicatorWC) ?? '%%prefix%%-ai-indicator', { ...rest, ref }, children);
152
147
  });
153
148
 
149
+ export const Accordion = React.forwardRef(function Accordion(props, ref) {
150
+ const { children, ...rest } = props;
151
+ return React.createElement(customElements.getName(AccordionWC) ?? '%%prefix%%-accordion', { ...rest, ref }, children);
152
+ });
153
+
154
154
  export const Anchor = React.forwardRef(function Anchor(props, ref) {
155
155
  const { children, ...rest } = props;
156
156
  return React.createElement(customElements.getName(AnchorWC) ?? '%%prefix%%-anchor', { ...rest, ref }, children);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/foundation-ui",
3
3
  "description": "Genesis Foundation UI",
4
- "version": "14.482.0",
4
+ "version": "14.482.1",
5
5
  "sideEffects": false,
6
6
  "license": "SEE LICENSE IN license.txt",
7
7
  "main": "dist/esm/index.js",
@@ -85,13 +85,13 @@
85
85
  }
86
86
  },
87
87
  "devDependencies": {
88
- "@genesislcap/foundation-testing": "14.482.0",
89
- "@genesislcap/genx": "14.482.0",
90
- "@genesislcap/rollup-builder": "14.482.0",
91
- "@genesislcap/ts-builder": "14.482.0",
92
- "@genesislcap/uvu-playwright-builder": "14.482.0",
93
- "@genesislcap/vite-builder": "14.482.0",
94
- "@genesislcap/webpack-builder": "14.482.0",
88
+ "@genesislcap/foundation-testing": "14.482.1",
89
+ "@genesislcap/genx": "14.482.1",
90
+ "@genesislcap/rollup-builder": "14.482.1",
91
+ "@genesislcap/ts-builder": "14.482.1",
92
+ "@genesislcap/uvu-playwright-builder": "14.482.1",
93
+ "@genesislcap/vite-builder": "14.482.1",
94
+ "@genesislcap/webpack-builder": "14.482.1",
95
95
  "copyfiles": "^2.4.1"
96
96
  },
97
97
  "dependencies": {
@@ -100,16 +100,16 @@
100
100
  "@fortawesome/free-regular-svg-icons": "^6.2.1",
101
101
  "@fortawesome/free-solid-svg-icons": "^6.2.1",
102
102
  "@genesiscommunitysuccess/analyzer-import-alias-plugin": "^5.0.3",
103
- "@genesislcap/expression-builder": "14.482.0",
104
- "@genesislcap/foundation-ai": "14.482.0",
105
- "@genesislcap/foundation-comms": "14.482.0",
106
- "@genesislcap/foundation-criteria": "14.482.0",
107
- "@genesislcap/foundation-errors": "14.482.0",
108
- "@genesislcap/foundation-events": "14.482.0",
109
- "@genesislcap/foundation-logger": "14.482.0",
110
- "@genesislcap/foundation-notifications": "14.482.0",
111
- "@genesislcap/foundation-user": "14.482.0",
112
- "@genesislcap/foundation-utils": "14.482.0",
103
+ "@genesislcap/expression-builder": "14.482.1",
104
+ "@genesislcap/foundation-ai": "14.482.1",
105
+ "@genesislcap/foundation-comms": "14.482.1",
106
+ "@genesislcap/foundation-criteria": "14.482.1",
107
+ "@genesislcap/foundation-errors": "14.482.1",
108
+ "@genesislcap/foundation-events": "14.482.1",
109
+ "@genesislcap/foundation-logger": "14.482.1",
110
+ "@genesislcap/foundation-notifications": "14.482.1",
111
+ "@genesislcap/foundation-user": "14.482.1",
112
+ "@genesislcap/foundation-utils": "14.482.1",
113
113
  "@microsoft/fast-colors": "5.3.1",
114
114
  "@microsoft/fast-components": "2.30.6",
115
115
  "@microsoft/fast-element": "1.14.0",
@@ -142,5 +142,5 @@
142
142
  "require": "./dist/react.cjs"
143
143
  }
144
144
  },
145
- "gitHead": "176fdab04821da415454fcdbc124f7fabac07aa7"
145
+ "gitHead": "43a902838587d527b6786bbb41a5c3784c638e70"
146
146
  }