@streamsai/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 (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -2
  3. package/dist/components/ui/agent-avatar.d.ts +50 -0
  4. package/dist/components/ui/agent-avatar.js +38 -0
  5. package/dist/components/ui/alert-dialog.d.ts +12 -0
  6. package/dist/components/ui/alert-dialog.js +37 -0
  7. package/dist/components/ui/alert.d.ts +10 -0
  8. package/dist/components/ui/alert.js +28 -0
  9. package/dist/components/ui/assets/loader.json.js +1 -0
  10. package/dist/components/ui/avatar-frame.d.ts +11 -0
  11. package/dist/components/ui/avatar-frame.js +20 -0
  12. package/dist/components/ui/avatar.d.ts +23 -0
  13. package/dist/components/ui/avatar.js +54 -0
  14. package/dist/components/ui/badge.d.ts +7 -0
  15. package/dist/components/ui/badge.js +36 -0
  16. package/dist/components/ui/bar-list.d.ts +40 -0
  17. package/dist/components/ui/bar-list.js +37 -0
  18. package/dist/components/ui/breadcrumb.d.ts +8 -0
  19. package/dist/components/ui/breadcrumb.js +21 -0
  20. package/dist/components/ui/button-group.d.ts +10 -0
  21. package/dist/components/ui/button-group.js +41 -0
  22. package/dist/components/ui/button.d.ts +9 -0
  23. package/dist/components/ui/button.js +39 -0
  24. package/dist/components/ui/card.d.ts +9 -0
  25. package/dist/components/ui/card.js +25 -0
  26. package/dist/components/ui/checkbox.d.ts +3 -0
  27. package/dist/components/ui/checkbox.js +16 -0
  28. package/dist/components/ui/chip.d.ts +13 -0
  29. package/dist/components/ui/chip.js +22 -0
  30. package/dist/components/ui/clickable.d.ts +27 -0
  31. package/dist/components/ui/clickable.js +54 -0
  32. package/dist/components/ui/code-block.d.ts +68 -0
  33. package/dist/components/ui/code-block.js +112 -0
  34. package/dist/components/ui/code-view.d.ts +21 -0
  35. package/dist/components/ui/code-view.js +20 -0
  36. package/dist/components/ui/collapsible.d.ts +6 -0
  37. package/dist/components/ui/collapsible.js +18 -0
  38. package/dist/components/ui/combobox.d.ts +14 -0
  39. package/dist/components/ui/combobox.js +37 -0
  40. package/dist/components/ui/command.d.ts +15 -0
  41. package/dist/components/ui/command.js +34 -0
  42. package/dist/components/ui/context-menu.d.ts +21 -0
  43. package/dist/components/ui/context-menu.js +60 -0
  44. package/dist/components/ui/counter.d.ts +11 -0
  45. package/dist/components/ui/counter.js +20 -0
  46. package/dist/components/ui/dialog.d.ts +17 -0
  47. package/dist/components/ui/dialog.js +41 -0
  48. package/dist/components/ui/disabled-reason.d.ts +22 -0
  49. package/dist/components/ui/disabled-reason.js +16 -0
  50. package/dist/components/ui/dropdown-menu.d.ts +33 -0
  51. package/dist/components/ui/dropdown-menu.js +58 -0
  52. package/dist/components/ui/editable-text.d.ts +95 -0
  53. package/dist/components/ui/editable-text.js +191 -0
  54. package/dist/components/ui/heading.d.ts +24 -0
  55. package/dist/components/ui/heading.js +92 -0
  56. package/dist/components/ui/hover-card.d.ts +9 -0
  57. package/dist/components/ui/hover-card.js +16 -0
  58. package/dist/components/ui/icon-button.d.ts +23 -0
  59. package/dist/components/ui/icon-button.js +32 -0
  60. package/dist/components/ui/input.d.ts +3 -0
  61. package/dist/components/ui/input.js +8 -0
  62. package/dist/components/ui/kbd.d.ts +12 -0
  63. package/dist/components/ui/kbd.js +12 -0
  64. package/dist/components/ui/label.d.ts +3 -0
  65. package/dist/components/ui/label.js +7 -0
  66. package/dist/components/ui/loader.d.ts +19 -0
  67. package/dist/components/ui/loader.js +157 -0
  68. package/dist/components/ui/message-toolbar.d.ts +20 -0
  69. package/dist/components/ui/message-toolbar.js +17 -0
  70. package/dist/components/ui/modal.d.ts +30 -0
  71. package/dist/components/ui/modal.js +41 -0
  72. package/dist/components/ui/nav-item.d.ts +25 -0
  73. package/dist/components/ui/nav-item.js +66 -0
  74. package/dist/components/ui/panel-section.d.ts +22 -0
  75. package/dist/components/ui/panel-section.js +26 -0
  76. package/dist/components/ui/popover.d.ts +14 -0
  77. package/dist/components/ui/popover.js +30 -0
  78. package/dist/components/ui/progress.d.ts +5 -0
  79. package/dist/components/ui/progress.js +16 -0
  80. package/dist/components/ui/provider-badge.d.ts +22 -0
  81. package/dist/components/ui/provider-badge.js +38 -0
  82. package/dist/components/ui/radio-group.d.ts +5 -0
  83. package/dist/components/ui/radio-group.js +21 -0
  84. package/dist/components/ui/reply-summary.d.ts +16 -0
  85. package/dist/components/ui/reply-summary.js +8 -0
  86. package/dist/components/ui/resizable.d.ts +8 -0
  87. package/dist/components/ui/resizable.js +15 -0
  88. package/dist/components/ui/rich-text-editor.d.ts +447 -0
  89. package/dist/components/ui/rich-text-editor.js +2419 -0
  90. package/dist/components/ui/running-indicator.d.ts +17 -0
  91. package/dist/components/ui/running-indicator.js +34 -0
  92. package/dist/components/ui/sandboxed-frame.d.ts +29 -0
  93. package/dist/components/ui/sandboxed-frame.js +77 -0
  94. package/dist/components/ui/scroll-area.d.ts +14 -0
  95. package/dist/components/ui/scroll-area.js +17 -0
  96. package/dist/components/ui/section-header.d.ts +12 -0
  97. package/dist/components/ui/section-header.js +12 -0
  98. package/dist/components/ui/select.d.ts +15 -0
  99. package/dist/components/ui/select.js +40 -0
  100. package/dist/components/ui/separator.d.ts +3 -0
  101. package/dist/components/ui/separator.js +13 -0
  102. package/dist/components/ui/sheet.d.ts +23 -0
  103. package/dist/components/ui/sheet.js +48 -0
  104. package/dist/components/ui/shimmer-text.d.ts +26 -0
  105. package/dist/components/ui/shimmer-text.js +32 -0
  106. package/dist/components/ui/sidebar.d.ts +63 -0
  107. package/dist/components/ui/sidebar.js +283 -0
  108. package/dist/components/ui/skeleton.d.ts +14 -0
  109. package/dist/components/ui/skeleton.js +12 -0
  110. package/dist/components/ui/sonner.d.ts +4 -0
  111. package/dist/components/ui/sonner.js +14 -0
  112. package/dist/components/ui/spark-bars.d.ts +29 -0
  113. package/dist/components/ui/spark-bars.js +24 -0
  114. package/dist/components/ui/spinner.d.ts +16 -0
  115. package/dist/components/ui/spinner.js +26 -0
  116. package/dist/components/ui/stacked-bar.d.ts +37 -0
  117. package/dist/components/ui/stacked-bar.js +56 -0
  118. package/dist/components/ui/status-dot.d.ts +16 -0
  119. package/dist/components/ui/status-dot.js +32 -0
  120. package/dist/components/ui/switch.d.ts +5 -0
  121. package/dist/components/ui/switch.js +13 -0
  122. package/dist/components/ui/tabs.d.ts +14 -0
  123. package/dist/components/ui/tabs.js +55 -0
  124. package/dist/components/ui/text.d.ts +27 -0
  125. package/dist/components/ui/text.js +100 -0
  126. package/dist/components/ui/textarea.d.ts +3 -0
  127. package/dist/components/ui/textarea.js +7 -0
  128. package/dist/components/ui/theme-toggle.d.ts +21 -0
  129. package/dist/components/ui/theme-toggle.js +17 -0
  130. package/dist/components/ui/toggle-group.d.ts +6 -0
  131. package/dist/components/ui/toggle-group.js +12 -0
  132. package/dist/components/ui/tooltip.d.ts +11 -0
  133. package/dist/components/ui/tooltip.js +21 -0
  134. package/dist/components/ui/trace.d.ts +24 -0
  135. package/dist/components/ui/trace.js +57 -0
  136. package/dist/components/ui/trend-line.d.ts +93 -0
  137. package/dist/components/ui/trend-line.js +215 -0
  138. package/dist/components/ui/truncate.d.ts +30 -0
  139. package/dist/components/ui/truncate.js +54 -0
  140. package/dist/components/ui/viewer-shell.d.ts +55 -0
  141. package/dist/components/ui/viewer-shell.js +15 -0
  142. package/dist/components/ui/virtual-list.d.ts +91 -0
  143. package/dist/components/ui/virtual-list.js +406 -0
  144. package/dist/components/ui/visually-hidden.d.ts +15 -0
  145. package/dist/components/ui/visually-hidden.js +19 -0
  146. package/dist/direction/index.d.ts +19 -0
  147. package/dist/direction/index.js +32 -0
  148. package/dist/hooks/use-code-highlighting.d.ts +22 -0
  149. package/dist/hooks/use-code-highlighting.js +47 -0
  150. package/dist/hooks/use-is-truncated.d.ts +7 -0
  151. package/dist/hooks/use-is-truncated.js +23 -0
  152. package/dist/hooks/use-mobile.d.ts +2 -0
  153. package/dist/hooks/use-mobile.js +15 -0
  154. package/dist/icons/custom.d.ts +29 -0
  155. package/dist/icons/custom.js +48 -0
  156. package/dist/icons/index.d.ts +49 -0
  157. package/dist/icons/index.js +50 -0
  158. package/dist/icons/provider-logos.d.ts +17 -0
  159. package/dist/icons/provider-logos.js +28 -0
  160. package/dist/icons/providers.d.ts +9 -0
  161. package/dist/icons/providers.js +51 -0
  162. package/dist/index.d.ts +102 -0
  163. package/dist/index.js +124 -0
  164. package/dist/lib/code-highlighter.d.ts +9 -0
  165. package/dist/lib/code-highlighter.js +65 -0
  166. package/dist/lib/code-language.d.ts +13 -0
  167. package/dist/lib/code-language.js +103 -0
  168. package/dist/lib/code-tokens.d.ts +9 -0
  169. package/dist/lib/code-tokens.js +27 -0
  170. package/dist/lib/copy-text.d.ts +6 -0
  171. package/dist/lib/copy-text.js +46 -0
  172. package/dist/lib/home-tile.d.ts +12 -0
  173. package/dist/lib/home-tile.js +45 -0
  174. package/dist/lib/reveal-mask.d.ts +9 -0
  175. package/dist/lib/reveal-mask.js +16 -0
  176. package/dist/lib/text-direction.d.ts +28 -0
  177. package/dist/lib/text-direction.js +119 -0
  178. package/dist/lib/utils.d.ts +11 -0
  179. package/dist/lib/utils.js +30 -0
  180. package/dist/motion/components.d.ts +184 -0
  181. package/dist/motion/components.js +211 -0
  182. package/dist/motion/config.d.ts +849 -0
  183. package/dist/motion/config.js +429 -0
  184. package/dist/motion/index.d.ts +8 -0
  185. package/dist/motion/index.js +8 -0
  186. package/dist/motion/modal-presence.d.ts +5 -0
  187. package/dist/motion/modal-presence.js +27 -0
  188. package/dist/motion/popup.d.ts +77 -0
  189. package/dist/motion/popup.js +103 -0
  190. package/dist/platform/index.d.ts +29 -0
  191. package/dist/platform/index.js +63 -0
  192. package/dist/styles/base.css +319 -0
  193. package/dist/styles/fonts/Figtree-Variable.woff2 +0 -0
  194. package/dist/styles/fonts/OFL.txt +93 -0
  195. package/dist/styles/fonts/Poppins-Medium.woff2 +0 -0
  196. package/dist/styles/fonts/Poppins-Regular.woff2 +0 -0
  197. package/dist/styles/fonts/Poppins-SemiBold.woff2 +0 -0
  198. package/dist/styles/fonts.css +28 -0
  199. package/dist/styles/globals.css +8 -0
  200. package/dist/styles/mcp-host.css +76 -0
  201. package/dist/styles/tokens.css +387 -0
  202. package/dist/styles/tokens.d.mts +57 -0
  203. package/dist/styles/tokens.mjs +59 -0
  204. package/dist/theme/index.d.ts +28 -0
  205. package/dist/theme/index.js +65 -0
  206. package/package.json +136 -3
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { motion } from '../../motion/index.js';
3
+ import { staggerDelay, transitions } from '../../motion/config.js';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { Skeleton } from './skeleton.js';
6
+ import { Tooltip, TooltipContent, TooltipTrigger } from './tooltip.js';
7
+ // Shared with `BarListSkeleton`: change a size here and the skeleton follows.
8
+ const LIST_CLASS = 'flex flex-col gap-2 text-sm';
9
+ const ITEM_CLASS = 'grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-1';
10
+ const LABEL_CLASS = 'flex min-w-0 items-center gap-2';
11
+ const SELECT_CLASS = '-m-1.5 w-[calc(100%+0.75rem)] cursor-pointer rounded-sm p-1.5 text-start transition-colors hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none';
12
+ const TRACK_CLASS = 'col-span-2 h-1.5 w-full overflow-hidden rounded-full bg-muted';
13
+ /**
14
+ * Ranked horizontal bars. The widest bar is the largest value; every other bar is a share of it
15
+ * so the eye compares lengths, not labels. Plain list semantics — an `<ol>` with one row per
16
+ * item — so it reads top to bottom without any extra roles.
17
+ */
18
+ function BarList({ items, formatValue = String, formatValueTooltip, className, ...props }) {
19
+ const max = Math.max(1, ...items.map((item) => item.value));
20
+ return (_jsx("ol", { "data-slot": "bar-list", className: cn(LIST_CLASS, className), ...props, children: items.map((item, index) => {
21
+ const share = Math.max(0, Math.min(100, (item.value / max) * 100));
22
+ const label = formatValue(item.value);
23
+ const tip = formatValueTooltip?.(item.value);
24
+ const value = tip ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx("span", { className: "cursor-default font-medium tabular-nums" }), children: label }), _jsx(TooltipContent, { children: tip })] })) : (_jsx("span", { className: "font-medium tabular-nums", children: label }));
25
+ const row = (_jsxs(_Fragment, { children: [_jsxs("div", { className: LABEL_CLASS, children: [item.leading, _jsx("span", { className: "truncate", children: item.label })] }), value, _jsx("div", { className: TRACK_CLASS, children: _jsx(motion.div, { "data-slot": "bar-list-bar", initial: { width: 0 }, animate: { width: `${share}%` }, transition: { ...transitions.slow, delay: staggerDelay(index) }, className: "h-full rounded-full bg-chart-1" }) })] }));
26
+ return (_jsx("li", { "data-slot": "bar-list-item", children: item.onSelect ? (_jsx("button", { type: "button", "aria-label": item.selectLabel, onClick: item.onSelect, className: cn(ITEM_CLASS, SELECT_CLASS), children: row })) : (_jsx("div", { className: ITEM_CLASS, children: row })) }, `${item.label}-${index}`));
27
+ }) }));
28
+ }
29
+ const SKELETON_LABEL_WIDTHS = ['w-1/3', 'w-1/4', 'w-2/5'];
30
+ /**
31
+ * The loading shape of `BarList`: the same list, row grid and bar track, with a label stub, a
32
+ * value stub and a still track in each row. Rows are `aria-hidden`; the host names the busy region.
33
+ */
34
+ function BarListSkeleton({ rows = 3, avatar = false, className, ...props }) {
35
+ return (_jsx("div", { "data-slot": "bar-list-skeleton", "aria-hidden": "true", className: cn(LIST_CLASS, className), ...props, children: Array.from({ length: rows }, (_, index) => (_jsxs("div", { className: ITEM_CLASS, children: [_jsxs("div", { className: cn(LABEL_CLASS, avatar ? 'h-7' : 'h-5'), children: [avatar && _jsx(Skeleton, { variant: "shimmer", className: "size-7 shrink-0 rounded-full" }), _jsx(Skeleton, { variant: "shimmer", className: cn('h-4', SKELETON_LABEL_WIDTHS[index % SKELETON_LABEL_WIDTHS.length]) })] }), _jsx("div", { className: "flex h-5 items-center", children: _jsx(Skeleton, { variant: "shimmer", className: "h-4 w-10" }) }), _jsx("div", { className: TRACK_CLASS, children: _jsx(Skeleton, { variant: "shimmer", className: "h-full w-full rounded-full" }) })] }, index))) }));
36
+ }
37
+ export { BarList, BarListSkeleton };
@@ -0,0 +1,8 @@
1
+ import type { ComponentProps } from 'react';
2
+ declare function Breadcrumb({ ...props }: ComponentProps<'nav'>): import("react").JSX.Element;
3
+ declare function BreadcrumbList({ className, ...props }: ComponentProps<'ol'>): import("react").JSX.Element;
4
+ declare function BreadcrumbItem({ className, ...props }: ComponentProps<'li'>): import("react").JSX.Element;
5
+ declare function BreadcrumbLink({ className, ...props }: ComponentProps<'a'>): import("react").JSX.Element;
6
+ declare function BreadcrumbPage({ className, ...props }: ComponentProps<'span'>): import("react").JSX.Element;
7
+ declare function BreadcrumbSeparator({ children, className, ...props }: ComponentProps<'li'>): import("react").JSX.Element;
8
+ export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, };
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../lib/utils.js';
3
+ function Breadcrumb({ ...props }) {
4
+ return _jsx("nav", { "aria-label": "breadcrumb", "data-slot": "breadcrumb", ...props });
5
+ }
6
+ function BreadcrumbList({ className, ...props }) {
7
+ return (_jsx("ol", { "data-slot": "breadcrumb-list", className: cn('flex flex-wrap items-center gap-1.5 text-body-2 text-muted-foreground', className), ...props }));
8
+ }
9
+ function BreadcrumbItem({ className, ...props }) {
10
+ return (_jsx("li", { "data-slot": "breadcrumb-item", className: cn('inline-flex items-center gap-1.5', className), ...props }));
11
+ }
12
+ function BreadcrumbLink({ className, ...props }) {
13
+ return (_jsx("a", { "data-slot": "breadcrumb-link", className: cn('hover:text-foreground transition-colors', className), ...props }));
14
+ }
15
+ function BreadcrumbPage({ className, ...props }) {
16
+ return (_jsx("span", { "data-slot": "breadcrumb-page", "aria-current": "page", role: "link", "aria-disabled": "true", className: cn('text-foreground font-medium', className), ...props }));
17
+ }
18
+ function BreadcrumbSeparator({ children, className, ...props }) {
19
+ return (_jsx("li", { "data-slot": "breadcrumb-separator", role: "presentation", "aria-hidden": "true", className: cn('text-icon', className), ...props, children: children ?? '/' }));
20
+ }
21
+ export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, };
@@ -0,0 +1,10 @@
1
+ import { useRender } from '@base-ui/react/use-render';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ import { Separator } from './separator.js';
4
+ declare const buttonGroupVariants: (props?: ({
5
+ orientation?: "horizontal" | "vertical" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ declare function ButtonGroup({ className, orientation, ...props }: React.ComponentProps<'div'> & VariantProps<typeof buttonGroupVariants>): import("react").JSX.Element;
8
+ declare function ButtonGroupText({ className, render, ...props }: useRender.ComponentProps<'div'>): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
9
+ declare function ButtonGroupSeparator({ className, orientation, ...props }: React.ComponentProps<typeof Separator>): import("react").JSX.Element;
10
+ export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { mergeProps } from '@base-ui/react/merge-props';
3
+ import { useRender } from '@base-ui/react/use-render';
4
+ import { cva } from 'class-variance-authority';
5
+ import { cn } from '../../lib/utils.js';
6
+ import { Separator } from './separator.js';
7
+ const buttonGroupVariants = cva("flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", {
8
+ variants: {
9
+ orientation: {
10
+ horizontal: '*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0',
11
+ vertical: 'flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0',
12
+ },
13
+ },
14
+ defaultVariants: {
15
+ orientation: 'horizontal',
16
+ },
17
+ });
18
+ function ButtonGroup({ className, orientation, ...props }) {
19
+ return (_jsx("div", { role: "group", "data-slot": "button-group", "data-orientation": orientation, className: cn(buttonGroupVariants({ orientation }), className), ...props }));
20
+ }
21
+ function ButtonGroupText({ className, render, ...props }) {
22
+ return useRender({
23
+ defaultTagName: 'div',
24
+ props: mergeProps({
25
+ className: cn("flex items-center gap-2 rounded-lg border bg-muted px-2.5 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4", className),
26
+ }, props),
27
+ render,
28
+ state: {
29
+ slot: 'button-group-text',
30
+ },
31
+ });
32
+ }
33
+ function ButtonGroupSeparator({ className, orientation = 'vertical', ...props }) {
34
+ return (_jsx(Separator, { "data-slot": "button-group-separator", orientation: orientation, className: cn(
35
+ // Deliberate fix to generated output: the registry ships `data-horizontal:` /
36
+ // `data-vertical:`, which Tailwind compiles to `[data-horizontal]` / `[data-vertical]`.
37
+ // Base UI's Separator emits `data-orientation="horizontal"|"vertical"`, so those never
38
+ // match. Re-check on the next `shadcn add button-group` in case upstream fixes it.
39
+ 'relative self-stretch bg-input data-[orientation=horizontal]:mx-px data-[orientation=horizontal]:w-auto data-[orientation=vertical]:my-px data-[orientation=vertical]:h-auto', className), ...props }));
40
+ }
41
+ export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
@@ -0,0 +1,9 @@
1
+ import { Button as ButtonPrimitive } from '@base-ui/react/button';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "link" | "outline" | "default" | "destructive" | "secondary" | "ghost" | null | undefined;
5
+ size?: "default" | "icon" | "sm" | "lg" | "xs" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ shape?: "default" | "pill" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ declare function Button({ className, variant, size, shape, ...props }: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>): import("react").JSX.Element;
9
+ export { Button, buttonVariants };
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Button as ButtonPrimitive } from '@base-ui/react/button';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../../lib/utils.js';
5
+ const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:bg-disabled disabled:text-disabled-foreground disabled:opacity-100 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 in-data-[platform=mobile]:not-[.absolute]:not-[.fixed]:not-[.sticky]:relative in-data-[platform=mobile]:after:absolute in-data-[platform=mobile]:after:top-1/2 in-data-[platform=mobile]:after:left-1/2 in-data-[platform=mobile]:after:size-full in-data-[platform=mobile]:after:min-h-11 in-data-[platform=mobile]:after:min-w-11 in-data-[platform=mobile]:after:-translate-1/2 in-data-[platform=mobile]:after:content-[''] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
6
+ variants: {
7
+ variant: {
8
+ default: 'bg-primary text-primary-foreground hover:bg-primary-hover',
9
+ outline: 'border-input bg-background hover:bg-accent',
10
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-accent aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
11
+ ghost: 'hover:bg-accent hover:text-foreground aria-expanded:bg-accent aria-expanded:text-foreground dark:hover:bg-accent/50',
12
+ destructive: 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40',
13
+ link: 'text-primary underline-offset-4 hover:underline',
14
+ },
15
+ size: {
16
+ default: 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
17
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
18
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-body-3 in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
19
+ lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
20
+ icon: 'size-8',
21
+ 'icon-xs': "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
22
+ 'icon-sm': 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
23
+ 'icon-lg': 'size-9',
24
+ },
25
+ shape: {
26
+ default: '',
27
+ pill: 'rounded-full px-4',
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ variant: 'default',
32
+ size: 'default',
33
+ shape: 'default',
34
+ },
35
+ });
36
+ function Button({ className, variant = 'default', size = 'default', shape = 'default', ...props }) {
37
+ return (_jsx(ButtonPrimitive, { "data-slot": "button", className: cn(buttonVariants({ variant, size, shape, className })), ...props }));
38
+ }
39
+ export { Button, buttonVariants };
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ declare function Card({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
3
+ declare function CardHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
4
+ declare function CardTitle({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
5
+ declare function CardDescription({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
6
+ declare function CardAction({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
7
+ declare function CardContent({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
8
+ declare function CardFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
9
+ export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter };
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { cn } from '../../lib/utils.js';
4
+ function Card({ className, ...props }) {
5
+ return (_jsx("div", { "data-slot": "card", className: cn('rounded-xl border bg-card text-card-foreground shadow-sm', className), ...props }));
6
+ }
7
+ function CardHeader({ className, ...props }) {
8
+ return (_jsx("div", { "data-slot": "card-header", className: cn('flex flex-col gap-1.5 p-6', className), ...props }));
9
+ }
10
+ function CardTitle({ className, ...props }) {
11
+ return (_jsx("div", { "data-slot": "card-title", className: cn('leading-none font-semibold', className), ...props }));
12
+ }
13
+ function CardDescription({ className, ...props }) {
14
+ return (_jsx("div", { "data-slot": "card-description", className: cn('text-sm text-muted-foreground', className), ...props }));
15
+ }
16
+ function CardAction({ className, ...props }) {
17
+ return _jsx("div", { "data-slot": "card-action", className: cn('ml-auto', className), ...props });
18
+ }
19
+ function CardContent({ className, ...props }) {
20
+ return _jsx("div", { "data-slot": "card-content", className: cn('p-6 pt-0', className), ...props });
21
+ }
22
+ function CardFooter({ className, ...props }) {
23
+ return (_jsx("div", { "data-slot": "card-footer", className: cn('flex items-center p-6 pt-0', className), ...props }));
24
+ }
25
+ export { Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter };
@@ -0,0 +1,3 @@
1
+ import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox';
2
+ declare function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props): import("react").JSX.Element;
3
+ export { Checkbox };
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox';
4
+ import { motion } from '../../motion/index.js';
5
+ import { scale, transitions } from '../../motion/config.js';
6
+ import { cn } from '../../lib/utils.js';
7
+ import { Check as CheckIcon } from '../../icons/index.js';
8
+ /** Indicator pops in with a spring scale when checked, out when unchecked. */
9
+ function renderCheckboxIndicator(props, state) {
10
+ const isChecked = state.checked !== false;
11
+ return (_jsx(motion.span, { ...props, initial: false, animate: { opacity: isChecked ? 1 : 0, scale: isChecked ? 1 : scale.pop }, transition: transitions.pop }));
12
+ }
13
+ function Checkbox({ className, ...props }) {
14
+ return (_jsx(CheckboxPrimitive.Root, { "data-slot": "checkbox", className: cn('peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary', className), ...props, children: _jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", render: renderCheckboxIndicator, keepMounted: true, className: "grid place-content-center text-current [&>svg]:size-3.5", children: _jsx(CheckIcon, {}) }) }));
15
+ }
16
+ export { Checkbox };
@@ -0,0 +1,13 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ import type { ComponentProps, ReactNode } from 'react';
3
+ declare const chipVariants: (props?: ({
4
+ variant?: "outline" | "default" | "primary" | "negative" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ interface ChipProps extends Omit<ComponentProps<'span'>, 'children'>, VariantProps<typeof chipVariants> {
7
+ icon?: ReactNode;
8
+ children?: ReactNode;
9
+ onRemove?: () => void;
10
+ removeLabel?: string;
11
+ }
12
+ declare function Chip({ icon, onRemove, removeLabel, variant, className, children, ...props }: ChipProps): import("react").JSX.Element;
13
+ export { Chip, chipVariants, type ChipProps };
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cva } from 'class-variance-authority';
3
+ import { AnimatePresence, motion } from '../../motion/index.js';
4
+ import { presets } from '../../motion/config.js';
5
+ import { cn } from '../../lib/utils.js';
6
+ import { X } from '../../icons/index.js';
7
+ const chipVariants = cva('inline-flex h-6 max-w-full items-center gap-1 rounded-sm px-2 text-body-3 font-medium [&>svg]:size-3.5 [&>svg]:shrink-0', {
8
+ variants: {
9
+ variant: {
10
+ default: 'bg-secondary text-secondary-foreground',
11
+ primary: 'bg-surface-primary text-primary',
12
+ outline: 'border border-input bg-background text-foreground',
13
+ /** Vibe's negative color at 10%: something is wrong or missing. */
14
+ negative: 'bg-negative/10 text-negative',
15
+ },
16
+ },
17
+ defaultVariants: { variant: 'default' },
18
+ });
19
+ function Chip({ icon, onRemove, removeLabel, variant, className, children, ...props }) {
20
+ return (_jsxs("span", { "data-slot": "chip", className: cn(chipVariants({ variant }), className), ...props, children: [icon, _jsx("span", { className: "truncate", children: children }), _jsx(AnimatePresence, { initial: false, children: onRemove ? (_jsx(motion.button, { ...presets.pop, type: "button", "aria-label": removeLabel, onClick: onRemove, className: "-mr-1 inline-flex size-4 items-center justify-center rounded-sm text-icon hover:bg-accent", children: _jsx(X, { className: "size-3", "aria-hidden": "true" }) }, "remove")) : null })] }));
21
+ }
22
+ export { Chip, chipVariants };
@@ -0,0 +1,27 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ import type { ComponentProps } from 'react';
3
+ declare const clickableVariants: (props?: ({
4
+ variant?: "default" | "plain" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ interface ClickableProps extends Omit<ComponentProps<'div'>, 'ref'>, VariantProps<typeof clickableVariants> {
8
+ /**
9
+ * When provided the element renders as `<a>`, preserving native link
10
+ * semantics. `role="button"` is NOT applied — do not override with the
11
+ * `role` prop.
12
+ */
13
+ href?: string;
14
+ /**
15
+ * Marks the element as non-interactive via `aria-disabled`. Activation via
16
+ * click, Enter, and Space is suppressed at the handler level so that the
17
+ * guard is not bypassable by removing the CSS.
18
+ */
19
+ disabled?: boolean;
20
+ /** Forwarded to `<a>` when `href` is set. */
21
+ rel?: string;
22
+ /** Forwarded to `<a>` when `href` is set. */
23
+ target?: string;
24
+ }
25
+ declare function Clickable({ className, variant, size, disabled, href, rel, target, onClick, onKeyDown, children, ...rest }: ClickableProps): import("react").JSX.Element;
26
+ export { Clickable, clickableVariants };
27
+ export type { ClickableProps };
@@ -0,0 +1,54 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../../lib/utils.js';
5
+ const clickableVariants = cva('group/clickable inline-flex cursor-pointer select-none items-center justify-center border border-transparent outline-none transition-colors focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:opacity-50', {
6
+ variants: {
7
+ variant: {
8
+ /** Subtle hover background — most common wrapper use. */
9
+ default: 'rounded-md hover:bg-accent hover:text-accent-foreground',
10
+ /** Lighter muted hover background — for secondary surfaces. */
11
+ ghost: 'rounded-md hover:bg-muted',
12
+ /** No hover treatment — caller owns all visual feedback. */
13
+ plain: '',
14
+ },
15
+ size: {
16
+ sm: 'min-h-6',
17
+ /** Meets the platform tap-target minimum (24 px web, 44 px mobile). */
18
+ default: 'min-h-tap',
19
+ lg: 'min-h-9',
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: 'default',
24
+ size: 'default',
25
+ },
26
+ });
27
+ function Clickable({ className, variant, size, disabled = false, href, rel, target, onClick, onKeyDown, children, ...rest }) {
28
+ const classes = cn(clickableVariants({ variant, size }), className);
29
+ const ariaDisabled = disabled || undefined;
30
+ function handleKeyDown(e) {
31
+ if (e.key === ' ') {
32
+ // Space must never scroll the page when a clickable element is focused.
33
+ e.preventDefault();
34
+ if (!disabled)
35
+ e.currentTarget.click();
36
+ }
37
+ else if (e.key === 'Enter' && href === undefined && !disabled) {
38
+ // Enter on <a> fires natively; on a div role="button" we synthesise a click.
39
+ e.currentTarget.click();
40
+ }
41
+ // Always forward to the caller's onKeyDown (after preventDefault so they
42
+ // can read e.defaultPrevented correctly).
43
+ onKeyDown?.(e);
44
+ }
45
+ if (href !== undefined) {
46
+ return (_jsx("a", { "data-slot": "clickable", href: disabled ? undefined : href, rel: rel, target: target, "aria-disabled": ariaDisabled, tabIndex: disabled ? -1 : undefined, onClick: disabled
47
+ ? (e) => {
48
+ e.preventDefault();
49
+ }
50
+ : onClick, onKeyDown: handleKeyDown, className: classes, ...rest, children: children }));
51
+ }
52
+ return (_jsx("div", { "data-slot": "clickable", role: "button", tabIndex: disabled ? -1 : 0, "aria-disabled": ariaDisabled, onClick: disabled ? undefined : onClick, onKeyDown: handleKeyDown, className: classes, ...rest, children: children }));
53
+ }
54
+ export { Clickable, clickableVariants };
@@ -0,0 +1,68 @@
1
+ import { type ComponentProps } from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ import { Button } from './button.js';
4
+ import type { CodeLanguage } from '../../lib/code-language.js';
5
+ declare const codeBlockVariants: (props?: ({
6
+ variant?: "default" | "destructive" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ type CodeBlockProps = ComponentProps<'div'> & VariantProps<typeof codeBlockVariants> & {
9
+ size?: 'default' | 'sm';
10
+ };
11
+ /**
12
+ * shadcn Code Block, adapted: a compound frame (header, actions, content, footer). The slots
13
+ * only lay out; pass text through `CodeBlockLines` so code is always a text node.
14
+ */
15
+ declare function CodeBlock({ className, variant, size, ...props }: CodeBlockProps): import("react").JSX.Element;
16
+ declare function CodeBlockHeader({ className, ...props }: ComponentProps<'div'>): import("react").JSX.Element;
17
+ declare function CodeBlockTitle({ className, ...props }: ComponentProps<'div'>): import("react").JSX.Element;
18
+ /**
19
+ * Header action row. As a direct child of `CodeBlock` (no header) it floats over the top corner,
20
+ * hidden until hover or focus on a mouse and always shown on touch.
21
+ */
22
+ declare function CodeBlockActions({ className, ...props }: ComponentProps<'div'>): import("react").JSX.Element;
23
+ type CodeBlockCopyLabels = {
24
+ copy: string;
25
+ copied: string;
26
+ failed: string;
27
+ };
28
+ type CodeBlockCopyButtonProps = Omit<ComponentProps<typeof Button>, 'value' | 'children'> & {
29
+ /** The exact text to copy: newlines and trailing whitespace included. */
30
+ value: string;
31
+ /** Already translated; the library holds no copy of its own. */
32
+ labels: CodeBlockCopyLabels;
33
+ /** Fires once per copy the browser confirmed, never for a rejection. */
34
+ onCopied?: () => void;
35
+ onCopyError?: () => void;
36
+ };
37
+ declare function CodeBlockCopyButton({ value, labels, onCopied, onCopyError, variant, size, className, onClick, ...props }: CodeBlockCopyButtonProps): import("react").JSX.Element;
38
+ type CodeBlockContentProps = ComponentProps<'pre'> & {
39
+ /** Wrap long lines instead of scrolling sideways. */
40
+ wrap?: boolean;
41
+ lineNumbers?: boolean;
42
+ startLine?: number;
43
+ };
44
+ /** Scrolling code body. Always `dir="ltr"`: code does not mirror in RTL. */
45
+ declare function CodeBlockContent({ className, children, style, wrap, lineNumbers, startLine, ...props }: CodeBlockContentProps): import("react").JSX.Element;
46
+ declare const codeBlockLineVariants: (props?: ({
47
+ variant?: "default" | "highlighted" | "added" | "removed" | null | undefined;
48
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
49
+ type CodeBlockLineProps = ComponentProps<'span'> & VariantProps<typeof codeBlockLineVariants>;
50
+ declare function CodeBlockLine({ className, variant, children, ...props }: CodeBlockLineProps): import("react").JSX.Element;
51
+ type CodeBlockLinesProps = {
52
+ /** Rendered verbatim as text. A trailing newline does not add a blank line. */
53
+ code: string;
54
+ /** Resolved language, or `null` for plain text (nothing is loaded). */
55
+ language: CodeLanguage | null;
56
+ /** False keeps plain text, e.g. while the fence is still open. Default true. */
57
+ highlight?: boolean;
58
+ /** Called when the highlighter fails to load; the plain text stays. */
59
+ onHighlightError?: (error: unknown) => void;
60
+ };
61
+ /**
62
+ * The lines of `code` as `CodeBlockLine`s: plain text at once, tokens when the shared lazy
63
+ * highlighter is ready. Same line geometry before and after, so the swap does not move anything.
64
+ * Code over the highlight size limits is one plain text node (no line wrappers or numbers).
65
+ */
66
+ declare function CodeBlockLines({ code, language, highlight, onHighlightError, }: CodeBlockLinesProps): import("react").JSX.Element;
67
+ declare function CodeBlockFooter({ className, ...props }: ComponentProps<'div'>): import("react").JSX.Element;
68
+ export { CodeBlock, CodeBlockHeader, CodeBlockTitle, CodeBlockActions, CodeBlockCopyButton, CodeBlockContent, CodeBlockLine, CodeBlockLines, CodeBlockFooter, type CodeBlockProps, type CodeBlockCopyLabels, type CodeBlockCopyButtonProps, type CodeBlockContentProps, type CodeBlockLineProps, type CodeBlockLinesProps, };
@@ -0,0 +1,112 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../../lib/utils.js';
5
+ import { Button } from './button.js';
6
+ import { Check, CircleAlert, Copy } from '../../icons/index.js';
7
+ import { copyText } from '../../lib/copy-text.js';
8
+ import { codeDisplayLines, renderCodeTokens } from '../../lib/code-tokens.js';
9
+ import { exceedsHighlightLimits, useCodeHighlighting } from '../../hooks/use-code-highlighting.js';
10
+ const codeBlockVariants = cva('group/code-block relative flex w-full min-w-0 flex-col overflow-hidden rounded-lg text-sm has-[>[data-slot=code-block-content]:focus-visible]:ring-3 has-[>[data-slot=code-block-content]:focus-visible]:ring-ring/50 data-[size=sm]:text-xs', {
11
+ variants: {
12
+ variant: {
13
+ default: 'border border-input bg-surface-1 text-foreground has-[>[data-slot=code-block-content]:focus-visible]:border-ring',
14
+ destructive: 'border border-destructive/30 text-destructive dark:border-destructive/40',
15
+ },
16
+ },
17
+ defaultVariants: { variant: 'default' },
18
+ });
19
+ /**
20
+ * shadcn Code Block, adapted: a compound frame (header, actions, content, footer). The slots
21
+ * only lay out; pass text through `CodeBlockLines` so code is always a text node.
22
+ */
23
+ function CodeBlock({ className, variant = 'default', size = 'default', ...props }) {
24
+ return (_jsx("div", { "data-slot": "code-block", "data-variant": variant, "data-size": size, className: cn(codeBlockVariants({ variant }), className), ...props }));
25
+ }
26
+ function CodeBlockHeader({ className, ...props }) {
27
+ return (_jsx("div", { "data-slot": "code-block-header", className: cn('flex min-h-8 min-w-0 shrink-0 items-center gap-2 px-3 pt-2 text-muted-foreground group-data-[size=sm]/code-block:min-h-7 group-data-[size=sm]/code-block:px-2.5 group-data-[size=sm]/code-block:pt-1.5 group-data-[variant=destructive]/code-block:text-destructive *:has-[>[data-slot=code-block-title]]:min-w-0', className), ...props }));
28
+ }
29
+ function CodeBlockTitle({ className, ...props }) {
30
+ return (_jsx("div", { "data-slot": "code-block-title", className: cn('min-w-0 truncate font-sans text-sm font-medium text-foreground group-data-[size=sm]/code-block:text-xs group-data-[variant=destructive]/code-block:text-destructive [&_svg]:pointer-events-none [&_svg]:inline-block [&_svg]:align-middle [&_svg:not([class*=size-])]:size-3.5 *:[svg]:me-1.5', className), ...props }));
31
+ }
32
+ /**
33
+ * Header action row. As a direct child of `CodeBlock` (no header) it floats over the top corner,
34
+ * hidden until hover or focus on a mouse and always shown on touch.
35
+ */
36
+ function CodeBlockActions({ className, ...props }) {
37
+ return (_jsx("div", { "data-slot": "code-block-actions", className: cn('-my-1 ms-auto -me-1.5 flex shrink-0 items-center gap-1 [[data-slot=code-block]>&]:absolute [[data-slot=code-block]>&]:end-2 [[data-slot=code-block]>&]:top-2 [[data-slot=code-block]>&]:z-10 [[data-slot=code-block]>&]:m-0 [[data-slot=code-block]>&]:opacity-0 [[data-slot=code-block]>&]:transition-opacity [[data-slot=code-block]>&]:group-focus-within/code-block:opacity-100 [[data-slot=code-block]>&]:group-hover/code-block:opacity-100 group-data-[size=sm]/code-block:[[data-slot=code-block]>&]:end-1.5 group-data-[size=sm]/code-block:[[data-slot=code-block]>&]:top-1.5 [[data-slot=code-block]>&]:pointer-coarse:opacity-100 [[data-slot=code-block]>&]:*:[button]:bg-background [[data-slot=code-block]>&]:*:[button]:ring-1 [[data-slot=code-block]>&]:*:[button]:ring-foreground/10', className), ...props }));
38
+ }
39
+ const FEEDBACK_MS = 2000;
40
+ function CodeBlockCopyButton({ value, labels, onCopied, onCopyError, variant = 'ghost', size = 'icon-xs', className, onClick, ...props }) {
41
+ const [result, setResult] = useState(null);
42
+ // Feedback belongs to the text that was copied; a changed value starts clean.
43
+ const status = result && result.value === value ? result.status : 'idle';
44
+ useEffect(() => {
45
+ if (!result)
46
+ return;
47
+ const timeout = setTimeout(() => setResult(null), FEEDBACK_MS);
48
+ return () => clearTimeout(timeout);
49
+ }, [result]);
50
+ const label = status === 'copied' ? labels.copied : status === 'failed' ? labels.failed : labels.copy;
51
+ const Glyph = status === 'copied' ? Check : status === 'failed' ? CircleAlert : Copy;
52
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { "data-slot": "code-block-copy-button", "data-copied": status === 'copied' || undefined, "data-copy-failed": status === 'failed' || undefined, variant: variant, size: size, "aria-label": label, className: cn(status === 'failed' && 'text-destructive', className), onClick: (event) => {
53
+ onClick?.(event);
54
+ if (event.defaultPrevented)
55
+ return;
56
+ void copyText(value).then((ok) => {
57
+ setResult({ value, status: ok ? 'copied' : 'failed' });
58
+ if (ok)
59
+ onCopied?.();
60
+ else
61
+ onCopyError?.();
62
+ });
63
+ }, ...props, children: _jsx(Glyph, { "aria-hidden": "true" }) }), _jsx("span", { "aria-live": "polite", role: "status", className: "sr-only", children: status === 'idle' ? '' : label })] }));
64
+ }
65
+ /** Scrolling code body. Always `dir="ltr"`: code does not mirror in RTL. */
66
+ function CodeBlockContent({ className, children, style, wrap = false, lineNumbers = false, startLine = 1, ...props }) {
67
+ return (_jsx("pre", { "data-slot": "code-block-content", "data-wrap": wrap || undefined, "data-numbered": lineNumbers || undefined, dir: "ltr", tabIndex: 0, style: { counterReset: `line ${startLine - 1}`, ...style }, className: cn('min-h-0 min-w-0 overflow-auto px-3 py-3 text-start font-mono leading-relaxed outline-none group-has-data-[slot=code-block-footer]/code-block:pb-2 group-has-data-[slot=code-block-header]/code-block:pt-1.5 group-data-[size=sm]/code-block:px-2.5 group-data-[size=sm]/code-block:py-2.5 group-data-[size=sm]/code-block:group-has-data-[slot=code-block-header]/code-block:pt-1 data-wrap:wrap-break-word data-wrap:whitespace-pre-wrap', className), ...props, children: _jsx("code", { "data-slot": "code-block-code", className: "grid min-h-lh min-w-max content-start in-data-numbered:grid-cols-[auto_1fr] in-data-wrap:min-w-0", children: children }) }));
68
+ }
69
+ const codeBlockLineVariants = cva("relative -mx-3 block min-h-lh px-3 group-data-[size=sm]/code-block:-mx-2.5 group-data-[size=sm]/code-block:px-2.5 before:min-w-6 before:text-end before:text-muted-foreground after:absolute after:start-1 after:top-0 after:text-muted-foreground after:select-none in-data-numbered:col-span-2 in-data-numbered:grid in-data-numbered:grid-cols-subgrid in-data-numbered:gap-x-3 in-data-numbered:[counter-increment:line] in-data-numbered:before:content-[counter(line)] in-data-numbered:before:select-none in-data-numbered:supports-[content:counter(line)_/_'']:before:content-[counter(line)_/_'']", {
70
+ variants: {
71
+ variant: {
72
+ default: '',
73
+ added: "bg-muted after:content-['+']",
74
+ removed: "bg-destructive/10 after:text-destructive after:content-['−']",
75
+ highlighted: 'bg-muted',
76
+ },
77
+ },
78
+ defaultVariants: { variant: 'default' },
79
+ });
80
+ function CodeBlockLine({ className, variant = 'default', children, ...props }) {
81
+ // An empty line holds a newline so a selection keeps blank lines.
82
+ const empty = children === undefined ||
83
+ children === null ||
84
+ children === '' ||
85
+ (Array.isArray(children) && children.length === 0);
86
+ return (_jsx("span", { "data-slot": "code-block-line", "data-variant": variant, className: cn(codeBlockLineVariants({ variant }), className), ...props, children: _jsx("span", { "data-slot": "code-block-line-content", className: "min-w-0", children: empty ? '\n' : children }) }));
87
+ }
88
+ /**
89
+ * The lines of `code` as `CodeBlockLine`s: plain text at once, tokens when the shared lazy
90
+ * highlighter is ready. Same line geometry before and after, so the swap does not move anything.
91
+ * Code over the highlight size limits is one plain text node (no line wrappers or numbers).
92
+ */
93
+ function CodeBlockLines({ code, language, highlight = true, onHighlightError, }) {
94
+ const tokens = useCodeHighlighting({
95
+ code,
96
+ language,
97
+ enabled: highlight,
98
+ onError: onHighlightError,
99
+ });
100
+ // Past the highlight limits one text node replaces the per-line wrappers: a 100,000-line
101
+ // file would otherwise mount hundreds of thousands of spans for no visible gain.
102
+ if (exceedsHighlightLimits(code)) {
103
+ return (_jsx("span", { "data-slot": "code-block-plain", className: "block", children: code.endsWith('\n') ? code.slice(0, -1) : code }));
104
+ }
105
+ const plain = codeDisplayLines(code);
106
+ const count = tokens ? Math.min(tokens.length, plain.length) : plain.length;
107
+ return (_jsx(_Fragment, { children: Array.from({ length: count }, (_, index) => (_jsx(CodeBlockLine, { children: tokens ? renderCodeTokens(tokens[index]) : plain[index] }, index))) }));
108
+ }
109
+ function CodeBlockFooter({ className, ...props }) {
110
+ return (_jsx("div", { "data-slot": "code-block-footer", className: cn('flex min-w-0 shrink-0 items-center gap-2 px-3 pb-3 text-muted-foreground group-data-[size=sm]/code-block:px-2.5 group-data-[size=sm]/code-block:pb-2.5', className), ...props }));
111
+ }
112
+ export { CodeBlock, CodeBlockHeader, CodeBlockTitle, CodeBlockActions, CodeBlockCopyButton, CodeBlockContent, CodeBlockLine, CodeBlockLines, CodeBlockFooter, };
@@ -0,0 +1,21 @@
1
+ import { type CodeLanguage } from '../../lib/code-language.js';
2
+ import { CODE_VIEW_MAX_CHARS, CODE_VIEW_MAX_LINES } from '../../hooks/use-code-highlighting.js';
3
+ export { CODE_VIEW_MAX_CHARS, CODE_VIEW_MAX_LINES };
4
+ type CodeViewProps = {
5
+ /** The file's text. Always rendered as text nodes, never as markup. */
6
+ code: string;
7
+ /** Picks the language from the extension. Unknown extensions stay plain and load nothing. */
8
+ fileName?: string;
9
+ /** Overrides the extension lookup. */
10
+ language?: CodeLanguage;
11
+ /** Called when the highlighter or a grammar fails to load or throws; the plain text stays. */
12
+ onError?: (error: unknown) => void;
13
+ className?: string;
14
+ };
15
+ /**
16
+ * Read-only code or text. Renders the plain `<pre>` straight away and swaps in syntax-highlighted
17
+ * tokens once the lazily loaded highlighter is ready. Highlighting is skipped for large files
18
+ * and whenever the language is unknown.
19
+ */
20
+ declare function CodeView({ code, fileName, language, onError, className }: CodeViewProps): import("react").JSX.Element;
21
+ export { CodeView, type CodeViewProps };
@@ -0,0 +1,20 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Fragment } from 'react';
3
+ import { cn } from '../../lib/utils.js';
4
+ import { codeLanguageForFileName } from '../../lib/code-language.js';
5
+ import { renderCodeTokens } from '../../lib/code-tokens.js';
6
+ import { CODE_VIEW_MAX_CHARS, CODE_VIEW_MAX_LINES, useCodeHighlighting, } from '../../hooks/use-code-highlighting.js';
7
+ export { CODE_VIEW_MAX_CHARS, CODE_VIEW_MAX_LINES };
8
+ /**
9
+ * Read-only code or text. Renders the plain `<pre>` straight away and swaps in syntax-highlighted
10
+ * tokens once the lazily loaded highlighter is ready. Highlighting is skipped for large files
11
+ * and whenever the language is unknown.
12
+ */
13
+ function CodeView({ code, fileName, language, onError, className }) {
14
+ const lang = language ?? codeLanguageForFileName(fileName);
15
+ const lines = useCodeHighlighting({ code, language: lang, onError });
16
+ return (_jsx("pre", { "data-slot": "code-view", "data-highlighted": lines ? 'true' : undefined, className: cn('whitespace-pre-wrap break-words p-6 font-mono text-sm text-foreground', className), children: lines
17
+ ? lines.map((line, index) => (_jsxs(Fragment, { children: [index > 0 ? '\n' : null, renderCodeTokens(line)] }, index)))
18
+ : code }));
19
+ }
20
+ export { CodeView };
@@ -0,0 +1,6 @@
1
+ import { Collapsible as CollapsiblePrimitive } from '@base-ui/react/collapsible';
2
+ declare function Collapsible({ ...props }: CollapsiblePrimitive.Root.Props): import("react").JSX.Element;
3
+ declare function CollapsibleTrigger({ className, ...props }: CollapsiblePrimitive.Trigger.Props): import("react").JSX.Element;
4
+ /** Animates open and shut with `presets.collapse` (motion), so callers never add their own. */
5
+ declare function CollapsibleContent({ className, ...props }: CollapsiblePrimitive.Panel.Props): import("react").JSX.Element;
6
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };