daisy-ui-kit 5.0.0-pre.3 → 5.0.0-pre.31

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 (151) hide show
  1. package/app/components/Accordion.vue +29 -0
  2. package/app/components/Alert.vue +36 -0
  3. package/app/components/Avatar.vue +131 -0
  4. package/app/components/AvatarGroup.vue +22 -0
  5. package/app/components/Badge.vue +72 -0
  6. package/app/components/Breadcrumbs.vue +7 -0
  7. package/app/components/Button.vue +140 -0
  8. package/app/components/Calendar.vue +175 -0
  9. package/app/components/CalendarInput.vue +275 -0
  10. package/app/components/CalendarSkeleton.vue +87 -0
  11. package/app/components/Card.vue +51 -0
  12. package/app/components/CardActions.vue +13 -0
  13. package/app/components/CardBody.vue +13 -0
  14. package/app/components/CardTitle.vue +11 -0
  15. package/app/components/Carousel.vue +24 -0
  16. package/app/components/CarouselItem.vue +5 -0
  17. package/app/components/Chat.vue +26 -0
  18. package/app/components/ChatBubble.vue +31 -0
  19. package/app/components/ChatFooter.vue +5 -0
  20. package/app/components/ChatHeader.vue +5 -0
  21. package/app/components/ChatImage.vue +5 -0
  22. package/app/components/Checkbox.vue +51 -0
  23. package/app/components/Collapse.vue +76 -0
  24. package/app/components/CollapseContent.vue +5 -0
  25. package/app/components/CollapseTitle.vue +15 -0
  26. package/app/components/Countdown.vue +15 -0
  27. package/app/components/CountdownTimers.vue +69 -0
  28. package/app/components/Counter.vue +21 -0
  29. package/app/components/Crumb.vue +5 -0
  30. package/app/components/DaisyLink.vue +56 -0
  31. package/app/components/Diff.vue +11 -0
  32. package/app/components/Divider.vue +43 -0
  33. package/app/components/Dock.vue +57 -0
  34. package/app/components/DockItem.vue +27 -0
  35. package/app/components/DockLabel.vue +5 -0
  36. package/app/components/Drawer.vue +50 -0
  37. package/app/components/DrawerContent.vue +20 -0
  38. package/app/components/DrawerSide.vue +21 -0
  39. package/app/components/Dropdown.vue +106 -0
  40. package/app/components/DropdownButton.vue +23 -0
  41. package/app/components/DropdownContent.vue +127 -0
  42. package/app/components/DropdownTarget.vue +21 -0
  43. package/app/components/Fab.vue +16 -0
  44. package/app/components/FabClose.vue +18 -0
  45. package/app/components/FabMainAction.vue +5 -0
  46. package/app/components/FabTrigger.vue +117 -0
  47. package/app/components/Fieldset.vue +20 -0
  48. package/app/components/FileInput.vue +53 -0
  49. package/app/components/Filter.vue +129 -0
  50. package/app/components/Flex.vue +89 -0
  51. package/app/components/FlexItem.vue +62 -0
  52. package/app/components/Footer.vue +31 -0
  53. package/app/components/FooterTitle.vue +18 -0
  54. package/app/components/FormControl.vue +5 -0
  55. package/app/components/Hero.vue +18 -0
  56. package/app/components/HeroContent.vue +18 -0
  57. package/app/components/HeroOverlay.vue +5 -0
  58. package/app/components/Hover3D.vue +22 -0
  59. package/app/components/HoverGallery.vue +11 -0
  60. package/app/components/Indicator.vue +20 -0
  61. package/app/components/IndicatorItem.vue +43 -0
  62. package/app/components/Input.vue +116 -0
  63. package/app/components/Join.vue +5 -0
  64. package/app/components/Kbd.vue +25 -0
  65. package/app/components/Label.vue +100 -0
  66. package/app/components/List.vue +5 -0
  67. package/app/components/ListColGrow.vue +5 -0
  68. package/app/components/ListColWrap.vue +5 -0
  69. package/app/components/ListRow.vue +5 -0
  70. package/app/components/LoadingBall.vue +42 -0
  71. package/app/components/LoadingBars.vue +42 -0
  72. package/app/components/LoadingDots.vue +42 -0
  73. package/app/components/LoadingInfinity.vue +42 -0
  74. package/app/components/LoadingRing.vue +42 -0
  75. package/app/components/LoadingSpinner.vue +42 -0
  76. package/app/components/Mask.vue +49 -0
  77. package/app/components/Menu.vue +30 -0
  78. package/app/components/MenuExpand.vue +92 -0
  79. package/app/components/MenuExpandToggle.vue +20 -0
  80. package/app/components/MenuItem.vue +39 -0
  81. package/app/components/MenuTitle.vue +5 -0
  82. package/app/components/MockupBrowser.vue +5 -0
  83. package/app/components/MockupBrowserToolbar.vue +5 -0
  84. package/app/components/MockupCode.vue +4 -0
  85. package/app/components/MockupPhone.vue +14 -0
  86. package/app/components/MockupWindow.vue +5 -0
  87. package/app/components/Modal.vue +63 -0
  88. package/app/components/ModalAction.vue +5 -0
  89. package/app/components/ModalBox.vue +5 -0
  90. package/app/components/NavButton.vue +12 -0
  91. package/app/components/Navbar.vue +12 -0
  92. package/app/components/NavbarCenter.vue +11 -0
  93. package/app/components/NavbarEnd.vue +11 -0
  94. package/app/components/NavbarStart.vue +11 -0
  95. package/app/components/Progress.vue +46 -0
  96. package/app/components/Prose.vue +37 -0
  97. package/app/components/RadialProgress.vue +36 -0
  98. package/app/components/Radio.vue +69 -0
  99. package/app/components/RadioGroup.vue +47 -0
  100. package/app/components/Range.vue +201 -0
  101. package/app/components/RangeMeasure.vue +87 -0
  102. package/app/components/RangeMeasureTick.vue +69 -0
  103. package/app/components/Rating.vue +197 -0
  104. package/app/components/Select.vue +101 -0
  105. package/app/components/Skeleton.vue +5 -0
  106. package/app/components/SkeletonText.vue +11 -0
  107. package/app/components/Stack.vue +30 -0
  108. package/app/components/Stat.vue +19 -0
  109. package/app/components/StatActions.vue +5 -0
  110. package/app/components/StatDesc.vue +5 -0
  111. package/app/components/StatFigure.vue +5 -0
  112. package/app/components/StatTitle.vue +5 -0
  113. package/app/components/StatValue.vue +5 -0
  114. package/app/components/Stats.vue +5 -0
  115. package/app/components/Status.vue +43 -0
  116. package/app/components/Step.vue +34 -0
  117. package/app/components/StepIcon.vue +5 -0
  118. package/app/components/Steps.vue +23 -0
  119. package/app/components/Swap.vue +56 -0
  120. package/app/components/Tab.vue +56 -0
  121. package/app/components/TabContent.vue +29 -0
  122. package/app/components/Table.vue +32 -0
  123. package/app/components/Tabs.vue +53 -0
  124. package/app/components/Text.vue +166 -0
  125. package/app/components/TextArea.vue +106 -0
  126. package/app/components/TextRotate.vue +24 -0
  127. package/app/components/ThemeController.vue +45 -0
  128. package/app/components/ThemeProvider.vue +302 -0
  129. package/app/components/ThemeTile.vue +50 -0
  130. package/app/components/Timeline.vue +22 -0
  131. package/app/components/TimelineEnd.vue +14 -0
  132. package/app/components/TimelineItem.vue +5 -0
  133. package/app/components/TimelineLine.vue +29 -0
  134. package/app/components/TimelineMiddle.vue +5 -0
  135. package/app/components/TimelineStart.vue +14 -0
  136. package/app/components/Toast.vue +67 -0
  137. package/app/components/Toggle.vue +60 -0
  138. package/app/components/Tooltip.vue +137 -0
  139. package/app/components/TooltipContent.vue +283 -0
  140. package/app/components/TooltipTarget.vue +20 -0
  141. package/app/components/ValidatorHint.vue +5 -0
  142. package/app/composables/__tests__/use-calendar.test.ts +239 -0
  143. package/app/composables/use-calendar.ts +288 -0
  144. package/app/composables/use-daisy-theme.ts +140 -0
  145. package/app/composables/use-toast.ts +345 -0
  146. package/app/composables/useSearch.ts +22 -0
  147. package/app/utils/drawer-utils.ts +34 -0
  148. package/app/utils/position-area.ts +40 -0
  149. package/nuxt.d.ts +13 -0
  150. package/nuxt.js +31 -0
  151. package/package.json +50 -22
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ is?: any
6
+ center?: boolean
7
+ duration?: number
8
+ }>()
9
+
10
+ const style = computed(() => {
11
+ if (props.duration) {
12
+ return { animationDuration: `${props.duration}ms` }
13
+ }
14
+ return undefined
15
+ })
16
+ </script>
17
+
18
+ <template>
19
+ <component :is="props.is || 'span'" class="text-rotate" :style="style">
20
+ <span :class="{ 'justify-items-center': props.center }">
21
+ <slot />
22
+ </span>
23
+ </component>
24
+ </template>
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ import type { DaisyThemeInput } from '@/composables/use-daisy-theme'
3
+ import { useDaisyTheme } from '@/composables/use-daisy-theme'
4
+ import { computed } from 'vue'
5
+
6
+ const props = defineProps<{
7
+ /**
8
+ * Optional: List of themes to provide (string or DaisyThemeMeta)
9
+ */
10
+ themes?: DaisyThemeInput[]
11
+ /**
12
+ * Optional: Default theme name (string or 'default')
13
+ */
14
+ defaultTheme?: string
15
+ /**
16
+ * Optional: Storage function for persistence (e.g., useCookie, useLocalStorage, or ref)
17
+ */
18
+ storage?: <T>(key: string, initial: T) => import('vue').Ref<T>
19
+ }>()
20
+
21
+ const themeOptions =
22
+ props.themes || props.defaultTheme ? { themes: props.themes || [], defaultTheme: props.defaultTheme } : undefined
23
+
24
+ const { theme, effectiveTheme, themes, setTheme, cycleTheme, registerTheme, removeTheme } = useDaisyTheme(
25
+ props.storage,
26
+ themeOptions,
27
+ )
28
+
29
+ const availableThemes = computed(() => themes.value.map(t => (typeof t === 'string' ? t : t.theme)))
30
+ </script>
31
+
32
+ <template>
33
+ <div class="theme-controller">
34
+ <slot
35
+ :theme="theme"
36
+ :effective-theme="effectiveTheme"
37
+ :themes="themes"
38
+ :available-themes="availableThemes"
39
+ :set-theme="setTheme"
40
+ :cycle-theme="cycleTheme"
41
+ :register-theme="registerTheme"
42
+ :remove-theme="removeTheme"
43
+ />
44
+ </div>
45
+ </template>
@@ -0,0 +1,302 @@
1
+ <script setup lang="ts">
2
+ import type { ComputedThemeVarsSlot } from './ThemeProvider.inject.js'
3
+ import { computed, nextTick, onUnmounted, provide, ref, watch } from 'vue'
4
+ import { daisyUiThemeKey } from './ThemeProvider.inject.js'
5
+
6
+ const props = defineProps<{
7
+ /**
8
+ * DaisyUI theme string (recommended prop name)
9
+ */
10
+ dataTheme?: string
11
+
12
+ cssVars?: string
13
+ snoop?: boolean
14
+ }>()
15
+
16
+ function cssVarToCamel(str: string): string {
17
+ return str.replace(/^--/, '').replace(/-([a-z0-9])/g, (_, c: string) => c.toUpperCase())
18
+ }
19
+ function dataAttrToCamel(str: string): string {
20
+ return str.replace(/-([a-z0-9])/g, (_, c: string) => c.toUpperCase())
21
+ }
22
+ function parseThemeString(themeString?: string): {
23
+ style: Record<string, string>
24
+ dataAttrs: Record<string, string>
25
+ dataTheme: string | undefined
26
+ allAttrs: Record<string, string>
27
+ } {
28
+ if (!themeString) {
29
+ return { style: {}, dataAttrs: {}, dataTheme: undefined, allAttrs: {} }
30
+ }
31
+ const varNamePattern = /^--[\w-]+$/
32
+ const attrNamePattern = /^[a-z_][\w-]*$/i
33
+ const forbiddenChars = /[<>{};]/g
34
+
35
+ const style: Record<string, string> = {}
36
+ const dataAttrs: Record<string, string> = {}
37
+ let dataTheme: string | undefined
38
+ const allAttrs: Record<string, string> = {}
39
+
40
+ // Remove @plugin ... { and closing } if present
41
+ const str = themeString
42
+ .trim()
43
+ .replace(/^@plugin[^{}]*\{/, '')
44
+ .replace(/\}$/, '')
45
+ .trim()
46
+
47
+ // works with or without newline characters
48
+ str.split(/[\n;]/).forEach(line => {
49
+ const trimmed = line.trim()
50
+ if (!trimmed || trimmed.startsWith('//')) {
51
+ return
52
+ }
53
+ const colonIdx = trimmed.indexOf(':')
54
+ if (colonIdx === -1) {
55
+ return
56
+ }
57
+ const key = trimmed.slice(0, colonIdx).trim()
58
+ let value = trimmed.slice(colonIdx + 1).trim()
59
+ if (value.endsWith(';')) {
60
+ value = value.slice(0, -1).trim()
61
+ }
62
+ value = value.replace(forbiddenChars, '')
63
+ if (!value) {
64
+ return
65
+ }
66
+ if (varNamePattern.test(key)) {
67
+ style[key] = value
68
+ allAttrs[cssVarToCamel(key)] = value
69
+ } else if (key === 'name') {
70
+ dataTheme = value.replace(/"/g, '')
71
+ allAttrs.dataTheme = dataTheme
72
+ } else if (attrNamePattern.test(key)) {
73
+ const attrKey = `data-${key.replace(/[^\w-]/g, '')}`
74
+ const attrVal = value.replace(/"/g, '')
75
+ dataAttrs[attrKey] = attrVal
76
+ if (attrKey.startsWith('data-')) {
77
+ allAttrs[dataAttrToCamel(attrKey)] = attrVal
78
+ }
79
+ }
80
+ })
81
+ return { style, dataAttrs, dataTheme, allAttrs }
82
+ }
83
+
84
+ const parsed = computed(() => parseThemeString(props.dataTheme ?? props.cssVars))
85
+
86
+ const themeVars = ref<Record<string, string>>({})
87
+ let observers: MutationObserver[] = []
88
+ let themeControllerInputs: Array<{ el: HTMLInputElement; listener: () => void }> = []
89
+ let themeControllerDomObserver: MutationObserver | null = null
90
+
91
+ // Converts a themeAttrs object to a DaisyUI theme string
92
+ function toThemeString(attrs: Record<string, string>, opts?: { asPlugin?: boolean }) {
93
+ const lines: string[] = []
94
+ // Map camelCase back to DaisyUI keys
95
+ for (const [key, value] of Object.entries(attrs)) {
96
+ if (key === 'dataTheme') {
97
+ lines.push(`name: "${value}";`)
98
+ } else if (key.startsWith('data')) {
99
+ // Convert dataFooBar -> foo-bar
100
+ const attr = key
101
+ .slice(4)
102
+ .replace(/([A-Z])/g, '-$1')
103
+ .toLowerCase()
104
+ if (attr !== 'theme') {
105
+ lines.push(`${attr}: ${value};`)
106
+ }
107
+ } else {
108
+ // Convert camelCase to --kebab-case
109
+ const cssVar = `--${key.replace(/([A-Z])/g, '-$1').toLowerCase()}`
110
+ lines.push(`${cssVar}: ${value};`)
111
+ }
112
+ }
113
+ const inner = lines.join('\n')
114
+ if (opts?.asPlugin) {
115
+ return `@plugin \"daisyui/theme\" {\n${inner}\n}`
116
+ }
117
+ return inner
118
+ }
119
+
120
+ // Returns the slot data object depending on snoop mode
121
+ const slotData: ComputedThemeVarsSlot = computed(() => {
122
+ // Access both dependencies so Vue always tracks them for reactivity
123
+ void themeVars.value
124
+ void parsed.value.allAttrs
125
+ if (props.snoop) {
126
+ return {
127
+ vars: themeVars.value,
128
+ toThemeString: (attrs = themeVars.value, opts) => toThemeString(attrs, opts),
129
+ }
130
+ }
131
+ return {
132
+ vars: parsed.value.allAttrs,
133
+ toThemeString: (attrs = parsed.value.allAttrs, opts) => toThemeString(attrs, opts),
134
+ }
135
+ })
136
+
137
+ // Provide the slotData as 'daisyUiTheme' for child consumers
138
+ provide(daisyUiThemeKey, slotData)
139
+
140
+ // DaisyUI variable names
141
+ const daisyVars = [
142
+ '--color-primary',
143
+ '--color-primary-content',
144
+ '--color-secondary',
145
+ '--color-secondary-content',
146
+ '--color-accent',
147
+ '--color-accent-content',
148
+ '--color-neutral',
149
+ '--color-neutral-content',
150
+ '--color-base-100',
151
+ '--color-base-200',
152
+ '--color-base-300',
153
+ '--color-base-content',
154
+ '--color-info',
155
+ '--color-info-content',
156
+ '--color-success',
157
+ '--color-success-content',
158
+ '--color-warning',
159
+ '--color-warning-content',
160
+ '--color-error',
161
+ '--color-error-content',
162
+ '--radius-selector',
163
+ '--radius-field',
164
+ '--radius-box',
165
+ '--size-selector',
166
+ '--size-field',
167
+ '--border',
168
+ '--depth',
169
+ '--noise',
170
+ ]
171
+
172
+ function getDaisyVarsFromEl(el: HTMLElement): Record<string, string> {
173
+ const vars: Record<string, string> = {}
174
+ const style = getComputedStyle(el)
175
+ for (const varName of daisyVars) {
176
+ const val = style.getPropertyValue(varName)
177
+ if (val) {
178
+ vars[cssVarToCamel(varName)] = val.trim()
179
+ }
180
+ }
181
+ return vars
182
+ }
183
+
184
+ let prefersColorSchemeMql: MediaQueryList | null = null
185
+ let prefersColorSchemeCleanup: (() => void) | null = null
186
+
187
+ function setupSnoop(rootEl: HTMLElement): void {
188
+ function updateVars(): void {
189
+ themeVars.value = getDaisyVarsFromEl(rootEl)
190
+ }
191
+ // Observe the current element for data-theme changes
192
+ const obs = new MutationObserver(() => updateVars())
193
+ obs.observe(rootEl, { attributes: true, attributeFilter: ['data-theme'] })
194
+
195
+ // Also observe the <html> element for data-theme changes
196
+ const htmlEl = document.documentElement
197
+ const htmlObs = new MutationObserver(() => updateVars())
198
+ htmlObs.observe(htmlEl, { attributes: true, attributeFilter: ['data-theme'] })
199
+
200
+ observers = [obs, htmlObs]
201
+
202
+ // Listen for prefers-color-scheme changes
203
+ prefersColorSchemeMql = window.matchMedia('(prefers-color-scheme: dark)')
204
+ const prefersColorSchemeListener = () => updateVars()
205
+ prefersColorSchemeMql.addEventListener('change', prefersColorSchemeListener)
206
+ prefersColorSchemeCleanup = () => {
207
+ prefersColorSchemeMql?.removeEventListener('change', prefersColorSchemeListener)
208
+ }
209
+
210
+ // --- Observe theme-controller checkboxes/radios, including dynamic changes ---
211
+ function bindThemeControllerInputs() {
212
+ // Remove any previous listeners
213
+ themeControllerInputs.forEach(({ el, listener }) => {
214
+ el.removeEventListener('change', listener)
215
+ })
216
+ themeControllerInputs = []
217
+ // Find all matching inputs in the document
218
+ const inputs = Array.from(
219
+ document.querySelectorAll('input[type="checkbox"].theme-controller, input[type="radio"].theme-controller'),
220
+ ) as HTMLInputElement[]
221
+ inputs.forEach(el => {
222
+ const listener = () => updateVars()
223
+ el.addEventListener('change', listener)
224
+ themeControllerInputs.push({ el, listener })
225
+ })
226
+ }
227
+ bindThemeControllerInputs()
228
+ // Observe DOM for dynamic addition/removal of theme-controller inputs
229
+ if (themeControllerDomObserver) {
230
+ themeControllerDomObserver.disconnect()
231
+ themeControllerDomObserver = null
232
+ }
233
+ themeControllerDomObserver = new MutationObserver(() => {
234
+ bindThemeControllerInputs()
235
+ })
236
+ themeControllerDomObserver.observe(document.body, { childList: true, subtree: true })
237
+
238
+ // Watch for applied style changes (parsed.style)
239
+ watch(
240
+ () => parsed.value.style,
241
+ () => {
242
+ nextTick(() => updateVars())
243
+ },
244
+ { immediate: false, deep: true },
245
+ )
246
+ updateVars()
247
+ }
248
+
249
+ const rootEl = ref<HTMLElement | null>(null)
250
+
251
+ const isClient = typeof window !== 'undefined' && typeof document !== 'undefined'
252
+
253
+ watch(
254
+ [() => props.snoop, () => rootEl.value],
255
+ ([snoop, el]) => {
256
+ if (isClient) {
257
+ // Clean up previous observers if any
258
+ observers.forEach((o: MutationObserver) => o.disconnect())
259
+ observers = []
260
+ if (snoop && el) {
261
+ nextTick(() => {
262
+ setupSnoop(el)
263
+ })
264
+ }
265
+ }
266
+ },
267
+ { immediate: true },
268
+ )
269
+
270
+ onUnmounted(() => {
271
+ observers.forEach((o: MutationObserver) => o.disconnect())
272
+ observers = []
273
+ // Remove prefers-color-scheme listener if present
274
+ if (prefersColorSchemeCleanup) {
275
+ prefersColorSchemeCleanup()
276
+ prefersColorSchemeCleanup = null
277
+ prefersColorSchemeMql = null
278
+ }
279
+ // Remove theme-controller listeners
280
+ themeControllerInputs.forEach(({ el, listener }) => {
281
+ el.removeEventListener('change', listener)
282
+ })
283
+ themeControllerInputs = []
284
+ // Disconnect theme-controller DOM observer
285
+ if (themeControllerDomObserver) {
286
+ themeControllerDomObserver.disconnect()
287
+ themeControllerDomObserver = null
288
+ }
289
+ })
290
+ </script>
291
+
292
+ <template>
293
+ <div
294
+ ref="rootEl"
295
+ v-bind="parsed.dataAttrs"
296
+ :data-theme="dataTheme"
297
+ :style="parsed.style"
298
+ class="[background-color:unset] theme-provider"
299
+ >
300
+ <slot v-bind="slotData" />
301
+ </div>
302
+ </template>
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ theme?: string
6
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
7
+ xs?: boolean
8
+ sm?: boolean
9
+ md?: boolean
10
+ lg?: boolean
11
+ xl?: boolean
12
+ }>()
13
+ const size = computed(() => props.size ?? 'md')
14
+
15
+ const squareClass = computed(() => {
16
+ switch (size.value) {
17
+ case 'xs':
18
+ return 'w-full h-full rounded-[2px]'
19
+ case 'sm':
20
+ return 'w-full h-full rounded-[2px]'
21
+ case 'md':
22
+ return 'w-full h-full rounded-xs'
23
+ case 'lg':
24
+ return 'w-full h-full rounded-sm'
25
+ case 'xl':
26
+ return 'w-full h-full rounded'
27
+ default:
28
+ return 'w-full h-full rounded-xs'
29
+ }
30
+ })
31
+ </script>
32
+
33
+ <template>
34
+ <div
35
+ :data-theme="theme"
36
+ class="grid grid-cols-2 bg-white rounded-sm"
37
+ :class="{
38
+ '!size-4 p-0.5 gap-px': xs || size === 'xs',
39
+ '!size-5 p-0.5 gap-px': sm || size === 'sm',
40
+ 'size-6 p-0.5 gap-0.5': md || size === 'md' || !size,
41
+ 'size-8 p-0.75 gap-0.5': lg || size === 'lg',
42
+ 'size-10 h-10 p-1 gap-0.75': xl || size === 'xl',
43
+ }"
44
+ >
45
+ <div class="bg-neutral" :class="squareClass" />
46
+ <div class="bg-primary" :class="squareClass" />
47
+ <div class="bg-secondary" :class="squareClass" />
48
+ <div class="bg-accent" :class="squareClass" />
49
+ </div>
50
+ </template>
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ vertical?: boolean
4
+ horizontal?: boolean
5
+ compact?: boolean
6
+ snapIcon?: boolean
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <ul
12
+ class="timeline"
13
+ :class="{
14
+ 'timeline-vertical': vertical,
15
+ 'timeline-horizontal': horizontal,
16
+ 'timeline-compact': compact,
17
+ 'timeline-snap-icon': snapIcon,
18
+ }"
19
+ >
20
+ <slot />
21
+ </ul>
22
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ defineProps<{ box?: boolean }>()
3
+ </script>
4
+
5
+ <template>
6
+ <div
7
+ class="timeline-end"
8
+ :class="{
9
+ 'timeline-box': box,
10
+ }"
11
+ >
12
+ <slot />
13
+ </div>
14
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <li class="timeline-item">
3
+ <slot />
4
+ </li>
5
+ </template>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ color?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error'
4
+ neutral?: boolean
5
+ primary?: boolean
6
+ secondary?: boolean
7
+ accent?: boolean
8
+ info?: boolean
9
+ success?: boolean
10
+ warning?: boolean
11
+ error?: boolean
12
+ }>()
13
+ </script>
14
+
15
+ <template>
16
+ <hr
17
+ class="timeline-line"
18
+ :class="{
19
+ 'bg-neutral': neutral || color === 'neutral',
20
+ 'bg-primary': primary || color === 'primary',
21
+ 'bg-secondary': secondary || color === 'secondary',
22
+ 'bg-accent': accent || color === 'accent',
23
+ 'bg-info': info || color === 'info',
24
+ 'bg-success': success || color === 'success',
25
+ 'bg-warning': warning || color === 'warning',
26
+ 'bg-error': error || color === 'error',
27
+ }"
28
+ />
29
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="timeline-middle">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ defineProps<{ box?: boolean }>()
3
+ </script>
4
+
5
+ <template>
6
+ <div
7
+ class="timeline-start"
8
+ :class="{
9
+ 'timeline-box': box,
10
+ }"
11
+ >
12
+ <slot />
13
+ </div>
14
+ </template>
@@ -0,0 +1,67 @@
1
+ <script setup lang="ts">
2
+ import type { Toast } from '../composables/use-toast'
3
+ import { computed } from 'vue'
4
+ import { useToast } from '../composables/use-toast'
5
+
6
+ // Explicit slot typing (Vue 3.4+ / Volar)
7
+ interface ToastSlotProps {
8
+ toast?: Toast
9
+ removeToast?: (id: number) => void
10
+ [key: string]: unknown
11
+ }
12
+ const props = defineProps<{
13
+ /**
14
+ * Horizontal alignment (start, center, end)
15
+ */
16
+ hAlign?: 'start' | 'center' | 'end'
17
+ start?: boolean
18
+ center?: boolean
19
+ end?: boolean
20
+ /**
21
+ * Vertical alignment (top, middle, bottom)
22
+ */
23
+ vAlign?: 'top' | 'middle' | 'bottom'
24
+ top?: boolean
25
+ middle?: boolean
26
+ bottom?: boolean
27
+ /**
28
+ * Toast channel name (for named channels)
29
+ */
30
+ name?: string
31
+ /**
32
+ * Default toast settings for this channel (merged into every toast)
33
+ * Example: { duration: 6000, type: 'info', position: 'top-center' }
34
+ */
35
+ defaults?: Partial<Toast>
36
+ }>()
37
+
38
+ defineSlots<{
39
+ default: (props: ToastSlotProps) => any
40
+ }>()
41
+
42
+ // Extract useToast options from props (name, defaults, future-proof)
43
+ const toastOptions = computed(() => {
44
+ const { name, defaults } = props
45
+ return { name, defaults }
46
+ })
47
+
48
+ const { toasts, removeToast } = useToast(toastOptions.value)
49
+ const visibleToasts = computed(() => toasts.value ?? [])
50
+ </script>
51
+
52
+ <template>
53
+ <div
54
+ class="toast"
55
+ :class="{
56
+ 'toast-start': props.start || props.hAlign === 'start',
57
+ 'toast-center': props.center || props.hAlign === 'center',
58
+ 'toast-end': props.end || props.hAlign === 'end',
59
+ 'toast-top': props.top || props.vAlign === 'top',
60
+ 'toast-middle': props.middle || props.vAlign === 'middle',
61
+ 'toast-bottom': props.bottom || props.vAlign === 'bottom',
62
+ }"
63
+ >
64
+ <slot v-for="toast in visibleToasts" :key="toast.id" :toast="toast" :remove-toast="removeToast" />
65
+ <slot />
66
+ </div>
67
+ </template>
@@ -0,0 +1,60 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ modelValue?: any
6
+ disabled?: boolean
7
+ validator?: boolean
8
+ themeController?: boolean
9
+
10
+ color?: string
11
+ neutral?: boolean
12
+ primary?: boolean
13
+ secondary?: boolean
14
+ accent?: boolean
15
+ success?: boolean
16
+ info?: boolean
17
+ warning?: boolean
18
+ error?: boolean
19
+
20
+ size?: string
21
+ xs?: boolean
22
+ sm?: boolean
23
+ md?: boolean
24
+ lg?: boolean
25
+ xl?: boolean
26
+ }>()
27
+ const emit = defineEmits(['update:modelValue'])
28
+
29
+ const currentValue = computed({
30
+ get: () => props.modelValue,
31
+ set: (val: string) => emit('update:modelValue', val),
32
+ })
33
+ </script>
34
+
35
+ <template>
36
+ <input
37
+ v-model="currentValue"
38
+ type="checkbox"
39
+ v-bind="$attrs"
40
+ class="toggle"
41
+ :disabled="disabled"
42
+ :class="{
43
+ validator,
44
+ 'toggle-neutral': neutral || color === 'neutral',
45
+ 'toggle-primary': primary || color === 'primary',
46
+ 'toggle-secondary': secondary || color === 'secondary',
47
+ 'toggle-accent': accent || color === 'accent',
48
+ 'toggle-success': success || color === 'success',
49
+ 'toggle-info': info || color === 'info',
50
+ 'toggle-warning': warning || color === 'warning',
51
+ 'toggle-error': error || color === 'error',
52
+ 'toggle-xs': xs || size === 'xs',
53
+ 'toggle-sm': sm || size === 'sm',
54
+ 'toggle-md': md || size === 'md',
55
+ 'toggle-lg': lg || size === 'lg',
56
+ 'toggle-xl': xl || size === 'xl',
57
+ 'theme-controller': themeController,
58
+ }"
59
+ />
60
+ </template>