@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
|
@@ -7,9 +7,9 @@ import type { input } from '../theme'
|
|
|
7
7
|
import type { ComponentAttrs } from '../types'
|
|
8
8
|
|
|
9
9
|
export interface InputEmits {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
'update:modelValue': [payload: string | number]
|
|
11
|
+
'blur': [event: FocusEvent]
|
|
12
|
+
'change': [event: Event]
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface InputSlots {
|
|
@@ -48,6 +48,7 @@ import { Primitive } from 'reka-ui'
|
|
|
48
48
|
import { computed, onMounted, ref } from 'vue'
|
|
49
49
|
import { useButtonGroup } from '../composables/useButtonGroup'
|
|
50
50
|
import { useComponentIcons } from '../composables/useComponentIcons'
|
|
51
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
51
52
|
import { useTheme } from '../composables/useTheme'
|
|
52
53
|
import { looseToNumber } from '../utils'
|
|
53
54
|
|
|
@@ -68,15 +69,27 @@ const [modelValue, modelModifiers] = defineModel<string | number>()
|
|
|
68
69
|
|
|
69
70
|
const inputRef = ref<HTMLInputElement | null>(null)
|
|
70
71
|
|
|
71
|
-
const {
|
|
72
|
+
const {
|
|
73
|
+
size: formItemSize,
|
|
74
|
+
id,
|
|
75
|
+
name,
|
|
76
|
+
highlight,
|
|
77
|
+
disabled,
|
|
78
|
+
ariaAttrs,
|
|
79
|
+
emitFormBlur,
|
|
80
|
+
emitFormInput,
|
|
81
|
+
emitFormChange,
|
|
82
|
+
emitFormFocus,
|
|
83
|
+
} = useFormItem<InputProps>(props, { deferInputValidation: true })
|
|
84
|
+
const { size: buttonGroupSize, orientation } = useButtonGroup(props)
|
|
72
85
|
const { isLeading, leadingIconName, isTrailing, trailingIconName } = useComponentIcons(props)
|
|
73
86
|
|
|
74
87
|
const { generateStyle } = useTheme()
|
|
75
88
|
const style = computed(() => generateStyle('input', {
|
|
76
89
|
...props,
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
90
|
+
type: props.type as InputVariants['type'],
|
|
91
|
+
size: buttonGroupSize.value || formItemSize.value,
|
|
92
|
+
highlight: highlight.value,
|
|
80
93
|
groupOrientation: orientation.value,
|
|
81
94
|
leading: isLeading.value || !!slots.leading,
|
|
82
95
|
trailing: isTrailing.value || !!slots.trailing,
|
|
@@ -95,6 +108,7 @@ function updateInput(value: string) {
|
|
|
95
108
|
value = looseToNumber(value)
|
|
96
109
|
|
|
97
110
|
modelValue.value = value
|
|
111
|
+
emitFormInput()
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
function onInput(event: Event) {
|
|
@@ -112,10 +126,12 @@ function onChange(event: Event) {
|
|
|
112
126
|
(event.target as HTMLInputElement).value = value.trim()
|
|
113
127
|
|
|
114
128
|
emit('change', event)
|
|
129
|
+
emitFormChange()
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
function onBlur(event: FocusEvent) {
|
|
118
133
|
emit('blur', event)
|
|
134
|
+
emitFormBlur()
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
defineExpose({
|
|
@@ -133,7 +149,7 @@ onMounted(() => {
|
|
|
133
149
|
<Primitive
|
|
134
150
|
:as="as"
|
|
135
151
|
:class="style.base({ class: [props.class, props.ui?.base] })"
|
|
136
|
-
:aria-disabled="
|
|
152
|
+
:aria-disabled="disabled ? true : undefined"
|
|
137
153
|
>
|
|
138
154
|
<span v-if="isLeading || slots.leading" :class="style.leading({ class: props.ui?.leading })">
|
|
139
155
|
<slot name="leading">
|
|
@@ -145,20 +161,18 @@ onMounted(() => {
|
|
|
145
161
|
</span>
|
|
146
162
|
|
|
147
163
|
<input
|
|
148
|
-
:id="id"
|
|
149
164
|
ref="inputRef"
|
|
165
|
+
:class="style.input({ class: props.ui?.input })"
|
|
150
166
|
:type="props.type"
|
|
151
167
|
:value="modelValue"
|
|
152
|
-
:name="props.name"
|
|
153
168
|
:placeholder="props.placeholder"
|
|
154
|
-
:class="style.input({ class: props.ui?.input })"
|
|
155
|
-
:disabled="props.disabled"
|
|
156
169
|
:required="props.required"
|
|
157
170
|
:autocomplete="props.autocomplete"
|
|
158
|
-
v-bind="
|
|
171
|
+
v-bind="{ ...$attrs, ...ariaAttrs, id, name, disabled }"
|
|
159
172
|
@input="onInput"
|
|
160
173
|
@blur="onBlur"
|
|
161
174
|
@change="onChange"
|
|
175
|
+
@focus="emitFormFocus"
|
|
162
176
|
/>
|
|
163
177
|
|
|
164
178
|
<slot></slot>
|
|
@@ -5,9 +5,9 @@ import type { inputNumber } from '../theme'
|
|
|
5
5
|
import type { ButtonProps, ComponentAttrs } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface InputNumberEmits {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
'update:modelValue': [payload: number]
|
|
9
|
+
'blur': [event: FocusEvent]
|
|
10
|
+
'change': [payload: Event]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface InputNumberSlots {
|
|
@@ -63,6 +63,7 @@ export interface InputNumberProps extends ComponentAttrs<typeof inputNumber>, Pi
|
|
|
63
63
|
import { reactivePick } from '@vueuse/core'
|
|
64
64
|
import { NumberFieldDecrement, NumberFieldIncrement, NumberFieldInput, NumberFieldRoot, useForwardPropsEmits } from 'reka-ui'
|
|
65
65
|
import { computed, onMounted, ref } from 'vue'
|
|
66
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
66
67
|
import { useLocale } from '../composables/useLocale'
|
|
67
68
|
import { useTheme } from '../composables/useTheme'
|
|
68
69
|
import Button from './Button.vue'
|
|
@@ -82,12 +83,18 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', '
|
|
|
82
83
|
|
|
83
84
|
const inputRef = ref<InstanceType<typeof NumberFieldInput> | null>(null)
|
|
84
85
|
|
|
85
|
-
const { t } = useLocale()
|
|
86
|
+
const { t, code: codeLocale } = useLocale()
|
|
87
|
+
const locale = computed(() => props.locale || codeLocale.value)
|
|
88
|
+
const { id, name, size, highlight, disabled, ariaAttrs, emitFormBlur, emitFormFocus, emitFormInput, emitFormChange } = useFormItem<InputNumberProps>(props)
|
|
86
89
|
const { theme, generateStyle } = useTheme()
|
|
87
90
|
const incrementIcon = computed(() => props.incrementIcon || (props.orientation === 'horizontal' ? theme.value.app.icons.plus : theme.value.app.icons.chevronUp))
|
|
88
91
|
const decrementIcon = computed(() => props.decrementIcon || (props.orientation === 'horizontal' ? theme.value.app.icons.minus : theme.value.app.icons.chevronDown))
|
|
89
92
|
|
|
90
|
-
const style = computed(() => generateStyle('inputNumber',
|
|
93
|
+
const style = computed(() => generateStyle('inputNumber', {
|
|
94
|
+
...props,
|
|
95
|
+
size: size.value,
|
|
96
|
+
highlight: highlight.value,
|
|
97
|
+
}))
|
|
91
98
|
|
|
92
99
|
onMounted(() => {
|
|
93
100
|
setTimeout(() => {
|
|
@@ -108,35 +115,36 @@ function onUpdate(value: number) {
|
|
|
108
115
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
109
116
|
const event = new Event('change', { target: { value } })
|
|
110
117
|
emit('change', event)
|
|
118
|
+
emitFormChange()
|
|
119
|
+
emitFormInput()
|
|
111
120
|
}
|
|
112
121
|
|
|
113
122
|
function onBlur(event: FocusEvent) {
|
|
114
123
|
emit('blur', event)
|
|
124
|
+
emitFormBlur()
|
|
115
125
|
}
|
|
116
126
|
</script>
|
|
117
127
|
|
|
118
128
|
<template>
|
|
119
129
|
<NumberFieldRoot
|
|
120
|
-
v-bind="rootProps"
|
|
121
|
-
:id="props.id"
|
|
122
|
-
:name="props.name"
|
|
123
|
-
:disabled="props.disabled"
|
|
124
|
-
:locale="props.locale"
|
|
130
|
+
v-bind="{ ...rootProps, id, name, disabled }"
|
|
125
131
|
:class="style.base({ class: [props.class, props.ui?.base] })"
|
|
126
|
-
:
|
|
132
|
+
:locale="locale"
|
|
133
|
+
:aria-disabled="disabled ? true : undefined"
|
|
127
134
|
@update:model-value="onUpdate"
|
|
128
135
|
>
|
|
129
136
|
<NumberFieldInput
|
|
130
|
-
v-bind="
|
|
137
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
131
138
|
ref="inputRef"
|
|
132
139
|
:placeholder="props.placeholder"
|
|
133
140
|
:required="props.required"
|
|
134
141
|
:class="style.input({ class: props.ui?.input })"
|
|
135
142
|
@blur="onBlur"
|
|
143
|
+
@focus="emitFormFocus"
|
|
136
144
|
/>
|
|
137
145
|
|
|
138
146
|
<div :class="style.increment({ class: props.ui?.increment })">
|
|
139
|
-
<NumberFieldIncrement as-child :disabled="
|
|
147
|
+
<NumberFieldIncrement as-child :disabled="disabled">
|
|
140
148
|
<slot name="increment">
|
|
141
149
|
<Button
|
|
142
150
|
:icon="incrementIcon"
|
|
@@ -150,7 +158,7 @@ function onBlur(event: FocusEvent) {
|
|
|
150
158
|
</div>
|
|
151
159
|
|
|
152
160
|
<div :class="style.decrement({ class: props.ui?.decrement })">
|
|
153
|
-
<NumberFieldDecrement as-child :disabled="
|
|
161
|
+
<NumberFieldDecrement as-child :disabled="disabled">
|
|
154
162
|
<slot name="decrement">
|
|
155
163
|
<Button
|
|
156
164
|
:icon="decrementIcon"
|
|
@@ -168,6 +168,9 @@ const isExternalLink = computed(() => {
|
|
|
168
168
|
if (!to)
|
|
169
169
|
return false
|
|
170
170
|
|
|
171
|
+
if (props.target === '_blank')
|
|
172
|
+
return true
|
|
173
|
+
|
|
171
174
|
return typeof to === 'string' && hasProtocol(to, { acceptRelative: true })
|
|
172
175
|
})
|
|
173
176
|
|
|
@@ -175,6 +178,9 @@ function isLinkActive({ route: linkRoute, isActive, isExactActive }: any) {
|
|
|
175
178
|
if (props.active !== undefined)
|
|
176
179
|
return props.active
|
|
177
180
|
|
|
181
|
+
if (isExternalLink.value || !props.to)
|
|
182
|
+
return false
|
|
183
|
+
|
|
178
184
|
if (props.exactQuery === 'partial') {
|
|
179
185
|
if (!isPartiallyEqual(linkRoute?.query, route.value?.query))
|
|
180
186
|
return false
|
|
@@ -275,19 +281,28 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
|
|
|
275
281
|
v-else
|
|
276
282
|
v-slot="{ href, navigate, route: linkRoute, isActive, isExactActive }"
|
|
277
283
|
v-bind="linkProps"
|
|
278
|
-
:to="to || '#'"
|
|
284
|
+
:to="isExternalLink ? '#' : to || '#'"
|
|
279
285
|
custom
|
|
280
286
|
>
|
|
281
287
|
<template v-if="custom">
|
|
282
288
|
<slot
|
|
283
289
|
v-bind="{
|
|
284
290
|
...$attrs,
|
|
291
|
+
...isExternalLink
|
|
292
|
+
? {
|
|
293
|
+
href: to || props.href,
|
|
294
|
+
target: props.target,
|
|
295
|
+
}
|
|
296
|
+
: {
|
|
297
|
+
href: to ? href : undefined,
|
|
298
|
+
target: undefined,
|
|
299
|
+
},
|
|
285
300
|
as,
|
|
286
301
|
type,
|
|
287
302
|
disabled,
|
|
288
|
-
href: to ? href : undefined,
|
|
289
303
|
navigate,
|
|
290
304
|
active: isLinkActive({ route: linkRoute, isActive, isExactActive }),
|
|
305
|
+
isExternal: isExternalLink,
|
|
291
306
|
}"
|
|
292
307
|
>
|
|
293
308
|
{{ props.label }}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
-
import type { DialogContentProps, DialogRootEmits, DialogRootProps } from 'reka-ui'
|
|
3
|
+
import type { DialogContentEmits, DialogContentProps, DialogRootEmits, DialogRootProps } from 'reka-ui'
|
|
4
4
|
import type { modal } from '../theme'
|
|
5
|
-
import type { ButtonProps, ComponentAttrs } from '../types'
|
|
5
|
+
import type { ButtonProps, ComponentAttrs, EmitsToProps } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface ModalEmits extends DialogRootEmits {
|
|
8
8
|
'after-leave': []
|
|
@@ -10,13 +10,13 @@ export interface ModalEmits extends DialogRootEmits {
|
|
|
10
10
|
|
|
11
11
|
export interface ModalSlots {
|
|
12
12
|
default?: (props: { open: boolean }) => any
|
|
13
|
-
content?:
|
|
14
|
-
header?:
|
|
15
|
-
title?:
|
|
16
|
-
description?:
|
|
17
|
-
close?: (props
|
|
18
|
-
body?:
|
|
19
|
-
footer?:
|
|
13
|
+
content?: any
|
|
14
|
+
header?: any
|
|
15
|
+
title?: any
|
|
16
|
+
description?: any
|
|
17
|
+
close?: (props: { ui: ComponentAttrs<typeof modal>['ui'] }) => any
|
|
18
|
+
body?: any
|
|
19
|
+
footer?: any
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
type ModalVariants = VariantProps<typeof modal>
|
|
@@ -25,7 +25,7 @@ export interface ModalProps extends ComponentAttrs<typeof modal>, DialogRootProp
|
|
|
25
25
|
title?: string
|
|
26
26
|
description?: string
|
|
27
27
|
size?: ModalVariants['size']
|
|
28
|
-
content?: Omit<DialogContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
28
|
+
content?: Omit<DialogContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<DialogContentEmits>>
|
|
29
29
|
/** @default true */
|
|
30
30
|
portal?: boolean
|
|
31
31
|
/** @default true */
|
|
@@ -119,7 +119,7 @@ const style = computed(() => generateStyle('modal', props))
|
|
|
119
119
|
</DialogTitle>
|
|
120
120
|
|
|
121
121
|
<DialogClose v-if="props.close || slots.close" as-child>
|
|
122
|
-
<slot name="close">
|
|
122
|
+
<slot name="close" :ui="props.ui">
|
|
123
123
|
<Button
|
|
124
124
|
variant="ghost"
|
|
125
125
|
:icon="props.closeIcon || theme.app.icons.close"
|
|
@@ -5,10 +5,10 @@ import type { pinInput } from '../theme'
|
|
|
5
5
|
import type { ComponentAttrs } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface PinInputEmits {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
'update:modelValue': [value: string[]]
|
|
9
|
+
'complete': [value: string[]]
|
|
10
|
+
'change': [payload: Event]
|
|
11
|
+
'blur': [payload: Event]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type PinInputVariants = VariantProps<typeof pinInput>
|
|
@@ -26,6 +26,7 @@ export interface PinInputProps extends ComponentAttrs<typeof pinInput>, Pick<Pin
|
|
|
26
26
|
import { reactivePick } from '@vueuse/core'
|
|
27
27
|
import { PinInputInput, PinInputRoot, useForwardPropsEmits } from 'reka-ui'
|
|
28
28
|
import { computed, ref } from 'vue'
|
|
29
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
29
30
|
import { useTheme } from '../composables/useTheme'
|
|
30
31
|
import { looseToNumber } from '../utils'
|
|
31
32
|
|
|
@@ -41,41 +42,49 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultValue', 'disa
|
|
|
41
42
|
|
|
42
43
|
const completed = ref(false)
|
|
43
44
|
|
|
45
|
+
const { id, name, size, highlight, disabled, ariaAttrs, emitFormInput, emitFormChange, emitFormFocus, emitFormBlur } = useFormItem<PinInputProps>(props)
|
|
44
46
|
const { generateStyle } = useTheme()
|
|
45
|
-
const style = computed(() => generateStyle('pinInput',
|
|
47
|
+
const style = computed(() => generateStyle('pinInput', {
|
|
48
|
+
...props,
|
|
49
|
+
size: size.value,
|
|
50
|
+
highlight: highlight.value,
|
|
51
|
+
}))
|
|
46
52
|
|
|
47
53
|
function onComplete(value: string[]) {
|
|
48
54
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
49
55
|
const event = new Event('change', { target: { value } })
|
|
50
56
|
emit('change', event)
|
|
57
|
+
emitFormChange()
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
function onBlur(event: FocusEvent) {
|
|
54
|
-
if (!event.relatedTarget || completed.value)
|
|
61
|
+
if (!event.relatedTarget || completed.value) {
|
|
55
62
|
emit('blur', event)
|
|
63
|
+
emitFormBlur()
|
|
64
|
+
}
|
|
56
65
|
}
|
|
57
66
|
</script>
|
|
58
67
|
|
|
59
68
|
<template>
|
|
60
69
|
<PinInputRoot
|
|
61
|
-
v-bind="rootProps"
|
|
62
|
-
:id="props.id"
|
|
63
|
-
:name="props.name"
|
|
70
|
+
v-bind="{ ...rootProps, ...ariaAttrs, id, name }"
|
|
64
71
|
:class="style.root({ class: [props.class, props.ui?.root] })"
|
|
72
|
+
@update:model-value="emitFormInput"
|
|
65
73
|
@complete="onComplete"
|
|
66
74
|
>
|
|
67
75
|
<span
|
|
68
76
|
v-for="(ids, index) in looseToNumber(props.length)"
|
|
69
77
|
:key="ids"
|
|
70
78
|
:class="style.container({ class: props.ui?.container })"
|
|
71
|
-
:aria-disabled="
|
|
79
|
+
:aria-disabled="disabled ? true : undefined"
|
|
72
80
|
>
|
|
73
81
|
<PinInputInput
|
|
74
|
-
:index="index"
|
|
75
|
-
:class="style.base({ class: props.ui?.base })"
|
|
76
82
|
v-bind="$attrs"
|
|
77
|
-
:
|
|
83
|
+
:class="style.base({ class: props.ui?.base })"
|
|
84
|
+
:index="index"
|
|
85
|
+
:disabled="disabled"
|
|
78
86
|
@blur="onBlur"
|
|
87
|
+
@focus="emitFormFocus"
|
|
79
88
|
/>
|
|
80
89
|
</span>
|
|
81
90
|
</PinInputRoot>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { HoverCardRootProps, PopoverArrowProps, PopoverContentProps, PopoverRootEmits, PopoverRootProps } from 'reka-ui'
|
|
2
|
+
import type { HoverCardRootProps, PopoverArrowProps, PopoverContentEmits, PopoverContentProps, PopoverRootEmits, PopoverRootProps } from 'reka-ui'
|
|
3
3
|
import type { popover } from '../theme'
|
|
4
|
-
import type { ComponentAttrs } from '../types'
|
|
4
|
+
import type { ComponentAttrs, EmitsToProps } from '../types'
|
|
5
5
|
|
|
6
6
|
export interface PopoverEmits extends PopoverRootEmits {}
|
|
7
7
|
|
|
@@ -17,7 +17,7 @@ export interface PopoverProps extends ComponentAttrs<typeof popover>, PopoverRoo
|
|
|
17
17
|
*/
|
|
18
18
|
mode?: 'click' | 'hover'
|
|
19
19
|
/** @default { side: 'bottom', sideOffset: 8, collisionPadding: 8 } */
|
|
20
|
-
content?: Omit<PopoverContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
20
|
+
content?: Omit<PopoverContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<PopoverContentEmits>>
|
|
21
21
|
arrow?: boolean | Omit<PopoverArrowProps, 'as' | 'asChild'>
|
|
22
22
|
/** @default true */
|
|
23
23
|
portal?: boolean
|
|
@@ -1,44 +1,35 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
-
import type {
|
|
3
|
+
import type { PrimitiveProps, RadioGroupRootProps } from 'reka-ui'
|
|
4
4
|
import type { radioGroup } from '../theme'
|
|
5
|
-
import type { ComponentAttrs } from '../types'
|
|
5
|
+
import type { AcceptableValue, ComponentAttrs } from '../types'
|
|
6
6
|
|
|
7
7
|
export interface RadioGroupEmits {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
'update:modelValue': [payload: string]
|
|
9
|
+
'change': [payload: Event]
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
type
|
|
12
|
+
export type RadioGroupValue = AcceptableValue
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
|
|
14
|
+
export type RadioGroupItem = {
|
|
15
|
+
label?: string
|
|
16
|
+
description?: string
|
|
17
|
+
disabled?: boolean
|
|
18
|
+
value?: RadioGroupValue
|
|
19
|
+
[key: string]: any
|
|
20
|
+
} | RadioGroupValue
|
|
21
|
+
|
|
22
|
+
type SlotProps<T extends RadioGroupItem> = (props: { item: T & { id: string }, modelValue?: RadioGroupValue }) => any
|
|
23
|
+
|
|
24
|
+
export interface RadioGroupSlots<T extends RadioGroupItem = RadioGroupItem> {
|
|
25
|
+
legend?: any
|
|
16
26
|
label?: SlotProps<T>
|
|
17
27
|
description?: SlotProps<T>
|
|
18
28
|
}
|
|
19
29
|
|
|
20
|
-
type NormalizeItem<T> = { id: string } & (
|
|
21
|
-
T extends RadioOption
|
|
22
|
-
? T
|
|
23
|
-
: {
|
|
24
|
-
id: string
|
|
25
|
-
label: string
|
|
26
|
-
value: any
|
|
27
|
-
description: string
|
|
28
|
-
disabled: boolean
|
|
29
|
-
}
|
|
30
|
-
)
|
|
31
|
-
|
|
32
30
|
type RadioGroupVariants = VariantProps<typeof radioGroup>
|
|
33
31
|
|
|
34
|
-
export interface
|
|
35
|
-
label?: string
|
|
36
|
-
description?: string
|
|
37
|
-
disabled?: boolean
|
|
38
|
-
value?: string
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface RadioGroupProps<T> extends ComponentAttrs<typeof radioGroup>, Pick<RadioGroupRootProps, 'defaultValue' | 'disabled' | 'loop' | 'modelValue' | 'name' | 'required'> {
|
|
32
|
+
export interface RadioGroupProps<T extends RadioGroupItem = RadioGroupItem> extends ComponentAttrs<typeof radioGroup>, Pick<RadioGroupRootProps, 'defaultValue' | 'disabled' | 'loop' | 'modelValue' | 'name' | 'required'> {
|
|
42
33
|
/**
|
|
43
34
|
* The element or component this component should render as.
|
|
44
35
|
* @default "div"
|
|
@@ -70,10 +61,11 @@ export interface RadioGroupProps<T> extends ComponentAttrs<typeof radioGroup>, P
|
|
|
70
61
|
}
|
|
71
62
|
</script>
|
|
72
63
|
|
|
73
|
-
<script lang="ts" setup generic="T extends
|
|
64
|
+
<script lang="ts" setup generic="T extends RadioGroupItem">
|
|
74
65
|
import { reactivePick } from '@vueuse/core'
|
|
75
66
|
import { Label, RadioGroupIndicator, RadioGroupItem, RadioGroupRoot, useForwardPropsEmits } from 'reka-ui'
|
|
76
67
|
import { computed, useId } from 'vue'
|
|
68
|
+
import { useFormItem } from '../composables/useFormItem'
|
|
77
69
|
import { useTheme } from '../composables/useTheme'
|
|
78
70
|
import { get } from '../utils'
|
|
79
71
|
|
|
@@ -88,20 +80,33 @@ const emit = defineEmits<RadioGroupEmits>()
|
|
|
88
80
|
const slots = defineSlots<RadioGroupSlots<T>>()
|
|
89
81
|
|
|
90
82
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emit)
|
|
91
|
-
|
|
83
|
+
|
|
84
|
+
const { id: _id, name, size, disabled, ariaAttrs, emitFormChange, emitFormInput } = useFormItem<RadioGroupProps<T>>(props)
|
|
85
|
+
const id = _id.value ?? useId()
|
|
92
86
|
|
|
93
87
|
const { generateStyle } = useTheme()
|
|
94
|
-
const style = computed(() => generateStyle('radioGroup',
|
|
88
|
+
const style = computed(() => generateStyle('radioGroup', {
|
|
89
|
+
...props,
|
|
90
|
+
size: size.value,
|
|
91
|
+
disabled: disabled.value,
|
|
92
|
+
}))
|
|
93
|
+
|
|
94
|
+
function normalizeItem(item: any) {
|
|
95
|
+
if (item === null) {
|
|
96
|
+
return {
|
|
97
|
+
id: `${id}:null`,
|
|
98
|
+
label: undefined,
|
|
99
|
+
value: undefined,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
if (['string', 'number', 'boolean'].includes(typeof item)) {
|
|
103
|
+
if (typeof item === 'string' || typeof item === 'number') {
|
|
98
104
|
return {
|
|
99
105
|
id: `${id}:${item}`,
|
|
106
|
+
label: String(item),
|
|
100
107
|
value: item,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
disabled: props.disabled,
|
|
104
|
-
} as any
|
|
108
|
+
disabled: disabled.value,
|
|
109
|
+
}
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
const value = get(item, props.valueKey)
|
|
@@ -110,11 +115,11 @@ function normalizeItem(item: any): NormalizeItem<T> {
|
|
|
110
115
|
|
|
111
116
|
return {
|
|
112
117
|
...item,
|
|
113
|
-
value
|
|
118
|
+
id: `${id}:${value}`,
|
|
114
119
|
label,
|
|
120
|
+
value,
|
|
115
121
|
description,
|
|
116
|
-
|
|
117
|
-
disabled: props.disabled || item.disabled,
|
|
122
|
+
disabled: disabled.value || item.disabled,
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
|
|
@@ -129,20 +134,19 @@ function onUpdate(value: any) {
|
|
|
129
134
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
130
135
|
const event = new Event('change', { target: { value } })
|
|
131
136
|
emit('change', event)
|
|
137
|
+
emitFormChange()
|
|
138
|
+
emitFormInput()
|
|
132
139
|
}
|
|
133
140
|
</script>
|
|
134
141
|
|
|
135
142
|
<template>
|
|
136
143
|
<RadioGroupRoot
|
|
137
|
-
:id="id"
|
|
138
144
|
v-slot="{ modelValue }"
|
|
139
|
-
v-bind="rootProps"
|
|
140
|
-
:name="props.name"
|
|
141
|
-
:disabled="props.disabled"
|
|
145
|
+
v-bind="{ ...rootProps, id, name, disabled }"
|
|
142
146
|
:class="style.root({ class: [props.class, props.ui?.root] })"
|
|
143
147
|
@update:model-value="onUpdate"
|
|
144
148
|
>
|
|
145
|
-
<fieldset :class="style.fieldset({ class: props.ui?.fieldset })">
|
|
149
|
+
<fieldset v-bind="ariaAttrs" :class="style.fieldset({ class: props.ui?.fieldset })">
|
|
146
150
|
<legend v-if="props.legend || slots.legend" :class="style.legend({ class: props.ui?.legend })">
|
|
147
151
|
<slot name="legend">
|
|
148
152
|
{{ props.legend }}
|
|
@@ -162,10 +166,10 @@ function onUpdate(value: any) {
|
|
|
162
166
|
|
|
163
167
|
<div :class="style.wrapper({ class: props.ui?.wrapper })">
|
|
164
168
|
<Label :for="item.id" :class="style.label({ class: props.ui?.label })">
|
|
165
|
-
<slot name="label" :item="item" :model-value="modelValue">{{ item.label }}</slot>
|
|
169
|
+
<slot name="label" :item="item" :model-value="(modelValue as RadioGroupValue)">{{ item.label }}</slot>
|
|
166
170
|
</Label>
|
|
167
171
|
<p v-if="item.description || slots.description" :class="style.description({ class: props.ui?.description })">
|
|
168
|
-
<slot name="description" :item="item" :model-value="modelValue">
|
|
172
|
+
<slot name="description" :item="item" :model-value="(modelValue as RadioGroupValue)">
|
|
169
173
|
{{ item.description }}
|
|
170
174
|
</slot>
|
|
171
175
|
</p>
|