daisy-ui-kit 5.0.0-pre.8 → 5.0.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 (93) hide show
  1. package/app/components/Accordion.vue +8 -5
  2. package/app/components/Alert.vue +2 -1
  3. package/app/components/Avatar.vue +10 -7
  4. package/app/components/AvatarGroup.vue +6 -2
  5. package/app/components/Badge.vue +19 -1
  6. package/app/components/Button.vue +67 -45
  7. package/app/components/Calendar.vue +151 -42
  8. package/app/components/CalendarInput.vue +229 -130
  9. package/app/components/CalendarSkeleton.vue +51 -10
  10. package/app/components/Card.vue +20 -2
  11. package/app/components/CardActions.vue +1 -1
  12. package/app/components/CardBody.vue +1 -1
  13. package/app/components/CardTitle.vue +1 -1
  14. package/app/components/Carousel.vue +2 -1
  15. package/app/components/Chat.vue +6 -1
  16. package/app/components/Checkbox.vue +1 -1
  17. package/app/components/Collapse.vue +38 -5
  18. package/app/components/CollapseTitle.vue +11 -1
  19. package/app/components/Countdown.vue +3 -3
  20. package/app/components/CountdownTimers.vue +4 -7
  21. package/app/components/Counter.vue +14 -3
  22. package/app/components/DaisyLink.vue +33 -15
  23. package/app/components/Dock.vue +5 -6
  24. package/app/components/DockItem.vue +5 -3
  25. package/app/components/Drawer.vue +15 -12
  26. package/app/components/DrawerContent.vue +9 -6
  27. package/app/components/DrawerSide.vue +9 -6
  28. package/app/components/Dropdown.vue +61 -50
  29. package/app/components/DropdownButton.vue +11 -4
  30. package/app/components/DropdownContent.vue +90 -20
  31. package/app/components/DropdownTarget.vue +10 -3
  32. package/app/components/Fab.vue +16 -0
  33. package/app/components/FabClose.vue +18 -0
  34. package/app/components/FabMainAction.vue +5 -0
  35. package/app/components/FabTrigger.vue +117 -0
  36. package/app/components/Fieldset.vue +5 -4
  37. package/app/components/FileInput.vue +1 -1
  38. package/app/components/Filter.vue +45 -38
  39. package/app/components/Flex.vue +8 -1
  40. package/app/components/FlexItem.vue +30 -27
  41. package/app/components/Footer.vue +16 -12
  42. package/app/components/FooterTitle.vue +8 -5
  43. package/app/components/Hero.vue +9 -6
  44. package/app/components/HeroContent.vue +9 -6
  45. package/app/components/Hover3D.vue +22 -0
  46. package/app/components/HoverGallery.vue +11 -0
  47. package/app/components/Indicator.vue +12 -5
  48. package/app/components/IndicatorItem.vue +21 -14
  49. package/app/components/Input.vue +44 -47
  50. package/app/components/Kbd.vue +2 -1
  51. package/app/components/Label.vue +32 -29
  52. package/app/components/MenuExpand.vue +5 -13
  53. package/app/components/MenuExpandToggle.vue +7 -1
  54. package/app/components/MenuItem.vue +6 -4
  55. package/app/components/Modal.vue +23 -17
  56. package/app/components/Progress.vue +13 -1
  57. package/app/components/Prose.vue +7 -2
  58. package/app/components/RadialProgress.vue +8 -8
  59. package/app/components/Radio.vue +1 -1
  60. package/app/components/RadioGroup.vue +2 -2
  61. package/app/components/Range.vue +186 -46
  62. package/app/components/RangeMeasure.vue +33 -30
  63. package/app/components/RangeMeasureTick.vue +4 -5
  64. package/app/components/Rating.vue +70 -53
  65. package/app/components/Select.vue +44 -47
  66. package/app/components/SkeletonText.vue +11 -0
  67. package/app/components/Stack.vue +5 -0
  68. package/app/components/Steps.vue +7 -2
  69. package/app/components/Swap.vue +4 -10
  70. package/app/components/Tab.vue +23 -5
  71. package/app/components/Text.vue +47 -23
  72. package/app/components/TextArea.vue +75 -30
  73. package/app/components/TextRotate.vue +24 -0
  74. package/app/components/ThemeController.vue +3 -4
  75. package/app/components/ThemeProvider.vue +47 -32
  76. package/app/components/TimelineLine.vue +1 -1
  77. package/app/components/TimelineStart.vue +2 -1
  78. package/app/components/Toast.vue +46 -8
  79. package/app/components/Toggle.vue +2 -2
  80. package/app/components/Tooltip.vue +111 -21
  81. package/app/components/TooltipContent.vue +279 -1
  82. package/app/components/TooltipTarget.vue +20 -0
  83. package/app/composables/__tests__/use-calendar.test.ts +239 -0
  84. package/app/composables/use-calendar.ts +288 -0
  85. package/app/composables/use-daisy-theme.ts +140 -0
  86. package/app/composables/use-toast.ts +345 -0
  87. package/app/composables/useSearch.ts +22 -0
  88. package/app/utils/drawer-utils.ts +15 -13
  89. package/app/utils/position-area.ts +40 -0
  90. package/nuxt.d.ts +13 -0
  91. package/nuxt.js +12 -9
  92. package/package.json +52 -27
  93. package/app/utils/random-string.ts +0 -19
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { provide, ref, watch } from 'vue';
2
+ import { provide, ref, watch } from 'vue'
3
3
 
4
4
  const props = defineProps<{
5
5
  modelValue?: string | number
@@ -7,10 +7,13 @@ const props = defineProps<{
7
7
  const emit = defineEmits(['update:modelValue'])
8
8
 
9
9
  const value = ref(props.modelValue)
10
- watch(() => props.modelValue, (val) => {
11
- value.value = val
12
- })
13
- watch(value, (val) => {
10
+ watch(
11
+ () => props.modelValue,
12
+ val => {
13
+ value.value = val
14
+ },
15
+ )
16
+ watch(value, val => {
14
17
  if (props.modelValue !== val) {
15
18
  emit('update:modelValue', val)
16
19
  }
@@ -16,7 +16,8 @@ const props = defineProps<{
16
16
 
17
17
  <template>
18
18
  <div
19
- class="alert" :class="{
19
+ class="alert"
20
+ :class="{
20
21
  'alert-outline': props.outline,
21
22
  'alert-dash': props.dash,
22
23
  'alert-soft': props.soft,
@@ -51,7 +51,7 @@ const maskShapeKeys = [
51
51
  'mask-half-2',
52
52
  ] as const
53
53
 
54
- type AvatarClassKey = typeof maskShapeKeys[number] | 'rounded-box' | 'avatar-online' | 'avatar-offline'
54
+ type AvatarClassKey = (typeof maskShapeKeys)[number] | 'rounded-box' | 'avatar-online' | 'avatar-offline'
55
55
 
56
56
  const avatarClasses = computed<Record<AvatarClassKey, boolean>>(() => {
57
57
  const mask: Record<AvatarClassKey, boolean> = {
@@ -86,18 +86,17 @@ const color = computed(() => {
86
86
  })
87
87
 
88
88
  function contrastingColor(color: any) {
89
- return (luma(color) >= 155) ? '000' : 'fff'
89
+ return luma(color) >= 155 ? '000' : 'fff'
90
90
  }
91
91
  // color can be a hx string or an array of RGB values 0-255
92
92
  function luma(color: any) {
93
- const rgb = (typeof color === 'string') ? hexToRGBArray(color) : color
94
- return (0.2126 * rgb[0]) + (0.7152 * rgb[1]) + (0.0722 * rgb[2]) // SMPTE C, Rec. 709 weightings
93
+ const rgb = typeof color === 'string' ? hexToRGBArray(color) : color
94
+ return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2] // SMPTE C, Rec. 709 weightings
95
95
  }
96
96
  function hexToRGBArray(color: any) {
97
97
  if (color.length === 3) {
98
98
  color = color.charAt(0) + color.charAt(0) + color.charAt(1) + color.charAt(1) + color.charAt(2) + color.charAt(2)
99
- }
100
- else if (color.length !== 6) {
99
+ } else if (color.length !== 6) {
101
100
  throw new Error(`Invalid hex color: ${color}`)
102
101
  }
103
102
  const rgb = []
@@ -110,7 +109,11 @@ function hexToRGBArray(color: any) {
110
109
 
111
110
  <template>
112
111
  <div class="avatar">
113
- <Mask :style="{ backgroundColor, color }" class="w-full h-full avatar-mask aspect-square" :class="[avatarClasses, maskClasses]">
112
+ <Mask
113
+ :style="{ backgroundColor, color }"
114
+ class="w-full h-full avatar-mask aspect-square"
115
+ :class="[avatarClasses, maskClasses]"
116
+ >
114
117
  <slot />
115
118
  </Mask>
116
119
  </div>
@@ -8,8 +8,12 @@ const props = defineProps<{
8
8
 
9
9
  <template>
10
10
  <div
11
- class="avatar-group" :class="{
12
- 'flex-row': props.orientation === 'horizontal' || props.horizontal || (!props.orientation && !props.vertical && !props.horizontal),
11
+ class="avatar-group"
12
+ :class="{
13
+ 'flex-row':
14
+ props.orientation === 'horizontal' ||
15
+ props.horizontal ||
16
+ (!props.orientation && !props.vertical && !props.horizontal),
13
17
  'flex-col': props.orientation === 'vertical' || props.vertical,
14
18
  }"
15
19
  >
@@ -1,4 +1,10 @@
1
1
  <script setup lang="ts">
2
+ import { computed, resolveComponent } from 'vue'
3
+
4
+ defineOptions({
5
+ inheritAttrs: false,
6
+ })
7
+
2
8
  const { is = 'div', ...props } = defineProps<{
3
9
  is?: string
4
10
  outline?: boolean
@@ -23,11 +29,23 @@ const { is = 'div', ...props } = defineProps<{
23
29
  warning?: boolean
24
30
  error?: boolean
25
31
  }>()
32
+
33
+ const NuxtLink = resolveComponent('NuxtLink')
34
+ const RouterLink = resolveComponent('RouterLink')
35
+
36
+ const resolvedComponent = computed(() => {
37
+ if (is === 'NuxtLink') return NuxtLink
38
+ if (is === 'RouterLink') return RouterLink
39
+ return is
40
+ })
26
41
  </script>
27
42
 
28
43
  <template>
29
44
  <component
30
- :is="is" class="badge" :class="{
45
+ :is="resolvedComponent"
46
+ v-bind="$attrs"
47
+ class="badge"
48
+ :class="{
31
49
  'badge-outline': props.outline,
32
50
  'badge-ghost': props.ghost,
33
51
  'badge-soft': props.soft,
@@ -1,50 +1,71 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- const props = defineProps<{
5
- is?: string
6
- join?: boolean
7
-
8
- color?: string
9
- neutral?: boolean
10
- primary?: boolean
11
- secondary?: boolean
12
- accent?: boolean
13
- info?: boolean
14
- success?: boolean
15
- warning?: boolean
16
- error?: boolean
17
-
18
- ghost?: boolean
19
- link?: boolean
20
- glass?: boolean
21
- outline?: boolean
22
- dash?: boolean
23
- soft?: boolean
24
- disabled?: boolean
25
-
26
- shape?: 'circle' | 'square' | 'wide' | 'block'
27
- circle?: boolean
28
- square?: boolean
29
- wide?: boolean
30
- block?: boolean
31
-
32
- noAnimation?: boolean
33
- active?: boolean
34
-
35
- size?: 'lg' | 'md' | 'sm' | 'xs' | 'xl'
36
- xl?: boolean
37
- lg?: boolean
38
- md?: boolean
39
- sm?: boolean
40
- xs?: boolean
41
-
42
- type?: 'button' | 'submit' | 'reset'
43
- }>()
2
+ import { computed, resolveComponent } from 'vue'
3
+
4
+ defineOptions({
5
+ inheritAttrs: false,
6
+ })
7
+
8
+ const props = withDefaults(
9
+ defineProps<{
10
+ is?: string
11
+ join?: boolean
12
+
13
+ color?: string
14
+ neutral?: boolean
15
+ primary?: boolean
16
+ secondary?: boolean
17
+ accent?: boolean
18
+ info?: boolean
19
+ success?: boolean
20
+ warning?: boolean
21
+ error?: boolean
22
+
23
+ ghost?: boolean
24
+ link?: boolean
25
+ glass?: boolean
26
+ outline?: boolean
27
+ dash?: boolean
28
+ soft?: boolean
29
+ disabled?: boolean
30
+
31
+ shape?: 'circle' | 'square' | 'wide' | 'block'
32
+ circle?: boolean
33
+ square?: boolean
34
+ wide?: boolean
35
+ block?: boolean
36
+
37
+ noAnimation?: boolean
38
+ active?: boolean
39
+
40
+ size?: 'lg' | 'md' | 'sm' | 'xs' | 'xl'
41
+ xl?: boolean
42
+ lg?: boolean
43
+ md?: boolean
44
+ sm?: boolean
45
+ xs?: boolean
46
+
47
+ type?: 'button' | 'submit' | 'reset'
48
+ }>(),
49
+ {
50
+ type: 'button',
51
+ },
52
+ )
53
+ const NuxtLink = resolveComponent('NuxtLink')
54
+ const RouterLink = resolveComponent('RouterLink')
44
55
 
45
56
  // Accessibility: Determine if rendering a native button
46
57
  const isButton = computed(() => (props.is || 'button') === 'button')
47
58
 
59
+ // Resolve the component to render
60
+ const resolvedComponent = computed(() => {
61
+ if (!props.is || props.is === 'button' || props.is === 'a') {
62
+ return props.is || 'button'
63
+ }
64
+ if (props.is === 'NuxtLink') return NuxtLink
65
+ if (props.is === 'RouterLink') return RouterLink
66
+ return props.is
67
+ })
68
+
48
69
  // Accessibility: Keyboard event handler for custom elements
49
70
  function onKeydown(e: KeyboardEvent) {
50
71
  if (props.disabled) {
@@ -60,8 +81,9 @@ function onKeydown(e: KeyboardEvent) {
60
81
 
61
82
  <template>
62
83
  <component
63
- :is="is || 'button'"
64
- :type="type"
84
+ :is="resolvedComponent"
85
+ v-bind="$attrs"
86
+ :type="isButton ? type : undefined"
65
87
  :disabled="isButton && disabled ? true : undefined"
66
88
  :aria-disabled="!isButton && disabled ? true : undefined"
67
89
  :tabindex="!isButton ? (disabled ? -1 : 0) : undefined"
@@ -88,7 +110,7 @@ function onKeydown(e: KeyboardEvent) {
88
110
  'text-warning': !disabled && (warning || color === 'warning') && link,
89
111
  'text-error': !disabled && (error || color === 'error') && link,
90
112
 
91
- 'glass': !disabled && glass,
113
+ glass: !disabled && glass,
92
114
 
93
115
  'btn-circle': circle || shape === 'circle',
94
116
  'btn-square': square || shape === 'square',
@@ -1,66 +1,175 @@
1
1
  <script setup lang="ts">
2
- import type { PikadayOptions } from 'pikaday'
3
- import { onMounted, ref } from 'vue'
4
- import { usePikaday } from '~/composables/use-pikaday'
5
- import CalendarSkeleton from './CalendarSkeleton.vue'
2
+ import type { CalendarOptions } from '../composables/use-calendar'
3
+ import { computed, watch } from 'vue'
4
+ import { useCalendar } from '../composables/use-calendar'
6
5
 
7
6
  const props = defineProps<{
8
7
  /** Bound value: Date object or ISO string or null */
9
- modelValue: Date | string | null
10
- /** All Pikaday options (except `container` and `bound`) */
11
- options?: Omit<PikadayOptions, 'container' | 'bound'>
8
+ modelValue?: Date | string | null
9
+ /** Calendar options */
10
+ options?: CalendarOptions
12
11
  /** If true, default to today when no value provided */
13
12
  autoDefault?: boolean
14
13
  }>()
14
+
15
15
  const emit = defineEmits<{
16
16
  (e: 'update:modelValue', v: Date | null): void
17
17
  }>()
18
18
 
19
- const containerRef = ref<HTMLElement | null>(null)
20
- const loading = ref(true)
21
-
22
- const defaultOptions: Partial<PikadayOptions> = {
23
- format: 'D MMM YYYY',
19
+ // Parse initial date from modelValue
20
+ function parseDate(value: Date | string | null | undefined): Date | null {
21
+ if (!value) return null
22
+ if (value instanceof Date) return value
23
+ const d = new Date(value)
24
+ return Number.isNaN(d.getTime()) ? null : d
24
25
  }
25
26
 
26
- function handleSelect(date: Date) {
27
+ const initialDate = computed(() => {
28
+ const parsed = parseDate(props.modelValue)
29
+ if (parsed) return parsed
30
+ if (props.autoDefault) return new Date()
31
+ return null
32
+ })
33
+
34
+ const {
35
+ selectedDate,
36
+ viewMonth,
37
+ viewYear,
38
+ monthName,
39
+ weekdayHeaders,
40
+ weekdayHeadersFull,
41
+ calendarDays,
42
+ prevMonth,
43
+ nextMonth,
44
+ selectDate,
45
+ goToDate,
46
+ } = useCalendar(initialDate.value, props.options)
47
+
48
+ // Sync selectedDate back to modelValue
49
+ watch(selectedDate, date => {
27
50
  emit('update:modelValue', date)
28
- }
51
+ })
29
52
 
30
- const { createPicker } = usePikaday(
31
- {
32
- ...defaultOptions,
33
- ...props.options,
34
- bound: false,
53
+ // Watch for external modelValue changes
54
+ watch(
55
+ () => props.modelValue,
56
+ newValue => {
57
+ const parsed = parseDate(newValue)
58
+ if (parsed && (!selectedDate.value || parsed.getTime() !== selectedDate.value.getTime())) {
59
+ selectDate(parsed)
60
+ goToDate(parsed)
61
+ }
35
62
  },
36
- handleSelect,
37
63
  )
38
64
 
39
- onMounted(async () => {
40
- if (containerRef.value) {
41
- const picker = await createPicker(containerRef.value)
42
- if (picker && picker.el && !containerRef.value.contains(picker.el)) {
43
- containerRef.value.appendChild(picker.el)
44
- }
45
- loading.value = false
46
- }
47
- })
65
+ function handleDayClick(day: (typeof calendarDays.value)[0]) {
66
+ if (day.isDisabled) return
67
+ selectDate(day.date)
68
+ }
48
69
  </script>
49
70
 
50
71
  <template>
51
- <div class="relative w-[270px] h-[270px]">
52
- <div class="absolute inset-0">
53
- <CalendarSkeleton :number-of-months="options?.numberOfMonths ?? 1" :class="loading ? '' : 'opacity-0 pointer-events-none transition-opacity duration-300'" />
72
+ <div class="pika-single">
73
+ <div class="pika-lendar">
74
+ <!-- Header with navigation -->
75
+ <div class="pika-title">
76
+ <div class="pika-label">
77
+ {{ monthName }}
78
+ <select
79
+ class="pika-select pika-select-month"
80
+ :value="viewMonth"
81
+ @change="
82
+ e => {
83
+ const target = e.target as HTMLSelectElement
84
+ const newMonth = parseInt(target.value, 10)
85
+ const d = new Date(viewYear, newMonth, 1)
86
+ goToDate(d)
87
+ }
88
+ "
89
+ >
90
+ <option
91
+ v-for="(m, i) in [
92
+ 'January',
93
+ 'February',
94
+ 'March',
95
+ 'April',
96
+ 'May',
97
+ 'June',
98
+ 'July',
99
+ 'August',
100
+ 'September',
101
+ 'October',
102
+ 'November',
103
+ 'December',
104
+ ]"
105
+ :key="i"
106
+ :value="i"
107
+ >
108
+ {{ m }}
109
+ </option>
110
+ </select>
111
+ </div>
112
+ <div class="pika-label">
113
+ {{ viewYear }}
114
+ <select
115
+ class="pika-select pika-select-year"
116
+ :value="viewYear"
117
+ @change="
118
+ e => {
119
+ const target = e.target as HTMLSelectElement
120
+ const newYear = parseInt(target.value, 10)
121
+ const d = new Date(newYear, viewMonth, 1)
122
+ goToDate(d)
123
+ }
124
+ "
125
+ >
126
+ <option v-for="y in Array.from({ length: 21 }, (_, i) => viewYear - 10 + i)" :key="y" :value="y">
127
+ {{ y }}
128
+ </option>
129
+ </select>
130
+ </div>
131
+ <button type="button" class="pika-prev" @click="prevMonth">Previous Month</button>
132
+ <button type="button" class="pika-next" @click="nextMonth">Next Month</button>
133
+ </div>
134
+
135
+ <!-- Calendar grid -->
136
+ <table class="pika-table" role="grid">
137
+ <thead>
138
+ <tr>
139
+ <th v-for="(day, i) in weekdayHeaders" :key="i" scope="col">
140
+ <abbr :title="weekdayHeadersFull[i]">{{ day }}</abbr>
141
+ </th>
142
+ </tr>
143
+ </thead>
144
+ <tbody>
145
+ <tr v-for="week in 6" :key="week" class="pika-row">
146
+ <td
147
+ v-for="dayIndex in 7"
148
+ :key="dayIndex"
149
+ :class="{
150
+ 'is-today': calendarDays[(week - 1) * 7 + dayIndex - 1]?.isToday,
151
+ 'is-selected': calendarDays[(week - 1) * 7 + dayIndex - 1]?.isSelected,
152
+ 'is-disabled': calendarDays[(week - 1) * 7 + dayIndex - 1]?.isDisabled,
153
+ 'is-outside-current-month': calendarDays[(week - 1) * 7 + dayIndex - 1]?.isOutsideMonth,
154
+ }"
155
+ :aria-selected="calendarDays[(week - 1) * 7 + dayIndex - 1]?.isSelected"
156
+ :data-day="calendarDays[(week - 1) * 7 + dayIndex - 1]?.day"
157
+ >
158
+ <button
159
+ type="button"
160
+ class="pika-button pika-day"
161
+ :disabled="calendarDays[(week - 1) * 7 + dayIndex - 1]?.isDisabled"
162
+ :data-pika-year="calendarDays[(week - 1) * 7 + dayIndex - 1]?.year"
163
+ :data-pika-month="calendarDays[(week - 1) * 7 + dayIndex - 1]?.month"
164
+ :data-pika-day="calendarDays[(week - 1) * 7 + dayIndex - 1]?.day"
165
+ @click="handleDayClick(calendarDays[(week - 1) * 7 + dayIndex - 1]!)"
166
+ >
167
+ {{ calendarDays[(week - 1) * 7 + dayIndex - 1]?.day }}
168
+ </button>
169
+ </td>
170
+ </tr>
171
+ </tbody>
172
+ </table>
54
173
  </div>
55
- <div ref="containerRef" class="absolute inset-0 inline-block w-full h-full" />
56
- <span class="pika-single hidden" />
57
174
  </div>
58
175
  </template>
59
-
60
- <style>
61
- .has-event {
62
- .pika-button {
63
- color: var(--color-primary);
64
- }
65
- }
66
- </style>