@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,133 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { SwitchRootProps } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
5
|
+
import _appConfig from '#build/app.config'
|
|
6
|
+
import theme from '#build/b24ui/switch'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
8
|
+
import type { IconComponent } from '../types'
|
|
9
|
+
import type { PartialString } from '../types/utils'
|
|
10
|
+
|
|
11
|
+
const appConfigSwitch = _appConfig as AppConfig & { b24ui: { switch: Partial<typeof theme> } }
|
|
12
|
+
|
|
13
|
+
const switchTv = tv({ extend: tv(theme), ...(appConfigSwitch.b24ui?.switch || {}) })
|
|
14
|
+
|
|
15
|
+
type SwitchVariants = VariantProps<typeof switchTv>
|
|
16
|
+
|
|
17
|
+
export interface SwitchProps extends Pick<SwitchRootProps, 'disabled' | 'id' | 'name' | 'required' | 'value' | 'defaultValue'> {
|
|
18
|
+
/**
|
|
19
|
+
* The element or component this component should render as.
|
|
20
|
+
* @defaultValue 'div'
|
|
21
|
+
*/
|
|
22
|
+
as?: any
|
|
23
|
+
color?: SwitchVariants['color']
|
|
24
|
+
size?: SwitchVariants['size']
|
|
25
|
+
/** When `true`, the loading icon will be displayed. */
|
|
26
|
+
loading?: boolean
|
|
27
|
+
/**
|
|
28
|
+
* The icon when the `loading` prop is `true`.
|
|
29
|
+
* @defaultValue icons.refresh
|
|
30
|
+
*/
|
|
31
|
+
loadingIcon?: IconComponent
|
|
32
|
+
/** Display an icon when the switch is checked. */
|
|
33
|
+
checkedIcon?: IconComponent
|
|
34
|
+
/** Display an icon when the switch is unchecked. */
|
|
35
|
+
uncheckedIcon?: IconComponent
|
|
36
|
+
label?: string
|
|
37
|
+
description?: string
|
|
38
|
+
class?: any
|
|
39
|
+
b24ui?: PartialString<typeof switchTv.slots>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type SwitchEmits = {
|
|
43
|
+
change: [payload: Event]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface SwitchSlots {
|
|
47
|
+
label(props: { label?: string }): any
|
|
48
|
+
description(props: { description?: string }): any
|
|
49
|
+
}
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
import { computed, useId } from 'vue'
|
|
54
|
+
import { Primitive, SwitchRoot, SwitchThumb, useForwardProps, Label } from 'reka-ui'
|
|
55
|
+
import { reactivePick } from '@vueuse/core'
|
|
56
|
+
import { useFormField } from '../composables/useFormField'
|
|
57
|
+
import icons from '../dictionary/icons'
|
|
58
|
+
|
|
59
|
+
const props = defineProps<SwitchProps>()
|
|
60
|
+
const slots = defineSlots<SwitchSlots>()
|
|
61
|
+
const emits = defineEmits<SwitchEmits>()
|
|
62
|
+
|
|
63
|
+
const modelValue = defineModel<boolean>({ default: undefined })
|
|
64
|
+
|
|
65
|
+
const rootProps = useForwardProps(reactivePick(props, 'required', 'value', 'defaultValue'))
|
|
66
|
+
|
|
67
|
+
const { id: _id, emitFormChange, emitFormInput, size, color, name, disabled, ariaAttrs } = useFormField<SwitchProps>(props)
|
|
68
|
+
const id = _id.value ?? useId()
|
|
69
|
+
|
|
70
|
+
const b24ui = computed(() => switchTv({
|
|
71
|
+
size: size.value,
|
|
72
|
+
color: color.value,
|
|
73
|
+
required: props.required,
|
|
74
|
+
loading: props.loading,
|
|
75
|
+
disabled: disabled.value || props.loading
|
|
76
|
+
}))
|
|
77
|
+
|
|
78
|
+
function onUpdate(value: any) {
|
|
79
|
+
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
80
|
+
const event = new Event('change', { target: { value } })
|
|
81
|
+
emits('change', event)
|
|
82
|
+
emitFormChange()
|
|
83
|
+
emitFormInput()
|
|
84
|
+
}
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<Primitive :as="as" :class="b24ui.root({ class: [props.class, props.b24ui?.root] })">
|
|
89
|
+
<div :class="b24ui.container({ class: props.b24ui?.container })">
|
|
90
|
+
<SwitchRoot
|
|
91
|
+
:id="id"
|
|
92
|
+
v-bind="{ ...rootProps, ...ariaAttrs }"
|
|
93
|
+
v-model="modelValue"
|
|
94
|
+
:name="name"
|
|
95
|
+
:disabled="disabled || loading"
|
|
96
|
+
:class="b24ui.base({ class: props.b24ui?.base })"
|
|
97
|
+
@update:model-value="onUpdate"
|
|
98
|
+
>
|
|
99
|
+
<SwitchThumb :class="b24ui.thumb({ class: props.b24ui?.thumb })">
|
|
100
|
+
<Component
|
|
101
|
+
:is="loadingIcon || icons.refresh"
|
|
102
|
+
v-if="loading"
|
|
103
|
+
:class="b24ui.icon({ class: props.b24ui?.icon, checked: true, unchecked: true })"
|
|
104
|
+
/>
|
|
105
|
+
<template v-else>
|
|
106
|
+
<Component
|
|
107
|
+
:is="checkedIcon"
|
|
108
|
+
v-if="checkedIcon"
|
|
109
|
+
:class="b24ui.icon({ class: props.b24ui?.icon, checked: true })"
|
|
110
|
+
/>
|
|
111
|
+
<Component
|
|
112
|
+
:is="uncheckedIcon"
|
|
113
|
+
v-if="uncheckedIcon"
|
|
114
|
+
:class="b24ui.icon({ class: props.b24ui?.icon, unchecked: true })"
|
|
115
|
+
/>
|
|
116
|
+
</template>
|
|
117
|
+
</SwitchThumb>
|
|
118
|
+
</SwitchRoot>
|
|
119
|
+
</div>
|
|
120
|
+
<div v-if="(label || !!slots.label) || (description || !!slots.description)" :class="b24ui.wrapper({ class: props.b24ui?.wrapper })">
|
|
121
|
+
<Label v-if="label || !!slots.label" :for="id" :class="b24ui.label({ class: props.b24ui?.label })">
|
|
122
|
+
<slot name="label" :label="label">
|
|
123
|
+
{{ label }}
|
|
124
|
+
</slot>
|
|
125
|
+
</Label>
|
|
126
|
+
<p v-if="description || !!slots.description" :class="b24ui.description({ class: props.b24ui?.description })">
|
|
127
|
+
<slot name="description" :description="description">
|
|
128
|
+
{{ description }}
|
|
129
|
+
</slot>
|
|
130
|
+
</p>
|
|
131
|
+
</div>
|
|
132
|
+
</Primitive>
|
|
133
|
+
</template>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { TabsRootProps, TabsRootEmits } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
5
|
+
import _appConfig from '#build/app.config'
|
|
6
|
+
import theme from '#build/b24ui/tabs'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
8
|
+
import type { AvatarProps, IconComponent } from '../types'
|
|
9
|
+
import type { DynamicSlots, PartialString } from '../types/utils'
|
|
10
|
+
|
|
11
|
+
const appConfigTabs = _appConfig as AppConfig & { b24ui: { tabs: Partial<typeof theme> } }
|
|
12
|
+
|
|
13
|
+
const tabs = tv({ extend: tv(theme), ...(appConfigTabs.b24ui?.tabs || {}) })
|
|
14
|
+
|
|
15
|
+
export interface TabsItem {
|
|
16
|
+
label?: string
|
|
17
|
+
icon?: IconComponent
|
|
18
|
+
avatar?: AvatarProps
|
|
19
|
+
slot?: string
|
|
20
|
+
content?: string
|
|
21
|
+
/** A unique value for the tab item. Defaults to the index. */
|
|
22
|
+
value?: string | number
|
|
23
|
+
disabled?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type TabsVariants = VariantProps<typeof tabs>
|
|
27
|
+
|
|
28
|
+
export interface TabsProps<T> extends Pick<TabsRootProps<string | number>, 'defaultValue' | 'modelValue' | 'activationMode' | 'unmountOnHide'> {
|
|
29
|
+
/**
|
|
30
|
+
* The element or component this component should render as.
|
|
31
|
+
* @defaultValue 'div'
|
|
32
|
+
*/
|
|
33
|
+
as?: any
|
|
34
|
+
items?: T[]
|
|
35
|
+
color?: TabsVariants['color']
|
|
36
|
+
variant?: TabsVariants['variant']
|
|
37
|
+
size?: TabsVariants['size']
|
|
38
|
+
/**
|
|
39
|
+
* The orientation of the tabs.
|
|
40
|
+
* @defaultValue 'horizontal'
|
|
41
|
+
*/
|
|
42
|
+
orientation?: TabsRootProps['orientation']
|
|
43
|
+
/**
|
|
44
|
+
* The content of the tabs, can be disabled to prevent rendering the content.
|
|
45
|
+
* @defaultValue true
|
|
46
|
+
*/
|
|
47
|
+
content?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* The key used to get the label from the item.
|
|
50
|
+
* @defaultValue 'label'
|
|
51
|
+
*/
|
|
52
|
+
labelKey?: string
|
|
53
|
+
class?: any
|
|
54
|
+
b24ui?: PartialString<typeof tabs.slots>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TabsEmits extends TabsRootEmits<string | number> {}
|
|
58
|
+
|
|
59
|
+
type SlotProps<T> = (props: { item: T, index: number }) => any
|
|
60
|
+
|
|
61
|
+
export type TabsSlots<T extends { slot?: string }> = {
|
|
62
|
+
leading: SlotProps<T>
|
|
63
|
+
default: SlotProps<T>
|
|
64
|
+
trailing: SlotProps<T>
|
|
65
|
+
content: SlotProps<T>
|
|
66
|
+
} & DynamicSlots<T, SlotProps<T>>
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<script setup lang="ts" generic="T extends TabsItem">
|
|
70
|
+
import { computed } from 'vue'
|
|
71
|
+
import { TabsRoot, TabsList, TabsIndicator, TabsTrigger, TabsContent, useForwardPropsEmits } from 'reka-ui'
|
|
72
|
+
import { reactivePick } from '@vueuse/core'
|
|
73
|
+
import { get } from '../utils'
|
|
74
|
+
import B24Avatar from './Avatar.vue'
|
|
75
|
+
|
|
76
|
+
const props = withDefaults(defineProps<TabsProps<T>>(), {
|
|
77
|
+
content: true,
|
|
78
|
+
defaultValue: '0',
|
|
79
|
+
orientation: 'horizontal',
|
|
80
|
+
unmountOnHide: true,
|
|
81
|
+
labelKey: 'label'
|
|
82
|
+
})
|
|
83
|
+
const emits = defineEmits<TabsEmits>()
|
|
84
|
+
const slots = defineSlots<TabsSlots<T>>()
|
|
85
|
+
|
|
86
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'activationMode', 'unmountOnHide'), emits)
|
|
87
|
+
|
|
88
|
+
const b24ui = computed(() => tabs({
|
|
89
|
+
color: props.color,
|
|
90
|
+
variant: props.variant,
|
|
91
|
+
size: props.size,
|
|
92
|
+
orientation: props.orientation
|
|
93
|
+
}))
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<template>
|
|
97
|
+
<TabsRoot v-bind="rootProps" :class="b24ui.root({ class: [props.class, props.b24ui?.root] })">
|
|
98
|
+
<TabsList :class="b24ui.list({ class: props.b24ui?.list })">
|
|
99
|
+
<TabsIndicator :class="b24ui.indicator({ class: props.b24ui?.indicator })" />
|
|
100
|
+
|
|
101
|
+
<TabsTrigger v-for="(item, index) of items" :key="index" :value="item.value || String(index)" :disabled="item.disabled" :class="b24ui.trigger({ class: props.b24ui?.trigger })">
|
|
102
|
+
<slot name="leading" :item="item" :index="index">
|
|
103
|
+
<Component
|
|
104
|
+
:is="item.icon"
|
|
105
|
+
v-if="item.icon"
|
|
106
|
+
:class="b24ui.leadingIcon({ class: props.b24ui?.leadingIcon })"
|
|
107
|
+
/>
|
|
108
|
+
<B24Avatar v-else-if="item.avatar" :size="((props.b24ui?.leadingAvatarSize || b24ui.leadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="b24ui.leadingAvatar({ class: props.b24ui?.leadingAvatar })" />
|
|
109
|
+
</slot>
|
|
110
|
+
|
|
111
|
+
<span v-if="get(item, props.labelKey as string) || !!slots.default" :class="b24ui.label({ class: props.b24ui?.label })">
|
|
112
|
+
<slot :item="item" :index="index">{{ get(item, props.labelKey as string) }}</slot>
|
|
113
|
+
</span>
|
|
114
|
+
|
|
115
|
+
<slot name="trailing" :item="item" :index="index" />
|
|
116
|
+
</TabsTrigger>
|
|
117
|
+
</TabsList>
|
|
118
|
+
|
|
119
|
+
<template v-if="!!content">
|
|
120
|
+
<TabsContent v-for="(item, index) of items" :key="index" :value="item.value || String(index)" :class="b24ui.content({ class: props.b24ui?.content })">
|
|
121
|
+
<slot :name="item.slot || 'content'" :item="item" :index="index">
|
|
122
|
+
{{ item.content }}
|
|
123
|
+
</slot>
|
|
124
|
+
</TabsContent>
|
|
125
|
+
</template>
|
|
126
|
+
</TabsRoot>
|
|
127
|
+
</template>
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
4
|
+
import _appConfig from '#build/app.config'
|
|
5
|
+
import theme from '#build/b24ui/textarea'
|
|
6
|
+
import { tv } from '../utils/tv'
|
|
7
|
+
|
|
8
|
+
const appConfigTextarea = _appConfig as AppConfig & { b24ui: { textarea: Partial<typeof theme> } }
|
|
9
|
+
|
|
10
|
+
const textarea = tv({ extend: tv(theme), ...(appConfigTextarea.b24ui?.textarea || {}) })
|
|
11
|
+
|
|
12
|
+
type TextareaVariants = VariantProps<typeof textarea>
|
|
13
|
+
|
|
14
|
+
export interface TextareaProps {
|
|
15
|
+
/**
|
|
16
|
+
* The element or component this component should render as.
|
|
17
|
+
* @defaultValue 'div'
|
|
18
|
+
*/
|
|
19
|
+
as?: any
|
|
20
|
+
id?: string
|
|
21
|
+
name?: string
|
|
22
|
+
/** The placeholder text when the textarea is empty. */
|
|
23
|
+
placeholder?: string
|
|
24
|
+
color?: TextareaVariants['color']
|
|
25
|
+
/** Removes padding from input. */
|
|
26
|
+
noPadding?: boolean
|
|
27
|
+
/** removes all borders (rings). */
|
|
28
|
+
noBorder?: boolean
|
|
29
|
+
/** removes all borders (rings) except the bottom one. */
|
|
30
|
+
underline?: boolean
|
|
31
|
+
/** Rounds the corners of the button. */
|
|
32
|
+
rounded?: boolean
|
|
33
|
+
required?: boolean
|
|
34
|
+
autofocus?: boolean
|
|
35
|
+
autofocusDelay?: number
|
|
36
|
+
disabled?: boolean
|
|
37
|
+
rows?: number
|
|
38
|
+
maxrows?: number
|
|
39
|
+
autoresize?: boolean
|
|
40
|
+
tag?: string
|
|
41
|
+
tagColor?: TextareaVariants['tagColor']
|
|
42
|
+
/** Highlight the ring color like a focus state. */
|
|
43
|
+
highlight?: boolean
|
|
44
|
+
class?: any
|
|
45
|
+
b24ui?: Partial<typeof textarea.slots>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TextareaEmits {
|
|
49
|
+
(e: 'update:modelValue', payload: string | number): void
|
|
50
|
+
(e: 'blur', event: FocusEvent): void
|
|
51
|
+
(e: 'change', event: Event): void
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TextareaSlots {
|
|
55
|
+
default(props?: {}): any
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
import { ref, computed, onMounted, nextTick, watch } from 'vue'
|
|
61
|
+
import { Primitive } from 'reka-ui'
|
|
62
|
+
import { useFormField } from '../composables/useFormField'
|
|
63
|
+
import { looseToNumber } from '../utils'
|
|
64
|
+
|
|
65
|
+
defineOptions({ inheritAttrs: false })
|
|
66
|
+
|
|
67
|
+
const props = withDefaults(defineProps<TextareaProps>(), {
|
|
68
|
+
rows: 3,
|
|
69
|
+
maxrows: 5,
|
|
70
|
+
autofocusDelay: 0
|
|
71
|
+
})
|
|
72
|
+
defineSlots<TextareaSlots>()
|
|
73
|
+
const emits = defineEmits<TextareaEmits>()
|
|
74
|
+
|
|
75
|
+
const [modelValue, modelModifiers] = defineModel<string | number>()
|
|
76
|
+
|
|
77
|
+
const { emitFormFocus, emitFormBlur, emitFormInput, emitFormChange, color, id, name, highlight, disabled, ariaAttrs } = useFormField<TextareaProps>(props, { deferInputValidation: true })
|
|
78
|
+
|
|
79
|
+
const isTag = computed(() => {
|
|
80
|
+
return props.tag
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const b24ui = computed(() => textarea({
|
|
84
|
+
color: color.value,
|
|
85
|
+
highlight: highlight.value,
|
|
86
|
+
tagColor: props.tagColor,
|
|
87
|
+
rounded: Boolean(props.rounded),
|
|
88
|
+
noPadding: Boolean(props.noPadding),
|
|
89
|
+
noBorder: Boolean(props.noBorder),
|
|
90
|
+
underline: Boolean(props.underline)
|
|
91
|
+
}))
|
|
92
|
+
|
|
93
|
+
const textareaRef = ref<HTMLTextAreaElement | null>(null)
|
|
94
|
+
|
|
95
|
+
function autoFocus() {
|
|
96
|
+
if (props.autofocus) {
|
|
97
|
+
textareaRef.value?.focus()
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Custom function to handle the v-model properties
|
|
102
|
+
function updateInput(value: string) {
|
|
103
|
+
if (modelModifiers.trim) {
|
|
104
|
+
value = value.trim()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (modelModifiers.number) {
|
|
108
|
+
value = looseToNumber(value)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
modelValue.value = value
|
|
112
|
+
emitFormInput()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function onInput(event: Event) {
|
|
116
|
+
autoResize()
|
|
117
|
+
|
|
118
|
+
if (!modelModifiers.lazy) {
|
|
119
|
+
updateInput((event.target as HTMLInputElement).value)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function onChange(event: Event) {
|
|
124
|
+
const value = (event.target as HTMLInputElement).value
|
|
125
|
+
|
|
126
|
+
if (modelModifiers.lazy) {
|
|
127
|
+
updateInput(value)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Update trimmed textarea so that it has same behavior as native textarea https://github.com/vuejs/core/blob/5ea8a8a4fab4e19a71e123e4d27d051f5e927172/packages/runtime-dom/src/directives/vModel.ts#L63
|
|
131
|
+
if (modelModifiers.trim) {
|
|
132
|
+
(event.target as HTMLInputElement).value = value.trim()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
emitFormChange()
|
|
136
|
+
emits('change', event)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function onBlur(event: FocusEvent) {
|
|
140
|
+
emitFormBlur()
|
|
141
|
+
emits('blur', event)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
onMounted(() => {
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
autoFocus()
|
|
147
|
+
}, props.autofocusDelay)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
function autoResize() {
|
|
151
|
+
if (props.autoresize) {
|
|
152
|
+
if (!textareaRef.value) {
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
textareaRef.value.rows = props.rows
|
|
157
|
+
const overflow = textareaRef.value.style.overflow
|
|
158
|
+
textareaRef.value.style.overflow = 'hidden'
|
|
159
|
+
|
|
160
|
+
const styles = window.getComputedStyle(textareaRef.value)
|
|
161
|
+
const paddingTop = Number.parseInt(styles.paddingTop)
|
|
162
|
+
const paddingBottom = Number.parseInt(styles.paddingBottom)
|
|
163
|
+
const padding = paddingTop + paddingBottom
|
|
164
|
+
const lineHeight = Number.parseInt(styles.lineHeight)
|
|
165
|
+
const { scrollHeight } = textareaRef.value
|
|
166
|
+
const newRows = (scrollHeight - padding) / lineHeight
|
|
167
|
+
|
|
168
|
+
if (newRows > props.rows) {
|
|
169
|
+
textareaRef.value.rows = props.maxrows ? Math.min(newRows, props.maxrows) : newRows
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
textareaRef.value.style.overflow = overflow
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
watch(modelValue, () => {
|
|
177
|
+
nextTick(autoResize)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
defineExpose({
|
|
181
|
+
textareaRef
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
onMounted(() => {
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
autoResize()
|
|
187
|
+
}, 100)
|
|
188
|
+
})
|
|
189
|
+
</script>
|
|
190
|
+
|
|
191
|
+
<template>
|
|
192
|
+
<Primitive :as="as" :class="b24ui.root({ class: [props.class, props.b24ui?.root] })">
|
|
193
|
+
<div v-if="isTag" :class="b24ui.tag({ class: props.b24ui?.tag })">
|
|
194
|
+
{{ props.tag }}
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<textarea
|
|
198
|
+
:id="id"
|
|
199
|
+
ref="textareaRef"
|
|
200
|
+
:value="modelValue"
|
|
201
|
+
:name="name"
|
|
202
|
+
:rows="rows"
|
|
203
|
+
:placeholder="placeholder"
|
|
204
|
+
:class="b24ui.base({ class: props.b24ui?.base })"
|
|
205
|
+
:disabled="disabled"
|
|
206
|
+
:required="required"
|
|
207
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
208
|
+
@input="onInput"
|
|
209
|
+
@blur="onBlur"
|
|
210
|
+
@change="onChange"
|
|
211
|
+
@focus="emitFormFocus"
|
|
212
|
+
/>
|
|
213
|
+
|
|
214
|
+
<slot />
|
|
215
|
+
</Primitive>
|
|
216
|
+
</template>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { ToastRootProps, ToastRootEmits } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
5
|
+
import _appConfig from '#build/app.config'
|
|
6
|
+
import theme from '#build/b24ui/toast'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
8
|
+
import type { AvatarProps, ButtonProps, IconComponent } from '../types'
|
|
9
|
+
|
|
10
|
+
const appConfigToast = _appConfig as AppConfig & { b24ui: { toast: Partial<typeof theme> } }
|
|
11
|
+
|
|
12
|
+
const toast = tv({ extend: tv(theme), ...(appConfigToast.b24ui?.toast || {}) })
|
|
13
|
+
|
|
14
|
+
type ToastVariants = VariantProps<typeof toast>
|
|
15
|
+
|
|
16
|
+
export interface ToastProps extends Pick<ToastRootProps, 'defaultOpen' | 'open' | 'type' | 'duration'> {
|
|
17
|
+
/**
|
|
18
|
+
* The element or component this component should render as.
|
|
19
|
+
* @defaultValue 'li'
|
|
20
|
+
*/
|
|
21
|
+
as?: any
|
|
22
|
+
title?: string
|
|
23
|
+
description?: string
|
|
24
|
+
icon?: IconComponent
|
|
25
|
+
avatar?: AvatarProps
|
|
26
|
+
color?: ToastVariants['color']
|
|
27
|
+
/**
|
|
28
|
+
* Display a list of actions:
|
|
29
|
+
* - under the title and description if multiline
|
|
30
|
+
* - next to the close button if not multiline
|
|
31
|
+
* `{ size: 'xs' }`{lang="ts-type"}
|
|
32
|
+
*/
|
|
33
|
+
actions?: ButtonProps[]
|
|
34
|
+
/**
|
|
35
|
+
* Display a close button to dismiss the toast.
|
|
36
|
+
* `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"}
|
|
37
|
+
* @defaultValue true
|
|
38
|
+
*/
|
|
39
|
+
close?: ButtonProps | boolean
|
|
40
|
+
/**
|
|
41
|
+
* The icon displayed in the close button.
|
|
42
|
+
* @defaultValue icons.close
|
|
43
|
+
*/
|
|
44
|
+
closeIcon?: IconComponent
|
|
45
|
+
class?: any
|
|
46
|
+
b24ui?: Partial<typeof toast.slots>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface ToastEmits extends ToastRootEmits {}
|
|
50
|
+
|
|
51
|
+
export interface ToastSlots {
|
|
52
|
+
leading(props?: {}): any
|
|
53
|
+
title(props?: {}): any
|
|
54
|
+
description(props?: {}): any
|
|
55
|
+
actions(props?: {}): any
|
|
56
|
+
close(props: { b24ui: any }): any
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<script setup lang="ts">
|
|
61
|
+
import { ref, computed, onMounted } from 'vue'
|
|
62
|
+
import { ToastRoot, ToastTitle, ToastDescription, ToastAction, ToastClose, useForwardPropsEmits } from 'reka-ui'
|
|
63
|
+
import { reactivePick } from '@vueuse/core'
|
|
64
|
+
import { useLocale } from '../composables/useLocale'
|
|
65
|
+
import icons from '../dictionary/icons'
|
|
66
|
+
import B24Avatar from './Avatar.vue'
|
|
67
|
+
import B24Button from './Button.vue'
|
|
68
|
+
|
|
69
|
+
const props = withDefaults(defineProps<ToastProps>(), {
|
|
70
|
+
close: true
|
|
71
|
+
})
|
|
72
|
+
const emits = defineEmits<ToastEmits>()
|
|
73
|
+
const slots = defineSlots<ToastSlots>()
|
|
74
|
+
|
|
75
|
+
const { t } = useLocale()
|
|
76
|
+
|
|
77
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen', 'open', 'duration', 'type'), emits)
|
|
78
|
+
|
|
79
|
+
const multiline = computed(() => !!props.title && !!props.description)
|
|
80
|
+
|
|
81
|
+
const b24ui = computed(() => toast({
|
|
82
|
+
color: props.color
|
|
83
|
+
}))
|
|
84
|
+
|
|
85
|
+
const el = ref()
|
|
86
|
+
const height = ref(0)
|
|
87
|
+
|
|
88
|
+
onMounted(() => {
|
|
89
|
+
if (!el.value) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
height.value = el.value.$el.getBoundingClientRect()?.height
|
|
95
|
+
}, 0)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
defineExpose({
|
|
99
|
+
height
|
|
100
|
+
})
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<template>
|
|
104
|
+
<ToastRoot
|
|
105
|
+
ref="el"
|
|
106
|
+
v-slot="{ remaining, duration }"
|
|
107
|
+
v-bind="rootProps"
|
|
108
|
+
:class="b24ui.root({ class: [props.class, props.b24ui?.root], multiline })"
|
|
109
|
+
:style="{ '--height': height }"
|
|
110
|
+
>
|
|
111
|
+
<slot name="leading">
|
|
112
|
+
<B24Avatar v-if="avatar" :size="((props.b24ui?.avatarSize || b24ui.avatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="b24ui.avatar({ class: props.b24ui?.avatar })" />
|
|
113
|
+
<Component
|
|
114
|
+
:is="icon"
|
|
115
|
+
v-if="icon"
|
|
116
|
+
:class="b24ui.icon({ class: props.b24ui?.icon })"
|
|
117
|
+
/>
|
|
118
|
+
</slot>
|
|
119
|
+
|
|
120
|
+
<div :class="b24ui.wrapper({ class: props.b24ui?.wrapper })">
|
|
121
|
+
<ToastTitle v-if="title || !!slots.title" :class="b24ui.title({ class: props.b24ui?.title })">
|
|
122
|
+
<slot name="title">
|
|
123
|
+
{{ title }}
|
|
124
|
+
</slot>
|
|
125
|
+
</ToastTitle>
|
|
126
|
+
<ToastDescription v-if="description || !!slots.description" :class="b24ui.description({ class: props.b24ui?.description })">
|
|
127
|
+
<slot name="description">
|
|
128
|
+
{{ description }}
|
|
129
|
+
</slot>
|
|
130
|
+
</ToastDescription>
|
|
131
|
+
|
|
132
|
+
<div v-if="multiline && actions?.length" :class="b24ui.actions({ class: props.b24ui?.actions, multiline: true })">
|
|
133
|
+
<slot name="actions">
|
|
134
|
+
<ToastAction v-for="(action, index) in actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
|
135
|
+
<B24Button size="xs" :color="color" v-bind="action" />
|
|
136
|
+
</ToastAction>
|
|
137
|
+
</slot>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div v-if="(!multiline && actions?.length) || close !== null" :class="b24ui.actions({ class: props.b24ui?.actions, multiline: false })">
|
|
142
|
+
<template v-if="!multiline">
|
|
143
|
+
<slot name="actions">
|
|
144
|
+
<ToastAction v-for="(action, index) in actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
|
145
|
+
<B24Button size="xs" :color="color" v-bind="action" />
|
|
146
|
+
</ToastAction>
|
|
147
|
+
</slot>
|
|
148
|
+
</template>
|
|
149
|
+
|
|
150
|
+
<ToastClose as-child>
|
|
151
|
+
<slot name="close" :b24ui="b24ui">
|
|
152
|
+
<B24Button
|
|
153
|
+
v-if="close"
|
|
154
|
+
:icon="closeIcon || icons.close"
|
|
155
|
+
size="xs"
|
|
156
|
+
color="link"
|
|
157
|
+
:aria-label="t('toast.close')"
|
|
158
|
+
v-bind="typeof close === 'object' ? close : undefined"
|
|
159
|
+
:class="b24ui.close({ class: props.b24ui?.close })"
|
|
160
|
+
@click.stop
|
|
161
|
+
/>
|
|
162
|
+
</slot>
|
|
163
|
+
</ToastClose>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div v-if="remaining > 0 && duration" :class="b24ui.progress({ class: props.b24ui?.progress })" :style="{ width: `${remaining / duration * 100}%` }" />
|
|
167
|
+
</ToastRoot>
|
|
168
|
+
</template>
|