Nychthemeron/packages/library/src/lib/index.ts
Matthew L McPeak 5d840fcc16 feat: migrate Message to shadcn-vue Alert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 14:45:45 -04:00

205 lines
5 KiB
TypeScript

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'
import {
NychLoadingIcon,
Button,
buttonVariants,
Input,
Textarea,
Switch,
Badge,
badgeVariants,
Checkbox,
CheckboxGroup,
RadioGroup,
RadioGroupItem,
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
CardAction,
Alert,
AlertTitle,
AlertDescription,
AlertAction,
alertVariants,
} from '../components'
export {
Button,
buttonVariants,
Input,
Textarea,
Switch,
Badge,
badgeVariants,
Checkbox,
CheckboxGroup,
RadioGroup,
RadioGroupItem,
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
CardAction,
Alert,
AlertTitle,
AlertDescription,
AlertAction,
alertVariants,
}
/**
* Build a Themeable that themes a PrimeVue component through its passthrough (`pt`) API.
*
* The engine injects the base class (`nych-<base>`) onto `pt.root`. This factory layers a
* `nych-<base>-<section>` class onto every additional section so multi-part components
* (Checkbox box, Select overlay, Card body, …) can be fully styled in unstyled mode, where
* PrimeVue emits no classes of its own.
*/
const ptThemeable = <T extends LibComponent>(
component: T,
base: string,
sections: string[] = [],
): Themeable<T> => ({
component,
unstyled: true as Themeable<T>['unstyled'],
classes: [`nych-${base}`],
injectionKeys: { class: 'pt' as Key<T> },
propMutator: ((props: Record<string, unknown>) => {
const pt = (props.pt as Record<string, { class?: string }>) ?? {}
for (const section of sections) {
const existing = pt[section]?.class
pt[section] = {
...(pt[section] ?? {}),
class: [existing, `nych-${base}-${section}`].filter(Boolean).join(' '),
}
}
props.pt = pt
return props
}) as Themeable<T>['propMutator'],
})
const loadingIconThemeable: Themeable<typeof NychLoadingIcon> = {
component: NychLoadingIcon,
unstyled: false,
}
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',
'title',
'headerActions',
'content',
'footer',
]),
},
}
const _engine = new ThemeEngine(nychthemeron)
export const LoadingIcon = _engine.getComponent<typeof NychLoadingIcon>('LoadingIcon')
export const Select: typeof PrimeSelect = _engine.getComponent<typeof PrimeSelect>('Select')
export const Dialog: typeof PrimeDialog = _engine.getComponent<typeof PrimeDialog>('Dialog')
export const createNychthemeron = (): {
Button: typeof Button
LoadingIcon: typeof NychLoadingIcon
Input: typeof Input
Textarea: typeof Textarea
Checkbox: typeof Checkbox
CheckboxGroup: typeof CheckboxGroup
RadioGroup: typeof RadioGroup
RadioGroupItem: typeof RadioGroupItem
Switch: typeof Switch
Select: typeof PrimeSelect
Card: typeof Card
CardHeader: typeof CardHeader
CardTitle: typeof CardTitle
CardDescription: typeof CardDescription
CardContent: typeof CardContent
CardFooter: typeof CardFooter
CardAction: typeof CardAction
Dialog: typeof PrimeDialog
Alert: typeof Alert
AlertTitle: typeof AlertTitle
AlertDescription: typeof AlertDescription
AlertAction: typeof AlertAction
Badge: typeof Badge
install: (app: App) => void
} => ({
Button,
LoadingIcon,
Input,
Textarea,
Checkbox,
CheckboxGroup,
RadioGroup,
RadioGroupItem,
Switch,
Select,
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
CardAction,
Dialog,
Alert,
AlertTitle,
AlertDescription,
AlertAction,
Badge,
install(app: App) {
app.component('NychButton', Button)
app.component('NychLoadingIcon', LoadingIcon)
app.component('NychInput', Input)
app.component('NychTextarea', Textarea)
app.component('NychCheckbox', Checkbox)
app.component('NychCheckboxGroup', CheckboxGroup)
app.component('NychRadioGroup', RadioGroup)
app.component('NychRadioGroupItem', RadioGroupItem)
app.component('NychSwitch', Switch)
app.component('NychSelect', Select)
app.component('NychCard', Card)
app.component('NychCardHeader', CardHeader)
app.component('NychCardTitle', CardTitle)
app.component('NychCardDescription', CardDescription)
app.component('NychCardContent', CardContent)
app.component('NychCardFooter', CardFooter)
app.component('NychCardAction', CardAction)
app.component('NychDialog', Dialog)
app.component('NychAlert', Alert)
app.component('NychAlertTitle', AlertTitle)
app.component('NychAlertDescription', AlertDescription)
app.component('NychAlertAction', AlertAction)
app.component('NychBadge', Badge)
},
})