@nexdom/uimed-vue 2.0.0-beta.41 → 2.0.0-beta.43
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/dist/components.d.ts +23 -12
- package/dist/components.js +76 -55
- package/package.json +1 -1
package/dist/components.d.ts
CHANGED
|
@@ -652,7 +652,9 @@ type MaskFieldVariant = TextFieldVariant;
|
|
|
652
652
|
* Masks the library provides:
|
|
653
653
|
*
|
|
654
654
|
* - `cpf`: `###.###.###-##` (e.g. `123.456.789-09`);
|
|
655
|
-
* - `cnpj`:
|
|
655
|
+
* - `cnpj`: `##.###.###/####-##`, where the first 12 positions also accept
|
|
656
|
+
* letters, typed in uppercase or lowercase and kept in uppercase (e.g.
|
|
657
|
+
* `12.345.678/0001-95` or the alphanumeric `12.ABC.345/01DE-35`);
|
|
656
658
|
* - `cep`: `#####-###` (e.g. `01310-100`);
|
|
657
659
|
* - `phone`: `(##) #####-####` (e.g. `(11) 91234-5678`);
|
|
658
660
|
* - `date`: `##/##/####` (e.g. `31/12/2026`), formatting only.
|
|
@@ -691,14 +693,21 @@ type MaskFieldProps = {
|
|
|
691
693
|
* inserted automatically (e.g. `####-##/####` or `Nº ####`). A custom mask
|
|
692
694
|
* must contain at least one `#`.
|
|
693
695
|
*
|
|
694
|
-
* Only digits are accepted, up to the number of `#` in the mask,
|
|
695
|
-
*
|
|
696
|
-
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
696
|
+
* Only digits are accepted, up to the number of `#` in the mask, except in
|
|
697
|
+
* the first 12 positions of `cnpj`, which also accept letters (A–Z, without
|
|
698
|
+
* accents, typed in uppercase or lowercase) for the alphanumeric CNPJ (only
|
|
699
|
+
* with `cnpj`: the custom mask `##.###.###/####-##` accepts only digits). The
|
|
700
|
+
* `v-model` holds only these characters, with letters in uppercase (e.g.
|
|
701
|
+
* `12345678909` for `cpf`, and `12345678000195` or `12ABC34501DE35` for
|
|
702
|
+
* `cnpj`). A literal the user could also type, such as a fixed digit
|
|
703
|
+
* (`0800 ###-####`), isn't supported: where the literal is expected, the
|
|
704
|
+
* same character is read as the literal.
|
|
699
705
|
*
|
|
700
|
-
*
|
|
701
|
-
*
|
|
706
|
+
* Editing in the middle of the value shifts the characters after it, and one
|
|
707
|
+
* that doesn't fit its new position (e.g. a letter of `cnpj` shifted into
|
|
708
|
+
* the last 2 positions) is discarded.
|
|
709
|
+
*
|
|
710
|
+
* The `cpf` and `cnpj` masks don't validate check digits.
|
|
702
711
|
*
|
|
703
712
|
* Changing it keeps the `v-model`: a value that doesn't fit the new mask
|
|
704
713
|
* (e.g. longer than it) is displayed cut and fails validation with "Valor
|
|
@@ -738,7 +747,8 @@ type MaskFieldProps = {
|
|
|
738
747
|
label?: string;
|
|
739
748
|
/**
|
|
740
749
|
* Field placeholder. Defaults to the mask, with `0` in place of each `#`,
|
|
741
|
-
* e.g. `000.000.000-00` for `cpf
|
|
750
|
+
* e.g. `000.000.000-00` for `cpf`, `00.000.000/0000-00` for `cnpj` and
|
|
751
|
+
* `Nº 0000` for `Nº ####`.
|
|
742
752
|
*/
|
|
743
753
|
placeholder?: string;
|
|
744
754
|
/**
|
|
@@ -755,9 +765,10 @@ type MaskFieldProps = {
|
|
|
755
765
|
//#endregion
|
|
756
766
|
//#region src/components/inputs/mask-field/mask-field.vue.d.ts
|
|
757
767
|
/**
|
|
758
|
-
* Text field that masks the value while the user types, such as CPF, CNPJ
|
|
759
|
-
* CEP, phone or a custom mask. Its value holds only
|
|
760
|
-
* mask's literals
|
|
768
|
+
* Text field that masks the value while the user types, such as CPF, CNPJ
|
|
769
|
+
* (numeric or alphanumeric), CEP, phone or a custom mask. Its value holds only
|
|
770
|
+
* the typed characters, without the mask's literals and with letters in
|
|
771
|
+
* uppercase.
|
|
761
772
|
*
|
|
762
773
|
* @example
|
|
763
774
|
* ```vue
|
package/dist/components.js
CHANGED
|
@@ -488,25 +488,41 @@ function useTextFieldType(type, isPasswordVisible) {
|
|
|
488
488
|
});
|
|
489
489
|
}
|
|
490
490
|
/**
|
|
491
|
-
* Controls the
|
|
492
|
-
*
|
|
493
|
-
* `
|
|
491
|
+
* Controls the icon at the end of the field: a decorative magnifier on
|
|
492
|
+
* `search`, and the toggle that shows or hides the value on `password`. The
|
|
493
|
+
* toggle works with click, `Enter` and `Space`, does nothing while disabled,
|
|
494
|
+
* and the password hides again whenever the type stops being `password`.
|
|
494
495
|
*/
|
|
495
|
-
function
|
|
496
|
+
function useTextFieldAppendIcon(type, disabled) {
|
|
496
497
|
const isPasswordField = computed(() => toValue(type) === "password");
|
|
497
498
|
const isPasswordVisible = ref(false);
|
|
498
|
-
const icon = computed(() => isPasswordVisible.value ? "mdi-eye-off" : "mdi-eye");
|
|
499
499
|
watch(isPasswordField, () => {
|
|
500
500
|
isPasswordVisible.value = false;
|
|
501
501
|
});
|
|
502
502
|
function toggle() {
|
|
503
|
+
if (toValue(disabled)) return;
|
|
503
504
|
isPasswordVisible.value = !isPasswordVisible.value;
|
|
504
505
|
}
|
|
506
|
+
function onKeydown(event) {
|
|
507
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
508
|
+
event.preventDefault();
|
|
509
|
+
event.stopPropagation();
|
|
510
|
+
toggle();
|
|
511
|
+
}
|
|
512
|
+
const iconProps = computed(() => {
|
|
513
|
+
if (toValue(type) === "search") return { icon: "mdi-magnify" };
|
|
514
|
+
if (!isPasswordField.value) return void 0;
|
|
515
|
+
return {
|
|
516
|
+
icon: isPasswordVisible.value ? "mdi-eye-off" : "mdi-eye",
|
|
517
|
+
"aria-label": "Mostrar senha",
|
|
518
|
+
"aria-pressed": isPasswordVisible.value,
|
|
519
|
+
onClick: toggle,
|
|
520
|
+
onKeydown
|
|
521
|
+
};
|
|
522
|
+
});
|
|
505
523
|
return {
|
|
506
|
-
isPasswordField,
|
|
507
524
|
isPasswordVisible: readonly(isPasswordVisible),
|
|
508
|
-
|
|
509
|
-
toggle
|
|
525
|
+
iconProps
|
|
510
526
|
};
|
|
511
527
|
}
|
|
512
528
|
function useTextFieldRules(props) {
|
|
@@ -614,12 +630,10 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
614
630
|
const modelValue = useModel(__props, "modelValue");
|
|
615
631
|
const props = __props;
|
|
616
632
|
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
617
|
-
const {
|
|
633
|
+
const { isPasswordVisible, iconProps: appendIconProps } = useTextFieldAppendIcon(() => props.type, () => props.disabled);
|
|
618
634
|
const vuetifyType = useTextFieldType(() => props.type, isPasswordVisible);
|
|
619
635
|
const rules = useTextFieldRules(props);
|
|
620
|
-
const
|
|
621
|
-
const computedClearable = computed(() => props.clearable ?? isSearchField.value);
|
|
622
|
-
const appendIcon = computed(() => isSearchField.value ? "mdi-magnify" : void 0);
|
|
636
|
+
const computedClearable = computed(() => props.clearable ?? props.type === "search");
|
|
623
637
|
function clear() {
|
|
624
638
|
modelValue.value = "";
|
|
625
639
|
}
|
|
@@ -629,7 +643,6 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
629
643
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => modelValue.value = $event),
|
|
630
644
|
variant: unref(vuetifyVariant),
|
|
631
645
|
type: unref(vuetifyType),
|
|
632
|
-
"append-inner-icon": appendIcon.value,
|
|
633
646
|
rules: unref(rules),
|
|
634
647
|
"data-testid": props.dataTestid,
|
|
635
648
|
disabled: props.disabled,
|
|
@@ -644,28 +657,14 @@ var text_field_default = /* @__PURE__ */ defineComponent({
|
|
|
644
657
|
}, createSlots({
|
|
645
658
|
loader: withCtx((loader) => [createVNode(field_loader_default, normalizeProps(guardReactiveProps(loader)), null, 16)]),
|
|
646
659
|
_: 2
|
|
647
|
-
}, [unref(
|
|
660
|
+
}, [unref(appendIconProps) ? {
|
|
648
661
|
name: "append-inner",
|
|
649
|
-
fn: withCtx(() => [createVNode(unref(
|
|
650
|
-
icon: unref(passwordToggleIcon),
|
|
651
|
-
"aria-label": "Mostrar senha",
|
|
652
|
-
"aria-pressed": unref(isPasswordVisible),
|
|
653
|
-
disabled: props.disabled,
|
|
654
|
-
size: "small",
|
|
655
|
-
variant: "text",
|
|
656
|
-
onClick: unref(togglePassword)
|
|
657
|
-
}, null, 8, [
|
|
658
|
-
"icon",
|
|
659
|
-
"aria-pressed",
|
|
660
|
-
"disabled",
|
|
661
|
-
"onClick"
|
|
662
|
-
])]),
|
|
662
|
+
fn: withCtx(() => [createVNode(unref(VIcon), mergeProps(unref(appendIconProps), { disabled: props.disabled }), null, 16, ["disabled"])]),
|
|
663
663
|
key: "0"
|
|
664
664
|
} : void 0]), 1032, [
|
|
665
665
|
"modelValue",
|
|
666
666
|
"variant",
|
|
667
667
|
"type",
|
|
668
|
-
"append-inner-icon",
|
|
669
668
|
"rules",
|
|
670
669
|
"data-testid",
|
|
671
670
|
"disabled",
|
|
@@ -1918,79 +1917,96 @@ var date_time_field_default = /* @__PURE__ */ defineComponent({
|
|
|
1918
1917
|
//#endregion
|
|
1919
1918
|
//#region src/composables/inputs/mask-field.ts
|
|
1920
1919
|
/**
|
|
1921
|
-
* Masks of the presets
|
|
1922
|
-
*
|
|
1920
|
+
* Masks of the presets, as Vuetify reads them: `#` is a digit and `N` is a
|
|
1921
|
+
* letter or a digit, with letters converted to uppercase. Our preset names
|
|
1922
|
+
* always map to these masks, never to Vuetify's own presets (e.g. its American
|
|
1923
|
+
* `phone`).
|
|
1923
1924
|
*/
|
|
1924
1925
|
const maskFieldPresets = {
|
|
1925
1926
|
cpf: "###.###.###-##",
|
|
1926
|
-
cnpj: "
|
|
1927
|
+
cnpj: "NN.NNN.NNN/NNNN-##",
|
|
1927
1928
|
cep: "#####-###",
|
|
1928
1929
|
phone: "(##) #####-####",
|
|
1929
1930
|
date: "##/##/####"
|
|
1930
1931
|
};
|
|
1931
1932
|
/**
|
|
1932
|
-
* Returns the mask of a preset, or the given mask
|
|
1933
|
-
* one.
|
|
1933
|
+
* Returns the mask as Vuetify reads it: the mask of a preset, or the given mask
|
|
1934
|
+
* itself, escaped, when it's a custom one.
|
|
1934
1935
|
*
|
|
1935
1936
|
* It takes any string, as the `mask` prop may get one through a cast or from
|
|
1936
1937
|
* JavaScript: a string that isn't a preset is taken as the mask.
|
|
1937
1938
|
*/
|
|
1938
1939
|
function resolveMask(mask) {
|
|
1939
|
-
return isMaskFieldPreset(mask) ? maskFieldPresets[mask] : mask;
|
|
1940
|
+
return isMaskFieldPreset(mask) ? maskFieldPresets[mask] : toVuetifyMask(mask);
|
|
1940
1941
|
}
|
|
1941
1942
|
/**
|
|
1942
|
-
* Returns a mask as Vuetify reads it. `#` is
|
|
1943
|
-
* adds its own tokens (`A`, `a`, `N`, `n` and `X`)
|
|
1944
|
-
* these characters are escaped to stay literals.
|
|
1943
|
+
* Returns a custom mask as Vuetify reads it. `#` is the only token of custom
|
|
1944
|
+
* masks, but Vuetify always adds its own tokens (`A`, `a`, `N`, `n` and `X`)
|
|
1945
|
+
* and its escape (`\`), so these characters are escaped to stay literals.
|
|
1945
1946
|
*/
|
|
1946
1947
|
function toVuetifyMask(mask) {
|
|
1947
1948
|
return mask.replaceAll(/[AaNnX\\]/g, String.raw`\$&`);
|
|
1948
1949
|
}
|
|
1949
1950
|
/**
|
|
1950
|
-
* Returns the
|
|
1951
|
-
*
|
|
1951
|
+
* Returns the tokens of a mask as Vuetify reads it (see {@link resolveMask}),
|
|
1952
|
+
* in order, without its literals (e.g. `NNNNNNNNNNNN##` for `cnpj`).
|
|
1953
|
+
*/
|
|
1954
|
+
function getMaskTokens(mask) {
|
|
1955
|
+
return mask.replaceAll(/\\.|[^#N]/g, "");
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* Returns the default placeholder of a mask as Vuetify reads it (see
|
|
1959
|
+
* {@link resolveMask}): the mask with `0` in place of each token, keeping its
|
|
1960
|
+
* literals (e.g. `000.000.000-00` for `cpf` and `Nº 0000` for `Nº ####`).
|
|
1952
1961
|
*/
|
|
1953
1962
|
function getMaskPlaceholder(mask) {
|
|
1954
|
-
return mask.replaceAll(
|
|
1963
|
+
return mask.replaceAll(/\\(.)|[#N]/g, (_token, literal) => literal ?? "0");
|
|
1955
1964
|
}
|
|
1956
1965
|
function isMaskFieldPreset(mask) {
|
|
1957
1966
|
return Object.hasOwn(maskFieldPresets, mask);
|
|
1958
1967
|
}
|
|
1959
1968
|
/**
|
|
1960
|
-
* Keeps the input masked while the user edits it, emitting only the
|
|
1961
|
-
* (Vuetify's `unmask`).
|
|
1969
|
+
* Keeps the input masked while the user edits it, emitting only the
|
|
1970
|
+
* characters of the tokens (Vuetify's `unmask`), with letters in uppercase.
|
|
1962
1971
|
*
|
|
1963
|
-
* A `v-model` out of the mask's format (masked,
|
|
1964
|
-
* the mask doesn't accept) is displayed normalized,
|
|
1965
|
-
* validated as it is, so a value that doesn't fit
|
|
1972
|
+
* A `v-model` out of the mask's format (masked, with lowercase letters, or with
|
|
1973
|
+
* characters or length the mask doesn't accept) is displayed normalized,
|
|
1974
|
+
* without being emitted, and validated as it is, so a value that doesn't fit
|
|
1975
|
+
* the mask fails validation.
|
|
1966
1976
|
*/
|
|
1967
1977
|
function useMaskField(props, model) {
|
|
1968
1978
|
const mask = computed(() => resolveMask(props.mask));
|
|
1969
|
-
const
|
|
1979
|
+
const tokens = computed(() => getMaskTokens(mask.value));
|
|
1980
|
+
const acceptsLetters = computed(() => tokens.value.includes("N"));
|
|
1970
1981
|
const vuetifyMask = useMask({ get mask() {
|
|
1971
1982
|
return {
|
|
1972
|
-
mask:
|
|
1983
|
+
mask: mask.value,
|
|
1973
1984
|
tokens: {}
|
|
1974
1985
|
};
|
|
1975
1986
|
} });
|
|
1976
1987
|
const displayValue = computed(() => vuetifyMask.mask(unmask(model.value)));
|
|
1977
1988
|
const placeholder = computed(() => props.placeholder ?? getMaskPlaceholder(mask.value));
|
|
1989
|
+
const inputMode = computed(() => acceptsLetters.value ? "text" : "numeric");
|
|
1990
|
+
const autocapitalize = computed(() => acceptsLetters.value ? "characters" : void 0);
|
|
1978
1991
|
const defaultRules = useRules(props);
|
|
1979
1992
|
const rules = computed(() => [
|
|
1980
1993
|
...defaultRules.value,
|
|
1981
|
-
(value) => !value || !
|
|
1982
|
-
(value) => !value ||
|
|
1994
|
+
(value) => !value || !isValid(value) || isComplete(value) || "Valor incompleto",
|
|
1995
|
+
(value) => !value || isValid(value) || "Valor inválido"
|
|
1983
1996
|
]);
|
|
1984
1997
|
function unmask(text) {
|
|
1985
1998
|
return vuetifyMask.unmask(text) ?? "";
|
|
1986
1999
|
}
|
|
2000
|
+
function isValid(value) {
|
|
2001
|
+
return unmask(value).toUpperCase() === unmask(vuetifyMask.mask(value));
|
|
2002
|
+
}
|
|
1987
2003
|
function isComplete(value) {
|
|
1988
|
-
return unmask(vuetifyMask.mask(value)).length ===
|
|
2004
|
+
return unmask(vuetifyMask.mask(value)).length === tokens.value.length;
|
|
1989
2005
|
}
|
|
1990
2006
|
/**
|
|
1991
2007
|
* Returns the position in a masked text right after the given number of
|
|
1992
|
-
*
|
|
1993
|
-
* (as Vuetify's mask input does).
|
|
2008
|
+
* characters of the value, skipping the literals after it unless the user
|
|
2009
|
+
* deleted backwards (as Vuetify's mask input does).
|
|
1994
2010
|
*/
|
|
1995
2011
|
function findCaret(masked, valueLength, deletedBackwards) {
|
|
1996
2012
|
let caret = 0;
|
|
@@ -2020,6 +2036,8 @@ function useMaskField(props, model) {
|
|
|
2020
2036
|
return {
|
|
2021
2037
|
displayValue,
|
|
2022
2038
|
placeholder,
|
|
2039
|
+
inputMode,
|
|
2040
|
+
autocapitalize,
|
|
2023
2041
|
rules,
|
|
2024
2042
|
onInput,
|
|
2025
2043
|
onCompositionEnd
|
|
@@ -2088,7 +2106,7 @@ var mask_field_default = /* @__PURE__ */ defineComponent({
|
|
|
2088
2106
|
const modelValue = useModel(__props, "modelValue");
|
|
2089
2107
|
const props = __props;
|
|
2090
2108
|
const vuetifyVariant = useTextFieldVariant(() => props.variant);
|
|
2091
|
-
const { displayValue, placeholder, rules, onInput, onCompositionEnd } = useMaskField(props, modelValue);
|
|
2109
|
+
const { displayValue, placeholder, inputMode, autocapitalize, rules, onInput, onCompositionEnd } = useMaskField(props, modelValue);
|
|
2092
2110
|
function keepFieldControlled() {}
|
|
2093
2111
|
function clear() {
|
|
2094
2112
|
modelValue.value = "";
|
|
@@ -2109,7 +2127,8 @@ var mask_field_default = /* @__PURE__ */ defineComponent({
|
|
|
2109
2127
|
hint: props.hint,
|
|
2110
2128
|
clearable: props.clearable,
|
|
2111
2129
|
type: "text",
|
|
2112
|
-
inputmode:
|
|
2130
|
+
inputmode: unref(inputMode),
|
|
2131
|
+
autocapitalize: unref(autocapitalize),
|
|
2113
2132
|
"onUpdate:modelValue": keepFieldControlled,
|
|
2114
2133
|
onInput: unref(onInput),
|
|
2115
2134
|
onCompositionend: unref(onCompositionEnd),
|
|
@@ -2131,6 +2150,8 @@ var mask_field_default = /* @__PURE__ */ defineComponent({
|
|
|
2131
2150
|
"placeholder",
|
|
2132
2151
|
"hint",
|
|
2133
2152
|
"clearable",
|
|
2153
|
+
"inputmode",
|
|
2154
|
+
"autocapitalize",
|
|
2134
2155
|
"onInput",
|
|
2135
2156
|
"onCompositionend"
|
|
2136
2157
|
]);
|