diff --git a/packages/library/src/components/index.ts b/packages/library/src/components/index.ts index a759617..b4fe48d 100644 --- a/packages/library/src/components/index.ts +++ b/packages/library/src/components/index.ts @@ -6,3 +6,5 @@ export { Input } from './ui/input' export { Textarea } from './ui/textarea' export { Switch } from './ui/switch' export { Badge, badgeVariants } from './ui/badge' +export { Checkbox } from './ui/checkbox' +export { CheckboxGroup } from './ui/checkbox-group' diff --git a/packages/library/src/components/ui/checkbox-group/CheckboxGroup.vue b/packages/library/src/components/ui/checkbox-group/CheckboxGroup.vue new file mode 100644 index 0000000..e67fac3 --- /dev/null +++ b/packages/library/src/components/ui/checkbox-group/CheckboxGroup.vue @@ -0,0 +1,18 @@ + + + diff --git a/packages/library/src/components/ui/checkbox-group/index.ts b/packages/library/src/components/ui/checkbox-group/index.ts new file mode 100644 index 0000000..0e33627 --- /dev/null +++ b/packages/library/src/components/ui/checkbox-group/index.ts @@ -0,0 +1,2 @@ +export { default as CheckboxGroup } from './CheckboxGroup.vue' +export const CHECKBOX_GROUP_NAME_KEY = 'nych-checkbox-group-name' diff --git a/packages/library/src/components/ui/checkbox/Checkbox.vue b/packages/library/src/components/ui/checkbox/Checkbox.vue new file mode 100644 index 0000000..f370cb2 --- /dev/null +++ b/packages/library/src/components/ui/checkbox/Checkbox.vue @@ -0,0 +1,34 @@ + + + diff --git a/packages/library/src/components/ui/checkbox/index.ts b/packages/library/src/components/ui/checkbox/index.ts new file mode 100644 index 0000000..3391a85 --- /dev/null +++ b/packages/library/src/components/ui/checkbox/index.ts @@ -0,0 +1 @@ +export { default as Checkbox } from "./Checkbox.vue" diff --git a/packages/library/src/lib/index.ts b/packages/library/src/lib/index.ts index 7245831..23498af 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 { - Checkbox as PrimeCheckbox, - CheckboxGroup as PrimeCheckboxGroup, RadioButton as PrimeRadioButton, RadioButtonGroup as PrimeRadioButtonGroup, Select as PrimeSelect, @@ -19,9 +17,11 @@ import { Switch, Badge, badgeVariants, + Checkbox, + CheckboxGroup, } from '../components' -export { Button, buttonVariants, Input, Textarea, Switch, Badge, badgeVariants } +export { Button, buttonVariants, Input, Textarea, Switch, Badge, badgeVariants, Checkbox, CheckboxGroup } /** * Build a Themeable that themes a PrimeVue component through its passthrough (`pt`) API. @@ -65,8 +65,6 @@ const loadingIconThemeable: Themeable = { const nychthemeron: ThemeLibrary = { components: { LoadingIcon: loadingIconThemeable, - Checkbox: ptThemeable(PrimeCheckbox, 'checkbox', ['box', 'input', 'icon']), - CheckboxGroup: ptThemeable(PrimeCheckboxGroup, 'checkbox-group'), RadioButton: ptThemeable(PrimeRadioButton, 'radio', ['box', 'input', 'icon']), RadioButtonGroup: ptThemeable(PrimeRadioButtonGroup, 'radio-group'), Select: ptThemeable(PrimeSelect, 'select', [ @@ -112,9 +110,6 @@ const nychthemeron: ThemeLibrary = { const _engine = new ThemeEngine(nychthemeron) export const LoadingIcon = _engine.getComponent('LoadingIcon') -export const Checkbox: typeof PrimeCheckbox = _engine.getComponent('Checkbox') -export const CheckboxGroup: typeof PrimeCheckboxGroup = - _engine.getComponent('CheckboxGroup') export const RadioButton: typeof PrimeRadioButton = _engine.getComponent('RadioButton') export const RadioButtonGroup: typeof PrimeRadioButtonGroup = @@ -129,8 +124,8 @@ export const createNychthemeron = (): { LoadingIcon: typeof NychLoadingIcon Input: typeof Input Textarea: typeof Textarea - Checkbox: typeof PrimeCheckbox - CheckboxGroup: typeof PrimeCheckboxGroup + Checkbox: typeof Checkbox + CheckboxGroup: typeof CheckboxGroup RadioButton: typeof PrimeRadioButton RadioButtonGroup: typeof PrimeRadioButtonGroup Switch: typeof Switch diff --git a/packages/library/tests/Checkbox.spec.ts b/packages/library/tests/Checkbox.spec.ts new file mode 100644 index 0000000..c89b22c --- /dev/null +++ b/packages/library/tests/Checkbox.spec.ts @@ -0,0 +1,21 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { Checkbox } from '../src/lib' + +describe('Checkbox', () => { + it('renders unchecked by default', () => { + const wrapper = mount(Checkbox) + expect(wrapper.get('button').attributes('data-state')).toBe('unchecked') + }) + + it('reflects modelValue as checked', () => { + const wrapper = mount(Checkbox, { props: { modelValue: true } }) + expect(wrapper.get('button').attributes('data-state')).toBe('checked') + }) + + it('emits update:modelValue on click', async () => { + const wrapper = mount(Checkbox, { props: { modelValue: false } }) + await wrapper.get('button').trigger('click') + expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true]) + }) +}) diff --git a/packages/library/tests/CheckboxGroup.spec.ts b/packages/library/tests/CheckboxGroup.spec.ts new file mode 100644 index 0000000..61098bc --- /dev/null +++ b/packages/library/tests/CheckboxGroup.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { CheckboxGroup } from '../src/lib' + +describe('CheckboxGroup', () => { + it('renders as a group container', () => { + const wrapper = mount(CheckboxGroup, { slots: { default: 'child' } }) + expect(wrapper.attributes('role')).toBe('group') + expect(wrapper.html()).toContain('child') + }) +}) diff --git a/packages/library/tests/lib.spec.ts b/packages/library/tests/lib.spec.ts index 0f62279..62e3929 100644 --- a/packages/library/tests/lib.spec.ts +++ b/packages/library/tests/lib.spec.ts @@ -3,9 +3,7 @@ import type { App } from 'vue' import { createNychthemeron, LoadingIcon, - Checkbox, RadioButton, - CheckboxGroup, RadioButtonGroup, Select, Card, @@ -67,8 +65,6 @@ describe('LoadingIcon', () => { describe('themed pt components', () => { const cases = [ - { name: 'Checkbox', component: Checkbox, base: 'nych-checkbox' }, - { name: 'CheckboxGroup', component: CheckboxGroup, base: 'nych-checkbox-group' }, { name: 'RadioButton', component: RadioButton, base: 'nych-radio' }, { name: 'RadioButtonGroup', component: RadioButtonGroup, base: 'nych-radio-group' }, { name: 'Select', component: Select, base: 'nych-select' }, @@ -94,13 +90,6 @@ describe('themed pt components', () => { expect(result).not.toHaveProperty('stylePlug') }) - it('Checkbox themes its box, input and icon sections', () => { - const result = callSetup(Checkbox, { pt: {} }) - expect(result.pt?.box?.class).toContain('nych-checkbox-box') - expect(result.pt?.input?.class).toContain('nych-checkbox-input') - expect(result.pt?.icon?.class).toContain('nych-checkbox-icon') - }) - it('Select themes its overlay and option sections', () => { const result = callSetup(Select, { pt: {} }) expect(result.pt?.overlay?.class).toContain('nych-select-overlay') diff --git a/packages/playground/stories/Checkbox.stories.ts b/packages/playground/stories/Checkbox.stories.ts index 6c9c57c..ac54c47 100644 --- a/packages/playground/stories/Checkbox.stories.ts +++ b/packages/playground/stories/Checkbox.stories.ts @@ -10,12 +10,6 @@ const meta = { layout: 'centered', }, tags: ['autodocs'], - argTypes: { - disabled: { - control: { type: 'boolean' }, - description: 'Disable the checkbox', - }, - }, } satisfies Meta export default meta @@ -28,7 +22,7 @@ export const Default: Story = { const checked = ref(false) return { checked } }, - template: ``, + template: ``, }), } @@ -39,21 +33,17 @@ export const Checked: Story = { const checked = ref(true) return { checked } }, - template: ``, + template: ``, }), } export const Disabled: Story = { render: () => ({ components: { NychCheckbox }, - setup() { - const checked = ref(true) - return { checked } - }, template: `
- - + +
`, }), @@ -63,48 +53,50 @@ export const WithLabels: Story = { render: () => ({ components: { NychCheckbox }, setup() { - const offerings = ref(['honey']) - return { offerings } + const honey = ref(true) + const wine = ref(false) + const laurel = ref(false) + return { honey, wine, laurel } }, template: `
-

Offerings: {{ offerings.join(', ') || 'none' }}

`, }), } -// CheckboxGroup holds the array v-model and shares a name across children. +// CheckboxGroup shares layout and a name across children; each checkbox still owns its own v-model. export const Group: Story = { render: () => ({ components: { NychCheckbox, NychCheckboxGroup }, setup() { - const offerings = ref(['honey']) - return { offerings } + const honey = ref(true) + const wine = ref(false) + const laurel = ref(false) + return { honey, wine, laurel } }, template: `
- + -

Offerings: {{ offerings.join(', ') || 'none' }}

`, }),