@nerds-with-charisma/revit-ui 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,19 @@ pnpm add @nerds-with-charisma/revit-ui
10
10
 
11
11
  Peer: React 19.
12
12
 
13
+ ## Documentation
14
+
15
+ Browse components locally:
16
+
17
+ ```bash
18
+ pnpm install
19
+ pnpm dev
20
+ ```
21
+
22
+ Opens **Storybook** at `http://localhost:6006` with live examples, props tables, and usage notes.
23
+
24
+ Build static docs: `pnpm build-storybook` → `storybook-static/`
25
+
13
26
  ## Use
14
27
 
15
28
  ```tsx
@@ -25,6 +38,240 @@ export const App = () => {
25
38
  }
26
39
  ```
27
40
 
28
- Pass a custom token object to `RevitUIProvider` to restyle without forking components.
41
+ Pass a custom token object to `RevitUIProvider` to restyle without forking components. Omit `tokens` and the kit uses `revitTokens`. The object must be complete (no merge / partials):
42
+
43
+ ```ts
44
+ import type { RevitThemeTokens } from '@nerds-with-charisma/revit-ui'
45
+
46
+ const myTokens: RevitThemeTokens = {
47
+ colors: {
48
+ background: string
49
+ foreground: string
50
+ card: string
51
+ cardForeground: string
52
+ popover: string
53
+ popoverForeground: string
54
+ primary: string
55
+ primaryForeground: string
56
+ secondary: string
57
+ secondaryForeground: string
58
+ muted: string
59
+ mutedForeground: string
60
+ accent: string
61
+ accentForeground: string
62
+ destructive: string
63
+ destructiveForeground: string
64
+ border: string
65
+ input: string
66
+ ring: string
67
+ brand: {
68
+ yellow: string
69
+ yellowLight: string
70
+ offBlack: string
71
+ pink: string
72
+ purple: string
73
+ blue: string
74
+ gold: string
75
+ brown: string
76
+ umber: string
77
+ mist: string
78
+ }
79
+ }
80
+ colorsDark: {
81
+ background: string
82
+ foreground: string
83
+ card: string
84
+ cardForeground: string
85
+ popover: string
86
+ popoverForeground: string
87
+ primary: string
88
+ primaryForeground: string
89
+ secondary: string
90
+ secondaryForeground: string
91
+ muted: string
92
+ mutedForeground: string
93
+ accent: string
94
+ accentForeground: string
95
+ destructive: string
96
+ destructiveForeground: string
97
+ border: string
98
+ input: string
99
+ ring: string
100
+ brand: {
101
+ yellow: string
102
+ yellowLight: string
103
+ offBlack: string
104
+ pink: string
105
+ purple: string
106
+ blue: string
107
+ gold: string
108
+ brown: string
109
+ umber: string
110
+ mist: string
111
+ }
112
+ }
113
+ radius: {
114
+ sm: string
115
+ md: string
116
+ lg: string
117
+ xl: string
118
+ pill: string
119
+ }
120
+ fontFamily: {
121
+ sans: string
122
+ }
123
+ }
124
+
125
+ <RevitUIProvider tokens={myTokens}>{children}</RevitUIProvider>
126
+ ```
29
127
 
30
128
  Tokens only: `import { revitTokens } from '@nerds-with-charisma/revit-ui/theme/revit'`
129
+
130
+ ## Components
131
+
132
+ | Category | Components |
133
+ |----------|------------|
134
+ | **Typography** | `Heading`, `Text`, `Link` |
135
+ | **Actions** | `Button`, `Badge`, `Toggle` |
136
+ | **Forms** | `Field`, `RevitForm`, `Input`, `PasswordInput`, `Textarea`, `Checkbox`, `Switch`, `Select`, `RadioGroup`, `Label` |
137
+ | **Layout** | `Card`, `Separator`, `AspectRatio`, `ScrollArea` |
138
+ | **Feedback** | `Alert`, `Progress`, `Skeleton`, `toast` / `Toaster` |
139
+ | **Overlays** | `Dialog`, `Sheet`, `Popover`, `Tooltip`, `DropdownMenu`, `AlertDialog` |
140
+ | **Navigation** | `Tabs`, `Breadcrumb`, `Pagination`, `NavigationMenu` |
141
+ | **Revit surfaces** | `FrostPanel`, `FrostNav`, `FrostTile`, `SearchBar`, `BrandGradient` |
142
+
143
+ See Storybook for examples. Low-level `Form*` primitives remain available for custom fields.
144
+
145
+ ### Single field
146
+
147
+ ```tsx
148
+ <Field description="We'll never share your email." label="Email">
149
+ <Input type="email" placeholder="you@example.com" />
150
+ </Field>
151
+ ```
152
+
153
+ ### Low-level escape hatch
154
+
155
+ `Form`, `FormField`, `FormItem`, `FormLabel`, `FormControl`, `FormMessage`, and `useForm` are still exported for custom fields that don't fit the config shape.
156
+
157
+ ## Forms
158
+
159
+ Config-driven forms — pass a `fields` array, `RevitForm` handles react-hook-form + labels, validation messages, and wiring.
160
+
161
+ ### Example (sign-in)
162
+
163
+ ```tsx
164
+ 'use client'
165
+
166
+ import { RevitForm } from '@nerds-with-charisma/revit-ui'
167
+
168
+ type SignInValues = {
169
+ email: string
170
+ password: string
171
+ remember: boolean
172
+ }
173
+
174
+ export const SignInForm = () => {
175
+ return (
176
+ <RevitForm<SignInValues>
177
+ defaultValues={{ email: '', password: '', remember: false }}
178
+ submitLabel="Sign in"
179
+ onSubmit={(values) => console.log(values)}
180
+ fields={[
181
+ {
182
+ name: 'email',
183
+ label: 'Email',
184
+ type: 'input',
185
+ placeholder: 'you@example.com',
186
+ inputProps: { type: 'email', autoComplete: 'email' },
187
+ },
188
+ {
189
+ name: 'password',
190
+ label: 'Password',
191
+ type: 'password',
192
+ placeholder: '••••••••',
193
+ showPasswordToggle: true,
194
+ forgotPassword: {
195
+ label: 'Forgot Password?',
196
+ href: '/forgot-password',
197
+ },
198
+ },
199
+ {
200
+ name: 'remember',
201
+ label: 'Remember me',
202
+ type: 'checkbox',
203
+ },
204
+ ]}
205
+ />
206
+ )
207
+ }
208
+ ```
209
+
210
+ ### Field types
211
+
212
+ | `type` | Renders | Notes |
213
+ | ------------ | ------------------------------- | ------------------------------------------ |
214
+ | `input` | `Input` | `placeholder`, `inputProps` |
215
+ | `password` | `PasswordInput` | `showPasswordToggle`, `forgotPassword` |
216
+ | `textarea` | `Textarea` | `placeholder`, `textareaProps` |
217
+ | `checkbox` | `Checkbox` | Inline label |
218
+ | `switch` | `Switch` | Inline label |
219
+ | `select` | `Select` | `options: { value, label }[]` |
220
+ | `radio` | `RadioGroup` | `options: { value, label }[]` |
221
+
222
+ Every field supports optional `description` (helper text below the control).
223
+
224
+ ### `RevitForm` props
225
+
226
+ | Prop | Type | Default | Description |
227
+ | --------------- | ---------------------------- | ---------- | ------------------------------------ |
228
+ | `defaultValues` | object | required | Initial field values |
229
+ | `fields` | `RevitFormField[]` | required | Field config array |
230
+ | `onSubmit` | `(values) => void` | required | Called with validated values |
231
+ | `submitLabel` | string | `"Submit"` | Submit button text |
232
+ | `hideSubmit` | boolean | `false` | Hide the built-in submit button |
233
+ | `resolver` | RHF `Resolver` | — | Pass a zod/yup resolver for validation |
234
+ | `className` | string | — | Classes on the `<form>` element |
235
+ | `fieldClassName`| string | — | Classes on each `FormItem` |
236
+
237
+ ### Password field extras
238
+
239
+ ```ts
240
+ {
241
+ name: 'password',
242
+ label: 'Password',
243
+ type: 'password',
244
+ showPasswordToggle: true, // default true — eye icon inside the input
245
+ forgotPassword: {
246
+ label: 'Forgot Password?', // default
247
+ href: '/forgot-password', // renders <a> (top-right, above input)
248
+ // onClick: () => {}, // use instead of href for a <button>
249
+ },
250
+ }
251
+ ```
252
+
253
+ `PasswordInput` is also exported standalone if you need it outside `RevitForm`.
254
+
255
+ ### Validation (optional)
256
+
257
+ ```tsx
258
+ import { zodResolver } from '@hookform/resolvers/zod'
259
+ import { z } from 'zod'
260
+
261
+ const schema = z.object({
262
+ email: z.string().email(),
263
+ password: z.string().min(8),
264
+ })
265
+
266
+ <RevitForm
267
+ resolver={zodResolver(schema)}
268
+ defaultValues={{ email: '', password: '' }}
269
+ onSubmit={onSubmit}
270
+ fields={[/* ... */]}
271
+ />
272
+ ```
273
+
274
+ ### Low-level escape hatch
275
+
276
+ `Form`, `FormField`, `FormItem`, `FormLabel`, `FormControl`, `FormMessage`, and `useForm` are still exported for custom fields that don't fit the config shape.
277
+
package/dist/index.d.ts CHANGED
@@ -16,7 +16,8 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
16
16
  import * as PopoverPrimitive from '@radix-ui/react-popover';
17
17
  import * as SliderPrimitive from '@radix-ui/react-slider';
18
18
  import * as react_hook_form from 'react-hook-form';
19
- import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
19
+ import { FieldValues, FieldPath, ControllerProps, DefaultValues, Resolver } from 'react-hook-form';
20
+ export { useForm } from 'react-hook-form';
20
21
  import { Slot } from '@radix-ui/react-slot';
21
22
  import { Toaster as Toaster$1 } from 'sonner';
22
23
  export { toast } from 'sonner';
@@ -346,6 +347,63 @@ declare const useFormField: () => {
346
347
  formMessageId: string;
347
348
  };
348
349
 
350
+ type PasswordInputProps = Omit<ComponentProps<typeof Input>, 'type'> & {
351
+ showPasswordToggle?: boolean;
352
+ };
353
+ declare const PasswordInput: ({ className, showPasswordToggle, ...props }: PasswordInputProps) => react.JSX.Element;
354
+
355
+ type RevitFormOption = {
356
+ value: string;
357
+ label: string;
358
+ };
359
+ type RevitFormFieldBase = {
360
+ name: string;
361
+ label: string;
362
+ description?: string;
363
+ };
364
+ type RevitFormForgotPassword = {
365
+ label?: string;
366
+ href?: string;
367
+ onClick?: () => void;
368
+ };
369
+ type RevitFormField = (RevitFormFieldBase & {
370
+ type: 'input';
371
+ placeholder?: string;
372
+ inputProps?: Omit<InputProps, 'name' | 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'ref'>;
373
+ }) | (RevitFormFieldBase & {
374
+ type: 'password';
375
+ placeholder?: string;
376
+ showPasswordToggle?: boolean;
377
+ forgotPassword?: RevitFormForgotPassword;
378
+ inputProps?: Omit<PasswordInputProps, 'name' | 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'ref' | 'showPasswordToggle'>;
379
+ }) | (RevitFormFieldBase & {
380
+ type: 'textarea';
381
+ placeholder?: string;
382
+ textareaProps?: Omit<TextareaProps, 'name' | 'value' | 'defaultValue' | 'onChange' | 'onBlur' | 'ref'>;
383
+ }) | (RevitFormFieldBase & {
384
+ type: 'checkbox';
385
+ }) | (RevitFormFieldBase & {
386
+ type: 'switch';
387
+ }) | (RevitFormFieldBase & {
388
+ type: 'select';
389
+ placeholder?: string;
390
+ options: RevitFormOption[];
391
+ }) | (RevitFormFieldBase & {
392
+ type: 'radio';
393
+ options: RevitFormOption[];
394
+ });
395
+ type RevitFormProps<TFieldValues extends FieldValues = FieldValues> = {
396
+ defaultValues: DefaultValues<TFieldValues>;
397
+ fields: RevitFormField[];
398
+ onSubmit: (values: TFieldValues) => void | Promise<void>;
399
+ resolver?: Resolver<TFieldValues>;
400
+ submitLabel?: string;
401
+ hideSubmit?: boolean;
402
+ className?: string;
403
+ fieldClassName?: string;
404
+ };
405
+ declare const RevitForm: <TFieldValues extends FieldValues = FieldValues>({ className, defaultValues, fieldClassName, fields, hideSubmit, onSubmit, resolver, submitLabel, }: RevitFormProps<TFieldValues>) => react.JSX.Element;
406
+
349
407
  type FormItemProps = HTMLAttributes<HTMLDivElement>;
350
408
  declare const FormItem: ({ className, ...props }: FormItemProps) => react.JSX.Element;
351
409
 
@@ -361,6 +419,41 @@ declare const FormDescription: ({ className, ...props }: FormDescriptionProps) =
361
419
  type FormMessageProps = HTMLAttributes<HTMLParagraphElement>;
362
420
  declare const FormMessage: ({ className, children, ...props }: FormMessageProps) => react.JSX.Element | null;
363
421
 
422
+ type FieldProps = {
423
+ children: ReactNode;
424
+ className?: string;
425
+ description?: string;
426
+ error?: string;
427
+ htmlFor?: string;
428
+ label: string;
429
+ required?: boolean;
430
+ };
431
+ declare const Field: ({ children, className, description, error, htmlFor, label, required, }: FieldProps) => react.JSX.Element;
432
+
433
+ declare const headingVariants: (props?: ({
434
+ variant?: "title" | "page" | "section" | "eyebrow" | "subtitle" | null | undefined;
435
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
436
+ type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p';
437
+ type HeadingProps = HTMLAttributes<HTMLElement> & VariantProps<typeof headingVariants> & {
438
+ as?: HeadingTag;
439
+ };
440
+ declare const Heading: ({ as, className, variant, ...props }: HeadingProps) => react.JSX.Element;
441
+
442
+ declare const linkVariants: (props?: ({
443
+ variant?: "default" | "muted" | "primary" | null | undefined;
444
+ size?: "default" | "sm" | "base" | null | undefined;
445
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
446
+ type LinkProps = ComponentProps<'a'> & VariantProps<typeof linkVariants> & {
447
+ asChild?: boolean;
448
+ };
449
+ declare const Link: ({ asChild, className, size, variant, ...props }: LinkProps) => react.JSX.Element;
450
+
451
+ declare const textVariants: (props?: ({
452
+ variant?: "sm" | "label" | "body" | "muted" | "lead" | null | undefined;
453
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
454
+ type TextProps = HTMLAttributes<HTMLParagraphElement> & VariantProps<typeof textVariants>;
455
+ declare const Text: ({ className, variant, ...props }: TextProps) => react.JSX.Element;
456
+
364
457
  type ToasterProps = ComponentProps<typeof Toaster$1>;
365
458
  declare const Toaster: ({ ...props }: ToasterProps) => react.JSX.Element;
366
459
 
@@ -643,4 +736,4 @@ declare const tokensToCssVars: (tokens: RevitThemeTokens) => {
643
736
  };
644
737
  declare const tokensToStylesheet: (tokens: RevitThemeTokens) => string;
645
738
 
646
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BrandGradient, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, Checkbox, type CheckboxProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, type ComboboxOption, type ComboboxProps, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, ConfirmDialog, ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerContent, DrawerDescription, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FrostFab, FrostNav, FrostPanel, FrostTile, HoverCard, HoverCardContent, HoverCardTrigger, ImageScrim, Input, InputOTP, InputOTPGroup, InputOTPSlot, type InputProps, Label, type LabelProps, Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, Pagination, PaginationBar, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RevitThemeTokens, RevitUIProvider, ScrollArea, ScrollBar, SearchBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, Skeleton, Slider, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alertVariants, badgeVariants, buttonVariants, cardVariants, cn, inputVariants, labelVariants, selectTriggerVariants, surfaces, textareaVariants, toggleVariants, tokensToCssVars, tokensToStylesheet, useFormField, useSidebar };
739
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, BrandGradient, Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, Checkbox, type CheckboxProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, type ComboboxOption, type ComboboxProps, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, ConfirmDialog, ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Drawer, DrawerContent, DrawerDescription, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Field, type FieldProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, FrostFab, FrostNav, FrostPanel, FrostTile, Heading, type HeadingProps, HoverCard, HoverCardContent, HoverCardTrigger, ImageScrim, Input, InputOTP, InputOTPGroup, InputOTPSlot, type InputProps, Label, type LabelProps, Link, type LinkProps, Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarTrigger, NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, Pagination, PaginationBar, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RevitForm, type RevitFormField, type RevitFormForgotPassword, type RevitFormOption, type RevitFormProps, RevitThemeTokens, RevitUIProvider, ScrollArea, ScrollBar, SearchBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, Skeleton, Slider, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, type TextProps, Textarea, type TextareaProps, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alertVariants, badgeVariants, buttonVariants, cardVariants, cn, headingVariants, inputVariants, labelVariants, linkVariants, selectTriggerVariants, surfaces, textVariants, textareaVariants, toggleVariants, tokensToCssVars, tokensToStylesheet, useFormField, useSidebar };