@vuetify/nightly 3.8.9-dev.2025-06-11 → 3.8.9-dev.2025-06-12

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vuetify v3.8.9-dev.2025-06-11
2
+ * Vuetify v3.8.9-dev.2025-06-12
3
3
  * Forged by John Leider
4
4
  * Released under the MIT License.
5
5
  */
@@ -30490,6 +30490,251 @@ const VIconBtn = genericComponent()({
30490
30490
  }
30491
30491
  });
30492
30492
 
30493
+ // Utilities
30494
+
30495
+ // Types
30496
+
30497
+ const makeMaskProps = propsFactory({
30498
+ mask: [String, Object],
30499
+ returnMaskedValue: Boolean
30500
+ }, 'mask');
30501
+ const defaultDelimiters = /[-!$%^&*()_+|~=`{}[\]:";'<>?,./\\ ]/;
30502
+ const presets = {
30503
+ 'credit-card': '#### - #### - #### - ####',
30504
+ date: '##/##/####',
30505
+ 'date-time': '##/##/#### ##:##',
30506
+ 'iso-date': '####-##-##',
30507
+ 'iso-date-time': '####-##-## ##:##',
30508
+ phone: '(###) ### - ####',
30509
+ social: '###-##-####',
30510
+ time: '##:##',
30511
+ 'time-with-seconds': '##:##:##'
30512
+ };
30513
+ function isMaskDelimiter(char) {
30514
+ return char ? defaultDelimiters.test(char) : false;
30515
+ }
30516
+ const defaultTokens = {
30517
+ '#': {
30518
+ pattern: /[0-9]/
30519
+ },
30520
+ A: {
30521
+ pattern: /[A-Z]/i,
30522
+ convert: v => v.toUpperCase()
30523
+ },
30524
+ a: {
30525
+ pattern: /[a-z]/i,
30526
+ convert: v => v.toLowerCase()
30527
+ },
30528
+ N: {
30529
+ pattern: /[0-9A-Z]/i,
30530
+ convert: v => v.toUpperCase()
30531
+ },
30532
+ n: {
30533
+ pattern: /[0-9a-z]/i,
30534
+ convert: v => v.toLowerCase()
30535
+ },
30536
+ X: {
30537
+ pattern: defaultDelimiters
30538
+ }
30539
+ };
30540
+ function useMask(props, inputRef) {
30541
+ const mask = computed(() => {
30542
+ if (typeof props.mask === 'string') {
30543
+ if (props.mask in presets) return presets[props.mask];
30544
+ return props.mask;
30545
+ }
30546
+ return props.mask?.mask ?? '';
30547
+ });
30548
+ const tokens = computed(() => {
30549
+ return {
30550
+ ...defaultTokens,
30551
+ ...(isObject(props.mask) ? props.mask.tokens : null)
30552
+ };
30553
+ });
30554
+ const selection = shallowRef(0);
30555
+ const lazySelection = shallowRef(0);
30556
+ function isMask(char) {
30557
+ return char in tokens.value;
30558
+ }
30559
+ function maskValidates(mask, char) {
30560
+ if (char == null || !isMask(mask)) return false;
30561
+ const item = tokens.value[mask];
30562
+ if (item.pattern) return item.pattern.test(char);
30563
+ return item.test(char);
30564
+ }
30565
+ function convert(mask, char) {
30566
+ const item = tokens.value[mask];
30567
+ return item.convert ? item.convert(char) : char;
30568
+ }
30569
+ function maskText(text) {
30570
+ const trimmedText = text?.trim().replace(/\s+/g, ' ');
30571
+ if (trimmedText == null) return '';
30572
+ if (!mask.value.length || !trimmedText.length) return trimmedText;
30573
+ let textIndex = 0;
30574
+ let maskIndex = 0;
30575
+ let newText = '';
30576
+ while (maskIndex < mask.value.length) {
30577
+ const mchar = mask.value[maskIndex];
30578
+ const tchar = trimmedText[textIndex];
30579
+
30580
+ // Escaped character in mask, the next mask character is inserted
30581
+ if (mchar === '\\') {
30582
+ newText += mask.value[maskIndex + 1];
30583
+ maskIndex += 2;
30584
+ continue;
30585
+ }
30586
+ if (!isMask(mchar)) {
30587
+ newText += mchar;
30588
+ if (tchar === mchar) {
30589
+ textIndex++;
30590
+ }
30591
+ } else if (maskValidates(mchar, tchar)) {
30592
+ newText += convert(mchar, tchar);
30593
+ textIndex++;
30594
+ } else {
30595
+ break;
30596
+ }
30597
+ maskIndex++;
30598
+ }
30599
+ return newText;
30600
+ }
30601
+ function unmaskText(text) {
30602
+ if (text == null) return null;
30603
+ if (!mask.value.length || !text.length) return text;
30604
+ let textIndex = 0;
30605
+ let maskIndex = 0;
30606
+ let newText = '';
30607
+ while (true) {
30608
+ const mchar = mask.value[maskIndex];
30609
+ const tchar = text[textIndex];
30610
+ if (tchar == null) break;
30611
+ if (mchar == null) {
30612
+ newText += tchar;
30613
+ textIndex++;
30614
+ continue;
30615
+ }
30616
+
30617
+ // Escaped character in mask, skip the next input character
30618
+ if (mchar === '\\') {
30619
+ if (tchar === mask.value[maskIndex + 1]) {
30620
+ textIndex++;
30621
+ }
30622
+ maskIndex += 2;
30623
+ continue;
30624
+ }
30625
+ if (maskValidates(mchar, tchar)) {
30626
+ // masked char
30627
+ newText += tchar;
30628
+ textIndex++;
30629
+ maskIndex++;
30630
+ continue;
30631
+ } else if (mchar !== tchar) {
30632
+ // input doesn't match mask, skip forward until it does
30633
+ while (true) {
30634
+ const mchar = mask.value[maskIndex++];
30635
+ if (mchar == null || maskValidates(mchar, tchar)) break;
30636
+ }
30637
+ continue;
30638
+ }
30639
+ textIndex++;
30640
+ maskIndex++;
30641
+ }
30642
+ return newText;
30643
+ }
30644
+ function setCaretPosition(newSelection) {
30645
+ selection.value = newSelection;
30646
+ inputRef.value && inputRef.value.setSelectionRange(selection.value, selection.value);
30647
+ }
30648
+ function resetSelections() {
30649
+ if (!inputRef.value?.selectionEnd) return;
30650
+ selection.value = inputRef.value.selectionEnd;
30651
+ lazySelection.value = 0;
30652
+ for (let index = 0; index < selection.value; index++) {
30653
+ isMaskDelimiter(inputRef.value.value[index]) || lazySelection.value++;
30654
+ }
30655
+ }
30656
+ function updateRange() {
30657
+ if (!inputRef.value) return;
30658
+ resetSelections();
30659
+ let selection = 0;
30660
+ const newValue = inputRef.value.value;
30661
+ if (newValue) {
30662
+ for (let index = 0; index < newValue.length; index++) {
30663
+ if (lazySelection.value <= 0) break;
30664
+ isMaskDelimiter(newValue[index]) || lazySelection.value--;
30665
+ selection++;
30666
+ }
30667
+ }
30668
+ setCaretPosition(selection);
30669
+ }
30670
+ return {
30671
+ updateRange,
30672
+ maskText,
30673
+ unmaskText
30674
+ };
30675
+ }
30676
+
30677
+ // Types
30678
+
30679
+ const makeVMaskInputProps = propsFactory({
30680
+ ...makeVTextFieldProps(),
30681
+ ...makeMaskProps()
30682
+ }, 'VMaskInput');
30683
+ const VMaskInput = genericComponent()({
30684
+ name: 'VMaskInput',
30685
+ props: makeVMaskInputProps(),
30686
+ emits: {
30687
+ 'update:modelValue': val => true
30688
+ },
30689
+ setup(props, _ref) {
30690
+ let {
30691
+ slots,
30692
+ emit
30693
+ } = _ref;
30694
+ const vTextFieldRef = ref();
30695
+ const {
30696
+ maskText,
30697
+ updateRange,
30698
+ unmaskText
30699
+ } = useMask(props, vTextFieldRef);
30700
+ const returnMaskedValue = computed(() => props.mask && props.returnMaskedValue);
30701
+ const model = useProxiedModel(props, 'modelValue', undefined,
30702
+ // Always display masked value in input when mask is applied
30703
+ val => props.mask ? maskText(unmaskText(val)) : val, val => {
30704
+ if (props.mask) {
30705
+ const valueBeforeChange = unmaskText(model.value);
30706
+ // E.g. mask is #-# and the input value is '2-23'
30707
+ // model-value should be enforced to '2-2'
30708
+ const enforcedMaskedValue = maskText(unmaskText(val));
30709
+ const newUnmaskedValue = unmaskText(enforcedMaskedValue);
30710
+ if (newUnmaskedValue === valueBeforeChange) {
30711
+ vTextFieldRef.value.value = enforcedMaskedValue;
30712
+ }
30713
+ val = newUnmaskedValue;
30714
+ updateRange();
30715
+ return returnMaskedValue.value ? maskText(val) : val;
30716
+ }
30717
+ return val;
30718
+ });
30719
+ onBeforeMount(() => {
30720
+ if (props.returnMaskedValue) {
30721
+ emit('update:modelValue', model.value);
30722
+ }
30723
+ });
30724
+ useRender(() => {
30725
+ const textFieldProps = VTextField.filterProps(props);
30726
+ return createVNode(VTextField, mergeProps(textFieldProps, {
30727
+ "modelValue": model.value,
30728
+ "onUpdate:modelValue": $event => model.value = $event,
30729
+ "ref": vTextFieldRef
30730
+ }), {
30731
+ ...slots
30732
+ });
30733
+ });
30734
+ return forwardRefs({}, vTextFieldRef);
30735
+ }
30736
+ });
30737
+
30493
30738
  // Types
30494
30739
 
30495
30740
  const makeVStepperVerticalActionsProps = propsFactory({
@@ -31995,6 +32240,7 @@ var components = /*#__PURE__*/Object.freeze({
31995
32240
  VListSubheader: VListSubheader,
31996
32241
  VLocaleProvider: VLocaleProvider,
31997
32242
  VMain: VMain,
32243
+ VMaskInput: VMaskInput,
31998
32244
  VMenu: VMenu,
31999
32245
  VMessages: VMessages,
32000
32246
  VNavigationDrawer: VNavigationDrawer,
@@ -32392,7 +32638,7 @@ function createVuetify$1() {
32392
32638
  };
32393
32639
  });
32394
32640
  }
32395
- const version$1 = "3.8.9-dev.2025-06-11";
32641
+ const version$1 = "3.8.9-dev.2025-06-12";
32396
32642
  createVuetify$1.version = version$1;
32397
32643
 
32398
32644
  // Vue's inject() can only be used in setup
@@ -32690,7 +32936,7 @@ var index = /*#__PURE__*/Object.freeze({
32690
32936
 
32691
32937
  /* eslint-disable local-rules/sort-imports */
32692
32938
 
32693
- const version = "3.8.9-dev.2025-06-11";
32939
+ const version = "3.8.9-dev.2025-06-12";
32694
32940
 
32695
32941
  /* eslint-disable local-rules/sort-imports */
32696
32942