@byyuurin/ui 0.0.0
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/LICENSE.md +21 -0
- package/README.md +32 -0
- package/dist/components/Accordion.vue +104 -0
- package/dist/components/App.vue +57 -0
- package/dist/components/Button.vue +94 -0
- package/dist/components/Card.vue +76 -0
- package/dist/components/Checkbox.vue +104 -0
- package/dist/components/Drawer.vue +133 -0
- package/dist/components/Input.vue +169 -0
- package/dist/components/Link.vue +117 -0
- package/dist/components/Modal.vue +145 -0
- package/dist/components/ModalProvider.vue +10 -0
- package/dist/components/Popover.vue +97 -0
- package/dist/components/RadioGroup.vue +180 -0
- package/dist/components/Select.vue +258 -0
- package/dist/components/Switch.vue +99 -0
- package/dist/components/Tabs.vue +117 -0
- package/dist/components/Toast.vue +126 -0
- package/dist/components/Toaster.vue +143 -0
- package/dist/components/Tooltip.vue +71 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/components/index.mjs +18 -0
- package/dist/composables/index.d.ts +4 -0
- package/dist/composables/index.mjs +4 -0
- package/dist/composables/useComponentIcons.d.ts +26 -0
- package/dist/composables/useComponentIcons.mjs +24 -0
- package/dist/composables/useModal.d.ts +15 -0
- package/dist/composables/useModal.mjs +51 -0
- package/dist/composables/useTheme.d.ts +8 -0
- package/dist/composables/useTheme.mjs +18 -0
- package/dist/composables/useToast.d.ts +24 -0
- package/dist/composables/useToast.mjs +48 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +3 -0
- package/dist/internal/constants.d.ts +3 -0
- package/dist/internal/constants.mjs +21 -0
- package/dist/internal/extend-theme.d.ts +9 -0
- package/dist/internal/extend-theme.mjs +16 -0
- package/dist/internal/extend-theme.test.d.ts +1 -0
- package/dist/internal/extend-theme.test.mjs +45 -0
- package/dist/internal/index.d.ts +4 -0
- package/dist/internal/index.mjs +4 -0
- package/dist/internal/link.d.ts +15 -0
- package/dist/internal/link.mjs +4 -0
- package/dist/internal/styler.d.ts +5 -0
- package/dist/internal/styler.mjs +236 -0
- package/dist/internal/styler.test.d.ts +1 -0
- package/dist/internal/styler.test.mjs +10 -0
- package/dist/nuxt.d.ts +10 -0
- package/dist/nuxt.mjs +28 -0
- package/dist/resolver.d.ts +10 -0
- package/dist/resolver.mjs +18 -0
- package/dist/theme/accordion.d.ts +39 -0
- package/dist/theme/accordion.mjs +25 -0
- package/dist/theme/app.d.ts +10 -0
- package/dist/theme/app.mjs +9 -0
- package/dist/theme/button.d.ts +184 -0
- package/dist/theme/button.mjs +140 -0
- package/dist/theme/card.d.ts +43 -0
- package/dist/theme/card.mjs +11 -0
- package/dist/theme/checkbox.d.ts +97 -0
- package/dist/theme/checkbox.mjs +53 -0
- package/dist/theme/drawer.d.ts +72 -0
- package/dist/theme/drawer.mjs +72 -0
- package/dist/theme/index.d.ts +17 -0
- package/dist/theme/index.mjs +17 -0
- package/dist/theme/input.d.ts +159 -0
- package/dist/theme/input.mjs +133 -0
- package/dist/theme/link.d.ts +31 -0
- package/dist/theme/link.mjs +23 -0
- package/dist/theme/modal.d.ts +50 -0
- package/dist/theme/modal.mjs +54 -0
- package/dist/theme/popover.d.ts +27 -0
- package/dist/theme/popover.mjs +10 -0
- package/dist/theme/radioGroup.d.ts +131 -0
- package/dist/theme/radioGroup.mjs +67 -0
- package/dist/theme/select.d.ts +177 -0
- package/dist/theme/select.mjs +154 -0
- package/dist/theme/switch.d.ts +131 -0
- package/dist/theme/switch.mjs +78 -0
- package/dist/theme/tabs.d.ts +101 -0
- package/dist/theme/tabs.mjs +117 -0
- package/dist/theme/toast.d.ts +51 -0
- package/dist/theme/toast.mjs +27 -0
- package/dist/theme/toaster.d.ts +73 -0
- package/dist/theme/toaster.mjs +89 -0
- package/dist/theme/tooltip.d.ts +31 -0
- package/dist/theme/tooltip.mjs +8 -0
- package/dist/types/components.d.ts +18 -0
- package/dist/types/components.mjs +0 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.mjs +2 -0
- package/dist/types/utils.d.ts +29 -0
- package/dist/types/utils.mjs +0 -0
- package/dist/unocss-preset.d.ts +37 -0
- package/dist/unocss-preset.mjs +164 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.mjs +70 -0
- package/dist/utils/unocss.d.ts +3 -0
- package/dist/utils/unocss.mjs +50 -0
- package/package.json +103 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PrimitiveProps, ToastRootEmits, ToastRootProps } from 'reka-ui'
|
|
3
|
+
import type { toast } from '../theme'
|
|
4
|
+
import type { ButtonProps, ComponentAttrs } from '../types'
|
|
5
|
+
|
|
6
|
+
export interface ToastProps extends ComponentAttrs<typeof toast>, Pick<ToastRootProps, 'defaultOpen' | 'open' | 'type' | 'duration'> {
|
|
7
|
+
/** @default "li" */
|
|
8
|
+
as?: PrimitiveProps['as']
|
|
9
|
+
title?: string
|
|
10
|
+
description?: string
|
|
11
|
+
icon?: string
|
|
12
|
+
actions?: ButtonProps[]
|
|
13
|
+
/**
|
|
14
|
+
* Display a close button to dismiss the toast.
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
close?: ButtonProps | boolean
|
|
18
|
+
/** @default `app.icons.close` */
|
|
19
|
+
closeIcon?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ToastEmits extends ToastRootEmits {}
|
|
23
|
+
|
|
24
|
+
export interface ToastSlots {
|
|
25
|
+
icon?: (props?: {}) => any
|
|
26
|
+
title?: (props?: {}) => any
|
|
27
|
+
description?: (props?: {}) => any
|
|
28
|
+
actions?: (props?: {}) => any
|
|
29
|
+
close?: (props: { ui: any }) => any
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { reactivePick, useElementBounding } from '@vueuse/core'
|
|
36
|
+
import { ToastAction, ToastClose, ToastDescription, ToastRoot, ToastTitle, useForwardPropsEmits } from 'reka-ui'
|
|
37
|
+
import { computed, ref } from 'vue'
|
|
38
|
+
import { useTheme } from '../composables'
|
|
39
|
+
import Button from './Button.vue'
|
|
40
|
+
|
|
41
|
+
const props = withDefaults(defineProps<ToastProps>(), {
|
|
42
|
+
close: true,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits<ToastEmits>()
|
|
46
|
+
const slots = defineSlots<ToastSlots>()
|
|
47
|
+
|
|
48
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen', 'open', 'duration', 'type'), emit)
|
|
49
|
+
|
|
50
|
+
const el = ref<InstanceType<typeof ToastRoot>>()
|
|
51
|
+
const { height } = useElementBounding(() => el.value?.$el.getBoundingClientRect ? el.value.$el : undefined)
|
|
52
|
+
|
|
53
|
+
const multiline = computed(() => !!props.title && !!props.description)
|
|
54
|
+
|
|
55
|
+
const { theme, createStyler } = useTheme()
|
|
56
|
+
const style = computed(() => {
|
|
57
|
+
const styler = createStyler(theme.value.toast)
|
|
58
|
+
return styler({ ...props, multiline: multiline.value })
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
defineExpose({
|
|
62
|
+
height,
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<ToastRoot
|
|
68
|
+
ref="el"
|
|
69
|
+
v-slot="{ remaining, duration }"
|
|
70
|
+
v-bind="rootProps"
|
|
71
|
+
:class="style.root({ class: [props.class, props.ui?.root], multiline })"
|
|
72
|
+
:style="{ '--height': height }"
|
|
73
|
+
>
|
|
74
|
+
<slot name="icon">
|
|
75
|
+
<i v-if="props.icon" :class="style.icon({ class: [props.icon, props.ui?.icon] })"></i>
|
|
76
|
+
</slot>
|
|
77
|
+
|
|
78
|
+
<div :class="style.wrapper({ class: props.ui?.wrapper })">
|
|
79
|
+
<ToastTitle v-if="props.title || !!slots.title" :class="style.title({ class: props.ui?.title })">
|
|
80
|
+
<slot name="title">
|
|
81
|
+
{{ props.title }}
|
|
82
|
+
</slot>
|
|
83
|
+
</ToastTitle>
|
|
84
|
+
<ToastDescription v-if="props.description || !!slots.description" :class="style.description({ class: props.ui?.description })">
|
|
85
|
+
<slot name="description">
|
|
86
|
+
{{ props.description }}
|
|
87
|
+
</slot>
|
|
88
|
+
</ToastDescription>
|
|
89
|
+
|
|
90
|
+
<div v-if="multiline && actions?.length" :class="style.actions({ class: props.ui?.actions, multiline: true })">
|
|
91
|
+
<slot name="actions">
|
|
92
|
+
<ToastAction v-for="(action, index) in props.actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
|
93
|
+
<Button size="xs" v-bind="action" />
|
|
94
|
+
</ToastAction>
|
|
95
|
+
</slot>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div v-if="(!multiline && actions?.length) || props.close !== null" :class="style.actions({ class: props.ui?.actions, multiline: false })">
|
|
100
|
+
<template v-if="!multiline">
|
|
101
|
+
<slot name="actions">
|
|
102
|
+
<ToastAction v-for="(action, index) in props.actions" :key="index" :alt-text="action.label || 'Action'" as-child @click.stop>
|
|
103
|
+
<Button size="xs" v-bind="action" />
|
|
104
|
+
</ToastAction>
|
|
105
|
+
</slot>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<ToastClose as-child>
|
|
109
|
+
<slot name="close" :ui="ui">
|
|
110
|
+
<UButton
|
|
111
|
+
v-if="props.close"
|
|
112
|
+
:icon="props.closeIcon || theme.app.icons.close"
|
|
113
|
+
size="md"
|
|
114
|
+
variant="link"
|
|
115
|
+
aria-label="close"
|
|
116
|
+
v-bind="typeof close === 'object' ? close : undefined"
|
|
117
|
+
:class="style.close({ class: props.ui?.close })"
|
|
118
|
+
@click.stop
|
|
119
|
+
/>
|
|
120
|
+
</slot>
|
|
121
|
+
</ToastClose>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div v-if="remaining > 0 && duration" :class="style.progress({ class: props.ui?.progress })" :style="{ width: `${remaining / duration * 100}%` }"></div>
|
|
125
|
+
</ToastRoot>
|
|
126
|
+
</template>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
+
import type { ToastProviderProps } from 'reka-ui'
|
|
4
|
+
import type { toaster } from '../theme'
|
|
5
|
+
import type { ComponentAttrs } from '../types'
|
|
6
|
+
|
|
7
|
+
type ToasterVariants = VariantProps<typeof toaster>
|
|
8
|
+
|
|
9
|
+
export interface ToasterProps extends ComponentAttrs<typeof toaster>, Omit<ToastProviderProps, 'swipeDirection'> {
|
|
10
|
+
/** @default "bottom-right" */
|
|
11
|
+
position?: ToasterVariants['position']
|
|
12
|
+
/**
|
|
13
|
+
* Expand the toasts to show multiple toasts at once.
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
expand?: boolean
|
|
17
|
+
/**
|
|
18
|
+
* Render the toaster in a portal.
|
|
19
|
+
* @default true
|
|
20
|
+
*/
|
|
21
|
+
portal?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ToasterSlots {
|
|
25
|
+
default?: (props?: {}) => any
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { reactivePick } from '@vueuse/core'
|
|
31
|
+
import { ToastPortal, ToastProvider, ToastViewport, useForwardProps } from 'reka-ui'
|
|
32
|
+
import { computed, ref } from 'vue'
|
|
33
|
+
import { useTheme, useToast } from '../composables'
|
|
34
|
+
import { omit } from '../utils'
|
|
35
|
+
import Toast from './Toast.vue'
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<ToasterProps>(), {
|
|
38
|
+
position: 'bottom-right',
|
|
39
|
+
expand: true,
|
|
40
|
+
portal: true,
|
|
41
|
+
duration: 5000,
|
|
42
|
+
})
|
|
43
|
+
defineSlots<ToasterSlots>()
|
|
44
|
+
|
|
45
|
+
const providerProps = useForwardProps(reactivePick(props, 'duration', 'label', 'swipeThreshold'))
|
|
46
|
+
|
|
47
|
+
const { toasts, remove } = useToast()
|
|
48
|
+
|
|
49
|
+
const swipeDirection = computed(() => {
|
|
50
|
+
switch (props.position) {
|
|
51
|
+
case 'top-center':
|
|
52
|
+
return 'up'
|
|
53
|
+
case 'top-right':
|
|
54
|
+
case 'bottom-right':
|
|
55
|
+
return 'right'
|
|
56
|
+
case 'bottom-center':
|
|
57
|
+
return 'down'
|
|
58
|
+
case 'top-left':
|
|
59
|
+
case 'bottom-left':
|
|
60
|
+
return 'left'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.warn(`[Toaster] Unknown position "${props.position}"`)
|
|
64
|
+
|
|
65
|
+
return 'right'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const { theme, createStyler } = useTheme()
|
|
69
|
+
const style = computed(() => {
|
|
70
|
+
const styler = createStyler(theme.value.toaster)
|
|
71
|
+
return styler({
|
|
72
|
+
...props,
|
|
73
|
+
swipeDirection: swipeDirection.value,
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
function onUpdateOpen(value: boolean, id: string | number) {
|
|
78
|
+
if (value)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
remove(id)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const hovered = ref(false)
|
|
85
|
+
const expanded = computed(() => props.expand || hovered.value)
|
|
86
|
+
|
|
87
|
+
const refs = ref<{ height: number }[]>([])
|
|
88
|
+
|
|
89
|
+
const height = computed(() => refs.value.reduce((sum, { height }) => sum + height + 16, 0))
|
|
90
|
+
const frontHeight = computed(() => refs.value[refs.value.length - 1]?.height || 0)
|
|
91
|
+
|
|
92
|
+
function getOffset(index: number) {
|
|
93
|
+
return refs.value.slice(index + 1).reduce((acc, { height }) => acc + height + 16, 0)
|
|
94
|
+
}
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<template>
|
|
98
|
+
<ToastProvider :swipe-direction="swipeDirection" v-bind="providerProps">
|
|
99
|
+
<slot></slot>
|
|
100
|
+
|
|
101
|
+
<Toast
|
|
102
|
+
v-for="(toast, index) of toasts"
|
|
103
|
+
:key="toast.id"
|
|
104
|
+
ref="refs"
|
|
105
|
+
v-bind="omit(toast, ['id'])"
|
|
106
|
+
:data-expanded="expanded"
|
|
107
|
+
:data-front="!expanded && index === toasts.length - 1"
|
|
108
|
+
:style="{
|
|
109
|
+
'--index': (index - toasts.length) + toasts.length,
|
|
110
|
+
'--before': toasts.length - 1 - index,
|
|
111
|
+
'--offset': getOffset(index),
|
|
112
|
+
'--scale': expanded ? '1' : 'calc(1 - var(--before) * var(--scale-factor))',
|
|
113
|
+
'--translate': expanded ? 'calc(var(--offset) * var(--translate-factor))' : 'calc(var(--before) * var(--gap))',
|
|
114
|
+
'--transform': 'translateY(var(--translate)) scale(var(--scale))',
|
|
115
|
+
}"
|
|
116
|
+
:class="[style.base(), {
|
|
117
|
+
'cursor-pointer': !!toast.click,
|
|
118
|
+
}]"
|
|
119
|
+
@update:open="onUpdateOpen($event, toast.id)"
|
|
120
|
+
@click="toast.click && toast.click(toast)"
|
|
121
|
+
/>
|
|
122
|
+
|
|
123
|
+
<ToastPortal :disabled="!portal">
|
|
124
|
+
<ToastViewport
|
|
125
|
+
:data-expanded="expanded"
|
|
126
|
+
:class="style.viewport({ class: [props.class, props.ui?.viewport] })"
|
|
127
|
+
:style="{
|
|
128
|
+
'--scale-factor': '0.05',
|
|
129
|
+
'--translate-factor': position?.startsWith('top') ? '1px' : '-1px',
|
|
130
|
+
'--gap': position?.startsWith('top') ? '16px' : '-16px',
|
|
131
|
+
'--front-height': `${frontHeight}px`,
|
|
132
|
+
'--height': `${height}px`,
|
|
133
|
+
}"
|
|
134
|
+
@mouseenter="hovered = true"
|
|
135
|
+
@mouseleave="hovered = false"
|
|
136
|
+
/>
|
|
137
|
+
</ToastPortal>
|
|
138
|
+
</ToastProvider>
|
|
139
|
+
</template>
|
|
140
|
+
|
|
141
|
+
<style>
|
|
142
|
+
@keyframes toast-collapsed-closed{0%{transform:var(--transform)}to{transform:translateY(calc((var(--before) - var(--height))*var(--gap))) scale(var(--scale))}}@keyframes toast-closed{0%{transform:var(--transform)}to{transform:translateY(calc((var(--offset) - var(--height))*var(--translate-factor)))}}@keyframes toast-slide-left{0%{transform:translateX(0) translateY(var(--translate))}to{transform:translateX(-100%) translateY(var(--translate))}}@keyframes toast-slide-right{0%{transform:translateX(0) translateY(var(--translate))}to{transform:translateX(100%) translateY(var(--translate))}}
|
|
143
|
+
</style>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { TooltipArrowProps, TooltipContentProps, TooltipRootEmits, TooltipRootProps } from 'reka-ui'
|
|
3
|
+
import type { tooltip } from '../theme'
|
|
4
|
+
import type { ComponentAttrs } from '../types'
|
|
5
|
+
|
|
6
|
+
export interface TooltipProps extends ComponentAttrs<typeof tooltip>, TooltipRootProps {
|
|
7
|
+
text?: string
|
|
8
|
+
content?: Omit<TooltipContentProps, 'as' | 'asChild'>
|
|
9
|
+
arrow?: boolean | Omit<TooltipArrowProps, 'as' | 'asChild'>
|
|
10
|
+
/** @default true */
|
|
11
|
+
portal?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TooltipEmits extends TooltipRootEmits {}
|
|
15
|
+
|
|
16
|
+
export interface TooltipSlots {
|
|
17
|
+
default?: (props: { open: boolean }) => any
|
|
18
|
+
content?: (props: {}) => any
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts" setup>
|
|
23
|
+
import { reactivePick } from '@vueuse/core'
|
|
24
|
+
import { defu } from 'defu'
|
|
25
|
+
import { TooltipArrow, TooltipContent, TooltipPortal, TooltipRoot, TooltipTrigger, useForwardPropsEmits } from 'reka-ui'
|
|
26
|
+
import { computed, toRef } from 'vue'
|
|
27
|
+
import { useTheme } from '../composables'
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<TooltipProps>(), {
|
|
30
|
+
portal: true,
|
|
31
|
+
})
|
|
32
|
+
const emit = defineEmits<TooltipEmits>()
|
|
33
|
+
const slots = defineSlots<TooltipSlots>()
|
|
34
|
+
|
|
35
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultOpen', 'open', 'delayDuration', 'disableHoverableContent', 'disableClosingTrigger', 'disabled', 'ignoreNonKeyboardFocus'), emit)
|
|
36
|
+
|
|
37
|
+
const contentDefaults: TooltipContentProps = {
|
|
38
|
+
side: 'bottom',
|
|
39
|
+
sideOffset: 8,
|
|
40
|
+
collisionPadding: 8,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const contentProps = toRef(() => defu(props.content, contentDefaults) as TooltipContentProps)
|
|
44
|
+
|
|
45
|
+
const arrowProps = toRef(() => props.arrow as TooltipArrowProps)
|
|
46
|
+
|
|
47
|
+
const { theme, createStyler } = useTheme()
|
|
48
|
+
const style = computed(() => {
|
|
49
|
+
const styler = createStyler(theme.value.tooltip)
|
|
50
|
+
return styler(props)
|
|
51
|
+
})
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<TooltipRoot v-slot="{ open }" v-bind="rootProps">
|
|
56
|
+
<TooltipTrigger v-if="slots.default" as-child :class="props.class">
|
|
57
|
+
<slot :open="open">
|
|
58
|
+
</slot>
|
|
59
|
+
</TooltipTrigger>
|
|
60
|
+
|
|
61
|
+
<TooltipPortal :disabled="!props.portal">
|
|
62
|
+
<TooltipContent v-bind="contentProps" :class="style.content({ class: [!slots.default && props.class, props.ui?.content] })">
|
|
63
|
+
<slot name="content">
|
|
64
|
+
<span v-if="props.text" :class="style.text({ class: props.ui?.text })">{{ props.text }}</span>
|
|
65
|
+
</slot>
|
|
66
|
+
|
|
67
|
+
<TooltipArrow v-if="props.arrow" v-bind="arrowProps" :class="style.arrow({ class: props.ui?.arrow })" />
|
|
68
|
+
</TooltipContent>
|
|
69
|
+
</TooltipPortal>
|
|
70
|
+
</TooltipRoot>
|
|
71
|
+
</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { default as Accordion } from './Accordion.vue';
|
|
2
|
+
export { default as App } from './App.vue';
|
|
3
|
+
export { default as Button } from './Button.vue';
|
|
4
|
+
export { default as Card } from './Card.vue';
|
|
5
|
+
export { default as Checkbox } from './Checkbox.vue';
|
|
6
|
+
export { default as Drawer } from './Drawer.vue';
|
|
7
|
+
export { default as Input } from './Input.vue';
|
|
8
|
+
export { default as Link } from './Link.vue';
|
|
9
|
+
export { default as Modal } from './Modal.vue';
|
|
10
|
+
export { default as ModalProvider } from './ModalProvider.vue';
|
|
11
|
+
export { default as Popover } from './Popover.vue';
|
|
12
|
+
export { default as RadioGroup } from './RadioGroup.vue';
|
|
13
|
+
export { default as Select } from './Select.vue';
|
|
14
|
+
export { default as Switch } from './Switch.vue';
|
|
15
|
+
export { default as Tabs } from './Tabs.vue';
|
|
16
|
+
export { default as Toast } from './Toast.vue';
|
|
17
|
+
export { default as Toaster } from './Toaster.vue';
|
|
18
|
+
export { default as Tooltip } from './Tooltip.vue';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { default as Accordion } from "./Accordion.vue";
|
|
2
|
+
export { default as App } from "./App.vue";
|
|
3
|
+
export { default as Button } from "./Button.vue";
|
|
4
|
+
export { default as Card } from "./Card.vue";
|
|
5
|
+
export { default as Checkbox } from "./Checkbox.vue";
|
|
6
|
+
export { default as Drawer } from "./Drawer.vue";
|
|
7
|
+
export { default as Input } from "./Input.vue";
|
|
8
|
+
export { default as Link } from "./Link.vue";
|
|
9
|
+
export { default as Modal } from "./Modal.vue";
|
|
10
|
+
export { default as ModalProvider } from "./ModalProvider.vue";
|
|
11
|
+
export { default as Popover } from "./Popover.vue";
|
|
12
|
+
export { default as RadioGroup } from "./RadioGroup.vue";
|
|
13
|
+
export { default as Select } from "./Select.vue";
|
|
14
|
+
export { default as Switch } from "./Switch.vue";
|
|
15
|
+
export { default as Tabs } from "./Tabs.vue";
|
|
16
|
+
export { default as Toast } from "./Toast.vue";
|
|
17
|
+
export { default as Toaster } from "./Toaster.vue";
|
|
18
|
+
export { default as Tooltip } from "./Tooltip.vue";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
export interface UseComponentIconsProps {
|
|
3
|
+
/** Display an icon based on the `prefix` and `suffix` props. */
|
|
4
|
+
icon?: string;
|
|
5
|
+
/** When `true`, the icon will be displayed on the left side. */
|
|
6
|
+
prefix?: boolean;
|
|
7
|
+
/** Display an icon on the left side. */
|
|
8
|
+
prefixIcon?: string;
|
|
9
|
+
/** When `true`, the icon will be displayed on the right side. */
|
|
10
|
+
suffix?: boolean;
|
|
11
|
+
/** Display an icon on the right side. */
|
|
12
|
+
suffixIcon?: string;
|
|
13
|
+
/** When `true`, the loading icon will be displayed. */
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The icon when the `loading` prop is `true`.
|
|
17
|
+
* @default app.icons.loading
|
|
18
|
+
*/
|
|
19
|
+
loadingIcon?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function useComponentIcons(componentProps: MaybeRefOrGetter<UseComponentIconsProps>): {
|
|
22
|
+
isPrefix: import("vue").ComputedRef<boolean>;
|
|
23
|
+
isSuffix: import("vue").ComputedRef<boolean>;
|
|
24
|
+
prefixIconName: import("vue").ComputedRef<string | undefined>;
|
|
25
|
+
suffixIconName: import("vue").ComputedRef<string | undefined>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
|
+
import { useTheme } from "./useTheme.mjs";
|
|
3
|
+
export function useComponentIcons(componentProps) {
|
|
4
|
+
const { theme } = useTheme();
|
|
5
|
+
const props = computed(() => toValue(componentProps));
|
|
6
|
+
const isPrefix = computed(() => props.value.icon && props.value.prefix || props.value.icon && !props.value.suffix || props.value.loading && !props.value.suffix || !!props.value.prefixIcon);
|
|
7
|
+
const isSuffix = computed(() => props.value.icon && props.value.suffix || props.value.loading && props.value.suffix || !!props.value.suffixIcon);
|
|
8
|
+
const prefixIconName = computed(() => {
|
|
9
|
+
if (props.value.loading)
|
|
10
|
+
return props.value.loadingIcon || theme.value.app.icons.loading;
|
|
11
|
+
return props.value.prefixIcon || props.value.icon;
|
|
12
|
+
});
|
|
13
|
+
const suffixIconName = computed(() => {
|
|
14
|
+
if (props.value.loading && !isPrefix.value)
|
|
15
|
+
return props.value.loadingIcon || theme.value.app.icons.loading;
|
|
16
|
+
return props.value.suffixIcon || props.value.icon;
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
isPrefix,
|
|
20
|
+
isSuffix,
|
|
21
|
+
prefixIconName,
|
|
22
|
+
suffixIconName
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Component, ShallowRef } from 'vue';
|
|
2
|
+
import type { ComponentProps } from 'vue-component-type-helpers';
|
|
3
|
+
import type { ModalProps } from '../types';
|
|
4
|
+
export interface ModalState {
|
|
5
|
+
component: Component | string;
|
|
6
|
+
props: ModalProps;
|
|
7
|
+
}
|
|
8
|
+
export declare const injectModalState: () => ShallowRef<ModalState> | undefined, provideModalState: (value: ShallowRef<ModalState>) => void;
|
|
9
|
+
export declare const useModal: () => {
|
|
10
|
+
open: <T extends Component>(component: T, props?: ModalProps & ComponentProps<T>) => void;
|
|
11
|
+
close: () => void;
|
|
12
|
+
reset: () => void;
|
|
13
|
+
patch: <T extends Component = Record<string, never>>(props: Partial<ModalProps & ComponentProps<T>>) => void;
|
|
14
|
+
isOpen: import("vue").Ref<boolean, boolean>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createSharedComposable } from "@vueuse/core";
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
import { createInjection } from "../utils/index.mjs";
|
|
4
|
+
export const {
|
|
5
|
+
inject: injectModalState,
|
|
6
|
+
provide: provideModalState
|
|
7
|
+
} = createInjection("ui.modal");
|
|
8
|
+
export const useModal = createSharedComposable(() => {
|
|
9
|
+
const modalState = injectModalState();
|
|
10
|
+
const isOpen = ref(false);
|
|
11
|
+
function open(component, props) {
|
|
12
|
+
if (!modalState)
|
|
13
|
+
throw new Error("useModal() is called without provider");
|
|
14
|
+
modalState.value = {
|
|
15
|
+
component,
|
|
16
|
+
props: props ?? {}
|
|
17
|
+
};
|
|
18
|
+
isOpen.value = true;
|
|
19
|
+
}
|
|
20
|
+
function close() {
|
|
21
|
+
if (!modalState)
|
|
22
|
+
return;
|
|
23
|
+
isOpen.value = false;
|
|
24
|
+
}
|
|
25
|
+
function reset() {
|
|
26
|
+
if (!modalState)
|
|
27
|
+
return;
|
|
28
|
+
modalState.value = {
|
|
29
|
+
component: "div",
|
|
30
|
+
props: {}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function patch(props) {
|
|
34
|
+
if (!modalState)
|
|
35
|
+
return;
|
|
36
|
+
modalState.value = {
|
|
37
|
+
...modalState.value,
|
|
38
|
+
props: {
|
|
39
|
+
...modalState.value.props,
|
|
40
|
+
...props
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
open,
|
|
46
|
+
close,
|
|
47
|
+
reset,
|
|
48
|
+
patch,
|
|
49
|
+
isOpen
|
|
50
|
+
};
|
|
51
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import * as theme from '../theme';
|
|
3
|
+
export declare const provideThemeExtension: (value: MaybeRefOrGetter<import("../types").PartialTheme<typeof theme>>) => void, injectThemeExtension: () => MaybeRefOrGetter<import("../types").PartialTheme<typeof theme>>;
|
|
4
|
+
export declare const mergeRules: import("@byyuurin/ui-kit/index").CRRule[];
|
|
5
|
+
export declare const useTheme: () => {
|
|
6
|
+
theme: import("vue").ComputedRef<typeof theme>;
|
|
7
|
+
createStyler: <V extends import("@byyuurin/ui-kit/index").CVVariants<S, B>, CV extends import("@byyuurin/ui-kit/index").CVCompoundVariants<V, S, B>, B extends import("@byyuurin/ui-kit/index").ClassValue = undefined, S extends import("@byyuurin/ui-kit/index").CVSlots = undefined>(theme: import("@byyuurin/ui-kit/index").CVMeta<V, CV, never, B, S>) => [keyof V] extends string[] ? (props: Required<import("@byyuurin/ui-kit/index").VariantProps<import("@byyuurin/ui-kit/index").CVReturnType<V, S, B>>> & import("../types").StylerBaseProps) => S extends undefined ? string : { [K in keyof S | (B extends undefined ? never : "base")]: import("@byyuurin/ui-kit/index").CVHandler<V, S, string>; } : (props?: import("../types").StylerBaseProps) => S extends undefined ? string : { [K in keyof S | (B extends undefined ? never : "base")]: import("@byyuurin/ui-kit/index").CVHandler<V, S, string>; };
|
|
8
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createSharedComposable } from "@vueuse/core";
|
|
2
|
+
import { computed, toValue } from "vue";
|
|
3
|
+
import { createMergeRules, extendTheme, prepareStyler } from "../internal/index.mjs";
|
|
4
|
+
import * as theme from "../theme/index.mjs";
|
|
5
|
+
import { createInjection } from "../utils/index.mjs";
|
|
6
|
+
export const {
|
|
7
|
+
provide: provideThemeExtension,
|
|
8
|
+
inject: injectThemeExtension
|
|
9
|
+
} = createInjection("ui.themeExtension", {});
|
|
10
|
+
export const mergeRules = createMergeRules();
|
|
11
|
+
export const useTheme = createSharedComposable(() => {
|
|
12
|
+
const _theme = injectThemeExtension();
|
|
13
|
+
const { createStyler } = prepareStyler(mergeRules);
|
|
14
|
+
return {
|
|
15
|
+
theme: computed(() => extendTheme(toValue(_theme), theme)),
|
|
16
|
+
createStyler
|
|
17
|
+
};
|
|
18
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ToastProps } from '../types';
|
|
2
|
+
export interface Toast extends Omit<ToastProps, 'defaultOpen'> {
|
|
3
|
+
id: string | number;
|
|
4
|
+
click?: (toast: Toast) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare const useToast: () => {
|
|
7
|
+
toasts: import("vue").Ref<{
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
[x: number]: any;
|
|
10
|
+
[x: symbol]: ToastProps;
|
|
11
|
+
id: string | number;
|
|
12
|
+
click?: ((toast: Toast) => void) | undefined;
|
|
13
|
+
}[], Toast[] | {
|
|
14
|
+
[x: string]: any;
|
|
15
|
+
[x: number]: any;
|
|
16
|
+
[x: symbol]: ToastProps;
|
|
17
|
+
id: string | number;
|
|
18
|
+
click?: ((toast: Toast) => void) | undefined;
|
|
19
|
+
}[]>;
|
|
20
|
+
add: (toast: Partial<Toast>) => Toast;
|
|
21
|
+
update: (id: string | number, toast: Partial<Omit<Toast, "id">>) => void;
|
|
22
|
+
remove: (id: string | number) => void;
|
|
23
|
+
clear: () => void;
|
|
24
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createSharedComposable } from "@vueuse/core";
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
export const useToast = createSharedComposable(() => {
|
|
4
|
+
const toasts = ref([]);
|
|
5
|
+
function add(toast) {
|
|
6
|
+
const body = {
|
|
7
|
+
id: Date.now().toString(),
|
|
8
|
+
open: true,
|
|
9
|
+
...toast
|
|
10
|
+
};
|
|
11
|
+
const index = toasts.value.findIndex((t) => t.id === body.id);
|
|
12
|
+
if (index === -1)
|
|
13
|
+
toasts.value.push(body);
|
|
14
|
+
toasts.value = toasts.value.slice(-5);
|
|
15
|
+
return body;
|
|
16
|
+
}
|
|
17
|
+
function update(id, toast) {
|
|
18
|
+
const index = toasts.value.findIndex((t) => t.id === id);
|
|
19
|
+
if (index === -1)
|
|
20
|
+
return;
|
|
21
|
+
toasts.value[index] = {
|
|
22
|
+
...toasts.value[index],
|
|
23
|
+
...toast
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function remove(id) {
|
|
27
|
+
const index = toasts.value.findIndex((t) => t.id === id);
|
|
28
|
+
if (index === -1)
|
|
29
|
+
return;
|
|
30
|
+
toasts.value[index] = {
|
|
31
|
+
...toasts.value[index],
|
|
32
|
+
open: false
|
|
33
|
+
};
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
toasts.value = toasts.value.filter((t) => t.id !== id);
|
|
36
|
+
}, 200);
|
|
37
|
+
}
|
|
38
|
+
function clear() {
|
|
39
|
+
toasts.value = [];
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
toasts,
|
|
43
|
+
add,
|
|
44
|
+
update,
|
|
45
|
+
remove,
|
|
46
|
+
clear
|
|
47
|
+
};
|
|
48
|
+
});
|
package/dist/index.d.ts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const packageName = "@byyuurin/ui";
|
|
2
|
+
export const componentNames = [
|
|
3
|
+
"Accordion",
|
|
4
|
+
"App",
|
|
5
|
+
"Button",
|
|
6
|
+
"Card",
|
|
7
|
+
"Checkbox",
|
|
8
|
+
"Drawer",
|
|
9
|
+
"Input",
|
|
10
|
+
"Link",
|
|
11
|
+
"Modal",
|
|
12
|
+
"ModalProvider",
|
|
13
|
+
"Popover",
|
|
14
|
+
"RadioGroup",
|
|
15
|
+
"Select",
|
|
16
|
+
"Switch",
|
|
17
|
+
"Tabs",
|
|
18
|
+
"Toast",
|
|
19
|
+
"Toaster",
|
|
20
|
+
"Tooltip"
|
|
21
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const extendTheme: <Source extends {
|
|
2
|
+
[x: string]: any;
|
|
3
|
+
[x: number]: any;
|
|
4
|
+
[x: symbol]: any;
|
|
5
|
+
}, Defaults extends Array<{
|
|
6
|
+
[x: string]: any;
|
|
7
|
+
[x: number]: any;
|
|
8
|
+
[x: symbol]: any;
|
|
9
|
+
} | (number | boolean | any[] | Record<never, any> | null | undefined)>>(source: Source, ...defaults: Defaults) => import("defu").Defu<Source, Defaults>;
|