From 7a4ae9ff6a2559c6cd9d4ac0f179138da4ea8428 Mon Sep 17 00:00:00 2001 From: Matthew L McPeak Date: Sat, 11 Jul 2026 14:28:51 -0400 Subject: [PATCH] feat: migrate ToggleSwitch to shadcn-vue Switch Co-Authored-By: Claude Sonnet 5 --- packages/library/src/components/index.ts | 1 + .../src/components/ui/switch/Switch.vue | 44 +++++++++++++++++++ .../library/src/components/ui/switch/index.ts | 1 + packages/library/src/index.ts | 2 +- packages/library/src/lib/index.ts | 14 +++--- packages/library/tests/Switch.spec.ts | 21 +++++++++ packages/library/tests/lib.spec.ts | 2 - ...gleSwitch.stories.ts => Switch.stories.ts} | 29 ++++++------ 8 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 packages/library/src/components/ui/switch/Switch.vue create mode 100644 packages/library/src/components/ui/switch/index.ts create mode 100644 packages/library/tests/Switch.spec.ts rename packages/playground/stories/{ToggleSwitch.stories.ts => Switch.stories.ts} (63%) diff --git a/packages/library/src/components/index.ts b/packages/library/src/components/index.ts index c449625..8f3f37d 100644 --- a/packages/library/src/components/index.ts +++ b/packages/library/src/components/index.ts @@ -4,3 +4,4 @@ export { Button, buttonVariants } from './ui/button' export type { ButtonVariants } from './ui/button' export { Input } from './ui/input' export { Textarea } from './ui/textarea' +export { Switch } from './ui/switch' diff --git a/packages/library/src/components/ui/switch/Switch.vue b/packages/library/src/components/ui/switch/Switch.vue new file mode 100644 index 0000000..f56f98b --- /dev/null +++ b/packages/library/src/components/ui/switch/Switch.vue @@ -0,0 +1,44 @@ + + + diff --git a/packages/library/src/components/ui/switch/index.ts b/packages/library/src/components/ui/switch/index.ts new file mode 100644 index 0000000..cc081f3 --- /dev/null +++ b/packages/library/src/components/ui/switch/index.ts @@ -0,0 +1 @@ +export { default as Switch } from "./Switch.vue" diff --git a/packages/library/src/index.ts b/packages/library/src/index.ts index da2523b..57fc4a8 100644 --- a/packages/library/src/index.ts +++ b/packages/library/src/index.ts @@ -16,7 +16,7 @@ export { CheckboxGroup, RadioButton, RadioButtonGroup, - ToggleSwitch, + Switch, Select, Card, Dialog, diff --git a/packages/library/src/lib/index.ts b/packages/library/src/lib/index.ts index f533da4..83479a6 100644 --- a/packages/library/src/lib/index.ts +++ b/packages/library/src/lib/index.ts @@ -4,7 +4,6 @@ import { CheckboxGroup as PrimeCheckboxGroup, RadioButton as PrimeRadioButton, RadioButtonGroup as PrimeRadioButtonGroup, - ToggleSwitch as PrimeToggleSwitch, Select as PrimeSelect, Card as PrimeCard, Dialog as PrimeDialog, @@ -12,9 +11,9 @@ import { Tag as PrimeTag, } from 'primevue' import { ThemeLibrary, type Themeable, ThemeEngine, type LibComponent, type Key } from '../engine' -import { NychLoadingIcon, Button, buttonVariants, Input, Textarea } from '../components' +import { NychLoadingIcon, Button, buttonVariants, Input, Textarea, Switch } from '../components' -export { Button, buttonVariants, Input, Textarea } +export { Button, buttonVariants, Input, Textarea, Switch } /** * Build a Themeable that themes a PrimeVue component through its passthrough (`pt`) API. @@ -62,7 +61,6 @@ const nychthemeron: ThemeLibrary = { CheckboxGroup: ptThemeable(PrimeCheckboxGroup, 'checkbox-group'), RadioButton: ptThemeable(PrimeRadioButton, 'radio', ['box', 'input', 'icon']), RadioButtonGroup: ptThemeable(PrimeRadioButtonGroup, 'radio-group'), - ToggleSwitch: ptThemeable(PrimeToggleSwitch, 'toggleswitch', ['input', 'slider', 'handle']), Select: ptThemeable(PrimeSelect, 'select', [ 'label', 'dropdown', @@ -114,8 +112,6 @@ export const RadioButton: typeof PrimeRadioButton = _engine.getComponent('RadioButton') export const RadioButtonGroup: typeof PrimeRadioButtonGroup = _engine.getComponent('RadioButtonGroup') -export const ToggleSwitch: typeof PrimeToggleSwitch = - _engine.getComponent('ToggleSwitch') export const Select: typeof PrimeSelect = _engine.getComponent('Select') export const Card: typeof PrimeCard = _engine.getComponent('Card') export const Dialog: typeof PrimeDialog = _engine.getComponent('Dialog') @@ -131,7 +127,7 @@ export const createNychthemeron = (): { CheckboxGroup: typeof PrimeCheckboxGroup RadioButton: typeof PrimeRadioButton RadioButtonGroup: typeof PrimeRadioButtonGroup - ToggleSwitch: typeof PrimeToggleSwitch + Switch: typeof Switch Select: typeof PrimeSelect Card: typeof PrimeCard Dialog: typeof PrimeDialog @@ -147,7 +143,7 @@ export const createNychthemeron = (): { CheckboxGroup, RadioButton, RadioButtonGroup, - ToggleSwitch, + Switch, Select, Card, Dialog, @@ -162,7 +158,7 @@ export const createNychthemeron = (): { app.component('NychCheckboxGroup', CheckboxGroup) app.component('NychRadioButton', RadioButton) app.component('NychRadioButtonGroup', RadioButtonGroup) - app.component('NychToggleSwitch', ToggleSwitch) + app.component('NychSwitch', Switch) app.component('NychSelect', Select) app.component('NychCard', Card) app.component('NychDialog', Dialog) diff --git a/packages/library/tests/Switch.spec.ts b/packages/library/tests/Switch.spec.ts new file mode 100644 index 0000000..21e41ab --- /dev/null +++ b/packages/library/tests/Switch.spec.ts @@ -0,0 +1,21 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { Switch } from '../src/lib' + +describe('Switch', () => { + it('renders unchecked by default', () => { + const wrapper = mount(Switch) + expect(wrapper.get('button').attributes('data-state')).toBe('unchecked') + }) + + it('reflects modelValue as checked', () => { + const wrapper = mount(Switch, { props: { modelValue: true } }) + expect(wrapper.get('button').attributes('data-state')).toBe('checked') + }) + + it('emits update:modelValue on click', async () => { + const wrapper = mount(Switch, { props: { modelValue: false } }) + await wrapper.get('button').trigger('click') + expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true]) + }) +}) diff --git a/packages/library/tests/lib.spec.ts b/packages/library/tests/lib.spec.ts index 5e600e2..c2ae6b2 100644 --- a/packages/library/tests/lib.spec.ts +++ b/packages/library/tests/lib.spec.ts @@ -7,7 +7,6 @@ import { RadioButton, CheckboxGroup, RadioButtonGroup, - ToggleSwitch, Select, Card, Dialog, @@ -73,7 +72,6 @@ describe('themed pt components', () => { { name: 'CheckboxGroup', component: CheckboxGroup, base: 'nych-checkbox-group' }, { name: 'RadioButton', component: RadioButton, base: 'nych-radio' }, { name: 'RadioButtonGroup', component: RadioButtonGroup, base: 'nych-radio-group' }, - { name: 'ToggleSwitch', component: ToggleSwitch, base: 'nych-toggleswitch' }, { 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/ToggleSwitch.stories.ts b/packages/playground/stories/Switch.stories.ts similarity index 63% rename from packages/playground/stories/ToggleSwitch.stories.ts rename to packages/playground/stories/Switch.stories.ts index 8374d17..b13d071 100644 --- a/packages/playground/stories/ToggleSwitch.stories.ts +++ b/packages/playground/stories/Switch.stories.ts @@ -1,11 +1,11 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite' import { ref } from 'vue' -import { ToggleSwitch as NychToggleSwitch } from '@nychthemeron/library' +import { Switch as NychSwitch } from '@nychthemeron/library' const meta = { - title: 'Components/ToggleSwitch', - component: NychToggleSwitch, + title: 'Components/Switch', + component: NychSwitch, parameters: { layout: 'centered', }, @@ -16,43 +16,40 @@ const meta = { description: 'Disable the switch', }, }, -} satisfies Meta +} satisfies Meta export default meta type Story = StoryObj export const Default: Story = { render: () => ({ - components: { NychToggleSwitch }, + components: { NychSwitch }, setup() { const on = ref(false) return { on } }, - template: ``, + template: ``, }), } export const On: Story = { render: () => ({ - components: { NychToggleSwitch }, + components: { NychSwitch }, setup() { const on = ref(true) return { on } }, - template: ``, + template: ``, }), } export const Disabled: Story = { render: () => ({ - components: { NychToggleSwitch }, - setup() { - return {} - }, + components: { NychSwitch }, template: `
- - + +
`, }), @@ -60,14 +57,14 @@ export const Disabled: Story = { export const WithLabel: Story = { render: () => ({ - components: { NychToggleSwitch }, + components: { NychSwitch }, setup() { const nocturnal = ref(true) return { nocturnal } }, template: ` `,