daisy-ui-kit 0.4.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 (131) hide show
  1. package/README.md +80 -0
  2. package/components/-utils.ts +41 -0
  3. package/components/.DS_Store +0 -0
  4. package/components/Alert.vue +27 -0
  5. package/components/Artboard.vue +33 -0
  6. package/components/Avatar.vue +85 -0
  7. package/components/AvatarGroup.vue +19 -0
  8. package/components/Badge.vue +45 -0
  9. package/components/BottomNav.vue +27 -0
  10. package/components/Breadcrumbs.vue +7 -0
  11. package/components/Button.config.ts +26 -0
  12. package/components/Button.vue +112 -0
  13. package/components/ButtonGroup.vue +5 -0
  14. package/components/Card.vue +31 -0
  15. package/components/CardActions.vue +16 -0
  16. package/components/CardBody.vue +16 -0
  17. package/components/CardTitle.vue +16 -0
  18. package/components/Carousel.vue +26 -0
  19. package/components/CarouselItem.vue +5 -0
  20. package/components/Checkbox.vue +47 -0
  21. package/components/Code.vue +91 -0
  22. package/components/CodePreview.vue +28 -0
  23. package/components/CodeWrapper.vue +10 -0
  24. package/components/Collapse.vue +33 -0
  25. package/components/CollapseContent.vue +5 -0
  26. package/components/CollapseTitle.vue +5 -0
  27. package/components/Countdown.vue +16 -0
  28. package/components/CountdownTimers.vue +66 -0
  29. package/components/Counter.vue +15 -0
  30. package/components/Crumb.vue +5 -0
  31. package/components/DarkToggle.vue +11 -0
  32. package/components/DemoElement.vue +32 -0
  33. package/components/DemoExample.vue +23 -0
  34. package/components/Divider.vue +25 -0
  35. package/components/Drawer.vue +19 -0
  36. package/components/DrawerLayout.vue +35 -0
  37. package/components/DrawerLayoutContent.vue +11 -0
  38. package/components/Dropdown.vue +30 -0
  39. package/components/DropdownContent.vue +3 -0
  40. package/components/Flex.vue +146 -0
  41. package/components/FlexItem.vue +146 -0
  42. package/components/Footer.vue +25 -0
  43. package/components/FooterTitle.vue +17 -0
  44. package/components/FormControl.vue +5 -0
  45. package/components/Hero.vue +17 -0
  46. package/components/HeroContent.vue +17 -0
  47. package/components/HeroOverlay.vue +5 -0
  48. package/components/Home/AlternatingFeatureSections.vue +217 -0
  49. package/components/Home/CTA.vue +27 -0
  50. package/components/Home/Footer.vue +210 -0
  51. package/components/Home/GradientFeatureSections.vue +98 -0
  52. package/components/Home/Header.vue +174 -0
  53. package/components/Home/Hero.vue +52 -0
  54. package/components/Home/LogoCloud.vue +49 -0
  55. package/components/Home/StatsSection.vue +51 -0
  56. package/components/Home/Testimonial.vue +23 -0
  57. package/components/Indicator.vue +16 -0
  58. package/components/IndicatorItem.vue +37 -0
  59. package/components/InputGroup.vue +33 -0
  60. package/components/Kbd.vue +26 -0
  61. package/components/Label.vue +17 -0
  62. package/components/LabelText.vue +17 -0
  63. package/components/LabelTextAlt.vue +17 -0
  64. package/components/Link.vue +32 -0
  65. package/components/Logo.vue +8 -0
  66. package/components/Mask.config.ts +77 -0
  67. package/components/Mask.vue +15 -0
  68. package/components/Menu.vue +26 -0
  69. package/components/MenuItem.vue +17 -0
  70. package/components/MenuTitle.vue +14 -0
  71. package/components/MobileSidebar.vue +92 -0
  72. package/components/MockupCode.vue +4 -0
  73. package/components/Modal.vue +16 -0
  74. package/components/ModalAction.vue +5 -0
  75. package/components/ModalBox.vue +5 -0
  76. package/components/ModalWrapper.vue +32 -0
  77. package/components/NavButton.vue +22 -0
  78. package/components/Navbar.vue +17 -0
  79. package/components/NavbarCenter.vue +16 -0
  80. package/components/NavbarEnd.vue +16 -0
  81. package/components/NavbarStart.vue +16 -0
  82. package/components/Phone.vue +8 -0
  83. package/components/Progress.vue +44 -0
  84. package/components/Prose.vue +36 -0
  85. package/components/RadialProgress.vue +42 -0
  86. package/components/Radio.vue +63 -0
  87. package/components/RadioGroup.vue +41 -0
  88. package/components/Range.vue +49 -0
  89. package/components/RangeMeasure.vue +71 -0
  90. package/components/RangeMeasureTick.vue +62 -0
  91. package/components/Rating.vue +152 -0
  92. package/components/Select.vue +104 -0
  93. package/components/Sidebar.vue +89 -0
  94. package/components/SidebarMenuSection.vue +35 -0
  95. package/components/SigninForm.vue +47 -0
  96. package/components/Stack.vue +16 -0
  97. package/components/Stat.vue +5 -0
  98. package/components/StatActions.vue +5 -0
  99. package/components/StatDesc.vue +5 -0
  100. package/components/StatFigure.vue +5 -0
  101. package/components/StatTitle.vue +5 -0
  102. package/components/StatValue.vue +5 -0
  103. package/components/Stats.vue +5 -0
  104. package/components/Step.vue +36 -0
  105. package/components/Steps.vue +22 -0
  106. package/components/Swap.vue +60 -0
  107. package/components/Tab.vue +49 -0
  108. package/components/TabContent.vue +28 -0
  109. package/components/Tabs.vue +71 -0
  110. package/components/TabsManager.vue +37 -0
  111. package/components/Text.vue +179 -0
  112. package/components/TextArea.vue +53 -0
  113. package/components/TextInput.vue +64 -0
  114. package/components/Toast.vue +33 -0
  115. package/components/Toggle.vue +48 -0
  116. package/components/Tooltip.vue +49 -0
  117. package/components/UserMenu.vue +62 -0
  118. package/components/Window.vue +5 -0
  119. package/components/fixtures.ts +62 -0
  120. package/components/theme/Builder.vue +284 -0
  121. package/components/theme/Output.vue +70 -0
  122. package/components/theme/Picker.vue +39 -0
  123. package/components/theme/Preview.vue +1684 -0
  124. package/components/theme/Provider.vue +43 -0
  125. package/components/theme/Snooper.vue +41 -0
  126. package/components/theme/Swatch.vue +47 -0
  127. package/components/theme/custom-themes.ts +34 -0
  128. package/components/theme/theme-utils.ts +164 -0
  129. package/components/types.ts +7 -0
  130. package/index.ts +96 -0
  131. package/package.json +55 -0
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import { defineProps } from 'vue'
3
+
4
+ interface Props {
5
+ fullWidth?: boolean
6
+ }
7
+ defineProps<Props>()
8
+ </script>
9
+
10
+ <template>
11
+ <article class="prose daisy-prose" :class="{ 'full-width': fullWidth }">
12
+ <slot />
13
+ </article>
14
+ </template>
15
+
16
+ <style lang="postcss">
17
+ .prose.full-width {
18
+ width: 100%;
19
+ max-width: 100%;
20
+ }
21
+ .prose.daisy-prose code:not(pre code) {
22
+ @apply bg-base-300;
23
+ }
24
+ .prose .link-primary {
25
+ @apply text-primary;
26
+ }
27
+ .prose .link-secondary {
28
+ @apply text-secondary;
29
+ }
30
+ .prose .link-neutral {
31
+ @apply text-neutral;
32
+ }
33
+ .prose .link-accent {
34
+ @apply text-accent;
35
+ }
36
+ </style>
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineProps } from 'vue'
3
+
4
+ interface Props {
5
+ value: number | string
6
+ size?: string
7
+ thickness?: string
8
+
9
+ color?: string
10
+ neutral?: boolean
11
+ primary?: boolean
12
+ secondary?: boolean
13
+ accent?: boolean
14
+ info?: boolean
15
+ success?: boolean
16
+ warning?: boolean
17
+ error?: boolean
18
+ }
19
+ const props = defineProps<Props>()
20
+
21
+ const calculatedSize = computed(() => props.size || '4rem')
22
+ const calculatedThickness = computed(() => props.thickness || 'calc(var(--size) / 10)')
23
+
24
+ const classes = computed(() => {
25
+ return {
26
+ 'text-primary': (props.primary || props.color === 'primary'),
27
+ 'text-secondary': (props.secondary || props.color === 'secondary'),
28
+ 'text-neutral': (props.neutral || props.color === 'neutral'),
29
+ 'text-accent': (props.accent || props.color === 'accent'),
30
+ 'text-info': (props.info || props.color === 'info'),
31
+ 'text-success': (props.success || props.color === 'success'),
32
+ 'text-warning': (props.warning || props.color === 'warning'),
33
+ 'text-error': (props.error || props.color === 'error'),
34
+ }
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <div class="radial-progress" :class="classes" :style="`--value:${value}; --size:${calculatedSize}; --thickness:${calculatedThickness};`">
40
+ <slot />
41
+ </div>
42
+ </template>
@@ -0,0 +1,63 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps, inject } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ modelValue?: any
6
+ value: any
7
+
8
+ color?: string
9
+ primary?: boolean
10
+ secondary?: boolean
11
+ accent?: boolean
12
+
13
+ size?: string
14
+ xs?: boolean
15
+ sm?: boolean
16
+ md?: boolean
17
+ lg?: boolean
18
+ }>()
19
+ const emit = defineEmits(['update:modelValue'])
20
+
21
+ const radioGroup = inject('radio-group', null)
22
+
23
+ const _props = computed(() => {
24
+ if (radioGroup) return Object.assign({}, radioGroup.props, props)
25
+ else return props
26
+ })
27
+
28
+ const classes = computed(() => {
29
+ const { color, primary, secondary, accent, size, xs, sm, md, lg } = _props.value
30
+ return {
31
+ 'radio-primary': primary || color === 'primary',
32
+ 'radio-secondary': secondary || color === 'secondary',
33
+ 'radio-accent': accent || color === 'accent',
34
+ 'radio-xs': xs || size === 'xs',
35
+ 'radio-sm': sm || size === 'sm',
36
+ 'radio-md': md || size === 'md',
37
+ 'radio-lg': lg || size === 'lg',
38
+ }
39
+ })
40
+
41
+ const currentValue = computed({
42
+ get() {
43
+ if (radioGroup) return radioGroup.currentValue
44
+ return props.modelValue
45
+ },
46
+ set(val: string) {
47
+ radioGroup && (radioGroup.currentValue = val)
48
+ emit('update:modelValue', val)
49
+ },
50
+ })
51
+
52
+ </script>
53
+
54
+ <template>
55
+ <input
56
+ v-model="currentValue"
57
+ type="radio"
58
+ v-bind="{..._props, ...$attrs}"
59
+ class="radio"
60
+ :class="classes"
61
+ :value="props.value"
62
+ >
63
+ </template>
@@ -0,0 +1,41 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps, provide, reactive } from 'vue'
3
+
4
+ const props = defineProps<{
5
+ modelValue?: any
6
+ name: string
7
+
8
+ color?: string
9
+ primary?: boolean
10
+ secondary?: boolean
11
+ accent?: boolean
12
+
13
+ size?: string
14
+ xs?: boolean
15
+ sm?: boolean
16
+ md?: boolean
17
+ lg?: boolean
18
+ }>()
19
+ const emit = defineEmits(['update:modelValue'])
20
+
21
+ const currentValue = computed({
22
+ get: () => {
23
+ return props.modelValue
24
+ },
25
+ set: (val) => {
26
+ emit('update:modelValue', val)
27
+ },
28
+ })
29
+
30
+ const state = reactive({
31
+ currentValue,
32
+ props,
33
+ })
34
+ provide('radio-group', state)
35
+ </script>
36
+
37
+ <template>
38
+ <div class="radio-group">
39
+ <slot />
40
+ </div>
41
+ </template>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps } from 'vue'
3
+
4
+ interface Props {
5
+ min?: number | string
6
+ max?: number | string
7
+ step?: number | string
8
+ modelValue?: number | string
9
+
10
+ color?: string
11
+ primary?: boolean
12
+ secondary?: boolean
13
+ accent?: boolean
14
+
15
+ size?: 'lg' | 'md' | 'sm' | 'xs'
16
+ lg?: boolean
17
+ md?: boolean
18
+ sm?: boolean
19
+ xs?: boolean
20
+ }
21
+ const props = defineProps<Props>()
22
+ defineEmits(['update:modelValue'])
23
+
24
+ const classes = computed(() => {
25
+ const { color, primary, secondary, accent, size, lg, md, sm, xs } = props
26
+ return {
27
+ 'range-primary': primary || color === 'primary',
28
+ 'range-secondary': secondary || color === 'secondary',
29
+ 'range-accent': accent || color === 'accent',
30
+ 'range-lg': lg || size === 'lg',
31
+ 'range-md': md || size === 'md',
32
+ 'range-sm': sm || size === 'sm',
33
+ 'range-xs': xs || size === 'xs',
34
+ }
35
+ })
36
+ </script>
37
+
38
+ <template>
39
+ <input
40
+ type="range"
41
+ class="range"
42
+ :class="classes"
43
+ :min="min"
44
+ :max="max"
45
+ :step="step"
46
+ :value="modelValue"
47
+ @input="$emit('update:modelValue', ($event.target as any).value)"
48
+ >
49
+ </template>
@@ -0,0 +1,71 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineProps, withDefaults } from 'vue'
3
+
4
+ interface Props {
5
+ numbered?: boolean
6
+ min?: number | string
7
+ max?: number | string
8
+ step?: number | string
9
+ modelValue?: number | string
10
+
11
+ asButtons?: boolean
12
+
13
+ color?: string
14
+ primary?: boolean
15
+ secondary?: boolean
16
+ accent?: boolean
17
+
18
+ size?: 'lg' | 'md' | 'sm' | 'xs'
19
+ lg?: boolean
20
+ md?: boolean
21
+ sm?: boolean
22
+ xs?: boolean
23
+ }
24
+ const props = withDefaults(defineProps<Props>(), {
25
+ min: 0,
26
+ max: 100,
27
+ step: 1,
28
+ })
29
+ defineEmits(['update:modelValue'])
30
+
31
+ const classes = computed(() => {
32
+ const { color, primary, secondary, accent, size, lg, md, sm, xs, numbered } = props
33
+ return {
34
+ 'text-primary': primary || color === 'primary',
35
+ 'text-secondary': secondary || color === 'secondary',
36
+ 'text-accent': accent || color === 'accent',
37
+ 'text-lg': lg || size === 'lg',
38
+ 'text-md': md || size === 'md',
39
+ 'text-sm': sm || size === 'sm',
40
+ 'text-xs': xs || size === 'xs',
41
+ }
42
+ })
43
+ const values = computed(() => {
44
+ const vals = []
45
+ for (let index = parseInt(props.min as string); index < parseInt(props.max as string) + 1; index++) {
46
+ vals.push({
47
+ value: index,
48
+ isVisible: index % parseInt(props.step as string) === 0,
49
+ })
50
+ }
51
+ return vals
52
+ })
53
+ const count = computed(() => parseInt(props.max as string) - parseInt(props.min as string))
54
+ </script>
55
+
56
+ <template>
57
+ <div class="flex justify-between select-none" :class="classes">
58
+ <RangeMeasureTick
59
+ v-for="tick in values"
60
+ :key="tick.value"
61
+ :tick="tick.value"
62
+ :model-value="modelValue"
63
+ :numbered="numbered"
64
+ :as-button="asButtons"
65
+ :is-hidden="!tick.isVisible"
66
+ @update:model-value="(val) => $emit('update:modelValue', val)"
67
+ >
68
+ {{ numbered ? tick : '|' }}
69
+ </RangeMeasureTick>
70
+ </div>
71
+ </template>
@@ -0,0 +1,62 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps } from 'vue'
3
+ import { useTimeoutFn } from '@vueuse/core'
4
+
5
+ interface Props {
6
+ tick: number
7
+ modelValue?: number | string
8
+ numbered?: boolean
9
+ asButton?: boolean
10
+ isHidden?: boolean
11
+ }
12
+ const props = defineProps<Props>()
13
+ defineEmits(['update:modelValue'])
14
+
15
+ const hasChanged = ref(false)
16
+ const { isPending, start, stop } = useTimeoutFn(() => {
17
+ hasChanged.value = false
18
+ }, 1000)
19
+ watch(
20
+ () => props.modelValue,
21
+ (val) => {
22
+ if (val) {
23
+ start()
24
+ hasChanged.value = true
25
+ }
26
+ else if (!isPending.value) {
27
+ stop()
28
+ }
29
+ },
30
+ )
31
+
32
+ // eslint-disable-next-line eqeqeq
33
+ const isCurrent = computed(() => props.modelValue == props.tick)
34
+
35
+ const classes = computed(() => {
36
+ return {
37
+ 'font-bold': isCurrent.value,
38
+ }
39
+ })
40
+ </script>
41
+
42
+ <template>
43
+ <Button
44
+ v-if="asButton && !isHidden" xs :ghost="!isCurrent" circle :class="classes"
45
+ @click="$emit('update:modelValue', tick)"
46
+ >
47
+ {{ numbered ? tick : '|' }}
48
+ </Button>
49
+ <Tooltip
50
+ v-else
51
+ :tip="tick"
52
+ :open="hasChanged && isCurrent"
53
+ position="bottom"
54
+ class="cursor-pointer"
55
+ :class="{ 'px-[2px]': !asButton }"
56
+ @click="$emit('update:modelValue', tick)"
57
+ >
58
+ <Text v-if="!isHidden" :black="isCurrent">
59
+ {{ numbered ? tick : '|' }}
60
+ </Text>
61
+ </Tooltip>
62
+ </template>
@@ -0,0 +1,152 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps, withDefaults } from 'vue'
3
+
4
+ interface Props {
5
+ modelValue?: number | string
6
+ count?: number | string
7
+ half?: boolean
8
+
9
+ color?: string
10
+ neutral?: boolean
11
+ primary?: boolean
12
+ secondary?: boolean
13
+ accent?: boolean
14
+ info?: boolean
15
+ success?: boolean
16
+ warning?: boolean
17
+ error?: boolean
18
+
19
+ bg?: string
20
+
21
+ shape?: string
22
+ squircle?: boolean
23
+ heart?: boolean
24
+ hexagon?: boolean
25
+ hexagon2?: boolean
26
+ decagon?: boolean
27
+ pentagon?: boolean
28
+ diamond?: boolean
29
+ square?: boolean
30
+ circle?: boolean
31
+ parallelogram?: boolean
32
+ parallelogram2?: boolean
33
+ parallelogram3?: boolean
34
+ parallelogram4?: boolean
35
+ star?: boolean
36
+ star2?: boolean
37
+ triangle?: boolean
38
+ triangle2?: boolean
39
+ triangle3?: boolean
40
+ triangle4?: boolean
41
+
42
+ size?: 'lg' | 'md' | 'sm' | 'xs'
43
+ lg?: boolean
44
+ md?: boolean
45
+ sm?: boolean
46
+ xs?: boolean
47
+ }
48
+ const props = withDefaults(defineProps<Props>(), {
49
+ count: 5,
50
+ })
51
+ defineEmits(['update:modelValue'])
52
+
53
+ const shapes = [
54
+ 'squircle',
55
+ 'heart',
56
+ 'hexagon',
57
+ 'hexagon2',
58
+ 'decagon',
59
+ 'pentagon',
60
+ 'diamond',
61
+ 'square',
62
+ 'circle',
63
+ 'parallelogram',
64
+ 'parallelogram2',
65
+ 'parallelogram3',
66
+ 'parallelogram4',
67
+ 'star',
68
+ 'star2',
69
+ 'triangle',
70
+ 'triangle2',
71
+ 'triangle3',
72
+ 'triangle4',
73
+ ]
74
+
75
+ const ratingClasses = computed(() => {
76
+ return {
77
+ 'rating-half': props.half,
78
+ 'rating-lg': props.lg || props.size === 'lg',
79
+ 'rating-md': props.md || props.size === 'md',
80
+ 'rating-sm': props.sm || props.size === 'sm',
81
+ 'rating-xs': props.xs || props.size === 'xs',
82
+ }
83
+ })
84
+
85
+ const maskClasses = computed(() => {
86
+ const hasShape = shapes.reduce((acc, current) => {
87
+ return acc || props.shape || props[current]
88
+ }, false)
89
+ return {
90
+ 'bg-neutral': props.neutral || props.color === 'neutral',
91
+ 'bg-primary': props.primary || props.color === 'primary',
92
+ 'bg-secondary': props.secondary || props.color === 'secondary',
93
+ 'bg-accent': props.accent || props.color === 'accent',
94
+ 'bg-info': props.info || props.color === 'info',
95
+ 'bg-success': props.success || props.color === 'success',
96
+ 'bg-warning': props.warning || props.color === 'warning',
97
+ 'bg-error': props.error || props.color === 'error',
98
+
99
+ 'mask-squircle': props.squircle || props.shape === 'squircle',
100
+ 'mask-heart': props.heart || props.shape === 'heart',
101
+ 'mask-hexagon': props.hexagon || props.shape === 'hexagon',
102
+ 'mask-hexagon-2': props.hexagon2 || props.shape === 'hexagon-2',
103
+ 'mask-decagon': props.decagon || props.shape === 'decagon',
104
+ 'mask-pentagon': props.pentagon || props.shape === 'pentagon',
105
+ 'mask-diamond': props.diamond || props.shape === 'diamond',
106
+ 'mask-square': props.square || props.shape === 'square',
107
+ 'mask-circle': props.circle || props.shape === 'circle',
108
+ 'mask-parallelogram': props.parallelogram || props.shape === 'parallelogram',
109
+ 'mask-parallelogram-2': props.parallelogram2 || props.shape === 'parallelogram-2',
110
+ 'mask-parallelogram-3': props.parallelogram3 || props.shape === 'parallelogram-3',
111
+ 'mask-parallelogram-4': props.parallelogram4 || props.shape === 'parallelogram-4',
112
+ 'mask-star': props.star || props.shape === 'star',
113
+ 'mask-star-2': props.star2 || props.shape === 'star-2' || !hasShape,
114
+ 'mask-triangle': props.triangle || props.shape === 'triangle',
115
+ 'mask-triangle-2': props.triangle2 || props.shape === 'triangle-2',
116
+ 'mask-triangle-3': props.triangle3 || props.shape === 'triangle-3',
117
+ 'mask-triangle-4': props.triangle4 || props.shape === 'triangle-4',
118
+ }
119
+ })
120
+ const max = computed(() => parseInt(props.count as string))
121
+ </script>
122
+
123
+ <template>
124
+ <div class="rating" :class="ratingClasses">
125
+ <input
126
+ type="radio"
127
+ :value="0"
128
+ class="rating-hidden"
129
+ :checked="modelValue === 0"
130
+ @change="$emit('update:modelValue', 0)"
131
+ >
132
+ <template v-for="digit in max" :key="digit">
133
+ <input
134
+ type="radio"
135
+ :value="half ? digit - 0.5 : digit"
136
+ class="mask"
137
+ :class="[maskClasses, { 'mask-half-1': half }, bg]"
138
+ :checked="half ? modelValue == digit - 0.5 : modelValue == digit"
139
+ @change="$emit('update:modelValue', half ? digit - 0.5 : digit)"
140
+ >
141
+ <input
142
+ v-if="half"
143
+ type="radio"
144
+ :value="digit"
145
+ class="mask"
146
+ :class="[maskClasses, 'mask-half-2', bg]"
147
+ :checked="modelValue == digit"
148
+ @change="$emit('update:modelValue', digit)"
149
+ >
150
+ </template>
151
+ </div>
152
+ </template>
@@ -0,0 +1,104 @@
1
+ <script setup lang="ts">
2
+ import { computed, defineEmits, defineProps, withDefaults } from 'vue'
3
+
4
+ type Value = string | Record<string, any>
5
+ type Color =
6
+ | 'primary'
7
+ | 'secondary'
8
+ | 'accent'
9
+ | 'info'
10
+ | 'success'
11
+ | 'warning'
12
+ | 'error'
13
+ interface Props {
14
+ modelValue: any
15
+ options: Record<string, any>[] | any[]
16
+ value?: <T extends Value>(val: T) => keyof T
17
+ label?: <T extends Value>(val: T) => keyof T
18
+ resultAsObject?: boolean
19
+
20
+ bordered?: boolean
21
+ ghost?: boolean
22
+
23
+ color?: Color
24
+ primary?: boolean
25
+ secondary?: boolean
26
+ accent?: boolean
27
+ info?: boolean
28
+ success?: boolean
29
+ warning?: boolean
30
+ error?: boolean
31
+
32
+ size?: 'lg' | 'md' | 'sm' | 'xs'
33
+ lg?: boolean
34
+ md?: boolean
35
+ sm?: boolean
36
+ xs?: boolean
37
+ }
38
+
39
+ const props = withDefaults(defineProps<Props>(), {
40
+ value: <T extends Value>(val: T) => {
41
+ if (!val)
42
+ return null
43
+
44
+ return typeof val === 'string'
45
+ ? (val as string)
46
+ : val?.value || val?.id || val?._id
47
+ },
48
+ label: <T extends Value>(val: T) =>
49
+ typeof val === 'string'
50
+ ? (val as string)
51
+ : val.label || val.name || val.title,
52
+ resultAsObject: false,
53
+ })
54
+ const emit = defineEmits(['update:modelValue'])
55
+
56
+ const computedVModel = computed({
57
+ get: () => {
58
+ if (props.resultAsObject && props.modelValue != null)
59
+ return props.value(props.modelValue)
60
+
61
+ return props.modelValue
62
+ },
63
+ set: (val) => {
64
+ if (val === undefined) val = null
65
+ if (props.resultAsObject && val != null)
66
+ val = props.options.find(o => props.value(o) === val)
67
+
68
+ emit('update:modelValue', val)
69
+ },
70
+ })
71
+
72
+ const classes = computed(() => {
73
+ return {
74
+ 'select-primary': props.primary || props.color === 'primary',
75
+ 'select-secondary': props.secondary || props.color === 'secondary',
76
+ 'select-accent': props.accent || props.color === 'accent',
77
+ 'select-info': props.info || props.color === 'info',
78
+ 'select-success': props.success || props.color === 'success',
79
+ 'select-warning': props.warning || props.color === 'warning',
80
+ 'select-error': props.error || props.color === 'error',
81
+
82
+ 'select-lg': props.lg || props.size === 'lg',
83
+ 'select-md': props.md || props.size === 'md',
84
+ 'select-sm': props.sm || props.size === 'sm',
85
+ 'select-xs': props.xs || props.size === 'xs',
86
+
87
+ 'select-bordered': props.bordered,
88
+ 'select-ghost': props.ghost,
89
+ }
90
+ })
91
+ </script>
92
+
93
+ <template>
94
+ <select v-model="computedVModel" class="select" :class="classes">
95
+ <option
96
+ v-for="option in options"
97
+ :key="value(option)"
98
+ :value="value(option)"
99
+ :disabled="option.disabled"
100
+ >
101
+ {{ label(option) }}
102
+ </option>
103
+ </select>
104
+ </template>