// shadcn-styled widgets that plug into the @voltro/ui widget seam. Plain, // accessible HTML with Tailwind utility classes against the design tokens in // `./tokens.css`. Drop them in app-wide: // // import { shadcnWidgets } from '@voltro/ui-shadcn' // import '@voltro/ui-shadcn/tokens.css' // // // They implement the SAME `Widget` contract as @voltro/ui's plain defaults — // the seam falls back to the plain default for any kind not overridden here. import { useId, type ReactNode } from 'react' import type { Widget, WidgetProps, WidgetRegistry } from '@voltro/ui' const cx = { field: 'voltro-field flex flex-col gap-1', label: 'text-sm font-medium text-foreground', control: 'block w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm ' + 'focus:outline-none focus:ring-2 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50', checkbox: 'h-4 w-4 rounded border-input text-primary focus:ring-2 focus:ring-ring', error: 'text-sm text-destructive', } const asString = (v: unknown): string => (v === undefined || v === null ? '' : String(v)) const describedBy = (id: string, error: string | undefined): string | undefined => error !== undefined ? `${id}-error` : undefined const Shell = (props: { readonly id: string readonly label: string readonly required: boolean readonly error?: string | undefined readonly children: ReactNode }): ReactNode => (
{props.children} {props.error !== undefined ? ( ) : null}
) const inputWidget = (type: string, toValue: (raw: string) => unknown): Widget => { const Component: Widget = (props) => { const id = useId() return ( props.onChange(toValue(e.target.value))} disabled={props.disabled} required={props.required} aria-invalid={props.error !== undefined} aria-describedby={describedBy(id, props.error)} /> ) } return Component } const TextareaWidget: Widget = (props) => { const id = useId() return (