@mantine-vue/core 3.3.0 → 3.4.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.
- package/cjs/index.cjs +74 -24
- package/cjs/index.cjs.map +1 -1
- package/esm/index.mjs +103 -53
- package/esm/index.mjs.map +1 -1
- package/lib/components/NumberInput/number-input-utils.d.ts +2 -0
- package/package.json +3 -3
package/cjs/index.cjs
CHANGED
|
@@ -1738,7 +1738,7 @@ function hashStyleProps(styles, media) {
|
|
|
1738
1738
|
return `mantine-vue-${Math.abs(hash).toString(36)}`;
|
|
1739
1739
|
}
|
|
1740
1740
|
function useRandomClassName() {
|
|
1741
|
-
return `mantine-vue-${Math.random().toString(36).slice(2, 9)}`;
|
|
1741
|
+
return `mantine-vue-${((0, vue.getCurrentInstance)() ? (0, vue.useId)() : Math.random().toString(36).slice(2, 9)).replace(/[^A-Za-z0-9_-]/g, "-")}`;
|
|
1742
1742
|
}
|
|
1743
1743
|
//#endregion
|
|
1744
1744
|
//#region src/core/Box/style-props/style-props-data.ts
|
|
@@ -13852,13 +13852,21 @@ var leadingZerosPattern = /^-?0\d+(\.\d+)?\.?$/;
|
|
|
13852
13852
|
var trailingZerosPattern = /\.\d*0$/;
|
|
13853
13853
|
var trailingDecimalSeparatorPattern = /^-?\d+\.$/;
|
|
13854
13854
|
function clamp$3(value, min, max) {
|
|
13855
|
-
return Math.min(max ??
|
|
13855
|
+
return Math.min(max ?? Number.POSITIVE_INFINITY, Math.max(min ?? Number.NEGATIVE_INFINITY, value));
|
|
13856
13856
|
}
|
|
13857
13857
|
function clampBigInt(value, min, max) {
|
|
13858
13858
|
if (min !== void 0 && value < min) return min;
|
|
13859
13859
|
if (max !== void 0 && value > max) return max;
|
|
13860
13860
|
return value;
|
|
13861
13861
|
}
|
|
13862
|
+
function canStep(value) {
|
|
13863
|
+
if (typeof value === "number") return value < Number.MAX_SAFE_INTEGER;
|
|
13864
|
+
return value === "" || value !== "-" && !Number.isNaN(Number(value)) && Number(value) < Number.MAX_SAFE_INTEGER;
|
|
13865
|
+
}
|
|
13866
|
+
function canStepBigInt(value, allowNegative) {
|
|
13867
|
+
if (typeof value === "bigint") return true;
|
|
13868
|
+
return value === "" || value !== "-" && (allowNegative || !value.startsWith("-")) && /^-?\d+$/.test(value);
|
|
13869
|
+
}
|
|
13862
13870
|
function stripFormatting(value, options) {
|
|
13863
13871
|
let next = value;
|
|
13864
13872
|
if (options.prefix && next.startsWith(options.prefix)) next = next.slice(options.prefix.length);
|
|
@@ -13888,9 +13896,19 @@ function parseNumberInputValue(rawValue, allowDecimal, allowNegative, allowLeadi
|
|
|
13888
13896
|
return parsed;
|
|
13889
13897
|
}
|
|
13890
13898
|
function sanitizeNumberInputString(rawValue, allowDecimal, allowNegative, decimalScale) {
|
|
13891
|
-
let normalized =
|
|
13892
|
-
|
|
13893
|
-
|
|
13899
|
+
let normalized = "";
|
|
13900
|
+
let hasDecimalSeparator = false;
|
|
13901
|
+
for (const character of rawValue) {
|
|
13902
|
+
if (character === "." && !allowDecimal) break;
|
|
13903
|
+
if (/\d/.test(character)) normalized += character;
|
|
13904
|
+
else if (character === "-" && allowNegative && normalized.length === 0) normalized = "-";
|
|
13905
|
+
else if (character === "." && allowDecimal && !hasDecimalSeparator) {
|
|
13906
|
+
normalized += character;
|
|
13907
|
+
hasDecimalSeparator = true;
|
|
13908
|
+
}
|
|
13909
|
+
}
|
|
13910
|
+
if (normalized.startsWith(".")) normalized = `0${normalized}`;
|
|
13911
|
+
else if (normalized.startsWith("-.")) normalized = `-0${normalized.slice(1)}`;
|
|
13894
13912
|
if (typeof decimalScale === "number" && normalized.includes(".")) {
|
|
13895
13913
|
const [integerPart, decimalPart = ""] = normalized.split(".");
|
|
13896
13914
|
return `${integerPart}.${decimalPart.slice(0, decimalScale)}`;
|
|
@@ -14110,7 +14128,6 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14110
14128
|
const slots = (0, vue.useSlots)();
|
|
14111
14129
|
const attrs = (0, vue.useAttrs)();
|
|
14112
14130
|
const inputRef = (0, vue.ref)(null);
|
|
14113
|
-
const isEditing = (0, vue.ref)(false);
|
|
14114
14131
|
const isBigIntMode = (0, vue.computed)(() => typeof props.modelValue === "bigint" || typeof props.defaultValue === "bigint");
|
|
14115
14132
|
const [value, setValue] = (0, _mantine_vue_hooks.useUncontrolled)({
|
|
14116
14133
|
value: () => props.modelValue,
|
|
@@ -14143,11 +14160,7 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14143
14160
|
thousandsGroupStyle: props.thousandsGroupStyle,
|
|
14144
14161
|
thousandSeparator: props.thousandSeparator
|
|
14145
14162
|
}));
|
|
14146
|
-
const
|
|
14147
|
-
...formatterOptions.value,
|
|
14148
|
-
fixedDecimalScale: isEditing.value || typeof nextValue === "string" ? false : formatterOptions.value.fixedDecimalScale
|
|
14149
|
-
});
|
|
14150
|
-
const displayValue = (0, vue.computed)(() => value.value === "" || value.value === "-" ? String(value.value) : formatNumber(value.value, getFormatterOptions()));
|
|
14163
|
+
const displayValue = (0, vue.computed)(() => value.value === "" || value.value === "-" ? String(value.value) : formatNumber(value.value, formatterOptions.value));
|
|
14151
14164
|
const clampCaretToFormatting = (input) => {
|
|
14152
14165
|
const { min, max } = getCaretBoundaries(input.value, formatterOptions.value);
|
|
14153
14166
|
const start = input.selectionStart;
|
|
@@ -14160,6 +14173,14 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14160
14173
|
const scheduleCaretClamp = (input) => {
|
|
14161
14174
|
setTimeout(() => clampCaretToFormatting(input), 0);
|
|
14162
14175
|
};
|
|
14176
|
+
const getFormattedCaretPosition = (value, formattedValue, position) => {
|
|
14177
|
+
let formattedPosition = 0;
|
|
14178
|
+
for (const character of value.slice(0, position)) {
|
|
14179
|
+
const nextPosition = formattedValue.indexOf(character, formattedPosition);
|
|
14180
|
+
if (nextPosition !== -1) formattedPosition = nextPosition + 1;
|
|
14181
|
+
}
|
|
14182
|
+
return formattedPosition;
|
|
14183
|
+
};
|
|
14163
14184
|
const commitValue = (nextValue, source = "event") => {
|
|
14164
14185
|
if (props.clampBehavior === "strict") {
|
|
14165
14186
|
const numeric = toNumeric(nextValue);
|
|
@@ -14171,18 +14192,19 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14171
14192
|
const raw = typeof nextValue === "bigint" ? nextValue.toString() : String(nextValue);
|
|
14172
14193
|
emit("value-change", {
|
|
14173
14194
|
floatValue: typeof nextValue === "number" ? nextValue : Number.isNaN(Number(raw)) ? void 0 : Number(raw),
|
|
14174
|
-
formattedValue: nextValue === "" ? "" : formatNumber(nextValue,
|
|
14195
|
+
formattedValue: nextValue === "" ? "" : formatNumber(nextValue, formatterOptions.value),
|
|
14175
14196
|
value: raw
|
|
14176
14197
|
}, { source });
|
|
14177
14198
|
};
|
|
14199
|
+
const canStepValue = (0, vue.computed)(() => isBigIntMode.value ? canStepBigInt(value.value, props.allowNegative) : canStep(value.value));
|
|
14178
14200
|
const stepValue = (direction) => {
|
|
14179
|
-
if (props.disabled || props.readOnly) return;
|
|
14201
|
+
if (props.disabled || props.readOnly || !canStepValue.value) return;
|
|
14180
14202
|
if (isBigIntMode.value) {
|
|
14181
14203
|
const current = typeof value.value === "bigint" ? value.value : BigInt(0);
|
|
14182
14204
|
const step = typeof props.step === "bigint" ? props.step : BigInt(props.step);
|
|
14183
14205
|
const start = typeof props.startValue === "bigint" ? props.startValue : BigInt(props.startValue);
|
|
14184
14206
|
const next = (value.value === "" || value.value === "-" ? start : current) + step * BigInt(direction);
|
|
14185
|
-
const min = typeof props.min === "bigint" ? props.min : props.min === void 0 ? void 0 : BigInt(props.min);
|
|
14207
|
+
const min = typeof props.min === "bigint" ? props.min : props.min === void 0 ? props.allowNegative ? void 0 : BigInt(0) : BigInt(props.min);
|
|
14186
14208
|
const max = typeof props.max === "bigint" ? props.max : props.max === void 0 ? void 0 : BigInt(props.max);
|
|
14187
14209
|
const clamped = clampBigInt(next, min, max);
|
|
14188
14210
|
if (max !== void 0 && next > max) emit("max-reached");
|
|
@@ -14272,7 +14294,7 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14272
14294
|
onPointercancel: clearHold
|
|
14273
14295
|
}, () => (0, vue.h)(NumberInputChevron, { direction: "down" }))]);
|
|
14274
14296
|
/** The step controls double as the right section unless one was supplied. */
|
|
14275
|
-
const rightSection = (0, vue.computed)(() => props.hideControls || props.readOnly ? props.rightSection : props.rightSection !== void 0 || slots.rightSection ? props.rightSection : controls);
|
|
14297
|
+
const rightSection = (0, vue.computed)(() => props.hideControls || props.readOnly || !canStepValue.value ? props.rightSection : props.rightSection !== void 0 || slots.rightSection ? props.rightSection : controls);
|
|
14276
14298
|
const rightSectionPointerEvents = (0, vue.computed)(() => props.rightSectionPointerEvents ?? (props.disabled ? "none" : void 0));
|
|
14277
14299
|
const rightSectionWidth = (0, vue.computed)(() => props.rightSectionWidth ?? `var(--ni-right-section-width-${props.size || "sm"})`);
|
|
14278
14300
|
/** `bigint` values are integers only, so the numeric keypad is the right hint. */
|
|
@@ -14289,22 +14311,52 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14289
14311
|
};
|
|
14290
14312
|
__expose({ rootElement });
|
|
14291
14313
|
function onInput(event) {
|
|
14292
|
-
isEditing.value = true;
|
|
14293
14314
|
const input = event.currentTarget;
|
|
14294
|
-
const
|
|
14315
|
+
const inputValue = input.value;
|
|
14316
|
+
const selectionStart = input.selectionStart;
|
|
14317
|
+
const selectionEnd = input.selectionEnd;
|
|
14318
|
+
const rawValue = stripFormatting(inputValue, formatterOptions.value);
|
|
14295
14319
|
const decimalSeparator = props.decimalSeparator || ".";
|
|
14296
|
-
const sanitized = sanitizeNumberInputString(props.allowedDecimalSeparators.filter((separator) => separator !== decimalSeparator).reduce((acc, separator) => acc.split(separator).join("."), rawValue.replace(decimalSeparator, ".")), props.allowDecimal, props.allowNegative, props.decimalScale);
|
|
14320
|
+
const sanitized = sanitizeNumberInputString(props.allowedDecimalSeparators.filter((separator) => separator !== decimalSeparator).reduce((acc, separator) => acc.split(separator).join("."), rawValue.replace(decimalSeparator, ".")), isBigIntMode.value ? false : props.allowDecimal, props.allowNegative, props.decimalScale);
|
|
14297
14321
|
const nextValue = isBigIntMode.value ? parseBigIntInputValue(sanitized, props.allowNegative, props.allowLeadingZeros) : parseNumberInputValue(sanitized, props.allowDecimal, props.allowNegative, props.allowLeadingZeros, props.decimalScale, props.fixedDecimalScale);
|
|
14298
14322
|
if (props.clampBehavior === "strict" && !isBigIntMode.value && !isStrictAllowed(nextValue, typeof props.min === "number" ? props.min : void 0, typeof props.max === "number" ? props.max : void 0)) {
|
|
14299
14323
|
restoreInputValue(input, displayValue.value);
|
|
14300
14324
|
return;
|
|
14301
14325
|
}
|
|
14302
|
-
const formattedNextValue = nextValue === "" || nextValue === "-" ? String(nextValue) : formatNumber(nextValue,
|
|
14303
|
-
if (input.value !== formattedNextValue)
|
|
14326
|
+
const formattedNextValue = nextValue === "" || nextValue === "-" ? String(nextValue) : formatNumber(nextValue, formatterOptions.value);
|
|
14327
|
+
if (input.value !== formattedNextValue) {
|
|
14328
|
+
restoreInputValue(input, formattedNextValue);
|
|
14329
|
+
if (props.fixedDecimalScale && selectionStart !== null && selectionEnd !== null) input.setSelectionRange(getFormattedCaretPosition(inputValue, formattedNextValue, selectionStart), getFormattedCaretPosition(inputValue, formattedNextValue, selectionEnd));
|
|
14330
|
+
}
|
|
14304
14331
|
scheduleCaretClamp(input);
|
|
14305
|
-
commitValue(nextValue);
|
|
14332
|
+
if (!Object.is(nextValue, value.value)) commitValue(nextValue);
|
|
14306
14333
|
}
|
|
14307
14334
|
function onKeydown(event) {
|
|
14335
|
+
const input = event.currentTarget;
|
|
14336
|
+
if (event.key === "Backspace" && !props.readOnly && !props.disabled && input.selectionStart !== null && input.selectionStart === input.selectionEnd) {
|
|
14337
|
+
if (input.selectionStart === 0) event.preventDefault();
|
|
14338
|
+
else if (props.fixedDecimalScale && typeof props.decimalScale === "number") {
|
|
14339
|
+
const decimalPosition = input.value.indexOf(props.decimalSeparator);
|
|
14340
|
+
const isAfterDecimalSeparator = input.value[input.selectionStart - 1] === props.decimalSeparator;
|
|
14341
|
+
const deletePosition = input.selectionStart - (isAfterDecimalSeparator ? 2 : 1);
|
|
14342
|
+
if (deletePosition >= 0 && deletePosition < decimalPosition) {
|
|
14343
|
+
const nextInputValue = input.value.slice(0, deletePosition) + input.value.slice(deletePosition + 1);
|
|
14344
|
+
const unformattedValue = stripFormatting(nextInputValue, formatterOptions.value);
|
|
14345
|
+
const [integerPart, decimalPart = ""] = (unformattedValue.startsWith("-") ? unformattedValue.slice(1) : unformattedValue).split(".");
|
|
14346
|
+
if (!/\d/.test(integerPart) && /^0*$/.test(decimalPart)) {
|
|
14347
|
+
event.preventDefault();
|
|
14348
|
+
input.value = "";
|
|
14349
|
+
input.setSelectionRange(0, 0);
|
|
14350
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
14351
|
+
} else if (isAfterDecimalSeparator) {
|
|
14352
|
+
event.preventDefault();
|
|
14353
|
+
input.value = nextInputValue;
|
|
14354
|
+
input.setSelectionRange(deletePosition, deletePosition);
|
|
14355
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
14356
|
+
}
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
}
|
|
14308
14360
|
if (!props.readOnly && props.withKeyboardEvents && event.key === "ArrowUp") {
|
|
14309
14361
|
event.preventDefault();
|
|
14310
14362
|
stepValue(1);
|
|
@@ -14313,7 +14365,7 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14313
14365
|
event.preventDefault();
|
|
14314
14366
|
stepValue(-1);
|
|
14315
14367
|
}
|
|
14316
|
-
scheduleCaretClamp(
|
|
14368
|
+
scheduleCaretClamp(input);
|
|
14317
14369
|
}
|
|
14318
14370
|
function onKeyup(event) {
|
|
14319
14371
|
scheduleCaretClamp(event.currentTarget);
|
|
@@ -14322,12 +14374,10 @@ var NumberInput = factory(/* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
14322
14374
|
scheduleCaretClamp(event.currentTarget);
|
|
14323
14375
|
}
|
|
14324
14376
|
function onFocus(event) {
|
|
14325
|
-
isEditing.value = true;
|
|
14326
14377
|
if (props.selectAllOnFocus) window.setTimeout(() => inputRef.value?.select(), 0);
|
|
14327
14378
|
else scheduleCaretClamp(event.currentTarget);
|
|
14328
14379
|
}
|
|
14329
14380
|
function onBlur() {
|
|
14330
|
-
isEditing.value = false;
|
|
14331
14381
|
let sanitizedValue = value.value;
|
|
14332
14382
|
const min = typeof props.min === "number" ? props.min : void 0;
|
|
14333
14383
|
const max = typeof props.max === "number" ? props.max : void 0;
|