diff --git a/packages/library/src/components/index.ts b/packages/library/src/components/index.ts
index ee48c97..6fac0a2 100644
--- a/packages/library/src/components/index.ts
+++ b/packages/library/src/components/index.ts
@@ -11,3 +11,13 @@ export { CheckboxGroup } from './ui/checkbox-group'
export { RadioGroup, RadioGroupItem } from './ui/radio-group'
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, CardAction } from './ui/card'
export { Alert, AlertTitle, AlertDescription, AlertAction, alertVariants } from './ui/alert'
+export {
+ Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+ SelectGroup,
+ SelectLabel,
+ SelectSeparator,
+} from './ui/select'
diff --git a/packages/library/src/components/ui/select/Select.vue b/packages/library/src/components/ui/select/Select.vue
new file mode 100644
index 0000000..c94bbe8
--- /dev/null
+++ b/packages/library/src/components/ui/select/Select.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectContent.vue b/packages/library/src/components/ui/select/SelectContent.vue
new file mode 100644
index 0000000..0b0a09c
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectContent.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectGroup.vue b/packages/library/src/components/ui/select/SelectGroup.vue
new file mode 100644
index 0000000..1662d6c
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectGroup.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectItem.vue b/packages/library/src/components/ui/select/SelectItem.vue
new file mode 100644
index 0000000..c1b1107
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectItem.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectItemText.vue b/packages/library/src/components/ui/select/SelectItemText.vue
new file mode 100644
index 0000000..b6700b1
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectItemText.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectLabel.vue b/packages/library/src/components/ui/select/SelectLabel.vue
new file mode 100644
index 0000000..a3dd751
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectLabel.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectScrollDownButton.vue b/packages/library/src/components/ui/select/SelectScrollDownButton.vue
new file mode 100644
index 0000000..fa40f25
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectScrollDownButton.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectScrollUpButton.vue b/packages/library/src/components/ui/select/SelectScrollUpButton.vue
new file mode 100644
index 0000000..235b8df
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectScrollUpButton.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectSeparator.vue b/packages/library/src/components/ui/select/SelectSeparator.vue
new file mode 100644
index 0000000..3279645
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectSeparator.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectTrigger.vue b/packages/library/src/components/ui/select/SelectTrigger.vue
new file mode 100644
index 0000000..3a87db5
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectTrigger.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/SelectValue.vue b/packages/library/src/components/ui/select/SelectValue.vue
new file mode 100644
index 0000000..d5ce58b
--- /dev/null
+++ b/packages/library/src/components/ui/select/SelectValue.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/packages/library/src/components/ui/select/index.ts b/packages/library/src/components/ui/select/index.ts
new file mode 100644
index 0000000..96eae60
--- /dev/null
+++ b/packages/library/src/components/ui/select/index.ts
@@ -0,0 +1,11 @@
+export { default as Select } from "./Select.vue"
+export { default as SelectContent } from "./SelectContent.vue"
+export { default as SelectGroup } from "./SelectGroup.vue"
+export { default as SelectItem } from "./SelectItem.vue"
+export { default as SelectItemText } from "./SelectItemText.vue"
+export { default as SelectLabel } from "./SelectLabel.vue"
+export { default as SelectScrollDownButton } from "./SelectScrollDownButton.vue"
+export { default as SelectScrollUpButton } from "./SelectScrollUpButton.vue"
+export { default as SelectSeparator } from "./SelectSeparator.vue"
+export { default as SelectTrigger } from "./SelectTrigger.vue"
+export { default as SelectValue } from "./SelectValue.vue"
diff --git a/packages/library/src/index.ts b/packages/library/src/index.ts
index d0e62cd..5c54557 100644
--- a/packages/library/src/index.ts
+++ b/packages/library/src/index.ts
@@ -18,6 +18,13 @@ export {
RadioGroupItem,
Switch,
Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+ SelectGroup,
+ SelectLabel,
+ SelectSeparator,
Card,
CardHeader,
CardTitle,
diff --git a/packages/library/src/lib/index.ts b/packages/library/src/lib/index.ts
index d44a8d3..df08540 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 {
- Select as PrimeSelect,
Dialog as PrimeDialog,
} from 'primevue'
import { ThemeLibrary, type Themeable, ThemeEngine, type LibComponent, type Key } from '../engine'
@@ -29,6 +28,14 @@ import {
AlertDescription,
AlertAction,
alertVariants,
+ Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+ SelectGroup,
+ SelectLabel,
+ SelectSeparator,
} from '../components'
export {
@@ -55,6 +62,14 @@ export {
AlertDescription,
AlertAction,
alertVariants,
+ Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+ SelectGroup,
+ SelectLabel,
+ SelectSeparator,
}
/**
@@ -99,18 +114,6 @@ const loadingIconThemeable: Themeable = {
const nychthemeron: ThemeLibrary = {
components: {
LoadingIcon: loadingIconThemeable,
- Select: ptThemeable(PrimeSelect, 'select', [
- 'label',
- 'dropdown',
- 'dropdownIcon',
- 'overlay',
- 'header',
- 'listContainer',
- 'list',
- 'option',
- 'optionLabel',
- 'emptyMessage',
- ]),
Dialog: ptThemeable(PrimeDialog, 'dialog', [
'mask',
'header',
@@ -125,7 +128,6 @@ const nychthemeron: ThemeLibrary = {
const _engine = new ThemeEngine(nychthemeron)
export const LoadingIcon = _engine.getComponent('LoadingIcon')
-export const Select: typeof PrimeSelect = _engine.getComponent('Select')
export const Dialog: typeof PrimeDialog = _engine.getComponent('Dialog')
export const createNychthemeron = (): {
@@ -138,7 +140,14 @@ export const createNychthemeron = (): {
RadioGroup: typeof RadioGroup
RadioGroupItem: typeof RadioGroupItem
Switch: typeof Switch
- Select: typeof PrimeSelect
+ Select: typeof Select
+ SelectTrigger: typeof SelectTrigger
+ SelectValue: typeof SelectValue
+ SelectContent: typeof SelectContent
+ SelectItem: typeof SelectItem
+ SelectGroup: typeof SelectGroup
+ SelectLabel: typeof SelectLabel
+ SelectSeparator: typeof SelectSeparator
Card: typeof Card
CardHeader: typeof CardHeader
CardTitle: typeof CardTitle
@@ -164,6 +173,13 @@ export const createNychthemeron = (): {
RadioGroupItem,
Switch,
Select,
+ SelectTrigger,
+ SelectValue,
+ SelectContent,
+ SelectItem,
+ SelectGroup,
+ SelectLabel,
+ SelectSeparator,
Card,
CardHeader,
CardTitle,
@@ -188,6 +204,13 @@ export const createNychthemeron = (): {
app.component('NychRadioGroupItem', RadioGroupItem)
app.component('NychSwitch', Switch)
app.component('NychSelect', Select)
+ app.component('NychSelectTrigger', SelectTrigger)
+ app.component('NychSelectValue', SelectValue)
+ app.component('NychSelectContent', SelectContent)
+ app.component('NychSelectItem', SelectItem)
+ app.component('NychSelectGroup', SelectGroup)
+ app.component('NychSelectLabel', SelectLabel)
+ app.component('NychSelectSeparator', SelectSeparator)
app.component('NychCard', Card)
app.component('NychCardHeader', CardHeader)
app.component('NychCardTitle', CardTitle)
diff --git a/packages/library/tests/Select.spec.ts b/packages/library/tests/Select.spec.ts
new file mode 100644
index 0000000..2ba1043
--- /dev/null
+++ b/packages/library/tests/Select.spec.ts
@@ -0,0 +1,38 @@
+import { describe, it, expect } from 'vitest'
+import { h } from 'vue'
+import { mount } from '@vue/test-utils'
+import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '../src/lib'
+
+const RIVERS = ['Styx', 'Acheron', 'Cocytus']
+
+function mountSelect(modelValue: string | undefined) {
+ return mount(Select, {
+ props: { modelValue },
+ slots: {
+ default: () => [
+ h(SelectTrigger, undefined, {
+ default: () => h(SelectValue, { placeholder: 'Choose a river' }),
+ }),
+ h(SelectContent, undefined, {
+ default: () => RIVERS.map((r) => h(SelectItem, { value: r }, { default: () => r })),
+ }),
+ ],
+ },
+ attachTo: document.body,
+ })
+}
+
+describe('Select', () => {
+ it('renders the trigger with the placeholder when no value is selected', () => {
+ const wrapper = mountSelect(undefined)
+ expect(wrapper.text()).toContain('Choose a river')
+ })
+
+ it('shows the selected value in the trigger once the item has rendered', async () => {
+ const wrapper = mountSelect('Styx')
+ // SelectValue resolves its display label from the matching SelectItem, which only
+ // mounts once the dropdown has opened at least once.
+ await wrapper.get('button[role="combobox"]').trigger('click')
+ expect(wrapper.text()).toContain('Styx')
+ })
+})
diff --git a/packages/library/tests/lib.spec.ts b/packages/library/tests/lib.spec.ts
index c6aa745..dec9161 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,
- Select,
Dialog,
} from '../src/index'
@@ -61,7 +60,6 @@ describe('LoadingIcon', () => {
describe('themed pt components', () => {
const cases = [
- { name: 'Select', component: Select, base: 'nych-select' },
{ name: 'Dialog', component: Dialog, base: 'nych-dialog' },
]
@@ -81,10 +79,4 @@ describe('themed pt components', () => {
expect(result).not.toHaveProperty('injectedStyles')
expect(result).not.toHaveProperty('stylePlug')
})
-
- it('Select themes its overlay and option sections', () => {
- const result = callSetup(Select, { pt: {} })
- expect(result.pt?.overlay?.class).toContain('nych-select-overlay')
- expect(result.pt?.option?.class).toContain('nych-select-option')
- })
})
diff --git a/packages/playground/stories/Select.stories.ts b/packages/playground/stories/Select.stories.ts
index 7ed9872..8c5f21e 100644
--- a/packages/playground/stories/Select.stories.ts
+++ b/packages/playground/stories/Select.stories.ts
@@ -1,7 +1,13 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { ref } from 'vue'
-import { Select as NychSelect } from '@nychthemeron/library'
+import {
+ Select as NychSelect,
+ SelectTrigger as NychSelectTrigger,
+ SelectValue as NychSelectValue,
+ SelectContent as NychSelectContent,
+ SelectItem as NychSelectItem,
+} from '@nychthemeron/library'
const meta = {
title: 'Components/Select',
@@ -10,16 +16,6 @@ const meta = {
layout: 'centered',
},
tags: ['autodocs'],
- argTypes: {
- placeholder: {
- control: { type: 'text' },
- description: 'Placeholder text',
- },
- disabled: {
- control: { type: 'boolean' },
- description: 'Disable the select',
- },
- },
} satisfies Meta
export default meta
@@ -29,42 +25,65 @@ const RIVERS = ['Styx', 'Acheron', 'Cocytus', 'Phlegethon', 'Lethe']
export const Default: Story = {
render: () => ({
- components: { NychSelect },
+ components: { NychSelect, NychSelectTrigger, NychSelectValue, NychSelectContent, NychSelectItem },
setup() {
- const river = ref(null)
+ const river = ref()
return { river, RIVERS }
},
- template: ``,
+ template: `
+
+
+
+
+
+ {{ r }}
+
+
+ `,
}),
}
export const Selected: Story = {
render: () => ({
- components: { NychSelect },
+ components: { NychSelect, NychSelectTrigger, NychSelectValue, NychSelectContent, NychSelectItem },
setup() {
const river = ref('Lethe')
return { river, RIVERS }
},
- template: ``,
+ template: `
+
+
+
+
+
+ {{ r }}
+
+
+ `,
}),
}
export const Disabled: Story = {
render: () => ({
- components: { NychSelect },
- setup() {
- const river = ref('Styx')
- return { river, RIVERS }
- },
- template: ``,
+ components: { NychSelect, NychSelectTrigger, NychSelectValue, NychSelectContent, NychSelectItem },
+ template: `
+
+
+
+
+
+ {{ r }}
+
+
+ `,
}),
}
export const ObjectOptions: Story = {
render: () => ({
- components: { NychSelect },
+ components: { NychSelect, NychSelectTrigger, NychSelectValue, NychSelectContent, NychSelectItem },
setup() {
- const god = ref(null)
+ const god = ref()
const gods = [
{ name: 'Apollo', domain: 'apollo' },
{ name: 'Hades', domain: 'hades' },
@@ -72,6 +91,15 @@ export const ObjectOptions: Story = {
]
return { god, gods }
},
- template: ``,
+ template: `
+
+
+
+
+
+ {{ g.name }}
+
+
+ `,
}),
}