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