@imaginario27/air-ui-ds 1.9.3 → 1.10.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to this package are documented in this file.
5
5
  Historical releases were reconstructed from git history (GitHub repository) and npm publish dates.
6
6
  Future releases will include detailed entries generated with Changesets.
7
7
 
8
+ ## 1.9.4 - 2026-04-06
9
+
10
+ Release type: patch.
11
+ Commits found in range: 1.
12
+
13
+ ### Fixed
14
+
15
+ 1. fix CardTitle text color ([6a8807b](https://github.com/imaginario27/air-ui/commit/6a8807b9c4a3b22aa3f2b78eada1d8421ae9ed85))
16
+
17
+ - Package: @imaginario27/air-ui-ds.
18
+
19
+ ## 1.9.3 - 2026-04-06
20
+
21
+ Release type: patch.
22
+ Commits found in range: 1.
23
+
24
+ ### Fixed
25
+
26
+ 1. fix SelectField empty div with multiple option and badge stack ([041fd2d](https://github.com/imaginario27/air-ui/commit/041fd2df2eab1a17c83b51cc736d0d7ce591faf6))
27
+
28
+ - Package: @imaginario27/air-ui-ds.
29
+
30
+ ## 1.9.2 - 2026-03-31
31
+
32
+ Release type: patch.
33
+ Commits found in range: 1.
34
+
35
+ ### Fixed
36
+
37
+ 1. fix typecheck issues ([763c932](https://github.com/imaginario27/air-ui/commit/763c932692a380b5b172d1258dcbb38083a27fde))
38
+
39
+ - Package: @imaginario27/air-ui-ds.
40
+
8
41
  ## 1.9.1 - 2026-03-31
9
42
 
10
43
  Release type: patch.
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <h3 class="font-semibold w-full">
2
+ <h3 class="font-semibold w-full text-text-default">
3
3
  {{ title }}
4
4
  </h3>
5
5
  </template>
@@ -71,6 +71,8 @@
71
71
  :to="item.to"
72
72
  :isExternal="item.isExternal"
73
73
  :hasSeparator="item.hasSeparator"
74
+ :disabled="disabled || item.disabled"
75
+ :prefetchOn
74
76
  @click="handleClick(item.callback)"
75
77
  />
76
78
  </template>
@@ -129,6 +131,8 @@
129
131
  :to="item.to"
130
132
  :isExternal="item.isExternal"
131
133
  :hasSeparator="item.hasSeparator"
134
+ :disabled="disabled || item.disabled"
135
+ :prefetchOn
132
136
  @click="handleClick(item.callback)"
133
137
  />
134
138
  </template>
@@ -193,6 +197,14 @@ const props = defineProps({
193
197
  default: Trigger.CLICK,
194
198
  validator: (value: Trigger) => Object.values(Trigger).includes(value),
195
199
  },
200
+ disabled: {
201
+ type: Boolean as PropType<boolean>,
202
+ default: false,
203
+ },
204
+ prefetchOn: {
205
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
206
+ default: PrefetchOn.VISIBILITY,
207
+ },
196
208
  })
197
209
 
198
210
  // Refs
@@ -251,6 +263,8 @@ const getActivatorElement = () => {
251
263
  }
252
264
 
253
265
  const onActivatorClick = (event: MouseEvent) => {
266
+ if(props.disabled) return
267
+
254
268
  if (props.trigger !== Trigger.CLICK) return
255
269
  if (!activatorWrapper.value) return
256
270
 
@@ -260,6 +274,8 @@ const onActivatorClick = (event: MouseEvent) => {
260
274
  }
261
275
 
262
276
  const onActivatorMouseEnter = () => {
277
+ if(props.disabled) return
278
+
263
279
  if (props.trigger !== Trigger.HOVER) return
264
280
 
265
281
  clearCloseTimer()
@@ -267,6 +283,8 @@ const onActivatorMouseEnter = () => {
267
283
  }
268
284
 
269
285
  const onActivatorMouseLeave = () => {
286
+ if(props.disabled) return
287
+
270
288
  if (props.trigger !== Trigger.HOVER) return
271
289
 
272
290
  scheduleClose()
@@ -16,6 +16,7 @@
16
16
  typeClass,
17
17
  hasSeparator ? 'border-b border-border-default' : undefined,
18
18
  helpText ? 'py-2' : undefined,
19
+ disabled && 'opacity-disabled cursor-not-allowed pointer-events-none',
19
20
  ]"
20
21
  >
21
22
  <div class="flex items-center gap-3 w-full">
@@ -120,6 +121,14 @@ const props = defineProps({
120
121
  type: Boolean as PropType<boolean>,
121
122
  default: false,
122
123
  },
124
+ disabled: {
125
+ type: Boolean as PropType<boolean>,
126
+ default: false,
127
+ },
128
+ prefetchOn: {
129
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
130
+ default: PrefetchOn.VISIBILITY,
131
+ },
123
132
  })
124
133
 
125
134
  // States
@@ -128,6 +137,8 @@ const isImageLoaded = ref(true)
128
137
  // Emits
129
138
  const emit = defineEmits(["click", "close"])
130
139
  const emitClick = () => {
140
+ if (props.disabled) return
141
+
131
142
  if (props.actionType === DropdownActionType.ACTION) {
132
143
  emit("click")
133
144
  emit("close")
@@ -196,6 +207,7 @@ const componentProps = computed(() => {
196
207
  target: props.isExternal ? '_blank' : '_self',
197
208
  rel: props.isExternal ? 'noopener noreferrer' : undefined,
198
209
  external: props.isExternal,
210
+ prefetchOn: props.prefetchOn,
199
211
  }
200
212
  } else {
201
213
  return {}
@@ -6,7 +6,7 @@
6
6
  :shouldTeleport="false"
7
7
  :positionClass="`absolute ${dropdownPositionClass}`"
8
8
  zIndex="10"
9
- dropdownClass="max-w-full"
9
+ :dropdownClass
10
10
  :class="[
11
11
  'max-h-[200px]',
12
12
  'overflow-y-auto',
@@ -128,7 +128,7 @@
128
128
  'p-2',
129
129
  'sticky',
130
130
  'top-0',
131
- 'bg-white',
131
+ 'bg-background-container-surface',
132
132
  'z-10'
133
133
  ]"
134
134
  >
@@ -300,6 +300,12 @@ const dropdownPositionClass = computed(() => {
300
300
  return positionVariant[props.dropdownPosition as Position] || 'top-full mt-1'
301
301
  })
302
302
 
303
+ const dropdownClass = computed(() => {
304
+ const baseClass= 'max-w-full'
305
+
306
+ return props.filterable? `${baseClass} pt-0!` : baseClass
307
+ })
308
+
303
309
  // States
304
310
  const isImageLoaded = ref(true)
305
311
  const selected = ref<SelectOption[] | SelectOption | null>(props.multiple ? [] : null)
@@ -67,6 +67,7 @@
67
67
  :submenuYOffset
68
68
  :submenuDropdownClass
69
69
  :submenuTrigger
70
+ :prefetchOn
70
71
  :class="navMenuClass"
71
72
  />
72
73
 
@@ -103,6 +104,7 @@
103
104
  :to="item.to"
104
105
  :isExternal="item.isExternal"
105
106
  :actionType="item.actionType"
107
+ :prefetchOn
106
108
  @click="item.callback"
107
109
  />
108
110
  </template>
@@ -224,6 +226,10 @@ const props = defineProps({
224
226
  type: Boolean,
225
227
  default: true,
226
228
  },
229
+ prefetchOn: {
230
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
231
+ default: PrefetchOn.VISIBILITY,
232
+ },
227
233
  navMenuClass: {
228
234
  type: String as PropType<string>,
229
235
  default: 'hidden lg:flex'
@@ -43,6 +43,7 @@
43
43
  :text="item.text"
44
44
  :to="item.to"
45
45
  :detectActive="props.detectActive"
46
+ :prefetchOn
46
47
  />
47
48
  </template>
48
49
  </nav>
@@ -84,6 +85,10 @@ const props = defineProps({
84
85
  default: Trigger.CLICK,
85
86
  validator: (value: Trigger) => Object.values(Trigger).includes(value),
86
87
  },
88
+ prefetchOn: {
89
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
90
+ default: PrefetchOn.VISIBILITY,
91
+ },
87
92
  })
88
93
 
89
94
  // Composables
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <NuxtLink :to="to">
2
+ <NuxtLink :to :prefetch-on="prefetchOn">
3
3
  <span
4
4
  :class="[
5
5
  'font-medium',
@@ -28,6 +28,10 @@ const props = defineProps({
28
28
  type: Boolean,
29
29
  default: true,
30
30
  },
31
+ prefetchOn: {
32
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
33
+ default: PrefetchOn.VISIBILITY,
34
+ },
31
35
  })
32
36
 
33
37
  // Composables
@@ -125,6 +125,8 @@
125
125
  :text="item.text"
126
126
  :icon="item.icon"
127
127
  :to="item.to"
128
+ :disabled="item.disabled"
129
+ :prefetchOn
128
130
  :styleType="itemsStyleType"
129
131
  :textClass="itemsTextClass"
130
132
  :iconClass="itemsIconClass"
@@ -143,6 +145,8 @@
143
145
  :text="child.text"
144
146
  :icon="child.icon"
145
147
  :to="child.to"
148
+ :disabled="child.disabled"
149
+ :prefetchOn
146
150
  :styleType="itemsStyleType"
147
151
  :textClass="subItemsTextClass"
148
152
  :iconClass="subItemsIconClass"
@@ -320,6 +324,10 @@ const props = defineProps({
320
324
  subItemsCustomClass: String as PropType<string>,
321
325
  subItemsTextClass: String as PropType<string>,
322
326
  subItemsIconClass: String as PropType<string>,
327
+ prefetchOn: {
328
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
329
+ default: PrefetchOn.VISIBILITY,
330
+ },
323
331
  })
324
332
 
325
333
  // States
@@ -6,6 +6,7 @@
6
6
  'flex',
7
7
  'items-center',
8
8
  'text-sm',
9
+ 'text-left',
9
10
  'font-semibold',
10
11
  'rounded-lg',
11
12
  'hover:bg-background-neutral-hover',
@@ -13,6 +14,7 @@
13
14
  spacingClass,
14
15
  !isActive && 'text-text-default',
15
16
  isActive && 'text-text-primary-brand-on-neutral-hover-bg bg-background-neutral-hover',
17
+ disabled && 'opacity-disabled cursor-not-allowed pointer-events-none',
16
18
  ]"
17
19
  @click="$emit('click')"
18
20
  >
@@ -32,7 +34,7 @@
32
34
 
33
35
  <span
34
36
  v-if="!isCollapsed"
35
- :class="textClass"
37
+ :class="[disabled && 'select-none', textClass]"
36
38
  >
37
39
  {{ text }}
38
40
  </span>
@@ -82,6 +84,14 @@ const props = defineProps({
82
84
  },
83
85
  textClass: String as PropType<string>,
84
86
  iconClass: String as PropType<string>,
87
+ disabled: {
88
+ type: Boolean as PropType<boolean>,
89
+ default: false,
90
+ },
91
+ prefetchOn: {
92
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
93
+ default: PrefetchOn.VISIBILITY,
94
+ },
85
95
  })
86
96
 
87
97
  // Emits
@@ -147,7 +157,7 @@ const componentTag = computed(() => {
147
157
 
148
158
  const componentProps = computed(() => {
149
159
  if (props.to) {
150
- return { to: props.to }
160
+ return { to: props.to, prefetchOn: props.prefetchOn }
151
161
  }
152
162
 
153
163
  return { type: 'button' }
@@ -7,7 +7,8 @@
7
7
  'px-3',
8
8
  'hover:cursor-pointer',
9
9
  'group',
10
- styleClass
10
+ disabled && 'opacity-disabled cursor-not-allowed pointer-events-none',
11
+ styleClass,
11
12
  ]"
12
13
  >
13
14
  <Icon
@@ -36,6 +37,7 @@
36
37
  :class="[
37
38
  'text-sm',
38
39
  'font-semibold',
40
+ disabled && 'select-none',
39
41
  ]"
40
42
  >
41
43
  {{ text }}
@@ -88,6 +90,10 @@ const props = defineProps({
88
90
  default: false,
89
91
  },
90
92
  badgeValue: [String, Number] as PropType<string | number>,
93
+ disabled: {
94
+ type: Boolean as PropType<boolean>,
95
+ default: false,
96
+ },
91
97
  })
92
98
 
93
99
  // States
@@ -5,6 +5,7 @@
5
5
  hasContainer && 'border border-border-default',
6
6
  hasContainer && containerStyleClass,
7
7
  hasContainer && isContainerFullWidth && 'w-full',
8
+ disabled && 'opacity-disabled cursor-not-allowed pointer-events-none',
8
9
  ]"
9
10
  >
10
11
  <Tab
@@ -15,10 +16,13 @@
15
16
  :imgUrl="tab.imgUrl"
16
17
  :badgeValue="tab.badgeValue"
17
18
  :active="index === activeIndex"
19
+ :disabled="disabled || tab.disabled"
18
20
  :tabStyle
19
21
  :size="tabSize"
20
22
  :decoration
21
23
  @click="handleTabClick(index, tab.to)"
24
+ @pointerenter="handleTabPrefetch(tab.to)"
25
+ @focus="handleTabPrefetch(tab.to)"
22
26
  />
23
27
  </div>
24
28
  </template>
@@ -59,6 +63,14 @@ const props = defineProps({
59
63
  type: Boolean as PropType<boolean>,
60
64
  default: false,
61
65
  },
66
+ disabled: {
67
+ type: Boolean as PropType<boolean>,
68
+ default: false,
69
+ },
70
+ prefetchOn: {
71
+ type: [String, Object] as PropType<PrefetchOnStrategy>,
72
+ default: PrefetchOn.VISIBILITY,
73
+ },
62
74
  })
63
75
 
64
76
  // Local
@@ -69,7 +81,7 @@ const emit = defineEmits(['update:modelValue'])
69
81
 
70
82
  // Methods
71
83
  const handleTabClick = (index: number, to?: string) => {
72
- if(to) { // If the to is provided, navigate to the route
84
+ if(to) {
73
85
  navigateTo(to)
74
86
  return
75
87
  }
@@ -78,6 +90,24 @@ const handleTabClick = (index: number, to?: string) => {
78
90
  emit('update:modelValue', index)
79
91
  }
80
92
 
93
+ const shouldPrefetchOn = (trigger: PrefetchOn): boolean => {
94
+ if (typeof props.prefetchOn === 'string') {
95
+ return props.prefetchOn === trigger
96
+ }
97
+
98
+ return trigger === PrefetchOn.VISIBILITY
99
+ ? !!props.prefetchOn?.visibility
100
+ : !!props.prefetchOn?.interaction
101
+ }
102
+
103
+ const handleTabPrefetch = (to?: string) => {
104
+ if (!to) return
105
+
106
+ if (!shouldPrefetchOn(PrefetchOn.INTERACTION)) return
107
+
108
+ // fire and forget — do not await to avoid blocking
109
+ preloadRouteComponents(to)
110
+ }
81
111
  // Watchers
82
112
  watch(() => props.modelValue, (newVal) => {
83
113
  activeIndex.value = newVal
@@ -93,5 +123,4 @@ const containerStyleClass = computed(() => {
93
123
 
94
124
  return variant[props.tabSize as TabSize] || "p-4 rounded-md"
95
125
  })
96
-
97
126
  </script>
@@ -0,0 +1,4 @@
1
+ export enum PrefetchOn {
2
+ VISIBILITY = 'visibility',
3
+ INTERACTION = 'interaction',
4
+ }
@@ -12,5 +12,6 @@ export interface DropdownMenuItem {
12
12
  to?: string
13
13
  isExternal?: boolean
14
14
  hasSeparator?: boolean
15
+ disabled?: boolean
15
16
  callback?: () => void
16
17
  }
@@ -22,4 +22,5 @@ export interface SidebarMenuItem {
22
22
  to?: string
23
23
  isSectionTitle?: boolean
24
24
  children?: SidebarMenuItem[]
25
+ disabled?: boolean
25
26
  }
@@ -0,0 +1,6 @@
1
+ export type PrefetchOnStrategy =
2
+ | PrefetchOn
3
+ | {
4
+ visibility?: boolean
5
+ interaction?: boolean
6
+ }
@@ -4,4 +4,5 @@ export interface TabItem {
4
4
  imgUrl?: string
5
5
  badgeValue?: number | string
6
6
  to?: string
7
+ disabled?: boolean
7
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imaginario27/air-ui-ds",
3
- "version": "1.9.3",
3
+ "version": "1.10.0",
4
4
  "author": "imaginario27",
5
5
  "type": "module",
6
6
  "homepage": "https://air-ui.netlify.app/",