Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class constructor cannot be invoked without "new" #1064

Open
DenisLantero opened this issue Aug 5, 2024 · 0 comments
Open

Class constructor cannot be invoked without "new" #1064

DenisLantero opened this issue Aug 5, 2024 · 0 comments

Comments

@DenisLantero
Copy link

I have an issue with vue-imask in Vue 3 using the setup script, I tried resetting both my npm and pnpm caches (I am using pnpm in my project), but neither seemed to fix the issue.

The problem arises as soon as I try to redefine the default blocks for the date mask, d, m and Y.

This is a simplified version of my code:

<template>
  <BsdkInputText
    v-bind="$props.inputProps"
    v-model="value"
    :mask="$props.inputProps?.mask || mask"
    @click="togglePopover"
  />
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { IMask } from 'vue-imask'
import type { FactoryArg } from 'imask'

const value = defineModel<string | null>()

const pattern = computed(() => {
  // Get the user's locale
  const userLocale = navigator.language

  // Create a date format using the user's locale
  const dateFormat = new Intl.DateTimeFormat(userLocale)

  // Get the format parts (e.g., day, month, year)
  const formatParts = dateFormat.formatToParts(new Date())

  // Create a mask pattern based on the format parts
  const maskPattern = formatParts.map((part) => {
    switch (part.type) {
      case 'day': return 'd'
      case 'month': return 'm'
      case 'year': return 'Y'
      case 'literal': return '/'
      default: return part.value
    }
  }).join('')

  return maskPattern
})

const mask = {
  mask: Date,
  lazy: false,
  pattern: pattern.value,
  blocks: {
    d: {
      mask: IMask.MaskedRange,
      from: 1,
      to: 31,
      maxLength: 2,
    },
    m: {
      mask: IMask.MaskedRange,
      from: 1,
      to: 12,
      maxLength: 2,
    },
    Y: {
      mask: IMask.MaskedRange,
      from: 1900,
      to: 9999,
    },
  },
  format: (date: Date) => {
    let day: string | number = date.getDate()
    let month: string | number = date.getMonth() + 1
    const year: string | number = date.getFullYear()

    if (day < 10) {
      day = `0${day}`
    }

    if (month < 10) {
      month = `0${month}`
    }

    return `${day}/${month}/${year}`
  },
  parse: (str: string) => {
    const [day, month, year] = str.split('/')

    return new Date(+year, +month - 1, +day)
  },

  min: props.minDate,
  max: props.maxDate,

  autofix: true,
} as FactoryArg
</script>

And this is my BsdkInputText component:

<template>
  <input
    :id
    v-imask="mask"
    :value="modelValue"
    :type
    :class="mergedInputClasses"
    :placeholder
    :required="field.required"
    :disabled="field.disabled"
    @accept="onAccept"
    @complete="onComplete"
    @input="onUpdateModelValue"
  >
</template>

<script setup lang="ts">
import { type Ref, computed, inject, ref } from 'vue'
import type { ClassEntries } from '@binarysystem/bsdk-ui-tailwind-merge'
import { useTailwindMerge } from '@binarysystem/bsdk-ui-tailwind-merge'
import { IMaskDirective as vImask } from 'vue-imask'

import type { Field } from '@binarysystem/bsdk-ui-form-field'

import type { FactoryArg } from 'imask'

export interface Props {
  id: string
  modelValue?: string | null
  type?: string
  placeholder?: string
  required?: boolean
  disabled?: boolean
  invalid?: boolean
  inputClasses?: ClassEntries
  mask?: FactoryArg
}
const props = withDefaults(defineProps<Props>(), {
  type: 'text',
  required: false,
  disabled: false,
  invalid: false,
})

const emit = defineEmits(['update:modelValue'])

const field = inject<Ref<Field>>('field', ref(props))
const { mergeClasses } = useTailwindMerge()

const mergedInputClasses = computed(() => {
// Tailwind classes logic
})

function onAccept (e: any) {
  const maskRef = e.detail

  emit('update:modelValue', maskRef.value)
}

function onComplete (e: any) {
  const maskRef = e.detail

  emit('update:modelValue', maskRef.value)
}

function onUpdateModelValue (e: any) {
  if (props.mask) {
    return
  }

  emit('update:modelValue', e.target.value)
}
</script>

First, I had to use a hack to make the v-imask directive work in Vue 3 while using the setup script, since I tried adding it to the app instance using the following, but there was a problem with types:

import type { App } from 'vue'
import '@assets/stylesheets/main.css'
import { IMaskDirective } from 'vue-imask'
import BsdkDatePicker from '@/components/BsdkDatePicker.vue'
import 'v-calendar/style.css'

export { BsdkDatePicker }

export default {
  install: (app: App) => {
    app.component('BsdkDatePicker', BsdkDatePicker)
    app.directive('imask', IMaskDirective)
  },
}

And this was the TypeScript error:

Argument of type '{ [x: string]: string | (<Opts extends FactoryArg>(el: DirectiveMaskElement<Opts>, { value: options }: { value: Opts; }) => void); name: string; }' is not assignable to parameter of type 'Directive<any, any>'.
  Type '{ [x: string]: string | (<Opts extends FactoryArg>(el: DirectiveMaskElement<Opts>, { value: options }: { value: Opts; }) => void); name: string; }' has no properties in common with type 'ObjectDirective<any, any>'.ts(2345

Anyway, the real problem is that I get the Class constructor x cannot be invoked without "new" error as soon as I try to redefine the default date blocks.
Is this caused by the way I am using the vue-imask plugin, a misuse of the blocks in the mask, or anything else?

Note that if I try to remove the definition of the blocks and use the default ones, everything works correctly, but I wanted to define the blocks to have a placeholder like this DD/MM/YYYY instead of the default one __/__/____.

Please let me know, and thanks in advance.

Versions:

  • vue-imaks: 7.6.1
  • vue: 3.4.27
  • @storybook/vue3: 8.1.5 (I am using Storybook to test the component)

Originally posted by @DenisLantero in #1012 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant