@byyuurin/ui 0.0.2 → 0.0.4

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 (109) hide show
  1. package/README.md +76 -4
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.mjs +3 -3
  4. package/dist/nuxt.d.mts +13 -0
  5. package/dist/nuxt.d.ts +6 -3
  6. package/dist/nuxt.mjs +6 -3
  7. package/dist/resolver.d.mts +13 -0
  8. package/dist/resolver.d.ts +6 -3
  9. package/dist/resolver.mjs +5 -2
  10. package/dist/{components → runtime/components}/Accordion.vue +19 -3
  11. package/dist/{components → runtime/components}/App.vue +5 -1
  12. package/dist/{components → runtime/components}/Button.vue +92 -94
  13. package/dist/{components → runtime/components}/Checkbox.vue +101 -104
  14. package/dist/{components → runtime/components}/Input.vue +5 -1
  15. package/dist/{components → runtime/components}/ModalProvider.vue +1 -1
  16. package/dist/{components → runtime/components}/RadioGroup.vue +174 -180
  17. package/dist/runtime/components/ScrollArea.vue +72 -0
  18. package/dist/{components → runtime/components}/Select.vue +262 -258
  19. package/dist/{components → runtime/components}/Switch.vue +98 -99
  20. package/dist/{components → runtime/components}/Tabs.vue +117 -117
  21. package/dist/runtime/components/Textarea.vue +173 -0
  22. package/dist/{components → runtime/components}/Toast.vue +1 -1
  23. package/dist/{components → runtime/components}/Toaster.vue +35 -1
  24. package/dist/{components → runtime/components}/index.d.ts +2 -0
  25. package/dist/{components → runtime/components}/index.mjs +2 -0
  26. package/dist/runtime/composables/defineInjection.d.ts +11 -0
  27. package/dist/runtime/composables/defineInjection.mjs +9 -0
  28. package/dist/{composables → runtime/composables}/index.d.ts +1 -0
  29. package/dist/{composables → runtime/composables}/index.mjs +1 -0
  30. package/dist/{composables → runtime/composables}/useModal.d.ts +1 -1
  31. package/dist/{composables → runtime/composables}/useModal.mjs +3 -2
  32. package/dist/{composables → runtime/composables}/useTheme.d.ts +3 -2
  33. package/dist/runtime/composables/useTheme.mjs +26 -0
  34. package/dist/{composables → runtime/composables}/useToast.d.ts +1 -1
  35. package/dist/{theme → runtime/theme}/button.d.ts +0 -8
  36. package/dist/{theme → runtime/theme}/button.mjs +1 -9
  37. package/dist/{theme → runtime/theme}/checkbox.d.ts +0 -12
  38. package/dist/{theme → runtime/theme}/checkbox.mjs +4 -9
  39. package/dist/{theme → runtime/theme}/index.d.ts +2 -0
  40. package/dist/{theme → runtime/theme}/index.mjs +2 -0
  41. package/dist/{theme → runtime/theme}/radioGroup.d.ts +0 -24
  42. package/dist/{theme → runtime/theme}/radioGroup.mjs +8 -20
  43. package/dist/runtime/theme/scrollArea.d.ts +51 -0
  44. package/dist/runtime/theme/scrollArea.mjs +30 -0
  45. package/dist/{theme → runtime/theme}/switch.d.ts +0 -12
  46. package/dist/{theme → runtime/theme}/switch.mjs +2 -8
  47. package/dist/{theme → runtime/theme}/tabs.d.ts +32 -11
  48. package/dist/{theme → runtime/theme}/tabs.mjs +19 -12
  49. package/dist/runtime/theme/textarea.d.ts +90 -0
  50. package/dist/runtime/theme/textarea.mjs +100 -0
  51. package/dist/{theme → runtime/theme}/toast.mjs +1 -1
  52. package/dist/{types → runtime/types}/components.d.ts +2 -0
  53. package/dist/{types → runtime/types}/index.d.ts +1 -1
  54. package/dist/{utils → runtime/utils}/index.d.ts +3 -12
  55. package/dist/{utils → runtime/utils}/index.mjs +3 -12
  56. package/dist/{internal → runtime/utils}/styler.d.ts +0 -1
  57. package/dist/runtime/utils/styler.mjs +10 -0
  58. package/dist/{internal/constants.mjs → shared/ui.Cmq14xN9.mjs} +6 -2
  59. package/dist/unocss-preset.d.mts +57 -0
  60. package/dist/unocss-preset.d.ts +29 -9
  61. package/dist/unocss-preset.mjs +164 -110
  62. package/package.json +18 -12
  63. package/dist/composables/useTheme.mjs +0 -18
  64. package/dist/internal/constants.d.ts +0 -3
  65. package/dist/internal/index.d.ts +0 -4
  66. package/dist/internal/index.mjs +0 -4
  67. package/dist/internal/styler.mjs +0 -236
  68. package/dist/utils/unocss.d.ts +0 -3
  69. package/dist/utils/unocss.mjs +0 -50
  70. /package/dist/{components → runtime/components}/Card.vue +0 -0
  71. /package/dist/{components → runtime/components}/Drawer.vue +0 -0
  72. /package/dist/{components → runtime/components}/Link.vue +0 -0
  73. /package/dist/{components → runtime/components}/Modal.vue +0 -0
  74. /package/dist/{components → runtime/components}/Popover.vue +0 -0
  75. /package/dist/{components → runtime/components}/Tooltip.vue +0 -0
  76. /package/dist/{composables → runtime/composables}/useComponentIcons.d.ts +0 -0
  77. /package/dist/{composables → runtime/composables}/useComponentIcons.mjs +0 -0
  78. /package/dist/{composables → runtime/composables}/useToast.mjs +0 -0
  79. /package/dist/{theme → runtime/theme}/accordion.d.ts +0 -0
  80. /package/dist/{theme → runtime/theme}/accordion.mjs +0 -0
  81. /package/dist/{theme → runtime/theme}/app.d.ts +0 -0
  82. /package/dist/{theme → runtime/theme}/app.mjs +0 -0
  83. /package/dist/{theme → runtime/theme}/card.d.ts +0 -0
  84. /package/dist/{theme → runtime/theme}/card.mjs +0 -0
  85. /package/dist/{theme → runtime/theme}/drawer.d.ts +0 -0
  86. /package/dist/{theme → runtime/theme}/drawer.mjs +0 -0
  87. /package/dist/{theme → runtime/theme}/input.d.ts +0 -0
  88. /package/dist/{theme → runtime/theme}/input.mjs +0 -0
  89. /package/dist/{theme → runtime/theme}/link.d.ts +0 -0
  90. /package/dist/{theme → runtime/theme}/link.mjs +0 -0
  91. /package/dist/{theme → runtime/theme}/modal.d.ts +0 -0
  92. /package/dist/{theme → runtime/theme}/modal.mjs +0 -0
  93. /package/dist/{theme → runtime/theme}/popover.d.ts +0 -0
  94. /package/dist/{theme → runtime/theme}/popover.mjs +0 -0
  95. /package/dist/{theme → runtime/theme}/select.d.ts +0 -0
  96. /package/dist/{theme → runtime/theme}/select.mjs +0 -0
  97. /package/dist/{theme → runtime/theme}/toast.d.ts +0 -0
  98. /package/dist/{theme → runtime/theme}/toaster.d.ts +0 -0
  99. /package/dist/{theme → runtime/theme}/toaster.mjs +0 -0
  100. /package/dist/{theme → runtime/theme}/tooltip.d.ts +0 -0
  101. /package/dist/{theme → runtime/theme}/tooltip.mjs +0 -0
  102. /package/dist/{types → runtime/types}/components.mjs +0 -0
  103. /package/dist/{types → runtime/types}/index.mjs +0 -0
  104. /package/dist/{types → runtime/types}/utils.d.ts +0 -0
  105. /package/dist/{types → runtime/types}/utils.mjs +0 -0
  106. /package/dist/{internal → runtime/utils}/extend-theme.d.ts +0 -0
  107. /package/dist/{internal → runtime/utils}/extend-theme.mjs +0 -0
  108. /package/dist/{internal → runtime/utils}/link.d.ts +0 -0
  109. /package/dist/{internal → runtime/utils}/link.mjs +0 -0
@@ -1,104 +1,101 @@
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>
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(props)
59
+ })
60
+
61
+ function onUpdate(value: any) {
62
+ // @ts-expect-error - 'target' does not exist in type 'EventInit'
63
+ const event = new Event('change', { target: value })
64
+ emit('change', event)
65
+ }
66
+ </script>
67
+
68
+ <template>
69
+ <Primitive :as="props.as" :class="style.root({ class: [props.class, props.ui?.root] })">
70
+ <div :class="style.container({ class: props.ui?.container })">
71
+ <CheckboxRoot
72
+ :id="id"
73
+ v-bind="rootProps"
74
+ v-slot="{ modelValue }"
75
+ v-model="innerValue"
76
+ :name="props.name"
77
+ :disabled="props.disabled"
78
+ :class="style.base({ class: props.ui?.base })"
79
+ @update:model-value="onUpdate"
80
+ >
81
+ <CheckboxIndicator as-child force-mount>
82
+ <i
83
+ v-if="modelValue === 'indeterminate'"
84
+ :class="style.icon({ class: [props.indeterminateIcon || theme.app.icons.indeterminate, props.ui?.icon] })"
85
+ ></i>
86
+ <i v-else :class="style.icon({ class: [props.icon, theme.app.icons.check, props.ui?.icon] })"></i>
87
+ </CheckboxIndicator>
88
+ </CheckboxRoot>
89
+ </div>
90
+ <div v-if="props.label || slots.label || props.description || slots.description" :class="style.wrapper({ class: props.ui?.wrapper })">
91
+ <Label v-if="props.label || slots.label" :for="id" :class="style.label({ class: props.ui?.label })">
92
+ <slot name="label" :label="props.label">{{ props.label }}</slot>
93
+ </Label>
94
+ <p v-if="props.description || slots.description" :class="style.description({ class: props.ui?.description })">
95
+ <slot name="description" :description="props.description">
96
+ {{ props.description }}
97
+ </slot>
98
+ </p>
99
+ </div>
100
+ </Primitive>
101
+ </template>
@@ -128,7 +128,11 @@ onMounted(() => {
128
128
  </script>
129
129
 
130
130
  <template>
131
- <Primitive :as="as" :class="style.root({ class: [props.class, props.ui?.root] })" :aria-disabled="props.disabled ? true : undefined">
131
+ <Primitive
132
+ :as="as"
133
+ :class="style.root({ class: [props.class, props.ui?.root] })"
134
+ :aria-disabled="props.disabled ? true : undefined"
135
+ >
132
136
  <span v-if="isPrefix || slots.prefix" :class="style.prefix({ class: props.ui?.prefix })">
133
137
  <slot name="prefix">
134
138
  <i
@@ -6,5 +6,5 @@ const { isOpen } = useModal()
6
6
  </script>
7
7
 
8
8
  <template>
9
- <component :is="modalState.component" v-if="modalState?.props.open" v-bind="modalState.props" v-model:open="isOpen" />
9
+ <component :is="modalState.component" v-if="modalState" v-bind="modalState.props" v-model:open="isOpen" />
10
10
  </template>
@@ -1,180 +1,174 @@
1
- <script lang="ts">
2
- import type { VariantProps } from '@byyuurin/ui-kit'
3
- import type { AcceptableValue, PrimitiveProps, RadioGroupRootProps } from 'reka-ui'
4
- import type { radioGroup } from '../theme'
5
- import type { ComponentAttrs } from '../types'
6
-
7
- type RadioGroupVariants = VariantProps<typeof radioGroup>
8
-
9
- export interface RadioOption {
10
- label?: string
11
- description?: string
12
- disabled?: boolean
13
- value?: string
14
- }
15
-
16
- export interface RadioGroupProps<T> extends ComponentAttrs<typeof radioGroup>, Pick<RadioGroupRootProps, 'defaultValue' | 'disabled' | 'loop' | 'modelValue' | 'name' | 'required'> {
17
- as?: PrimitiveProps['as']
18
- legend?: string
19
- /**
20
- * When `options` is an array of objects, select the field to use as the value.
21
- * @default 'value'
22
- */
23
- valueKey?: string
24
- /**
25
- * When `options` is an array of objects, select the field to use as the label.
26
- * @default 'label'
27
- */
28
- labelKey?: string
29
- /**
30
- * When `options` is an array of objects, select the field to use as the description.
31
- * @default 'description'
32
- */
33
- descriptionKey?: string
34
- options?: T[]
35
- size?: RadioGroupVariants['size']
36
- /**
37
- * The orientation the radio buttons are laid out.
38
- * @default 'vertical'
39
- */
40
- orientation?: RadioGroupRootProps['orientation']
41
- /** @default true */
42
- round?: boolean
43
- /** @default true */
44
- dot?: boolean
45
- }
46
-
47
- export interface RadioGroupEmits {
48
- (event: 'update:modelValue', payload: string): void
49
- (event: 'change', payload: Event): void
50
- }
51
-
52
- type SlotProps<T> = (props: { item: NormalizeItem<T>, modelValue?: AcceptableValue }) => any
53
-
54
- export interface RadioGroupSlots<T> {
55
- legend?: (props?: {}) => any
56
- label?: SlotProps<T>
57
- description?: SlotProps<T>
58
- }
59
-
60
- type NormalizeItem<T> = { id: string } & (
61
- T extends RadioOption
62
- ? T
63
- : {
64
- id: string
65
- label: string
66
- value: any
67
- description: string
68
- disabled: false
69
- }
70
- )
71
- </script>
72
-
73
- <script lang="ts" setup generic="T extends RadioOption | AcceptableValue">
74
- import { reactivePick } from '@vueuse/core'
75
- import { Label, RadioGroupIndicator, RadioGroupItem, RadioGroupRoot, useForwardPropsEmits } from 'reka-ui'
76
- import { computed, useId } from 'vue'
77
- import { useTheme } from '../composables'
78
- import { get } from '../utils'
79
-
80
- const props = withDefaults(defineProps<RadioGroupProps<T>>(), {
81
- size: 'md',
82
- valueKey: 'value',
83
- labelKey: 'label',
84
- descriptionKey: 'description',
85
- orientation: 'vertical',
86
- dot: true,
87
- round: true,
88
- })
89
-
90
- const emit = defineEmits<RadioGroupEmits>()
91
- const slots = defineSlots<RadioGroupSlots<T>>()
92
-
93
- const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emit)
94
- const id = useId()
95
-
96
- const { theme, createStyler } = useTheme()
97
- const style = computed(() => {
98
- const styler = createStyler(theme.value.radioGroup)
99
- return styler(props)
100
- })
101
-
102
- function normalizeItem(item: any): NormalizeItem<T> {
103
- if (['string', 'number', 'boolean'].includes(typeof item)) {
104
- return {
105
- id: `${id}:${item}`,
106
- value: item,
107
- label: item,
108
- description: '',
109
- } as any
110
- }
111
-
112
- const value = get(item, props.valueKey as string)
113
- const label = get(item, props.labelKey as string)
114
- const description = get(item, props.descriptionKey as string)
115
-
116
- return {
117
- ...item,
118
- value,
119
- label,
120
- description,
121
- id: `${id}:${value}`,
122
- }
123
- }
124
-
125
- const normalizedItems = computed(() => {
126
- if (!props.options)
127
- return []
128
-
129
- return props.options.map(normalizeItem)
130
- })
131
-
132
- function onUpdate(value: any) {
133
- // @ts-expect-error - 'target' does not exist in type 'EventInit'
134
- const event = new Event('change', { target: { value } })
135
- emit('change', event)
136
- }
137
- </script>
138
-
139
- <template>
140
- <RadioGroupRoot
141
- :id="id"
142
- v-slot="{ modelValue }"
143
- v-bind="rootProps"
144
- :name="props.name"
145
- :disabled="props.disabled"
146
- :class="style.root({ class: [props.class, props.ui?.root] })"
147
- @update:model-value="onUpdate"
148
- >
149
- <fieldset :class="style.fieldset({ class: props.ui?.fieldset })">
150
- <legend v-if="props.legend || slots.legend" :class="style.legend({ class: props.ui?.legend })">
151
- <slot name="legend">
152
- {{ props.legend }}
153
- </slot>
154
- </legend>
155
- <div v-for="item in normalizedItems" :key="item.value" :class="style.item({ class: props.ui?.item })">
156
- <div :class="style.container({ class: props.ui?.container })">
157
- <RadioGroupItem
158
- :id="item.id"
159
- :value="item.value"
160
- :disabled="item.disabled"
161
- :class="style.base({ class: props.ui?.base })"
162
- >
163
- <RadioGroupIndicator :class="style.indicator({ class: props.ui?.indicator })" />
164
- </RadioGroupItem>
165
- </div>
166
-
167
- <div :class="style.wrapper({ class: props.ui?.wrapper })">
168
- <Label :for="item.id" :class="style.label({ class: props.ui?.label })">
169
- <slot name="label" :item="item" :model-value="modelValue">{{ item.label }}</slot>
170
- </Label>
171
- <p v-if="item.description || slots.description" :class="style.description({ class: props.ui?.description })">
172
- <slot name="description" :item="item" :model-value="modelValue">
173
- {{ item.description }}
174
- </slot>
175
- </p>
176
- </div>
177
- </div>
178
- </fieldset>
179
- </RadioGroupRoot>
180
- </template>
1
+ <script lang="ts">
2
+ import type { VariantProps } from '@byyuurin/ui-kit'
3
+ import type { AcceptableValue, PrimitiveProps, RadioGroupRootProps } from 'reka-ui'
4
+ import type { radioGroup } from '../theme'
5
+ import type { ComponentAttrs } from '../types'
6
+
7
+ type RadioGroupVariants = VariantProps<typeof radioGroup>
8
+
9
+ export interface RadioOption {
10
+ label?: string
11
+ description?: string
12
+ disabled?: boolean
13
+ value?: string
14
+ }
15
+
16
+ export interface RadioGroupProps<T> extends ComponentAttrs<typeof radioGroup>, Pick<RadioGroupRootProps, 'defaultValue' | 'disabled' | 'loop' | 'modelValue' | 'name' | 'required'> {
17
+ as?: PrimitiveProps['as']
18
+ legend?: string
19
+ /**
20
+ * When `options` is an array of objects, select the field to use as the value.
21
+ * @default 'value'
22
+ */
23
+ valueKey?: string
24
+ /**
25
+ * When `options` is an array of objects, select the field to use as the label.
26
+ * @default 'label'
27
+ */
28
+ labelKey?: string
29
+ /**
30
+ * When `options` is an array of objects, select the field to use as the description.
31
+ * @default 'description'
32
+ */
33
+ descriptionKey?: string
34
+ options?: T[]
35
+ size?: RadioGroupVariants['size']
36
+ /**
37
+ * The orientation the radio buttons are laid out.
38
+ * @default 'vertical'
39
+ */
40
+ orientation?: RadioGroupRootProps['orientation']
41
+ }
42
+
43
+ export interface RadioGroupEmits {
44
+ (event: 'update:modelValue', payload: string): void
45
+ (event: 'change', payload: Event): void
46
+ }
47
+
48
+ type SlotProps<T> = (props: { item: NormalizeItem<T>, modelValue?: AcceptableValue }) => any
49
+
50
+ export interface RadioGroupSlots<T> {
51
+ legend?: (props?: {}) => any
52
+ label?: SlotProps<T>
53
+ description?: SlotProps<T>
54
+ }
55
+
56
+ type NormalizeItem<T> = { id: string } & (
57
+ T extends RadioOption
58
+ ? T
59
+ : {
60
+ id: string
61
+ label: string
62
+ value: any
63
+ description: string
64
+ disabled: false
65
+ }
66
+ )
67
+ </script>
68
+
69
+ <script lang="ts" setup generic="T extends RadioOption | AcceptableValue">
70
+ import { reactivePick } from '@vueuse/core'
71
+ import { Label, RadioGroupIndicator, RadioGroupItem, RadioGroupRoot, useForwardPropsEmits } from 'reka-ui'
72
+ import { computed, useId } from 'vue'
73
+ import { useTheme } from '../composables'
74
+ import { get } from '../utils'
75
+
76
+ const props = withDefaults(defineProps<RadioGroupProps<T>>(), {
77
+ size: 'md',
78
+ valueKey: 'value',
79
+ labelKey: 'label',
80
+ descriptionKey: 'description',
81
+ orientation: 'vertical',
82
+ })
83
+
84
+ const emit = defineEmits<RadioGroupEmits>()
85
+ const slots = defineSlots<RadioGroupSlots<T>>()
86
+
87
+ const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emit)
88
+ const id = useId()
89
+
90
+ const { theme, createStyler } = useTheme()
91
+ const style = computed(() => {
92
+ const styler = createStyler(theme.value.radioGroup)
93
+ return styler(props)
94
+ })
95
+
96
+ function normalizeItem(item: any): NormalizeItem<T> {
97
+ if (['string', 'number', 'boolean'].includes(typeof item)) {
98
+ return {
99
+ id: `${id}:${item}`,
100
+ value: item,
101
+ label: item,
102
+ description: '',
103
+ } as any
104
+ }
105
+
106
+ const value = get(item, props.valueKey)
107
+ const label = get(item, props.labelKey)
108
+ const description = get(item, props.descriptionKey)
109
+
110
+ return {
111
+ ...item,
112
+ value,
113
+ label,
114
+ description,
115
+ id: `${id}:${value}`,
116
+ }
117
+ }
118
+
119
+ const normalizedItems = computed(() => {
120
+ if (!props.options)
121
+ return []
122
+
123
+ return props.options.map(normalizeItem)
124
+ })
125
+
126
+ function onUpdate(value: any) {
127
+ // @ts-expect-error - 'target' does not exist in type 'EventInit'
128
+ const event = new Event('change', { target: { value } })
129
+ emit('change', event)
130
+ }
131
+ </script>
132
+
133
+ <template>
134
+ <RadioGroupRoot
135
+ :id="id"
136
+ v-slot="{ modelValue }"
137
+ v-bind="rootProps"
138
+ :name="props.name"
139
+ :disabled="props.disabled"
140
+ :class="style.root({ class: [props.class, props.ui?.root] })"
141
+ @update:model-value="onUpdate"
142
+ >
143
+ <fieldset :class="style.fieldset({ class: props.ui?.fieldset })">
144
+ <legend v-if="props.legend || slots.legend" :class="style.legend({ class: props.ui?.legend })">
145
+ <slot name="legend">
146
+ {{ props.legend }}
147
+ </slot>
148
+ </legend>
149
+ <div v-for="item in normalizedItems" :key="item.value" :class="style.item({ class: props.ui?.item })">
150
+ <div :class="style.container({ class: props.ui?.container })">
151
+ <RadioGroupItem
152
+ :id="item.id"
153
+ :value="item.value"
154
+ :disabled="item.disabled"
155
+ :class="style.base({ class: props.ui?.base })"
156
+ >
157
+ <RadioGroupIndicator :class="style.indicator({ class: props.ui?.indicator })" force-mount />
158
+ </RadioGroupItem>
159
+ </div>
160
+
161
+ <div :class="style.wrapper({ class: props.ui?.wrapper })">
162
+ <Label :for="item.id" :class="style.label({ class: props.ui?.label })">
163
+ <slot name="label" :item="item" :model-value="modelValue">{{ item.label }}</slot>
164
+ </Label>
165
+ <p v-if="item.description || slots.description" :class="style.description({ class: props.ui?.description })">
166
+ <slot name="description" :item="item" :model-value="modelValue">
167
+ {{ item.description }}
168
+ </slot>
169
+ </p>
170
+ </div>
171
+ </div>
172
+ </fieldset>
173
+ </RadioGroupRoot>
174
+ </template>