diff --git a/bun.lock b/bun.lock index 62e2a07..57f6333 100644 --- a/bun.lock +++ b/bun.lock @@ -39,6 +39,7 @@ "dependencies": { "@lucide/vue": "^1.24.0", "@tailwindcss/vite": "^4.3.2", + "@vueuse/core": "^14.3.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "reka-ui": "^2.10.1", diff --git a/packages/library/package.json b/packages/library/package.json index aff95e4..1f3309a 100644 --- a/packages/library/package.json +++ b/packages/library/package.json @@ -42,6 +42,7 @@ "dependencies": { "@lucide/vue": "^1.24.0", "@tailwindcss/vite": "^4.3.2", + "@vueuse/core": "^14.3.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "reka-ui": "^2.10.1", diff --git a/packages/library/src/components/index.ts b/packages/library/src/components/index.ts index d380276..772dd91 100644 --- a/packages/library/src/components/index.ts +++ b/packages/library/src/components/index.ts @@ -2,3 +2,4 @@ export { default as NychLoadingIcon } from './NychLoadingIcon.vue' export { Button, buttonVariants } from './ui/button' export type { ButtonVariants } from './ui/button' +export { Input } from './ui/input' diff --git a/packages/library/src/components/ui/input/Input.vue b/packages/library/src/components/ui/input/Input.vue new file mode 100644 index 0000000..215999f --- /dev/null +++ b/packages/library/src/components/ui/input/Input.vue @@ -0,0 +1,31 @@ + + + diff --git a/packages/library/src/components/ui/input/index.ts b/packages/library/src/components/ui/input/index.ts new file mode 100644 index 0000000..9976b86 --- /dev/null +++ b/packages/library/src/components/ui/input/index.ts @@ -0,0 +1 @@ +export { default as Input } from "./Input.vue" diff --git a/packages/library/src/index.ts b/packages/library/src/index.ts index 37802dd..da2523b 100644 --- a/packages/library/src/index.ts +++ b/packages/library/src/index.ts @@ -10,7 +10,7 @@ export { createNychthemeron, Button, LoadingIcon, - InputText, + Input, Textarea, Checkbox, CheckboxGroup, diff --git a/packages/library/src/lib/index.ts b/packages/library/src/lib/index.ts index 58cb645..bc2f952 100644 --- a/packages/library/src/lib/index.ts +++ b/packages/library/src/lib/index.ts @@ -1,6 +1,5 @@ import type { App } from 'vue' import { - InputText as PrimeInputText, Textarea as PrimeTextarea, Checkbox as PrimeCheckbox, CheckboxGroup as PrimeCheckboxGroup, @@ -14,9 +13,9 @@ import { Tag as PrimeTag, } from 'primevue' import { ThemeLibrary, type Themeable, ThemeEngine, type LibComponent, type Key } from '../engine' -import { NychLoadingIcon, Button, buttonVariants } from '../components' +import { NychLoadingIcon, Button, buttonVariants, Input } from '../components' -export { Button, buttonVariants } +export { Button, buttonVariants, Input } /** * Build a Themeable that themes a PrimeVue component through its passthrough (`pt`) API. @@ -60,7 +59,6 @@ const loadingIconThemeable: Themeable = { const nychthemeron: ThemeLibrary = { components: { LoadingIcon: loadingIconThemeable, - InputText: ptThemeable(PrimeInputText, 'input'), Textarea: ptThemeable(PrimeTextarea, 'textarea'), Checkbox: ptThemeable(PrimeCheckbox, 'checkbox', ['box', 'input', 'icon']), CheckboxGroup: ptThemeable(PrimeCheckboxGroup, 'checkbox-group'), @@ -111,8 +109,6 @@ const nychthemeron: ThemeLibrary = { const _engine = new ThemeEngine(nychthemeron) export const LoadingIcon = _engine.getComponent('LoadingIcon') -export const InputText: typeof PrimeInputText = - _engine.getComponent('InputText') export const Textarea: typeof PrimeTextarea = _engine.getComponent('Textarea') export const Checkbox: typeof PrimeCheckbox = _engine.getComponent('Checkbox') export const CheckboxGroup: typeof PrimeCheckboxGroup = @@ -132,7 +128,7 @@ export const Tag: typeof PrimeTag = _engine.getComponent('Tag') export const createNychthemeron = (): { Button: typeof Button LoadingIcon: typeof NychLoadingIcon - InputText: typeof PrimeInputText + Input: typeof Input Textarea: typeof PrimeTextarea Checkbox: typeof PrimeCheckbox CheckboxGroup: typeof PrimeCheckboxGroup @@ -148,7 +144,7 @@ export const createNychthemeron = (): { } => ({ Button, LoadingIcon, - InputText, + Input, Textarea, Checkbox, CheckboxGroup, @@ -163,7 +159,7 @@ export const createNychthemeron = (): { install(app: App) { app.component('NychButton', Button) app.component('NychLoadingIcon', LoadingIcon) - app.component('NychInputText', InputText) + app.component('NychInput', Input) app.component('NychTextarea', Textarea) app.component('NychCheckbox', Checkbox) app.component('NychCheckboxGroup', CheckboxGroup) diff --git a/packages/library/tests/Input.spec.ts b/packages/library/tests/Input.spec.ts new file mode 100644 index 0000000..c65ae39 --- /dev/null +++ b/packages/library/tests/Input.spec.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { Input } from '../src/lib' + +describe('Input', () => { + it('renders a native input element', () => { + const wrapper = mount(Input) + expect(wrapper.element.tagName).toBe('INPUT') + }) + + it('supports v-model', async () => { + const wrapper = mount(Input, { props: { modelValue: 'Styx' } }) + expect((wrapper.element as HTMLInputElement).value).toBe('Styx') + + await wrapper.setValue('Lethe') + expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['Lethe']) + }) + + it('applies the disabled attribute', () => { + const wrapper = mount(Input, { attrs: { disabled: true } }) + expect(wrapper.attributes('disabled')).toBeDefined() + }) +}) diff --git a/packages/library/tests/lib.spec.ts b/packages/library/tests/lib.spec.ts index 10dd589..b361777 100644 --- a/packages/library/tests/lib.spec.ts +++ b/packages/library/tests/lib.spec.ts @@ -3,7 +3,6 @@ import type { App } from 'vue' import { createNychthemeron, LoadingIcon, - InputText, Textarea, Checkbox, RadioButton, @@ -71,7 +70,6 @@ describe('LoadingIcon', () => { describe('themed pt components', () => { const cases = [ - { name: 'InputText', component: InputText, base: 'nych-input' }, { name: 'Textarea', component: Textarea, base: 'nych-textarea' }, { name: 'Checkbox', component: Checkbox, base: 'nych-checkbox' }, { name: 'CheckboxGroup', component: CheckboxGroup, base: 'nych-checkbox-group' }, diff --git a/packages/playground/stories/Input.stories.ts b/packages/playground/stories/Input.stories.ts new file mode 100644 index 0000000..154b78b --- /dev/null +++ b/packages/playground/stories/Input.stories.ts @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { ref } from 'vue' + +import { Input as NychInput } from '@nychthemeron/library' + +const meta = { + title: 'Components/Input', + component: NychInput, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = { + render: () => ({ + components: { NychInput }, + setup() { + const value = ref('') + return { value } + }, + template: ``, + }), +} + +export const Filled: Story = { + render: () => ({ + components: { NychInput }, + setup() { + const value = ref('Charon') + return { value } + }, + template: ``, + }), +} + +export const Disabled: Story = { + render: () => ({ + components: { NychInput }, + setup() { + const value = ref('Sealed') + return { value } + }, + template: ``, + }), +} diff --git a/packages/playground/stories/InputText.stories.ts b/packages/playground/stories/InputText.stories.ts deleted file mode 100644 index 139d007..0000000 --- a/packages/playground/stories/InputText.stories.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/vue3-vite' -import { ref } from 'vue' - -import { InputText as NychInputText } from '@nychthemeron/library' - -const meta = { - title: 'Components/InputText', - component: NychInputText, - parameters: { - layout: 'centered', - }, - tags: ['autodocs'], - argTypes: { - size: { - control: { type: 'select' }, - options: ['small', undefined, 'large'], - description: 'Input size', - }, - placeholder: { - control: { type: 'text' }, - description: 'Placeholder text', - }, - disabled: { - control: { type: 'boolean' }, - description: 'Disable the input', - }, - invalid: { - control: { type: 'boolean' }, - description: 'Mark the input as invalid', - }, - }, -} satisfies Meta - -export default meta -type Story = StoryObj - -const modelTemplate = (attrs: string) => ({ - components: { NychInputText }, - setup() { - const value = ref('') - return { value } - }, - template: ``, -}) - -export const Default: Story = { - render: () => modelTemplate('placeholder="Speak, traveller…"'), -} - -export const Filled: Story = { - render: () => ({ - components: { NychInputText }, - setup() { - const value = ref('Charon') - return { value } - }, - template: ``, - }), -} - -export const Invalid: Story = { - render: () => modelTemplate('placeholder="Required" invalid'), -} - -export const Disabled: Story = { - render: () => ({ - components: { NychInputText }, - setup() { - const value = ref('Sealed') - return { value } - }, - template: ``, - }), -} - -export const Sizes: Story = { - render: () => ({ - components: { NychInputText }, - setup() { - const a = ref('') - const b = ref('') - const c = ref('') - return { a, b, c } - }, - template: ` -
- - - -
- `, - }), -}