@bitrix24/b24ui-nuxt 0.1.1
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/.nuxt/b24ui/advice.ts +52 -0
- package/.nuxt/b24ui/alert.ts +118 -0
- package/.nuxt/b24ui/avatar-group.ts +52 -0
- package/.nuxt/b24ui/avatar.ts +63 -0
- package/.nuxt/b24ui/badge.ts +256 -0
- package/.nuxt/b24ui/button-group.ts +27 -0
- package/.nuxt/b24ui/button.ts +342 -0
- package/.nuxt/b24ui/checkbox.ts +128 -0
- package/.nuxt/b24ui/chip.ts +205 -0
- package/.nuxt/b24ui/container.ts +3 -0
- package/.nuxt/b24ui/content/description-list.ts +62 -0
- package/.nuxt/b24ui/countdown.ts +94 -0
- package/.nuxt/b24ui/form-field.ts +57 -0
- package/.nuxt/b24ui/form.ts +3 -0
- package/.nuxt/b24ui/index.ts +28 -0
- package/.nuxt/b24ui/input.ts +472 -0
- package/.nuxt/b24ui/kbd.ts +31 -0
- package/.nuxt/b24ui/link.ts +20 -0
- package/.nuxt/b24ui/progress.ts +303 -0
- package/.nuxt/b24ui/radio-group.ts +135 -0
- package/.nuxt/b24ui/range.ts +172 -0
- package/.nuxt/b24ui/select.ts +550 -0
- package/.nuxt/b24ui/separator.ts +176 -0
- package/.nuxt/b24ui/skeleton.ts +3 -0
- package/.nuxt/b24ui/switch.ts +134 -0
- package/.nuxt/b24ui/tabs.ts +341 -0
- package/.nuxt/b24ui/textarea.ts +332 -0
- package/.nuxt/b24ui/toast.ts +89 -0
- package/.nuxt/b24ui/toaster.ts +91 -0
- package/.nuxt/b24ui/tooltip.ts +16 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/cli/commands/make/component.mjs +95 -0
- package/cli/commands/make/index.mjs +14 -0
- package/cli/commands/make/locale.mjs +64 -0
- package/cli/index.mjs +15 -0
- package/cli/package.json +13 -0
- package/cli/templates.mjs +240 -0
- package/cli/utils.mjs +31 -0
- package/dist/meta.cjs +23610 -0
- package/dist/meta.d.cts +23608 -0
- package/dist/meta.d.mts +23608 -0
- package/dist/meta.d.ts +23608 -0
- package/dist/meta.mjs +23608 -0
- package/dist/module.cjs +54 -0
- package/dist/module.d.cts +14 -0
- package/dist/module.d.mts +14 -0
- package/dist/module.d.ts +14 -0
- package/dist/module.json +13 -0
- package/dist/module.mjs +51 -0
- package/dist/runtime/components/Advice.vue +115 -0
- package/dist/runtime/components/Alert.vue +136 -0
- package/dist/runtime/components/App.vue +52 -0
- package/dist/runtime/components/Avatar.vue +118 -0
- package/dist/runtime/components/AvatarGroup.vue +99 -0
- package/dist/runtime/components/Badge.vue +114 -0
- package/dist/runtime/components/Button.vue +177 -0
- package/dist/runtime/components/ButtonGroup.vue +58 -0
- package/dist/runtime/components/Checkbox.vue +110 -0
- package/dist/runtime/components/Chip.vue +81 -0
- package/dist/runtime/components/Container.vue +36 -0
- package/dist/runtime/components/Countdown.vue +498 -0
- package/dist/runtime/components/Form.vue +271 -0
- package/dist/runtime/components/FormField.vue +128 -0
- package/dist/runtime/components/Input.vue +224 -0
- package/dist/runtime/components/Kbd.vue +50 -0
- package/dist/runtime/components/Link.vue +219 -0
- package/dist/runtime/components/LinkBase.vue +63 -0
- package/dist/runtime/components/Progress.vue +182 -0
- package/dist/runtime/components/RadioGroup.vue +178 -0
- package/dist/runtime/components/Range.vue +114 -0
- package/dist/runtime/components/Select.vue +328 -0
- package/dist/runtime/components/Separator.vue +82 -0
- package/dist/runtime/components/Skeleton.vue +31 -0
- package/dist/runtime/components/Switch.vue +133 -0
- package/dist/runtime/components/Tabs.vue +127 -0
- package/dist/runtime/components/Textarea.vue +216 -0
- package/dist/runtime/components/Toast.vue +168 -0
- package/dist/runtime/components/Toaster.vue +143 -0
- package/dist/runtime/components/Tooltip.vue +94 -0
- package/dist/runtime/components/content/DescriptionList.vue +220 -0
- package/dist/runtime/composables/defineLocale.d.ts +9 -0
- package/dist/runtime/composables/defineLocale.js +4 -0
- package/dist/runtime/composables/defineShortcuts.d.ts +15 -0
- package/dist/runtime/composables/defineShortcuts.js +135 -0
- package/dist/runtime/composables/useAvatarGroup.d.ts +10 -0
- package/dist/runtime/composables/useAvatarGroup.js +10 -0
- package/dist/runtime/composables/useButtonGroup.d.ts +17 -0
- package/dist/runtime/composables/useButtonGroup.js +10 -0
- package/dist/runtime/composables/useComponentIcons.d.ts +20 -0
- package/dist/runtime/composables/useComponentIcons.js +25 -0
- package/dist/runtime/composables/useFormField.d.ts +42 -0
- package/dist/runtime/composables/useFormField.js +65 -0
- package/dist/runtime/composables/useKbd.d.ts +35 -0
- package/dist/runtime/composables/useKbd.js +52 -0
- package/dist/runtime/composables/useLocale.d.ts +4 -0
- package/dist/runtime/composables/useLocale.js +10 -0
- package/dist/runtime/composables/useToast.d.ts +12 -0
- package/dist/runtime/composables/useToast.js +62 -0
- package/dist/runtime/dictionary/icons.d.ts +20 -0
- package/dist/runtime/dictionary/icons.js +35 -0
- package/dist/runtime/index.css +1 -0
- package/dist/runtime/keyframes.css +1 -0
- package/dist/runtime/locale/en.d.ts +2 -0
- package/dist/runtime/locale/en.js +48 -0
- package/dist/runtime/locale/es.d.ts +2 -0
- package/dist/runtime/locale/es.js +48 -0
- package/dist/runtime/locale/index.d.ts +3 -0
- package/dist/runtime/locale/index.js +3 -0
- package/dist/runtime/locale/ru.d.ts +2 -0
- package/dist/runtime/locale/ru.js +48 -0
- package/dist/runtime/plugins/colors.d.ts +2 -0
- package/dist/runtime/plugins/colors.js +40 -0
- package/dist/runtime/types/app.config.d.ts +6 -0
- package/dist/runtime/types/form.d.ts +84 -0
- package/dist/runtime/types/form.js +12 -0
- package/dist/runtime/types/icons.d.ts +3 -0
- package/dist/runtime/types/icons.js +0 -0
- package/dist/runtime/types/index.d.ts +33 -0
- package/dist/runtime/types/index.js +33 -0
- package/dist/runtime/types/locale.d.ts +50 -0
- package/dist/runtime/types/locale.js +0 -0
- package/dist/runtime/types/utils.d.ts +22 -0
- package/dist/runtime/types/utils.js +0 -0
- package/dist/runtime/utils/form.d.ts +17 -0
- package/dist/runtime/utils/form.js +153 -0
- package/dist/runtime/utils/fuse.d.ts +4 -0
- package/dist/runtime/utils/fuse.js +63 -0
- package/dist/runtime/utils/index.d.ts +6 -0
- package/dist/runtime/utils/index.js +63 -0
- package/dist/runtime/utils/link.d.ts +29 -0
- package/dist/runtime/utils/link.js +4 -0
- package/dist/runtime/utils/locale.d.ts +15 -0
- package/dist/runtime/utils/locale.js +25 -0
- package/dist/runtime/utils/tv.d.ts +1 -0
- package/dist/runtime/utils/tv.js +4 -0
- package/dist/runtime/vue/components/Link.vue +203 -0
- package/dist/runtime/vue/plugins/color-mode.d.ts +4 -0
- package/dist/runtime/vue/plugins/color-mode.js +6 -0
- package/dist/runtime/vue/plugins/head.d.ts +4 -0
- package/dist/runtime/vue/plugins/head.js +6 -0
- package/dist/runtime/vue/stubs.d.ts +15 -0
- package/dist/runtime/vue/stubs.js +27 -0
- package/dist/shared/b24ui-nuxt.CNGvMe2S.mjs +4074 -0
- package/dist/shared/b24ui-nuxt.D22QQtm8.cjs +4079 -0
- package/dist/types.d.mts +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/unplugin.cjs +213 -0
- package/dist/unplugin.d.cts +22 -0
- package/dist/unplugin.d.mts +22 -0
- package/dist/unplugin.d.ts +22 -0
- package/dist/unplugin.mjs +202 -0
- package/dist/vite.cjs +21 -0
- package/dist/vite.d.cts +12 -0
- package/dist/vite.d.mts +12 -0
- package/dist/vite.d.ts +12 -0
- package/dist/vite.mjs +19 -0
- package/package.json +166 -0
- package/vue-plugin.d.ts +5 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ButtonHTMLAttributes } from 'vue'
|
|
3
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
4
|
+
import _appConfig from '#build/app.config'
|
|
5
|
+
import type { RouterLinkProps, RouteLocationRaw } from 'vue-router'
|
|
6
|
+
import theme from '#build/b24ui/link'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
8
|
+
|
|
9
|
+
interface NuxtLinkProps extends Omit<RouterLinkProps, 'to'> {
|
|
10
|
+
/**
|
|
11
|
+
* Route Location the link should navigate to when clicked on.
|
|
12
|
+
*/
|
|
13
|
+
to?: RouteLocationRaw // need to manually type to avoid breaking typedPages
|
|
14
|
+
/**
|
|
15
|
+
* An alias for `to`. If used with `to`, `href` will be ignored
|
|
16
|
+
*/
|
|
17
|
+
href?: NuxtLinkProps['to']
|
|
18
|
+
/**
|
|
19
|
+
* Forces the link to be considered as external (true) or internal (false). This is helpful to handle edge-cases
|
|
20
|
+
*/
|
|
21
|
+
external?: boolean
|
|
22
|
+
/**
|
|
23
|
+
* Where to display the linked URL as the name for a browsing context.
|
|
24
|
+
*/
|
|
25
|
+
target?: '_blank' | '_parent' | '_self' | '_top' | (string & {}) | null
|
|
26
|
+
/**
|
|
27
|
+
* A rel attribute value to apply on the link. Defaults to "noopener noreferrer" for external links.
|
|
28
|
+
*/
|
|
29
|
+
rel?: 'noopener' | 'noreferrer' | 'nofollow' | 'sponsored' | 'ugc' | (string & {}) | null
|
|
30
|
+
/**
|
|
31
|
+
* If set to true, no rel attribute will be added to the link
|
|
32
|
+
*/
|
|
33
|
+
noRel?: boolean
|
|
34
|
+
/**
|
|
35
|
+
* A class to apply to links that have been prefetched.
|
|
36
|
+
*/
|
|
37
|
+
prefetchedClass?: string
|
|
38
|
+
/**
|
|
39
|
+
* When enabled will prefetch middleware, layouts and payloads of links in the viewport.
|
|
40
|
+
*/
|
|
41
|
+
prefetch?: boolean
|
|
42
|
+
/**
|
|
43
|
+
* Allows controlling when to prefetch links. By default, prefetch is triggered only on visibility.
|
|
44
|
+
*/
|
|
45
|
+
prefetchOn?: 'visibility' | 'interaction' | Partial<{
|
|
46
|
+
visibility: boolean
|
|
47
|
+
interaction: boolean
|
|
48
|
+
}>
|
|
49
|
+
/**
|
|
50
|
+
* Escape hatch to disable `prefetch` attribute.
|
|
51
|
+
*/
|
|
52
|
+
noPrefetch?: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const appConfigLink = _appConfig as AppConfig & { b24ui: { link: Partial<typeof theme> } }
|
|
56
|
+
|
|
57
|
+
const link = tv({ extend: tv(theme), ...(appConfigLink.b24ui?.link || {}) })
|
|
58
|
+
|
|
59
|
+
export interface LinkProps extends NuxtLinkProps {
|
|
60
|
+
/**
|
|
61
|
+
* The element or component this component should render as when not a link.
|
|
62
|
+
* @defaultValue 'button'
|
|
63
|
+
*/
|
|
64
|
+
as?: any
|
|
65
|
+
/**
|
|
66
|
+
* The type of the button when not a link.
|
|
67
|
+
* @defaultValue 'button'
|
|
68
|
+
*/
|
|
69
|
+
type?: ButtonHTMLAttributes['type']
|
|
70
|
+
disabled?: boolean
|
|
71
|
+
/** Force the link to be active independent of the current route. */
|
|
72
|
+
active?: boolean
|
|
73
|
+
/** Will only be active if the current route is an exact match. */
|
|
74
|
+
exact?: boolean
|
|
75
|
+
/** Allows controlling how the current route query sets the link as active. */
|
|
76
|
+
exactQuery?: boolean | 'partial'
|
|
77
|
+
/** Will only be active if the current route hash is an exact match. */
|
|
78
|
+
exactHash?: boolean
|
|
79
|
+
/** The class to apply when the link is inactive. */
|
|
80
|
+
inactiveClass?: string
|
|
81
|
+
custom?: boolean
|
|
82
|
+
/** When `true`, uses special underlined styling. */
|
|
83
|
+
isAction?: boolean
|
|
84
|
+
/** When `true`, only styles from `class`, `activeClass`, and `inactiveClass` will be applied. */
|
|
85
|
+
raw?: boolean
|
|
86
|
+
class?: any
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface LinkSlots {
|
|
90
|
+
default(props: { active: boolean }): any
|
|
91
|
+
}
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<script setup lang="ts">
|
|
95
|
+
import { computed } from 'vue'
|
|
96
|
+
import { isEqual, diff } from 'ohash'
|
|
97
|
+
import { useForwardProps } from 'reka-ui'
|
|
98
|
+
import { reactiveOmit } from '@vueuse/core'
|
|
99
|
+
import { useRoute } from '#imports'
|
|
100
|
+
import B24LinkBase from './LinkBase.vue'
|
|
101
|
+
|
|
102
|
+
defineOptions({ inheritAttrs: false })
|
|
103
|
+
|
|
104
|
+
const props = withDefaults(defineProps<LinkProps>(), {
|
|
105
|
+
as: 'button',
|
|
106
|
+
type: 'button',
|
|
107
|
+
active: undefined,
|
|
108
|
+
isAction: false,
|
|
109
|
+
activeClass: '',
|
|
110
|
+
inactiveClass: ''
|
|
111
|
+
})
|
|
112
|
+
defineSlots<LinkSlots>()
|
|
113
|
+
|
|
114
|
+
const route = useRoute()
|
|
115
|
+
const nuxtLinkProps = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'exactQuery', 'exactHash', 'activeClass', 'inactiveClass', 'raw', 'class'))
|
|
116
|
+
|
|
117
|
+
const b24ui = computed(() => tv({
|
|
118
|
+
extend: link,
|
|
119
|
+
variants: {
|
|
120
|
+
active: {
|
|
121
|
+
true: props.activeClass,
|
|
122
|
+
false: props.inactiveClass
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}))
|
|
126
|
+
|
|
127
|
+
function isPartiallyEqual(item1: any, item2: any) {
|
|
128
|
+
const diffedKeys = diff(item1, item2).reduce((filtered, q) => {
|
|
129
|
+
if (q.type === 'added') {
|
|
130
|
+
filtered.push(q.key)
|
|
131
|
+
}
|
|
132
|
+
return filtered
|
|
133
|
+
}, [] as string[])
|
|
134
|
+
return isEqual(item1, item2, { excludeKeys: key => diffedKeys.includes(key) })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isLinkActive({ route: linkRoute, isActive, isExactActive }: any) {
|
|
138
|
+
if (props.active !== undefined) {
|
|
139
|
+
return props.active
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (props.exactQuery === 'partial') {
|
|
143
|
+
if (!isPartiallyEqual(linkRoute.query, route.query)) return false
|
|
144
|
+
} else if (props.exactQuery === true) {
|
|
145
|
+
if (!isEqual(linkRoute.query, route.query)) return false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (props.exactHash && linkRoute.hash !== route.hash) {
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (props.exact && isExactActive) {
|
|
153
|
+
return true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!props.exact && isActive) {
|
|
157
|
+
return true
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function resolveLinkClass({ route, isActive, isExactActive }: any) {
|
|
164
|
+
const active = isLinkActive({ route, isActive, isExactActive })
|
|
165
|
+
|
|
166
|
+
if (props.raw) {
|
|
167
|
+
return [props.class, active ? props.activeClass : props.inactiveClass]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return b24ui.value({
|
|
171
|
+
class: props.class,
|
|
172
|
+
active,
|
|
173
|
+
disabled: props.disabled,
|
|
174
|
+
isAction: Boolean(props.isAction)
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<template>
|
|
180
|
+
<NuxtLink
|
|
181
|
+
v-slot="{ href, navigate, route: linkRoute, rel, target, isExternal, isActive, isExactActive }"
|
|
182
|
+
v-bind="nuxtLinkProps"
|
|
183
|
+
custom
|
|
184
|
+
>
|
|
185
|
+
<template v-if="custom">
|
|
186
|
+
<slot
|
|
187
|
+
v-bind="{
|
|
188
|
+
...$attrs,
|
|
189
|
+
as,
|
|
190
|
+
type,
|
|
191
|
+
disabled,
|
|
192
|
+
href,
|
|
193
|
+
navigate,
|
|
194
|
+
rel,
|
|
195
|
+
target,
|
|
196
|
+
isExternal,
|
|
197
|
+
active: isLinkActive({ route: linkRoute, isActive, isExactActive })
|
|
198
|
+
}"
|
|
199
|
+
/>
|
|
200
|
+
</template>
|
|
201
|
+
<B24LinkBase
|
|
202
|
+
v-else
|
|
203
|
+
v-bind="{
|
|
204
|
+
...$attrs,
|
|
205
|
+
as,
|
|
206
|
+
type,
|
|
207
|
+
disabled,
|
|
208
|
+
href,
|
|
209
|
+
navigate,
|
|
210
|
+
rel,
|
|
211
|
+
target,
|
|
212
|
+
isExternal
|
|
213
|
+
}"
|
|
214
|
+
:class="resolveLinkClass({ route: linkRoute, isActive, isExactActive })"
|
|
215
|
+
>
|
|
216
|
+
<slot :active="isLinkActive({ route: linkRoute, isActive, isExactActive })" />
|
|
217
|
+
</B24LinkBase>
|
|
218
|
+
</NuxtLink>
|
|
219
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export interface LinkBaseProps {
|
|
3
|
+
as?: string
|
|
4
|
+
type?: string
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
onClick?: ((e: MouseEvent) => void | Promise<void>) | Array<((e: MouseEvent) => void | Promise<void>)>
|
|
7
|
+
href?: string
|
|
8
|
+
navigate?: (e: MouseEvent) => void
|
|
9
|
+
rel?: string
|
|
10
|
+
target?: string
|
|
11
|
+
isExternal?: boolean
|
|
12
|
+
}
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import { Primitive } from 'reka-ui'
|
|
17
|
+
|
|
18
|
+
const props = withDefaults(defineProps<LinkBaseProps>(), {
|
|
19
|
+
as: 'button',
|
|
20
|
+
type: 'button'
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function onClickWrapper(e: MouseEvent) {
|
|
24
|
+
if (props.disabled) {
|
|
25
|
+
e.stopPropagation()
|
|
26
|
+
e.preventDefault()
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (props.onClick) {
|
|
31
|
+
for (const onClick of Array.isArray(props.onClick) ? props.onClick : [props.onClick]) {
|
|
32
|
+
onClick(e)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (props.href && props.navigate && !props.isExternal) {
|
|
37
|
+
props.navigate(e)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<Primitive
|
|
44
|
+
v-bind="href ? {
|
|
45
|
+
'as': 'a',
|
|
46
|
+
'href': disabled ? undefined : href,
|
|
47
|
+
'aria-disabled': disabled ? 'true' : undefined,
|
|
48
|
+
'role': disabled ? 'link' : undefined,
|
|
49
|
+
'tabindex': disabled ? -1 : undefined
|
|
50
|
+
} : as === 'button' ? {
|
|
51
|
+
as,
|
|
52
|
+
type,
|
|
53
|
+
disabled
|
|
54
|
+
} : {
|
|
55
|
+
as
|
|
56
|
+
}"
|
|
57
|
+
:rel="rel"
|
|
58
|
+
:target="target"
|
|
59
|
+
@click="onClickWrapper"
|
|
60
|
+
>
|
|
61
|
+
<slot />
|
|
62
|
+
</Primitive>
|
|
63
|
+
</template>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<!-- eslint-disable vue/block-tag-newline -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
4
|
+
import type { ProgressRootProps, ProgressRootEmits } from 'reka-ui'
|
|
5
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
6
|
+
import _appConfig from '#build/app.config'
|
|
7
|
+
import theme from '#build/b24ui/progress'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
9
|
+
|
|
10
|
+
const appConfigProgress = _appConfig as AppConfig & { b24ui: { progress: Partial<typeof theme> } }
|
|
11
|
+
|
|
12
|
+
const progress = tv({ extend: tv(theme), ...(appConfigProgress.b24ui?.progress || {}) })
|
|
13
|
+
|
|
14
|
+
type ProgressVariants = VariantProps<typeof progress>
|
|
15
|
+
|
|
16
|
+
export interface ProgressProps extends Pick<ProgressRootProps, 'getValueLabel' | 'modelValue'> {
|
|
17
|
+
/**
|
|
18
|
+
* The element or component this component should render as.
|
|
19
|
+
* @defaultValue 'div'
|
|
20
|
+
*/
|
|
21
|
+
as?: any
|
|
22
|
+
/** The maximum progress value. */
|
|
23
|
+
max?: number | Array<any>
|
|
24
|
+
/** Display the current progress value. */
|
|
25
|
+
status?: boolean
|
|
26
|
+
/** Whether the progress is visually inverted. */
|
|
27
|
+
inverted?: boolean
|
|
28
|
+
size?: ProgressVariants['size']
|
|
29
|
+
color?: ProgressVariants['color']
|
|
30
|
+
/**
|
|
31
|
+
* The orientation of the progress bar.
|
|
32
|
+
* @defaultValue 'horizontal'
|
|
33
|
+
*/
|
|
34
|
+
orientation?: ProgressVariants['orientation']
|
|
35
|
+
animation?: ProgressVariants['animation']
|
|
36
|
+
class?: any
|
|
37
|
+
b24ui?: Partial<typeof progress.slots>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ProgressEmits extends ProgressRootEmits {}
|
|
41
|
+
|
|
42
|
+
export type ProgressSlots = {
|
|
43
|
+
status(props: { percent?: number }): any
|
|
44
|
+
} & {
|
|
45
|
+
[key: string]: (props: { step: number }) => any
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<script setup lang="ts">
|
|
51
|
+
import { computed } from 'vue'
|
|
52
|
+
import { Primitive, ProgressRoot, ProgressIndicator, useForwardPropsEmits } from 'reka-ui'
|
|
53
|
+
import { reactivePick } from '@vueuse/core'
|
|
54
|
+
import { useLocale } from '../composables/useLocale'
|
|
55
|
+
|
|
56
|
+
const props = withDefaults(defineProps<ProgressProps>(), {
|
|
57
|
+
inverted: false,
|
|
58
|
+
modelValue: null,
|
|
59
|
+
orientation: 'horizontal'
|
|
60
|
+
})
|
|
61
|
+
const emits = defineEmits<ProgressEmits>()
|
|
62
|
+
const slots = defineSlots<ProgressSlots>()
|
|
63
|
+
|
|
64
|
+
const { dir } = useLocale()
|
|
65
|
+
|
|
66
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'getValueLabel', 'modelValue'), emits)
|
|
67
|
+
|
|
68
|
+
const isIndeterminate = computed(() => rootProps.value.modelValue === null)
|
|
69
|
+
const hasSteps = computed(() => Array.isArray(props.max))
|
|
70
|
+
|
|
71
|
+
const realMax = computed(() => {
|
|
72
|
+
if (isIndeterminate.value || !props.max) {
|
|
73
|
+
return undefined
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (Array.isArray(props.max)) {
|
|
77
|
+
return props.max.length - 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return Number(props.max)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const percent = computed(() => {
|
|
84
|
+
if (isIndeterminate.value) {
|
|
85
|
+
return undefined
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
switch (true) {
|
|
89
|
+
case rootProps.value.modelValue! < 0: return 0
|
|
90
|
+
case rootProps.value.modelValue! > (realMax.value ?? 100): return 100
|
|
91
|
+
default: return Math.round((rootProps.value.modelValue! / (realMax.value ?? 100)) * 100)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const indicatorStyle = computed(() => {
|
|
96
|
+
if (percent.value === undefined) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (props.orientation === 'vertical') {
|
|
101
|
+
return {
|
|
102
|
+
transform: `translateY(${props.inverted ? '' : '-'}${100 - percent.value}%)`
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
if (dir.value === 'rtl') {
|
|
106
|
+
return {
|
|
107
|
+
transform: `translateX(${props.inverted ? '-' : ''}${100 - percent.value}%)`
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
return {
|
|
111
|
+
transform: `translateX(${props.inverted ? '' : '-'}${100 - percent.value}%)`
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const statusStyle = computed(() => {
|
|
118
|
+
return {
|
|
119
|
+
[props.orientation === 'vertical' ? 'height' : 'width']: percent.value ? `${percent.value}%` : 'fit-content'
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
function isActive(index: number) {
|
|
124
|
+
return index === Number(props.modelValue)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function isFirst(index: number) {
|
|
128
|
+
return index === 0
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isLast(index: number) {
|
|
132
|
+
return index === realMax.value
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function stepVariant(index: number | string) {
|
|
136
|
+
index = Number(index)
|
|
137
|
+
|
|
138
|
+
if (isActive(index) && !isFirst(index)) {
|
|
139
|
+
return 'active'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (isFirst(index) && isActive(index)) {
|
|
143
|
+
return 'first'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (isLast(index) && isActive(index)) {
|
|
147
|
+
return 'last'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return 'other'
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const b24ui = computed(() => progress({
|
|
154
|
+
animation: props.animation,
|
|
155
|
+
size: props.size,
|
|
156
|
+
color: props.color,
|
|
157
|
+
orientation: props.orientation,
|
|
158
|
+
inverted: props.inverted
|
|
159
|
+
}))
|
|
160
|
+
</script>
|
|
161
|
+
|
|
162
|
+
<template>
|
|
163
|
+
<Primitive :as="as" :class="b24ui.root({ class: [props.class, props.b24ui?.root] })">
|
|
164
|
+
<div v-if="!isIndeterminate && (status || !!slots.status)" :class="b24ui.status({ class: props.b24ui?.status })" :style="statusStyle">
|
|
165
|
+
<slot name="status" :percent="percent">
|
|
166
|
+
{{ percent }}%
|
|
167
|
+
</slot>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<ProgressRoot v-bind="rootProps" :max="realMax" :class="b24ui.base({ class: props.b24ui?.base })" style="transform: translateZ(0)">
|
|
171
|
+
<ProgressIndicator :class="b24ui.indicator({ class: props.b24ui?.indicator })" :style="indicatorStyle" />
|
|
172
|
+
</ProgressRoot>
|
|
173
|
+
|
|
174
|
+
<div v-if="hasSteps" :class="b24ui.steps({ class: props.b24ui?.steps })">
|
|
175
|
+
<div v-for="(step, index) in max" :key="index" :class="b24ui.step({ class: props.b24ui?.step, step: stepVariant(index) })">
|
|
176
|
+
<slot :name="`step-${index}`" :step="step">
|
|
177
|
+
{{ step }}
|
|
178
|
+
</slot>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</Primitive>
|
|
182
|
+
</template>
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { RadioGroupRootProps, RadioGroupRootEmits, AcceptableValue } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
5
|
+
import _appConfig from '#build/app.config'
|
|
6
|
+
import theme from '#build/b24ui/radio-group'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
8
|
+
|
|
9
|
+
const appConfigRadioGroup = _appConfig as AppConfig & { b24ui: { radioGroup: Partial<typeof theme> } }
|
|
10
|
+
|
|
11
|
+
const radioGroup = tv({ extend: tv(theme), ...(appConfigRadioGroup.b24ui?.radioGroup || {}) })
|
|
12
|
+
|
|
13
|
+
type RadioGroupVariants = VariantProps<typeof radioGroup>
|
|
14
|
+
|
|
15
|
+
export interface RadioGroupItem {
|
|
16
|
+
label?: string
|
|
17
|
+
description?: string
|
|
18
|
+
disabled?: boolean
|
|
19
|
+
value?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RadioGroupProps<T> extends Pick<RadioGroupRootProps, 'defaultValue' | 'disabled' | 'loop' | 'modelValue' | 'name' | 'required'> {
|
|
23
|
+
/**
|
|
24
|
+
* The element or component this component should render as.
|
|
25
|
+
* @defaultValue 'div'
|
|
26
|
+
*/
|
|
27
|
+
as?: any
|
|
28
|
+
legend?: string
|
|
29
|
+
/**
|
|
30
|
+
* When `items` is an array of objects, select the field to use as the value.
|
|
31
|
+
* @defaultValue 'value'
|
|
32
|
+
*/
|
|
33
|
+
valueKey?: string
|
|
34
|
+
/**
|
|
35
|
+
* When `items` is an array of objects, select the field to use as the label.
|
|
36
|
+
* @defaultValue 'label'
|
|
37
|
+
*/
|
|
38
|
+
labelKey?: string
|
|
39
|
+
/**
|
|
40
|
+
* When `items` is an array of objects, select the field to use as the description.
|
|
41
|
+
* @defaultValue 'description'
|
|
42
|
+
*/
|
|
43
|
+
descriptionKey?: string
|
|
44
|
+
items?: T[]
|
|
45
|
+
size?: RadioGroupVariants['size']
|
|
46
|
+
color?: RadioGroupVariants['color']
|
|
47
|
+
/**
|
|
48
|
+
* The orientation the radio buttons are laid out.
|
|
49
|
+
* @defaultValue 'vertical'
|
|
50
|
+
*/
|
|
51
|
+
orientation?: RadioGroupRootProps['orientation']
|
|
52
|
+
class?: any
|
|
53
|
+
b24ui?: Partial<typeof radioGroup.slots>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type RadioGroupEmits = RadioGroupRootEmits & {
|
|
57
|
+
change: [payload: Event]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type SlotProps<T> = (props: { item: T, modelValue?: AcceptableValue }) => any
|
|
61
|
+
|
|
62
|
+
export interface RadioGroupSlots<T> {
|
|
63
|
+
legend(props?: {}): any
|
|
64
|
+
label: SlotProps<T>
|
|
65
|
+
description: SlotProps<T>
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<script setup lang="ts" generic="T extends RadioGroupItem | AcceptableValue">
|
|
70
|
+
import { computed, useId } from 'vue'
|
|
71
|
+
import { RadioGroupRoot, RadioGroupItem, RadioGroupIndicator, Label, useForwardPropsEmits } from 'reka-ui'
|
|
72
|
+
import { reactivePick } from '@vueuse/core'
|
|
73
|
+
import { useFormField } from '../composables/useFormField'
|
|
74
|
+
import { get } from '../utils'
|
|
75
|
+
|
|
76
|
+
const props = withDefaults(defineProps<RadioGroupProps<T>>(), {
|
|
77
|
+
valueKey: 'value',
|
|
78
|
+
labelKey: 'label',
|
|
79
|
+
descriptionKey: 'description',
|
|
80
|
+
orientation: 'vertical'
|
|
81
|
+
})
|
|
82
|
+
const emits = defineEmits<RadioGroupEmits>()
|
|
83
|
+
const slots = defineSlots<RadioGroupSlots<T>>()
|
|
84
|
+
|
|
85
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emits)
|
|
86
|
+
|
|
87
|
+
const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled, ariaAttrs } = useFormField<RadioGroupProps<T>>(props, { bind: false })
|
|
88
|
+
const id = _id.value ?? useId()
|
|
89
|
+
|
|
90
|
+
const b24ui = computed(() => radioGroup({
|
|
91
|
+
size: size.value,
|
|
92
|
+
color: color.value,
|
|
93
|
+
disabled: disabled.value,
|
|
94
|
+
required: props.required,
|
|
95
|
+
orientation: props.orientation
|
|
96
|
+
}))
|
|
97
|
+
|
|
98
|
+
function normalizeItem(item: any) {
|
|
99
|
+
if (['string', 'number', 'boolean'].includes(typeof item)) {
|
|
100
|
+
return {
|
|
101
|
+
id: `${id}:${item}`,
|
|
102
|
+
value: item,
|
|
103
|
+
label: item
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const value = get(item, props.valueKey as string)
|
|
108
|
+
const label = get(item, props.labelKey as string)
|
|
109
|
+
const description = get(item, props.descriptionKey as string)
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
...item,
|
|
113
|
+
value,
|
|
114
|
+
label,
|
|
115
|
+
description,
|
|
116
|
+
id: `${id}:${value}`
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const normalizedItems = computed(() => {
|
|
121
|
+
if (!props.items) {
|
|
122
|
+
return []
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return props.items.map(normalizeItem)
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
function onUpdate(value: any) {
|
|
129
|
+
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
130
|
+
const event = new Event('change', { target: { value } })
|
|
131
|
+
emits('change', event)
|
|
132
|
+
emitFormChange()
|
|
133
|
+
emitFormInput()
|
|
134
|
+
}
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<template>
|
|
138
|
+
<RadioGroupRoot
|
|
139
|
+
:id="id"
|
|
140
|
+
v-slot="{ modelValue }"
|
|
141
|
+
v-bind="rootProps"
|
|
142
|
+
:name="name"
|
|
143
|
+
:disabled="disabled"
|
|
144
|
+
:class="b24ui.root({ class: [props.class, props.b24ui?.root] })"
|
|
145
|
+
@update:model-value="onUpdate"
|
|
146
|
+
>
|
|
147
|
+
<fieldset :class="b24ui.fieldset({ class: props.b24ui?.fieldset })" v-bind="ariaAttrs">
|
|
148
|
+
<legend v-if="legend || !!slots.legend" :class="b24ui.legend({ class: props.b24ui?.legend })">
|
|
149
|
+
<slot name="legend">
|
|
150
|
+
{{ legend }}
|
|
151
|
+
</slot>
|
|
152
|
+
</legend>
|
|
153
|
+
<div v-for="item in normalizedItems" :key="item.value" :class="b24ui.item({ class: props.b24ui?.item })">
|
|
154
|
+
<div :class="b24ui.container({ class: props.b24ui?.container })">
|
|
155
|
+
<RadioGroupItem
|
|
156
|
+
:id="item.id"
|
|
157
|
+
:value="item.value"
|
|
158
|
+
:disabled="disabled"
|
|
159
|
+
:class="b24ui.base({ class: props.b24ui?.base })"
|
|
160
|
+
>
|
|
161
|
+
<RadioGroupIndicator :class="b24ui.indicator({ class: props.b24ui?.indicator })" />
|
|
162
|
+
</RadioGroupItem>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<div :class="b24ui.wrapper({ class: props.b24ui?.wrapper })">
|
|
166
|
+
<Label :class="b24ui.label({ class: props.b24ui?.label })" :for="item.id">
|
|
167
|
+
<slot name="label" :item="item" :model-value="modelValue">{{ item.label }}</slot>
|
|
168
|
+
</Label>
|
|
169
|
+
<p v-if="item.description || !!slots.description" :class="b24ui.description({ class: props.b24ui?.description })">
|
|
170
|
+
<slot name="description" :item="item" :model-value="modelValue">
|
|
171
|
+
{{ item.description }}
|
|
172
|
+
</slot>
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</fieldset>
|
|
177
|
+
</RadioGroupRoot>
|
|
178
|
+
</template>
|