@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.
Files changed (101) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +32 -0
  3. package/dist/components/Accordion.vue +104 -0
  4. package/dist/components/App.vue +57 -0
  5. package/dist/components/Button.vue +94 -0
  6. package/dist/components/Card.vue +76 -0
  7. package/dist/components/Checkbox.vue +104 -0
  8. package/dist/components/Drawer.vue +133 -0
  9. package/dist/components/Input.vue +169 -0
  10. package/dist/components/Link.vue +117 -0
  11. package/dist/components/Modal.vue +145 -0
  12. package/dist/components/ModalProvider.vue +10 -0
  13. package/dist/components/Popover.vue +97 -0
  14. package/dist/components/RadioGroup.vue +180 -0
  15. package/dist/components/Select.vue +258 -0
  16. package/dist/components/Switch.vue +99 -0
  17. package/dist/components/Tabs.vue +117 -0
  18. package/dist/components/Toast.vue +126 -0
  19. package/dist/components/Toaster.vue +143 -0
  20. package/dist/components/Tooltip.vue +71 -0
  21. package/dist/components/index.d.ts +18 -0
  22. package/dist/components/index.mjs +18 -0
  23. package/dist/composables/index.d.ts +4 -0
  24. package/dist/composables/index.mjs +4 -0
  25. package/dist/composables/useComponentIcons.d.ts +26 -0
  26. package/dist/composables/useComponentIcons.mjs +24 -0
  27. package/dist/composables/useModal.d.ts +15 -0
  28. package/dist/composables/useModal.mjs +51 -0
  29. package/dist/composables/useTheme.d.ts +8 -0
  30. package/dist/composables/useTheme.mjs +18 -0
  31. package/dist/composables/useToast.d.ts +24 -0
  32. package/dist/composables/useToast.mjs +48 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.mjs +3 -0
  35. package/dist/internal/constants.d.ts +3 -0
  36. package/dist/internal/constants.mjs +21 -0
  37. package/dist/internal/extend-theme.d.ts +9 -0
  38. package/dist/internal/extend-theme.mjs +16 -0
  39. package/dist/internal/extend-theme.test.d.ts +1 -0
  40. package/dist/internal/extend-theme.test.mjs +45 -0
  41. package/dist/internal/index.d.ts +4 -0
  42. package/dist/internal/index.mjs +4 -0
  43. package/dist/internal/link.d.ts +15 -0
  44. package/dist/internal/link.mjs +4 -0
  45. package/dist/internal/styler.d.ts +5 -0
  46. package/dist/internal/styler.mjs +236 -0
  47. package/dist/internal/styler.test.d.ts +1 -0
  48. package/dist/internal/styler.test.mjs +10 -0
  49. package/dist/nuxt.d.ts +10 -0
  50. package/dist/nuxt.mjs +28 -0
  51. package/dist/resolver.d.ts +10 -0
  52. package/dist/resolver.mjs +18 -0
  53. package/dist/theme/accordion.d.ts +39 -0
  54. package/dist/theme/accordion.mjs +25 -0
  55. package/dist/theme/app.d.ts +10 -0
  56. package/dist/theme/app.mjs +9 -0
  57. package/dist/theme/button.d.ts +184 -0
  58. package/dist/theme/button.mjs +140 -0
  59. package/dist/theme/card.d.ts +43 -0
  60. package/dist/theme/card.mjs +11 -0
  61. package/dist/theme/checkbox.d.ts +97 -0
  62. package/dist/theme/checkbox.mjs +53 -0
  63. package/dist/theme/drawer.d.ts +72 -0
  64. package/dist/theme/drawer.mjs +72 -0
  65. package/dist/theme/index.d.ts +17 -0
  66. package/dist/theme/index.mjs +17 -0
  67. package/dist/theme/input.d.ts +159 -0
  68. package/dist/theme/input.mjs +133 -0
  69. package/dist/theme/link.d.ts +31 -0
  70. package/dist/theme/link.mjs +23 -0
  71. package/dist/theme/modal.d.ts +50 -0
  72. package/dist/theme/modal.mjs +54 -0
  73. package/dist/theme/popover.d.ts +27 -0
  74. package/dist/theme/popover.mjs +10 -0
  75. package/dist/theme/radioGroup.d.ts +131 -0
  76. package/dist/theme/radioGroup.mjs +67 -0
  77. package/dist/theme/select.d.ts +177 -0
  78. package/dist/theme/select.mjs +154 -0
  79. package/dist/theme/switch.d.ts +131 -0
  80. package/dist/theme/switch.mjs +78 -0
  81. package/dist/theme/tabs.d.ts +101 -0
  82. package/dist/theme/tabs.mjs +117 -0
  83. package/dist/theme/toast.d.ts +51 -0
  84. package/dist/theme/toast.mjs +27 -0
  85. package/dist/theme/toaster.d.ts +73 -0
  86. package/dist/theme/toaster.mjs +89 -0
  87. package/dist/theme/tooltip.d.ts +31 -0
  88. package/dist/theme/tooltip.mjs +8 -0
  89. package/dist/types/components.d.ts +18 -0
  90. package/dist/types/components.mjs +0 -0
  91. package/dist/types/index.d.ts +7 -0
  92. package/dist/types/index.mjs +2 -0
  93. package/dist/types/utils.d.ts +29 -0
  94. package/dist/types/utils.mjs +0 -0
  95. package/dist/unocss-preset.d.ts +37 -0
  96. package/dist/unocss-preset.mjs +164 -0
  97. package/dist/utils/index.d.ts +18 -0
  98. package/dist/utils/index.mjs +70 -0
  99. package/dist/utils/unocss.d.ts +3 -0
  100. package/dist/utils/unocss.mjs +50 -0
  101. 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>