adata-ui 2.1.40-beta → 2.1.40-beta.2

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.
@@ -0,0 +1,229 @@
1
+ <script setup lang="ts">
2
+ type Size = 'sm' | 'md' | 'lg'
3
+ type Side = 'left' | 'right'
4
+ type View = 'checkbox' | 'chip'
5
+
6
+ const props = withDefaults(defineProps<{
7
+ value?: string | number | boolean | Record<string, unknown> | null
8
+ view?: View
9
+ size?: Size
10
+ side?: Side
11
+ intermediate?: boolean
12
+ disabled?: boolean
13
+ name?: string
14
+ label?: string
15
+ }>(), {
16
+ value: null,
17
+ view: 'checkbox',
18
+ size: 'md',
19
+ side: 'right',
20
+ intermediate: false,
21
+ disabled: false,
22
+ })
23
+
24
+ const modelValue = defineModel<boolean | unknown[]>({ required: true })
25
+
26
+ const slots = useSlots()
27
+
28
+ const isChecked = computed(() => {
29
+ const v = modelValue.value
30
+ if (Array.isArray(v)) return v.includes(props.value as never)
31
+ return v === true
32
+ })
33
+
34
+ const ariaChecked = computed<'true' | 'false' | 'mixed'>(() => {
35
+ if (props.intermediate) return 'mixed'
36
+ return isChecked.value ? 'true' : 'false'
37
+ })
38
+
39
+ const hasLabel = computed(() => Boolean(props.label) || Boolean(slots.default?.().length))
40
+
41
+ function toggle() {
42
+ if (props.disabled) return
43
+
44
+ const current = modelValue.value
45
+ if (Array.isArray(current)) {
46
+ const next = [...current]
47
+ const idx = next.indexOf(props.value as never)
48
+ if (idx === -1) next.push(props.value as never)
49
+ else next.splice(idx, 1)
50
+ modelValue.value = next
51
+ }
52
+ else {
53
+ modelValue.value = !current
54
+ }
55
+ }
56
+
57
+ const gapClass = computed(() => {
58
+ switch (props.size) {
59
+ case 'sm': return 'gap-1.5'
60
+ case 'lg': return 'gap-2.5'
61
+ default: return 'gap-2'
62
+ }
63
+ })
64
+
65
+ const textClass = computed(() => {
66
+ switch (props.size) {
67
+ case 'sm': return 'text-xs'
68
+ case 'lg': return 'text-base'
69
+ default: return 'text-sm'
70
+ }
71
+ })
72
+
73
+ const squareSizeClass = computed(() => {
74
+ switch (props.size) {
75
+ case 'sm': return 'size-4'
76
+ case 'lg': return 'size-6'
77
+ default: return 'size-[18px]'
78
+ }
79
+ })
80
+
81
+ const isActive = computed(() => isChecked.value || props.intermediate)
82
+
83
+ const squareClass = computed(() => {
84
+ const base = [
85
+ 'checkbox-square inline-flex shrink-0 items-center justify-center rounded-md border transition-colors duration-150',
86
+ squareSizeClass.value,
87
+ ]
88
+
89
+ if (isActive.value) {
90
+ base.push('border-transparent bg-blue-700 text-white dark:bg-blue-500')
91
+ }
92
+ else {
93
+ base.push('border-gray-300 bg-white text-transparent dark:border-gray-600 dark:bg-white/[0.04]')
94
+ if (!props.disabled) {
95
+ base.push('group-hover/cb:border-blue-500 dark:group-hover/cb:border-blue-400')
96
+ }
97
+ }
98
+
99
+ return base.join(' ')
100
+ })
101
+
102
+ const chipClass = computed(() => {
103
+ const base = [
104
+ 'inline-flex items-center rounded-full border px-3 py-1 text-xs transition-colors duration-150',
105
+ ]
106
+
107
+ if (isActive.value) {
108
+ base.push('border-transparent bg-blue-700 text-white dark:bg-blue-500 dark:text-gray-900')
109
+ }
110
+ else {
111
+ base.push('border-gray-300 bg-transparent text-gray-700 dark:border-gray-600 dark:text-gray-300')
112
+ if (!props.disabled) {
113
+ base.push('group-hover/cb:border-gray-400 dark:group-hover/cb:border-gray-500')
114
+ }
115
+ }
116
+
117
+ return base.join(' ')
118
+ })
119
+
120
+ const labelClass = computed(() => `${textClass.value} leading-none text-deepblue-900 dark:text-gray-200`)
121
+
122
+ const rootClass = computed(() => {
123
+ const base = [
124
+ 'checkbox-v2 group/cb inline-flex items-center select-none rounded transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900',
125
+ ]
126
+
127
+ if (props.view === 'checkbox') {
128
+ base.push(gapClass.value)
129
+ }
130
+
131
+ if (props.disabled) {
132
+ base.push('cursor-not-allowed opacity-50')
133
+ }
134
+ else {
135
+ base.push('cursor-pointer')
136
+ }
137
+
138
+ return base.join(' ')
139
+ })
140
+ </script>
141
+
142
+ <template>
143
+ <button
144
+ type="button"
145
+ role="checkbox"
146
+ :aria-checked="ariaChecked"
147
+ :aria-disabled="disabled || undefined"
148
+ :disabled="disabled"
149
+ :name="name"
150
+ :class="rootClass"
151
+ @click="toggle"
152
+ @keydown.space.prevent="toggle"
153
+ >
154
+ <template v-if="view === 'checkbox'">
155
+ <span v-if="side === 'left' && hasLabel" :class="labelClass">
156
+ <slot>{{ label }}</slot>
157
+ </span>
158
+
159
+ <span :class="squareClass">
160
+ <svg
161
+ v-if="intermediate"
162
+ class="checkbox-intermediate size-3/4"
163
+ viewBox="0 0 16 16"
164
+ fill="none"
165
+ stroke="currentColor"
166
+ aria-hidden="true"
167
+ >
168
+ <line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round" />
169
+ </svg>
170
+ <svg
171
+ v-else-if="isChecked"
172
+ class="checkbox-check size-3/4"
173
+ viewBox="0 0 16 16"
174
+ fill="none"
175
+ stroke="currentColor"
176
+ aria-hidden="true"
177
+ >
178
+ <path
179
+ d="M3 8.5 L6.5 12 L13 4.5"
180
+ stroke-width="2"
181
+ stroke-linecap="round"
182
+ stroke-linejoin="round"
183
+ />
184
+ </svg>
185
+ </span>
186
+
187
+ <span v-if="side === 'right' && hasLabel" :class="labelClass">
188
+ <slot>{{ label }}</slot>
189
+ </span>
190
+ </template>
191
+
192
+ <span v-else :class="chipClass">
193
+ <slot>{{ label }}</slot>
194
+ </span>
195
+ </button>
196
+ </template>
197
+
198
+ <style scoped lang="scss">
199
+ .checkbox-check path {
200
+ stroke-dasharray: 22;
201
+ stroke-dashoffset: 22;
202
+ animation: check-draw 220ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
203
+ }
204
+
205
+ .checkbox-intermediate line {
206
+ stroke-dasharray: 14;
207
+ stroke-dashoffset: 14;
208
+ animation: check-draw 160ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
209
+ }
210
+
211
+ @keyframes check-draw {
212
+ to {
213
+ stroke-dashoffset: 0;
214
+ }
215
+ }
216
+
217
+ @media (prefers-reduced-motion: reduce) {
218
+ .checkbox-check path,
219
+ .checkbox-intermediate line {
220
+ animation: none;
221
+ stroke-dashoffset: 0;
222
+ }
223
+
224
+ .checkbox-v2,
225
+ .checkbox-square {
226
+ transition: none;
227
+ }
228
+ }
229
+ </style>