daisy-ui-kit 5.0.0-pre.10 → 5.0.0-pre.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.
Files changed (81) 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 +14 -1
  6. package/app/components/Button.vue +60 -45
  7. package/app/components/Calendar.vue +24 -1
  8. package/app/components/CalendarInput.vue +2 -2
  9. package/app/components/CalendarSkeleton.vue +51 -10
  10. package/app/components/Card.vue +15 -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 +37 -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 +13 -2
  22. package/app/components/DaisyLink.vue +29 -15
  23. package/app/components/Dock.vue +1 -1
  24. package/app/components/DockItem.vue +1 -1
  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 -19
  31. package/app/components/DropdownTarget.vue +9 -2
  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 +1 -4
  37. package/app/components/FileInput.vue +1 -1
  38. package/app/components/Filter.vue +35 -32
  39. package/app/components/Flex.vue +3 -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 +8 -5
  48. package/app/components/IndicatorItem.vue +16 -13
  49. package/app/components/Input.vue +47 -40
  50. package/app/components/Kbd.vue +2 -1
  51. package/app/components/Label.vue +32 -29
  52. package/app/components/MenuExpand.vue +1 -7
  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 +2 -2
  62. package/app/components/RangeMeasure.vue +33 -30
  63. package/app/components/Rating.vue +70 -53
  64. package/app/components/Select.vue +44 -47
  65. package/app/components/SkeletonText.vue +11 -0
  66. package/app/components/Steps.vue +7 -2
  67. package/app/components/Swap.vue +4 -10
  68. package/app/components/Tab.vue +18 -5
  69. package/app/components/Text.vue +42 -22
  70. package/app/components/TextArea.vue +30 -27
  71. package/app/components/TextRotate.vue +24 -0
  72. package/app/components/ThemeController.vue +3 -4
  73. package/app/components/ThemeProvider.vue +47 -32
  74. package/app/components/TimelineLine.vue +1 -1
  75. package/app/components/TimelineStart.vue +2 -1
  76. package/app/components/Toast.vue +1 -6
  77. package/app/components/Toggle.vue +2 -2
  78. package/app/components/Tooltip.vue +2 -1
  79. package/app/utils/drawer-utils.ts +15 -13
  80. package/app/utils/position-area.ts +41 -0
  81. package/package.json +9 -7
@@ -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,6 @@
1
1
  <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
2
4
  const { is = 'div', ...props } = defineProps<{
3
5
  is?: string
4
6
  outline?: boolean
@@ -23,11 +25,22 @@ const { is = 'div', ...props } = defineProps<{
23
25
  warning?: boolean
24
26
  error?: boolean
25
27
  }>()
28
+
29
+ const NuxtLink = resolveComponent('NuxtLink')
30
+ const RouterLink = resolveComponent('RouterLink')
31
+
32
+ const resolvedComponent = computed(() => {
33
+ if (is === 'NuxtLink') return NuxtLink
34
+ if (is === 'RouterLink') return RouterLink
35
+ return is
36
+ })
26
37
  </script>
27
38
 
28
39
  <template>
29
40
  <component
30
- :is="is" class="badge" :class="{
41
+ :is="resolvedComponent"
42
+ class="badge"
43
+ :class="{
31
44
  'badge-outline': props.outline,
32
45
  'badge-ghost': props.ghost,
33
46
  'badge-soft': props.soft,
@@ -1,52 +1,67 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
3
 
4
- const props = withDefaults(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
- }>(), {
44
- type: 'button',
45
- })
4
+ const props = withDefaults(
5
+ defineProps<{
6
+ is?: string
7
+ join?: boolean
8
+
9
+ color?: string
10
+ neutral?: boolean
11
+ primary?: boolean
12
+ secondary?: boolean
13
+ accent?: boolean
14
+ info?: boolean
15
+ success?: boolean
16
+ warning?: boolean
17
+ error?: boolean
18
+
19
+ ghost?: boolean
20
+ link?: boolean
21
+ glass?: boolean
22
+ outline?: boolean
23
+ dash?: boolean
24
+ soft?: boolean
25
+ disabled?: boolean
26
+
27
+ shape?: 'circle' | 'square' | 'wide' | 'block'
28
+ circle?: boolean
29
+ square?: boolean
30
+ wide?: boolean
31
+ block?: boolean
32
+
33
+ noAnimation?: boolean
34
+ active?: boolean
35
+
36
+ size?: 'lg' | 'md' | 'sm' | 'xs' | 'xl'
37
+ xl?: boolean
38
+ lg?: boolean
39
+ md?: boolean
40
+ sm?: boolean
41
+ xs?: boolean
42
+
43
+ type?: 'button' | 'submit' | 'reset'
44
+ }>(),
45
+ {
46
+ type: 'button',
47
+ },
48
+ )
49
+ const NuxtLink = resolveComponent('NuxtLink')
50
+ const RouterLink = resolveComponent('RouterLink')
46
51
 
47
52
  // Accessibility: Determine if rendering a native button
48
53
  const isButton = computed(() => (props.is || 'button') === 'button')
49
54
 
55
+ // Resolve the component to render
56
+ const resolvedComponent = computed(() => {
57
+ if (!props.is || props.is === 'button' || props.is === 'a') {
58
+ return props.is || 'button'
59
+ }
60
+ if (props.is === 'NuxtLink') return NuxtLink
61
+ if (props.is === 'RouterLink') return RouterLink
62
+ return props.is
63
+ })
64
+
50
65
  // Accessibility: Keyboard event handler for custom elements
51
66
  function onKeydown(e: KeyboardEvent) {
52
67
  if (props.disabled) {
@@ -62,8 +77,8 @@ function onKeydown(e: KeyboardEvent) {
62
77
 
63
78
  <template>
64
79
  <component
65
- :is="is || 'button'"
66
- :type="type"
80
+ :is="resolvedComponent"
81
+ :type="isButton ? type : undefined"
67
82
  :disabled="isButton && disabled ? true : undefined"
68
83
  :aria-disabled="!isButton && disabled ? true : undefined"
69
84
  :tabindex="!isButton ? (disabled ? -1 : 0) : undefined"
@@ -90,7 +105,7 @@ function onKeydown(e: KeyboardEvent) {
90
105
  'text-warning': !disabled && (warning || color === 'warning') && link,
91
106
  'text-error': !disabled && (error || color === 'error') && link,
92
107
 
93
- 'glass': !disabled && glass,
108
+ glass: !disabled && glass,
94
109
 
95
110
  'btn-circle': circle || shape === 'circle',
96
111
  'btn-square': square || shape === 'square',
@@ -23,6 +23,24 @@ const defaultOptions: Partial<PikadayOptions> = {
23
23
  format: 'D MMM YYYY',
24
24
  }
25
25
 
26
+ // Determine the date to use for the skeleton
27
+ const skeletonDate = computed(() => {
28
+ // Try to use modelValue if it's a Date
29
+ if (props.modelValue instanceof Date) {
30
+ return props.modelValue
31
+ }
32
+ // Try to parse modelValue if it's a string
33
+ if (typeof props.modelValue === 'string') {
34
+ return new Date(props.modelValue)
35
+ }
36
+ // Use defaultDate from options if provided
37
+ if (props.options?.defaultDate instanceof Date) {
38
+ return props.options.defaultDate
39
+ }
40
+ // Fall back to today
41
+ return new Date()
42
+ })
43
+
26
44
  function handleSelect(date: Date) {
27
45
  emit('update:modelValue', date)
28
46
  }
@@ -50,7 +68,12 @@ onMounted(async () => {
50
68
  <template>
51
69
  <div class="relative w-[270px] h-[270px]">
52
70
  <div class="absolute inset-0">
53
- <CalendarSkeleton :number-of-months="options?.numberOfMonths ?? 1" :class="loading ? '' : 'opacity-0 pointer-events-none transition-opacity duration-300'" />
71
+ <CalendarSkeleton
72
+ :number-of-months="options?.numberOfMonths ?? 1"
73
+ :date="skeletonDate"
74
+ :first-day="options?.firstDay"
75
+ :class="loading ? '' : 'opacity-0 pointer-events-none transition-opacity duration-300'"
76
+ />
54
77
  </div>
55
78
  <div ref="containerRef" class="absolute inset-0 inline-block w-full h-full" />
56
79
  <span class="pika-single hidden" />
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { onMounted, ref, watch } from 'vue'
3
- import type { ComponentPublicInstance, Ref } from 'vue'
4
2
  import type { PikadayOptions } from 'pikaday'
3
+ import type { ComponentPublicInstance } from 'vue'
4
+ import { onMounted, ref, watch } from 'vue'
5
5
 
6
6
  import { usePikaday } from '~/composables/use-pikaday'
7
7
 
@@ -1,17 +1,58 @@
1
1
  <script setup lang="ts">
2
2
  import Skeleton from './Skeleton.vue'
3
3
 
4
- const { numberOfMonths = 1 } = defineProps<{
4
+ const props = defineProps<{
5
5
  numberOfMonths?: number
6
+ date?: Date
7
+ firstDay?: number // 0 = Sunday, 1 = Monday, etc. (matches Pikaday's firstDay option)
6
8
  }>()
9
+
10
+ // Calculate the number of weeks needed for a given month
11
+ function getWeeksInMonth(date: Date, weekStartDay: number = 0): number {
12
+ const year = date.getFullYear()
13
+ const month = date.getMonth()
14
+
15
+ // Get first day of month
16
+ const firstDay = new Date(year, month, 1)
17
+ const firstDayOfWeek = firstDay.getDay()
18
+
19
+ // Get last day of month
20
+ const lastDay = new Date(year, month + 1, 0)
21
+ const daysInMonth = lastDay.getDate()
22
+
23
+ // Calculate offset based on what day the week starts on
24
+ // If week starts on Monday (1) and month starts on Sunday (0), offset is 6
25
+ // If week starts on Sunday (0) and month starts on Sunday (0), offset is 0
26
+ const offset = (firstDayOfWeek - weekStartDay + 7) % 7
27
+
28
+ // Calculate total cells needed (days in month + offset from first day)
29
+ const totalCells = daysInMonth + offset
30
+
31
+ // Return number of weeks (rows) needed
32
+ return Math.ceil(totalCells / 7)
33
+ }
34
+
35
+ // Calculate weeks for each month being displayed
36
+ const weeksPerMonth = computed(() => {
37
+ const baseDate = props.date || new Date()
38
+ const weekStartDay = props.firstDay ?? 0
39
+ const weeks: number[] = []
40
+
41
+ for (let i = 0; i < (props.numberOfMonths || 1); i++) {
42
+ const monthDate = new Date(baseDate.getFullYear(), baseDate.getMonth() + i, 1)
43
+ weeks.push(getWeeksInMonth(monthDate, weekStartDay))
44
+ }
45
+
46
+ return weeks
47
+ })
7
48
  </script>
8
49
 
9
50
  <template>
10
51
  <Skeleton col class="bg-base-200 rounded-box">
11
52
  <div
12
- v-for="(month, idx) in numberOfMonths"
13
- :key="`calendar-${month}`"
14
- class="w-[270px] h-[270px] p-3 mx-auto flex flex-col gap-2"
53
+ v-for="(weeks, idx) in weeksPerMonth"
54
+ :key="`calendar-${idx}`"
55
+ class="w-[270px] px-3 py-[14px] mx-auto flex flex-col gap-2"
15
56
  :class="{
16
57
  '-mt-3.5': idx > 0,
17
58
  }"
@@ -28,17 +69,17 @@ const { numberOfMonths = 1 } = defineProps<{
28
69
  <span
29
70
  class="size-4 rounded-full bg-base-300 inline-block"
30
71
  :class="{
31
- 'bg-base-300': idx === numberOfMonths - 1,
32
- 'bg-transparent': idx !== numberOfMonths - 1,
72
+ 'bg-base-300': idx === weeksPerMonth.length - 1,
73
+ 'bg-transparent': idx !== weeksPerMonth.length - 1,
33
74
  }"
34
75
  />
35
76
  </Flex>
36
- <Flex col grow justify-between class="h-full">
37
- <div class="grid grid-cols-7 gap-[4px] mb-4 flex-shrink-0">
77
+ <Flex col class="h-full">
78
+ <div class="grid grid-cols-7 gap-[4px] mb-3 flex-shrink-0">
38
79
  <span v-for="d in 7" :key="`dow-${d}`" class="size-4 rounded-full bg-base-300 mx-auto block" />
39
80
  </div>
40
- <div class="grid grid-cols-7 gap-[4px] flex-grow items-center">
41
- <span v-for="i in 35" :key="`day-${i}`" class="size-7 rounded-full bg-base-300 block mx-auto" />
81
+ <div class="grid grid-cols-7 gap-y-[8px] gap-x-[4px]">
82
+ <span v-for="i in weeks * 7" :key="`day-${i}`" class="size-7 rounded-full bg-base-300 block mx-auto" />
42
83
  </div>
43
84
  </Flex>
44
85
  </div>
@@ -1,6 +1,8 @@
1
1
  <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
2
4
  const { is = 'div', ...props } = defineProps<{
3
- is?: any
5
+ is?: string
4
6
  border?: boolean
5
7
  dash?: boolean
6
8
  side?: boolean
@@ -12,11 +14,22 @@ const { is = 'div', ...props } = defineProps<{
12
14
  sm?: boolean
13
15
  xs?: boolean
14
16
  }>()
17
+
18
+ const NuxtLink = resolveComponent('NuxtLink')
19
+ const RouterLink = resolveComponent('RouterLink')
20
+
21
+ const resolvedComponent = computed(() => {
22
+ if (is === 'NuxtLink') return NuxtLink
23
+ if (is === 'RouterLink') return RouterLink
24
+ return is
25
+ })
15
26
  </script>
16
27
 
17
28
  <template>
18
29
  <component
19
- :is="is" class="card" :class="{
30
+ :is="resolvedComponent"
31
+ class="card"
32
+ :class="{
20
33
  'card-border': props.border,
21
34
  'card-side': props.side,
22
35
  'image-full': props.imageFull,
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import Text from './Text.vue';
2
+ import Text from './Text.vue'
3
3
 
4
4
  const { is = 'div' } = defineProps<{
5
5
  is?: string
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import Text from './Text.vue';
2
+ import Text from './Text.vue'
3
3
 
4
4
  const { is = 'div' } = defineProps<{
5
5
  is?: string
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import Text from './Text.vue';
2
+ import Text from './Text.vue'
3
3
 
4
4
  const { is = 'div' } = defineProps<{ is?: string }>()
5
5
  </script>
@@ -11,7 +11,8 @@ const { snapTo, center, end, vertical } = defineProps<{
11
11
 
12
12
  <template>
13
13
  <div
14
- class="carousel" :class="{
14
+ class="carousel"
15
+ :class="{
15
16
  'carousel-center': center || snapTo === 'center',
16
17
  'carousel-end': end || snapTo === 'end',
17
18
  'carousel-horizontal': horizontal || orientation === 'horizontal',
@@ -1,5 +1,10 @@
1
1
  <script setup lang="ts">
2
- const { pre, align = 'start', start, end } = defineProps<{
2
+ const {
3
+ pre,
4
+ align = 'start',
5
+ start,
6
+ end,
7
+ } = defineProps<{
3
8
  pre?: boolean
4
9
  align?: string
5
10
  start?: boolean
@@ -47,5 +47,5 @@ const currentValue = computed({
47
47
  'checkbox-lg': lg || size === 'lg',
48
48
  'theme-controller': themeController,
49
49
  }"
50
- >
50
+ />
51
51
  </template>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { inject, ref } from 'vue'
2
+ import { inject, provide, ref, watch } from 'vue'
3
3
 
4
4
  const props = defineProps<{
5
5
  variant?: 'arrow' | 'plus'
@@ -11,19 +11,49 @@ const props = defineProps<{
11
11
  value?: any
12
12
  }>()
13
13
 
14
+ const isOpen = defineModel('open', { default: false })
15
+
14
16
  const accordionValue = inject('accordion-value', ref(null))
15
17
  const useAccordion = accordionValue.value !== null
16
18
 
19
+ // Internal state for toggle mode
20
+ const internalChecked = ref(props.open || false)
21
+
22
+ // Generate unique ID for checkbox
23
+ const checkboxId = `collapse-${Math.random().toString(36).substr(2, 9)}`
24
+ provide('collapseCheckboxId', checkboxId)
25
+ provide('collapseToggle', props.toggle || useAccordion)
26
+
27
+ // Sync internal state with modelValue
28
+ watch(
29
+ () => isOpen.value,
30
+ newVal => {
31
+ internalChecked.value = newVal
32
+ },
33
+ )
34
+
35
+ watch(internalChecked, newVal => {
36
+ isOpen.value = newVal
37
+ })
38
+
17
39
  function handleClick() {
40
+ // Only handle clicks for accordion mode
18
41
  if (useAccordion) {
19
42
  accordionValue.value = props.value
20
43
  }
21
44
  }
45
+
46
+ const isChecked = computed(() => {
47
+ if (useAccordion) {
48
+ return accordionValue.value === props.value
49
+ }
50
+ return internalChecked.value
51
+ })
22
52
  </script>
23
53
 
24
54
  <template>
25
55
  <div
26
- tabindex="0"
56
+ :tabindex="props.toggle || useAccordion ? undefined : 0"
27
57
  class="collapse"
28
58
  :class="[
29
59
  { 'collapse-arrow': props.arrow || props.variant === 'arrow' },
@@ -31,13 +61,15 @@ function handleClick() {
31
61
  { 'collapse-open': (props.open && !props.close) || (useAccordion && accordionValue === props.value) },
32
62
  { 'collapse-close': props.close },
33
63
  ]"
34
- @click="handleClick"
64
+ @click="useAccordion ? handleClick : undefined"
35
65
  >
36
66
  <input
37
67
  v-if="props.toggle || useAccordion"
68
+ :id="checkboxId"
69
+ v-model="internalChecked"
38
70
  :type="useAccordion ? 'radio' : 'checkbox'"
39
- :checked="useAccordion ? accordionValue === props.value : undefined"
40
- >
71
+ :checked="useAccordion ? isChecked : undefined"
72
+ />
41
73
  <slot />
42
74
  </div>
43
75
  </template>
@@ -1,5 +1,15 @@
1
+ <script setup lang="ts">
2
+ import { inject } from 'vue'
3
+
4
+ const checkboxId = inject('collapseCheckboxId', null)
5
+ const hasToggle = inject('collapseToggle', false)
6
+ </script>
7
+
1
8
  <template>
2
- <div class="collapse-title">
9
+ <label v-if="hasToggle && checkboxId" :for="checkboxId" class="collapse-title">
10
+ <slot />
11
+ </label>
12
+ <div v-else class="collapse-title">
3
13
  <slot />
4
14
  </div>
5
15
  </template>
@@ -1,11 +1,11 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue';
2
+ import { computed } from 'vue'
3
3
 
4
- const { is = 'span' } = defineProps<{
4
+ const props = defineProps<{
5
5
  is?: any
6
6
  }>()
7
7
 
8
- const tag = computed(() => is)
8
+ const tag = computed(() => props.is || 'span')
9
9
  </script>
10
10
 
11
11
  <template>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { useIntervalFn } from '@vueuse/core';
3
- import { computed, ref, watch } from 'vue';
2
+ import { useIntervalFn } from '@vueuse/core'
3
+ import { computed, ref, watch } from 'vue'
4
4
 
5
5
  const { durationInSeconds = 0, untilDate } = defineProps<{
6
6
  durationInSeconds?: number
@@ -29,7 +29,7 @@ useIntervalFn(() => {
29
29
  timeLeft.value = calcTimeLeft()
30
30
  }, 1000)
31
31
 
32
- watch(timeLeft, (val) => {
32
+ watch(timeLeft, val => {
33
33
  if (val === 0) {
34
34
  emit('done')
35
35
  }
@@ -42,10 +42,7 @@ const totalDays = computed(() => Math.floor(totalHours.value / 24))
42
42
  const totalWeeks = computed(() => Math.floor(totalDays.value / 7))
43
43
  const totalMonths = computed(() => {
44
44
  const now = new Date()
45
- return (
46
- (targetDate.value.getFullYear() - now.getFullYear()) * 12
47
- + (targetDate.value.getMonth() - now.getMonth())
48
- )
45
+ return (targetDate.value.getFullYear() - now.getFullYear()) * 12 + (targetDate.value.getMonth() - now.getMonth())
49
46
  })
50
47
  const split = computed(() => {
51
48
  const days = totalDays.value
@@ -1,10 +1,21 @@
1
1
  <script setup lang="ts">
2
- const { is = 'span' } = defineProps<{
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps<{
3
5
  value: number
4
6
  is?: any
7
+ digits?: 2 | 3
5
8
  }>()
9
+
10
+ const style = computed(() => {
11
+ let css = `--value:${props.value};`
12
+ if (props.digits) {
13
+ css += `--digits:${props.digits};`
14
+ }
15
+ return css
16
+ })
6
17
  </script>
7
18
 
8
19
  <template>
9
- <component :is="is" v-bind="$attrs" :style="`--value:${value};`" />
20
+ <component :is="props.is || 'span'" v-bind="$attrs" :style="style" />
10
21
  </template>