@openwarelabs/ui 0.0.0-stage → 0.1.1

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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +100 -2
  3. package/dist/components/Accordion/Accordion.d.cts +54 -0
  4. package/dist/components/Accordion/Accordion.d.ts +54 -0
  5. package/dist/components/Alert/Alert.d.cts +18 -0
  6. package/dist/components/Alert/Alert.d.ts +18 -0
  7. package/dist/components/Avatar/Avatar.d.cts +14 -0
  8. package/dist/components/Avatar/Avatar.d.ts +14 -0
  9. package/dist/components/Avatar/AvatarGroup.d.cts +28 -0
  10. package/dist/components/Avatar/AvatarGroup.d.ts +28 -0
  11. package/dist/components/Badge/Badge.d.cts +13 -0
  12. package/dist/components/Badge/Badge.d.ts +13 -0
  13. package/dist/components/Breadcrumbs/Breadcrumbs.d.cts +33 -0
  14. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +33 -0
  15. package/dist/components/Button/Button.d.cts +42 -0
  16. package/dist/components/Button/Button.d.ts +42 -0
  17. package/dist/components/Button/ButtonGroup.d.cts +33 -0
  18. package/dist/components/Button/ButtonGroup.d.ts +33 -0
  19. package/dist/components/Calendar/Calendar.d.cts +31 -0
  20. package/dist/components/Calendar/Calendar.d.ts +31 -0
  21. package/dist/components/Calendar/DatePicker.d.cts +21 -0
  22. package/dist/components/Calendar/DatePicker.d.ts +21 -0
  23. package/dist/components/Calendar/dates.d.cts +15 -0
  24. package/dist/components/Calendar/dates.d.ts +15 -0
  25. package/dist/components/Card/Card.d.cts +18 -0
  26. package/dist/components/Card/Card.d.ts +18 -0
  27. package/dist/components/Checkbox/Checkbox.d.cts +59 -0
  28. package/dist/components/Checkbox/Checkbox.d.ts +59 -0
  29. package/dist/components/ChoiceCard/ChoiceCard.d.cts +14 -0
  30. package/dist/components/ChoiceCard/ChoiceCard.d.ts +14 -0
  31. package/dist/components/CodeBlock/CodeBlock.d.cts +50 -0
  32. package/dist/components/CodeBlock/CodeBlock.d.ts +50 -0
  33. package/dist/components/ColorPicker/ColorPicker.d.cts +62 -0
  34. package/dist/components/ColorPicker/ColorPicker.d.ts +62 -0
  35. package/dist/components/Combobox/Combobox.d.cts +42 -0
  36. package/dist/components/Combobox/Combobox.d.ts +42 -0
  37. package/dist/components/CommandPalette/CommandPalette.d.cts +27 -0
  38. package/dist/components/CommandPalette/CommandPalette.d.ts +27 -0
  39. package/dist/components/CommandPalette/filterCommands.d.cts +3 -0
  40. package/dist/components/CommandPalette/filterCommands.d.ts +3 -0
  41. package/dist/components/Dialog/Dialog.d.cts +42 -0
  42. package/dist/components/Dialog/Dialog.d.ts +42 -0
  43. package/dist/components/Drawer/Drawer.d.cts +23 -0
  44. package/dist/components/Drawer/Drawer.d.ts +23 -0
  45. package/dist/components/EmptyState/EmptyState.d.cts +18 -0
  46. package/dist/components/EmptyState/EmptyState.d.ts +18 -0
  47. package/dist/components/Field/Field.d.cts +18 -0
  48. package/dist/components/Field/Field.d.ts +18 -0
  49. package/dist/components/FileDropZone/FileDropZone.d.cts +29 -0
  50. package/dist/components/FileDropZone/FileDropZone.d.ts +29 -0
  51. package/dist/components/FileTree/FileTree.d.cts +29 -0
  52. package/dist/components/FileTree/FileTree.d.ts +29 -0
  53. package/dist/components/Input/Input.d.cts +18 -0
  54. package/dist/components/Input/Input.d.ts +18 -0
  55. package/dist/components/InputOTP/InputOTP.d.cts +31 -0
  56. package/dist/components/InputOTP/InputOTP.d.ts +31 -0
  57. package/dist/components/Kbd/Kbd.d.cts +5 -0
  58. package/dist/components/Kbd/Kbd.d.ts +5 -0
  59. package/dist/components/Layout/Layout.d.cts +50 -0
  60. package/dist/components/Layout/Layout.d.ts +50 -0
  61. package/dist/components/Marketing/Marketing.d.cts +39 -0
  62. package/dist/components/Marketing/Marketing.d.ts +39 -0
  63. package/dist/components/Menu/Menu.d.cts +43 -0
  64. package/dist/components/Menu/Menu.d.ts +43 -0
  65. package/dist/components/NavList/NavList.d.cts +27 -0
  66. package/dist/components/NavList/NavList.d.ts +27 -0
  67. package/dist/components/NumberField/NumberField.d.cts +23 -0
  68. package/dist/components/NumberField/NumberField.d.ts +23 -0
  69. package/dist/components/Pagination/Pagination.d.cts +24 -0
  70. package/dist/components/Pagination/Pagination.d.ts +24 -0
  71. package/dist/components/Popover/Popover.d.cts +30 -0
  72. package/dist/components/Popover/Popover.d.ts +30 -0
  73. package/dist/components/Progress/Progress.d.cts +41 -0
  74. package/dist/components/Progress/Progress.d.ts +41 -0
  75. package/dist/components/RadioGroup/RadioGroup.d.cts +36 -0
  76. package/dist/components/RadioGroup/RadioGroup.d.ts +36 -0
  77. package/dist/components/SearchField/SearchField.d.cts +17 -0
  78. package/dist/components/SearchField/SearchField.d.ts +17 -0
  79. package/dist/components/SegmentedControl/SegmentedControl.d.cts +32 -0
  80. package/dist/components/SegmentedControl/SegmentedControl.d.ts +32 -0
  81. package/dist/components/Select/Select.d.cts +40 -0
  82. package/dist/components/Select/Select.d.ts +40 -0
  83. package/dist/components/Skeleton/Skeleton.d.cts +26 -0
  84. package/dist/components/Skeleton/Skeleton.d.ts +26 -0
  85. package/dist/components/Slider/Slider.d.cts +33 -0
  86. package/dist/components/Slider/Slider.d.ts +33 -0
  87. package/dist/components/Spinner/Spinner.d.cts +14 -0
  88. package/dist/components/Spinner/Spinner.d.ts +14 -0
  89. package/dist/components/Stat/Stat.d.cts +20 -0
  90. package/dist/components/Stat/Stat.d.ts +20 -0
  91. package/dist/components/Steps/Steps.d.cts +27 -0
  92. package/dist/components/Steps/Steps.d.ts +27 -0
  93. package/dist/components/Switch/Switch.d.cts +9 -0
  94. package/dist/components/Switch/Switch.d.ts +9 -0
  95. package/dist/components/Table/Table.d.cts +55 -0
  96. package/dist/components/Table/Table.d.ts +55 -0
  97. package/dist/components/Tabs/Tabs.d.cts +35 -0
  98. package/dist/components/Tabs/Tabs.d.ts +35 -0
  99. package/dist/components/Tag/Tag.d.cts +40 -0
  100. package/dist/components/Tag/Tag.d.ts +40 -0
  101. package/dist/components/Textarea/Textarea.d.cts +12 -0
  102. package/dist/components/Textarea/Textarea.d.ts +12 -0
  103. package/dist/components/Toast/Toast.d.cts +41 -0
  104. package/dist/components/Toast/Toast.d.ts +41 -0
  105. package/dist/components/Tooltip/Tooltip.d.cts +19 -0
  106. package/dist/components/Tooltip/Tooltip.d.ts +19 -0
  107. package/dist/components.css +5236 -0
  108. package/dist/fonts.css +3 -0
  109. package/dist/hooks/useControllableState.d.cts +5 -0
  110. package/dist/hooks/useControllableState.d.ts +5 -0
  111. package/dist/hooks/useFloating.d.cts +26 -0
  112. package/dist/hooks/useFloating.d.ts +26 -0
  113. package/dist/hooks/useIndicator.d.cts +8 -0
  114. package/dist/hooks/useIndicator.d.ts +8 -0
  115. package/dist/hooks/useMenuKeyboard.d.cts +12 -0
  116. package/dist/hooks/useMenuKeyboard.d.ts +12 -0
  117. package/dist/hooks/useModalDialog.d.cts +9 -0
  118. package/dist/hooks/useModalDialog.d.ts +9 -0
  119. package/dist/hooks/usePresence.d.cts +13 -0
  120. package/dist/hooks/usePresence.d.ts +13 -0
  121. package/dist/icons.d.cts +33 -0
  122. package/dist/icons.d.ts +33 -0
  123. package/dist/index.cjs +4622 -0
  124. package/dist/index.cjs.map +7 -0
  125. package/dist/index.d.cts +114 -0
  126. package/dist/index.d.ts +114 -0
  127. package/dist/index.js +4650 -0
  128. package/dist/index.js.map +7 -0
  129. package/dist/openware-ui.iife.js +8 -0
  130. package/dist/styles.css +5664 -0
  131. package/dist/tailwind.css +145 -0
  132. package/dist/tokens.css +427 -0
  133. package/dist/tokens.json +1163 -0
  134. package/dist/utils/brand.d.cts +30 -0
  135. package/dist/utils/brand.d.ts +30 -0
  136. package/dist/utils/copyText.d.cts +2 -0
  137. package/dist/utils/copyText.d.ts +2 -0
  138. package/dist/utils/cx.d.cts +4 -0
  139. package/dist/utils/cx.d.ts +4 -0
  140. package/dist/utils/resizeTextArea.d.cts +2 -0
  141. package/dist/utils/resizeTextArea.d.ts +2 -0
  142. package/dist/utils/text.d.cts +4 -0
  143. package/dist/utils/text.d.ts +4 -0
  144. package/package.json +83 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander Silver
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,101 @@
1
- # Temporary Holding Version
1
+ # Openware UI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ React components and design tokens with a quiet, tactile look: a midnight brand colour, a brass accent kept small, cool slate surfaces, buttons that press in, and Inter. Light and dark themes, and a brand colour you can swap.
4
+
5
+ ## Docs
6
+
7
+ ```sh
8
+ npm install # installs and builds dist/
9
+ npm run dev # the docs site: http://localhost:5173
10
+ npm run docs:build # the same site as static files in docs-dist/
11
+ ```
12
+
13
+ The docs have a page for every component, with live examples, the code to copy, keyboard behaviour, accessibility notes and a props table read from the TypeScript source, plus guides to installation, theming, colours, type and tokens. The Blocks section has 92 whole page sections (headers, heroes, pricing, settings, sign-in, chat and more), each live in a frame you can narrow to a tablet or a phone, with its `.tsx` and `.css` to copy. Search with ⌘K or Ctrl+K. They rebuild as you edit `src/`, `docs/` or `tokens/tokens.json`.
14
+
15
+ To document a new component, add `docs/examples/<Name>.tsx`: a `meta` export (title, category, description, source file) and one exported function per example. The function's JSDoc becomes the example's description, and its code is what the page shows.
16
+
17
+ To add a block, list it in `docs/app/blocks.tsx` and write `docs/blocks/<category>/<Name>.tsx` and `<Name>.css`; `docs/blocks/README.md` has the rules, and `npm run blocks:check` checks them.
18
+
19
+ ## Install in a project
20
+
21
+ ```sh
22
+ npm install @openwarelabs/ui
23
+ ```
24
+
25
+ React 18 or 19 is a peer dependency. Toasts come from [sonner](https://sonner.emilkowal.ski) and the colour picker from [react-colorful](https://github.com/omgovich/react-colorful), both installed with it.
26
+
27
+ ## Set up once
28
+
29
+ ```tsx
30
+ import "@openwarelabs/ui/fonts.css"; // Inter and Geist Mono, self-hosted
31
+ import "@openwarelabs/ui/styles.css"; // tokens + components
32
+ ```
33
+
34
+ ```html
35
+ <html data-theme="light"> <!-- "light", "dark", or "system" to follow the OS -->
36
+ <body class="ow-app"> <!-- the system's font, 14px text, colours and canvas -->
37
+ ```
38
+
39
+ Then use the components:
40
+
41
+ ```tsx
42
+ import { Button, Field, Input, Toaster, toast } from "@openwarelabs/ui";
43
+
44
+ <Field label="Project name" hint="Letters, numbers and dashes.">
45
+ <Input placeholder="recipe-app" />
46
+ </Field>
47
+ <Button variant="primary" onClick={() => toast.success("Saved")}>Save</Button>
48
+ <Toaster />
49
+ ```
50
+
51
+ ## Components
52
+
53
+ 70 components, each with a page in the docs.
54
+
55
+ | Group | Components |
56
+ | --- | --- |
57
+ | Buttons | `Button` (primary, secondary, ghost, danger; sm, md, lg; `loading`; `shape="pill"`), `buttonClassName()` for links, `ButtonGroup`, `ToggleButton`, `CloseButton`, `CopyButton`, `SegmentedControl`, `ChoiceCard` |
58
+ | Forms | `Field`, `Fieldset`, `Input` (start and end content), `SearchField`, `NumberField`, `InputOTP`, `Textarea` (`autoGrow`), `Select`, `Combobox`, `Checkbox`, `CheckboxGroup`, `RadioGroup` (plain or cards), `Switch`, `Slider` (one value or a range), `ColorPicker`, `ColorField`, `FileDropZone` |
59
+ | Dates | `Calendar`, `DatePicker` |
60
+ | Feedback | `Alert`, `Badge`, `ProgressBar`, `ProgressCircle`, `Spinner`, `Skeleton`, `SkeletonRows`, `Toaster` + `toast()` (sonner: stacked, swipeable, with actions and promises), `Tooltip` |
61
+ | Overlays | `Dialog`, `ConfirmDialog`, `Drawer`, `Popover`, `Menu` + `MenuItem`, `CommandPalette` |
62
+ | Navigation | `Tabs`, `Accordion`, `Disclosure`, `Breadcrumbs`, `Link`, `Pagination`, `Steps`, `NavList` + `NavItem` |
63
+ | Data display | `Table` (sorting, selection), `Stat`, `FileTree`, `EmptyState`, `Tag`, `ColorSwatch`, `Avatar`, `AvatarGroup`, `User`, `Kbd`, `Code`, `CodeBlock`, `Snippet` |
64
+ | Layout | `Card`, `SettingsRow`, `Stack`, `Separator`, `ScrollShadow`, `VisuallyHidden` |
65
+ | Marketing | `SiteHeader`, `SectionHeading`, `Chip`, `DotGrid` |
66
+
67
+ Hooks for your own components: `useControllableState`, `useFloating` (top-layer positioning that flips), `usePresence` (keeps a layer mounted while it animates out), `useDismiss`, `useModalDialog`, `useMenuKeyboard`. Every prop is typed and described, so your editor explains it on hover.
68
+
69
+ ## Tokens
70
+
71
+ Every colour, space, radius, shadow and weight is a CSS variable named `--ow-…` (`var(--ow-surface)`, `var(--ow-radius-container)`), and every text style is a class (`ow-type-section-title`, `ow-type-lead`). `tokens/tokens.json` is the single source; `npm run tokens` regenerates the CSS and `npm run contrast` checks every text and focus pair in both themes.
72
+
73
+ **Rebrand** by overriding the eleven brand steps; the primary button, focus ring, checkboxes, tints and the primary button's glow follow, in both themes. `brandScale` builds the steps from any colour, on Openware's lightness curve so the contrast holds, and `applyBrand` puts them on the page:
74
+
75
+ ```ts
76
+ import { applyBrand, brandCss, brandPresets, brandScale } from "@openwarelabs/ui";
77
+
78
+ applyBrand("#0d9488"); // the whole page, from one colour
79
+ applyBrand(brandPresets[2]!.scale); // or a preset: Midnight, Ocean, Teal, Forest, Plum, Rose, Ember
80
+ brandCss("#0d9488"); // ":root { --ow-brand-50: …; }" for a stylesheet
81
+ ```
82
+
83
+ The docs' header has a colour picker that does this live, and the Theming page shows each preset in both themes.
84
+
85
+ **Motion** uses the timing tokens: things enter with `ow-ease-emphasized` and leave faster with `ow-ease-exit`, and knobs and indicators settle with `ow-ease-spring`. Menus, popovers, listboxes and tooltips grow from their trigger and shrink back into it; dialogs and drawers animate both ways; segmented controls and tabs slide their indicator. Everything stands still under `prefers-reduced-motion`.
86
+
87
+ **Tailwind v4**: `@import "@openwarelabs/ui/tailwind.css";` after `@import "tailwindcss";` gives you `bg-surface`, `text-text-muted`, `rounded-container`, `p-lg`, `font-action`, `shadow-menu` and the rest, plus a `dark:` variant tied to `data-theme="dark"`.
88
+
89
+ **No bundler?** `dist/openware-ui.iife.js` sets `window.OpenwareUI`, reading React from `window.React`. A CDN serves it straight from npm: `https://cdn.jsdelivr.net/npm/@openwarelabs/ui/dist/openware-ui.iife.js`, with `dist/styles.css` beside it.
90
+
91
+ ## Rules worth keeping
92
+
93
+ - One primary button per view. Everything else is secondary or ghost.
94
+ - Borders before shadows: cards are `--ow-surface` with a 1px `--ow-border`. Shadows are for things that float or press.
95
+ - Brass stays small: dots, a star, the pointer on the grid. Never a button.
96
+ - Sentence case for every label. Name the action on the button ("Delete project"), never "OK".
97
+ - Icons are [Lucide](https://lucide.dev) (`lucide-react`), 16px, 2px stroke; icon-only buttons need an `aria-label`.
98
+
99
+ ## Credits
100
+
101
+ Icons drawn inside the components are Lucide shapes (ISC). Inter and Geist Mono are under the SIL Open Font License 1.1. Toasts use sonner and the colour picker uses react-colorful, both under the MIT licence.
@@ -0,0 +1,54 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ export interface DisclosureProps {
3
+ title: ReactNode;
4
+ /** A muted line under the title. */
5
+ subtitle?: ReactNode;
6
+ /** A 15px icon between the chevron and the title. */
7
+ icon?: ReactNode;
8
+ /** Controls on the right of the header, outside the toggle (a ghost Button). */
9
+ actions?: ReactNode;
10
+ open?: boolean;
11
+ /** @default false */
12
+ defaultOpen?: boolean;
13
+ onOpenChange?(open: boolean): void;
14
+ /** `card` is a bordered surface; `plain` is just the toggle and its content, for "Show details".
15
+ * @default "card" */
16
+ variant?: "card" | "plain";
17
+ /** The heading level of the title, to fit the page's outline.
18
+ * @default 3 */
19
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
20
+ disabled?: boolean;
21
+ children: ReactNode;
22
+ className?: string;
23
+ }
24
+ /** A section that opens and closes under its title, like "3 files changed" in a code review. */
25
+ export declare function Disclosure({ open, defaultOpen, onOpenChange, variant, headingLevel, className, ...props }: DisclosureProps): import("react").JSX.Element;
26
+ export interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue" | "onChange"> {
27
+ /** `single` keeps one item open at a time; `multiple` lets any number be open.
28
+ * @default "single" */
29
+ type?: "single" | "multiple";
30
+ /** The open items' values. */
31
+ value?: string[];
32
+ /** @default [] */
33
+ defaultValue?: string[];
34
+ onValueChange?(value: string[]): void;
35
+ /** `bordered` puts the items in one card with hairlines between; `separated` gives each its own card.
36
+ * @default "bordered" */
37
+ variant?: "bordered" | "separated";
38
+ /** @default 3 */
39
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
40
+ children: ReactNode;
41
+ }
42
+ /** A stack of Disclosures, such as an FAQ. Up and Down move between the headers. */
43
+ export declare function Accordion({ type, value, defaultValue, onValueChange, variant, headingLevel, className, children, onKeyDown, ...props }: AccordionProps): import("react").JSX.Element;
44
+ export interface AccordionItemProps {
45
+ value: string;
46
+ title: ReactNode;
47
+ subtitle?: ReactNode;
48
+ icon?: ReactNode;
49
+ disabled?: boolean;
50
+ children: ReactNode;
51
+ className?: string;
52
+ }
53
+ /** One section of an Accordion. */
54
+ export declare function AccordionItem({ value, ...props }: AccordionItemProps): import("react").JSX.Element;
@@ -0,0 +1,54 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ export interface DisclosureProps {
3
+ title: ReactNode;
4
+ /** A muted line under the title. */
5
+ subtitle?: ReactNode;
6
+ /** A 15px icon between the chevron and the title. */
7
+ icon?: ReactNode;
8
+ /** Controls on the right of the header, outside the toggle (a ghost Button). */
9
+ actions?: ReactNode;
10
+ open?: boolean;
11
+ /** @default false */
12
+ defaultOpen?: boolean;
13
+ onOpenChange?(open: boolean): void;
14
+ /** `card` is a bordered surface; `plain` is just the toggle and its content, for "Show details".
15
+ * @default "card" */
16
+ variant?: "card" | "plain";
17
+ /** The heading level of the title, to fit the page's outline.
18
+ * @default 3 */
19
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
20
+ disabled?: boolean;
21
+ children: ReactNode;
22
+ className?: string;
23
+ }
24
+ /** A section that opens and closes under its title, like "3 files changed" in a code review. */
25
+ export declare function Disclosure({ open, defaultOpen, onOpenChange, variant, headingLevel, className, ...props }: DisclosureProps): import("react").JSX.Element;
26
+ export interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue" | "onChange"> {
27
+ /** `single` keeps one item open at a time; `multiple` lets any number be open.
28
+ * @default "single" */
29
+ type?: "single" | "multiple";
30
+ /** The open items' values. */
31
+ value?: string[];
32
+ /** @default [] */
33
+ defaultValue?: string[];
34
+ onValueChange?(value: string[]): void;
35
+ /** `bordered` puts the items in one card with hairlines between; `separated` gives each its own card.
36
+ * @default "bordered" */
37
+ variant?: "bordered" | "separated";
38
+ /** @default 3 */
39
+ headingLevel?: 2 | 3 | 4 | 5 | 6;
40
+ children: ReactNode;
41
+ }
42
+ /** A stack of Disclosures, such as an FAQ. Up and Down move between the headers. */
43
+ export declare function Accordion({ type, value, defaultValue, onValueChange, variant, headingLevel, className, children, onKeyDown, ...props }: AccordionProps): import("react").JSX.Element;
44
+ export interface AccordionItemProps {
45
+ value: string;
46
+ title: ReactNode;
47
+ subtitle?: ReactNode;
48
+ icon?: ReactNode;
49
+ disabled?: boolean;
50
+ children: ReactNode;
51
+ className?: string;
52
+ }
53
+ /** One section of an Accordion. */
54
+ export declare function AccordionItem({ value, ...props }: AccordionItemProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export type AlertVariant = "info" | "success" | "warning" | "danger" | "neutral";
3
+ export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
4
+ /** info for news, success for something done, warning for something that needs the person, danger for something that failed.
5
+ * @default "info" */
6
+ variant?: AlertVariant;
7
+ /** A short bold line. */
8
+ title?: ReactNode;
9
+ /** Replaces the variant's icon; false hides it. */
10
+ icon?: ReactNode | false;
11
+ /** Buttons under the text, usually small ones. */
12
+ actions?: ReactNode;
13
+ /** Shows a ✕ that calls this. */
14
+ onClose?(): void;
15
+ children?: ReactNode;
16
+ }
17
+ /** A message inside the page about the page: a notice, a warning before an action, an error that blocks the work. */
18
+ export declare function Alert({ variant, title, icon, actions, onClose, children, className, role, ...props }: AlertProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ export type AlertVariant = "info" | "success" | "warning" | "danger" | "neutral";
3
+ export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
4
+ /** info for news, success for something done, warning for something that needs the person, danger for something that failed.
5
+ * @default "info" */
6
+ variant?: AlertVariant;
7
+ /** A short bold line. */
8
+ title?: ReactNode;
9
+ /** Replaces the variant's icon; false hides it. */
10
+ icon?: ReactNode | false;
11
+ /** Buttons under the text, usually small ones. */
12
+ actions?: ReactNode;
13
+ /** Shows a ✕ that calls this. */
14
+ onClose?(): void;
15
+ children?: ReactNode;
16
+ }
17
+ /** A message inside the page about the page: a notice, a warning before an action, an error that blocks the work. */
18
+ export declare function Alert({ variant, title, icon, actions, onClose, children, className, role, ...props }: AlertProps): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ export interface AvatarProps {
2
+ /** The person's name; its initials show when there's no image. */
3
+ name: string;
4
+ /** A photo URL. If it fails to load, the initials show instead. */
5
+ src?: string;
6
+ /** sm 24px, md 28px, lg 36px.
7
+ * @default "md" */
8
+ size?: "sm" | "md" | "lg";
9
+ /** Give it when the avatar stands alone; beside the name, leave it out and it's hidden from screen readers. */
10
+ label?: string;
11
+ className?: string;
12
+ }
13
+ /** A round picture of a person: their photo, else their initials on the brand colour, else a person icon. */
14
+ export declare function Avatar({ name, src, size, label, className }: AvatarProps): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ export interface AvatarProps {
2
+ /** The person's name; its initials show when there's no image. */
3
+ name: string;
4
+ /** A photo URL. If it fails to load, the initials show instead. */
5
+ src?: string;
6
+ /** sm 24px, md 28px, lg 36px.
7
+ * @default "md" */
8
+ size?: "sm" | "md" | "lg";
9
+ /** Give it when the avatar stands alone; beside the name, leave it out and it's hidden from screen readers. */
10
+ label?: string;
11
+ className?: string;
12
+ }
13
+ /** A round picture of a person: their photo, else their initials on the brand colour, else a person icon. */
14
+ export declare function Avatar({ name, src, size, label, className }: AvatarProps): import("react").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { type ReactNode } from "react";
2
+ import { type AvatarProps } from "./Avatar.cjs";
3
+ export interface AvatarGroupProps {
4
+ /** Avatars. */
5
+ children: ReactNode;
6
+ /** Shows this many, then a "+3" count.
7
+ * @default 4 */
8
+ max?: number;
9
+ /** Applied to every avatar in the group.
10
+ * @default "md" */
11
+ size?: AvatarProps["size"];
12
+ /** Names the group for screen readers, e.g. "5 people on this project". */
13
+ label?: string;
14
+ className?: string;
15
+ }
16
+ /** Overlapping avatars for the people on something, with a count for the rest. */
17
+ export declare function AvatarGroup({ children, max, size, label, className }: AvatarGroupProps): import("react").JSX.Element;
18
+ export interface UserProps {
19
+ name: string;
20
+ /** A second line: an email, a role. */
21
+ description?: ReactNode;
22
+ src?: string;
23
+ /** @default "md" */
24
+ size?: AvatarProps["size"];
25
+ className?: string;
26
+ }
27
+ /** A person: avatar, name and a line about them, as in an account menu. */
28
+ export declare function User({ name, description, src, size, className }: UserProps): import("react").JSX.Element;
@@ -0,0 +1,28 @@
1
+ import { type ReactNode } from "react";
2
+ import { type AvatarProps } from "./Avatar.js";
3
+ export interface AvatarGroupProps {
4
+ /** Avatars. */
5
+ children: ReactNode;
6
+ /** Shows this many, then a "+3" count.
7
+ * @default 4 */
8
+ max?: number;
9
+ /** Applied to every avatar in the group.
10
+ * @default "md" */
11
+ size?: AvatarProps["size"];
12
+ /** Names the group for screen readers, e.g. "5 people on this project". */
13
+ label?: string;
14
+ className?: string;
15
+ }
16
+ /** Overlapping avatars for the people on something, with a count for the rest. */
17
+ export declare function AvatarGroup({ children, max, size, label, className }: AvatarGroupProps): import("react").JSX.Element;
18
+ export interface UserProps {
19
+ name: string;
20
+ /** A second line: an email, a role. */
21
+ description?: ReactNode;
22
+ src?: string;
23
+ /** @default "md" */
24
+ size?: AvatarProps["size"];
25
+ className?: string;
26
+ }
27
+ /** A person: avatar, name and a line about them, as in an account menu. */
28
+ export declare function User({ name, description, src, size, className }: UserProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ /** `active` is for work in progress, so it isn't confused with `warning` (something needs you). */
3
+ export type BadgeVariant = "neutral" | "active" | "success" | "warning" | "danger";
4
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
5
+ /** A 12px icon before the text. */
6
+ icon?: ReactNode;
7
+ /** @default "md" */
8
+ size?: "sm" | "md" | "lg";
9
+ /** @default "neutral" */
10
+ variant?: BadgeVariant;
11
+ }
12
+ /** A pill-shaped status label: one or two words, with an optional icon. */
13
+ export declare function Badge({ children, className, icon, size, variant, ...spanProps }: BadgeProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { HTMLAttributes, ReactNode } from "react";
2
+ /** `active` is for work in progress, so it isn't confused with `warning` (something needs you). */
3
+ export type BadgeVariant = "neutral" | "active" | "success" | "warning" | "danger";
4
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
5
+ /** A 12px icon before the text. */
6
+ icon?: ReactNode;
7
+ /** @default "md" */
8
+ size?: "sm" | "md" | "lg";
9
+ /** @default "neutral" */
10
+ variant?: BadgeVariant;
11
+ }
12
+ /** A pill-shaped status label: one or two words, with an optional icon. */
13
+ export declare function Badge({ children, className, icon, size, variant, ...spanProps }: BadgeProps): import("react").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { type AnchorHTMLAttributes, type MouseEvent, type ReactNode } from "react";
2
+ export interface BreadcrumbItem {
3
+ label: ReactNode;
4
+ /** Where it goes. The last item is the current page and isn't a link. */
5
+ href?: string;
6
+ onClick?(event: MouseEvent<HTMLElement>): void;
7
+ }
8
+ export interface BreadcrumbsProps {
9
+ items: BreadcrumbItem[];
10
+ /** @default "chevron" */
11
+ separator?: "chevron" | "slash";
12
+ /** Names the trail for screen readers.
13
+ * @default "Breadcrumb" */
14
+ label?: string;
15
+ className?: string;
16
+ }
17
+ /** Where the current page sits: a trail of links from the top level down. */
18
+ export declare function Breadcrumbs({ items, separator, label, className }: BreadcrumbsProps): import("react").JSX.Element;
19
+ export interface LinkStyleOptions {
20
+ /** `default` underlines in a hairline and turns brass on hover; `muted` is quieter, for footnotes; `standalone` has no underline until hovered, for lists of links.
21
+ * @default "default" */
22
+ variant?: "default" | "muted" | "standalone";
23
+ }
24
+ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, LinkStyleOptions {
25
+ /** Opens in a new tab with an ↗ arrow, for links that leave your site.
26
+ * @default false */
27
+ external?: boolean;
28
+ children?: ReactNode;
29
+ }
30
+ /** The class names of a link, for a router's own <Link>: `<RouterLink className={linkClassName()}>`. */
31
+ export declare function linkClassName({ variant }?: LinkStyleOptions): string;
32
+ /** A text link. Its hover turns brass, the one place brass is text on a light ground. */
33
+ export declare const Link: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1,33 @@
1
+ import { type AnchorHTMLAttributes, type MouseEvent, type ReactNode } from "react";
2
+ export interface BreadcrumbItem {
3
+ label: ReactNode;
4
+ /** Where it goes. The last item is the current page and isn't a link. */
5
+ href?: string;
6
+ onClick?(event: MouseEvent<HTMLElement>): void;
7
+ }
8
+ export interface BreadcrumbsProps {
9
+ items: BreadcrumbItem[];
10
+ /** @default "chevron" */
11
+ separator?: "chevron" | "slash";
12
+ /** Names the trail for screen readers.
13
+ * @default "Breadcrumb" */
14
+ label?: string;
15
+ className?: string;
16
+ }
17
+ /** Where the current page sits: a trail of links from the top level down. */
18
+ export declare function Breadcrumbs({ items, separator, label, className }: BreadcrumbsProps): import("react").JSX.Element;
19
+ export interface LinkStyleOptions {
20
+ /** `default` underlines in a hairline and turns brass on hover; `muted` is quieter, for footnotes; `standalone` has no underline until hovered, for lists of links.
21
+ * @default "default" */
22
+ variant?: "default" | "muted" | "standalone";
23
+ }
24
+ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, LinkStyleOptions {
25
+ /** Opens in a new tab with an ↗ arrow, for links that leave your site.
26
+ * @default false */
27
+ external?: boolean;
28
+ children?: ReactNode;
29
+ }
30
+ /** The class names of a link, for a router's own <Link>: `<RouterLink className={linkClassName()}>`. */
31
+ export declare function linkClassName({ variant }?: LinkStyleOptions): string;
32
+ /** A text link. Its hover turns brass, the one place brass is text on a light ground. */
33
+ export declare const Link: import("react").ForwardRefExoticComponent<LinkProps & import("react").RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1,42 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
3
+ export type ButtonSize = "sm" | "md" | "lg";
4
+ /** `rounded` is the app's 8px corner; `pill` is the marketing site's. */
5
+ export type ButtonShape = "rounded" | "pill";
6
+ export interface ButtonStyleOptions {
7
+ /** primary for the one main action, secondary for the rest, ghost for low-stakes actions, danger for destructive ones.
8
+ * @default "secondary" */
9
+ variant?: ButtonVariant;
10
+ /** sm 32px, md 40px, lg 44px (36, 40 and 46px as pills).
11
+ * @default "md" */
12
+ size?: ButtonSize;
13
+ /** @default "rounded" */
14
+ shape?: ButtonShape;
15
+ /** A square button holding only an icon. Give it an aria-label.
16
+ * @default false */
17
+ iconOnly?: boolean;
18
+ }
19
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonStyleOptions {
20
+ /** An icon before the label, usually a 16px lucide-react icon. */
21
+ startIcon?: ReactNode;
22
+ /** An icon after the label, such as an arrow or a chevron. */
23
+ endIcon?: ReactNode;
24
+ /** Keyboard shortcut shown at the end, e.g. "⌘N". Only pass one that actually works. */
25
+ shortcut?: string;
26
+ /** Shows a spinner in place of the start icon and disables the button, keeping its width.
27
+ * @default false */
28
+ loading?: boolean;
29
+ /** Stretches the button to its container's width.
30
+ * @default false */
31
+ fullWidth?: boolean;
32
+ }
33
+ /**
34
+ * The class names of a button, for things that must be another element: a router <Link>, an <a>.
35
+ * `<Link className={buttonClassName({ variant: "primary" })}>Pricing</Link>`
36
+ */
37
+ export declare function buttonClassName({ variant, size, shape, iconOnly, }?: ButtonStyleOptions): string;
38
+ /**
39
+ * A tactile button: a light top-to-bottom gradient, a highlight along the top edge and a soft shadow,
40
+ * pressed in by a pixel on click.
41
+ */
42
+ export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,42 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
3
+ export type ButtonSize = "sm" | "md" | "lg";
4
+ /** `rounded` is the app's 8px corner; `pill` is the marketing site's. */
5
+ export type ButtonShape = "rounded" | "pill";
6
+ export interface ButtonStyleOptions {
7
+ /** primary for the one main action, secondary for the rest, ghost for low-stakes actions, danger for destructive ones.
8
+ * @default "secondary" */
9
+ variant?: ButtonVariant;
10
+ /** sm 32px, md 40px, lg 44px (36, 40 and 46px as pills).
11
+ * @default "md" */
12
+ size?: ButtonSize;
13
+ /** @default "rounded" */
14
+ shape?: ButtonShape;
15
+ /** A square button holding only an icon. Give it an aria-label.
16
+ * @default false */
17
+ iconOnly?: boolean;
18
+ }
19
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonStyleOptions {
20
+ /** An icon before the label, usually a 16px lucide-react icon. */
21
+ startIcon?: ReactNode;
22
+ /** An icon after the label, such as an arrow or a chevron. */
23
+ endIcon?: ReactNode;
24
+ /** Keyboard shortcut shown at the end, e.g. "⌘N". Only pass one that actually works. */
25
+ shortcut?: string;
26
+ /** Shows a spinner in place of the start icon and disables the button, keeping its width.
27
+ * @default false */
28
+ loading?: boolean;
29
+ /** Stretches the button to its container's width.
30
+ * @default false */
31
+ fullWidth?: boolean;
32
+ }
33
+ /**
34
+ * The class names of a button, for things that must be another element: a router <Link>, an <a>.
35
+ * `<Link className={buttonClassName({ variant: "primary" })}>Pricing</Link>`
36
+ */
37
+ export declare function buttonClassName({ variant, size, shape, iconOnly, }?: ButtonStyleOptions): string;
38
+ /**
39
+ * A tactile button: a light top-to-bottom gradient, a highlight along the top edge and a soft shadow,
40
+ * pressed in by a pixel on click.
41
+ */
42
+ export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,33 @@
1
+ import { type ButtonHTMLAttributes, type HTMLAttributes } from "react";
2
+ import { type ButtonProps } from "./Button.cjs";
3
+ export interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement> {
4
+ /** Joins the buttons into one control with shared borders. Off, they sit 8px apart.
5
+ * @default true */
6
+ attached?: boolean;
7
+ /** @default "horizontal" */
8
+ orientation?: "horizontal" | "vertical";
9
+ }
10
+ /** Buttons that belong together: a toolbar's actions, or a split choice like "Day · Week · Month". */
11
+ export declare function ButtonGroup({ attached, orientation, className, ...props }: ButtonGroupProps): import("react").JSX.Element;
12
+ export interface CloseButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
13
+ /** sm 24px for toasts and tags, md 32px for dialogs and panels.
14
+ * @default "md" */
15
+ size?: "sm" | "md";
16
+ /** What it closes, for screen readers.
17
+ * @default "Close" */
18
+ label?: string;
19
+ }
20
+ /** The ✕ in a dialog, drawer or panel header. */
21
+ export declare const CloseButton: import("react").ForwardRefExoticComponent<CloseButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
22
+ export interface ToggleButtonProps extends Omit<ButtonProps, "variant"> {
23
+ /** Whether it's on. Leave out to let the button keep its own state. */
24
+ pressed?: boolean;
25
+ /** The starting state when uncontrolled.
26
+ * @default false */
27
+ defaultPressed?: boolean;
28
+ onPressedChange?(pressed: boolean): void;
29
+ /** @default "secondary" */
30
+ variant?: "secondary" | "ghost";
31
+ }
32
+ /** A button that stays pressed in while something is on: bold text, a filter, a view mode. */
33
+ export declare const ToggleButton: import("react").ForwardRefExoticComponent<ToggleButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,33 @@
1
+ import { type ButtonHTMLAttributes, type HTMLAttributes } from "react";
2
+ import { type ButtonProps } from "./Button.js";
3
+ export interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement> {
4
+ /** Joins the buttons into one control with shared borders. Off, they sit 8px apart.
5
+ * @default true */
6
+ attached?: boolean;
7
+ /** @default "horizontal" */
8
+ orientation?: "horizontal" | "vertical";
9
+ }
10
+ /** Buttons that belong together: a toolbar's actions, or a split choice like "Day · Week · Month". */
11
+ export declare function ButtonGroup({ attached, orientation, className, ...props }: ButtonGroupProps): import("react").JSX.Element;
12
+ export interface CloseButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
13
+ /** sm 24px for toasts and tags, md 32px for dialogs and panels.
14
+ * @default "md" */
15
+ size?: "sm" | "md";
16
+ /** What it closes, for screen readers.
17
+ * @default "Close" */
18
+ label?: string;
19
+ }
20
+ /** The ✕ in a dialog, drawer or panel header. */
21
+ export declare const CloseButton: import("react").ForwardRefExoticComponent<CloseButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
22
+ export interface ToggleButtonProps extends Omit<ButtonProps, "variant"> {
23
+ /** Whether it's on. Leave out to let the button keep its own state. */
24
+ pressed?: boolean;
25
+ /** The starting state when uncontrolled.
26
+ * @default false */
27
+ defaultPressed?: boolean;
28
+ onPressedChange?(pressed: boolean): void;
29
+ /** @default "secondary" */
30
+ variant?: "secondary" | "ghost";
31
+ }
32
+ /** A button that stays pressed in while something is on: bold text, a filter, a view mode. */
33
+ export declare const ToggleButton: import("react").ForwardRefExoticComponent<ToggleButtonProps & import("react").RefAttributes<HTMLButtonElement>>;