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: `
-
-
-
-
-
- `,
- }),
-}