@dynect/base 0.10.4 → 0.12.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.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/src/module.ts +46 -58
  3. package/src/runtime/components/dynect/Accordion.vue +1 -1
  4. package/src/runtime/components/dynect/Alert.vue +1 -1
  5. package/src/runtime/components/dynect/Autocomplete.vue +3 -3
  6. package/src/runtime/components/dynect/Avatar.vue +2 -2
  7. package/src/runtime/components/dynect/AvatarGroup.vue +1 -1
  8. package/src/runtime/components/dynect/AvatarLabel.vue +1 -1
  9. package/src/runtime/components/dynect/Badge.vue +1 -1
  10. package/src/runtime/components/dynect/Button.vue +1 -1
  11. package/src/runtime/components/dynect/Checkbox.vue +1 -1
  12. package/src/runtime/components/dynect/DatePicker.vue +2 -2
  13. package/src/runtime/components/dynect/DateRange.vue +2 -2
  14. package/src/runtime/components/dynect/FormDescription.vue +1 -1
  15. package/src/runtime/components/dynect/FormError.vue +1 -1
  16. package/src/runtime/components/dynect/FormField.vue +1 -1
  17. package/src/runtime/components/dynect/FormLabel.vue +1 -1
  18. package/src/runtime/components/dynect/Gantt.vue +1 -1
  19. package/src/runtime/components/dynect/Input.vue +7 -7
  20. package/src/runtime/components/dynect/Kanban.vue +1 -1
  21. package/src/runtime/components/dynect/Modal.vue +1 -1
  22. package/src/runtime/components/dynect/OtpInput.vue +1 -1
  23. package/src/runtime/components/dynect/Progress.vue +1 -1
  24. package/src/runtime/components/dynect/Radio.vue +1 -1
  25. package/src/runtime/components/dynect/Select.vue +1 -1
  26. package/src/runtime/components/dynect/SelectMultiple.vue +1 -1
  27. package/src/runtime/components/dynect/Sheet.vue +1 -1
  28. package/src/runtime/components/dynect/SwitchLanguage.vue +1 -1
  29. package/src/runtime/components/dynect/Table.vue +7 -3
  30. package/src/runtime/components/dynect/TagsInput.vue +1 -1
  31. package/src/runtime/components/dynect/Telephone.vue +2 -2
  32. package/src/runtime/components/dynect/TextEditor.vue +1 -1
  33. package/src/runtime/components/dynect/Textarea.vue +2 -2
  34. package/src/runtime/components/dynect/TimePicker.vue +3 -3
  35. package/src/runtime/components/dynect/Timeline.vue +1 -1
  36. package/src/runtime/components/dynect/Toggle.vue +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynect/base",
3
- "version": "0.10.4",
3
+ "version": "0.12.0",
4
4
  "description": "Reusable Nuxt base module — components, composables, utils, plugins and i18n from the Dynect design system.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/module.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { addComponentsDir, addImports, addImportsDir, addPlugin, createResolver, defineNuxtModule, installModule } from '@nuxt/kit';
2
- import { defu } from 'defu';
3
2
  import { existsSync } from 'node:fs';
4
3
  import { join } from 'node:path';
5
4
 
@@ -46,7 +45,7 @@ export default defineNuxtModule<DynectBaseOptions>({
46
45
  veeValidate: {},
47
46
  colorMode: {},
48
47
  i18n: {},
49
- shadcn: { prefix: '' },
48
+ shadcn: {},
50
49
  icon: {},
51
50
  plugins: { toast: true, ssrWidth: true },
52
51
  },
@@ -97,78 +96,67 @@ export default defineNuxtModule<DynectBaseOptions>({
97
96
  }
98
97
 
99
98
  // ── Install required Nuxt modules ────────────────────────────────────────
100
- // installModule is marked @deprecated in @nuxt/kit but is the only practical
101
- // API for installing sub-modules with dynamic options during a module's setup.
102
99
  if (options.shadcn !== false) {
103
- // Extract componentDir separately keeping it out of defaults prevents
104
- // defu from always populating it, which would override the computed path.
105
- const { componentDir: userComponentDir, ...shadcnRest } = (options.shadcn ?? {}) as { prefix?: string; componentDir?: string };
106
- const shadcnComponentDir = userComponentDir ?? (isStandalone ? join(runtimeComponentsDir, 'ui') : '~/components/ui');
100
+ const shadcnComponentDir = isStandalone ? join(runtimeComponentsDir, 'ui') : '~/components/ui';
107
101
 
108
- await installModule('shadcn-nuxt', { prefix: '', ...shadcnRest, componentDir: shadcnComponentDir }); // NOSONAR
102
+ await installModule('shadcn-nuxt', {
103
+ prefix: '',
104
+ componentDir: shadcnComponentDir,
105
+ ...options.shadcn,
106
+ });
109
107
  }
110
108
 
111
109
  if (options.veeValidate !== false) {
112
- await installModule('@vee-validate/nuxt', options.veeValidate ?? {}); // NOSONAR
110
+ await installModule('@vee-validate/nuxt', options.veeValidate ?? {});
113
111
  }
114
112
 
115
113
  if (options.colorMode !== false) {
116
- // defu(user, defaults): user keys win; nested objects are deep-merged, not replaced
117
- await installModule(
118
- '@nuxtjs/color-mode',
119
- defu(options.colorMode ?? {}, {
120
- // NOSONAR
121
- preference: 'system',
122
- fallback: 'light',
123
- classPrefix: '',
124
- classSuffix: '',
125
- storage: 'cookie',
126
- storageKey: 'dynect_color_mode',
127
- })
128
- );
114
+ await installModule('@nuxtjs/color-mode', {
115
+ preference: 'system',
116
+ fallback: 'light',
117
+ classPrefix: '',
118
+ classSuffix: '',
119
+ storage: 'cookie',
120
+ storageKey: 'dynect_color_mode',
121
+ ...options.colorMode,
122
+ });
129
123
  }
130
124
 
131
125
  if (options.i18n !== false) {
132
126
  const langDir = isStandalone ? resolver.resolve('./runtime/assets/lang') : resolver.resolve('../../../app/assets/lang');
133
127
 
134
- await installModule(
135
- '@nuxtjs/i18n',
136
- defu(options.i18n ?? {}, {
137
- // NOSONAR
138
- locales: [
139
- { code: 'en', iso: 'en_US', file: 'en.json', name: 'English' },
140
- { code: 'ms', iso: 'ms_MY', file: 'ms.json', name: 'Bahasa' },
141
- ],
142
- langDir,
143
- defaultLocale: 'en',
144
- strategy: 'no_prefix',
145
- detectBrowserLanguage: {
146
- useCookie: true,
147
- cookieKey: 'dynect_language',
148
- cookieSecure: true,
149
- redirectOn: 'root',
150
- alwaysRedirect: true,
151
- },
152
- })
153
- );
128
+ await installModule('@nuxtjs/i18n', {
129
+ locales: [
130
+ { code: 'en', iso: 'en_US', file: 'en.json', name: 'English' },
131
+ { code: 'ms', iso: 'ms_MY', file: 'ms.json', name: 'Bahasa' },
132
+ ],
133
+ langDir,
134
+ defaultLocale: 'en',
135
+ strategy: 'no_prefix',
136
+ detectBrowserLanguage: {
137
+ useCookie: true,
138
+ cookieKey: 'dynect_language',
139
+ cookieSecure: true,
140
+ redirectOn: 'root',
141
+ alwaysRedirect: true,
142
+ },
143
+ ...options.i18n,
144
+ });
154
145
  }
155
146
 
156
147
  if (options.icon !== false) {
157
- await installModule(
158
- '@nuxt/icon',
159
- defu(options.icon ?? {}, {
160
- // NOSONAR
161
- provider: 'server',
162
- mode: 'svg',
163
- serverBundle: {
164
- collections: ['heroicons', 'lucide', 'mdi'],
165
- remote: false,
166
- },
167
- })
168
- );
148
+ await installModule('@nuxt/icon', {
149
+ provider: 'server',
150
+ mode: 'svg',
151
+ serverBundle: {
152
+ collections: ['heroicons', 'lucide', 'mdi'],
153
+ remote: false,
154
+ },
155
+ ...options.icon,
156
+ });
169
157
  }
170
158
 
171
- await installModule('@pinia/nuxt'); // NOSONAR
159
+ await installModule('@pinia/nuxt');
172
160
 
173
161
  // ── CSS ──────────────────────────────────────────────────────────────────
174
162
  const cssPath = isStandalone ? resolver.resolve('./runtime/assets/css/main.css') : resolver.resolve('../../../app/assets/css/main.css');
@@ -178,13 +166,13 @@ export default defineNuxtModule<DynectBaseOptions>({
178
166
  }
179
167
 
180
168
  // ── Components ───────────────────────────────────────────────────────────
181
- for (const dir of options.dirs) {
169
+ for (const dir of options.dirs!) {
182
170
  const dirPath = join(componentsBase, dir);
183
171
  if (!existsSync(dirPath)) continue;
184
172
 
185
173
  addComponentsDir({
186
174
  path: dirPath,
187
- prefix: DIR_CONFIGS[dir].prefix,
175
+ prefix: DIR_CONFIGS[dir]!.prefix,
188
176
  pathPrefix: false,
189
177
  global: options.global,
190
178
  });
@@ -2,7 +2,7 @@
2
2
  import { computed } from 'vue';
3
3
  import type { HTMLAttributes } from 'vue';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
- import { cn } from '@/lib/utils';
5
+ import { cn } from '../../lib/utils';
6
6
 
7
7
  // ── Types ────────────────────────────────────────────────────────────────────
8
8
  export interface AccordionItemData {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed, ref } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  type AlertVariant = 'success' | 'danger' | 'warning' | 'info' | 'default';
6
6
  type AlertType = 'default' | 'complex' | 'border-top' | 'small';
@@ -5,7 +5,7 @@ import { computed, ref } from 'vue';
5
5
  import { useId } from 'nuxt/app';
6
6
  import type { HTMLAttributes } from 'vue';
7
7
  import { cva } from 'class-variance-authority';
8
- import { cn } from '@/lib/utils';
8
+ import { cn } from '../../lib/utils';
9
9
 
10
10
  export interface AutocompleteOption {
11
11
  label: string;
@@ -281,7 +281,7 @@ function clearValue() {
281
281
  <!-- Avatar slot -->
282
282
  <template v-if="option.avatar || $slots.optionAvatar">
283
283
  <slot name="optionAvatar" :option="option">
284
- <img :src="option.avatar" :alt="option.label" class="size-4.5 shrink-0 rounded-full object-cover" >
284
+ <img :src="option.avatar" :alt="option.label" class="size-4.5 shrink-0 rounded-full object-cover" />
285
285
  </slot>
286
286
  </template>
287
287
 
@@ -342,7 +342,7 @@ function clearValue() {
342
342
  <!-- Avatar slot -->
343
343
  <template v-if="option.avatar || $slots.optionAvatar">
344
344
  <slot name="optionAvatar" :option="option">
345
- <img :src="option.avatar" :alt="option.label" class="size-4.5 shrink-0 rounded-full object-cover" >
345
+ <img :src="option.avatar" :alt="option.label" class="size-4.5 shrink-0 rounded-full object-cover" />
346
346
  </slot>
347
347
  </template>
348
348
 
@@ -2,8 +2,8 @@
2
2
  import type { HTMLAttributes } from 'vue';
3
3
  import { AvatarRoot, AvatarImage, AvatarFallback } from 'reka-ui';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
- import { cn } from '@/lib/utils';
6
- import { getAvatarText } from '@/utils/function';
5
+ import { cn } from '../../lib/utils';
6
+ import { getAvatarText } from '../../utils/function';
7
7
 
8
8
  // ── Variants ────────────────────────────────────────────────────────────────
9
9
  const avatarVariants = cva('relative flex shrink-0 rounded-full ring-1 ring-border-base dark:ring-border-base', {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
3
  import { cva, type VariantProps } from 'class-variance-authority';
4
- import { cn } from '@/lib/utils';
4
+ import { cn } from '../../lib/utils';
5
5
 
6
6
  // ── Variants ────────────────────────────────────────────────────────────────
7
7
  const groupVariants = cva('flex items-center overflow-hidden', {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
3
  import { cva, type VariantProps } from 'class-variance-authority';
4
- import { cn } from '@/lib/utils';
4
+ import { cn } from '../../lib/utils';
5
5
 
6
6
  // ── Variants ────────────────────────────────────────────────────────────────
7
7
  const wrapperVariants = cva('flex items-center', {
@@ -2,7 +2,7 @@
2
2
  import { computed } from 'vue';
3
3
  import type { HTMLAttributes } from 'vue';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
- import { cn } from '@/lib/utils';
5
+ import { cn } from '../../lib/utils';
6
6
 
7
7
  // ── Variants ────────────────────────────────────────────────────────────────
8
8
  const badgeVariants = cva('inline-flex max-w-fit items-center justify-center gap-1 font-medium whitespace-nowrap border', {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
3
  import { Primitive, type PrimitiveProps } from 'reka-ui';
4
- import { cn } from '@/lib/utils';
4
+ import { cn } from '../../lib/utils';
5
5
  import { buttonVariants, type ButtonVariants } from '@/components/ui/button';
6
6
 
7
7
  // ── Props ─────────────────────────────────────────────────────────────────────
@@ -44,7 +44,7 @@
44
44
  import { useField } from 'vee-validate';
45
45
  import { computed } from 'vue';
46
46
  import { useId } from 'nuxt/app';
47
- import { cn } from '@/lib/utils';
47
+ import { cn } from '../../lib/utils';
48
48
 
49
49
  export interface AppCheckboxProps {
50
50
  // Core Props
@@ -24,7 +24,7 @@
24
24
  <Icon name="lucide:calendar-days" />
25
25
  </template>
26
26
  </DynectInput>
27
- <input :id="`${resolvedId}`" v-model="modelValue" type="hidden" >
27
+ <input :id="`${resolvedId}`" v-model="modelValue" type="hidden" />
28
28
  </PopoverTrigger>
29
29
 
30
30
  <PopoverContent class="w-auto rounded-xl bg-white p-0 dark:bg-gray-900" :align="align">
@@ -55,7 +55,7 @@ import { computed, readonly, ref, watch } from 'vue';
55
55
  import { useId } from 'nuxt/app';
56
56
  import type { DateValue } from '@internationalized/date';
57
57
  import { DateFormatter, getLocalTimeZone, parseDate, today } from '@internationalized/date';
58
- import { cn } from '@/lib/utils';
58
+ import { cn } from '../../lib/utils';
59
59
  import type { LayoutTypes } from '../ui/calendar';
60
60
 
61
61
  export interface DatePickerProps {
@@ -14,7 +14,7 @@
14
14
  :state="errorMessage ? 'danger' : 'default'"
15
15
  :aria-invalid="!!errorMessage"
16
16
  :aria-describedby="errorMessage ? `${resolvedId}-error` : description ? `${resolvedId}-description` : undefined"
17
- :readonly="readonly"
17
+ :readonly="props.readonly"
18
18
  :class="cn('cursor-pointer ring-inset', buttonClass)"
19
19
  >
20
20
  <template #leading>
@@ -58,7 +58,7 @@ import { computed, readonly, ref, watch } from 'vue';
58
58
  import { useId } from 'nuxt/app';
59
59
  import type { DateValue } from '@internationalized/date';
60
60
  import { DateFormatter, getLocalTimeZone, today, parseDate } from '@internationalized/date';
61
- import { cn } from '@/lib/utils';
61
+ import { cn } from '../../lib/utils';
62
62
 
63
63
  export interface DateRangeValue {
64
64
  start: Date | string | undefined | any;
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  interface Props {
6
6
  /** Description text to display */
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  interface Props {
6
6
  /** Error message to display */
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { Form } from 'vee-validate';
3
3
  import type { HTMLAttributes } from 'vue';
4
- import { cn } from '@/lib/utils';
4
+ import { cn } from '../../lib/utils';
5
5
 
6
6
  interface Props {
7
7
  /** Label text */
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  interface Props {
6
6
  /** The label text to display */
@@ -90,7 +90,7 @@
90
90
 
91
91
  <script setup lang="ts" generic="T extends DynectGanttFeature">
92
92
  import { computed } from 'vue';
93
- import { cn } from '@/lib/utils';
93
+ import { cn } from '../../lib/utils';
94
94
  import type { GanttFeature, GanttRange } from '../../composables/useGantt';
95
95
 
96
96
  export interface DynectGanttFeature extends GanttFeature {
@@ -4,7 +4,7 @@ import { computed, readonly } from 'vue';
4
4
  import { useId } from 'nuxt/app';
5
5
  import type { HTMLAttributes } from 'vue';
6
6
  import { cva } from 'class-variance-authority';
7
- import { cn, inputSizeClasses } from '@/lib/utils';
7
+ import { cn, inputSizeClasses } from '../../lib/utils';
8
8
 
9
9
  type InputSize = 'sm' | 'base' | 'lg' | 'xl';
10
10
  type InputState = 'default' | 'success' | 'danger';
@@ -128,7 +128,7 @@ const iconSize = computed(() => (sz.value === 'lg' || sz.value === 'xl' ? 'w-5 h
128
128
  <span>{{ addonText }}</span>
129
129
  </slot>
130
130
  </div>
131
- <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="readonly" :class="textCls" @blur="handleBlur" >
131
+ <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="props.readonly" :class="textCls" @blur="handleBlur" />
132
132
  <div v-if="!disabled && !readonly" :class="cn(iconCls, 'flex shrink-0 items-center pr-2.5', props.iconClass)">
133
133
  <slot name="trailing">
134
134
  <DynectButton v-if="modelValue" tabindex="-1" type="button" color="ghost" size="xs" icon-only :disabled="disabled || readonly" @click="modelValue = ''">
@@ -145,7 +145,7 @@ const iconSize = computed(() => (sz.value === 'lg' || sz.value === 'xl' ? 'w-5 h
145
145
  <div :class="cn('border-border-base-medium flex shrink-0 items-center justify-center self-stretch rounded-l-xl border-r', addonSzCls, iconCls)">
146
146
  <slot name="addon-icon"><Icon name="lucide:user" :class="iconSize" /></slot>
147
147
  </div>
148
- <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="readonly" :class="textCls" @blur="handleBlur" >
148
+ <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="props.readonly" :class="textCls" @blur="handleBlur" />
149
149
  <div v-if="!disabled && !readonly" :class="cn(iconCls, 'flex shrink-0 items-center pr-2.5', props.iconClass)">
150
150
  <slot name="trailing">
151
151
  <DynectButton v-if="modelValue" tabindex="-1" type="button" color="ghost" size="xs" icon-only :disabled="disabled || readonly" @click="modelValue = ''">
@@ -162,7 +162,7 @@ const iconSize = computed(() => (sz.value === 'lg' || sz.value === 'xl' ? 'w-5 h
162
162
  <div :class="cn(iconCls, 'flex shrink-0 items-center pl-3')">
163
163
  <slot name="leading"><Icon name="lucide:user" :class="iconSize" /></slot>
164
164
  </div>
165
- <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="readonly" :class="textCls" @blur="handleBlur" >
165
+ <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="props.readonly" :class="textCls" @blur="handleBlur" />
166
166
  <div class="shrink-0 pr-2">
167
167
  <DynectButton type="button" color="secondary" size="xs" :disabled="disabled" @click="emits('button-click')">
168
168
  <template #leftIcon>
@@ -189,10 +189,10 @@ const iconSize = computed(() => (sz.value === 'lg' || sz.value === 'xl' ? 'w-5 h
189
189
  :type="($attrs.type as any) ?? 'text'"
190
190
  :placeholder="placeholder ?? '—'"
191
191
  :disabled="disabled"
192
- :readonly="readonly"
192
+ :readonly="props.readonly"
193
193
  :class="cn(textColorCls, 'text-center text-sm font-normal')"
194
194
  @blur="handleBlur"
195
- >
195
+ />
196
196
  <div :class="cn(iconCls, 'absolute top-1/2 right-2.5 flex shrink-0 -translate-y-1/2 items-center')">
197
197
  <DynectButton v-if="modelValue" tabindex="-1" type="button" color="ghost" size="xs" icon-only :disabled="disabled || readonly" @click="modelValue = ''">
198
198
  <Icon name="lucide:x" class="size-4" />
@@ -213,7 +213,7 @@ const iconSize = computed(() => (sz.value === 'lg' || sz.value === 'xl' ? 'w-5 h
213
213
  <div v-if="$slots.leading" :class="cn(iconCls, 'flex shrink-0 items-center pl-2.5', props.iconClass)">
214
214
  <slot name="leading" />
215
215
  </div>
216
- <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="readonly" :class="textCls" @blur="handleBlur" >
216
+ <input :id="resolvedId" v-model="modelValue" :value="value" autocomplete="off" :name="resolvedId" :type="($attrs.type as any) ?? 'text'" :placeholder="placeholder ?? 'Placeholder text'" :disabled="disabled" :readonly="props.readonly" :class="textCls" @blur="handleBlur" />
217
217
  <div v-if="!disabled && !readonly" :class="cn(iconCls, 'flex shrink-0 items-center pr-2.5', props.iconClass)">
218
218
  <slot name="trailing">
219
219
  <DynectButton v-if="modelValue" tabindex="-1" type="button" color="ghost" size="xs" icon-only :disabled="disabled || readonly" @click="modelValue = ''">
@@ -51,7 +51,7 @@
51
51
  </template>
52
52
 
53
53
  <script setup lang="ts" generic="T extends KanbanItemProps, C extends KanbanColumnProps">
54
- import { cn } from '@/lib/utils';
54
+ import { cn } from '../../lib/utils';
55
55
  import type { KanbanItemProps, KanbanColumnProps } from '../../composables/useKanban';
56
56
 
57
57
  export interface DynectKanbanColumn extends KanbanColumnProps {
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  interface DialogProps {
6
6
  open?: boolean;
@@ -6,7 +6,7 @@ import type { HTMLAttributes } from 'vue';
6
6
  import type { OTPInputEmits, OTPInputProps } from 'vue-input-otp';
7
7
  import { useForwardPropsEmits } from 'reka-ui';
8
8
  import { reactiveOmit } from '@vueuse/core';
9
- import { cn } from '@/lib/utils';
9
+ import { cn } from '../../lib/utils';
10
10
 
11
11
  /**
12
12
  * OTP Input variant types (matching the Dynect design)
@@ -2,7 +2,7 @@
2
2
  import { computed } from 'vue';
3
3
  import type { HTMLAttributes } from 'vue';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
- import { cn } from '@/lib/utils';
5
+ import { cn } from '../../lib/utils';
6
6
 
7
7
  // ── Variants ────────────────────────────────────────────────────────────────
8
8
  const trackVariants = cva('w-full overflow-hidden rounded-full bg-bg-quaternary', {
@@ -40,7 +40,7 @@
40
40
  import { useField } from 'vee-validate';
41
41
  import { computed } from 'vue';
42
42
  import { useId } from 'nuxt/app';
43
- import { cn } from '@/lib/utils';
43
+ import { cn } from '../../lib/utils';
44
44
 
45
45
  defineOptions({
46
46
  inheritAttrs: false,
@@ -5,7 +5,7 @@ import { computed, ref } from 'vue';
5
5
  import { useId } from 'nuxt/app';
6
6
  import type { HTMLAttributes } from 'vue';
7
7
  import { cva } from 'class-variance-authority';
8
- import { cn, inputSizeClasses } from '@/lib/utils';
8
+ import { cn, inputSizeClasses } from '../../lib/utils';
9
9
 
10
10
  export interface SelectOption {
11
11
  label: string;
@@ -5,7 +5,7 @@ import { computed, ref } from 'vue';
5
5
  import { useId } from 'nuxt/app';
6
6
  import type { HTMLAttributes } from 'vue';
7
7
  import { cva } from 'class-variance-authority';
8
- import { cn, inputSizeClasses } from '@/lib/utils';
8
+ import { cn, inputSizeClasses } from '../../lib/utils';
9
9
  import type { SelectOption } from './Select.vue';
10
10
 
11
11
  type SelectSize = 'sm' | 'base' | 'lg' | 'xl';
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue';
3
- import { cn } from '@/lib/utils';
3
+ import { cn } from '../../lib/utils';
4
4
 
5
5
  interface SheetProps {
6
6
  open?: boolean;
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { toUpperCase } from '../../utils/function';
3
3
  import { useI18n } from 'vue-i18n';
4
- import { cn } from '@/lib/utils';
4
+ import { cn } from '../../lib/utils';
5
5
  const { locale, setLocale } = useI18n();
6
6
  const props = withDefaults(
7
7
  defineProps<{
@@ -1,6 +1,10 @@
1
- <script setup lang="ts" generic="TData extends Record<string, any>
2
- import { computed, onMounted, ref, watch } from 'vue';">
3
- import { cn } from '@/lib/utils';
1
+ <script
2
+ setup
3
+ lang="ts"
4
+ generic="TData extends Record<string, any>
5
+ import { computed, onMounted, ref, watch } from 'vue';"
6
+ >
7
+ import { cn } from '../../lib/utils';
4
8
 
5
9
  // Column definition
6
10
  export interface TableColumn<T = any> {
@@ -107,7 +107,7 @@ import { computed, readonly, ref, watch } from 'vue';
107
107
  import { useId } from 'nuxt/app';
108
108
  import { onClickOutside } from '@vueuse/core';
109
109
  import { cva } from 'class-variance-authority';
110
- import { cn, inputSizeClasses } from '@/lib/utils';
110
+ import { cn, inputSizeClasses } from '../../lib/utils';
111
111
 
112
112
  export interface TagsInputOption {
113
113
  label: string;
@@ -92,7 +92,7 @@
92
92
  @input="onInput"
93
93
  @keyup.enter="onEnter"
94
94
  @keyup.space="onSpace"
95
- >
95
+ />
96
96
 
97
97
  <div v-if="!disabled && !inputOptions.readonly" :class="cn(iconCls, 'flex shrink-0 items-center', variant === 'spaced' ? inputSizeClasses[sz] : 'pr-3')">
98
98
  <DynectButton v-if="data.phone" type="button" color="ghost" size="xs" icon-only left-icon="lucide:x" :disabled="disabled || inputOptions.readonly" aria-label="Clear phone number" @click="clearPhone" />
@@ -113,7 +113,7 @@ import { computed, nextTick, onMounted, reactive, readonly, ref, useTemplateRef,
113
113
  import { parsePhoneNumberFromString, type CountryCode, type NumberFormat } from 'libphonenumber-js/max';
114
114
  import { cva } from 'class-variance-authority';
115
115
  import { useState, useId } from 'nuxt/app';
116
- import { cn, inputSizeClasses } from '@/lib/utils';
116
+ import { cn, inputSizeClasses } from '../../lib/utils';
117
117
 
118
118
  type InputSize = 'sm' | 'base' | 'lg' | 'xl';
119
119
  type VariantState = 'default' | 'success' | 'danger' | 'disabled' | 'readonly';
@@ -2,7 +2,7 @@
2
2
  import { watch } from 'vue';
3
3
  import type { Content, Extensions } from '@tiptap/vue-3';
4
4
  import type { HTMLAttributes } from 'vue';
5
- import { cn } from '@/lib/utils';
5
+ import { cn } from '../../lib/utils';
6
6
  import Blockquote from '@tiptap/extension-blockquote';
7
7
  import Bold from '@tiptap/extension-bold';
8
8
  import BulletList from '@tiptap/extension-bullet-list';
@@ -4,7 +4,7 @@ import { computed, readonly } from 'vue';
4
4
  import { useId } from 'nuxt/app';
5
5
  import type { HTMLAttributes } from 'vue';
6
6
  import { cva } from 'class-variance-authority';
7
- import { cn, inputSizeClasses } from '@/lib/utils';
7
+ import { cn, inputSizeClasses } from '../../lib/utils';
8
8
 
9
9
  type TextareaSize = 'sm' | 'base' | 'lg' | 'xl';
10
10
  type TextareaState = 'default' | 'success' | 'danger';
@@ -99,7 +99,7 @@ const textCls = computed(() => cn(textColorCls.value, inputSizeClasses[sz.value]
99
99
 
100
100
  <!-- Textarea Wrapper -->
101
101
  <div :class="cn(wrapperCls, props.class)">
102
- <textarea :id="resolvedId" v-model="modelValue" autocomplete="off" :name="resolvedId" :placeholder="placeholder ?? 'Enter text...'" :disabled="disabled" :readonly="readonly" :rows="rows" :maxlength="maxlength" :minlength="minlength" :class="textCls" @blur="handleBlur" />
102
+ <textarea :id="resolvedId" v-model="modelValue" autocomplete="off" :name="resolvedId" :placeholder="placeholder ?? 'Enter text...'" :disabled="disabled" :readonly="props.readonly" :rows="rows" :maxlength="maxlength" :minlength="minlength" :class="textCls" @blur="handleBlur" />
103
103
  </div>
104
104
 
105
105
  <!-- Description -->
@@ -38,7 +38,7 @@
38
38
  :disabled="disabled"
39
39
  class="border-border-base focus:border-dynect-600 focus:ring-dynect-600/20 dark:focus:border-dynect-400 w-16 rounded-lg border bg-white py-2 text-center text-lg font-semibold text-gray-900 focus:ring-2 focus:outline-none disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
40
40
  @blur="handleHoursBlur"
41
- >
41
+ />
42
42
  <DynectButton type="button" :disabled="disabled" color="secondary" size="xs" icon-only left-icon="lucide:chevron-down" class="h-8 w-8" @click="decrementHours" />
43
43
  <span class="text-text-body-subtle text-xs">Hours</span>
44
44
  </div>
@@ -57,7 +57,7 @@
57
57
  :disabled="disabled"
58
58
  class="border-border-base focus:border-dynect-600 focus:ring-dynect-600/20 dark:focus:border-dynect-400 w-16 rounded-lg border bg-white py-2 text-center text-lg font-semibold text-gray-900 focus:ring-2 focus:outline-none disabled:opacity-50 dark:border-gray-700 dark:bg-gray-800 dark:text-white"
59
59
  @blur="handleMinutesBlur"
60
- >
60
+ />
61
61
  <DynectButton type="button" :disabled="disabled" color="secondary" size="xs" icon-only left-icon="lucide:chevron-down" class="h-8 w-8" @click="decrementMinutes" />
62
62
  <span class="text-text-body-subtle text-xs">Minutes</span>
63
63
  </div>
@@ -90,7 +90,7 @@
90
90
  import { useField } from 'vee-validate';
91
91
  import { computed, readonly, ref, watch } from 'vue';
92
92
  import { useId } from 'nuxt/app';
93
- import { cn } from '@/lib/utils';
93
+ import { cn } from '../../lib/utils';
94
94
 
95
95
  defineOptions({
96
96
  inheritAttrs: false,
@@ -2,7 +2,7 @@
2
2
  import { computed } from 'vue';
3
3
  import type { HTMLAttributes } from 'vue';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
- import { cn } from '@/lib/utils';
5
+ import { cn } from '../../lib/utils';
6
6
 
7
7
  // ── Types ───────────────────────────────────────────────────────────────────
8
8
  export interface TimelineButton {
@@ -63,7 +63,7 @@
63
63
  import { useField } from 'vee-validate';
64
64
  import { computed } from 'vue';
65
65
  import { useId } from 'nuxt/app';
66
- import { cn } from '@/lib/utils';
66
+ import { cn } from '../../lib/utils';
67
67
 
68
68
  export interface ToggleProps {
69
69
  label?: string;