daisy-ui-kit 5.0.2 → 5.0.4

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 (153) hide show
  1. package/README.md +20 -1
  2. package/dist/index.css +1 -0
  3. package/dist/index.d.ts +4652 -0
  4. package/dist/index.js +5279 -0
  5. package/package.json +12 -16
  6. package/app/components/Accordion.vue +0 -29
  7. package/app/components/Alert.vue +0 -36
  8. package/app/components/Avatar.vue +0 -131
  9. package/app/components/AvatarGroup.vue +0 -22
  10. package/app/components/Badge.vue +0 -72
  11. package/app/components/Breadcrumbs.vue +0 -7
  12. package/app/components/Button.vue +0 -140
  13. package/app/components/Calendar.vue +0 -175
  14. package/app/components/CalendarInput.vue +0 -275
  15. package/app/components/CalendarSkeleton.vue +0 -87
  16. package/app/components/Card.vue +0 -51
  17. package/app/components/CardActions.vue +0 -13
  18. package/app/components/CardBody.vue +0 -13
  19. package/app/components/CardTitle.vue +0 -11
  20. package/app/components/Carousel.vue +0 -24
  21. package/app/components/CarouselItem.vue +0 -5
  22. package/app/components/Chat.vue +0 -26
  23. package/app/components/ChatBubble.vue +0 -31
  24. package/app/components/ChatFooter.vue +0 -5
  25. package/app/components/ChatHeader.vue +0 -5
  26. package/app/components/ChatImage.vue +0 -5
  27. package/app/components/Checkbox.vue +0 -51
  28. package/app/components/Collapse.vue +0 -76
  29. package/app/components/CollapseContent.vue +0 -5
  30. package/app/components/CollapseTitle.vue +0 -15
  31. package/app/components/Countdown.vue +0 -15
  32. package/app/components/CountdownTimers.vue +0 -69
  33. package/app/components/Counter.vue +0 -21
  34. package/app/components/Crumb.vue +0 -5
  35. package/app/components/DaisyLink.vue +0 -56
  36. package/app/components/Diff.vue +0 -11
  37. package/app/components/Divider.vue +0 -43
  38. package/app/components/Dock.vue +0 -57
  39. package/app/components/DockItem.vue +0 -27
  40. package/app/components/DockLabel.vue +0 -5
  41. package/app/components/Drawer.vue +0 -50
  42. package/app/components/DrawerContent.vue +0 -20
  43. package/app/components/DrawerSide.vue +0 -21
  44. package/app/components/Dropdown.vue +0 -106
  45. package/app/components/DropdownButton.vue +0 -23
  46. package/app/components/DropdownContent.vue +0 -127
  47. package/app/components/DropdownTarget.vue +0 -21
  48. package/app/components/Fab.vue +0 -16
  49. package/app/components/FabClose.vue +0 -18
  50. package/app/components/FabMainAction.vue +0 -5
  51. package/app/components/FabTrigger.vue +0 -117
  52. package/app/components/Fieldset.vue +0 -20
  53. package/app/components/FileInput.vue +0 -53
  54. package/app/components/Filter.vue +0 -129
  55. package/app/components/Flex.vue +0 -89
  56. package/app/components/FlexItem.vue +0 -62
  57. package/app/components/Footer.vue +0 -31
  58. package/app/components/FooterTitle.vue +0 -18
  59. package/app/components/FormControl.vue +0 -5
  60. package/app/components/Hero.vue +0 -18
  61. package/app/components/HeroContent.vue +0 -18
  62. package/app/components/HeroOverlay.vue +0 -5
  63. package/app/components/Hover3D.vue +0 -22
  64. package/app/components/HoverGallery.vue +0 -11
  65. package/app/components/Indicator.vue +0 -20
  66. package/app/components/IndicatorItem.vue +0 -43
  67. package/app/components/Input.vue +0 -116
  68. package/app/components/Join.vue +0 -5
  69. package/app/components/Kbd.vue +0 -25
  70. package/app/components/Label.vue +0 -100
  71. package/app/components/List.vue +0 -5
  72. package/app/components/ListColGrow.vue +0 -5
  73. package/app/components/ListColWrap.vue +0 -5
  74. package/app/components/ListRow.vue +0 -5
  75. package/app/components/LoadingBall.vue +0 -42
  76. package/app/components/LoadingBars.vue +0 -42
  77. package/app/components/LoadingDots.vue +0 -42
  78. package/app/components/LoadingInfinity.vue +0 -42
  79. package/app/components/LoadingRing.vue +0 -42
  80. package/app/components/LoadingSpinner.vue +0 -42
  81. package/app/components/Mask.vue +0 -49
  82. package/app/components/Menu.vue +0 -30
  83. package/app/components/MenuExpand.vue +0 -92
  84. package/app/components/MenuExpandToggle.vue +0 -20
  85. package/app/components/MenuItem.vue +0 -39
  86. package/app/components/MenuTitle.vue +0 -5
  87. package/app/components/MockupBrowser.vue +0 -5
  88. package/app/components/MockupBrowserToolbar.vue +0 -5
  89. package/app/components/MockupCode.vue +0 -4
  90. package/app/components/MockupPhone.vue +0 -14
  91. package/app/components/MockupWindow.vue +0 -5
  92. package/app/components/Modal.vue +0 -63
  93. package/app/components/ModalAction.vue +0 -5
  94. package/app/components/ModalBox.vue +0 -5
  95. package/app/components/NavButton.vue +0 -12
  96. package/app/components/Navbar.vue +0 -12
  97. package/app/components/NavbarCenter.vue +0 -11
  98. package/app/components/NavbarEnd.vue +0 -11
  99. package/app/components/NavbarStart.vue +0 -11
  100. package/app/components/Progress.vue +0 -46
  101. package/app/components/Prose.vue +0 -37
  102. package/app/components/RadialProgress.vue +0 -36
  103. package/app/components/Radio.vue +0 -69
  104. package/app/components/RadioGroup.vue +0 -47
  105. package/app/components/Range.vue +0 -201
  106. package/app/components/RangeMeasure.vue +0 -87
  107. package/app/components/RangeMeasureTick.vue +0 -69
  108. package/app/components/Rating.vue +0 -197
  109. package/app/components/Select.vue +0 -101
  110. package/app/components/Skeleton.vue +0 -5
  111. package/app/components/SkeletonText.vue +0 -11
  112. package/app/components/Stack.vue +0 -30
  113. package/app/components/Stat.vue +0 -19
  114. package/app/components/StatActions.vue +0 -5
  115. package/app/components/StatDesc.vue +0 -5
  116. package/app/components/StatFigure.vue +0 -5
  117. package/app/components/StatTitle.vue +0 -5
  118. package/app/components/StatValue.vue +0 -5
  119. package/app/components/Stats.vue +0 -5
  120. package/app/components/Status.vue +0 -43
  121. package/app/components/Step.vue +0 -34
  122. package/app/components/StepIcon.vue +0 -5
  123. package/app/components/Steps.vue +0 -23
  124. package/app/components/Swap.vue +0 -56
  125. package/app/components/Tab.vue +0 -56
  126. package/app/components/TabContent.vue +0 -29
  127. package/app/components/Table.vue +0 -32
  128. package/app/components/Tabs.vue +0 -53
  129. package/app/components/Text.vue +0 -166
  130. package/app/components/TextArea.vue +0 -106
  131. package/app/components/TextRotate.vue +0 -24
  132. package/app/components/ThemeController.vue +0 -45
  133. package/app/components/ThemeProvider.vue +0 -302
  134. package/app/components/ThemeTile.vue +0 -50
  135. package/app/components/Timeline.vue +0 -22
  136. package/app/components/TimelineEnd.vue +0 -14
  137. package/app/components/TimelineItem.vue +0 -5
  138. package/app/components/TimelineLine.vue +0 -29
  139. package/app/components/TimelineMiddle.vue +0 -5
  140. package/app/components/TimelineStart.vue +0 -14
  141. package/app/components/Toast.vue +0 -67
  142. package/app/components/Toggle.vue +0 -60
  143. package/app/components/Tooltip.vue +0 -137
  144. package/app/components/TooltipContent.vue +0 -283
  145. package/app/components/TooltipTarget.vue +0 -20
  146. package/app/components/ValidatorHint.vue +0 -5
  147. package/app/composables/__tests__/use-calendar.test.ts +0 -239
  148. package/app/composables/use-calendar.ts +0 -288
  149. package/app/composables/use-daisy-theme.ts +0 -140
  150. package/app/composables/use-toast.ts +0 -345
  151. package/app/composables/useSearch.ts +0 -22
  152. package/app/utils/drawer-utils.ts +0 -34
  153. package/app/utils/position-area.ts +0 -40
@@ -1,5 +0,0 @@
1
- <template>
2
- <div class="collapse-content">
3
- <slot />
4
- </div>
5
- </template>
@@ -1,15 +0,0 @@
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
-
8
- <template>
9
- <label v-if="hasToggle && checkboxId" :for="checkboxId" class="collapse-title">
10
- <slot />
11
- </label>
12
- <div v-else class="collapse-title">
13
- <slot />
14
- </div>
15
- </template>
@@ -1,15 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- const props = defineProps<{
5
- is?: any
6
- }>()
7
-
8
- const tag = computed(() => props.is || 'span')
9
- </script>
10
-
11
- <template>
12
- <component :is="tag" class="countdown">
13
- <slot />
14
- </component>
15
- </template>
@@ -1,69 +0,0 @@
1
- <script setup lang="ts">
2
- import { useIntervalFn } from '@vueuse/core'
3
- import { computed, ref, watch } from 'vue'
4
-
5
- const { durationInSeconds = 0, untilDate } = defineProps<{
6
- durationInSeconds?: number
7
- untilDate?: Date
8
- }>()
9
- const emit = defineEmits(['done'])
10
-
11
- function getTargetDate() {
12
- return untilDate || new Date(Date.now() + durationInSeconds * 1000)
13
- }
14
-
15
- const targetDate = ref(getTargetDate())
16
-
17
- watch(
18
- () => [durationInSeconds, untilDate],
19
- () => {
20
- targetDate.value = getTargetDate()
21
- },
22
- { immediate: true },
23
- )
24
-
25
- const timeLeft = ref(0)
26
- const calcTimeLeft = () => Math.max(0, targetDate.value.getTime() - Date.now())
27
-
28
- useIntervalFn(() => {
29
- timeLeft.value = calcTimeLeft()
30
- }, 1000)
31
-
32
- watch(timeLeft, val => {
33
- if (val === 0) {
34
- emit('done')
35
- }
36
- })
37
-
38
- const totalSeconds = computed(() => Math.round(timeLeft.value / 1000))
39
- const totalMinutes = computed(() => Math.floor(totalSeconds.value / 60))
40
- const totalHours = computed(() => Math.floor(totalMinutes.value / 60))
41
- const totalDays = computed(() => Math.floor(totalHours.value / 24))
42
- const totalWeeks = computed(() => Math.floor(totalDays.value / 7))
43
- const totalMonths = computed(() => {
44
- const now = new Date()
45
- return (targetDate.value.getFullYear() - now.getFullYear()) * 12 + (targetDate.value.getMonth() - now.getMonth())
46
- })
47
- const split = computed(() => {
48
- const days = totalDays.value
49
- const hours = totalHours.value - days * 24
50
- const minutes = totalMinutes.value - totalHours.value * 60
51
- const seconds = totalSeconds.value - totalMinutes.value * 60
52
- return { days, hours, minutes, seconds }
53
- })
54
- </script>
55
-
56
- <template>
57
- <slot
58
- v-bind="{
59
- totalSeconds,
60
- totalMinutes,
61
- totalHours,
62
- totalDays,
63
- totalWeeks,
64
- totalMonths,
65
- targetDate,
66
- split,
67
- }"
68
- />
69
- </template>
@@ -1,21 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- const props = defineProps<{
5
- value: number | string
6
- is?: any
7
- digits?: 2 | 3 | '2' | '3'
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
- })
17
- </script>
18
-
19
- <template>
20
- <component :is="props.is || 'span'" v-bind="$attrs" :style="style" />
21
- </template>
@@ -1,5 +0,0 @@
1
- <template>
2
- <li class="crumb">
3
- <slot />
4
- </li>
5
- </template>
@@ -1,56 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, resolveComponent } from 'vue'
3
-
4
- defineOptions({
5
- inheritAttrs: false,
6
- })
7
-
8
- const props = withDefaults(
9
- defineProps<{
10
- is?: string
11
- hover?: boolean
12
-
13
- color?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'success' | 'info' | 'warning' | 'error'
14
- neutral?: boolean
15
- primary?: boolean
16
- secondary?: boolean
17
- accent?: boolean
18
- success?: boolean
19
- info?: boolean
20
- warning?: boolean
21
- error?: boolean
22
- }>(),
23
- {
24
- is: 'a',
25
- },
26
- )
27
- const NuxtLink = resolveComponent('NuxtLink')
28
- const RouterLink = resolveComponent('RouterLink')
29
-
30
- const resolvedComponent = computed(() => {
31
- if (props.is === 'NuxtLink') return NuxtLink
32
- if (props.is === 'RouterLink') return RouterLink
33
- return props.is
34
- })
35
- </script>
36
-
37
- <template>
38
- <component
39
- :is="resolvedComponent"
40
- v-bind="$attrs"
41
- class="link"
42
- :class="{
43
- 'link-neutral': neutral || color === 'neutral',
44
- 'link-primary': primary || color === 'primary',
45
- 'link-secondary': secondary || color === 'secondary',
46
- 'link-accent': accent || color === 'accent',
47
- 'link-success': success || color === 'success',
48
- 'link-info': info || color === 'info',
49
- 'link-warning': warning || color === 'warning',
50
- 'link-error': error || color === 'error',
51
- 'link-hover': hover,
52
- }"
53
- >
54
- <slot />
55
- </component>
56
- </template>
@@ -1,11 +0,0 @@
1
- <template>
2
- <figure class="diff" tabindex="0">
3
- <div class="diff-item-1" role="img" tabindex="0">
4
- <slot name="one" />
5
- </div>
6
- <div class="diff-item-2" role="img">
7
- <slot name="two" />
8
- </div>
9
- <div class="diff-resizer" />
10
- </figure>
11
- </template>
@@ -1,43 +0,0 @@
1
- <script setup lang="ts">
2
- defineProps<{
3
- orientation?: 'horizontal' | 'vertical'
4
- horizontal?: boolean
5
- vertical?: boolean
6
- align?: 'center' | 'start' | 'end'
7
- center?: boolean
8
- start?: boolean
9
- end?: boolean
10
- color?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'info' | 'error'
11
- neutral?: boolean
12
- primary?: boolean
13
- secondary?: boolean
14
- accent?: boolean
15
- success?: boolean
16
- warning?: boolean
17
- info?: boolean
18
- error?: boolean
19
- }>()
20
- </script>
21
-
22
- <template>
23
- <div
24
- class="divider"
25
- :class="{
26
- 'divider-vertical': orientation === 'vertical' || vertical,
27
- 'divider-horizontal': orientation !== 'vertical' || horizontal,
28
- 'divider-neutral': color === 'neutral' || neutral,
29
- 'divider-primary': color === 'primary' || primary,
30
- 'divider-secondary': color === 'secondary' || secondary,
31
- 'divider-accent': color === 'accent' || accent,
32
- 'divider-success': color === 'success' || success,
33
- 'divider-warning': color === 'warning' || warning,
34
- 'divider-info': color === 'info' || info,
35
- 'divider-error': color === 'error' || error,
36
- 'divider-start': align === 'start' || start,
37
- 'divider-center': align === 'center' || center,
38
- 'divider-end': align === 'end' || end,
39
- }"
40
- >
41
- <slot />
42
- </div>
43
- </template>
@@ -1,57 +0,0 @@
1
- <script setup lang="ts">
2
- import type { Ref } from 'vue'
3
- import { provide, ref } from 'vue'
4
-
5
- const { size, xl, lg, md, sm, xs } = defineProps<{
6
- size?: string
7
- xl?: boolean
8
- lg?: boolean
9
- md?: boolean
10
- sm?: boolean
11
- xs?: boolean
12
- }>()
13
-
14
- const activeItemId = ref<string | null>(null)
15
- const itemIds = ref<string[]>([])
16
-
17
- function registerItem(itemId: string) {
18
- itemIds.value.push(itemId)
19
- return function unregister() {
20
- itemIds.value = itemIds.value.filter(id => id !== itemId)
21
- if (activeItemId.value === itemId) {
22
- activeItemId.value = null
23
- }
24
- }
25
- }
26
-
27
- function setActiveItemId(itemId: string) {
28
- activeItemId.value = itemId
29
- }
30
-
31
- export interface DockState {
32
- activeItemId: Ref<string | null>
33
- registerItem: (itemId: string) => () => void
34
- setActiveItemId: (itemId: string) => void
35
- }
36
-
37
- provide<DockState>('dockState', {
38
- activeItemId,
39
- registerItem,
40
- setActiveItemId,
41
- })
42
- </script>
43
-
44
- <template>
45
- <div
46
- class="dock"
47
- :class="{
48
- 'dock-xl': xl || size === 'xl',
49
- 'dock-lg': lg || size === 'lg',
50
- 'dock-md': md || size === 'md',
51
- 'dock-sm': sm || size === 'sm',
52
- 'dock-xs': xs || size === 'xs',
53
- }"
54
- >
55
- <slot />
56
- </div>
57
- </template>
@@ -1,27 +0,0 @@
1
- <script setup lang="ts">
2
- import type { DockState } from './Dock.vue'
3
- import { inject, onUnmounted, useId } from 'vue'
4
-
5
- const { active } = defineProps<{
6
- active?: boolean
7
- }>()
8
-
9
- const itemId = useId()
10
- const { registerItem, setActiveItemId, activeItemId } = inject<DockState>('dockState')!
11
- const unregister = registerItem(itemId)
12
-
13
- onUnmounted(() => {
14
- unregister()
15
- })
16
- </script>
17
-
18
- <template>
19
- <div
20
- :id="`dock-item-${itemId}`"
21
- class="dock-item"
22
- :class="{ 'dock-active': active || activeItemId === itemId }"
23
- @click="setActiveItemId(itemId)"
24
- >
25
- <slot />
26
- </div>
27
- </template>
@@ -1,5 +0,0 @@
1
- <template>
2
- <div class="dock-label">
3
- <slot />
4
- </div>
5
- </template>
@@ -1,50 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, watch } from 'vue'
3
- import { createDrawerState } from '../utils/drawer-utils'
4
-
5
- const props = withDefaults(
6
- defineProps<{
7
- open?: boolean
8
- name?: string
9
- end?: boolean
10
- }>(),
11
- {
12
- name: 'drawer',
13
- },
14
- )
15
- const emit = defineEmits(['update:open'])
16
-
17
- // sync `open` prop with drawerState.isDrawerOpen
18
- const drawerState = createDrawerState(props.name)
19
- watch(
20
- () => props.open,
21
- value => {
22
- if (drawerState.isDrawerOpen !== value) {
23
- drawerState.isDrawerOpen = value
24
- }
25
- },
26
- { immediate: true },
27
- )
28
- watch(
29
- () => drawerState.isDrawerOpen,
30
- value => {
31
- if (props.open !== value) {
32
- emit('update:open', value)
33
- }
34
- },
35
- { immediate: true },
36
- )
37
-
38
- const classes = computed(() => {
39
- return {
40
- 'drawer-end': props.end,
41
- }
42
- })
43
- </script>
44
-
45
- <template>
46
- <div class="drawer" :class="classes">
47
- <input :id="name" v-model="drawerState.isDrawerOpen" type="checkbox" class="drawer-toggle" />
48
- <slot v-bind="drawerState" />
49
- </div>
50
- </template>
@@ -1,20 +0,0 @@
1
- <script setup lang="ts">
2
- import { createDrawerState } from '../utils/drawer-utils'
3
-
4
- const props = withDefaults(
5
- defineProps<{
6
- name?: string
7
- }>(),
8
- {
9
- name: 'drawer',
10
- },
11
- )
12
-
13
- const drawerState = createDrawerState(props.name)
14
- </script>
15
-
16
- <template>
17
- <div class="drawer-content">
18
- <slot v-bind="drawerState" />
19
- </div>
20
- </template>
@@ -1,21 +0,0 @@
1
- <script setup lang="ts">
2
- import { createDrawerState } from '../utils/drawer-utils'
3
-
4
- const props = withDefaults(
5
- defineProps<{
6
- name?: string
7
- }>(),
8
- {
9
- name: 'drawer',
10
- },
11
- )
12
-
13
- const drawerState = createDrawerState(props.name)
14
- </script>
15
-
16
- <template>
17
- <div class="drawer-side">
18
- <div class="drawer-overlay" @click="() => drawerState?.closeDrawer()" />
19
- <slot v-bind="drawerState" />
20
- </div>
21
- </template>
@@ -1,106 +0,0 @@
1
- <script setup lang="ts">
2
- import { useId } from 'vue'
3
- import { useElementHover } from '@vueuse/core'
4
- import { onMounted, provide, ref, watch } from 'vue'
5
-
6
- const props = withDefaults(
7
- defineProps<{
8
- autoFocus?: boolean
9
-
10
- placement?:
11
- | 'top'
12
- | 'top-start'
13
- | 'top-end'
14
- | 'right'
15
- | 'right-start'
16
- | 'right-end'
17
- | 'bottom'
18
- | 'bottom-start'
19
- | 'bottom-end'
20
- | 'left'
21
- | 'left-start'
22
- | 'left-end'
23
-
24
- hover?: boolean
25
- delayEnter?: number
26
- delayLeave?: number
27
- closeOnClickOutside?: boolean
28
- }>(),
29
- {
30
- autoFocus: false,
31
- placement: 'bottom-start',
32
- hover: false,
33
- delayEnter: 0,
34
- delayLeave: 300,
35
- closeOnClickOutside: true,
36
- },
37
- )
38
-
39
- // Dropdown Visibility
40
- const isOpen = defineModel('open', { default: false })
41
- provide('isDropdownOpen', isOpen)
42
-
43
- const autoFocus = ref(props.autoFocus)
44
- provide('dropdownAutoFocus', autoFocus)
45
-
46
- // Use Nuxt's useId() for unique IDs
47
- const uniqueId = useId()
48
- const wrapperId = `dropdown-wrapper-${uniqueId}`
49
- const id = `dropdown-${uniqueId}`
50
- provide('dropdownId', id)
51
-
52
- // Provide placement for CSS anchor positioning
53
- provide('dropdownPlacement', ref(props.placement))
54
-
55
- // Provide closeOnClickOutside for popover mode selection
56
- provide('dropdownCloseOnClickOutside', ref(props.closeOnClickOutside))
57
-
58
- // Provide hover mode for button behavior
59
- provide('dropdownHover', ref(props.hover))
60
-
61
- // References
62
- const buttonEl = ref(null)
63
- const contentEl = ref(null)
64
-
65
- provide('buttonEl', buttonEl)
66
- provide('contentEl', contentEl)
67
-
68
- // Visibility Utils
69
- function toggle() {
70
- isOpen.value = !isOpen.value
71
- }
72
- function open() {
73
- isOpen.value = true
74
- }
75
- function close() {
76
- isOpen.value = false
77
- }
78
- provide('toggleDropdown', toggle)
79
- provide('openDropdown', open)
80
- provide('closeDropdown', close)
81
-
82
- const dropdownWrapper = ref(null)
83
-
84
- onMounted(() => {
85
- // Note: closeOnClickOutside is handled automatically by popover="auto"
86
- // The popover API provides "light dismiss" behavior by default
87
-
88
- // Sync with hover state for SSR compatibility
89
- if (props.hover) {
90
- const hover = useElementHover(dropdownWrapper, {
91
- delayLeave: props.delayLeave,
92
- delayEnter: props.delayEnter,
93
- })
94
-
95
- watch(hover, newValue => {
96
- isOpen.value = newValue
97
- })
98
- }
99
- })
100
- </script>
101
-
102
- <template>
103
- <div :id="wrapperId" ref="dropdownWrapper" class="relative inline-block">
104
- <slot v-bind="{ toggle, open, close }" />
105
- </div>
106
- </template>
@@ -1,23 +0,0 @@
1
- <script setup>
2
- import { inject } from 'vue'
3
-
4
- const id = inject('dropdownId')
5
- const isOpen = inject('isDropdownOpen')
6
- const buttonEl = inject('buttonEl')
7
- const isHover = inject('dropdownHover')
8
- </script>
9
-
10
- <template>
11
- <Button
12
- :id="id"
13
- ref="buttonEl"
14
- :aria-expanded="isOpen"
15
- aria-haspopup="menu"
16
- :popovertarget="`${id}-content`"
17
- :popovertargetaction="isHover ? 'show' : undefined"
18
- :style="{ 'anchor-name': `--${id}` }"
19
- class="dropdown-button"
20
- >
21
- <slot />
22
- </Button>
23
- </template>
@@ -1,127 +0,0 @@
1
- <script setup>
2
- import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
3
- import { computed, inject, nextTick, watch, watchEffect } from 'vue'
4
- import { getPositionArea, getPositionFallbacks } from '../utils/position-area'
5
-
6
- const autoFocus = inject('dropdownAutoFocus')
7
- const id = inject('dropdownId')
8
- const isOpen = inject('isDropdownOpen')
9
- const contentEl = inject('contentEl')
10
- const placement = inject('dropdownPlacement')
11
- const closeOnClickOutside = inject('dropdownCloseOnClickOutside')
12
-
13
- // Dropdown Utils
14
- const toggle = inject('toggleDropdown')
15
- const open = inject('openDropdown')
16
- const close = inject('closeDropdown')
17
-
18
- // Compute CSS position-area value based on placement
19
- const positionArea = computed(() => getPositionArea(placement.value))
20
- const positionFallbacks = computed(() => getPositionFallbacks(placement.value))
21
-
22
- // Determine popover mode: "auto" for light dismiss, "manual" to disable it
23
- const popoverMode = computed(() => (closeOnClickOutside.value ? 'auto' : 'manual'))
24
-
25
- let activate
26
- let deactivate
27
-
28
- if (autoFocus.value) {
29
- const { activate: _activate, deactivate: _deactivate, hasFocus } = useFocusTrap(contentEl, { immediate: true })
30
- activate = _activate
31
- deactivate = _deactivate
32
-
33
- // hide the dropdown when the focus-trap drops focus (by pressing escape, for example)
34
- watchEffect(() => {
35
- if (!hasFocus.value) {
36
- close()
37
- }
38
- })
39
- }
40
-
41
- // Sync popover state with isOpen model (for programmatic control)
42
- watch(
43
- isOpen,
44
- async newValue => {
45
- if (contentEl.value) {
46
- try {
47
- // Check current popover state
48
- const isPopoverOpen = contentEl.value.matches(':popover-open')
49
-
50
- // Only programmatically control if state differs
51
- if (newValue && !isPopoverOpen) {
52
- contentEl.value.showPopover()
53
- if (autoFocus.value) {
54
- await nextTick()
55
- activate?.()
56
- }
57
- } else if (!newValue && isPopoverOpen) {
58
- contentEl.value.hidePopover()
59
- if (autoFocus.value) {
60
- deactivate?.()
61
- await nextTick()
62
- }
63
- }
64
- } catch (e) {
65
- // Silently handle if popover API is not supported
66
- console.warn('Popover API not supported:', e)
67
- }
68
- }
69
- },
70
- { flush: 'post' },
71
- )
72
-
73
- // Listen to popover toggle events to sync back to isOpen model
74
- function handleToggle(event) {
75
- const newState = event.newState === 'open'
76
-
77
- if (isOpen.value !== newState) {
78
- isOpen.value = newState
79
-
80
- if (newState && autoFocus.value) {
81
- nextTick().then(() => activate?.())
82
- } else if (!newState && autoFocus.value) {
83
- deactivate?.()
84
- }
85
- }
86
- }
87
- </script>
88
-
89
- <template>
90
- <div
91
- :id="`${id}-content`"
92
- ref="contentEl"
93
- :anchor="id"
94
- :aria-labelledby="id"
95
- role="menu"
96
- :popover="popoverMode"
97
- class="dropdown-content dropdown-popover"
98
- :style="{
99
- 'position-anchor': `--${id}`,
100
- 'position-area': positionArea,
101
- 'position-try-fallbacks': positionFallbacks,
102
- }"
103
- @toggle="handleToggle"
104
- >
105
- <slot v-bind="{ toggle, open, close }" />
106
- </div>
107
- </template>
108
-
109
- <style>
110
- @layer components {
111
- /* Reset default popover styles - in components layer so utilities can override */
112
- .dropdown-popover[popover] {
113
- border: none;
114
- color: inherit;
115
- overflow: visible;
116
- /* Use auto for inset to allow anchor positioning to work */
117
- inset: auto;
118
- margin: 0;
119
- background-color: transparent;
120
- }
121
-
122
- /* Position anchoring support */
123
- .dropdown-popover[popover]:popover-open {
124
- position: fixed;
125
- }
126
- }
127
- </style>