@nibapp/ui 0.0.0-stage → 0.1.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.
Files changed (292) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +21 -0
  3. package/README.md +124 -2
  4. package/TRADEMARKS.md +22 -0
  5. package/dist/_bundled/money/index.d.ts +98 -0
  6. package/dist/_bundled/money/index.js +152 -0
  7. package/dist/_bundled/tokens/index.d.ts +2 -0
  8. package/dist/_bundled/tokens/index.js +2 -0
  9. package/dist/_bundled/tokens/palette.gen.d.ts +51 -0
  10. package/dist/_bundled/tokens/palette.gen.js +206 -0
  11. package/dist/_bundled/tokens/spec.d.ts +291 -0
  12. package/dist/_bundled/tokens/spec.js +221 -0
  13. package/dist/components/accordion.d.ts +27 -0
  14. package/dist/components/accordion.js +66 -0
  15. package/dist/components/alert-dialog.d.ts +59 -0
  16. package/dist/components/alert-dialog.js +82 -0
  17. package/dist/components/alert.d.ts +141 -0
  18. package/dist/components/alert.js +55 -0
  19. package/dist/components/appear.d.ts +21 -0
  20. package/dist/components/appear.js +42 -0
  21. package/dist/components/avatar.d.ts +196 -0
  22. package/dist/components/avatar.js +135 -0
  23. package/dist/components/badge.d.ts +183 -0
  24. package/dist/components/badge.js +68 -0
  25. package/dist/components/block-stack.d.ts +33 -0
  26. package/dist/components/block-stack.js +197 -0
  27. package/dist/components/button.d.ts +327 -0
  28. package/dist/components/button.js +101 -0
  29. package/dist/components/card.d.ts +131 -0
  30. package/dist/components/card.js +100 -0
  31. package/dist/components/checkbox.d.ts +34 -0
  32. package/dist/components/checkbox.js +37 -0
  33. package/dist/components/choice-row.d.ts +104 -0
  34. package/dist/components/choice-row.js +56 -0
  35. package/dist/components/clamped-text.d.ts +17 -0
  36. package/dist/components/clamped-text.js +47 -0
  37. package/dist/components/code-block.d.ts +48 -0
  38. package/dist/components/code-block.js +124 -0
  39. package/dist/components/code-input.d.ts +49 -0
  40. package/dist/components/code-input.js +59 -0
  41. package/dist/components/combobox.d.ts +194 -0
  42. package/dist/components/combobox.js +176 -0
  43. package/dist/components/command-palette.d.ts +57 -0
  44. package/dist/components/command-palette.js +83 -0
  45. package/dist/components/context-menu.d.ts +24 -0
  46. package/dist/components/context-menu.js +30 -0
  47. package/dist/components/copy-button.d.ts +9 -0
  48. package/dist/components/copy-button.js +20 -0
  49. package/dist/components/copy-command.d.ts +18 -0
  50. package/dist/components/copy-command.js +19 -0
  51. package/dist/components/data-table.d.ts +240 -0
  52. package/dist/components/data-table.js +63 -0
  53. package/dist/components/dialog.d.ts +80 -0
  54. package/dist/components/dialog.js +85 -0
  55. package/dist/components/diff-lines.d.ts +20 -0
  56. package/dist/components/diff-lines.js +10 -0
  57. package/dist/components/diff-view.d.ts +128 -0
  58. package/dist/components/diff-view.js +675 -0
  59. package/dist/components/disclosure.d.ts +33 -0
  60. package/dist/components/disclosure.js +51 -0
  61. package/dist/components/drawn-check.d.ts +8 -0
  62. package/dist/components/drawn-check.js +16 -0
  63. package/dist/components/edge-resizer.d.ts +26 -0
  64. package/dist/components/edge-resizer.js +53 -0
  65. package/dist/components/empty-state.d.ts +112 -0
  66. package/dist/components/empty-state.js +56 -0
  67. package/dist/components/expand-toggle.d.ts +19 -0
  68. package/dist/components/expand-toggle.js +10 -0
  69. package/dist/components/field.d.ts +48 -0
  70. package/dist/components/field.js +60 -0
  71. package/dist/components/filter-chip.d.ts +47 -0
  72. package/dist/components/filter-chip.js +33 -0
  73. package/dist/components/group.d.ts +10 -0
  74. package/dist/components/group.js +9 -0
  75. package/dist/components/icon-text.d.ts +11 -0
  76. package/dist/components/icon-text.js +10 -0
  77. package/dist/components/image-sources.d.ts +57 -0
  78. package/dist/components/image-sources.js +58 -0
  79. package/dist/components/image-thumbnail.d.ts +34 -0
  80. package/dist/components/image-thumbnail.js +58 -0
  81. package/dist/components/image-viewer.d.ts +60 -0
  82. package/dist/components/image-viewer.js +411 -0
  83. package/dist/components/inline-edit.d.ts +22 -0
  84. package/dist/components/inline-edit.js +51 -0
  85. package/dist/components/input.d.ts +155 -0
  86. package/dist/components/input.js +109 -0
  87. package/dist/components/item-label.d.ts +11 -0
  88. package/dist/components/item-label.js +5 -0
  89. package/dist/components/item-row.d.ts +23 -0
  90. package/dist/components/item-row.js +19 -0
  91. package/dist/components/kbd.d.ts +55 -0
  92. package/dist/components/kbd.js +86 -0
  93. package/dist/components/link-policy.d.ts +24 -0
  94. package/dist/components/link-policy.js +32 -0
  95. package/dist/components/linked-text.d.ts +15 -0
  96. package/dist/components/linked-text.js +48 -0
  97. package/dist/components/loading-region.d.ts +18 -0
  98. package/dist/components/loading-region.js +17 -0
  99. package/dist/components/markdown.d.ts +34 -0
  100. package/dist/components/markdown.js +307 -0
  101. package/dist/components/menu.d.ts +132 -0
  102. package/dist/components/menu.js +102 -0
  103. package/dist/components/message-bubble.d.ts +57 -0
  104. package/dist/components/message-bubble.js +28 -0
  105. package/dist/components/meta-line.d.ts +28 -0
  106. package/dist/components/meta-line.js +36 -0
  107. package/dist/components/money-input.d.ts +23 -0
  108. package/dist/components/money-input.js +34 -0
  109. package/dist/components/native-select.d.ts +120 -0
  110. package/dist/components/native-select.js +85 -0
  111. package/dist/components/page-trail.d.ts +30 -0
  112. package/dist/components/page-trail.js +43 -0
  113. package/dist/components/page.d.ts +80 -0
  114. package/dist/components/page.js +60 -0
  115. package/dist/components/path-text.d.ts +8 -0
  116. package/dist/components/path-text.js +11 -0
  117. package/dist/components/percent-input.d.ts +20 -0
  118. package/dist/components/percent-input.js +32 -0
  119. package/dist/components/popover.d.ts +52 -0
  120. package/dist/components/popover.js +36 -0
  121. package/dist/components/progress.d.ts +389 -0
  122. package/dist/components/progress.js +142 -0
  123. package/dist/components/radio.d.ts +65 -0
  124. package/dist/components/radio.js +54 -0
  125. package/dist/components/remote-image-gate.d.ts +34 -0
  126. package/dist/components/remote-image-gate.js +60 -0
  127. package/dist/components/resizable.d.ts +23 -0
  128. package/dist/components/resizable.js +30 -0
  129. package/dist/components/rolling-number.d.ts +13 -0
  130. package/dist/components/rolling-number.js +69 -0
  131. package/dist/components/scroll-area.d.ts +17 -0
  132. package/dist/components/scroll-area.js +25 -0
  133. package/dist/components/section-label.d.ts +10 -0
  134. package/dist/components/section-label.js +21 -0
  135. package/dist/components/section-nav.d.ts +22 -0
  136. package/dist/components/section-nav.js +80 -0
  137. package/dist/components/segmented-control.d.ts +125 -0
  138. package/dist/components/segmented-control.js +101 -0
  139. package/dist/components/select.d.ts +120 -0
  140. package/dist/components/select.js +89 -0
  141. package/dist/components/separator.d.ts +10 -0
  142. package/dist/components/separator.js +12 -0
  143. package/dist/components/sheet.d.ts +101 -0
  144. package/dist/components/sheet.js +129 -0
  145. package/dist/components/shortcut-recorder.d.ts +31 -0
  146. package/dist/components/shortcut-recorder.js +67 -0
  147. package/dist/components/skeleton.d.ts +31 -0
  148. package/dist/components/skeleton.js +33 -0
  149. package/dist/components/slider.d.ts +138 -0
  150. package/dist/components/slider.js +98 -0
  151. package/dist/components/spinner.d.ts +37 -0
  152. package/dist/components/spinner.js +16 -0
  153. package/dist/components/switch.d.ts +59 -0
  154. package/dist/components/switch.js +56 -0
  155. package/dist/components/tab-strip.d.ts +29 -0
  156. package/dist/components/tab-strip.js +42 -0
  157. package/dist/components/tabs.d.ts +13 -0
  158. package/dist/components/tabs.js +68 -0
  159. package/dist/components/text-link.d.ts +54 -0
  160. package/dist/components/text-link.js +38 -0
  161. package/dist/components/textarea.d.ts +75 -0
  162. package/dist/components/textarea.js +90 -0
  163. package/dist/components/toast.d.ts +74 -0
  164. package/dist/components/toast.js +128 -0
  165. package/dist/components/tooltip.d.ts +50 -0
  166. package/dist/components/tooltip.js +46 -0
  167. package/dist/components/truncated-text.d.ts +15 -0
  168. package/dist/components/truncated-text.js +19 -0
  169. package/dist/i18n/defaults.d.ts +7 -0
  170. package/dist/i18n/defaults.js +7 -0
  171. package/dist/i18n/format.d.ts +84 -0
  172. package/dist/i18n/format.js +169 -0
  173. package/dist/i18n/index.d.ts +6 -0
  174. package/dist/i18n/index.js +8 -0
  175. package/dist/i18n/locales/ru-formatters.d.ts +3 -0
  176. package/dist/i18n/locales/ru-formatters.js +22 -0
  177. package/dist/i18n/locales/ru.d.ts +5 -0
  178. package/dist/i18n/locales/ru.js +185 -0
  179. package/dist/i18n/plural.d.ts +20 -0
  180. package/dist/i18n/plural.js +26 -0
  181. package/dist/i18n/provider.d.ts +36 -0
  182. package/dist/i18n/provider.js +39 -0
  183. package/dist/i18n/rich.d.ts +14 -0
  184. package/dist/i18n/rich.js +44 -0
  185. package/dist/i18n/ru-plural.d.ts +3 -0
  186. package/dist/i18n/ru-plural.js +4 -0
  187. package/dist/i18n/strings/alert-dialog.d.ts +5 -0
  188. package/dist/i18n/strings/alert-dialog.js +5 -0
  189. package/dist/i18n/strings/block-stack.d.ts +17 -0
  190. package/dist/i18n/strings/block-stack.js +11 -0
  191. package/dist/i18n/strings/code-block.d.ts +18 -0
  192. package/dist/i18n/strings/code-block.js +13 -0
  193. package/dist/i18n/strings/combobox.d.ts +12 -0
  194. package/dist/i18n/strings/combobox.js +10 -0
  195. package/dist/i18n/strings/command-palette.d.ts +17 -0
  196. package/dist/i18n/strings/command-palette.js +11 -0
  197. package/dist/i18n/strings/diff-view.d.ts +92 -0
  198. package/dist/i18n/strings/diff-view.js +68 -0
  199. package/dist/i18n/strings/image-viewer.d.ts +43 -0
  200. package/dist/i18n/strings/image-viewer.js +32 -0
  201. package/dist/i18n/strings/index.d.ts +314 -0
  202. package/dist/i18n/strings/index.js +43 -0
  203. package/dist/i18n/strings/kbd.d.ts +42 -0
  204. package/dist/i18n/strings/kbd.js +39 -0
  205. package/dist/i18n/strings/markdown.d.ts +23 -0
  206. package/dist/i18n/strings/markdown.js +18 -0
  207. package/dist/i18n/strings/money.d.ts +7 -0
  208. package/dist/i18n/strings/money.js +5 -0
  209. package/dist/i18n/strings/primitives.d.ts +25 -0
  210. package/dist/i18n/strings/primitives.js +18 -0
  211. package/dist/i18n/strings/progress.d.ts +4 -0
  212. package/dist/i18n/strings/progress.js +4 -0
  213. package/dist/i18n/strings/shortcut-recorder.d.ts +15 -0
  214. package/dist/i18n/strings/shortcut-recorder.js +11 -0
  215. package/dist/i18n/strings/time.d.ts +41 -0
  216. package/dist/i18n/strings/time.js +20 -0
  217. package/dist/i18n/strings/toast.d.ts +6 -0
  218. package/dist/i18n/strings/toast.js +6 -0
  219. package/dist/i18n/time-zones.d.ts +20 -0
  220. package/dist/i18n/time-zones.js +64 -0
  221. package/dist/index.d.ts +84 -0
  222. package/dist/index.js +88 -0
  223. package/dist/lib/ansi.d.ts +55 -0
  224. package/dist/lib/ansi.js +438 -0
  225. package/dist/lib/clock.d.ts +32 -0
  226. package/dist/lib/clock.js +106 -0
  227. package/dist/lib/cn.d.ts +12 -0
  228. package/dist/lib/cn.js +28 -0
  229. package/dist/lib/control-props.d.ts +21 -0
  230. package/dist/lib/control-props.js +14 -0
  231. package/dist/lib/direction.d.ts +13 -0
  232. package/dist/lib/direction.js +25 -0
  233. package/dist/lib/image-size.d.ts +12 -0
  234. package/dist/lib/image-size.js +66 -0
  235. package/dist/lib/keycaps.d.ts +21 -0
  236. package/dist/lib/keycaps.js +62 -0
  237. package/dist/lib/keyed.d.ts +9 -0
  238. package/dist/lib/keyed.js +14 -0
  239. package/dist/lib/keys.d.ts +49 -0
  240. package/dist/lib/keys.js +159 -0
  241. package/dist/lib/kit-motion.d.ts +9 -0
  242. package/dist/lib/kit-motion.js +12 -0
  243. package/dist/lib/link-check-dialog.d.ts +11 -0
  244. package/dist/lib/link-check-dialog.js +18 -0
  245. package/dist/lib/motion-features.d.ts +1 -0
  246. package/dist/lib/motion-features.js +4 -0
  247. package/dist/lib/motion-provider.d.ts +5 -0
  248. package/dist/lib/motion-provider.js +8 -0
  249. package/dist/lib/motion.d.ts +39 -0
  250. package/dist/lib/motion.js +49 -0
  251. package/dist/lib/number-format.d.ts +114 -0
  252. package/dist/lib/number-format.js +313 -0
  253. package/dist/lib/patch.d.ts +72 -0
  254. package/dist/lib/patch.js +344 -0
  255. package/dist/lib/path.d.ts +34 -0
  256. package/dist/lib/path.js +85 -0
  257. package/dist/lib/search.d.ts +10 -0
  258. package/dist/lib/search.js +20 -0
  259. package/dist/lib/shiki-themes.d.ts +7 -0
  260. package/dist/lib/shiki-themes.js +115 -0
  261. package/dist/lib/shiki.d.ts +101 -0
  262. package/dist/lib/shiki.js +353 -0
  263. package/dist/lib/shortcut-context.d.ts +23 -0
  264. package/dist/lib/shortcut-context.js +29 -0
  265. package/dist/lib/text.d.ts +56 -0
  266. package/dist/lib/text.js +149 -0
  267. package/dist/lib/theme-scope.d.ts +18 -0
  268. package/dist/lib/theme-scope.js +24 -0
  269. package/dist/lib/theme.d.ts +40 -0
  270. package/dist/lib/theme.js +96 -0
  271. package/dist/lib/tree-keys.d.ts +72 -0
  272. package/dist/lib/tree-keys.js +126 -0
  273. package/dist/lib/url.d.ts +17 -0
  274. package/dist/lib/url.js +38 -0
  275. package/dist/lib/use-copy-to-clipboard.d.ts +13 -0
  276. package/dist/lib/use-copy-to-clipboard.js +40 -0
  277. package/dist/lib/use-delayed-loading.d.ts +11 -0
  278. package/dist/lib/use-delayed-loading.js +31 -0
  279. package/dist/lib/use-file-picker.d.ts +26 -0
  280. package/dist/lib/use-file-picker.js +43 -0
  281. package/dist/lib/use-hydrated.d.ts +6 -0
  282. package/dist/lib/use-hydrated.js +11 -0
  283. package/dist/lib/use-latest.d.ts +12 -0
  284. package/dist/lib/use-latest.js +22 -0
  285. package/dist/lib/use-resolved-theme.d.ts +12 -0
  286. package/dist/lib/use-resolved-theme.js +25 -0
  287. package/dist/styles/base.css +393 -0
  288. package/dist/styles/code.css +35 -0
  289. package/dist/styles/fonts.css +12 -0
  290. package/dist/styles/index.css +13 -0
  291. package/dist/styles/tokens.gen.css +494 -0
  292. package/package.json +208 -4
@@ -0,0 +1,57 @@
1
+ import { Command } from "cmdk";
2
+ import { type ComponentProps, type ReactNode } from "react";
3
+ export interface UseCommandPaletteOptions {
4
+ /** Key pressed with ⌘ (macOS) or Ctrl (elsewhere). Defaults to `"k"`. */
5
+ hotkey?: string;
6
+ /** Turn the global listener off (e.g. while another modal owns the keyboard). */
7
+ enabled?: boolean;
8
+ defaultOpen?: boolean;
9
+ }
10
+ /** Open state for a CommandPalette plus a global ⌘K / Ctrl+K toggle. Spread `bind` onto the palette. */
11
+ export declare function useCommandPalette({ hotkey, enabled, defaultOpen, }?: UseCommandPaletteOptions): {
12
+ open: boolean;
13
+ setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
14
+ toggle: () => void;
15
+ bind: {
16
+ open: boolean;
17
+ onOpenChange: import("react").Dispatch<import("react").SetStateAction<boolean>>;
18
+ };
19
+ };
20
+ export interface CommandPaletteProps {
21
+ open: boolean;
22
+ onOpenChange: (open: boolean) => void;
23
+ /** Groups / items / separators. */
24
+ children: ReactNode;
25
+ placeholder?: string;
26
+ /** Accessible name for the dialog and listbox. */
27
+ label?: string;
28
+ /** Shows a spinner in the input and a loading row in the list (async results). */
29
+ loading?: boolean;
30
+ /** Controlled query (e.g. to fetch async results); cleared when the palette closes. */
31
+ search?: string;
32
+ onSearchChange?: (search: string) => void;
33
+ /** Disable cmdk's built-in fuzzy filter when results are filtered server-side. */
34
+ shouldFilter?: boolean;
35
+ /** Custom empty state; receives the current query. */
36
+ empty?: (search: string) => ReactNode;
37
+ /** Left side of the footer (e.g. the current workspace). */
38
+ footer?: ReactNode;
39
+ className?: string;
40
+ }
41
+ /** Raycast-style launcher: big search, grouped results, keyboard hints. Pair with `useCommandPalette`. */
42
+ export declare function CommandPalette({ open, onOpenChange, children, placeholder, label: labelProp, loading, search: searchProp, onSearchChange, shouldFilter, empty, footer, className, }: CommandPaletteProps): import("react").JSX.Element;
43
+ export type CommandPaletteGroupProps = ComponentProps<typeof Command.Group>;
44
+ /** Titled section; pass `heading`. Hidden automatically when none of its items match. */
45
+ export declare function CommandPaletteGroup(props: CommandPaletteGroupProps): import("react").JSX.Element;
46
+ export declare function CommandPaletteSeparator({ className, ...props }: ComponentProps<typeof Command.Separator>): import("react").JSX.Element;
47
+ export interface CommandPaletteItemProps extends Omit<ComponentProps<typeof Command.Item>, "children"> {
48
+ children: ReactNode;
49
+ icon?: ReactNode;
50
+ /** Secondary line (path, model id, hint). */
51
+ description?: ReactNode;
52
+ /** Logical keys, e.g. `["mod", "n"]`. */
53
+ shortcut?: readonly string[];
54
+ /** Trailing adornment (badge, "Jump to" hint…). */
55
+ trailing?: ReactNode;
56
+ }
57
+ export declare function CommandPaletteItem({ icon, description, shortcut, trailing, onSelect, className, children, ...props }: CommandPaletteItemProps): import("react").JSX.Element;
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Dialog as BaseDialog } from "@base-ui/react/dialog";
4
+ import { Command } from "cmdk";
5
+ import { SearchIcon } from "lucide-react";
6
+ import { createContext, use, useCallback, useEffect, useMemo, useRef, useState, } from "react";
7
+ import { useUiStrings } from "../i18n/provider.js";
8
+ import { cn } from "../lib/cn.js";
9
+ import { keyShortcutsProps } from "../lib/keys.js";
10
+ import { usePortalContainer } from "../lib/theme-scope.js";
11
+ import { dialogBackdropClass, dialogPopupStyles, dialogViewportClass } from "./dialog.js";
12
+ import { Kbd, Shortcut } from "./kbd.js";
13
+ import { Spinner } from "./spinner.js";
14
+ /** Open state for a CommandPalette plus a global ⌘K / Ctrl+K toggle. Spread `bind` onto the palette. */
15
+ export function useCommandPalette({ hotkey = "k", enabled = true, defaultOpen = false, } = {}) {
16
+ const [open, setOpen] = useState(defaultOpen);
17
+ const toggle = useCallback(() => setOpen((o) => !o), []);
18
+ useEffect(() => {
19
+ if (!enabled)
20
+ return undefined;
21
+ const key = hotkey.toLowerCase();
22
+ const onKeyDown = (event) => {
23
+ if (event.defaultPrevented || event.repeat)
24
+ return;
25
+ if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey)
26
+ return;
27
+ if (event.key.toLowerCase() !== key)
28
+ return;
29
+ event.preventDefault();
30
+ setOpen((o) => !o);
31
+ };
32
+ window.addEventListener("keydown", onKeyDown);
33
+ return () => window.removeEventListener("keydown", onKeyDown);
34
+ }, [hotkey, enabled]);
35
+ const bind = useMemo(() => ({ open, onOpenChange: setOpen }), [open]);
36
+ return { open, setOpen, toggle, bind };
37
+ }
38
+ /* ------------------------------------------------------------------------------------------ */
39
+ /* Palette */
40
+ /* ------------------------------------------------------------------------------------------ */
41
+ const PaletteContext = createContext({ close: () => undefined });
42
+ /** Raycast-style launcher: big search, grouped results, keyboard hints. Pair with `useCommandPalette`. */
43
+ export function CommandPalette({ open, onOpenChange, children, placeholder, label: labelProp, loading = false, search: searchProp, onSearchChange, shouldFilter, empty, footer, className, }) {
44
+ const container = usePortalContainer();
45
+ const t = useUiStrings().commandPalette;
46
+ const keys = useUiStrings().kbd.keys;
47
+ const label = labelProp ?? t.label;
48
+ const [uncontrolledSearch, setUncontrolledSearch] = useState("");
49
+ const search = searchProp ?? uncontrolledSearch;
50
+ const inputRef = useRef(null);
51
+ const listRef = useRef(null);
52
+ const setSearch = (next) => {
53
+ if (searchProp === undefined)
54
+ setUncontrolledSearch(next);
55
+ onSearchChange?.(next);
56
+ };
57
+ const context = useMemo(() => ({ close: () => onOpenChange(false) }), [onOpenChange]);
58
+ return (_jsx(BaseDialog.Root, { open: open, onOpenChange: (next) => onOpenChange(next), onOpenChangeComplete: (isOpen) => {
59
+ if (!isOpen)
60
+ setSearch("");
61
+ }, children: _jsxs(BaseDialog.Portal, { container: container, children: [_jsx(BaseDialog.Backdrop, { "data-slot": "command-palette-backdrop", className: dialogBackdropClass }), _jsx(BaseDialog.Viewport, { className: dialogViewportClass, children: _jsxs(BaseDialog.Popup, { "data-slot": "command-palette", initialFocus: inputRef, className: cn(dialogPopupStyles({ size: "lg" }), "mt-[min(12vh,7rem)] mb-auto max-w-[640px] overflow-hidden", className), children: [_jsx(BaseDialog.Title, { className: "sr-only", children: label }), _jsx(PaletteContext, { value: context, children: _jsxs(Command, { label: label, loop: true, vimBindings: false, ...(shouldFilter !== undefined && { shouldFilter }), className: "flex min-h-0 flex-col", children: [_jsxs("div", { className: "flex h-14 shrink-0 items-center gap-3 border-b border-border-subtle px-4", children: [_jsx(SearchIcon, { "aria-hidden": true, className: "size-[18px] shrink-0 text-fg-subtle" }), _jsx(Command.Input, { ref: inputRef, value: search, onValueChange: (value) => {
62
+ setSearch(value);
63
+ // New query → start from the top of the list.
64
+ listRef.current?.scrollTo({ top: 0 });
65
+ }, placeholder: placeholder ?? t.placeholder, className: "h-full min-w-0 flex-1 bg-transparent text-md text-fg outline-none placeholder:text-fg-faint" }), loading ? (_jsx(Spinner, { size: "md", className: "text-fg-subtle" })) : (_jsx(Kbd, { size: "md", className: "shrink-0", children: keys.esc }))] }), _jsxs(Command.List, { ref: listRef, label: label, className: cn("max-h-[min(440px,58vh)] scroll-py-2 overflow-y-auto overscroll-contain p-2", "[&_[cmdk-group]+[cmdk-group]]:mt-1", "[&_[cmdk-group-heading]]:flex [&_[cmdk-group-heading]]:h-7 [&_[cmdk-group-heading]]:select-none [&_[cmdk-group-heading]]:items-center", "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-fg-subtle"), children: [loading && (_jsx(Command.Loading, { label: t.loadingResults, children: _jsxs("div", { className: "flex h-10 items-center gap-3 px-3 text-sm text-fg-subtle", children: [_jsx(Spinner, { size: "sm" }), t.searching] }) })), !loading && (_jsx(Command.Empty, { children: empty ? (empty(search)) : (_jsxs("div", { className: "flex flex-col items-center gap-1 px-6 py-10 text-center", children: [_jsx(SearchIcon, { "aria-hidden": true, className: "mb-2 size-5 text-fg-faint" }), _jsx("p", { className: "text-base text-fg", children: t.noResults }), _jsx("p", { className: "max-w-full truncate text-sm text-fg-subtle", children: t.nothingMatches({ query: search }) })] })) })), children] }), _jsxs("div", { className: "flex h-10 shrink-0 items-center gap-4 border-t border-border-subtle bg-bg-subtle/60 px-4 text-xs text-fg-subtle", children: [_jsx("div", { className: "min-w-0 flex-1 truncate", children: footer }), _jsx(FooterHint, { keys: ["up", "down"], label: t.hints.navigate }), _jsx(FooterHint, { keys: ["enter"], label: t.hints.select }), _jsx(FooterHint, { keys: ["esc"], label: t.hints.close })] })] }) })] }) })] }) }));
66
+ }
67
+ function FooterHint({ keys, label }) {
68
+ return (_jsxs("span", { className: "flex shrink-0 items-center gap-1.5", children: [_jsx(Shortcut, { keys: keys, size: "sm", spoken: true, className: "gap-0.5" }), _jsx("span", { children: label })] }));
69
+ }
70
+ /** Titled section; pass `heading`. Hidden automatically when none of its items match. */
71
+ export function CommandPaletteGroup(props) {
72
+ return _jsx(Command.Group, { "data-slot": "command-palette-group", ...props });
73
+ }
74
+ export function CommandPaletteSeparator({ className, ...props }) {
75
+ return (_jsx(Command.Separator, { "data-slot": "command-palette-separator", className: cn("-mx-2 my-1.5 h-px bg-border-subtle", className), ...props }));
76
+ }
77
+ export function CommandPaletteItem({ icon, description, shortcut, trailing, onSelect, className, children, ...props }) {
78
+ const { close } = use(PaletteContext);
79
+ return (_jsxs(Command.Item, { "data-slot": "command-palette-item", ...keyShortcutsProps(shortcut), onSelect: (value) => {
80
+ onSelect?.(value);
81
+ close();
82
+ }, className: cn("group/cmd relative flex min-h-10 cursor-default select-none items-center gap-3 rounded-lg px-3 text-base text-fg outline-none", "transition-colors duration-(--duration-instant) ease-(--ease-standard)", "data-[selected=true]:bg-hover data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-45", className), ...props, children: [icon !== undefined && (_jsx("span", { "aria-hidden": true, className: "flex size-4 shrink-0 items-center justify-center text-fg-subtle transition-colors duration-(--duration-instant) group-data-[selected=true]/cmd:text-fg [&_svg]:size-4", children: icon })), description === undefined ? (_jsx("span", { className: "min-w-0 flex-1 truncate", children: children })) : (_jsxs("span", { className: "flex min-w-0 flex-1 items-baseline gap-2 py-2", children: [_jsx("span", { className: "shrink-0 truncate", children: children }), _jsx("span", { className: "min-w-0 truncate text-sm text-fg-subtle", children: description })] })), trailing, shortcut && _jsx(Shortcut, { keys: shortcut, size: "md", className: "ms-auto shrink-0 ps-3" })] }));
83
+ }
@@ -0,0 +1,24 @@
1
+ import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
2
+ import type { ComponentProps, ReactNode } from "react";
3
+ export { MenuCheckboxItem as ContextMenuCheckboxItem, MenuGroup as ContextMenuGroup, MenuGroupLabel as ContextMenuGroupLabel, MenuItem as ContextMenuItem, MenuLinkItem as ContextMenuLinkItem, MenuRadioGroup as ContextMenuRadioGroup, MenuRadioItem as ContextMenuRadioItem, MenuSeparator as ContextMenuSeparator, MenuSubmenuRoot as ContextMenuSubmenuRoot, MenuSubmenuTrigger as ContextMenuSubmenuTrigger, } from "./menu.js";
4
+ export declare const ContextMenuRoot: typeof BaseContextMenu.Root;
5
+ /** The area that opens the menu on right-click / long-press. Renders a `<div>`. */
6
+ export declare function ContextMenuTrigger({ className, ...props }: ComponentProps<typeof BaseContextMenu.Trigger>): import("react").JSX.Element;
7
+ export interface ContextMenuContentProps extends ComponentProps<typeof BaseContextMenu.Popup> {
8
+ positionerProps?: ComponentProps<typeof BaseContextMenu.Positioner>;
9
+ }
10
+ /** Portal + pointer-anchored positioner + popup. */
11
+ export declare function ContextMenuContent({ positionerProps, className, ...props }: ContextMenuContentProps): import("react").JSX.Element;
12
+ /** Popup for a nested context submenu; overlaps the parent so the first item aligns with the trigger. */
13
+ export declare function ContextMenuSubmenuContent({ positionerProps, className, ...props }: ContextMenuContentProps): import("react").JSX.Element;
14
+ export interface ContextMenuProps {
15
+ /** The region that responds to right-click. */
16
+ children: ReactNode;
17
+ /** Menu items. */
18
+ content: ReactNode;
19
+ /** Class for the trigger region. */
20
+ className?: string;
21
+ disabled?: boolean;
22
+ }
23
+ /** Convenience wrapper: `<ContextMenu content={…items…}><Row/></ContextMenu>`. */
24
+ export declare function ContextMenu({ children, content, className, disabled }: ContextMenuProps): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
4
+ import { withBase } from "../lib/cn.js";
5
+ import { usePortalContainer } from "../lib/theme-scope.js";
6
+ import { menuPopupClass, menuPositionerClass } from "./menu.js";
7
+ /*
8
+ * Context menus share every item part with Menu (Base UI re-exports the same primitives), so
9
+ * items, labels and separators are re-exported from menu.tsx under ContextMenu* names.
10
+ */
11
+ export { MenuCheckboxItem as ContextMenuCheckboxItem, MenuGroup as ContextMenuGroup, MenuGroupLabel as ContextMenuGroupLabel, MenuItem as ContextMenuItem, MenuLinkItem as ContextMenuLinkItem, MenuRadioGroup as ContextMenuRadioGroup, MenuRadioItem as ContextMenuRadioItem, MenuSeparator as ContextMenuSeparator, MenuSubmenuRoot as ContextMenuSubmenuRoot, MenuSubmenuTrigger as ContextMenuSubmenuTrigger, } from "./menu.js";
12
+ export const ContextMenuRoot = BaseContextMenu.Root;
13
+ /** The area that opens the menu on right-click / long-press. Renders a `<div>`. */
14
+ export function ContextMenuTrigger({ className, ...props }) {
15
+ return (_jsx(BaseContextMenu.Trigger, { "data-slot": "context-menu-trigger", className: withBase("select-none", className), ...props }));
16
+ }
17
+ /** Portal + pointer-anchored positioner + popup. */
18
+ export function ContextMenuContent({ positionerProps, className, ...props }) {
19
+ const container = usePortalContainer();
20
+ return (_jsx(BaseContextMenu.Portal, { container: container, children: _jsx(BaseContextMenu.Positioner, { collisionPadding: 8, className: menuPositionerClass, ...positionerProps, children: _jsx(BaseContextMenu.Popup, { "data-slot": "context-menu", className: withBase(menuPopupClass, className), ...props }) }) }));
21
+ }
22
+ /** Popup for a nested context submenu; overlaps the parent so the first item aligns with the trigger. */
23
+ export function ContextMenuSubmenuContent({ positionerProps, className, ...props }) {
24
+ const container = usePortalContainer();
25
+ return (_jsx(BaseContextMenu.Portal, { container: container, children: _jsx(BaseContextMenu.Positioner, { sideOffset: -2, alignOffset: -5, collisionPadding: 8, className: menuPositionerClass, ...positionerProps, children: _jsx(BaseContextMenu.Popup, { "data-slot": "context-menu-submenu", className: withBase(menuPopupClass, className), ...props }) }) }));
26
+ }
27
+ /** Convenience wrapper: `<ContextMenu content={…items…}><Row/></ContextMenu>`. */
28
+ export function ContextMenu({ children, content, className, disabled }) {
29
+ return (_jsxs(BaseContextMenu.Root, { ...(disabled !== undefined && { disabled }), children: [_jsx(ContextMenuTrigger, { className: className, children: children }), _jsx(ContextMenuContent, { children: content })] }));
30
+ }
@@ -0,0 +1,9 @@
1
+ import { type IconButtonProps } from "./button.js";
2
+ export interface CopyButtonProps extends Omit<IconButtonProps, "aria-label" | "children" | "value" | "onClick"> {
3
+ /** Text to copy, or a getter evaluated on click (for large/derived values). */
4
+ value: string | (() => string);
5
+ /** Accessible + tooltip label (default `codeBlock.copy`). */
6
+ label?: string;
7
+ }
8
+ /** Icon button that copies `value` and confirms with a check. */
9
+ export declare function CopyButton({ value, label, size, className, ...props }: CopyButtonProps): import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Copy } from "lucide-react";
4
+ import { AnimatePresence } from "motion/react";
5
+ import * as m from "motion/react-m";
6
+ import { useUiStrings } from "../i18n/provider.js";
7
+ import { cn } from "../lib/cn.js";
8
+ import { KitMotion } from "../lib/kit-motion.js";
9
+ import { spring } from "../lib/motion.js";
10
+ import { useCopyToClipboard } from "../lib/use-copy-to-clipboard.js";
11
+ import { IconButton } from "./button.js";
12
+ import { DrawnCheck } from "./drawn-check.js";
13
+ import { Tooltip } from "./tooltip.js";
14
+ /** Icon button that copies `value` and confirms with a check. */
15
+ export function CopyButton({ value, label, size = "xs", className, ...props }) {
16
+ const strings = useUiStrings().codeBlock;
17
+ const [copied, copy] = useCopyToClipboard();
18
+ const name = copied ? strings.copied : (label ?? strings.copy);
19
+ return (_jsx(Tooltip, { content: name, children: _jsxs(IconButton, { "data-slot": "copy-button", "aria-label": name, size: size, className: cn("text-fg-subtle", className), onClick: () => copy(typeof value === "function" ? value() : value), ...props, children: [_jsx(KitMotion, { children: _jsx(AnimatePresence, { mode: "popLayout", initial: false, children: _jsx(m.span, { initial: copied ? { opacity: 0, scale: 0.6 } : { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1, transition: copied ? spring.bouncy : spring.snappy }, exit: { opacity: 0, scale: 0.6, transition: { duration: 0.08 } }, className: "grid place-items-center", children: copied ? _jsx(DrawnCheck, { className: "text-fg" }) : _jsx(Copy, {}) }, copied ? "check" : "copy") }) }), _jsx("span", { className: "sr-only", "aria-live": "polite", children: copied ? strings.copiedAnnouncement : "" })] }) }));
20
+ }
@@ -0,0 +1,18 @@
1
+ export interface CopyCommandProps {
2
+ /** The command copied and shown. */
3
+ readonly command: string;
4
+ /** Written before it and left out of the copy (`$`); `""` for none. */
5
+ readonly prompt?: string | undefined;
6
+ /**
7
+ * What copying does ("Copy install command"); the name is it and the command, so it holds the text
8
+ * the button shows. Default: "Copy <command>".
9
+ */
10
+ readonly label?: string | undefined;
11
+ readonly className?: string | undefined;
12
+ }
13
+ /**
14
+ * A command to paste into a terminal as one button: the prompt, the command and the copy mark. The
15
+ * check that confirms the copy draws in the accent, one of its few uses, and a polite live region says
16
+ * it was copied.
17
+ */
18
+ export declare function CopyCommand({ command, prompt, label, className }: CopyCommandProps): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Copy } from "lucide-react";
4
+ import { useUiStrings } from "../i18n/provider.js";
5
+ import { cn } from "../lib/cn.js";
6
+ import { useCopyToClipboard } from "../lib/use-copy-to-clipboard.js";
7
+ import { DrawnCheck } from "./drawn-check.js";
8
+ /**
9
+ * A command to paste into a terminal as one button: the prompt, the command and the copy mark. The
10
+ * check that confirms the copy draws in the accent, one of its few uses, and a polite live region says
11
+ * it was copied.
12
+ */
13
+ export function CopyCommand({ command, prompt = "$", label, className }) {
14
+ const strings = useUiStrings().codeBlock;
15
+ const [copied, copy] = useCopyToClipboard();
16
+ return (_jsxs("button", { type: "button", "data-slot": "copy-command", onClick: () => copy(command), "aria-label": label === undefined
17
+ ? strings.copyCommand({ command })
18
+ : strings.copyLabelledCommand({ label, command }), className: cn("group inline-flex h-10 max-w-full items-center gap-3 rounded-xl border border-border bg-surface px-3.5 font-mono text-sm text-fg-muted shadow-xs outline-none", "transition-[border-color,color] duration-(--duration-fast) ease-(--ease-standard) hover:border-border-strong hover:text-fg focus-visible:ring-focus", className), children: [prompt !== "" && (_jsx("span", { "aria-hidden": true, className: "select-none text-fg-faint", children: prompt })), _jsx("span", { dir: "ltr", className: "truncate", children: command }), _jsx("span", { className: "grid size-5 shrink-0 place-items-center text-fg-subtle group-hover:text-fg", children: copied ? _jsx(DrawnCheck, { className: "size-3.5 text-accent" }) : _jsx(Copy, { "aria-hidden": true, className: "size-3.5" }) }), _jsx("span", { className: "sr-only", "aria-live": "polite", children: copied ? strings.copiedAnnouncement : "" })] }));
19
+ }
@@ -0,0 +1,240 @@
1
+ import type { ComponentProps, ReactNode } from "react";
2
+ import { type VariantProps } from "../lib/cn.js";
3
+ export interface DataTableColumn<Row> {
4
+ /** Unique in the table. */
5
+ readonly key: string;
6
+ readonly header: ReactNode;
7
+ readonly cell: (row: Row) => ReactNode;
8
+ /** Figures (counts, money, sizes, durations): aligned to the end, in tabular figures. */
9
+ readonly numeric?: boolean;
10
+ /** Where the column's header and cells sit when they aren't figures (a comparison's checkmarks: `center`). */
11
+ readonly align?: "start" | "center" | "end";
12
+ /** Classes for the column's header and every cell in it: its width. */
13
+ readonly className?: string;
14
+ /** Classes for the column's body cells, or a function of the row: tone, weight, truncation. */
15
+ readonly cellClassName?: string | ((row: Row) => string | undefined);
16
+ }
17
+ declare const dataTable: import("tailwind-variants").TVReturnType<{
18
+ size: {
19
+ /** Inside a card or a pane: a detail under something larger. */
20
+ sm: {
21
+ table: string;
22
+ headCell: string;
23
+ cell: string;
24
+ };
25
+ md: {
26
+ table: string;
27
+ headCell: string;
28
+ cell: string;
29
+ };
30
+ /** A page's own table (a plan comparison): roomy cells, the outer columns off the edges, banded groups. */
31
+ lg: {
32
+ table: string;
33
+ headCell: string;
34
+ cell: string;
35
+ groupCell: string;
36
+ };
37
+ };
38
+ /** Column widths are set, not measured from the content (long names truncate). */
39
+ fixed: {
40
+ true: {
41
+ table: string;
42
+ };
43
+ };
44
+ /** Keeps the column headers in view while the rows scroll under them. */
45
+ stickyHeader: {
46
+ true: {
47
+ head: string;
48
+ };
49
+ };
50
+ /** The column headers are for assistive technology only (the columns explain themselves). */
51
+ hideHeader: {
52
+ true: {
53
+ head: string;
54
+ };
55
+ };
56
+ /** The table reaches the edges of its pane: the first and last columns keep a gap from them. */
57
+ inset: {
58
+ true: {
59
+ headCell: string;
60
+ cell: string;
61
+ };
62
+ };
63
+ }, {
64
+ table: string;
65
+ caption: string;
66
+ head: string;
67
+ headRow: string;
68
+ headCell: string;
69
+ row: string;
70
+ cell: string;
71
+ /** A group's heading row: the label across every column, above the group's rows. */
72
+ groupCell: string;
73
+ /** The rows that sum the body up, under a full-strength rule. */
74
+ foot: string;
75
+ }, undefined, {
76
+ size: {
77
+ /** Inside a card or a pane: a detail under something larger. */
78
+ sm: {
79
+ table: string;
80
+ headCell: string;
81
+ cell: string;
82
+ };
83
+ md: {
84
+ table: string;
85
+ headCell: string;
86
+ cell: string;
87
+ };
88
+ /** A page's own table (a plan comparison): roomy cells, the outer columns off the edges, banded groups. */
89
+ lg: {
90
+ table: string;
91
+ headCell: string;
92
+ cell: string;
93
+ groupCell: string;
94
+ };
95
+ };
96
+ /** Column widths are set, not measured from the content (long names truncate). */
97
+ fixed: {
98
+ true: {
99
+ table: string;
100
+ };
101
+ };
102
+ /** Keeps the column headers in view while the rows scroll under them. */
103
+ stickyHeader: {
104
+ true: {
105
+ head: string;
106
+ };
107
+ };
108
+ /** The column headers are for assistive technology only (the columns explain themselves). */
109
+ hideHeader: {
110
+ true: {
111
+ head: string;
112
+ };
113
+ };
114
+ /** The table reaches the edges of its pane: the first and last columns keep a gap from them. */
115
+ inset: {
116
+ true: {
117
+ headCell: string;
118
+ cell: string;
119
+ };
120
+ };
121
+ }, {
122
+ table: string;
123
+ caption: string;
124
+ head: string;
125
+ headRow: string;
126
+ headCell: string;
127
+ row: string;
128
+ cell: string;
129
+ /** A group's heading row: the label across every column, above the group's rows. */
130
+ groupCell: string;
131
+ /** The rows that sum the body up, under a full-strength rule. */
132
+ foot: string;
133
+ }, import("tailwind-variants").TVReturnTypeLike<{
134
+ size: {
135
+ /** Inside a card or a pane: a detail under something larger. */
136
+ sm: {
137
+ table: string;
138
+ headCell: string;
139
+ cell: string;
140
+ };
141
+ md: {
142
+ table: string;
143
+ headCell: string;
144
+ cell: string;
145
+ };
146
+ /** A page's own table (a plan comparison): roomy cells, the outer columns off the edges, banded groups. */
147
+ lg: {
148
+ table: string;
149
+ headCell: string;
150
+ cell: string;
151
+ groupCell: string;
152
+ };
153
+ };
154
+ /** Column widths are set, not measured from the content (long names truncate). */
155
+ fixed: {
156
+ true: {
157
+ table: string;
158
+ };
159
+ };
160
+ /** Keeps the column headers in view while the rows scroll under them. */
161
+ stickyHeader: {
162
+ true: {
163
+ head: string;
164
+ };
165
+ };
166
+ /** The column headers are for assistive technology only (the columns explain themselves). */
167
+ hideHeader: {
168
+ true: {
169
+ head: string;
170
+ };
171
+ };
172
+ /** The table reaches the edges of its pane: the first and last columns keep a gap from them. */
173
+ inset: {
174
+ true: {
175
+ headCell: string;
176
+ cell: string;
177
+ };
178
+ };
179
+ }, {
180
+ table: string;
181
+ caption: string;
182
+ head: string;
183
+ headRow: string;
184
+ headCell: string;
185
+ row: string;
186
+ cell: string;
187
+ /** A group's heading row: the label across every column, above the group's rows. */
188
+ groupCell: string;
189
+ /** The rows that sum the body up, under a full-strength rule. */
190
+ foot: string;
191
+ }>>;
192
+ /** Rows under one heading (a plan comparison's "Models", "Teams"): one `<tbody>` with its label. */
193
+ export interface DataTableGroup<Row> {
194
+ /** Unique in the table. */
195
+ readonly key: string;
196
+ readonly label: ReactNode;
197
+ readonly rows: readonly Row[];
198
+ }
199
+ interface DataTableBaseProps<Row> extends Omit<ComponentProps<"table">, "children">, Omit<VariantProps<typeof dataTable>, "fixed" | "stickyHeader" | "hideHeader" | "inset"> {
200
+ /** What the table holds, read first by assistive technology. */
201
+ readonly caption: ReactNode;
202
+ /** The caption is for assistive technology only (a heading above already says it). */
203
+ readonly hideCaption?: boolean;
204
+ readonly columns: readonly DataTableColumn<Row>[];
205
+ readonly rowKey: (row: Row) => string;
206
+ /** The key of the column that names each row: its cells are the row headers. */
207
+ readonly rowHeader: string;
208
+ /** Classes for a row (a failed request's danger tone), from the row. */
209
+ readonly rowClassName?: (row: Row) => string | undefined;
210
+ /** A row's tooltip, from the row. */
211
+ readonly rowTitle?: (row: Row) => string | undefined;
212
+ readonly fixed?: boolean;
213
+ readonly stickyHeader?: boolean;
214
+ readonly hideHeader?: boolean;
215
+ readonly inset?: boolean;
216
+ /** Classes for the header row's group (a sticky header's background, when it isn't the surface). */
217
+ readonly headClassName?: string;
218
+ /** Classes for each group's heading cell (a band of its own colour). */
219
+ readonly groupClassName?: string;
220
+ /**
221
+ * Rows under the body, in a `<tfoot>`: a total. The same columns render them, the naming column's
222
+ * cells are their row headers, and they are set in the medium weight.
223
+ */
224
+ readonly footer?: readonly Row[];
225
+ }
226
+ /** The rows, or the rows in labelled groups (each its own `<tbody>`, headed across the columns). */
227
+ export type DataTableProps<Row> = DataTableBaseProps<Row> & ({
228
+ readonly rows: readonly Row[];
229
+ readonly groups?: never;
230
+ } | {
231
+ readonly groups: readonly DataTableGroup<Row>[];
232
+ readonly rows?: never;
233
+ });
234
+ /**
235
+ * A table of records: a caption, column headers scoped to their columns, the naming column as row
236
+ * headers, and figures aligned to the end of their columns (the right in English, the left in a
237
+ * right-to-left language) in tabular figures. Columns say how each cell renders.
238
+ */
239
+ export declare function DataTable<Row>({ caption, hideCaption, columns, rows, groups, rowKey, rowHeader, rowClassName, rowTitle, size, fixed, stickyHeader, hideHeader, inset, headClassName, groupClassName, footer, className, ...props }: DataTableProps<Row>): import("react").JSX.Element;
240
+ export {};
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn, tv } from "../lib/cn.js";
3
+ const dataTable = tv({
4
+ slots: {
5
+ table: "w-full border-collapse",
6
+ caption: "pb-2 text-start text-sm font-medium text-fg",
7
+ head: "",
8
+ headRow: "border-b border-border",
9
+ headCell: "pe-3 text-start align-bottom text-xs font-medium text-fg-subtle last:pe-0",
10
+ row: "border-b border-border-subtle last:border-b-0",
11
+ cell: "pe-3 text-start last:pe-0",
12
+ /** A group's heading row: the label across every column, above the group's rows. */
13
+ groupCell: "pt-4 pb-1.5 text-start text-xs font-medium text-fg-subtle",
14
+ /** The rows that sum the body up, under a full-strength rule. */
15
+ foot: "border-t border-border font-medium text-fg",
16
+ },
17
+ variants: {
18
+ size: {
19
+ /** Inside a card or a pane: a detail under something larger. */
20
+ sm: { table: "text-xs", headCell: "py-1", cell: "py-1" },
21
+ md: { table: "text-sm", headCell: "py-1.5", cell: "py-1.5" },
22
+ /** A page's own table (a plan comparison): roomy cells, the outer columns off the edges, banded groups. */
23
+ lg: {
24
+ table: "text-sm",
25
+ headCell: "px-4 py-3.5 first:ps-6 last:pe-6",
26
+ cell: "px-4 py-3.5 first:ps-6 last:pe-6",
27
+ groupCell: "bg-bg-subtle px-6 py-2.5",
28
+ },
29
+ },
30
+ /** Column widths are set, not measured from the content (long names truncate). */
31
+ fixed: { true: { table: "table-fixed" } },
32
+ /** Keeps the column headers in view while the rows scroll under them. */
33
+ stickyHeader: { true: { head: "sticky top-0 z-(--z-sticky) bg-surface" } },
34
+ /** The column headers are for assistive technology only (the columns explain themselves). */
35
+ hideHeader: { true: { head: "sr-only" } },
36
+ /** The table reaches the edges of its pane: the first and last columns keep a gap from them. */
37
+ inset: { true: { headCell: "first:ps-2 last:pe-2", cell: "first:ps-2 last:pe-2" } },
38
+ },
39
+ defaultVariants: { size: "md" },
40
+ });
41
+ /**
42
+ * A table of records: a caption, column headers scoped to their columns, the naming column as row
43
+ * headers, and figures aligned to the end of their columns (the right in English, the left in a
44
+ * right-to-left language) in tabular figures. Columns say how each cell renders.
45
+ */
46
+ export function DataTable({ caption, hideCaption = false, columns, rows, groups, rowKey, rowHeader, rowClassName, rowTitle, size, fixed = false, stickyHeader = false, hideHeader = false, inset = false, headClassName, groupClassName, footer, className, ...props }) {
47
+ const styles = dataTable({ size, fixed, stickyHeader, hideHeader, inset });
48
+ const align = (column) => {
49
+ if (column.numeric === true)
50
+ return "text-end tabular whitespace-nowrap";
51
+ if (column.align === "center")
52
+ return "text-center";
53
+ return column.align === "end" ? "text-end" : undefined;
54
+ };
55
+ const renderRow = (row, total = false) => (_jsx("tr", { title: rowTitle?.(row), className: styles.row({ className: rowClassName?.(row) }), children: columns.map((column) => {
56
+ const Cell = column.key === rowHeader ? "th" : "td";
57
+ const own = typeof column.cellClassName === "function" ? column.cellClassName(row) : column.cellClassName;
58
+ return (_jsx(Cell, { ...(Cell === "th" ? { scope: "row" } : {}), className: styles.cell({
59
+ className: cn(Cell === "th" && !total && "font-normal", column.className, align(column), own),
60
+ }), children: column.cell(row) }, column.key));
61
+ }) }, rowKey(row)));
62
+ return (_jsxs("table", { "data-slot": "data-table", className: styles.table({ className }), ...props, children: [_jsx("caption", { className: hideCaption ? "sr-only" : styles.caption(), children: caption }), _jsx("thead", { className: styles.head({ className: headClassName }), children: _jsx("tr", { className: styles.headRow(), children: columns.map((column) => (_jsx("th", { scope: "col", className: styles.headCell({ className: cn(column.className, align(column)) }), children: column.header }, column.key))) }) }), groups === undefined ? (_jsx("tbody", { children: rows.map((row) => renderRow(row)) })) : (groups.map((group) => (_jsxs("tbody", { children: [_jsx("tr", { children: _jsx("th", { scope: "colgroup", colSpan: columns.length, className: styles.groupCell({ className: groupClassName }), children: group.label }) }), group.rows.map((row) => renderRow(row))] }, group.key)))), footer !== undefined && footer.length > 0 && (_jsx("tfoot", { className: styles.foot(), children: footer.map((row) => renderRow(row, true)) }))] }));
63
+ }