Skip to content

Commit

Permalink
feat(number-field): allowedInput defaults to locale and format char…
Browse files Browse the repository at this point in the history
…acters. (#372)
  • Loading branch information
jer3m01 authored Mar 16, 2024
1 parent 8e34972 commit 570a6e9
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 7 deletions.
9 changes: 9 additions & 0 deletions .changeset/short-shoes-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@kobalte/core": patch
---

## v0.12.6 (March 16, 2024)

**New features**

- NumberField: `allowedInput` defaults to locale and format characters. ([#372](https://github.com/kobaltedev/kobalte/pull/372))
6 changes: 6 additions & 0 deletions apps/docs/src/routes/docs/changelog/0-12-x.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# v0.12.x

## v0.12.6 (March 16, 2024)

**New features**

- NumberField: `allowedInput` defaults to locale and format characters. ([#372](https://github.com/kobaltedev/kobalte/pull/372))

## v0.12.5 (March 14, 2024)

**Bug fixes**
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/routes/docs/core/components/number-field.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ The number field supports autofill through `NumberField.HiddenInput`.
| changeOnWheel | `boolean` <br/> Whether to increment/decrement on wheel scroll inside the number field. |
| format | `boolean` <br/> Whether to format the input value. |
| formatOptions | [`Intl.NumberFormatOptions`](https://github.com/microsoft/TypeScript/blob/353ccb7688351ae33ccf6e0acb913aa30621eaf4/src/lib/es2020.intl.d.ts#L243-L251) <br/> Formating options for the value of the number field. |
| allowedInput | `RegExp` <br/> Allowed input characters in the number field (only prevents onInput, not paste), defautls to `/[-\d,.\s]/`. |
| allowedInput | `RegExp` <br/> Allowed input characters in the number field (only prevents onInput, not paste), defaults to locale and format characters. |
| name | `string` <br/> The name of the NumberField.HiddenInput of the number field, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
| validationState | `'valid' \| 'invalid'` <br/> Whether the number field should display its "valid" or "invalid" visual styling. |
| required | `boolean` <br/> Whether the user must fill the number field before the owning form can be submitted. |
Expand Down
56 changes: 50 additions & 6 deletions packages/core/src/number-field/number-field-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export interface NumberFieldRootOptions
/** Options for formatting input value. */
formatOptions?: Intl.NumberFormatOptions;

/** Allowed input characters, defautls to `/[-\d,.\s]/`. */
/** Allowed input characters, defaults to locale and format characters. */
allowedInput?: RegExp;

/**
Expand Down Expand Up @@ -125,7 +125,6 @@ export function NumberFieldRoot(props: NumberFieldRootProps) {
maxValue: Number.MAX_SAFE_INTEGER,
step: 1,
changeOnWheel: true,
allowedInput: /[-\d,.\s]/,
},
props,
);
Expand Down Expand Up @@ -164,6 +163,39 @@ export function NumberFieldRoot(props: NumberFieldRootProps) {
return new NumberFormatter(locale(), local.formatOptions);
});

const allNumberFormatParts = createMemo(() => [
...numberFormatter().formatToParts(-1234567890.1),
...numberFormatter().formatToParts(1),
]);

const uniquePartTypes: Array<Intl.NumberFormatPart["type"]> = [
"decimal",
"minusSign",
"plusSign",
];
const commonPartTypes: Array<Intl.NumberFormatPart["type"]> = [
"integer",
"group",
"percentSign",
];

const uniqueCharacters = () =>
new Set(
allNumberFormatParts()
.filter((part) => uniquePartTypes.includes(part.type))
.map((part) => part.value)
.join("")
.split(""),
);
const commonCharacters = () =>
new Set(
allNumberFormatParts()
.filter((part) => commonPartTypes.includes(part.type))
.map((part) => part.value)
.join("")
.split(""),
);

const parseRawValue = (value: string | number | undefined) =>
local.format && typeof value !== "number"
? numberParser().parse(value ?? "")
Expand All @@ -182,6 +214,21 @@ export function NumberFieldRoot(props: NumberFieldRootProps) {

local.onRawValueChange?.(parseRawValue(value()));

function isAllowedInput(char: string): boolean {
if (local.allowedInput !== undefined) return local.allowedInput.test(char);

if (commonCharacters().has(char)) return true;

if (uniqueCharacters().has(char)) {
let val = value() ?? "";
if (typeof val === "number") val = numberFormatter().format(val);

return !val.split("").includes(char);
}

return false;
}

const { formControlContext } = createFormControl(formControlProps);

createFormResetListener(
Expand All @@ -200,10 +247,7 @@ export function NumberFieldRoot(props: NumberFieldRootProps) {

const target = e.target as HTMLInputElement;

if (
e.inputType !== "insertText" ||
local.allowedInput!.test(e.data || "")
) {
if (e.inputType !== "insertText" || isAllowedInput(e.data || "")) {
setValue(target.value);
}

Expand Down

0 comments on commit 570a6e9

Please sign in to comment.