@byyuurin/ui 0.0.8 → 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 +4 -3
- package/dist/module.mjs.map +1 -1
- package/dist/runtime/app/injections.d.ts +9299 -8
- package/dist/runtime/app/injections.js +35 -5
- package/dist/runtime/components/Accordion.vue +17 -19
- package/dist/runtime/components/Alert.vue +6 -9
- package/dist/runtime/components/App.vue +14 -19
- package/dist/runtime/components/Avatar.vue +5 -8
- package/dist/runtime/components/AvatarGroup.vue +2 -5
- package/dist/runtime/components/Badge.vue +3 -6
- package/dist/runtime/components/Breadcrumb.vue +22 -23
- package/dist/runtime/components/Button.vue +2 -3
- package/dist/runtime/components/ButtonGroup.vue +2 -5
- package/dist/runtime/components/Calendar.vue +185 -0
- package/dist/runtime/components/Card.vue +2 -5
- package/dist/runtime/components/Carousel.vue +11 -16
- package/dist/runtime/components/Checkbox.vue +13 -11
- package/dist/runtime/components/Chip.vue +6 -9
- package/dist/runtime/components/Collapsible.vue +2 -5
- package/dist/runtime/components/Drawer.vue +88 -45
- 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 +34 -23
- package/dist/runtime/components/InputNumber.vue +23 -18
- package/dist/runtime/components/Kbd.vue +2 -6
- package/dist/runtime/components/Link.vue +25 -7
- package/dist/runtime/components/Modal.vue +31 -22
- package/dist/runtime/components/OverlayProvider.vue +29 -0
- package/dist/runtime/components/Pagination.vue +34 -27
- package/dist/runtime/components/PinInput.vue +23 -17
- package/dist/runtime/components/Popover.vue +5 -8
- package/dist/runtime/components/Progress.vue +2 -5
- package/dist/runtime/components/RadioGroup.vue +52 -49
- package/dist/runtime/components/ScrollArea.vue +2 -6
- package/dist/runtime/components/Select.vue +96 -89
- package/dist/runtime/components/Separator.vue +2 -6
- package/dist/runtime/components/Skeleton.vue +2 -5
- package/dist/runtime/components/Slider.vue +13 -11
- package/dist/runtime/components/Switch.vue +18 -11
- package/dist/runtime/components/Table.vue +23 -13
- package/dist/runtime/components/Tabs.vue +14 -16
- package/dist/runtime/components/Textarea.vue +20 -17
- package/dist/runtime/components/Toast.vue +12 -13
- package/dist/runtime/components/{Toaster.vue → ToastProvider.vue} +18 -16
- package/dist/runtime/components/Tooltip.vue +5 -8
- package/dist/runtime/composables/useFormItem.d.ts +27 -0
- package/dist/runtime/composables/useFormItem.js +64 -0
- package/dist/runtime/composables/useKbd.d.ts +1 -1
- package/dist/runtime/composables/useOverlay.d.ts +29 -0
- package/dist/runtime/composables/useOverlay.js +69 -0
- package/dist/runtime/composables/useTheme.d.ts +6 -2
- package/dist/runtime/composables/useTheme.js +10 -3
- package/dist/runtime/composables/useToast.d.ts +4 -20
- package/dist/runtime/composables/useToast.js +6 -5
- package/dist/runtime/index.d.ts +6 -2
- package/dist/runtime/index.js +6 -2
- package/dist/runtime/locale/en.js +6 -0
- package/dist/runtime/locale/zh-tw.js +6 -0
- package/dist/runtime/theme/accordion.js +3 -3
- package/dist/runtime/theme/alert.js +3 -3
- package/dist/runtime/theme/app.d.ts +1 -0
- package/dist/runtime/theme/app.js +2 -1
- package/dist/runtime/theme/avatar.js +2 -2
- package/dist/runtime/theme/badge.d.ts +21 -45
- package/dist/runtime/theme/breadcrumb.d.ts +3 -3
- package/dist/runtime/theme/breadcrumb.js +5 -5
- package/dist/runtime/theme/button.d.ts +111 -57
- package/dist/runtime/theme/button.js +13 -13
- package/dist/runtime/theme/calendar.d.ts +56 -0
- package/dist/runtime/theme/calendar.js +69 -0
- package/dist/runtime/theme/card.js +6 -6
- package/dist/runtime/theme/carousel.js +1 -1
- package/dist/runtime/theme/checkbox.js +5 -5
- package/dist/runtime/theme/chip.d.ts +11 -44
- package/dist/runtime/theme/chip.js +3 -3
- package/dist/runtime/theme/drawer.d.ts +85 -47
- package/dist/runtime/theme/drawer.js +46 -19
- 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 +5 -1
- package/dist/runtime/theme/index.js +5 -1
- package/dist/runtime/theme/input-number.d.ts +41 -61
- package/dist/runtime/theme/input-number.js +1 -1
- package/dist/runtime/theme/input.d.ts +99 -71
- package/dist/runtime/theme/input.js +15 -15
- package/dist/runtime/theme/kbd.d.ts +2 -2
- package/dist/runtime/theme/kbd.js +1 -1
- package/dist/runtime/theme/link.d.ts +1 -1
- package/dist/runtime/theme/link.js +3 -3
- package/dist/runtime/theme/modal.d.ts +5 -33
- package/dist/runtime/theme/modal.js +4 -4
- package/dist/runtime/theme/pagination.d.ts +27 -3
- package/dist/runtime/theme/pagination.js +6 -2
- package/dist/runtime/theme/pinInput.d.ts +42 -42
- package/dist/runtime/theme/pinInput.js +13 -13
- package/dist/runtime/theme/progress.d.ts +117 -53
- package/dist/runtime/theme/progress.js +4 -4
- package/dist/runtime/theme/radio-group.d.ts +2 -2
- package/dist/runtime/theme/radio-group.js +7 -7
- package/dist/runtime/theme/select.d.ts +100 -84
- package/dist/runtime/theme/select.js +21 -20
- package/dist/runtime/theme/separator.d.ts +13 -28
- package/dist/runtime/theme/separator.js +1 -1
- package/dist/runtime/theme/skeleton.d.ts +1 -1
- package/dist/runtime/theme/skeleton.js +1 -1
- package/dist/runtime/theme/slider.js +1 -1
- package/dist/runtime/theme/switch.js +5 -5
- package/dist/runtime/theme/table.d.ts +3 -0
- package/dist/runtime/theme/table.js +8 -7
- package/dist/runtime/theme/tabs.d.ts +51 -68
- package/dist/runtime/theme/tabs.js +10 -10
- package/dist/runtime/theme/textarea.d.ts +37 -43
- package/dist/runtime/theme/textarea.js +13 -13
- package/dist/runtime/theme/{toaster.d.ts → toast-provider.d.ts} +26 -41
- package/dist/runtime/theme/toast.js +5 -5
- package/dist/runtime/theme/tooltip.js +1 -1
- package/dist/runtime/types/components.d.ts +6 -1
- 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/locale.d.ts +6 -0
- package/dist/runtime/types/utils.d.ts +35 -12
- 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 +21 -16
- package/dist/unocss.mjs.map +1 -1
- package/dist/unplugin.mjs +1 -1
- package/dist/vite.mjs +1 -1
- package/package.json +20 -18
- package/dist/runtime/components/ModalProvider.vue +0 -11
- package/dist/runtime/composables/useModal.d.ts +0 -10
- package/dist/runtime/composables/useModal.js +0 -47
- package/dist/shared/ui.ba24b380.mjs +0 -4
- package/dist/shared/ui.ba24b380.mjs.map +0 -1
- /package/dist/runtime/theme/{toaster.js → toast-provider.js} +0 -0
|
@@ -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,22 +69,31 @@ 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
|
-
const {
|
|
75
|
-
const style = computed(() => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
trailing: isTrailing.value || !!slots.trailing,
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
+
const { generateStyle } = useTheme()
|
|
88
|
+
const style = computed(() => generateStyle('input', {
|
|
89
|
+
...props,
|
|
90
|
+
type: props.type as InputVariants['type'],
|
|
91
|
+
size: buttonGroupSize.value || formItemSize.value,
|
|
92
|
+
highlight: highlight.value,
|
|
93
|
+
groupOrientation: orientation.value,
|
|
94
|
+
leading: isLeading.value || !!slots.leading,
|
|
95
|
+
trailing: isTrailing.value || !!slots.trailing,
|
|
96
|
+
}))
|
|
87
97
|
|
|
88
98
|
function autoFocus() {
|
|
89
99
|
if (props.autofocus)
|
|
@@ -98,6 +108,7 @@ function updateInput(value: string) {
|
|
|
98
108
|
value = looseToNumber(value)
|
|
99
109
|
|
|
100
110
|
modelValue.value = value
|
|
111
|
+
emitFormInput()
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
function onInput(event: Event) {
|
|
@@ -115,10 +126,12 @@ function onChange(event: Event) {
|
|
|
115
126
|
(event.target as HTMLInputElement).value = value.trim()
|
|
116
127
|
|
|
117
128
|
emit('change', event)
|
|
129
|
+
emitFormChange()
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
function onBlur(event: FocusEvent) {
|
|
121
133
|
emit('blur', event)
|
|
134
|
+
emitFormBlur()
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
defineExpose({
|
|
@@ -136,7 +149,7 @@ onMounted(() => {
|
|
|
136
149
|
<Primitive
|
|
137
150
|
:as="as"
|
|
138
151
|
:class="style.base({ class: [props.class, props.ui?.base] })"
|
|
139
|
-
:aria-disabled="
|
|
152
|
+
:aria-disabled="disabled ? true : undefined"
|
|
140
153
|
>
|
|
141
154
|
<span v-if="isLeading || slots.leading" :class="style.leading({ class: props.ui?.leading })">
|
|
142
155
|
<slot name="leading">
|
|
@@ -148,20 +161,18 @@ onMounted(() => {
|
|
|
148
161
|
</span>
|
|
149
162
|
|
|
150
163
|
<input
|
|
151
|
-
:id="id"
|
|
152
164
|
ref="inputRef"
|
|
165
|
+
:class="style.input({ class: props.ui?.input })"
|
|
153
166
|
:type="props.type"
|
|
154
167
|
:value="modelValue"
|
|
155
|
-
:name="props.name"
|
|
156
168
|
:placeholder="props.placeholder"
|
|
157
|
-
:class="style.input({ class: props.ui?.input })"
|
|
158
|
-
:disabled="props.disabled"
|
|
159
169
|
:required="props.required"
|
|
160
170
|
:autocomplete="props.autocomplete"
|
|
161
|
-
v-bind="
|
|
171
|
+
v-bind="{ ...$attrs, ...ariaAttrs, id, name, disabled }"
|
|
162
172
|
@input="onInput"
|
|
163
173
|
@blur="onBlur"
|
|
164
174
|
@change="onChange"
|
|
175
|
+
@focus="emitFormFocus"
|
|
165
176
|
/>
|
|
166
177
|
|
|
167
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,15 +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
|
|
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)
|
|
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(() => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
const style = computed(() => generateStyle('inputNumber', {
|
|
94
|
+
...props,
|
|
95
|
+
size: size.value,
|
|
96
|
+
highlight: highlight.value,
|
|
97
|
+
}))
|
|
94
98
|
|
|
95
99
|
onMounted(() => {
|
|
96
100
|
setTimeout(() => {
|
|
@@ -111,35 +115,36 @@ function onUpdate(value: number) {
|
|
|
111
115
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
112
116
|
const event = new Event('change', { target: { value } })
|
|
113
117
|
emit('change', event)
|
|
118
|
+
emitFormChange()
|
|
119
|
+
emitFormInput()
|
|
114
120
|
}
|
|
115
121
|
|
|
116
122
|
function onBlur(event: FocusEvent) {
|
|
117
123
|
emit('blur', event)
|
|
124
|
+
emitFormBlur()
|
|
118
125
|
}
|
|
119
126
|
</script>
|
|
120
127
|
|
|
121
128
|
<template>
|
|
122
129
|
<NumberFieldRoot
|
|
123
|
-
v-bind="rootProps"
|
|
124
|
-
:id="props.id"
|
|
125
|
-
:name="props.name"
|
|
126
|
-
:disabled="props.disabled"
|
|
127
|
-
:locale="props.locale"
|
|
130
|
+
v-bind="{ ...rootProps, id, name, disabled }"
|
|
128
131
|
:class="style.base({ class: [props.class, props.ui?.base] })"
|
|
129
|
-
:
|
|
132
|
+
:locale="locale"
|
|
133
|
+
:aria-disabled="disabled ? true : undefined"
|
|
130
134
|
@update:model-value="onUpdate"
|
|
131
135
|
>
|
|
132
136
|
<NumberFieldInput
|
|
133
|
-
v-bind="
|
|
137
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
134
138
|
ref="inputRef"
|
|
135
139
|
:placeholder="props.placeholder"
|
|
136
140
|
:required="props.required"
|
|
137
141
|
:class="style.input({ class: props.ui?.input })"
|
|
138
142
|
@blur="onBlur"
|
|
143
|
+
@focus="emitFormFocus"
|
|
139
144
|
/>
|
|
140
145
|
|
|
141
146
|
<div :class="style.increment({ class: props.ui?.increment })">
|
|
142
|
-
<NumberFieldIncrement as-child :disabled="
|
|
147
|
+
<NumberFieldIncrement as-child :disabled="disabled">
|
|
143
148
|
<slot name="increment">
|
|
144
149
|
<Button
|
|
145
150
|
:icon="incrementIcon"
|
|
@@ -153,7 +158,7 @@ function onBlur(event: FocusEvent) {
|
|
|
153
158
|
</div>
|
|
154
159
|
|
|
155
160
|
<div :class="style.decrement({ class: props.ui?.decrement })">
|
|
156
|
-
<NumberFieldDecrement as-child :disabled="
|
|
161
|
+
<NumberFieldDecrement as-child :disabled="disabled">
|
|
157
162
|
<slot name="decrement">
|
|
158
163
|
<Button
|
|
159
164
|
:icon="decrementIcon"
|
|
@@ -36,12 +36,8 @@ const props = withDefaults(defineProps<KbdProps>(), {
|
|
|
36
36
|
defineSlots<KbdSlots>()
|
|
37
37
|
|
|
38
38
|
const { getKbdKey } = useKbd()
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const style = computed(() => {
|
|
42
|
-
const styler = createStyler(theme.value.kbd)
|
|
43
|
-
return styler(props)
|
|
44
|
-
})
|
|
39
|
+
const { generateStyle } = useTheme()
|
|
40
|
+
const style = computed(() => generateStyle('kbd', props))
|
|
45
41
|
</script>
|
|
46
42
|
|
|
47
43
|
<template>
|
|
@@ -163,16 +163,24 @@ function isPartiallyEqual(item1: any, item2: any) {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
const isExternalLink = computed(() => {
|
|
166
|
-
|
|
166
|
+
const to = props.to || props.href
|
|
167
|
+
|
|
168
|
+
if (!to)
|
|
167
169
|
return false
|
|
168
170
|
|
|
169
|
-
|
|
171
|
+
if (props.target === '_blank')
|
|
172
|
+
return true
|
|
173
|
+
|
|
174
|
+
return typeof to === 'string' && hasProtocol(to, { acceptRelative: true })
|
|
170
175
|
})
|
|
171
176
|
|
|
172
177
|
function isLinkActive({ route: linkRoute, isActive, isExactActive }: any) {
|
|
173
178
|
if (props.active !== undefined)
|
|
174
179
|
return props.active
|
|
175
180
|
|
|
181
|
+
if (isExternalLink.value || !props.to)
|
|
182
|
+
return false
|
|
183
|
+
|
|
176
184
|
if (props.exactQuery === 'partial') {
|
|
177
185
|
if (!isPartiallyEqual(linkRoute?.query, route.value?.query))
|
|
178
186
|
return false
|
|
@@ -273,19 +281,28 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
|
|
|
273
281
|
v-else
|
|
274
282
|
v-slot="{ href, navigate, route: linkRoute, isActive, isExactActive }"
|
|
275
283
|
v-bind="linkProps"
|
|
276
|
-
:to="to || '#'"
|
|
284
|
+
:to="isExternalLink ? '#' : to || '#'"
|
|
277
285
|
custom
|
|
278
286
|
>
|
|
279
287
|
<template v-if="custom">
|
|
280
288
|
<slot
|
|
281
289
|
v-bind="{
|
|
282
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
|
+
},
|
|
283
300
|
as,
|
|
284
301
|
type,
|
|
285
302
|
disabled,
|
|
286
|
-
href: to ? href : undefined,
|
|
287
303
|
navigate,
|
|
288
304
|
active: isLinkActive({ route: linkRoute, isActive, isExactActive }),
|
|
305
|
+
isExternal: isExternalLink,
|
|
289
306
|
}"
|
|
290
307
|
>
|
|
291
308
|
{{ props.label }}
|
|
@@ -301,6 +318,7 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
|
|
|
301
318
|
href: to ? href : undefined,
|
|
302
319
|
navigate,
|
|
303
320
|
}"
|
|
321
|
+
:is-external="isExternalLink"
|
|
304
322
|
:class="resolveLinkClass({ route: linkRoute, isActive, isExactActive })"
|
|
305
323
|
>
|
|
306
324
|
<slot :active="isLinkActive({ route: linkRoute, isActive, isExactActive })">
|
|
@@ -318,7 +336,7 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
|
|
|
318
336
|
type,
|
|
319
337
|
disabled,
|
|
320
338
|
href: to || href,
|
|
321
|
-
target: isExternalLink ? '_blank' :
|
|
339
|
+
target: target || (isExternalLink ? '_blank' : undefined),
|
|
322
340
|
active: false,
|
|
323
341
|
}"
|
|
324
342
|
>
|
|
@@ -332,8 +350,8 @@ function resolveLinkClass({ route, isActive, isExactActive }: any = {}) {
|
|
|
332
350
|
as,
|
|
333
351
|
type,
|
|
334
352
|
disabled,
|
|
335
|
-
href: ((to
|
|
336
|
-
target: isExternalLink ? '_blank' :
|
|
353
|
+
href: ((typeof to === 'string' ? to : href) as string),
|
|
354
|
+
target: target || (isExternalLink ? '_blank' : undefined),
|
|
337
355
|
}"
|
|
338
356
|
:is-external="isExternalLink"
|
|
339
357
|
:class="resolveLinkClass()"
|
|
@@ -1,20 +1,22 @@
|
|
|
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
|
-
export interface ModalEmits extends DialogRootEmits {
|
|
7
|
+
export interface ModalEmits extends DialogRootEmits {
|
|
8
|
+
'after-leave': []
|
|
9
|
+
}
|
|
8
10
|
|
|
9
11
|
export interface ModalSlots {
|
|
10
12
|
default?: (props: { open: boolean }) => any
|
|
11
|
-
content?:
|
|
12
|
-
header?:
|
|
13
|
-
title?:
|
|
14
|
-
description?:
|
|
15
|
-
close?: (props
|
|
16
|
-
body?:
|
|
17
|
-
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
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
type ModalVariants = VariantProps<typeof modal>
|
|
@@ -23,7 +25,7 @@ export interface ModalProps extends ComponentAttrs<typeof modal>, DialogRootProp
|
|
|
23
25
|
title?: string
|
|
24
26
|
description?: string
|
|
25
27
|
size?: ModalVariants['size']
|
|
26
|
-
content?: Omit<DialogContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
28
|
+
content?: Omit<DialogContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<DialogContentEmits>>
|
|
27
29
|
/** @default true */
|
|
28
30
|
portal?: boolean
|
|
29
31
|
/** @default true */
|
|
@@ -35,6 +37,10 @@ export interface ModalProps extends ComponentAttrs<typeof modal>, DialogRootProp
|
|
|
35
37
|
* @default true
|
|
36
38
|
*/
|
|
37
39
|
dismissible?: boolean
|
|
40
|
+
/**
|
|
41
|
+
* Display a close button to dismiss the modal.
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
38
44
|
close?: ButtonProps | boolean
|
|
39
45
|
/** @default app.icons.close */
|
|
40
46
|
closeIcon?: string
|
|
@@ -43,7 +49,7 @@ export interface ModalProps extends ComponentAttrs<typeof modal>, DialogRootProp
|
|
|
43
49
|
|
|
44
50
|
<script setup lang="ts">
|
|
45
51
|
import { reactivePick } from '@vueuse/core'
|
|
46
|
-
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, useForwardPropsEmits } from 'reka-ui'
|
|
52
|
+
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, useForwardPropsEmits, VisuallyHidden } from 'reka-ui'
|
|
47
53
|
import { computed, toRef } from 'vue'
|
|
48
54
|
import { useLocale } from '../composables/useLocale'
|
|
49
55
|
import { useTheme } from '../composables/useTheme'
|
|
@@ -60,7 +66,10 @@ const props = withDefaults(defineProps<ModalProps>(), {
|
|
|
60
66
|
const emit = defineEmits<ModalEmits>()
|
|
61
67
|
const slots = defineSlots<ModalSlots>()
|
|
62
68
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'modal'), emit)
|
|
63
|
-
const contentProps = toRef(() =>
|
|
69
|
+
const contentProps = toRef(() => ({
|
|
70
|
+
...props.content,
|
|
71
|
+
...(slots.content || slots.header || (!props.description && !slots.description)) ? { 'aria-describedby': undefined } : {},
|
|
72
|
+
}))
|
|
64
73
|
const contentEvents = computed(() => {
|
|
65
74
|
if (props.dismissible)
|
|
66
75
|
return {}
|
|
@@ -73,11 +82,8 @@ const contentEvents = computed(() => {
|
|
|
73
82
|
})
|
|
74
83
|
|
|
75
84
|
const { t } = useLocale()
|
|
76
|
-
const { theme,
|
|
77
|
-
const style = computed(() =>
|
|
78
|
-
const styler = createStyler(theme.value.modal)
|
|
79
|
-
return styler(props)
|
|
80
|
-
})
|
|
85
|
+
const { theme, generateStyle } = useTheme()
|
|
86
|
+
const style = computed(() => generateStyle('modal', props))
|
|
81
87
|
</script>
|
|
82
88
|
|
|
83
89
|
<template>
|
|
@@ -92,7 +98,11 @@ const style = computed(() => {
|
|
|
92
98
|
<DialogPortal :disabled="!props.portal">
|
|
93
99
|
<DialogOverlay v-if="props.overlay" :class="style.overlay({ class: props.ui?.overlay })" />
|
|
94
100
|
|
|
95
|
-
<DialogContent :class="style.content({ class: props.ui?.content })" v-bind="contentProps" v-on="contentEvents">
|
|
101
|
+
<DialogContent :class="style.content({ class: props.ui?.content })" v-bind="contentProps" v-on="contentEvents" @after-leave="emit('after-leave')">
|
|
102
|
+
<VisuallyHidden v-if="slots.content || slots.header || (!props.title && !slots.title)">
|
|
103
|
+
<DialogTitle />
|
|
104
|
+
</VisuallyHidden>
|
|
105
|
+
|
|
96
106
|
<slot name="content">
|
|
97
107
|
<div
|
|
98
108
|
v-if="slots.header || props.title || slots.title || props.description || slots.description || props.close || slots.close"
|
|
@@ -108,10 +118,9 @@ const style = computed(() => {
|
|
|
108
118
|
</slot>
|
|
109
119
|
</DialogTitle>
|
|
110
120
|
|
|
111
|
-
<DialogClose as-child>
|
|
112
|
-
<slot name="close">
|
|
121
|
+
<DialogClose v-if="props.close || slots.close" as-child>
|
|
122
|
+
<slot name="close" :ui="props.ui">
|
|
113
123
|
<Button
|
|
114
|
-
v-if="props.close"
|
|
115
124
|
variant="ghost"
|
|
116
125
|
:icon="props.closeIcon || theme.app.icons.close"
|
|
117
126
|
v-bind="typeof props.close === 'boolean' ? {} : props.close"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { OverlayComponentState } from '../composables/useOverlay'
|
|
4
|
+
import { useOverlay } from '../composables/useOverlay'
|
|
5
|
+
|
|
6
|
+
const { overlays, unmount, close } = useOverlay()
|
|
7
|
+
const mountedOverlays = computed(() => overlays.filter((overlay) => overlay.isMounted))
|
|
8
|
+
|
|
9
|
+
function onOverlayUnmount(id: OverlayComponentState['id']) {
|
|
10
|
+
close(id)
|
|
11
|
+
unmount(id)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function onClose(id: OverlayComponentState['id'], value: any) {
|
|
15
|
+
close(id, value)
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<component
|
|
21
|
+
:is="overlay.component"
|
|
22
|
+
v-for="overlay in mountedOverlays"
|
|
23
|
+
:key="overlay.id"
|
|
24
|
+
v-bind="overlay.props"
|
|
25
|
+
v-model:open="overlay.modelValue"
|
|
26
|
+
@close="onClose(overlay.id, $event)"
|
|
27
|
+
@after-leave="onOverlayUnmount(overlay.id)"
|
|
28
|
+
/>
|
|
29
|
+
</template>
|
|
@@ -70,6 +70,10 @@ export interface PaginationProps extends ComponentAttrs<typeof pagination>, Pick
|
|
|
70
70
|
* @default true
|
|
71
71
|
*/
|
|
72
72
|
showControls?: boolean
|
|
73
|
+
/**
|
|
74
|
+
* A function to render page controls as links.
|
|
75
|
+
*/
|
|
76
|
+
to?: (page: number) => ButtonProps['to']
|
|
73
77
|
}
|
|
74
78
|
</script>
|
|
75
79
|
|
|
@@ -77,6 +81,7 @@ export interface PaginationProps extends ComponentAttrs<typeof pagination>, Pick
|
|
|
77
81
|
import { reactivePick } from '@vueuse/core'
|
|
78
82
|
import { PaginationEllipsis, PaginationFirst, PaginationLast, PaginationList, PaginationListItem, PaginationNext, PaginationPrev, PaginationRoot, useForwardPropsEmits } from 'reka-ui'
|
|
79
83
|
import { computed } from 'vue'
|
|
84
|
+
import { useLocale } from '../composables/useLocale'
|
|
80
85
|
import { useTheme } from '../composables/useTheme'
|
|
81
86
|
import Button from './Button.vue'
|
|
82
87
|
|
|
@@ -95,71 +100,73 @@ const slots = defineSlots<PaginationSlots>()
|
|
|
95
100
|
|
|
96
101
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultPage', 'disabled', 'itemsPerPage', 'page', 'showEdges', 'siblingCount', 'total'), emit)
|
|
97
102
|
|
|
98
|
-
const {
|
|
103
|
+
const { dir } = useLocale()
|
|
104
|
+
const { theme, generateStyle } = useTheme()
|
|
105
|
+
const style = computed(() => generateStyle('pagination', props))
|
|
99
106
|
|
|
100
|
-
const firstIcon = computed(() => props.firstIcon || theme.value.app.icons.chevronDoubleLeft)
|
|
101
|
-
const prevIcon = computed(() => props.prevIcon || theme.value.app.icons.chevronLeft)
|
|
102
|
-
const nextIcon = computed(() => props.nextIcon || theme.value.app.icons.chevronRight)
|
|
103
|
-
const lastIcon = computed(() => props.lastIcon || theme.value.app.icons.chevronDoubleRight)
|
|
107
|
+
const firstIcon = computed(() => props.firstIcon || (dir.value === 'rtl' ? theme.value.app.icons.chevronDoubleRight : theme.value.app.icons.chevronDoubleLeft))
|
|
108
|
+
const prevIcon = computed(() => props.prevIcon || (dir.value === 'rtl' ? theme.value.app.icons.chevronRight : theme.value.app.icons.chevronLeft))
|
|
109
|
+
const nextIcon = computed(() => props.nextIcon || (dir.value === 'rtl' ? theme.value.app.icons.chevronLeft : theme.value.app.icons.chevronRight))
|
|
110
|
+
const lastIcon = computed(() => props.lastIcon || (dir.value === 'rtl' ? theme.value.app.icons.chevronDoubleLeft : theme.value.app.icons.chevronDoubleRight))
|
|
104
111
|
const ellipsisIcon = computed(() => props.ellipsisIcon || theme.value.app.icons.ellipsis)
|
|
105
|
-
|
|
106
|
-
const style = computed(() => {
|
|
107
|
-
const styler = createStyler(theme.value.pagination)
|
|
108
|
-
return styler(props)
|
|
109
|
-
})
|
|
110
112
|
</script>
|
|
111
113
|
|
|
112
114
|
<template>
|
|
113
115
|
<PaginationRoot v-slot="{ page, pageCount }" v-bind="rootProps" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
114
116
|
<PaginationList v-slot="{ items }" :class="style.list({ class: props.ui?.list })">
|
|
115
|
-
<PaginationFirst v-if="props.showControls || !!slots.first" as-child>
|
|
117
|
+
<PaginationFirst v-if="props.showControls || !!slots.first" :class="style.first({ class: props.ui?.first })" as-child>
|
|
116
118
|
<slot name="first">
|
|
117
|
-
<Button :
|
|
119
|
+
<Button :variant="props.variant" :size="props.size" :icon="firstIcon" :to="props.to?.(1)" />
|
|
118
120
|
</slot>
|
|
119
121
|
</PaginationFirst>
|
|
120
|
-
<PaginationPrev v-if="props.showControls || !!slots.prev" as-child>
|
|
122
|
+
<PaginationPrev v-if="props.showControls || !!slots.prev" :class="style.prev({ class: props.ui?.prev })" as-child>
|
|
121
123
|
<slot name="prev">
|
|
122
|
-
<Button :
|
|
124
|
+
<Button :variant="props.variant" :size="props.size" :icon="prevIcon" :to="page > 1 ? props.to?.(page - 1) : undefined" />
|
|
123
125
|
</slot>
|
|
124
126
|
</PaginationPrev>
|
|
125
127
|
|
|
126
128
|
<template v-for="(item, index) in items">
|
|
127
|
-
<PaginationListItem v-if="item.type === 'page'" :key="index"
|
|
129
|
+
<PaginationListItem v-if="item.type === 'page'" :key="index" :class="style.item({ class: props.ui?.item })" :value="item.value" as-child>
|
|
128
130
|
<slot name="item" v-bind="{ item, index, page, pageCount }">
|
|
129
131
|
<Button
|
|
130
|
-
:class="style.item({ class: props.ui?.item })"
|
|
131
132
|
:variant="props.page === item.value ? props.activeVariant : props.variant"
|
|
132
133
|
:size="props.size"
|
|
133
134
|
:label="String(item.value)"
|
|
134
|
-
:
|
|
135
|
+
:to="props.to?.(item.value)"
|
|
136
|
+
:ui="{ label: style.label({ class: props.ui?.label }) }"
|
|
135
137
|
/>
|
|
136
138
|
</slot>
|
|
137
139
|
</PaginationListItem>
|
|
138
140
|
|
|
139
|
-
<PaginationEllipsis
|
|
141
|
+
<PaginationEllipsis
|
|
142
|
+
v-else
|
|
143
|
+
:key="item.type"
|
|
144
|
+
:class="[
|
|
145
|
+
style.item({ class: props.ui?.item }),
|
|
146
|
+
style.ellipsis({ class: props.ui?.ellipsis }),
|
|
147
|
+
]"
|
|
148
|
+
:index="index"
|
|
149
|
+
:disabled="props.disabled"
|
|
150
|
+
as-child
|
|
151
|
+
>
|
|
140
152
|
<slot name="ellipsis">
|
|
141
153
|
<Button
|
|
142
154
|
:variant="props.variant"
|
|
143
155
|
:size="props.size"
|
|
144
156
|
:icon="ellipsisIcon"
|
|
145
|
-
:disabled="props.disabled /* TODO: remove after reka-ui update */"
|
|
146
|
-
:class="[
|
|
147
|
-
style.item({ class: props.ui?.item }),
|
|
148
|
-
style.ellipsis({ class: props.ui?.ellipsis }),
|
|
149
|
-
]"
|
|
150
157
|
/>
|
|
151
158
|
</slot>
|
|
152
159
|
</PaginationEllipsis>
|
|
153
160
|
</template>
|
|
154
161
|
|
|
155
|
-
<PaginationNext v-if="props.showControls || !!slots.next" as-child>
|
|
162
|
+
<PaginationNext v-if="props.showControls || !!slots.next" :class="style.next({ class: props.ui?.next })" as-child>
|
|
156
163
|
<slot name="next">
|
|
157
|
-
<Button :
|
|
164
|
+
<Button :variant="props.variant" :size="props.size" :icon="nextIcon" :to="page < pageCount ? props.to?.(page + 1) : undefined" />
|
|
158
165
|
</slot>
|
|
159
166
|
</PaginationNext>
|
|
160
|
-
<PaginationLast v-if="props.showControls || !!slots.last" as-child>
|
|
167
|
+
<PaginationLast v-if="props.showControls || !!slots.last" :class="style.last({ class: props.ui?.last })" as-child>
|
|
161
168
|
<slot name="last">
|
|
162
|
-
<Button :
|
|
169
|
+
<Button :variant="props.variant" :size="props.size" :icon="lastIcon" :to="props.to?.(pageCount)" />
|
|
163
170
|
</slot>
|
|
164
171
|
</PaginationLast>
|
|
165
172
|
</PaginationList>
|
|
@@ -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,44 +42,49 @@ const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultValue', 'disa
|
|
|
41
42
|
|
|
42
43
|
const completed = ref(false)
|
|
43
44
|
|
|
44
|
-
const {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const { id, name, size, highlight, disabled, ariaAttrs, emitFormInput, emitFormChange, emitFormFocus, emitFormBlur } = useFormItem<PinInputProps>(props)
|
|
46
|
+
const { generateStyle } = useTheme()
|
|
47
|
+
const style = computed(() => generateStyle('pinInput', {
|
|
48
|
+
...props,
|
|
49
|
+
size: size.value,
|
|
50
|
+
highlight: highlight.value,
|
|
51
|
+
}))
|
|
49
52
|
|
|
50
53
|
function onComplete(value: string[]) {
|
|
51
54
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
52
55
|
const event = new Event('change', { target: { value } })
|
|
53
56
|
emit('change', event)
|
|
57
|
+
emitFormChange()
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
function onBlur(event: FocusEvent) {
|
|
57
|
-
if (!event.relatedTarget || completed.value)
|
|
61
|
+
if (!event.relatedTarget || completed.value) {
|
|
58
62
|
emit('blur', event)
|
|
63
|
+
emitFormBlur()
|
|
64
|
+
}
|
|
59
65
|
}
|
|
60
66
|
</script>
|
|
61
67
|
|
|
62
68
|
<template>
|
|
63
69
|
<PinInputRoot
|
|
64
|
-
v-bind="rootProps"
|
|
65
|
-
:id="props.id"
|
|
66
|
-
:name="props.name"
|
|
70
|
+
v-bind="{ ...rootProps, ...ariaAttrs, id, name }"
|
|
67
71
|
:class="style.root({ class: [props.class, props.ui?.root] })"
|
|
72
|
+
@update:model-value="emitFormInput"
|
|
68
73
|
@complete="onComplete"
|
|
69
74
|
>
|
|
70
75
|
<span
|
|
71
76
|
v-for="(ids, index) in looseToNumber(props.length)"
|
|
72
77
|
:key="ids"
|
|
73
78
|
:class="style.container({ class: props.ui?.container })"
|
|
74
|
-
:aria-disabled="
|
|
79
|
+
:aria-disabled="disabled ? true : undefined"
|
|
75
80
|
>
|
|
76
81
|
<PinInputInput
|
|
77
|
-
:index="index"
|
|
78
|
-
:class="style.base({ class: props.ui?.base })"
|
|
79
82
|
v-bind="$attrs"
|
|
80
|
-
:
|
|
83
|
+
:class="style.base({ class: props.ui?.base })"
|
|
84
|
+
:index="index"
|
|
85
|
+
:disabled="disabled"
|
|
81
86
|
@blur="onBlur"
|
|
87
|
+
@focus="emitFormFocus"
|
|
82
88
|
/>
|
|
83
89
|
</span>
|
|
84
90
|
</PinInputRoot>
|