diff --git a/packages/library/src/components/index.ts b/packages/library/src/components/index.ts
index b4fe48d..d75a3c1 100644
--- a/packages/library/src/components/index.ts
+++ b/packages/library/src/components/index.ts
@@ -8,3 +8,4 @@ export { Switch } from './ui/switch'
export { Badge, badgeVariants } from './ui/badge'
export { Checkbox } from './ui/checkbox'
export { CheckboxGroup } from './ui/checkbox-group'
+export { RadioGroup, RadioGroupItem } from './ui/radio-group'
diff --git a/packages/library/src/components/ui/radio-group/RadioGroup.vue b/packages/library/src/components/ui/radio-group/RadioGroup.vue
new file mode 100644
index 0000000..7f35f19
--- /dev/null
+++ b/packages/library/src/components/ui/radio-group/RadioGroup.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/radio-group/RadioGroupItem.vue b/packages/library/src/components/ui/radio-group/RadioGroupItem.vue
new file mode 100644
index 0000000..18960ab
--- /dev/null
+++ b/packages/library/src/components/ui/radio-group/RadioGroupItem.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/radio-group/index.ts b/packages/library/src/components/ui/radio-group/index.ts
new file mode 100644
index 0000000..7cb0e3b
--- /dev/null
+++ b/packages/library/src/components/ui/radio-group/index.ts
@@ -0,0 +1,2 @@
+export { default as RadioGroup } from "./RadioGroup.vue"
+export { default as RadioGroupItem } from "./RadioGroupItem.vue"
diff --git a/packages/library/src/index.ts b/packages/library/src/index.ts
index 1f27b8f..0a51792 100644
--- a/packages/library/src/index.ts
+++ b/packages/library/src/index.ts
@@ -14,8 +14,8 @@ export {
Textarea,
Checkbox,
CheckboxGroup,
- RadioButton,
- RadioButtonGroup,
+ RadioGroup,
+ RadioGroupItem,
Switch,
Select,
Card,
diff --git a/packages/library/src/lib/index.ts b/packages/library/src/lib/index.ts
index 23498af..4efbb97 100644
--- a/packages/library/src/lib/index.ts
+++ b/packages/library/src/lib/index.ts
@@ -1,7 +1,5 @@
import type { App } from 'vue'
import {
- RadioButton as PrimeRadioButton,
- RadioButtonGroup as PrimeRadioButtonGroup,
Select as PrimeSelect,
Card as PrimeCard,
Dialog as PrimeDialog,
@@ -19,9 +17,23 @@ import {
badgeVariants,
Checkbox,
CheckboxGroup,
+ RadioGroup,
+ RadioGroupItem,
} from '../components'
-export { Button, buttonVariants, Input, Textarea, Switch, Badge, badgeVariants, Checkbox, CheckboxGroup }
+export {
+ Button,
+ buttonVariants,
+ Input,
+ Textarea,
+ Switch,
+ Badge,
+ badgeVariants,
+ Checkbox,
+ CheckboxGroup,
+ RadioGroup,
+ RadioGroupItem,
+}
/**
* Build a Themeable that themes a PrimeVue component through its passthrough (`pt`) API.
@@ -65,8 +77,6 @@ const loadingIconThemeable: Themeable = {
const nychthemeron: ThemeLibrary = {
components: {
LoadingIcon: loadingIconThemeable,
- RadioButton: ptThemeable(PrimeRadioButton, 'radio', ['box', 'input', 'icon']),
- RadioButtonGroup: ptThemeable(PrimeRadioButtonGroup, 'radio-group'),
Select: ptThemeable(PrimeSelect, 'select', [
'label',
'dropdown',
@@ -110,10 +120,6 @@ const nychthemeron: ThemeLibrary = {
const _engine = new ThemeEngine(nychthemeron)
export const LoadingIcon = _engine.getComponent('LoadingIcon')
-export const RadioButton: typeof PrimeRadioButton =
- _engine.getComponent('RadioButton')
-export const RadioButtonGroup: typeof PrimeRadioButtonGroup =
- _engine.getComponent('RadioButtonGroup')
export const Select: typeof PrimeSelect = _engine.getComponent('Select')
export const Card: typeof PrimeCard = _engine.getComponent('Card')
export const Dialog: typeof PrimeDialog = _engine.getComponent('Dialog')
@@ -126,8 +132,8 @@ export const createNychthemeron = (): {
Textarea: typeof Textarea
Checkbox: typeof Checkbox
CheckboxGroup: typeof CheckboxGroup
- RadioButton: typeof PrimeRadioButton
- RadioButtonGroup: typeof PrimeRadioButtonGroup
+ RadioGroup: typeof RadioGroup
+ RadioGroupItem: typeof RadioGroupItem
Switch: typeof Switch
Select: typeof PrimeSelect
Card: typeof PrimeCard
@@ -142,8 +148,8 @@ export const createNychthemeron = (): {
Textarea,
Checkbox,
CheckboxGroup,
- RadioButton,
- RadioButtonGroup,
+ RadioGroup,
+ RadioGroupItem,
Switch,
Select,
Card,
@@ -157,8 +163,8 @@ export const createNychthemeron = (): {
app.component('NychTextarea', Textarea)
app.component('NychCheckbox', Checkbox)
app.component('NychCheckboxGroup', CheckboxGroup)
- app.component('NychRadioButton', RadioButton)
- app.component('NychRadioButtonGroup', RadioButtonGroup)
+ app.component('NychRadioGroup', RadioGroup)
+ app.component('NychRadioGroupItem', RadioGroupItem)
app.component('NychSwitch', Switch)
app.component('NychSelect', Select)
app.component('NychCard', Card)
diff --git a/packages/library/tests/RadioGroup.spec.ts b/packages/library/tests/RadioGroup.spec.ts
new file mode 100644
index 0000000..7a06724
--- /dev/null
+++ b/packages/library/tests/RadioGroup.spec.ts
@@ -0,0 +1,32 @@
+import { describe, it, expect } from 'vitest'
+import { h } from 'vue'
+import { mount } from '@vue/test-utils'
+import { RadioGroup, RadioGroupItem } from '../src/lib'
+
+describe('RadioGroup', () => {
+ it('marks the item matching modelValue as checked', () => {
+ const wrapper = mount(RadioGroup, {
+ props: { modelValue: 'hades' },
+ slots: {
+ default: () => [
+ h(RadioGroupItem, { value: 'apollo' }),
+ h(RadioGroupItem, { value: 'hades' }),
+ ],
+ },
+ })
+ const items = wrapper.findAllComponents(RadioGroupItem)
+ expect(items[0]?.get('button').attributes('data-state')).toBe('unchecked')
+ expect(items[1]?.get('button').attributes('data-state')).toBe('checked')
+ })
+
+ it('emits update:modelValue when an item is selected', async () => {
+ const wrapper = mount(RadioGroup, {
+ props: { modelValue: 'apollo' },
+ slots: {
+ default: () => [h(RadioGroupItem, { value: 'hades' })],
+ },
+ })
+ await wrapper.findComponent(RadioGroupItem).get('button').trigger('click')
+ expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['hades'])
+ })
+})
diff --git a/packages/library/tests/lib.spec.ts b/packages/library/tests/lib.spec.ts
index 62e3929..4a523c5 100644
--- a/packages/library/tests/lib.spec.ts
+++ b/packages/library/tests/lib.spec.ts
@@ -3,8 +3,6 @@ import type { App } from 'vue'
import {
createNychthemeron,
LoadingIcon,
- RadioButton,
- RadioButtonGroup,
Select,
Card,
Dialog,
@@ -65,8 +63,6 @@ describe('LoadingIcon', () => {
describe('themed pt components', () => {
const cases = [
- { name: 'RadioButton', component: RadioButton, base: 'nych-radio' },
- { name: 'RadioButtonGroup', component: RadioButtonGroup, base: 'nych-radio-group' },
{ name: 'Select', component: Select, base: 'nych-select' },
{ name: 'Card', component: Card, base: 'nych-card' },
{ name: 'Dialog', component: Dialog, base: 'nych-dialog' },
diff --git a/packages/playground/stories/RadioButton.stories.ts b/packages/playground/stories/RadioButton.stories.ts
deleted file mode 100644
index 3e73ad4..0000000
--- a/packages/playground/stories/RadioButton.stories.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import type { Meta, StoryObj } from '@storybook/vue3-vite'
-import { ref } from 'vue'
-
-import {
- RadioButton as NychRadioButton,
- RadioButtonGroup as NychRadioButtonGroup,
-} from '@nychthemeron/library'
-
-const meta = {
- title: 'Components/RadioButton',
- component: NychRadioButton,
- parameters: {
- layout: 'centered',
- },
- tags: ['autodocs'],
- argTypes: {
- disabled: {
- control: { type: 'boolean' },
- description: 'Disable the radio button',
- },
- },
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Default: Story = {
- render: () => ({
- components: { NychRadioButton },
- setup() {
- const realm = ref('underworld')
- return { realm }
- },
- template: `
-
-
-
-
- `,
- }),
-}
-
-export const Disabled: Story = {
- render: () => ({
- components: { NychRadioButton },
- setup() {
- const realm = ref('sky')
- return { realm }
- },
- template: `
-
-
-
-
- `,
- }),
-}
-
-export const WithLabels: Story = {
- render: () => ({
- components: { NychRadioButton },
- setup() {
- const god = ref('apollo')
- return { god }
- },
- template: `
-
-
- Apollo
-
-
- Hades
-
-
- Hermes
-
-
Chosen: {{ god }}
-
- `,
- }),
-}
-
-// RadioButtonGroup binds the v-model once on the group and shares a name across
-// children — the children only carry a `value`.
-export const Group: Story = {
- render: () => ({
- components: { NychRadioButton, NychRadioButtonGroup },
- setup() {
- const god = ref('apollo')
- return { god }
- },
- template: `
-
-
-
- Apollo
-
-
- Hades
-
-
- Hermes
-
-
-
Chosen: {{ god }}
-
- `,
- }),
-}
diff --git a/packages/playground/stories/RadioGroup.stories.ts b/packages/playground/stories/RadioGroup.stories.ts
new file mode 100644
index 0000000..c425d82
--- /dev/null
+++ b/packages/playground/stories/RadioGroup.stories.ts
@@ -0,0 +1,70 @@
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+import { ref } from 'vue'
+
+import { RadioGroup as NychRadioGroup, RadioGroupItem as NychRadioGroupItem } from '@nychthemeron/library'
+
+const meta = {
+ title: 'Components/RadioGroup',
+ component: NychRadioGroup,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {
+ render: () => ({
+ components: { NychRadioGroup, NychRadioGroupItem },
+ setup() {
+ const realm = ref('underworld')
+ return { realm }
+ },
+ template: `
+
+
+
+
+ `,
+ }),
+}
+
+export const Disabled: Story = {
+ render: () => ({
+ components: { NychRadioGroup, NychRadioGroupItem },
+ template: `
+
+
+
+
+ `,
+ }),
+}
+
+export const WithLabels: Story = {
+ render: () => ({
+ components: { NychRadioGroup, NychRadioGroupItem },
+ setup() {
+ const god = ref('apollo')
+ return { god }
+ },
+ template: `
+
+
+
+ Apollo
+
+
+ Hades
+
+
+ Hermes
+
+
+
Chosen: {{ god }}
+
+ `,
+ }),
+}