daisy-ui-kit 5.0.0-pre.13 → 5.0.0-pre.15

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.
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { computed, resolveComponent } from 'vue'
3
3
 
4
4
  const { is = 'div', ...props } = defineProps<{
5
5
  is?: string
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { computed, resolveComponent } from 'vue'
3
3
 
4
4
  const props = withDefaults(
5
5
  defineProps<{
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { computed, resolveComponent } from 'vue'
3
3
 
4
4
  const { is = 'div', ...props } = defineProps<{
5
5
  is?: string
@@ -1,8 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
3
-
4
- const NuxtLink = resolveComponent('NuxtLink')
5
- const RouterLink = resolveComponent('RouterLink')
2
+ import { computed, resolveComponent } from 'vue'
6
3
 
7
4
  const props = withDefaults(
8
5
  defineProps<{
@@ -23,6 +20,8 @@ const props = withDefaults(
23
20
  is: 'a',
24
21
  },
25
22
  )
23
+ const NuxtLink = resolveComponent('NuxtLink')
24
+ const RouterLink = resolveComponent('RouterLink')
26
25
 
27
26
  const resolvedComponent = computed(() => {
28
27
  if (props.is === 'NuxtLink') return NuxtLink
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed, inject } from 'vue'
2
+ import { computed, inject, resolveComponent } from 'vue'
3
3
 
4
4
  const {
5
5
  is = 'label',
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { computed, resolveComponent } from 'vue'
3
3
 
4
4
  const props = defineProps<{
5
5
  is?: string
@@ -1,28 +1,112 @@
1
1
  <script setup lang="ts">
2
- const props = defineProps<{
3
- tip?: string | number
4
- open?: boolean
5
-
6
- color?: string
7
- neutral?: boolean
8
- primary?: boolean
9
- secondary?: boolean
10
- accent?: boolean
11
- info?: boolean
12
- success?: boolean
13
- warning?: boolean
14
- error?: boolean
15
-
16
- position?: 'top' | 'right' | 'bottom' | 'left'
17
- top?: boolean
18
- right?: boolean
19
- bottom?: boolean
20
- left?: boolean
21
- }>()
2
+ import { useId } from '#imports'
3
+ import { useElementHover } from '@vueuse/core'
4
+ import { computed, onMounted, provide, ref, watch } from 'vue'
5
+
6
+ const props = withDefaults(
7
+ defineProps<{
8
+ tip?: string | number
9
+ open?: boolean
10
+
11
+ color?: string
12
+ neutral?: boolean
13
+ primary?: boolean
14
+ secondary?: boolean
15
+ accent?: boolean
16
+ info?: boolean
17
+ success?: boolean
18
+ warning?: boolean
19
+ error?: boolean
20
+
21
+ position?: 'top' | 'right' | 'bottom' | 'left'
22
+ top?: boolean
23
+ right?: boolean
24
+ bottom?: boolean
25
+ left?: boolean
26
+
27
+ // Popover mode props
28
+ delayEnter?: number
29
+ delayLeave?: number
30
+ }>(),
31
+ {
32
+ delayEnter: 200,
33
+ delayLeave: 100,
34
+ },
35
+ )
36
+
37
+ // Detect if using popover mode (when TooltipTarget/TooltipContent are used)
38
+ const isPopoverMode = computed(() => {
39
+ return !props.tip
40
+ })
41
+
42
+ // Popover mode setup
43
+ const isOpen = defineModel('open', { default: false })
44
+ provide('isTooltipOpen', isOpen)
45
+
46
+ const uniqueId = useId()
47
+ const id = `tooltip-${uniqueId}`
48
+ provide('tooltipId', id)
49
+
50
+ // Compute placement for CSS anchor positioning
51
+ const placement = computed(() => {
52
+ if (props.top || props.position === 'top') return 'top'
53
+ if (props.right || props.position === 'right') return 'right'
54
+ if (props.left || props.position === 'left') return 'left'
55
+ return 'bottom' // default
56
+ })
57
+ provide('tooltipPlacement', placement)
58
+
59
+ // Provide color for TooltipContent
60
+ const color = computed(() => {
61
+ if (props.color) return props.color
62
+ if (props.neutral) return 'neutral'
63
+ if (props.primary) return 'primary'
64
+ if (props.secondary) return 'secondary'
65
+ if (props.accent) return 'accent'
66
+ if (props.info) return 'info'
67
+ if (props.success) return 'success'
68
+ if (props.warning) return 'warning'
69
+ if (props.error) return 'error'
70
+ return null
71
+ })
72
+ provide('tooltipColor', color)
73
+
74
+ // References
75
+ const targetEl = ref(null)
76
+ const contentEl = ref(null)
77
+ provide('targetEl', targetEl)
78
+ provide('contentEl', contentEl)
79
+
80
+ // Visibility utils
81
+ function open() {
82
+ isOpen.value = true
83
+ }
84
+ function close() {
85
+ isOpen.value = false
86
+ }
87
+ provide('openTooltip', open)
88
+ provide('closeTooltip', close)
89
+
90
+ const tooltipWrapper = ref(null)
91
+
92
+ onMounted(() => {
93
+ if (isPopoverMode.value) {
94
+ const hover = useElementHover(tooltipWrapper, {
95
+ delayLeave: props.delayLeave,
96
+ delayEnter: props.delayEnter,
97
+ })
98
+
99
+ watch(hover, newValue => {
100
+ isOpen.value = newValue
101
+ })
102
+ }
103
+ })
22
104
  </script>
23
105
 
24
106
  <template>
107
+ <!-- CSS-only mode (when tip prop is provided) -->
25
108
  <div
109
+ v-if="!isPopoverMode"
26
110
  :data-tip="tip"
27
111
  class="tooltip"
28
112
  :class="{
@@ -45,4 +129,9 @@ const props = defineProps<{
45
129
  >
46
130
  <slot />
47
131
  </div>
132
+
133
+ <!-- Popover API mode (when using TooltipTarget/TooltipContent) -->
134
+ <div v-else ref="tooltipWrapper" class="tooltip-wrapper inline-block">
135
+ <slot />
136
+ </div>
48
137
  </template>
@@ -1,5 +1,283 @@
1
+ <script setup>
2
+ import { computed, inject, ref, watch } from 'vue'
3
+ import { getPositionArea, getPositionFallbacks } from '../utils/position-area'
4
+
5
+ const id = inject('tooltipId', null)
6
+ const isOpen = inject('isTooltipOpen', ref(false))
7
+ const contentEl = inject('contentEl', ref(null))
8
+ const placement = inject('tooltipPlacement', ref('bottom'))
9
+ const color = inject('tooltipColor', ref(null))
10
+
11
+ // Check if we're in popover mode (inside a Tooltip wrapper with context)
12
+ const isPopoverMode = computed(() => id !== null)
13
+
14
+ // Compute CSS position-area value based on placement
15
+ const positionArea = computed(() => getPositionArea(placement.value))
16
+ const positionFallbacks = computed(() => getPositionFallbacks(placement.value))
17
+
18
+ // Color classes for the tooltip
19
+ const colorClass = computed(() => {
20
+ if (!color.value) return ''
21
+ const colorMap = {
22
+ neutral: 'tooltip-neutral',
23
+ primary: 'tooltip-primary',
24
+ secondary: 'tooltip-secondary',
25
+ accent: 'tooltip-accent',
26
+ info: 'tooltip-info',
27
+ success: 'tooltip-success',
28
+ warning: 'tooltip-warning',
29
+ error: 'tooltip-error',
30
+ }
31
+ return colorMap[color.value] || ''
32
+ })
33
+
34
+ // Sync popover state with isOpen model
35
+ watch(
36
+ isOpen,
37
+ newValue => {
38
+ if (!isPopoverMode.value || !contentEl.value) return
39
+
40
+ try {
41
+ const isPopoverOpen = contentEl.value.matches(':popover-open')
42
+
43
+ if (newValue && !isPopoverOpen) {
44
+ contentEl.value.showPopover()
45
+ } else if (!newValue && isPopoverOpen) {
46
+ contentEl.value.hidePopover()
47
+ }
48
+ } catch (e) {
49
+ console.warn('Popover API not supported:', e)
50
+ }
51
+ },
52
+ { flush: 'post' },
53
+ )
54
+
55
+ // Listen to popover toggle events to sync back to isOpen model
56
+ function handleToggle(event) {
57
+ const newState = event.newState === 'open'
58
+ if (isOpen.value !== newState) {
59
+ isOpen.value = newState
60
+ }
61
+ }
62
+ </script>
63
+
1
64
  <template>
2
- <div class="tooltip-content">
65
+ <!-- Popover mode -->
66
+ <div
67
+ v-if="isPopoverMode"
68
+ :id="`${id}-content`"
69
+ ref="contentEl"
70
+ :anchor="id"
71
+ :data-placement="placement"
72
+ role="tooltip"
73
+ popover="manual"
74
+ class="tooltip-popover"
75
+ :class="colorClass"
76
+ :style="{
77
+ 'position-anchor': `--${id}`,
78
+ 'position-area': positionArea,
79
+ 'position-try-fallbacks': positionFallbacks,
80
+ }"
81
+ @toggle="handleToggle"
82
+ >
83
+ <slot />
84
+ </div>
85
+
86
+ <!-- Simple mode (no Tooltip wrapper context) -->
87
+ <div v-else class="tooltip-content">
3
88
  <slot />
4
89
  </div>
5
90
  </template>
91
+
92
+ <style>
93
+ @layer components {
94
+ .tooltip-popover[popover] {
95
+ border: none;
96
+ overflow: visible;
97
+ inset: auto;
98
+ margin: 0;
99
+ padding: 0.25rem 0.5rem;
100
+ font-size: 0.875rem;
101
+ line-height: 1.25rem;
102
+ border-radius: var(--radius-selector, 0.25rem);
103
+ background-color: var(--color-neutral);
104
+ color: var(--color-neutral-content);
105
+ max-width: 20rem;
106
+ }
107
+
108
+ .tooltip-popover[popover]:popover-open {
109
+ position: fixed;
110
+ }
111
+
112
+ /* Arrow base styles */
113
+ .tooltip-popover[popover]::before {
114
+ content: '';
115
+ position: absolute;
116
+ border: 6px solid transparent;
117
+ }
118
+
119
+ /* Bottom placement - arrow points up */
120
+ .tooltip-popover[data-placement='bottom'] {
121
+ margin-top: 6px;
122
+ }
123
+ .tooltip-popover[data-placement='bottom']::before {
124
+ bottom: 100%;
125
+ left: 50%;
126
+ transform: translateX(-50%);
127
+ border-bottom-color: var(--color-neutral);
128
+ }
129
+
130
+ /* Top placement - arrow points down */
131
+ .tooltip-popover[data-placement='top'] {
132
+ margin-bottom: 6px;
133
+ }
134
+ .tooltip-popover[data-placement='top']::before {
135
+ top: 100%;
136
+ left: 50%;
137
+ transform: translateX(-50%);
138
+ border-top-color: var(--color-neutral);
139
+ }
140
+
141
+ /* Right placement - arrow points left */
142
+ .tooltip-popover[data-placement='right'] {
143
+ margin-left: 6px;
144
+ }
145
+ .tooltip-popover[data-placement='right']::before {
146
+ right: 100%;
147
+ top: 50%;
148
+ transform: translateY(-50%);
149
+ border-right-color: var(--color-neutral);
150
+ }
151
+
152
+ /* Left placement - arrow points right */
153
+ .tooltip-popover[data-placement='left'] {
154
+ margin-right: 6px;
155
+ }
156
+ .tooltip-popover[data-placement='left']::before {
157
+ left: 100%;
158
+ top: 50%;
159
+ transform: translateY(-50%);
160
+ border-left-color: var(--color-neutral);
161
+ }
162
+
163
+ /* Color variants */
164
+ .tooltip-popover.tooltip-primary {
165
+ background-color: var(--color-primary);
166
+ color: var(--color-primary-content);
167
+ }
168
+ .tooltip-popover.tooltip-primary[data-placement='bottom']::before {
169
+ border-bottom-color: var(--color-primary);
170
+ }
171
+ .tooltip-popover.tooltip-primary[data-placement='top']::before {
172
+ border-top-color: var(--color-primary);
173
+ }
174
+ .tooltip-popover.tooltip-primary[data-placement='right']::before {
175
+ border-right-color: var(--color-primary);
176
+ }
177
+ .tooltip-popover.tooltip-primary[data-placement='left']::before {
178
+ border-left-color: var(--color-primary);
179
+ }
180
+
181
+ .tooltip-popover.tooltip-secondary {
182
+ background-color: var(--color-secondary);
183
+ color: var(--color-secondary-content);
184
+ }
185
+ .tooltip-popover.tooltip-secondary[data-placement='bottom']::before {
186
+ border-bottom-color: var(--color-secondary);
187
+ }
188
+ .tooltip-popover.tooltip-secondary[data-placement='top']::before {
189
+ border-top-color: var(--color-secondary);
190
+ }
191
+ .tooltip-popover.tooltip-secondary[data-placement='right']::before {
192
+ border-right-color: var(--color-secondary);
193
+ }
194
+ .tooltip-popover.tooltip-secondary[data-placement='left']::before {
195
+ border-left-color: var(--color-secondary);
196
+ }
197
+
198
+ .tooltip-popover.tooltip-accent {
199
+ background-color: var(--color-accent);
200
+ color: var(--color-accent-content);
201
+ }
202
+ .tooltip-popover.tooltip-accent[data-placement='bottom']::before {
203
+ border-bottom-color: var(--color-accent);
204
+ }
205
+ .tooltip-popover.tooltip-accent[data-placement='top']::before {
206
+ border-top-color: var(--color-accent);
207
+ }
208
+ .tooltip-popover.tooltip-accent[data-placement='right']::before {
209
+ border-right-color: var(--color-accent);
210
+ }
211
+ .tooltip-popover.tooltip-accent[data-placement='left']::before {
212
+ border-left-color: var(--color-accent);
213
+ }
214
+
215
+ .tooltip-popover.tooltip-info {
216
+ background-color: var(--color-info);
217
+ color: var(--color-info-content);
218
+ }
219
+ .tooltip-popover.tooltip-info[data-placement='bottom']::before {
220
+ border-bottom-color: var(--color-info);
221
+ }
222
+ .tooltip-popover.tooltip-info[data-placement='top']::before {
223
+ border-top-color: var(--color-info);
224
+ }
225
+ .tooltip-popover.tooltip-info[data-placement='right']::before {
226
+ border-right-color: var(--color-info);
227
+ }
228
+ .tooltip-popover.tooltip-info[data-placement='left']::before {
229
+ border-left-color: var(--color-info);
230
+ }
231
+
232
+ .tooltip-popover.tooltip-success {
233
+ background-color: var(--color-success);
234
+ color: var(--color-success-content);
235
+ }
236
+ .tooltip-popover.tooltip-success[data-placement='bottom']::before {
237
+ border-bottom-color: var(--color-success);
238
+ }
239
+ .tooltip-popover.tooltip-success[data-placement='top']::before {
240
+ border-top-color: var(--color-success);
241
+ }
242
+ .tooltip-popover.tooltip-success[data-placement='right']::before {
243
+ border-right-color: var(--color-success);
244
+ }
245
+ .tooltip-popover.tooltip-success[data-placement='left']::before {
246
+ border-left-color: var(--color-success);
247
+ }
248
+
249
+ .tooltip-popover.tooltip-warning {
250
+ background-color: var(--color-warning);
251
+ color: var(--color-warning-content);
252
+ }
253
+ .tooltip-popover.tooltip-warning[data-placement='bottom']::before {
254
+ border-bottom-color: var(--color-warning);
255
+ }
256
+ .tooltip-popover.tooltip-warning[data-placement='top']::before {
257
+ border-top-color: var(--color-warning);
258
+ }
259
+ .tooltip-popover.tooltip-warning[data-placement='right']::before {
260
+ border-right-color: var(--color-warning);
261
+ }
262
+ .tooltip-popover.tooltip-warning[data-placement='left']::before {
263
+ border-left-color: var(--color-warning);
264
+ }
265
+
266
+ .tooltip-popover.tooltip-error {
267
+ background-color: var(--color-error);
268
+ color: var(--color-error-content);
269
+ }
270
+ .tooltip-popover.tooltip-error[data-placement='bottom']::before {
271
+ border-bottom-color: var(--color-error);
272
+ }
273
+ .tooltip-popover.tooltip-error[data-placement='top']::before {
274
+ border-top-color: var(--color-error);
275
+ }
276
+ .tooltip-popover.tooltip-error[data-placement='right']::before {
277
+ border-right-color: var(--color-error);
278
+ }
279
+ .tooltip-popover.tooltip-error[data-placement='left']::before {
280
+ border-left-color: var(--color-error);
281
+ }
282
+ }
283
+ </style>
@@ -0,0 +1,20 @@
1
+ <script setup>
2
+ import { inject } from 'vue'
3
+
4
+ const id = inject('tooltipId')
5
+ const targetEl = inject('targetEl')
6
+ </script>
7
+
8
+ <template>
9
+ <div
10
+ :id="id"
11
+ ref="targetEl"
12
+ :aria-describedby="`${id}-content`"
13
+ :popovertarget="`${id}-content`"
14
+ popovertargetaction="toggle"
15
+ :style="{ 'anchor-name': `--${id}` }"
16
+ class="tooltip-target inline-block"
17
+ >
18
+ <slot />
19
+ </div>
20
+ </template>
@@ -8,7 +8,7 @@
8
8
  export function getPositionArea(placement: string): string {
9
9
  const positionMap: Record<string, string> = {
10
10
  // Top positions
11
- top: 'top', // centered above
11
+ top: 'center top', // centered above
12
12
  'top-start': 'top span-right', // above, left edge aligned
13
13
  'top-end': 'top span-left', // above, right edge aligned
14
14
 
@@ -34,8 +34,7 @@ export function getPositionArea(placement: string): string {
34
34
  /**
35
35
  * Gets position-try-fallbacks for automatic repositioning
36
36
  */
37
- export function getPositionFallbacks(placement: string): string {
38
- // Use flip-block and flip-inline to automatically flip positions
39
- // when there's not enough room in the preferred direction
37
+ export function getPositionFallbacks(_placement: string): string {
38
+ // Simple flip fallbacks - flip to opposite side on same axis
40
39
  return 'flip-block, flip-inline'
41
40
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "daisy-ui-kit",
3
3
  "type": "module",
4
- "version": "5.0.0-pre.13",
5
- "author": "feathers.dev",
4
+ "version": "5.0.0-pre.15",
6
5
  "packageManager": "pnpm@10.10.0",
6
+ "author": "feathers.dev",
7
7
  "exports": {
8
8
  ".": {
9
9
  "import": "./nuxt.js",