@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
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Yuurin<https://github.com/byyuurin>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @byyuurin/ui
|
|
2
|
+
|
|
3
|
+
A collection of Vue.js components for my projects.
|
|
4
|
+
|
|
5
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
6
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
7
|
+
[![bundle][bundle-src]][bundle-href]
|
|
8
|
+
[![JSDocs][jsdocs-src]][jsdocs-href]
|
|
9
|
+
[![License][license-src]][license-href]
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
```ssh
|
|
14
|
+
pnpm i @byyuurin/ui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## License
|
|
18
|
+
|
|
19
|
+
[MIT](./LICENSE) License © 2024-PRESENT [Yuurin](https://github.com/byyurin)
|
|
20
|
+
|
|
21
|
+
<!-- Badges -->
|
|
22
|
+
|
|
23
|
+
[npm-version-src]: https://img.shields.io/npm/v/@byyuurin/ui?style=flat&colorA=080f12&colorB=1fa669
|
|
24
|
+
[npm-version-href]: https://npmjs.com/package/@byyuurin/ui
|
|
25
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/@byyuurin/ui?style=flat&colorA=080f12&colorB=1fa669
|
|
26
|
+
[npm-downloads-href]: https://npmjs.com/package/@byyuurin/ui
|
|
27
|
+
[bundle-src]: https://img.shields.io/bundlephobia/minzip/@byyuurin/ui?style=flat&colorA=080f12&colorB=1fa669&label=minzip
|
|
28
|
+
[bundle-href]: https://bundlephobia.com/result?p=@byyuurin/ui
|
|
29
|
+
[license-src]: https://img.shields.io/github/license/byyuurin/@byyuurin/ui.svg?style=flat&colorA=080f12&colorB=1fa669
|
|
30
|
+
[license-href]: https://github.com/byyuurin/@byyuurin/ui/blob/main/LICENSE
|
|
31
|
+
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
|
|
32
|
+
[jsdocs-href]: https://www.jsdocs.io/package/@byyuurin/ui
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { AccordionRootEmits, AccordionRootProps, PrimitiveProps } from 'reka-ui'
|
|
3
|
+
import type { accordion } from '../theme'
|
|
4
|
+
import type { ComponentAttrs, DynamicSlots } from '../types'
|
|
5
|
+
|
|
6
|
+
export interface AccordionItem {
|
|
7
|
+
label?: string
|
|
8
|
+
icon?: string
|
|
9
|
+
trailingIcon?: string
|
|
10
|
+
slot?: string
|
|
11
|
+
content?: string
|
|
12
|
+
/** A unique value for the accordion item. Defaults to the index. */
|
|
13
|
+
value?: string
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface AccordionEmits extends AccordionRootEmits {}
|
|
18
|
+
|
|
19
|
+
type SlotProps<T> = (props: { item: T, index: number, open: boolean }) => any
|
|
20
|
+
|
|
21
|
+
export type AccordionSlots<T extends { slot?: string }> = {
|
|
22
|
+
default?: SlotProps<T>
|
|
23
|
+
icon?: SlotProps<T>
|
|
24
|
+
content?: SlotProps<T>
|
|
25
|
+
body?: SlotProps<T>
|
|
26
|
+
} & DynamicSlots<T, SlotProps<T>>
|
|
27
|
+
|
|
28
|
+
export interface AccordionProps<T> extends ComponentAttrs<typeof accordion>, Pick<AccordionRootProps, 'collapsible' | 'defaultValue' | 'modelValue' | 'type' | 'disabled' | 'unmountOnHide'> {
|
|
29
|
+
as?: PrimitiveProps['as']
|
|
30
|
+
items?: T[]
|
|
31
|
+
labelKey?: string
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<script setup lang="ts" generic="T extends AccordionItem">
|
|
36
|
+
import { reactivePick } from '@vueuse/core'
|
|
37
|
+
import { AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger, useForwardPropsEmits } from 'reka-ui'
|
|
38
|
+
import { computed } from 'vue'
|
|
39
|
+
import { useTheme } from '../composables'
|
|
40
|
+
import { get } from '../utils'
|
|
41
|
+
|
|
42
|
+
const props = withDefaults(defineProps<AccordionProps<T>>(), {
|
|
43
|
+
type: 'single',
|
|
44
|
+
collapsible: true,
|
|
45
|
+
unmountOnHide: true,
|
|
46
|
+
labelKey: 'label',
|
|
47
|
+
items: () => [],
|
|
48
|
+
})
|
|
49
|
+
const slots = defineSlots<AccordionSlots<T>>()
|
|
50
|
+
|
|
51
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'collapsible', 'defaultValue', 'disabled', 'modelValue', 'type', 'unmountOnHide'))
|
|
52
|
+
|
|
53
|
+
const { theme, createStyler } = useTheme()
|
|
54
|
+
const style = computed(() => {
|
|
55
|
+
const styler = createStyler(theme.value.accordion)
|
|
56
|
+
return styler(props)
|
|
57
|
+
})
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<AccordionRoot v-bind="rootProps" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
62
|
+
<AccordionItem
|
|
63
|
+
v-for="(item, index) in props.items"
|
|
64
|
+
v-slot="{ open }"
|
|
65
|
+
:key="index"
|
|
66
|
+
:value="item.value || String(index)"
|
|
67
|
+
:disabled="item.disabled"
|
|
68
|
+
:class="style.item({ class: props.ui?.item })"
|
|
69
|
+
>
|
|
70
|
+
<AccordionHeader :class="style.header({ class: props.ui?.header })">
|
|
71
|
+
<AccordionTrigger :class="style.trigger({ class: props.ui?.trigger, disabled: item.disabled })">
|
|
72
|
+
<slot name="icon" v-bind="{ item, index, open }">
|
|
73
|
+
<i v-if="item.icon" :class="style.icon({ class: [item.icon, props.ui?.icon] })"></i>
|
|
74
|
+
</slot>
|
|
75
|
+
|
|
76
|
+
<span v-if="get(item, props.labelKey as string) || slots.default" :class="style.label({ class: props.ui?.label })">
|
|
77
|
+
<slot v-bind="{ item, index, open }">{{ get(item, props.labelKey as string) }}</slot>
|
|
78
|
+
</span>
|
|
79
|
+
|
|
80
|
+
<slot name="trailing-icon" v-bind="{ item, index, open }">
|
|
81
|
+
<i v-if="item.trailingIcon" :class="style.icon({ class: [item.trailingIcon, props.ui?.trailingIcon] })"></i>
|
|
82
|
+
</slot>
|
|
83
|
+
</AccordionTrigger>
|
|
84
|
+
</AccordionHeader>
|
|
85
|
+
|
|
86
|
+
<AccordionContent
|
|
87
|
+
v-if="item.content || slots.content || (item.slot && slots[item.slot]) || slots.body || (slots[`${item.slot}-body`])"
|
|
88
|
+
:class="style.content({ class: props.ui?.content })"
|
|
89
|
+
>
|
|
90
|
+
<slot :name="item.slot || 'content'" v-bind="{ item, index, open }">
|
|
91
|
+
<div :class="style.body({ class: props.ui?.body })">
|
|
92
|
+
<slot :name="item.slot ? item.slot : 'body'" v-bind="{ item, index, open }">
|
|
93
|
+
{{ item.content }}
|
|
94
|
+
</slot>
|
|
95
|
+
</div>
|
|
96
|
+
</slot>
|
|
97
|
+
</AccordionContent>
|
|
98
|
+
</AccordionItem>
|
|
99
|
+
</AccordionRoot>
|
|
100
|
+
</template>
|
|
101
|
+
|
|
102
|
+
<style>
|
|
103
|
+
@keyframes accordion-up{0%{height:var(--reka-accordion-content-height)}to{height:0}}@keyframes accordion-down{0%{height:0}to{height:var(--reka-accordion-content-height)}}
|
|
104
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ConfigProviderProps, TooltipProviderProps } from 'reka-ui'
|
|
3
|
+
import type { ThemeExtension, ToasterProps } from '../types'
|
|
4
|
+
|
|
5
|
+
export interface AppProps extends Omit<ConfigProviderProps, 'useId' | 'dir' | 'locale'> {
|
|
6
|
+
ui?: ThemeExtension
|
|
7
|
+
tooltip?: TooltipProviderProps
|
|
8
|
+
toaster?: ToasterProps
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface AppSlots {
|
|
12
|
+
default: (props?: Record<string, unknown>) => any
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<script setup lang="ts">
|
|
17
|
+
import { reactivePick } from '@vueuse/core'
|
|
18
|
+
import { ConfigProvider, TooltipProvider, useForwardProps } from 'reka-ui'
|
|
19
|
+
import { computed, shallowRef, toRef, useId } from 'vue'
|
|
20
|
+
import type { ModalState } from '../composables/useModal'
|
|
21
|
+
import { provideModalState } from '../composables/useModal'
|
|
22
|
+
import { provideThemeExtension } from '../composables/useTheme'
|
|
23
|
+
import ModalProvider from './ModalProvider.vue'
|
|
24
|
+
import Toaster from './Toaster.vue'
|
|
25
|
+
|
|
26
|
+
const props = withDefaults(defineProps<AppProps>(), {
|
|
27
|
+
ui: () => ({}),
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
defineSlots<AppSlots>()
|
|
31
|
+
|
|
32
|
+
const configProviderProps = useForwardProps(reactivePick(props, 'scrollBody'))
|
|
33
|
+
const tooltipProps = toRef(() => props.tooltip)
|
|
34
|
+
const toasterProps = toRef(() => props.toaster)
|
|
35
|
+
|
|
36
|
+
const modalState = shallowRef<ModalState>({
|
|
37
|
+
component: 'div',
|
|
38
|
+
props: {},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const themeExtension = computed(() => props.ui)
|
|
42
|
+
|
|
43
|
+
provideModalState(modalState)
|
|
44
|
+
provideThemeExtension(themeExtension)
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<ConfigProvider :use-id="useId" v-bind="configProviderProps">
|
|
49
|
+
<TooltipProvider v-bind="tooltipProps">
|
|
50
|
+
<Toaster v-if="props.toaster !== null" v-bind="toasterProps">
|
|
51
|
+
<slot></slot>
|
|
52
|
+
</Toaster>
|
|
53
|
+
<slot v-else></slot>
|
|
54
|
+
</TooltipProvider>
|
|
55
|
+
<ModalProvider />
|
|
56
|
+
</ConfigProvider>
|
|
57
|
+
</template>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
+
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
4
|
+
import type { button } from '../theme'
|
|
5
|
+
import type { ComponentAttrs } from '../types'
|
|
6
|
+
import type { LinkProps } from './Link.vue'
|
|
7
|
+
|
|
8
|
+
export interface ButtonSlots {
|
|
9
|
+
default?: (props?: any) => any
|
|
10
|
+
prefix?: (props?: any) => any
|
|
11
|
+
suffix?: (props?: any) => any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type ButtonVariants = VariantProps<typeof button>
|
|
15
|
+
type UIOptions = ComponentAttrs<typeof button>['ui'] & LinkProps['ui']
|
|
16
|
+
|
|
17
|
+
export interface ButtonProps extends Omit<ComponentAttrs<typeof button>, 'ui'>, UseComponentIconsProps, Omit<LinkProps, 'ui' | 'raw'> {
|
|
18
|
+
icon?: string
|
|
19
|
+
label?: string
|
|
20
|
+
variant?: ButtonVariants['variant']
|
|
21
|
+
size?: ButtonVariants['size']
|
|
22
|
+
round?: boolean
|
|
23
|
+
loading?: boolean
|
|
24
|
+
active?: boolean
|
|
25
|
+
disabled?: boolean
|
|
26
|
+
ui?: UIOptions
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts" setup>
|
|
31
|
+
import { computed } from 'vue'
|
|
32
|
+
import { useComponentIcons, useTheme } from '../composables'
|
|
33
|
+
import { pickLinkProps } from '../internal'
|
|
34
|
+
import { omit } from '../utils'
|
|
35
|
+
import Link from './Link.vue'
|
|
36
|
+
|
|
37
|
+
const props = withDefaults(defineProps<ButtonProps>(), {
|
|
38
|
+
variant: 'solid',
|
|
39
|
+
size: 'md',
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const slots = defineSlots<ButtonSlots>()
|
|
43
|
+
|
|
44
|
+
const { isPrefix, isSuffix, prefixIconName, suffixIconName } = useComponentIcons(
|
|
45
|
+
computed(() => ({ ...props, loading: props.loading })),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
const linkProps = pickLinkProps(props)
|
|
49
|
+
|
|
50
|
+
const { theme, createStyler } = useTheme()
|
|
51
|
+
|
|
52
|
+
const style = computed(() => {
|
|
53
|
+
const styler = createStyler(theme.value.button)
|
|
54
|
+
return styler({
|
|
55
|
+
...props,
|
|
56
|
+
prefix: isPrefix.value,
|
|
57
|
+
suffix: isSuffix.value,
|
|
58
|
+
class: [
|
|
59
|
+
props.class,
|
|
60
|
+
props.active ? props.ui?.active : props.ui?.inactive,
|
|
61
|
+
props.disabled ? props.ui?.disabled : undefined,
|
|
62
|
+
],
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<Link
|
|
69
|
+
:class="style.base({ class: [props.class, props.ui?.base] })"
|
|
70
|
+
:type="props.type"
|
|
71
|
+
:disabled="props.disabled || props.loading"
|
|
72
|
+
v-bind="omit(linkProps, ['type', 'disabled'])"
|
|
73
|
+
raw
|
|
74
|
+
>
|
|
75
|
+
<slot name="prefix">
|
|
76
|
+
<i
|
|
77
|
+
v-if="isPrefix && prefixIconName"
|
|
78
|
+
:class="style.prefixIcon({ class: [prefixIconName, props.ui?.prefixIcon] })"
|
|
79
|
+
></i>
|
|
80
|
+
</slot>
|
|
81
|
+
<span
|
|
82
|
+
v-if="slots.default || props.label"
|
|
83
|
+
:class="style.label({ class: props.ui?.label })"
|
|
84
|
+
>
|
|
85
|
+
<slot>{{ label }}</slot>
|
|
86
|
+
</span>
|
|
87
|
+
<slot name="suffix">
|
|
88
|
+
<i
|
|
89
|
+
v-if="isSuffix && suffixIconName"
|
|
90
|
+
:class="style.suffixIcon({ class: [suffixIconName, props.ui?.suffixIcon] })"
|
|
91
|
+
></i>
|
|
92
|
+
</slot>
|
|
93
|
+
</Link>
|
|
94
|
+
</template>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PrimitiveProps } from 'reka-ui'
|
|
3
|
+
import type { card } from '../theme'
|
|
4
|
+
import type { ComponentAttrs } from '../types'
|
|
5
|
+
|
|
6
|
+
export interface CardProps extends ComponentAttrs<typeof card> {
|
|
7
|
+
as?: PrimitiveProps['as']
|
|
8
|
+
title?: string
|
|
9
|
+
description?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CardSlots {
|
|
13
|
+
default?: (props?: {}) => any
|
|
14
|
+
content?: (props?: {}) => any
|
|
15
|
+
header?: (props?: {}) => any
|
|
16
|
+
title?: (props?: any) => any
|
|
17
|
+
description?: (props?: any) => any
|
|
18
|
+
footer?: (props?: {}) => any
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { Primitive } from 'reka-ui'
|
|
24
|
+
import { computed } from 'vue'
|
|
25
|
+
import { useTheme } from '../composables'
|
|
26
|
+
|
|
27
|
+
const props = withDefaults(defineProps<CardProps>(), {})
|
|
28
|
+
const slots = defineSlots<CardSlots>()
|
|
29
|
+
|
|
30
|
+
const { theme, createStyler } = useTheme()
|
|
31
|
+
const style = computed(() => {
|
|
32
|
+
const styler = createStyler(theme.value.card)
|
|
33
|
+
return styler(props)
|
|
34
|
+
})
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<Primitive :as="props.as" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
39
|
+
<slot name="content">
|
|
40
|
+
<div
|
|
41
|
+
v-if="slots.header || slots.title || props.title || slots.description || props.description"
|
|
42
|
+
:class="style.header({ class: props.ui?.header })"
|
|
43
|
+
>
|
|
44
|
+
<slot name="header">
|
|
45
|
+
<Primitive
|
|
46
|
+
v-if="slots.title || props.title"
|
|
47
|
+
:as="slots.title ? undefined : 'h2'"
|
|
48
|
+
:class="style.title({ class: props.ui?.title })"
|
|
49
|
+
>
|
|
50
|
+
<slot name="title">
|
|
51
|
+
{{ props.title }}
|
|
52
|
+
</slot>
|
|
53
|
+
</Primitive>
|
|
54
|
+
<Primitive
|
|
55
|
+
v-if="slots.description || props.description"
|
|
56
|
+
:as="slots.description ? undefined : 'p'"
|
|
57
|
+
:as-child="!!slots.description"
|
|
58
|
+
:class="style.description({ class: props.ui?.description })"
|
|
59
|
+
>
|
|
60
|
+
<slot name="description">
|
|
61
|
+
{{ props.description }}
|
|
62
|
+
</slot>
|
|
63
|
+
</Primitive>
|
|
64
|
+
</slot>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div v-if="slots.default" :class="style.body({ class: props.ui?.body })">
|
|
68
|
+
<slot></slot>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div v-if="slots.footer" :class="style.footer({ class: props.ui?.footer })">
|
|
72
|
+
<slot name="footer"></slot>
|
|
73
|
+
</div>
|
|
74
|
+
</slot>
|
|
75
|
+
</Primitive>
|
|
76
|
+
</template>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from '@byyuurin/ui-kit'
|
|
3
|
+
import type { CheckboxRootProps, PrimitiveProps } from 'reka-ui'
|
|
4
|
+
import type { checkbox } from '../theme'
|
|
5
|
+
import type { ComponentAttrs } from '../types'
|
|
6
|
+
|
|
7
|
+
type CheckboxVariants = VariantProps<typeof checkbox>
|
|
8
|
+
|
|
9
|
+
export interface CheckboxProps extends ComponentAttrs<typeof checkbox>, Pick<CheckboxRootProps, 'disabled' | 'required' | 'name' | 'value' | 'id' | 'defaultValue'> {
|
|
10
|
+
as?: PrimitiveProps['as']
|
|
11
|
+
label?: string
|
|
12
|
+
description?: string
|
|
13
|
+
size?: CheckboxVariants['size']
|
|
14
|
+
/**
|
|
15
|
+
* The icon displayed when checked.
|
|
16
|
+
* @default app.icons.check
|
|
17
|
+
*/
|
|
18
|
+
icon?: string
|
|
19
|
+
/**
|
|
20
|
+
* The icon displayed when the checkbox is indeterminate.
|
|
21
|
+
* @default app.icons.indeterminate
|
|
22
|
+
*/
|
|
23
|
+
indeterminateIcon?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CheckboxEmits {
|
|
27
|
+
(event: 'change', payload: Event): void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CheckboxSlots {
|
|
31
|
+
label?: (props: { label?: string }) => any
|
|
32
|
+
description?: (props: { description?: string }) => any
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<script lang="ts" setup>
|
|
37
|
+
import { reactivePick } from '@vueuse/core'
|
|
38
|
+
import { CheckboxIndicator, CheckboxRoot, Label, Primitive, useForwardProps } from 'reka-ui'
|
|
39
|
+
import { computed, useId } from 'vue'
|
|
40
|
+
import { useTheme } from '../composables'
|
|
41
|
+
|
|
42
|
+
const props = withDefaults(defineProps<CheckboxProps>(), {
|
|
43
|
+
size: 'md',
|
|
44
|
+
required: false,
|
|
45
|
+
disabled: false,
|
|
46
|
+
})
|
|
47
|
+
const emit = defineEmits<CheckboxEmits>()
|
|
48
|
+
const slots = defineSlots<CheckboxSlots>()
|
|
49
|
+
|
|
50
|
+
const innerValue = defineModel<boolean | 'indeterminate'>({ default: undefined })
|
|
51
|
+
const rootProps = useForwardProps(reactivePick(props, 'required', 'value', 'defaultValue'))
|
|
52
|
+
|
|
53
|
+
const id = props.id ?? useId()
|
|
54
|
+
|
|
55
|
+
const { theme, createStyler } = useTheme()
|
|
56
|
+
const style = computed(() => {
|
|
57
|
+
const styler = createStyler(theme.value.checkbox)
|
|
58
|
+
return styler({
|
|
59
|
+
...props,
|
|
60
|
+
checked: Boolean(innerValue.value ?? props.defaultValue),
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
function onUpdate(value: any) {
|
|
65
|
+
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
66
|
+
const event = new Event('change', { target: value })
|
|
67
|
+
emit('change', event)
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<Primitive :as="props.as" :class="style.root({ class: [props.class, props.ui?.root] })">
|
|
73
|
+
<div :class="style.container({ class: props.ui?.container })">
|
|
74
|
+
<CheckboxRoot
|
|
75
|
+
:id="id"
|
|
76
|
+
v-bind="rootProps"
|
|
77
|
+
v-slot="{ modelValue }"
|
|
78
|
+
v-model="innerValue"
|
|
79
|
+
:name="props.name"
|
|
80
|
+
:disabled="props.disabled"
|
|
81
|
+
:class="style.base({ class: props.ui?.base })"
|
|
82
|
+
@update:model-value="onUpdate"
|
|
83
|
+
>
|
|
84
|
+
<CheckboxIndicator as-child>
|
|
85
|
+
<i
|
|
86
|
+
v-if="modelValue === 'indeterminate'"
|
|
87
|
+
:class="style.icon({ class: [props.indeterminateIcon || theme.app.icons.indeterminate, props.ui?.icon] })"
|
|
88
|
+
></i>
|
|
89
|
+
<i v-else :class="style.icon({ class: [props.icon, theme.app.icons.check, props.ui?.icon] })"></i>
|
|
90
|
+
</CheckboxIndicator>
|
|
91
|
+
</CheckboxRoot>
|
|
92
|
+
</div>
|
|
93
|
+
<div v-if="props.label || slots.label || props.description || slots.description" :class="style.wrapper({ class: props.ui?.wrapper })">
|
|
94
|
+
<Label v-if="props.label || slots.label" :for="id" :class="style.label({ class: props.ui?.label })">
|
|
95
|
+
<slot name="label" :label="props.label">{{ props.label }}</slot>
|
|
96
|
+
</Label>
|
|
97
|
+
<p v-if="props.description || slots.description" :class="style.description({ class: props.ui?.description })">
|
|
98
|
+
<slot name="description" :description="props.description">
|
|
99
|
+
{{ props.description }}
|
|
100
|
+
</slot>
|
|
101
|
+
</p>
|
|
102
|
+
</div>
|
|
103
|
+
</Primitive>
|
|
104
|
+
</template>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { DialogContentProps, PrimitiveProps } from 'reka-ui'
|
|
3
|
+
import type { DrawerRootEmits, DrawerRootProps } from 'vaul-vue'
|
|
4
|
+
import type { drawer } from '../theme'
|
|
5
|
+
import type { ComponentAttrs } from '../types'
|
|
6
|
+
|
|
7
|
+
export interface DrawerProps extends ComponentAttrs<typeof drawer>, Pick<DrawerRootProps, 'activeSnapPoint' | 'closeThreshold' | 'defaultOpen' | 'direction' | 'fadeFromIndex' | 'fixed' | 'modal' | 'nested' | 'direction' | 'open' | 'scrollLockTimeout' | 'shouldScaleBackground' | 'snapPoints'> {
|
|
8
|
+
as?: PrimitiveProps['as']
|
|
9
|
+
title?: string
|
|
10
|
+
description?: string
|
|
11
|
+
/** The content of the drawer. */
|
|
12
|
+
content?: Omit<DialogContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
13
|
+
/**
|
|
14
|
+
* Render an overlay behind the drawer.
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
overlay?: boolean
|
|
18
|
+
blur?: boolean
|
|
19
|
+
full?: boolean
|
|
20
|
+
/**
|
|
21
|
+
* Render a handle on the drawer.
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
handle?: boolean
|
|
25
|
+
/**
|
|
26
|
+
* Render the drawer in a portal.
|
|
27
|
+
* @default true
|
|
28
|
+
*/
|
|
29
|
+
portal?: boolean
|
|
30
|
+
/**
|
|
31
|
+
* When `false`, the drawer will not close when clicking outside or pressing escape.
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
dismissible?: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DrawerEmits extends DrawerRootEmits {}
|
|
38
|
+
|
|
39
|
+
export interface DrawerSlots {
|
|
40
|
+
default?: (props?: {}) => any
|
|
41
|
+
handle?: (props?: {}) => any
|
|
42
|
+
content?: (props?: {}) => any
|
|
43
|
+
header?: (props?: {}) => any
|
|
44
|
+
title?: (props?: {}) => any
|
|
45
|
+
description?: (props?: {}) => any
|
|
46
|
+
body?: (props?: {}) => any
|
|
47
|
+
footer?: (props?: {}) => any
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<script setup lang="ts">
|
|
52
|
+
import { reactivePick } from '@vueuse/core'
|
|
53
|
+
import { useForwardPropsEmits } from 'reka-ui'
|
|
54
|
+
import { DrawerContent, DrawerDescription, DrawerOverlay, DrawerPortal, DrawerRoot, DrawerTitle, DrawerTrigger } from 'vaul-vue'
|
|
55
|
+
import { computed, toRef } from 'vue'
|
|
56
|
+
import { useTheme } from '../composables'
|
|
57
|
+
|
|
58
|
+
const props = withDefaults(defineProps<DrawerProps>(), {
|
|
59
|
+
direction: 'bottom',
|
|
60
|
+
portal: true,
|
|
61
|
+
overlay: true,
|
|
62
|
+
handle: true,
|
|
63
|
+
})
|
|
64
|
+
const emit = defineEmits<DrawerEmits>()
|
|
65
|
+
const slots = defineSlots<DrawerSlots>()
|
|
66
|
+
|
|
67
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'activeSnapPoint', 'closeThreshold', 'defaultOpen', 'dismissible', 'fadeFromIndex', 'fixed', 'modal', 'nested', 'direction', 'open', 'scrollLockTimeout', 'shouldScaleBackground', 'snapPoints'), emit)
|
|
68
|
+
const contentProps = toRef(() => props.content)
|
|
69
|
+
|
|
70
|
+
const { theme, createStyler } = useTheme()
|
|
71
|
+
const style = computed(() => {
|
|
72
|
+
const styler = createStyler(theme.value.drawer)
|
|
73
|
+
return styler(props)
|
|
74
|
+
})
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<template>
|
|
78
|
+
<DrawerRoot v-bind="rootProps">
|
|
79
|
+
<DrawerTrigger v-if="slots.default" as-child :class="props.class">
|
|
80
|
+
<slot></slot>
|
|
81
|
+
</DrawerTrigger>
|
|
82
|
+
|
|
83
|
+
<DrawerPortal :disabled="!props.portal">
|
|
84
|
+
<DrawerOverlay v-if="props.overlay" :class="style.overlay({ class: props.ui?.overlay })" />
|
|
85
|
+
|
|
86
|
+
<DrawerContent
|
|
87
|
+
:class="style.content({ class: [!slots.default && props.class, props.ui?.content] })"
|
|
88
|
+
v-bind="contentProps"
|
|
89
|
+
>
|
|
90
|
+
<slot name="handle">
|
|
91
|
+
<div v-if="props.handle" :class="style.handle({ class: props.ui?.handle })"></div>
|
|
92
|
+
</slot>
|
|
93
|
+
|
|
94
|
+
<slot name="content">
|
|
95
|
+
<div :class="style.container({ class: props.ui?.container })">
|
|
96
|
+
<div
|
|
97
|
+
v-if="slots.header || (props.title || slots.title) || (props.description || slots.description)"
|
|
98
|
+
:class="style.header({ class: props.ui?.header })"
|
|
99
|
+
>
|
|
100
|
+
<slot name="header">
|
|
101
|
+
<DrawerTitle
|
|
102
|
+
v-if="props.title || slots.title"
|
|
103
|
+
:class="style.title({ class: props.ui?.title })"
|
|
104
|
+
>
|
|
105
|
+
<slot name="title">
|
|
106
|
+
{{ props.title }}
|
|
107
|
+
</slot>
|
|
108
|
+
</DrawerTitle>
|
|
109
|
+
|
|
110
|
+
<DrawerDescription
|
|
111
|
+
v-if="props.description || slots.description"
|
|
112
|
+
:class="style.description({ class: props.ui?.description })"
|
|
113
|
+
>
|
|
114
|
+
<slot name="description">
|
|
115
|
+
{{ props.description }}
|
|
116
|
+
</slot>
|
|
117
|
+
</DrawerDescription>
|
|
118
|
+
</slot>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div v-if="slots.body" :class="style.body({ class: props.ui?.body })">
|
|
122
|
+
<slot name="body"></slot>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div v-if="slots.footer" :class="style.footer({ class: props.ui?.footer })">
|
|
126
|
+
<slot name="footer"></slot>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</slot>
|
|
130
|
+
</DrawerContent>
|
|
131
|
+
</DrawerPortal>
|
|
132
|
+
</DrawerRoot>
|
|
133
|
+
</template>
|