daisy-ui-kit 3.0.12 → 5.0.0-pre.10

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 (198) hide show
  1. package/README.md +62 -14
  2. package/{components → app/components}/Accordion.vue +7 -10
  3. package/app/components/Alert.vue +35 -0
  4. package/app/components/Avatar.vue +128 -0
  5. package/app/components/AvatarGroup.vue +18 -0
  6. package/app/components/Badge.vue +54 -0
  7. package/app/components/Button.vue +120 -0
  8. package/app/components/Calendar.vue +66 -0
  9. package/app/components/CalendarInput.vue +174 -0
  10. package/app/components/CalendarSkeleton.vue +46 -0
  11. package/app/components/Card.vue +33 -0
  12. package/{components → app/components}/CardActions.vue +3 -6
  13. package/{components → app/components}/CardBody.vue +3 -6
  14. package/{components → app/components}/CardTitle.vue +2 -7
  15. package/app/components/Carousel.vue +23 -0
  16. package/app/components/Chat.vue +21 -0
  17. package/app/components/ChatBubble.vue +31 -0
  18. package/app/components/Checkbox.vue +51 -0
  19. package/app/components/Collapse.vue +43 -0
  20. package/app/components/Countdown.vue +15 -0
  21. package/app/components/CountdownTimers.vue +72 -0
  22. package/app/components/Counter.vue +10 -0
  23. package/app/components/DaisyLink.vue +38 -0
  24. package/app/components/Diff.vue +11 -0
  25. package/app/components/Divider.vue +43 -0
  26. package/app/components/Dock.vue +60 -0
  27. package/app/components/DockItem.vue +26 -0
  28. package/app/components/DockLabel.vue +5 -0
  29. package/{components → app/components}/Drawer.vue +6 -4
  30. package/{components → app/components}/DrawerContent.vue +1 -1
  31. package/{components → app/components}/DrawerSide.vue +1 -1
  32. package/{components → app/components}/Dropdown.vue +2 -2
  33. package/{components → app/components}/DropdownContent.vue +3 -3
  34. package/app/components/Fieldset.vue +19 -0
  35. package/app/components/FileInput.vue +53 -0
  36. package/app/components/Filter.vue +122 -0
  37. package/app/components/Flex.vue +82 -0
  38. package/{components → app/components}/FlexItem.vue +1 -1
  39. package/app/components/Footer.vue +27 -0
  40. package/app/components/FormControl.vue +5 -0
  41. package/{components → app/components}/Hero.vue +1 -1
  42. package/{components → app/components}/HeroContent.vue +1 -1
  43. package/app/components/Input.vue +119 -0
  44. package/app/components/Kbd.vue +24 -0
  45. package/app/components/Label.vue +97 -0
  46. package/app/components/List.vue +5 -0
  47. package/{components/FormControl.vue → app/components/ListColGrow.vue} +1 -1
  48. package/app/components/ListColWrap.vue +5 -0
  49. package/{components/Stat.vue → app/components/ListRow.vue} +1 -1
  50. package/app/components/LoadingBall.vue +42 -0
  51. package/app/components/LoadingBars.vue +42 -0
  52. package/app/components/LoadingDots.vue +42 -0
  53. package/app/components/LoadingInfinity.vue +42 -0
  54. package/app/components/LoadingRing.vue +42 -0
  55. package/app/components/LoadingSpinner.vue +42 -0
  56. package/app/components/Mask.vue +49 -0
  57. package/app/components/Menu.vue +30 -0
  58. package/app/components/MenuExpand.vue +100 -0
  59. package/{components → app/components}/MenuExpandToggle.vue +5 -4
  60. package/{components → app/components}/MenuItem.vue +3 -4
  61. package/app/components/MockupPhone.vue +14 -0
  62. package/{components → app/components}/Modal.vue +14 -5
  63. package/app/components/NavButton.vue +12 -0
  64. package/{components → app/components}/Navbar.vue +3 -5
  65. package/{components → app/components}/NavbarCenter.vue +3 -5
  66. package/{components → app/components}/NavbarEnd.vue +3 -5
  67. package/{components → app/components}/NavbarStart.vue +3 -5
  68. package/app/components/Progress.vue +34 -0
  69. package/{components → app/components}/Prose.vue +1 -1
  70. package/app/components/RadialProgress.vue +36 -0
  71. package/app/components/Radio.vue +69 -0
  72. package/{components → app/components}/RadioGroup.vue +2 -1
  73. package/app/components/Range.vue +61 -0
  74. package/{components → app/components}/RangeMeasure.vue +22 -21
  75. package/{components → app/components}/RangeMeasureTick.vue +9 -14
  76. package/app/components/Rating.vue +180 -0
  77. package/{components → app/components}/Select.vue +33 -29
  78. package/app/components/Skeleton.vue +5 -0
  79. package/app/components/Stack.vue +25 -0
  80. package/app/components/Stat.vue +19 -0
  81. package/app/components/Status.vue +43 -0
  82. package/app/components/Step.vue +34 -0
  83. package/app/components/StepIcon.vue +5 -0
  84. package/app/components/Steps.vue +18 -0
  85. package/app/components/Swap.vue +62 -0
  86. package/app/components/Tab.vue +38 -0
  87. package/{components → app/components}/TabContent.vue +10 -10
  88. package/app/components/Table.vue +32 -0
  89. package/app/components/Tabs.vue +53 -0
  90. package/app/components/Text.vue +142 -0
  91. package/app/components/TextArea.vue +61 -0
  92. package/app/components/ThemeController.vue +46 -0
  93. package/app/components/ThemeProvider.vue +287 -0
  94. package/app/components/ThemeTile.vue +50 -0
  95. package/app/components/Timeline.vue +22 -0
  96. package/app/components/TimelineEnd.vue +14 -0
  97. package/app/components/TimelineItem.vue +5 -0
  98. package/app/components/TimelineLine.vue +29 -0
  99. package/app/components/TimelineMiddle.vue +5 -0
  100. package/app/components/TimelineStart.vue +13 -0
  101. package/app/components/Toast.vue +72 -0
  102. package/app/components/Toggle.vue +60 -0
  103. package/app/components/Tooltip.vue +47 -0
  104. package/app/components/TooltipContent.vue +5 -0
  105. package/app/components/ValidatorHint.vue +5 -0
  106. package/nuxt.js +7 -1
  107. package/package.json +58 -61
  108. package/components/Alert.vue +0 -25
  109. package/components/Artboard.vue +0 -33
  110. package/components/Avatar.vue +0 -70
  111. package/components/AvatarGroup.vue +0 -19
  112. package/components/Badge.vue +0 -50
  113. package/components/BottomNav.vue +0 -25
  114. package/components/Button.vue +0 -111
  115. package/components/Card.vue +0 -30
  116. package/components/Carousel.vue +0 -25
  117. package/components/Chat.vue +0 -27
  118. package/components/ChatBubble.vue +0 -34
  119. package/components/Checkbox.vue +0 -55
  120. package/components/Code.vue +0 -92
  121. package/components/Collapse.vue +0 -54
  122. package/components/Countdown.vue +0 -15
  123. package/components/CountdownTimers.vue +0 -70
  124. package/components/Counter.vue +0 -14
  125. package/components/Divider.vue +0 -24
  126. package/components/FileInput.vue +0 -59
  127. package/components/Flex.vue +0 -59
  128. package/components/Footer.vue +0 -24
  129. package/components/Kbd.vue +0 -25
  130. package/components/Label.vue +0 -15
  131. package/components/LabelText.vue +0 -15
  132. package/components/LabelTextAlt.vue +0 -15
  133. package/components/Link.vue +0 -40
  134. package/components/LoadingBall.vue +0 -43
  135. package/components/LoadingBars.vue +0 -43
  136. package/components/LoadingDots.vue +0 -43
  137. package/components/LoadingInfinity.vue +0 -43
  138. package/components/LoadingRing.vue +0 -43
  139. package/components/LoadingSpinner.vue +0 -43
  140. package/components/Mask.config.ts +0 -77
  141. package/components/Mask.vue +0 -14
  142. package/components/Menu.vue +0 -35
  143. package/components/MenuExpand.vue +0 -79
  144. package/components/MockupPhone.vue +0 -8
  145. package/components/NavButton.vue +0 -20
  146. package/components/Progress.vue +0 -42
  147. package/components/RadialProgress.vue +0 -41
  148. package/components/Radio.vue +0 -76
  149. package/components/Range.vue +0 -60
  150. package/components/Rating.vue +0 -167
  151. package/components/Stack.vue +0 -13
  152. package/components/Step.vue +0 -36
  153. package/components/Steps.vue +0 -21
  154. package/components/Swap.vue +0 -58
  155. package/components/Tab.vue +0 -48
  156. package/components/Tabs.vue +0 -77
  157. package/components/TabsManager.vue +0 -38
  158. package/components/Text.vue +0 -142
  159. package/components/TextArea.vue +0 -64
  160. package/components/TextInput.vue +0 -66
  161. package/components/Toast.vue +0 -31
  162. package/components/Toggle.vue +0 -59
  163. package/components/Tooltip.vue +0 -47
  164. package/index.ts +0 -108
  165. package/utils/-utils.ts +0 -41
  166. package/utils/Button.config.ts +0 -26
  167. package/utils/fixtures.ts +0 -62
  168. package/utils/types.ts +0 -7
  169. /package/{components → app/components}/Breadcrumbs.vue +0 -0
  170. /package/{components → app/components}/CarouselItem.vue +0 -0
  171. /package/{components → app/components}/ChatFooter.vue +0 -0
  172. /package/{components → app/components}/ChatHeader.vue +0 -0
  173. /package/{components → app/components}/ChatImage.vue +0 -0
  174. /package/{components → app/components}/CollapseContent.vue +0 -0
  175. /package/{components → app/components}/CollapseTitle.vue +0 -0
  176. /package/{components → app/components}/Crumb.vue +0 -0
  177. /package/{components → app/components}/DropdownButton.vue +0 -0
  178. /package/{components → app/components}/DropdownTarget.vue +0 -0
  179. /package/{components → app/components}/FooterTitle.vue +0 -0
  180. /package/{components → app/components}/HeroOverlay.vue +0 -0
  181. /package/{components → app/components}/Indicator.vue +0 -0
  182. /package/{components → app/components}/IndicatorItem.vue +0 -0
  183. /package/{components → app/components}/Join.vue +0 -0
  184. /package/{components → app/components}/MenuTitle.vue +0 -0
  185. /package/{components → app/components}/MockupBrowser.vue +0 -0
  186. /package/{components → app/components}/MockupBrowserToolbar.vue +0 -0
  187. /package/{components → app/components}/MockupCode.vue +0 -0
  188. /package/{components → app/components}/MockupWindow.vue +0 -0
  189. /package/{components → app/components}/ModalAction.vue +0 -0
  190. /package/{components → app/components}/ModalBox.vue +0 -0
  191. /package/{components → app/components}/StatActions.vue +0 -0
  192. /package/{components → app/components}/StatDesc.vue +0 -0
  193. /package/{components → app/components}/StatFigure.vue +0 -0
  194. /package/{components → app/components}/StatTitle.vue +0 -0
  195. /package/{components → app/components}/StatValue.vue +0 -0
  196. /package/{components → app/components}/Stats.vue +0 -0
  197. /package/{utils → app/utils}/drawer-utils.ts +0 -0
  198. /package/{utils → app/utils}/random-string.ts +0 -0
package/README.md CHANGED
@@ -1,27 +1,75 @@
1
- # DaisyUI Kit
1
+ # Nuxt Minimal Starter
2
2
 
3
- [Read the Docs](https://daisyuikit.com)
3
+ Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
4
4
 
5
- ## Start with CSS. Sprinkle in VueJS
5
+ ## Setup
6
6
 
7
- You can do a lot with CSS. VueJS lets us go beyond any limitations to give your users exactly the UX they desire. Where it makes sense, we've integrated components with reactive `v-model` support.
7
+ Make sure to install dependencies:
8
8
 
9
- ## No Memorizing Class Names
9
+ ```bash
10
+ # npm
11
+ npm install
10
12
 
11
- When you don't have to memorize class names, you can start building right away.
13
+ # pnpm
14
+ pnpm install
12
15
 
13
- ## Semantic Markup
16
+ # yarn
17
+ yarn install
14
18
 
15
- It's much nicer to read component names than `<div class="" />`. It reduces mental overhead and frees up creativity.
19
+ # bun
20
+ bun install
21
+ ```
16
22
 
17
- ## Built with TypeScript
23
+ ## Development Server
18
24
 
19
- Since DaisyUI is built with Typescript, you get type-friendly components and props. The props practically document themselves.
25
+ Start the development server on `http://localhost:3000`:
20
26
 
21
- ## Great Documentation
27
+ ```bash
28
+ # npm
29
+ npm run dev
22
30
 
23
- The DaisyUI Kit documentation is loaded with examples. Expand the code panel below any example to copy, paste, then customize.
31
+ # pnpm
32
+ pnpm dev
24
33
 
25
- ## Small Bundle Size
34
+ # yarn
35
+ yarn dev
26
36
 
27
- We've found the perfect middle ground that captures the ease-of-use you get with components while also not bundling a lot of extra CSS class utilities.
37
+ # bun
38
+ bun run dev
39
+ ```
40
+
41
+ ## Production
42
+
43
+ Build the application for production:
44
+
45
+ ```bash
46
+ # npm
47
+ npm run build
48
+
49
+ # pnpm
50
+ pnpm build
51
+
52
+ # yarn
53
+ yarn build
54
+
55
+ # bun
56
+ bun run build
57
+ ```
58
+
59
+ Locally preview production build:
60
+
61
+ ```bash
62
+ # npm
63
+ npm run preview
64
+
65
+ # pnpm
66
+ pnpm preview
67
+
68
+ # yarn
69
+ yarn preview
70
+
71
+ # bun
72
+ bun run preview
73
+ ```
74
+
75
+ Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
@@ -1,22 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { computed, provide, ref, watch } from 'vue'
2
+ import { provide, ref, watch } from 'vue';
3
3
 
4
4
  const props = defineProps<{
5
5
  modelValue?: string | number
6
6
  }>()
7
7
  const emit = defineEmits(['update:modelValue'])
8
8
 
9
- const _value = ref(props.modelValue)
9
+ const value = ref(props.modelValue)
10
10
  watch(() => props.modelValue, (val) => {
11
- _value.value = val
11
+ value.value = val
12
12
  })
13
- const value = computed({
14
- get: () => _value.value,
15
- set: (val) => {
16
- _value.value = val
17
- if (props.modelValue !== val)
18
- emit('update:modelValue', val)
19
- },
13
+ watch(value, (val) => {
14
+ if (props.modelValue !== val) {
15
+ emit('update:modelValue', val)
16
+ }
20
17
  })
21
18
 
22
19
  provide('accordion-value', value)
@@ -0,0 +1,35 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps<{
3
+ outline?: boolean
4
+ dash?: boolean
5
+ soft?: boolean
6
+ type?: 'info' | 'success' | 'warning' | 'error'
7
+ info?: boolean
8
+ success?: boolean
9
+ warning?: boolean
10
+ error?: boolean
11
+ orientation?: 'vertical' | 'horizontal'
12
+ vertical?: boolean
13
+ horizontal?: boolean
14
+ }>()
15
+ </script>
16
+
17
+ <template>
18
+ <div
19
+ class="alert" :class="{
20
+ 'alert-outline': props.outline,
21
+ 'alert-dash': props.dash,
22
+ 'alert-soft': props.soft,
23
+
24
+ 'alert-info': props.info || props.type === 'info',
25
+ 'alert-success': props.success || props.type === 'success',
26
+ 'alert-warning': props.warning || props.type === 'warning',
27
+ 'alert-error': props.error || props.type === 'error',
28
+
29
+ 'alert-vertical': props.vertical || props.orientation === 'vertical',
30
+ 'alert-horizontal': props.horizontal || props.orientation === 'horizontal',
31
+ }"
32
+ >
33
+ <slot />
34
+ </div>
35
+ </template>
@@ -0,0 +1,128 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import Mask from './Mask.vue'
4
+
5
+ const props = defineProps({
6
+ backgroundColor: { type: String, default: '#BBB' },
7
+ maskClasses: String,
8
+ showStatus: Boolean,
9
+ // Presence props
10
+ presence: String,
11
+ online: Boolean,
12
+ offline: Boolean,
13
+ // Mask shape props (self-contained, no Mask.config.ts dependency)
14
+ shape: String,
15
+ squircle: Boolean,
16
+ heart: Boolean,
17
+ hexagon: Boolean,
18
+ hexagon2: Boolean,
19
+ decagon: Boolean,
20
+ pentagon: Boolean,
21
+ diamond: Boolean,
22
+ square: Boolean,
23
+ circle: Boolean,
24
+ star: Boolean,
25
+ star2: Boolean,
26
+ triangle: Boolean,
27
+ triangle2: Boolean,
28
+ triangle3: Boolean,
29
+ triangle4: Boolean,
30
+ half1: Boolean,
31
+ half2: Boolean,
32
+ })
33
+
34
+ const maskShapeKeys = [
35
+ 'mask-squircle',
36
+ 'mask-heart',
37
+ 'mask-hexagon',
38
+ 'mask-hexagon-2',
39
+ 'mask-decagon',
40
+ 'mask-pentagon',
41
+ 'mask-diamond',
42
+ 'mask-square',
43
+ 'mask-circle',
44
+ 'mask-star',
45
+ 'mask-star-2',
46
+ 'mask-triangle',
47
+ 'mask-triangle-2',
48
+ 'mask-triangle-3',
49
+ 'mask-triangle-4',
50
+ 'mask-half-1',
51
+ 'mask-half-2',
52
+ ] as const
53
+
54
+ type AvatarClassKey = typeof maskShapeKeys[number] | 'rounded-box' | 'avatar-online' | 'avatar-offline'
55
+
56
+ const avatarClasses = computed<Record<AvatarClassKey, boolean>>(() => {
57
+ const mask: Record<AvatarClassKey, boolean> = {
58
+ 'mask-squircle': props.squircle || props.shape === 'squircle',
59
+ 'mask-heart': props.heart || props.shape === 'heart',
60
+ 'mask-hexagon': props.hexagon || props.shape === 'hexagon',
61
+ 'mask-hexagon-2': props.hexagon2 || props.shape === 'hexagon-2',
62
+ 'mask-decagon': props.decagon || props.shape === 'decagon',
63
+ 'mask-pentagon': props.pentagon || props.shape === 'pentagon',
64
+ 'mask-diamond': props.diamond || props.shape === 'diamond',
65
+ 'mask-square': props.square || props.shape === 'square',
66
+ 'mask-circle': props.circle || props.shape === 'circle',
67
+ 'mask-star': props.star || props.shape === 'star',
68
+ 'mask-star-2': props.star2 || props.shape === 'star-2',
69
+ 'mask-triangle': props.triangle || props.shape === 'triangle',
70
+ 'mask-triangle-2': props.triangle2 || props.shape === 'triangle-2',
71
+ 'mask-triangle-3': props.triangle3 || props.shape === 'triangle-3',
72
+ 'mask-triangle-4': props.triangle4 || props.shape === 'triangle-4',
73
+ 'mask-half-1': props.half1 || props.shape === 'half-1',
74
+ 'mask-half-2': props.half2 || props.shape === 'half-2',
75
+ 'rounded-box': false,
76
+ 'avatar-online': props.presence === 'online' || props.online,
77
+ 'avatar-offline': props.presence === 'offline' || props.offline,
78
+ }
79
+ const hasMask = maskShapeKeys.some(k => mask[k])
80
+ mask['rounded-box'] = !hasMask
81
+ return mask
82
+ })
83
+
84
+ const color = computed(() => {
85
+ return `#${contrastingColor(props.backgroundColor.replace('#', ''))}`
86
+ })
87
+
88
+ function contrastingColor(color: any) {
89
+ return (luma(color) >= 155) ? '000' : 'fff'
90
+ }
91
+ // color can be a hx string or an array of RGB values 0-255
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
95
+ }
96
+ function hexToRGBArray(color: any) {
97
+ if (color.length === 3) {
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) {
101
+ throw new Error(`Invalid hex color: ${color}`)
102
+ }
103
+ const rgb = []
104
+ for (let i = 0; i <= 2; i++) {
105
+ rgb[i] = Number.parseInt(color.substr(i * 2, 2), 16)
106
+ }
107
+ return rgb
108
+ }
109
+ </script>
110
+
111
+ <template>
112
+ <div class="avatar">
113
+ <Mask :style="{ backgroundColor, color }" class="w-full h-full avatar-mask aspect-square" :class="[avatarClasses, maskClasses]">
114
+ <slot />
115
+ </Mask>
116
+ </div>
117
+ </template>
118
+
119
+ <style lang="postcss">
120
+ .avatar-mask > * {
121
+ aspect-ratio: 1/1;
122
+ width: 100%;
123
+ height: 100%;
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ }
128
+ </style>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ const props = defineProps<{
3
+ orientation: string
4
+ horizontal: boolean
5
+ vertical: boolean
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <div
11
+ class="avatar-group" :class="{
12
+ 'flex-row': props.orientation === 'horizontal' || props.horizontal || (!props.orientation && !props.vertical && !props.horizontal),
13
+ 'flex-col': props.orientation === 'vertical' || props.vertical,
14
+ }"
15
+ >
16
+ <slot />
17
+ </div>
18
+ </template>
@@ -0,0 +1,54 @@
1
+ <script setup lang="ts">
2
+ const { is = 'div', ...props } = defineProps<{
3
+ is?: string
4
+ outline?: boolean
5
+ soft?: boolean
6
+ dash?: boolean
7
+ ghost?: boolean
8
+
9
+ size?: string
10
+ xl?: boolean
11
+ lg?: boolean
12
+ md?: boolean
13
+ sm?: boolean
14
+ xs?: boolean
15
+
16
+ color?: string
17
+ neutral?: boolean
18
+ primary?: boolean
19
+ secondary?: boolean
20
+ accent?: boolean
21
+ info?: boolean
22
+ success?: boolean
23
+ warning?: boolean
24
+ error?: boolean
25
+ }>()
26
+ </script>
27
+
28
+ <template>
29
+ <component
30
+ :is="is" class="badge" :class="{
31
+ 'badge-outline': props.outline,
32
+ 'badge-ghost': props.ghost,
33
+ 'badge-soft': props.soft,
34
+ 'badge-dash': props.dash,
35
+
36
+ 'badge-xl': props.xl || props.size === 'xl',
37
+ 'badge-lg': props.lg || props.size === 'lg',
38
+ 'badge-md': props.md || props.size === 'md',
39
+ 'badge-sm': props.sm || props.size === 'sm',
40
+ 'badge-xs': props.xs || props.size === 'xs',
41
+
42
+ 'badge-neutral': props.neutral || props.color === 'neutral',
43
+ 'badge-primary': props.primary || props.color === 'primary',
44
+ 'badge-secondary': props.secondary || props.color === 'secondary',
45
+ 'badge-accent': props.accent || props.color === 'accent',
46
+ 'badge-info': props.info || props.color === 'info',
47
+ 'badge-success': props.success || props.color === 'success',
48
+ 'badge-warning': props.warning || props.color === 'warning',
49
+ 'badge-error': props.error || props.color === 'error',
50
+ }"
51
+ >
52
+ <slot />
53
+ </component>
54
+ </template>
@@ -0,0 +1,120 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
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
+ })
46
+
47
+ // Accessibility: Determine if rendering a native button
48
+ const isButton = computed(() => (props.is || 'button') === 'button')
49
+
50
+ // Accessibility: Keyboard event handler for custom elements
51
+ function onKeydown(e: KeyboardEvent) {
52
+ if (props.disabled) {
53
+ return
54
+ }
55
+ if (e.code === 'Space' || e.code === 'Enter' || e.key === ' ' || e.key === 'Enter') {
56
+ e.preventDefault()
57
+ // @ts-expect-error: $el may not exist yet
58
+ e.currentTarget?.click?.()
59
+ }
60
+ }
61
+ </script>
62
+
63
+ <template>
64
+ <component
65
+ :is="is || 'button'"
66
+ :type="type"
67
+ :disabled="isButton && disabled ? true : undefined"
68
+ :aria-disabled="!isButton && disabled ? true : undefined"
69
+ :tabindex="!isButton ? (disabled ? -1 : 0) : undefined"
70
+ :role="!isButton ? 'button' : undefined"
71
+ class="btn"
72
+ :class="{
73
+ 'join-item': join,
74
+
75
+ 'btn-neutral': !disabled && (neutral || color === 'neutral'),
76
+ 'btn-primary': !disabled && (primary || color === 'primary'),
77
+ 'btn-secondary': !disabled && (secondary || color === 'secondary'),
78
+ 'btn-accent': !disabled && (accent || color === 'accent'),
79
+ 'btn-info': !disabled && (info || color === 'info'),
80
+ 'btn-success': !disabled && (success || color === 'success'),
81
+ 'btn-warning': !disabled && (warning || color === 'warning'),
82
+ 'btn-error': !disabled && (error || color === 'error'),
83
+
84
+ 'text-primary': !disabled && (primary || color === 'primary') && link,
85
+ 'text-secondary': !disabled && (secondary || color === 'secondary') && link,
86
+ 'text-neutral': !disabled && (neutral || color === 'neutral') && link,
87
+ 'text-accent': !disabled && (accent || color === 'accent') && link,
88
+ 'text-info': !disabled && (info || color === 'info') && link,
89
+ 'text-success': !disabled && (success || color === 'success') && link,
90
+ 'text-warning': !disabled && (warning || color === 'warning') && link,
91
+ 'text-error': !disabled && (error || color === 'error') && link,
92
+
93
+ 'glass': !disabled && glass,
94
+
95
+ 'btn-circle': circle || shape === 'circle',
96
+ 'btn-square': square || shape === 'square',
97
+ 'btn-wide': wide || shape === 'wide',
98
+ 'btn-block': block || shape === 'block',
99
+
100
+ 'btn-xl': xl || size === 'xl',
101
+ 'btn-lg': lg || size === 'lg',
102
+ 'btn-md': md || size === 'md',
103
+ 'btn-sm': sm || size === 'sm',
104
+ 'btn-xs': xs || size === 'xs',
105
+
106
+ 'btn-outline': !disabled && outline,
107
+ 'btn-dash': !disabled && dash,
108
+ 'btn-ghost': !disabled && ghost,
109
+ 'btn-soft': !disabled && soft,
110
+ 'btn-link': !disabled && link,
111
+ 'btn-disabled': disabled,
112
+
113
+ 'no-animation': noAnimation,
114
+ 'btn-active': !disabled && active,
115
+ }"
116
+ @keydown="!isButton ? onKeydown : undefined"
117
+ >
118
+ <slot />
119
+ </component>
120
+ </template>
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ import type { PikadayOptions } from 'pikaday'
3
+ import { onMounted, ref } from 'vue'
4
+ import { usePikaday } from '~/composables/use-pikaday'
5
+ import CalendarSkeleton from './CalendarSkeleton.vue'
6
+
7
+ const props = defineProps<{
8
+ /** Bound value: Date object or ISO string or null */
9
+ modelValue: Date | string | null
10
+ /** All Pikaday options (except `container` and `bound`) */
11
+ options?: Omit<PikadayOptions, 'container' | 'bound'>
12
+ /** If true, default to today when no value provided */
13
+ autoDefault?: boolean
14
+ }>()
15
+ const emit = defineEmits<{
16
+ (e: 'update:modelValue', v: Date | null): void
17
+ }>()
18
+
19
+ const containerRef = ref<HTMLElement | null>(null)
20
+ const loading = ref(true)
21
+
22
+ const defaultOptions: Partial<PikadayOptions> = {
23
+ format: 'D MMM YYYY',
24
+ }
25
+
26
+ function handleSelect(date: Date) {
27
+ emit('update:modelValue', date)
28
+ }
29
+
30
+ const { createPicker } = usePikaday(
31
+ {
32
+ ...defaultOptions,
33
+ ...props.options,
34
+ bound: false,
35
+ },
36
+ handleSelect,
37
+ )
38
+
39
+ onMounted(async () => {
40
+ if (containerRef.value) {
41
+ const picker = await createPicker(containerRef.value)
42
+ if (picker && picker.el && !containerRef.value.contains(picker.el)) {
43
+ containerRef.value.appendChild(picker.el)
44
+ }
45
+ loading.value = false
46
+ }
47
+ })
48
+ </script>
49
+
50
+ <template>
51
+ <div class="relative w-[270px] h-[270px]">
52
+ <div class="absolute inset-0">
53
+ <CalendarSkeleton :number-of-months="options?.numberOfMonths ?? 1" :class="loading ? '' : 'opacity-0 pointer-events-none transition-opacity duration-300'" />
54
+ </div>
55
+ <div ref="containerRef" class="absolute inset-0 inline-block w-full h-full" />
56
+ <span class="pika-single hidden" />
57
+ </div>
58
+ </template>
59
+
60
+ <style>
61
+ .has-event {
62
+ .pika-button {
63
+ color: var(--color-primary);
64
+ }
65
+ }
66
+ </style>