@byyuurin/ui 0.0.9 → 0.0.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.
- package/README.md +0 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/app/injections.d.ts +9299 -3
- package/dist/runtime/app/injections.js +35 -0
- package/dist/runtime/components/Accordion.vue +16 -20
- package/dist/runtime/components/Alert.vue +1 -1
- package/dist/runtime/components/Badge.vue +1 -1
- package/dist/runtime/components/Breadcrumb.vue +17 -21
- package/dist/runtime/components/Calendar.vue +15 -6
- package/dist/runtime/components/Carousel.vue +5 -3
- package/dist/runtime/components/Checkbox.vue +12 -7
- package/dist/runtime/components/Drawer.vue +12 -12
- package/dist/runtime/components/DropdownMenu.vue +143 -0
- package/dist/runtime/components/DropdownMenuContent.vue +188 -0
- package/dist/runtime/components/Form.vue +311 -0
- package/dist/runtime/components/FormItem.vue +129 -0
- package/dist/runtime/components/Input.vue +27 -13
- package/dist/runtime/components/InputNumber.vue +22 -14
- package/dist/runtime/components/Link.vue +17 -2
- package/dist/runtime/components/Modal.vue +11 -11
- package/dist/runtime/components/PinInput.vue +22 -13
- package/dist/runtime/components/Popover.vue +3 -3
- package/dist/runtime/components/RadioGroup.vue +50 -46
- package/dist/runtime/components/Select.vue +90 -80
- package/dist/runtime/components/Slider.vue +12 -7
- package/dist/runtime/components/Switch.vue +12 -6
- package/dist/runtime/components/Table.vue +21 -8
- package/dist/runtime/components/Tabs.vue +12 -11
- package/dist/runtime/components/Textarea.vue +19 -13
- package/dist/runtime/components/Toast.vue +6 -3
- package/dist/runtime/components/Tooltip.vue +3 -3
- package/dist/runtime/composables/useFormItem.d.ts +27 -0
- package/dist/runtime/composables/useFormItem.js +64 -0
- package/dist/runtime/composables/useTheme.js +2 -1
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/theme/app.d.ts +1 -0
- package/dist/runtime/theme/app.js +2 -1
- package/dist/runtime/theme/badge.d.ts +21 -45
- package/dist/runtime/theme/breadcrumb.d.ts +3 -3
- package/dist/runtime/theme/button.d.ts +111 -57
- package/dist/runtime/theme/calendar.d.ts +2 -2
- package/dist/runtime/theme/chip.d.ts +11 -44
- package/dist/runtime/theme/drawer.d.ts +68 -33
- package/dist/runtime/theme/dropdown-menu.d.ts +71 -0
- package/dist/runtime/theme/dropdown-menu.js +83 -0
- package/dist/runtime/theme/form-item.d.ts +76 -0
- package/dist/runtime/theme/form-item.js +34 -0
- package/dist/runtime/theme/form.d.ts +8 -0
- package/dist/runtime/theme/form.js +7 -0
- package/dist/runtime/theme/index.d.ts +3 -0
- package/dist/runtime/theme/index.js +3 -0
- package/dist/runtime/theme/input-number.d.ts +41 -61
- package/dist/runtime/theme/input.d.ts +99 -71
- package/dist/runtime/theme/input.js +2 -2
- package/dist/runtime/theme/modal.d.ts +5 -33
- package/dist/runtime/theme/pinInput.d.ts +42 -42
- package/dist/runtime/theme/pinInput.js +1 -1
- package/dist/runtime/theme/progress.d.ts +117 -53
- package/dist/runtime/theme/select.d.ts +100 -84
- package/dist/runtime/theme/select.js +2 -1
- package/dist/runtime/theme/separator.d.ts +13 -28
- package/dist/runtime/theme/table.d.ts +3 -0
- package/dist/runtime/theme/table.js +2 -1
- package/dist/runtime/theme/tabs.d.ts +51 -68
- package/dist/runtime/theme/textarea.d.ts +37 -43
- package/dist/runtime/theme/textarea.js +1 -1
- package/dist/runtime/theme/toast-provider.d.ts +26 -41
- package/dist/runtime/types/components.d.ts +3 -0
- package/dist/runtime/types/form.d.ts +45 -0
- package/dist/runtime/types/form.js +0 -0
- package/dist/runtime/types/index.d.ts +5 -2
- package/dist/runtime/types/index.js +1 -0
- package/dist/runtime/types/utils.d.ts +32 -11
- package/dist/runtime/utils/extend-theme.js +15 -4
- package/dist/runtime/utils/form.d.ts +5 -0
- package/dist/runtime/utils/form.js +24 -0
- package/dist/runtime/utils/index.d.ts +2 -0
- package/dist/runtime/utils/index.js +4 -0
- package/dist/runtime/utils/link.d.ts +4 -26
- package/dist/runtime/utils/link.js +10 -3
- package/dist/shared/ui.3e7fad19.mjs +5 -0
- package/dist/shared/ui.3e7fad19.mjs.map +1 -0
- package/dist/unocss.mjs +2 -2
- package/dist/unocss.mjs.map +1 -1
- package/dist/unplugin.mjs +1 -1
- package/dist/vite.mjs +1 -1
- package/package.json +16 -14
- package/dist/shared/ui.1a1f119c.mjs +0 -5
- package/dist/shared/ui.1a1f119c.mjs.map +0 -1
|
@@ -1,33 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
-
import type {
|
|
3
|
+
import type { SelectArrowProps, SelectContentEmits, SelectContentProps, SelectRootEmits, SelectRootProps } from 'reka-ui'
|
|
4
4
|
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
5
5
|
import type { select } from '../theme'
|
|
6
|
-
import type { ComponentAttrs,
|
|
6
|
+
import type { AcceptableValue, ArrayOrNested, ComponentAttrs, EmitsToProps, GetItemKeys, GetItemValue, GetModelValue, GetModelValueEmits, MaybeArray, NestedItem } from '../types'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
(event: 'update:open', value: boolean): void
|
|
10
|
-
(event: 'update:modelValue', payload: SelectModelValue<T, V, M, T extends { value: infer U } ? U : never>): void
|
|
11
|
-
(event: 'change', payload: Event): void
|
|
12
|
-
(event: 'blur', payload: FocusEvent): void
|
|
13
|
-
(event: 'focus', payload: FocusEvent): void
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type SlotProps<T> = (props: { item: T, index: number }) => any
|
|
17
|
-
|
|
18
|
-
export interface SelectSlots<T, M extends boolean> {
|
|
19
|
-
'leading'?: (props: { modelValue?: M extends true ? AcceptableValue[] : AcceptableValue, open: boolean, ui: ComponentAttrs<typeof select>['ui'] }) => any
|
|
20
|
-
'default'?: (props: { modelValue?: M extends true ? AcceptableValue[] : AcceptableValue, open: boolean }) => any
|
|
21
|
-
'trailing'?: (props: { modelValue?: M extends true ? AcceptableValue[] : AcceptableValue, open: boolean, ui: ComponentAttrs<typeof select>['ui'] }) => any
|
|
22
|
-
'item'?: SlotProps<T>
|
|
23
|
-
'item-leading'?: SlotProps<T>
|
|
24
|
-
'item-label'?: SlotProps<T>
|
|
25
|
-
'item-trailing'?: SlotProps<T>
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type SelectVariants = VariantProps<typeof select>
|
|
29
|
-
|
|
30
|
-
export interface SelectOption {
|
|
8
|
+
interface SelectItemBase {
|
|
31
9
|
label?: string
|
|
32
10
|
icon?: string
|
|
33
11
|
/**
|
|
@@ -35,18 +13,43 @@ export interface SelectOption {
|
|
|
35
13
|
* @default "option"
|
|
36
14
|
*/
|
|
37
15
|
type?: 'label' | 'separator' | 'option'
|
|
38
|
-
value?:
|
|
16
|
+
value?: AcceptableValue
|
|
39
17
|
disabled?: boolean
|
|
18
|
+
[key: string]: any
|
|
40
19
|
}
|
|
41
20
|
|
|
42
|
-
export type
|
|
21
|
+
export type SelectItem = SelectItemBase | AcceptableValue | boolean
|
|
22
|
+
|
|
23
|
+
export type SelectEmits<T extends ArrayOrNested<SelectItem>, VK extends GetItemKeys<T> | undefined, M extends boolean> = Omit<SelectRootEmits, 'update:modelValue'> & {
|
|
24
|
+
change: [payload: Event]
|
|
25
|
+
blur: [payload: FocusEvent]
|
|
26
|
+
focus: [payload: FocusEvent]
|
|
27
|
+
} & GetModelValueEmits<T, VK, M>
|
|
28
|
+
|
|
29
|
+
type SlotProps<T extends SelectItem> = (props: { item: T, index: number }) => any
|
|
30
|
+
|
|
31
|
+
export interface SelectSlots<
|
|
32
|
+
T extends ArrayOrNested<SelectItem> = ArrayOrNested<SelectItem>,
|
|
33
|
+
VK extends GetItemKeys<T> | undefined = undefined,
|
|
34
|
+
M extends boolean = false,
|
|
35
|
+
I extends NestedItem<T> = NestedItem<T>,
|
|
36
|
+
> {
|
|
37
|
+
'leading'?: (props: { modelValue?: GetModelValue<T, VK, M>, open: boolean, ui: ComponentAttrs<typeof select>['ui'] }) => any
|
|
38
|
+
'default'?: (props: { modelValue?: GetModelValue<T, VK, M>, open: boolean }) => any
|
|
39
|
+
'trailing'?: (props: { modelValue?: GetModelValue<T, VK, M>, open: boolean, ui: ComponentAttrs<typeof select>['ui'] }) => any
|
|
40
|
+
'item'?: SlotProps<I>
|
|
41
|
+
'item-leading'?: SlotProps<I>
|
|
42
|
+
'item-label'?: SlotProps<I>
|
|
43
|
+
'item-trailing'?: SlotProps<I>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type SelectVariants = VariantProps<typeof select>
|
|
43
47
|
|
|
44
48
|
export interface SelectProps<
|
|
45
|
-
T extends
|
|
46
|
-
|
|
47
|
-
V extends SelectOptionKey<T> | undefined = undefined,
|
|
49
|
+
T extends ArrayOrNested<SelectItem> = ArrayOrNested<SelectItem>,
|
|
50
|
+
VK extends GetItemKeys<T> = 'value',
|
|
48
51
|
M extends boolean = false,
|
|
49
|
-
> extends Omit<SelectRootProps<T>, 'dir' | 'multiple' | 'modelValue' | 'defaultValue' | 'by'
|
|
52
|
+
> extends ComponentAttrs<typeof select>, UseComponentIconsProps, Omit<SelectRootProps<T>, 'dir' | 'multiple' | 'modelValue' | 'defaultValue' | 'by'> {
|
|
50
53
|
id?: string
|
|
51
54
|
/** The placeholder text when the select is empty. */
|
|
52
55
|
placeholder?: string
|
|
@@ -66,7 +69,7 @@ export interface SelectProps<
|
|
|
66
69
|
* The content of the menu.
|
|
67
70
|
* @default { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
|
|
68
71
|
*/
|
|
69
|
-
content?: Omit<SelectContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
72
|
+
content?: Omit<SelectContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<SelectContentEmits>>
|
|
70
73
|
/**
|
|
71
74
|
* Display an arrow alongside the menu.
|
|
72
75
|
* @default false
|
|
@@ -81,17 +84,17 @@ export interface SelectProps<
|
|
|
81
84
|
* When `options` is an array of objects, select the field to use as the value.
|
|
82
85
|
* @default "value"
|
|
83
86
|
*/
|
|
84
|
-
valueKey?:
|
|
87
|
+
valueKey?: VK
|
|
85
88
|
/**
|
|
86
89
|
* When `options` is an array of objects, select the field to use as the label.
|
|
87
90
|
* @default "label"
|
|
88
91
|
*/
|
|
89
|
-
labelKey?:
|
|
90
|
-
options?:
|
|
92
|
+
labelKey?: VK
|
|
93
|
+
options?: T
|
|
91
94
|
/** The value of the Select when initially rendered. Use when you do not need to control the state of the Select. */
|
|
92
|
-
defaultValue?:
|
|
95
|
+
defaultValue?: GetModelValue<T, VK, M>
|
|
93
96
|
/** The controlled value of the Select. Can be bind as `v-model`. */
|
|
94
|
-
modelValue?:
|
|
97
|
+
modelValue?: GetModelValue<T, VK, M>
|
|
95
98
|
/** Whether multiple options can be selected or not. */
|
|
96
99
|
multiple?: M & boolean
|
|
97
100
|
/** Highlight the ring color like a focus state. */
|
|
@@ -100,82 +103,89 @@ export interface SelectProps<
|
|
|
100
103
|
}
|
|
101
104
|
</script>
|
|
102
105
|
|
|
103
|
-
<script lang="ts" setup generic="T extends
|
|
106
|
+
<script lang="ts" setup generic="T extends ArrayOrNested<SelectItem>, VK extends GetItemKeys<T> = 'value', M extends boolean = false">
|
|
104
107
|
import { reactivePick } from '@vueuse/core'
|
|
105
108
|
import { defu } from 'defu'
|
|
106
109
|
import { SelectArrow, SelectContent, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectSeparator, SelectTrigger, SelectViewport, useForwardPropsEmits } from 'reka-ui'
|
|
107
110
|
import { computed, toRef } from 'vue'
|
|
108
111
|
import { useButtonGroup } from '../composables/useButtonGroup'
|
|
109
112
|
import { useComponentIcons } from '../composables/useComponentIcons'
|
|
113
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
110
114
|
import { useTheme } from '../composables/useTheme'
|
|
111
|
-
import { compare, get } from '../utils'
|
|
115
|
+
import { compare, get, isArrayOfArray } from '../utils'
|
|
112
116
|
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
defineOptions({
|
|
118
|
+
inheritAttrs: false,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const props = withDefaults(defineProps<SelectProps<T, VK, M>>(), {
|
|
115
122
|
valueKey: 'value' as never,
|
|
116
123
|
labelKey: 'label' as never,
|
|
117
124
|
portal: true,
|
|
118
125
|
})
|
|
119
126
|
|
|
120
|
-
const emit = defineEmits<SelectEmits<T,
|
|
121
|
-
const slots = defineSlots<SelectSlots<T, M>>()
|
|
127
|
+
const emit = defineEmits<SelectEmits<T, VK, M>>()
|
|
128
|
+
const slots = defineSlots<SelectSlots<T, VK, M>>()
|
|
122
129
|
|
|
123
130
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emit)
|
|
124
131
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as SelectContentProps)
|
|
125
132
|
const arrowProps = toRef(() => props.arrow as SelectArrowProps)
|
|
126
133
|
|
|
127
|
-
const {
|
|
134
|
+
const { id, name, size: formItemSize, highlight, disabled, ariaAttrs, emitFormChange, emitFormInput, emitFormBlur, emitFormFocus } = useFormItem<SelectProps<T, VK, M>>(props)
|
|
135
|
+
const { size: buttonGroupSize, orientation } = useButtonGroup(props)
|
|
128
136
|
|
|
129
|
-
const {
|
|
137
|
+
const { theme, generateStyle } = useTheme()
|
|
130
138
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, {
|
|
131
139
|
trailingIcon: theme.value.app.icons.chevronDown,
|
|
132
140
|
})))
|
|
133
141
|
|
|
134
142
|
const style = computed(() => generateStyle('select', {
|
|
135
143
|
...props,
|
|
136
|
-
size: size.value,
|
|
137
144
|
groupOrientation: orientation.value,
|
|
145
|
+
size: buttonGroupSize.value || formItemSize.value,
|
|
146
|
+
highlight: highlight.value,
|
|
138
147
|
leading: isLeading.value,
|
|
139
148
|
trailing: isTrailing.value,
|
|
140
149
|
}))
|
|
141
150
|
|
|
142
|
-
const groups = computed
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
151
|
+
const groups = computed<SelectItem[][]>(
|
|
152
|
+
() => props.options?.length
|
|
153
|
+
? isArrayOfArray(props.options) ? props.options : [props.options]
|
|
154
|
+
: [],
|
|
155
|
+
)
|
|
148
156
|
|
|
149
|
-
|
|
150
|
-
return value as unknown as M extends true ? AcceptableValue[] : AcceptableValue
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function typedModelValue(value: any) {
|
|
154
|
-
return value as MaybeArray<AcceptableValue> | undefined
|
|
155
|
-
}
|
|
157
|
+
const items = computed(() => groups.value.flat() as T[])
|
|
156
158
|
|
|
157
|
-
function displayValue(value?: MaybeArray<
|
|
159
|
+
function displayValue(value?: MaybeArray<GetItemValue<T, VK>>): string {
|
|
158
160
|
if (props.multiple && Array.isArray(value))
|
|
159
161
|
return value.map((v) => displayValue(v)).filter(Boolean).join(', ')
|
|
160
162
|
|
|
161
163
|
const item = items.value.find((item) => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
|
|
162
|
-
return (item != null) && (typeof item === 'object' ? get(item, props.labelKey as string) : item
|
|
164
|
+
return (item != null) && (typeof item === 'object' ? get(item, props.labelKey as string) : String(item))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function isSelectItem(item: SelectItem): item is SelectItemBase {
|
|
168
|
+
return typeof item === 'object' && item !== null
|
|
163
169
|
}
|
|
164
170
|
|
|
165
171
|
function onUpdate(value: any) {
|
|
166
172
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
167
173
|
const event = new Event('change', { target: { value } })
|
|
168
174
|
emit('change', event)
|
|
175
|
+
emitFormChange()
|
|
176
|
+
emitFormInput()
|
|
169
177
|
}
|
|
170
178
|
|
|
171
179
|
function onUpdateOpen(value: boolean) {
|
|
172
180
|
if (value) {
|
|
173
181
|
const event = new FocusEvent('focus')
|
|
174
182
|
emit('focus', event)
|
|
183
|
+
emitFormFocus()
|
|
175
184
|
}
|
|
176
185
|
else {
|
|
177
186
|
const event = new FocusEvent('blur')
|
|
178
187
|
emit('blur', event)
|
|
188
|
+
emitFormBlur()
|
|
179
189
|
}
|
|
180
190
|
}
|
|
181
191
|
</script>
|
|
@@ -183,24 +193,24 @@ function onUpdateOpen(value: boolean) {
|
|
|
183
193
|
<template>
|
|
184
194
|
<SelectRoot
|
|
185
195
|
v-slot="{ modelValue: innerValue, open }"
|
|
186
|
-
:name="props.name"
|
|
187
196
|
v-bind="rootProps"
|
|
197
|
+
:name="name"
|
|
188
198
|
:autocomplete="props.autocomplete"
|
|
189
|
-
:disabled="
|
|
190
|
-
:default-value="
|
|
191
|
-
:model-value="
|
|
199
|
+
:disabled="disabled"
|
|
200
|
+
:default-value="(props.defaultValue as MaybeArray<AcceptableValue>)"
|
|
201
|
+
:model-value="(props.modelValue as MaybeArray<AcceptableValue>)"
|
|
192
202
|
@update:model-value="onUpdate"
|
|
193
203
|
@update:open="onUpdateOpen"
|
|
194
204
|
>
|
|
195
|
-
<SelectTrigger
|
|
205
|
+
<SelectTrigger v-bind="{ ...$attrs, ...ariaAttrs, id }" :class="style.base({ class: [props.class, props.ui?.base] })">
|
|
196
206
|
<span v-if="isLeading || slots.leading" :class="style.leading({ class: props.ui?.leading })">
|
|
197
|
-
<slot name="leading" :model-value="
|
|
207
|
+
<slot name="leading" :model-value="(innerValue as GetModelValue<T, VK, M>)" :open="open" :ui="props.ui">
|
|
198
208
|
<span v-if="isLeading && leadingIconName" :class="style.leadingIcon({ class: [leadingIconName, props.ui?.leadingIcon] })"></span>
|
|
199
209
|
</slot>
|
|
200
210
|
</span>
|
|
201
211
|
|
|
202
|
-
<slot :model-value="
|
|
203
|
-
<template v-for="displayedModelValue in [displayValue(innerValue)]" :key="displayedModelValue">
|
|
212
|
+
<slot :model-value="(innerValue as GetModelValue<T, VK, M>)" :open="open">
|
|
213
|
+
<template v-for="displayedModelValue in [displayValue((innerValue as GetModelValue<T, VK, M>))]" :key="displayedModelValue">
|
|
204
214
|
<span v-if="displayedModelValue" :class="style.value({ class: props.ui?.value })">
|
|
205
215
|
{{ displayedModelValue }}
|
|
206
216
|
</span>
|
|
@@ -211,7 +221,7 @@ function onUpdateOpen(value: boolean) {
|
|
|
211
221
|
</slot>
|
|
212
222
|
|
|
213
223
|
<span v-if="isTrailing || !!slots.trailing" :class="style.trailing({ class: props.ui?.trailing })">
|
|
214
|
-
<slot name="trailing" :model-value="
|
|
224
|
+
<slot name="trailing" :model-value="(innerValue as GetModelValue<T, VK, M>)" :open="open" :ui="props.ui">
|
|
215
225
|
<span v-if="trailingIconName" :class="style.trailingIcon({ class: [trailingIconName, props.ui?.trailingIcon] })"></span>
|
|
216
226
|
</slot>
|
|
217
227
|
</span>
|
|
@@ -222,30 +232,30 @@ function onUpdateOpen(value: boolean) {
|
|
|
222
232
|
<SelectViewport :class="style.viewport({ class: props.ui?.viewport })">
|
|
223
233
|
<SelectGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="style.group({ class: props.ui?.group })">
|
|
224
234
|
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
|
225
|
-
<SelectLabel v-if="item.type === 'label'" :class="style.label({ class: props.ui?.label })">
|
|
235
|
+
<SelectLabel v-if="isSelectItem(item) && item.type === 'label'" :class="style.label({ class: props.ui?.label })">
|
|
226
236
|
{{ get(item, props.labelKey as string) }}
|
|
227
237
|
</SelectLabel>
|
|
228
|
-
<SelectSeparator v-else-if="item.type === 'separator'" :class="style.separator({ class: props.ui?.separator })" />
|
|
238
|
+
<SelectSeparator v-else-if="isSelectItem(item) && item.type === 'separator'" :class="style.separator({ class: props.ui?.separator })" />
|
|
229
239
|
|
|
230
240
|
<SelectItem
|
|
231
241
|
v-else
|
|
232
242
|
:class="style.item({ class: props.ui?.item })"
|
|
233
|
-
:disabled="item.disabled"
|
|
234
|
-
:value="
|
|
243
|
+
:disabled="isSelectItem(item) && item.disabled"
|
|
244
|
+
:value="isSelectItem(item) ? get(item, props.valueKey as string) : item"
|
|
235
245
|
>
|
|
236
|
-
<slot name="item" :item="
|
|
237
|
-
<slot name="item-leading" :item="
|
|
238
|
-
<span v-if="item.icon" :class="style.itemLeadingIcon({ class: [item.icon, props.ui?.itemLeadingIcon] })"></span>
|
|
246
|
+
<slot name="item" :item="(item as NestedItem<T>)" :index="index">
|
|
247
|
+
<slot name="item-leading" :item="(item as NestedItem<T>)" :index="index">
|
|
248
|
+
<span v-if="isSelectItem(item) && item.icon" :class="style.itemLeadingIcon({ class: [item.icon, props.ui?.itemLeadingIcon] })"></span>
|
|
239
249
|
</slot>
|
|
240
250
|
|
|
241
251
|
<SelectItemText :class="style.itemLabel({ class: props.ui?.itemLabel })">
|
|
242
|
-
<slot name="item-label" :item="
|
|
243
|
-
{{
|
|
252
|
+
<slot name="item-label" :item="(item as NestedItem<T>)" :index="index">
|
|
253
|
+
{{ isSelectItem(item) ? get(item, props.labelKey as string) : item }}
|
|
244
254
|
</slot>
|
|
245
255
|
</SelectItemText>
|
|
246
256
|
|
|
247
257
|
<span :class="style.itemTrailing({ class: props.ui?.itemTrailing })">
|
|
248
|
-
<slot name="item-trailing" :item="
|
|
258
|
+
<slot name="item-trailing" :item="(item as NestedItem<T>)" :index="index"></slot>
|
|
249
259
|
|
|
250
260
|
<SelectItemIndicator as-child>
|
|
251
261
|
<span :class="style.itemTrailingIcon({ class: [props.selectedIcon || theme.app.icons.check, props.ui?.itemTrailingIcon] })"></span>
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
3
|
import type { SliderRootProps } from 'reka-ui'
|
|
4
4
|
import type { slider } from '../theme'
|
|
5
|
-
import type { ComponentAttrs } from '../types'
|
|
5
|
+
import type { ComponentAttrs, MaybeArray } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface SliderEmits {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
'update:modelValue': [payload: MaybeArray<number>]
|
|
9
|
+
'change': [payload: Event]
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
type SliderVariants = VariantProps<typeof slider>
|
|
@@ -28,6 +28,7 @@ export interface SliderProps extends ComponentAttrs<typeof slider>, Pick<SliderR
|
|
|
28
28
|
import { reactivePick } from '@vueuse/core'
|
|
29
29
|
import { SliderRange, SliderRoot, SliderThumb, SliderTrack, useForwardPropsEmits } from 'reka-ui'
|
|
30
30
|
import { computed } from 'vue'
|
|
31
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
31
32
|
import { useTheme } from '../composables/useTheme'
|
|
32
33
|
|
|
33
34
|
const props = withDefaults(defineProps<SliderProps>(), {
|
|
@@ -63,22 +64,26 @@ const sliderValue = computed({
|
|
|
63
64
|
|
|
64
65
|
const thumbsCount = computed(() => sliderValue.value?.length ?? 1)
|
|
65
66
|
|
|
67
|
+
const { id, size, name, disabled, ariaAttrs, emitFormChange, emitFormInput } = useFormItem<SliderProps>(props)
|
|
66
68
|
const { generateStyle } = useTheme()
|
|
67
|
-
const style = computed(() => generateStyle('slider',
|
|
69
|
+
const style = computed(() => generateStyle('slider', {
|
|
70
|
+
...props,
|
|
71
|
+
size: size.value,
|
|
72
|
+
}))
|
|
68
73
|
|
|
69
74
|
function onChange(value: any) {
|
|
70
75
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
71
76
|
const event = new Event('change', { target: { value } })
|
|
72
77
|
emit('change', event)
|
|
78
|
+
emitFormChange()
|
|
79
|
+
emitFormInput()
|
|
73
80
|
}
|
|
74
81
|
</script>
|
|
75
82
|
|
|
76
83
|
<template>
|
|
77
84
|
<SliderRoot
|
|
78
|
-
v-bind="rootProps"
|
|
85
|
+
v-bind="{ ...rootProps, ...ariaAttrs, id, name, disabled }"
|
|
79
86
|
v-model="sliderValue"
|
|
80
|
-
:name="props.name"
|
|
81
|
-
:disabled="props.disabled"
|
|
82
87
|
:class="style.root({ class: [props.class, props.ui?.root] })"
|
|
83
88
|
:default-value="defaultSliderValue"
|
|
84
89
|
:data-steps="thumbsCount"
|
|
@@ -5,7 +5,7 @@ import type { switch as _switch } from '../theme'
|
|
|
5
5
|
import type { ComponentAttrs } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface SwitchEmits {
|
|
8
|
-
|
|
8
|
+
change: [payload: Event]
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface SwitchSlots {
|
|
@@ -37,6 +37,7 @@ export interface SwitchProps extends ComponentAttrs<typeof _switch>, Pick<Switch
|
|
|
37
37
|
import { reactivePick } from '@vueuse/core'
|
|
38
38
|
import { Label, Primitive, SwitchRoot, SwitchThumb, useForwardProps } from 'reka-ui'
|
|
39
39
|
import { computed, useId } from 'vue'
|
|
40
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
40
41
|
import { useTheme } from '../composables/useTheme'
|
|
41
42
|
|
|
42
43
|
const props = withDefaults(defineProps<SwitchProps>(), {})
|
|
@@ -45,11 +46,15 @@ const slots = defineSlots<SwitchSlots>()
|
|
|
45
46
|
const modelValue = defineModel<boolean>({ default: undefined })
|
|
46
47
|
|
|
47
48
|
const rootProps = useForwardProps(reactivePick(props, 'required', 'value', 'defaultValue'))
|
|
48
|
-
|
|
49
|
+
|
|
50
|
+
const { id: _id, size, name, disabled, ariaAttrs, emitFormChange, emitFormInput } = useFormItem<SwitchProps>(props)
|
|
51
|
+
const id = _id.value ?? useId()
|
|
49
52
|
|
|
50
53
|
const { theme, generateStyle } = useTheme()
|
|
51
54
|
const style = computed(() => generateStyle('switch', {
|
|
52
55
|
...props,
|
|
56
|
+
size: size.value,
|
|
57
|
+
disabled: disabled.value,
|
|
53
58
|
checked: false,
|
|
54
59
|
unchecked: false,
|
|
55
60
|
}))
|
|
@@ -57,7 +62,10 @@ const style = computed(() => generateStyle('switch', {
|
|
|
57
62
|
function onUpdate(value: any) {
|
|
58
63
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
59
64
|
const event = new Event('change', { target: { value } })
|
|
65
|
+
|
|
60
66
|
emit('change', event)
|
|
67
|
+
emitFormChange()
|
|
68
|
+
emitFormInput()
|
|
61
69
|
}
|
|
62
70
|
</script>
|
|
63
71
|
|
|
@@ -65,12 +73,10 @@ function onUpdate(value: any) {
|
|
|
65
73
|
<Primitive :as="props.as" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
66
74
|
<div :class="style.container({ class: props.ui?.container })">
|
|
67
75
|
<SwitchRoot
|
|
68
|
-
|
|
69
|
-
v-bind="rootProps"
|
|
76
|
+
v-bind="{ ...rootProps, ...ariaAttrs, id, name }"
|
|
70
77
|
v-model="modelValue"
|
|
71
|
-
:name="props.name"
|
|
72
|
-
:disabled="props.disabled || props.loading"
|
|
73
78
|
:class="style.base({ class: props.ui?.base })"
|
|
79
|
+
:disabled="disabled || props.loading"
|
|
74
80
|
@update:model-value="onUpdate"
|
|
75
81
|
>
|
|
76
82
|
<SwitchThumb :class="style.thumb({ class: props.ui?.thumb })">
|
|
@@ -10,9 +10,10 @@ type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T
|
|
|
10
10
|
type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
|
|
11
11
|
|
|
12
12
|
export type TableSlots<T> = {
|
|
13
|
-
expanded
|
|
14
|
-
empty
|
|
15
|
-
|
|
13
|
+
expanded?: (props: { row: Row<T> }) => any
|
|
14
|
+
empty?: any
|
|
15
|
+
loading?: any
|
|
16
|
+
caption?: any
|
|
16
17
|
} & DynamicHeaderSlots<T> & DynamicCellSlots<T>
|
|
17
18
|
|
|
18
19
|
export type TableData = RowData
|
|
@@ -33,11 +34,18 @@ export interface TableProps<T extends TableData> extends ComponentAttrs<typeof t
|
|
|
33
34
|
data?: T[]
|
|
34
35
|
columns?: TableColumn<T>[]
|
|
35
36
|
caption?: string
|
|
37
|
+
/**
|
|
38
|
+
* The text to display when the table is empty.
|
|
39
|
+
* @default t('table.noData')
|
|
40
|
+
*/
|
|
41
|
+
empty?: string
|
|
36
42
|
/**
|
|
37
43
|
* Whether the table should have a sticky header.
|
|
38
44
|
* @default false
|
|
39
45
|
*/
|
|
40
46
|
sticky?: boolean
|
|
47
|
+
/** Whether the table should be in loading state. */
|
|
48
|
+
loading?: boolean
|
|
41
49
|
/**
|
|
42
50
|
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#table-options)
|
|
43
51
|
* @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)
|
|
@@ -111,8 +119,7 @@ import { useLocale } from '../composables/useLocale'
|
|
|
111
119
|
import { useTheme } from '../composables/useTheme'
|
|
112
120
|
|
|
113
121
|
const props = defineProps<TableProps<T>>()
|
|
114
|
-
|
|
115
|
-
defineSlots<TableSlots<T>>()
|
|
122
|
+
const slots = defineSlots<TableSlots<T>>()
|
|
116
123
|
|
|
117
124
|
const globalFilterState = defineModel<string>('globalFilter', { default: undefined })
|
|
118
125
|
const columnFiltersState = defineModel<ColumnFiltersState>('columnFilters', { default: [] })
|
|
@@ -137,7 +144,7 @@ const columns = computed<TableColumn<T>[]>(
|
|
|
137
144
|
)
|
|
138
145
|
|
|
139
146
|
const tableApi = useVueTable({
|
|
140
|
-
...reactiveOmit(props, 'data', 'columns', 'caption', 'sticky', 'class', 'ui'),
|
|
147
|
+
...reactiveOmit(props, 'data', 'columns', 'caption', 'sticky', 'loading', 'class', 'ui'),
|
|
141
148
|
data,
|
|
142
149
|
columns: columns.value,
|
|
143
150
|
getCoreRowModel: getCoreRowModel(),
|
|
@@ -240,7 +247,7 @@ defineExpose({
|
|
|
240
247
|
<template>
|
|
241
248
|
<Primitive :as="props.as" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
242
249
|
<table :class="style.base({ class: props.ui?.base })">
|
|
243
|
-
<caption v-if="props.caption" :class="style.caption({ class: props.caption })">
|
|
250
|
+
<caption v-if="props.caption || slots.caption" :class="style.caption({ class: props.caption })">
|
|
244
251
|
<slot name="caption">
|
|
245
252
|
{{ props.caption }}
|
|
246
253
|
</slot>
|
|
@@ -284,10 +291,16 @@ defineExpose({
|
|
|
284
291
|
</template>
|
|
285
292
|
</template>
|
|
286
293
|
|
|
294
|
+
<tr v-else-if="props.loading && slots.loading">
|
|
295
|
+
<td :colspan="columns.length" :class="style.loading({ class: props.ui?.loading })">
|
|
296
|
+
<slot name="loading"></slot>
|
|
297
|
+
</td>
|
|
298
|
+
</tr>
|
|
299
|
+
|
|
287
300
|
<tr v-else :class="style.tr({ class: props.ui?.tr })">
|
|
288
301
|
<td :colspan="columns.length" :class="style.empty({ class: props.ui?.empty })">
|
|
289
302
|
<slot name="empty">
|
|
290
|
-
{{ t('table.noData') }}
|
|
303
|
+
{{ props.empty || t('table.noData') }}
|
|
291
304
|
</slot>
|
|
292
305
|
</td>
|
|
293
306
|
</tr>
|
|
@@ -6,15 +6,6 @@ import type { ComponentAttrs, DynamicSlots } from '../types'
|
|
|
6
6
|
|
|
7
7
|
export interface TabsEmits extends TabsRootEmits<string | number> {}
|
|
8
8
|
|
|
9
|
-
type SlotProps<T> = (props: { item: T, index: number }) => any
|
|
10
|
-
|
|
11
|
-
export type TabsSlots<T extends { slot?: string }> = {
|
|
12
|
-
leading?: SlotProps<T>
|
|
13
|
-
default?: SlotProps<T>
|
|
14
|
-
trailing?: SlotProps<T>
|
|
15
|
-
content?: SlotProps<T>
|
|
16
|
-
} & DynamicSlots<T, SlotProps<T>>
|
|
17
|
-
|
|
18
9
|
export interface TabsItem {
|
|
19
10
|
label?: string
|
|
20
11
|
icon?: string
|
|
@@ -23,11 +14,21 @@ export interface TabsItem {
|
|
|
23
14
|
/** A unique value for the tab item. Defaults to the index. */
|
|
24
15
|
value?: string | number
|
|
25
16
|
disabled?: boolean
|
|
17
|
+
[key: string]: any
|
|
26
18
|
}
|
|
27
19
|
|
|
20
|
+
type SlotProps<T extends TabsItem> = (props: { item: T, index: number }) => any
|
|
21
|
+
|
|
22
|
+
export type TabsSlots<T extends TabsItem = TabsItem> = {
|
|
23
|
+
leading?: SlotProps<T>
|
|
24
|
+
default?: SlotProps<T>
|
|
25
|
+
trailing?: SlotProps<T>
|
|
26
|
+
content?: SlotProps<T>
|
|
27
|
+
} & DynamicSlots<T, undefined, SlotProps<T>>
|
|
28
|
+
|
|
28
29
|
type TabsVariants = VariantProps<typeof tabs>
|
|
29
30
|
|
|
30
|
-
export interface TabsProps<T> extends ComponentAttrs<typeof tabs>, Pick<TabsRootProps<string | number>, 'defaultValue' | 'modelValue' | 'activationMode' | 'unmountOnHide'> {
|
|
31
|
+
export interface TabsProps<T extends TabsItem = TabsItem> extends ComponentAttrs<typeof tabs>, Pick<TabsRootProps<string | number>, 'defaultValue' | 'modelValue' | 'activationMode' | 'unmountOnHide'> {
|
|
31
32
|
/**
|
|
32
33
|
* The element or component this component should render as.
|
|
33
34
|
* @default "div"
|
|
@@ -108,7 +109,7 @@ const style = computed(() => generateStyle('tabs', props))
|
|
|
108
109
|
:value="item.value || String(index)"
|
|
109
110
|
:class="style.content({ class: props.ui?.content })"
|
|
110
111
|
>
|
|
111
|
-
<slot :name="item.slot || 'content'" :item="item" :index="index">
|
|
112
|
+
<slot :name="((item.slot || 'content') as keyof TabsSlots<T>)" :item="(item as Extract<T, { slot: string }>)" :index="index">
|
|
112
113
|
{{ item.content }}
|
|
113
114
|
</slot>
|
|
114
115
|
</TabsContent>
|
|
@@ -5,9 +5,9 @@ import type { textarea } from '../theme'
|
|
|
5
5
|
import type { ComponentAttrs } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface TextareaEmits {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
'update:modelValue': [payload: string]
|
|
9
|
+
'blur': [event: FocusEvent]
|
|
10
|
+
'change': [event: Event]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface TextareaSlots {
|
|
@@ -41,7 +41,8 @@ export interface TextareaProps extends ComponentAttrs<typeof textarea> {
|
|
|
41
41
|
|
|
42
42
|
<script setup lang="ts">
|
|
43
43
|
import { Primitive } from 'reka-ui'
|
|
44
|
-
import { computed, nextTick, onMounted,
|
|
44
|
+
import { computed, nextTick, onMounted, useTemplateRef, watch } from 'vue'
|
|
45
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
45
46
|
import { useTheme } from '../composables/useTheme'
|
|
46
47
|
|
|
47
48
|
defineOptions({
|
|
@@ -59,10 +60,15 @@ const emit = defineEmits<TextareaEmits>()
|
|
|
59
60
|
defineSlots<TextareaSlots>()
|
|
60
61
|
const [modelValue, modelModifiers] = defineModel<string | number>()
|
|
61
62
|
|
|
62
|
-
const textareaRef =
|
|
63
|
+
const textareaRef = useTemplateRef('textareaRef')
|
|
63
64
|
|
|
65
|
+
const { id, name, size, highlight, disabled, ariaAttrs, emitFormInput, emitFormChange, emitFormBlur, emitFormFocus } = useFormItem<TextareaProps>(props)
|
|
64
66
|
const { generateStyle } = useTheme()
|
|
65
|
-
const style = computed(() => generateStyle('textarea',
|
|
67
|
+
const style = computed(() => generateStyle('textarea', {
|
|
68
|
+
...props,
|
|
69
|
+
size: size.value,
|
|
70
|
+
highlight: highlight.value,
|
|
71
|
+
}))
|
|
66
72
|
|
|
67
73
|
function autoFocus() {
|
|
68
74
|
if (props.autofocus)
|
|
@@ -74,6 +80,7 @@ function updateInput(value: string) {
|
|
|
74
80
|
value = value.trim()
|
|
75
81
|
|
|
76
82
|
modelValue.value = value
|
|
83
|
+
emitFormInput()
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
function onInput(event: Event) {
|
|
@@ -93,10 +100,12 @@ function onChange(event: Event) {
|
|
|
93
100
|
(event.target as HTMLInputElement).value = value.trim()
|
|
94
101
|
|
|
95
102
|
emit('change', event)
|
|
103
|
+
emitFormChange()
|
|
96
104
|
}
|
|
97
105
|
|
|
98
106
|
function onBlur(event: FocusEvent) {
|
|
99
107
|
emit('blur', event)
|
|
108
|
+
emitFormBlur()
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
function autoResize() {
|
|
@@ -144,23 +153,20 @@ onMounted(() => {
|
|
|
144
153
|
<Primitive
|
|
145
154
|
:as="props.as"
|
|
146
155
|
:class="style.root({ class: [props.class, props.ui?.root] })"
|
|
147
|
-
:aria-disabled="
|
|
156
|
+
:aria-disabled="disabled ? true : undefined"
|
|
148
157
|
>
|
|
149
158
|
<textarea
|
|
150
|
-
:id="props.id"
|
|
151
159
|
ref="textareaRef"
|
|
160
|
+
:class="style.base({ class: props.ui?.base })"
|
|
152
161
|
:value="modelValue"
|
|
153
|
-
:name="props.name"
|
|
154
162
|
:rows="props.rows"
|
|
155
163
|
:placeholder="props.placeholder"
|
|
156
|
-
:class="style.base({ class: props.ui?.base })"
|
|
157
|
-
:disabled="props.disabled"
|
|
158
164
|
:required="props.required"
|
|
159
|
-
v-bind="
|
|
165
|
+
v-bind="{ ...$attrs, ...ariaAttrs, id, name, disabled }"
|
|
160
166
|
@input="onInput"
|
|
161
167
|
@blur="onBlur"
|
|
162
168
|
@change="onChange"
|
|
163
|
-
@focus="
|
|
169
|
+
@focus="emitFormFocus"
|
|
164
170
|
></textarea>
|
|
165
171
|
|
|
166
172
|
<slot></slot>
|