@mcp-b/react-components 0.1.1 → 0.1.2

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 (203) hide show
  1. package/dist/Button-QCM8ZKgR.d.ts +98 -0
  2. package/dist/CodeBlock-CttHhWcb.js +356 -0
  3. package/dist/CodeBlock-V6pgafSS.d.ts +174 -0
  4. package/dist/Select-CRsKCJ9x.d.ts +200 -0
  5. package/dist/class-names-9UtZwb0J.js +12 -0
  6. package/dist/components/Accordion.d.ts +81 -0
  7. package/dist/components/Accordion.js +97 -0
  8. package/dist/components/AgentConnection.d.ts +69 -0
  9. package/dist/components/AgentConnection.js +176 -0
  10. package/dist/components/AlertDialog.d.ts +148 -0
  11. package/dist/components/AlertDialog.js +141 -0
  12. package/dist/components/Artifact.d.ts +128 -0
  13. package/dist/components/Artifact.js +115 -0
  14. package/dist/components/Autocomplete.d.ts +186 -0
  15. package/dist/components/Autocomplete.js +186 -0
  16. package/dist/components/Avatar.d.ts +134 -0
  17. package/dist/components/Avatar.js +118 -0
  18. package/dist/components/Badge.d.ts +68 -0
  19. package/dist/components/Badge.js +108 -0
  20. package/dist/components/Button.d.ts +2 -0
  21. package/dist/components/Button.js +73 -0
  22. package/dist/components/Card.d.ts +87 -0
  23. package/dist/components/Card.js +81 -0
  24. package/dist/components/ChainOfThought.d.ts +153 -0
  25. package/dist/components/ChainOfThought.js +157 -0
  26. package/dist/components/Checkbox.d.ts +35 -0
  27. package/dist/components/Checkbox.js +47 -0
  28. package/dist/components/CheckboxGroup.d.ts +76 -0
  29. package/dist/components/CheckboxGroup.js +69 -0
  30. package/dist/components/CodeBlock.d.ts +2 -0
  31. package/dist/components/CodeBlock.js +2 -0
  32. package/dist/components/Collapsible.d.ts +127 -0
  33. package/dist/components/Collapsible.js +103 -0
  34. package/dist/components/Combobox.d.ts +177 -0
  35. package/dist/components/Combobox.js +179 -0
  36. package/dist/components/Commit.d.ts +265 -0
  37. package/dist/components/Commit.js +282 -0
  38. package/dist/components/Context.d.ts +129 -0
  39. package/dist/components/Context.js +309 -0
  40. package/dist/components/ContextMenu.d.ts +282 -0
  41. package/dist/components/ContextMenu.js +270 -0
  42. package/dist/components/Conversation.d.ts +166 -0
  43. package/dist/components/Conversation.js +202 -0
  44. package/dist/components/Dialog.d.ts +120 -0
  45. package/dist/components/Dialog.js +114 -0
  46. package/dist/components/EnvironmentVariables.d.ts +176 -0
  47. package/dist/components/EnvironmentVariables.js +221 -0
  48. package/dist/components/Field.d.ts +281 -0
  49. package/dist/components/Field.js +274 -0
  50. package/dist/components/Fieldset.d.ts +93 -0
  51. package/dist/components/Fieldset.js +81 -0
  52. package/dist/components/FileTree.d.ts +116 -0
  53. package/dist/components/FileTree.js +310 -0
  54. package/dist/components/Form.d.ts +94 -0
  55. package/dist/components/Form.js +88 -0
  56. package/dist/components/GithubMotionMark.d.ts +13 -0
  57. package/dist/components/GithubMotionMark.js +23 -0
  58. package/dist/components/Input.d.ts +33 -0
  59. package/dist/components/Input.js +27 -0
  60. package/dist/components/Label.d.ts +44 -0
  61. package/dist/components/Label.js +41 -0
  62. package/dist/components/Menu.d.ts +395 -0
  63. package/dist/components/Menu.js +338 -0
  64. package/dist/components/Menubar.d.ts +331 -0
  65. package/dist/components/Menubar.js +299 -0
  66. package/dist/components/Message.d.ts +216 -0
  67. package/dist/components/Message.js +245 -0
  68. package/dist/components/Meter.d.ts +151 -0
  69. package/dist/components/Meter.js +121 -0
  70. package/dist/components/ModelSelector.d.ts +198 -0
  71. package/dist/components/ModelSelector.js +306 -0
  72. package/dist/components/NaniteScene.d.ts +33 -0
  73. package/dist/components/NaniteScene.js +405 -0
  74. package/dist/components/NavigationMenu.d.ts +256 -0
  75. package/dist/components/NavigationMenu.js +228 -0
  76. package/dist/components/NumberField.d.ts +159 -0
  77. package/dist/components/NumberField.js +123 -0
  78. package/dist/components/Popover.d.ts +278 -0
  79. package/dist/components/Popover.js +245 -0
  80. package/dist/components/PreviewCard.d.ts +156 -0
  81. package/dist/components/PreviewCard.js +156 -0
  82. package/dist/components/PricingPage.d.ts +209 -0
  83. package/dist/components/PricingPage.js +506 -0
  84. package/dist/components/Progress.d.ts +58 -0
  85. package/dist/components/Progress.js +51 -0
  86. package/dist/components/PromptInput.d.ts +399 -0
  87. package/dist/components/PromptInput.js +737 -0
  88. package/dist/components/Queue.d.ts +241 -0
  89. package/dist/components/Queue.js +225 -0
  90. package/dist/components/RadioGroup.d.ts +78 -0
  91. package/dist/components/RadioGroup.js +72 -0
  92. package/dist/components/Reasoning.d.ts +88 -0
  93. package/dist/components/Reasoning.js +187 -0
  94. package/dist/components/ScrollArea.d.ts +160 -0
  95. package/dist/components/ScrollArea.js +145 -0
  96. package/dist/components/Select.d.ts +2 -0
  97. package/dist/components/Select.js +260 -0
  98. package/dist/components/Separator.d.ts +45 -0
  99. package/dist/components/Separator.js +40 -0
  100. package/dist/components/Shell.d.ts +163 -0
  101. package/dist/components/Shell.js +137 -0
  102. package/dist/components/Slider.d.ts +120 -0
  103. package/dist/components/Slider.js +115 -0
  104. package/dist/components/Sources.d.ts +91 -0
  105. package/dist/components/Sources.js +121 -0
  106. package/dist/components/Stepper.d.ts +190 -0
  107. package/dist/components/Stepper.js +315 -0
  108. package/dist/components/Switch.d.ts +57 -0
  109. package/dist/components/Switch.js +55 -0
  110. package/dist/components/Tabs.d.ts +84 -0
  111. package/dist/components/Tabs.js +78 -0
  112. package/dist/components/Task.d.ts +100 -0
  113. package/dist/components/Task.js +120 -0
  114. package/dist/components/Terminal.d.ts +118 -0
  115. package/dist/components/Terminal.js +234 -0
  116. package/dist/components/TestResults.d.ts +236 -0
  117. package/dist/components/TestResults.js +346 -0
  118. package/dist/components/Toast.d.ts +192 -0
  119. package/dist/components/Toast.js +163 -0
  120. package/dist/components/Toggle.d.ts +69 -0
  121. package/dist/components/Toggle.js +66 -0
  122. package/dist/components/ToggleGroup.d.ts +69 -0
  123. package/dist/components/ToggleGroup.js +99 -0
  124. package/dist/components/Tool.d.ts +119 -0
  125. package/dist/components/Tool.js +192 -0
  126. package/dist/components/Toolbar.d.ts +162 -0
  127. package/dist/components/Toolbar.js +126 -0
  128. package/dist/components/Tooltip.d.ts +81 -0
  129. package/dist/components/Tooltip.js +74 -0
  130. package/dist/components/WebPreview.d.ts +143 -0
  131. package/dist/components/WebPreview.js +280 -0
  132. package/dist/components/useStickToBottom.d.ts +30 -0
  133. package/dist/components/useStickToBottom.js +95 -0
  134. package/dist/copy-button-BIATcZWZ.d.ts +16 -0
  135. package/dist/copy-button-BNgclDrO.js +43 -0
  136. package/dist/icons-BsWc8g4E.js +221 -0
  137. package/dist/styles/accordion.css +10 -10
  138. package/dist/styles/agent-connection.css +18 -17
  139. package/dist/styles/alert-dialog.css +48 -29
  140. package/dist/styles/artifact.css +10 -10
  141. package/dist/styles/autocomplete.css +25 -24
  142. package/dist/styles/avatar.css +96 -6
  143. package/dist/styles/badge.css +78 -14
  144. package/dist/styles/base.css +9 -9
  145. package/dist/styles/button.css +57 -38
  146. package/dist/styles/card.css +57 -10
  147. package/dist/styles/chain-of-thought.css +47 -33
  148. package/dist/styles/checkbox.css +24 -10
  149. package/dist/styles/code-block.css +22 -15
  150. package/dist/styles/collapsible.css +14 -12
  151. package/dist/styles/combobox.css +26 -25
  152. package/dist/styles/commit.css +49 -24
  153. package/dist/styles/context-menu.css +70 -16
  154. package/dist/styles/context.css +15 -15
  155. package/dist/styles/conversation.css +12 -12
  156. package/dist/styles/dialog.css +52 -16
  157. package/dist/styles/environment-variables.css +19 -19
  158. package/dist/styles/field.css +184 -22
  159. package/dist/styles/fieldset.css +5 -4
  160. package/dist/styles/file-tree.css +17 -17
  161. package/dist/styles/index.css.d.ts +1 -0
  162. package/dist/styles/input.css +45 -11
  163. package/dist/styles/label.css +21 -4
  164. package/dist/styles/menu.css +55 -32
  165. package/dist/styles/menubar.css +80 -28
  166. package/dist/styles/message.css +22 -13
  167. package/dist/styles/meter.css +8 -8
  168. package/dist/styles/model-selector.css +33 -21
  169. package/dist/styles/navigation-menu.css +26 -24
  170. package/dist/styles/number-field.css +20 -18
  171. package/dist/styles/popover.css +38 -28
  172. package/dist/styles/preview-card.css +15 -13
  173. package/dist/styles/pricing-page.css +53 -53
  174. package/dist/styles/progress.css +7 -7
  175. package/dist/styles/prompt-input.css +73 -24
  176. package/dist/styles/queue.css +58 -32
  177. package/dist/styles/radio.css +26 -11
  178. package/dist/styles/reasoning.css +15 -11
  179. package/dist/styles/scroll-area.css +6 -6
  180. package/dist/styles/scrollbars.css +4 -4
  181. package/dist/styles/select.css +84 -25
  182. package/dist/styles/separator.css +1 -1
  183. package/dist/styles/shell.css +21 -20
  184. package/dist/styles/slider.css +35 -11
  185. package/dist/styles/sources.css +20 -20
  186. package/dist/styles/stepper.css +22 -22
  187. package/dist/styles/switch.css +29 -13
  188. package/dist/styles/tabs.css +23 -16
  189. package/dist/styles/task.css +27 -23
  190. package/dist/styles/terminal.css +16 -13
  191. package/dist/styles/test-results.css +79 -32
  192. package/dist/styles/toast.css +26 -25
  193. package/dist/styles/toggle-group.css +12 -12
  194. package/dist/styles/toggle.css +29 -11
  195. package/dist/styles/tool.css +54 -32
  196. package/dist/styles/toolbar.css +30 -28
  197. package/dist/styles/tooltip.css +10 -8
  198. package/dist/styles/web-preview.css +37 -21
  199. package/dist/utils/structured-code.d.ts +10 -0
  200. package/dist/utils/structured-code.js +81 -0
  201. package/package.json +16 -7
  202. package/dist/index.d.ts +0 -7236
  203. package/dist/index.js +0 -8945
@@ -0,0 +1,81 @@
1
+ import "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Fieldset as Fieldset$1 } from "@base-ui/react/fieldset";
4
+ //#region src/components/Fieldset.tsx
5
+ /**
6
+ * Groups the fieldset legend and associated fields.
7
+ * Renders a `<fieldset>` element.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <Fieldset.Root>
12
+ * <Fieldset.Legend>Contact Information</Fieldset.Legend>
13
+ * <Field.Root>
14
+ * <Field.Label>Email</Field.Label>
15
+ * <Field.Control type="email" />
16
+ * </Field.Root>
17
+ * </Fieldset.Root>
18
+ * ```
19
+ *
20
+ * @see {@link https://base-ui.com/react/components/fieldset | Base UI Fieldset}
21
+ */
22
+ function FieldsetRoot({ className = "", ref, ...props }) {
23
+ const classes = ["fieldset", className].filter(Boolean).join(" ");
24
+ return /* @__PURE__ */ jsx(Fieldset$1.Root, {
25
+ ref,
26
+ className: classes,
27
+ ...props
28
+ });
29
+ }
30
+ /**
31
+ * Accessible label for the fieldset, automatically associated with it.
32
+ * Renders a `<div>` element (styled as legend).
33
+ */
34
+ function FieldsetLegend({ className = "", ref, ...props }) {
35
+ const classes = ["fieldset__legend", className].filter(Boolean).join(" ");
36
+ return /* @__PURE__ */ jsx(Fieldset$1.Legend, {
37
+ ref,
38
+ className: classes,
39
+ ...props
40
+ });
41
+ }
42
+ /**
43
+ * A native fieldset element with an easily stylable legend.
44
+ * Useful for grouping related form controls.
45
+ *
46
+ * @example
47
+ * ```tsx
48
+ * // Basic fieldset
49
+ * <Fieldset.Root>
50
+ * <Fieldset.Legend>Personal Information</Fieldset.Legend>
51
+ * <Field.Root name="firstName">
52
+ * <Field.Label>First Name</Field.Label>
53
+ * <Field.Control />
54
+ * </Field.Root>
55
+ * <Field.Root name="lastName">
56
+ * <Field.Label>Last Name</Field.Label>
57
+ * <Field.Control />
58
+ * </Field.Root>
59
+ * </Fieldset.Root>
60
+ * ```
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * // With checkbox group
65
+ * <Fieldset.Root>
66
+ * <Fieldset.Legend>Notification Preferences</Fieldset.Legend>
67
+ * <CheckboxGroup>
68
+ * <label><Checkbox name="email" /> Email</label>
69
+ * <label><Checkbox name="sms" /> SMS</label>
70
+ * </CheckboxGroup>
71
+ * </Fieldset.Root>
72
+ * ```
73
+ *
74
+ * @see {@link https://base-ui.com/react/components/fieldset | Base UI Fieldset}
75
+ */
76
+ const Fieldset = {
77
+ Root: FieldsetRoot,
78
+ Legend: FieldsetLegend
79
+ };
80
+ //#endregion
81
+ export { Fieldset };
@@ -0,0 +1,116 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/components/FileTree.d.ts
4
+ interface FileTreeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect"> {
5
+ /** Set of folder paths that should be expanded. Controlled mode. */
6
+ expanded?: Set<string>;
7
+ /** Initial set of expanded folder paths. Uncontrolled mode. */
8
+ defaultExpanded?: Set<string>;
9
+ /** Currently selected file path. Controlled mode. */
10
+ selectedPath?: string | null;
11
+ /** Called when a file is selected. */
12
+ onSelect?: (path: string) => void;
13
+ /** Called when the expanded set changes. */
14
+ onExpandedChange?: (next: Set<string>) => void;
15
+ }
16
+ /**
17
+ * A keyboard-accessible hierarchical file browser. Compose with
18
+ * FileTreeFolder and FileTreeFile children.
19
+ *
20
+ * Keyboard: ↑/↓ move focus, →/← expand/collapse folders, Enter/Space
21
+ * selects files and selects/toggles folders, Home/End jump to first/last node.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <FileTree defaultExpanded={new Set(["src"])}>
26
+ * <FileTreeFolder path="src" name="src">
27
+ * <FileTreeFile path="src/index.ts" name="index.ts" />
28
+ * <FileTreeFolder path="src/lib" name="lib">
29
+ * <FileTreeFile path="src/lib/utils.ts" name="utils.ts" />
30
+ * </FileTreeFolder>
31
+ * </FileTreeFolder>
32
+ * </FileTree>
33
+ * ```
34
+ */
35
+ declare function FileTree({
36
+ className,
37
+ "aria-label": ariaLabel,
38
+ expanded,
39
+ defaultExpanded,
40
+ selectedPath,
41
+ onSelect,
42
+ onExpandedChange,
43
+ children,
44
+ ref,
45
+ ...props
46
+ }: FileTreeProps & {
47
+ ref?: React.Ref<HTMLDivElement>;
48
+ }): React.JSX.Element;
49
+ interface FileTreeFolderProps extends React.HTMLAttributes<HTMLLIElement> {
50
+ /** Unique path identifier for this folder. */
51
+ path: string;
52
+ /** Display name. */
53
+ name: string;
54
+ /** Depth level (0 for top-level). Auto-incremented by nested folders. */
55
+ level?: number;
56
+ }
57
+ declare function FileTreeFolder({
58
+ className,
59
+ path,
60
+ name,
61
+ level,
62
+ children,
63
+ ref,
64
+ ...props
65
+ }: FileTreeFolderProps & {
66
+ ref?: React.Ref<HTMLLIElement>;
67
+ }): React.JSX.Element;
68
+ interface FileTreeFileProps extends React.HTMLAttributes<HTMLLIElement> {
69
+ path: string;
70
+ name: string;
71
+ /** Optional custom icon; defaults to a generic file icon. */
72
+ icon?: React.ReactNode;
73
+ /** Depth level, auto-set by parent folder. */
74
+ level?: number;
75
+ }
76
+ declare function FileTreeFile({
77
+ className,
78
+ path,
79
+ name,
80
+ icon,
81
+ level,
82
+ ref,
83
+ ...props
84
+ }: FileTreeFileProps & {
85
+ ref?: React.Ref<HTMLLIElement>;
86
+ }): React.JSX.Element;
87
+ interface FileTreeIconProps extends React.HTMLAttributes<HTMLSpanElement> {}
88
+ declare function FileTreeIcon({
89
+ className,
90
+ children,
91
+ ref,
92
+ ...props
93
+ }: FileTreeIconProps & {
94
+ ref?: React.Ref<HTMLSpanElement>;
95
+ }): React.JSX.Element;
96
+ interface FileTreeNameProps extends React.HTMLAttributes<HTMLSpanElement> {}
97
+ declare function FileTreeName({
98
+ className,
99
+ children,
100
+ ref,
101
+ ...props
102
+ }: FileTreeNameProps & {
103
+ ref?: React.Ref<HTMLSpanElement>;
104
+ }): React.JSX.Element;
105
+ interface FileTreeActionsProps extends React.HTMLAttributes<HTMLDivElement> {}
106
+ declare function FileTreeActions({
107
+ className,
108
+ children,
109
+ onClick,
110
+ ref,
111
+ ...props
112
+ }: FileTreeActionsProps & {
113
+ ref?: React.Ref<HTMLDivElement>;
114
+ }): React.JSX.Element;
115
+ //#endregion
116
+ export { FileTree, FileTreeActions, FileTreeActionsProps, FileTreeFile, FileTreeFileProps, FileTreeFolder, FileTreeFolderProps, FileTreeIcon, FileTreeIconProps, FileTreeName, FileTreeNameProps, FileTreeProps };
@@ -0,0 +1,310 @@
1
+ import { c as ChevronRightIcon, g as FolderOpenIcon, h as FolderIcon, m as FileIcon } from "../icons-BsWc8g4E.js";
2
+ import { t as cx } from "../class-names-9UtZwb0J.js";
3
+ import * as React from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/_internal/use-file-tree-nav.ts
6
+ const FileTreeContext = React.createContext(null);
7
+ function useFileTreeContext() {
8
+ const ctx = React.useContext(FileTreeContext);
9
+ if (!ctx) throw new Error("FileTree subcomponents must be used inside <FileTree>.");
10
+ return ctx;
11
+ }
12
+ /**
13
+ * Builds a FileTreeContextValue that tracks registered nodes and dispatches
14
+ * keyboard navigation per the WAI-ARIA Tree Pattern.
15
+ *
16
+ * Call `register` from every FileTreeFolder/FileTreeFile during render. The
17
+ * hook resets its internal list on each render pass so removed nodes don't
18
+ * leave stale entries.
19
+ */
20
+ function useFileTreeNav({ expanded, selectedPath, onSelect, onExpandedChange }) {
21
+ const [focusedPath, setFocusedPath] = React.useState(null);
22
+ const nodesRef = React.useRef([]);
23
+ nodesRef.current = [];
24
+ const register = React.useCallback((path, kind, parentExpanded) => {
25
+ nodesRef.current.push({
26
+ path,
27
+ kind,
28
+ visible: parentExpanded
29
+ });
30
+ }, []);
31
+ const visibleNodes = () => nodesRef.current.filter((n) => n.visible);
32
+ const moveFocus = React.useCallback((direction, from) => {
33
+ const visible = visibleNodes();
34
+ const idx = visible.findIndex((n) => n.path === from);
35
+ if (idx < 0) return;
36
+ const next = visible[Math.max(0, Math.min(visible.length - 1, idx + direction))];
37
+ if (next) setFocusedPath(next.path);
38
+ }, []);
39
+ const focusFirstVisibleNode = React.useCallback(() => {
40
+ const first = visibleNodes()[0];
41
+ if (first) setFocusedPath(first.path);
42
+ }, []);
43
+ const focusLastVisibleNode = React.useCallback(() => {
44
+ const visible = visibleNodes();
45
+ const last = visible[visible.length - 1];
46
+ if (last) setFocusedPath(last.path);
47
+ }, []);
48
+ const setFolderExpanded = React.useCallback((path, nextExpanded) => {
49
+ const next = new Set(expanded);
50
+ if (nextExpanded) next.add(path);
51
+ else next.delete(path);
52
+ onExpandedChange(next);
53
+ }, [expanded, onExpandedChange]);
54
+ const toggleFolderExpanded = React.useCallback((path) => {
55
+ setFolderExpanded(path, !expanded.has(path));
56
+ }, [expanded, setFolderExpanded]);
57
+ const keyHandlers = React.useMemo(() => ({
58
+ ArrowDown(path) {
59
+ moveFocus(1, path);
60
+ },
61
+ ArrowUp(path) {
62
+ moveFocus(-1, path);
63
+ },
64
+ ArrowRight(path, kind) {
65
+ if (!(kind === "folder")) return;
66
+ if (expanded.has(path)) moveFocus(1, path);
67
+ else setFolderExpanded(path, true);
68
+ },
69
+ ArrowLeft(path, kind) {
70
+ if (kind === "folder" && expanded.has(path)) setFolderExpanded(path, false);
71
+ },
72
+ Enter(path, kind) {
73
+ if (kind === "folder") {
74
+ onSelect(path);
75
+ toggleFolderExpanded(path);
76
+ } else onSelect(path);
77
+ },
78
+ " "(path, kind) {
79
+ if (kind === "folder") {
80
+ onSelect(path);
81
+ toggleFolderExpanded(path);
82
+ } else onSelect(path);
83
+ },
84
+ Home() {
85
+ focusFirstVisibleNode();
86
+ },
87
+ End() {
88
+ focusLastVisibleNode();
89
+ }
90
+ }), [
91
+ expanded,
92
+ focusFirstVisibleNode,
93
+ focusLastVisibleNode,
94
+ moveFocus,
95
+ onSelect,
96
+ setFolderExpanded,
97
+ toggleFolderExpanded
98
+ ]);
99
+ const handleKeyDown = React.useCallback((event, path, kind) => {
100
+ const keyHandler = keyHandlers[event.key];
101
+ if (!keyHandler) return;
102
+ event.preventDefault();
103
+ keyHandler(path, kind);
104
+ }, [keyHandlers]);
105
+ return {
106
+ focusedPath,
107
+ selectedPath,
108
+ expanded,
109
+ onFocus: React.useCallback((path) => {
110
+ setFocusedPath(path);
111
+ }, []),
112
+ onSelect,
113
+ onExpandedChange: React.useCallback((path, next) => {
114
+ setFolderExpanded(path, next);
115
+ }, [setFolderExpanded]),
116
+ register,
117
+ handleKeyDown
118
+ };
119
+ }
120
+ //#endregion
121
+ //#region src/components/FileTree.tsx
122
+ /**
123
+ * A keyboard-accessible hierarchical file browser. Compose with
124
+ * FileTreeFolder and FileTreeFile children.
125
+ *
126
+ * Keyboard: ↑/↓ move focus, →/← expand/collapse folders, Enter/Space
127
+ * selects files and selects/toggles folders, Home/End jump to first/last node.
128
+ *
129
+ * @example
130
+ * ```tsx
131
+ * <FileTree defaultExpanded={new Set(["src"])}>
132
+ * <FileTreeFolder path="src" name="src">
133
+ * <FileTreeFile path="src/index.ts" name="index.ts" />
134
+ * <FileTreeFolder path="src/lib" name="lib">
135
+ * <FileTreeFile path="src/lib/utils.ts" name="utils.ts" />
136
+ * </FileTreeFolder>
137
+ * </FileTreeFolder>
138
+ * </FileTree>
139
+ * ```
140
+ */
141
+ function FileTree({ className, "aria-label": ariaLabel = "File tree", expanded, defaultExpanded, selectedPath = null, onSelect, onExpandedChange, children, ref, ...props }) {
142
+ const [internalExpanded, setInternalExpanded] = React.useState(() => defaultExpanded ?? /* @__PURE__ */ new Set());
143
+ const isControlled = expanded !== void 0;
144
+ const currentExpanded = isControlled ? expanded : internalExpanded;
145
+ const handleExpandedChange = React.useCallback((next) => {
146
+ if (!isControlled) setInternalExpanded(next);
147
+ onExpandedChange?.(next);
148
+ }, [isControlled, onExpandedChange]);
149
+ const ctx = useFileTreeNav({
150
+ expanded: currentExpanded,
151
+ selectedPath,
152
+ onSelect: React.useCallback((path) => {
153
+ onSelect?.(path);
154
+ }, [onSelect]),
155
+ onExpandedChange: handleExpandedChange
156
+ });
157
+ return /* @__PURE__ */ jsx(FileTreeContext.Provider, {
158
+ value: ctx,
159
+ children: /* @__PURE__ */ jsx("div", {
160
+ ref,
161
+ className: cx("file-tree", className),
162
+ ...props,
163
+ children: /* @__PURE__ */ jsx("ul", {
164
+ className: "file-tree__list",
165
+ role: "tree",
166
+ "aria-label": ariaLabel,
167
+ tabIndex: 0,
168
+ children
169
+ })
170
+ })
171
+ });
172
+ }
173
+ function renderNestedFileTreeChild(child, level) {
174
+ if (React.isValidElement(child) && (child.type === FileTreeFolder || child.type === FileTreeFile)) return React.cloneElement(child, { level: level + 1 });
175
+ return child;
176
+ }
177
+ function dataFlag(enabled) {
178
+ return enabled ? "" : void 0;
179
+ }
180
+ function getFileTreeNodeTabIndex(focusedPath, path, level) {
181
+ return focusedPath === path || !focusedPath && level === 0 ? 0 : -1;
182
+ }
183
+ function getFileTreeNodeIndent(level, offset) {
184
+ return `${level * 1.125 + offset}rem`;
185
+ }
186
+ function FileTreeFolder({ className, path, name, level = 0, children, ref, ...props }) {
187
+ const { expanded, focusedPath, selectedPath, onFocus, onSelect, register, handleKeyDown, onExpandedChange } = useFileTreeContext();
188
+ const isExpanded = expanded.has(path);
189
+ const isFocused = focusedPath === path;
190
+ const isSelected = selectedPath === path;
191
+ register(path, "folder", true);
192
+ const toggle = React.useCallback(() => {
193
+ onExpandedChange(path, !isExpanded);
194
+ }, [
195
+ isExpanded,
196
+ onExpandedChange,
197
+ path
198
+ ]);
199
+ const handleClick = React.useCallback(() => {
200
+ onSelect(path);
201
+ toggle();
202
+ }, [
203
+ onSelect,
204
+ path,
205
+ toggle
206
+ ]);
207
+ return /* @__PURE__ */ jsxs("li", {
208
+ ref,
209
+ role: "treeitem",
210
+ "aria-expanded": isExpanded,
211
+ "aria-selected": isSelected,
212
+ className: cx("file-tree__folder", className),
213
+ ...props,
214
+ children: [/* @__PURE__ */ jsxs("button", {
215
+ type: "button",
216
+ className: "file-tree__node file-tree__node--folder",
217
+ "data-focused": dataFlag(isFocused),
218
+ "data-selected": dataFlag(isSelected),
219
+ tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
220
+ onClick: handleClick,
221
+ onFocus: () => onFocus(path),
222
+ onKeyDown: (e) => handleKeyDown(e, path, "folder"),
223
+ style: { paddingInlineStart: getFileTreeNodeIndent(level, .5) },
224
+ children: [
225
+ /* @__PURE__ */ jsx("span", {
226
+ className: cx("file-tree__chevron", isExpanded && "file-tree__chevron--expanded"),
227
+ "aria-hidden": "true",
228
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
229
+ }),
230
+ /* @__PURE__ */ jsx("span", {
231
+ className: "file-tree__icon",
232
+ "aria-hidden": "true",
233
+ children: isExpanded ? /* @__PURE__ */ jsx(FolderOpenIcon, {}) : /* @__PURE__ */ jsx(FolderIcon, {})
234
+ }),
235
+ /* @__PURE__ */ jsx("span", {
236
+ className: "file-tree__name",
237
+ children: name
238
+ })
239
+ ]
240
+ }), isExpanded ? /* @__PURE__ */ jsx("ul", {
241
+ className: "file-tree__list",
242
+ role: "group",
243
+ children: React.Children.map(children, (child) => renderNestedFileTreeChild(child, level))
244
+ }) : null]
245
+ });
246
+ }
247
+ function FileTreeFile({ className, path, name, icon, level = 0, ref, ...props }) {
248
+ const { selectedPath, focusedPath, onFocus, onSelect, register, handleKeyDown } = useFileTreeContext();
249
+ const isSelected = selectedPath === path;
250
+ const isFocused = focusedPath === path;
251
+ register(path, "file", true);
252
+ return /* @__PURE__ */ jsx("li", {
253
+ ref,
254
+ role: "treeitem",
255
+ "aria-selected": isSelected,
256
+ className: cx("file-tree__file", className),
257
+ ...props,
258
+ children: /* @__PURE__ */ jsxs("button", {
259
+ type: "button",
260
+ className: "file-tree__node file-tree__node--file",
261
+ "data-selected": dataFlag(isSelected),
262
+ "data-focused": dataFlag(isFocused),
263
+ tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
264
+ onClick: () => onSelect(path),
265
+ onFocus: () => onFocus(path),
266
+ onKeyDown: (e) => handleKeyDown(e, path, "file"),
267
+ style: { paddingInlineStart: getFileTreeNodeIndent(level, 1.5) },
268
+ children: [/* @__PURE__ */ jsx("span", {
269
+ className: "file-tree__icon",
270
+ "aria-hidden": "true",
271
+ children: icon ?? /* @__PURE__ */ jsx(FileIcon, {})
272
+ }), /* @__PURE__ */ jsx("span", {
273
+ className: "file-tree__name",
274
+ children: name
275
+ })]
276
+ })
277
+ });
278
+ }
279
+ function FileTreeIcon({ className, children, ref, ...props }) {
280
+ return /* @__PURE__ */ jsx("span", {
281
+ ref,
282
+ className: cx("file-tree__icon", className),
283
+ "aria-hidden": "true",
284
+ ...props,
285
+ children
286
+ });
287
+ }
288
+ function FileTreeName({ className, children, ref, ...props }) {
289
+ return /* @__PURE__ */ jsx("span", {
290
+ ref,
291
+ className: cx("file-tree__name", className),
292
+ ...props,
293
+ children
294
+ });
295
+ }
296
+ function FileTreeActions({ className, children, onClick, ref, ...props }) {
297
+ const handleClick = React.useCallback((e) => {
298
+ e.stopPropagation();
299
+ onClick?.(e);
300
+ }, [onClick]);
301
+ return /* @__PURE__ */ jsx("div", {
302
+ ref,
303
+ className: cx("file-tree__actions", className),
304
+ onClick: handleClick,
305
+ ...props,
306
+ children
307
+ });
308
+ }
309
+ //#endregion
310
+ export { FileTree, FileTreeActions, FileTreeFile, FileTreeFolder, FileTreeIcon, FileTreeName };
@@ -0,0 +1,94 @@
1
+ import * as React from "react";
2
+ import { Form as Form$1 } from "@base-ui/react/form";
3
+
4
+ //#region src/components/Form.d.ts
5
+ /**
6
+ * Props for the Form component.
7
+ */
8
+ interface FormProps extends Omit<React.ComponentPropsWithoutRef<typeof Form$1>, "className"> {
9
+ /** Additional CSS class names */
10
+ className?: string;
11
+ }
12
+ /**
13
+ * A form component that provides consolidated error handling and validation
14
+ * for form controls. Works seamlessly with the Field component.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * // Basic usage with Field components
19
+ * <Form onFormSubmit={(values) => console.log(values)}>
20
+ * <Field.Root name="username">
21
+ * <Field.Label>Username</Field.Label>
22
+ * <Field.Control required />
23
+ * <Field.Error match="valueMissing">Username is required</Field.Error>
24
+ * </Field.Root>
25
+ *
26
+ * <Field.Root name="email">
27
+ * <Field.Label>Email</Field.Label>
28
+ * <Field.Control type="email" required />
29
+ * <Field.Error match="valueMissing">Email is required</Field.Error>
30
+ * <Field.Error match="typeMismatch">Invalid email format</Field.Error>
31
+ * </Field.Root>
32
+ *
33
+ * <Button type="submit">Submit</Button>
34
+ * </Form>
35
+ * ```
36
+ *
37
+ * @example
38
+ * ```tsx
39
+ * // With external/server errors
40
+ * const [errors, setErrors] = useState({});
41
+ *
42
+ * async function handleSubmit(values) {
43
+ * const result = await api.submit(values);
44
+ * if (result.errors) {
45
+ * setErrors(result.errors); // { email: "Already registered" }
46
+ * }
47
+ * }
48
+ *
49
+ * <Form errors={errors} onFormSubmit={handleSubmit}>
50
+ * <Field.Root name="email">
51
+ * <Field.Control type="email" />
52
+ * <Field.Error />
53
+ * </Field.Root>
54
+ * </Form>
55
+ * ```
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * // Native submit handlers remain native, so TanStack Form can own state.
60
+ * <Form
61
+ * onSubmit={(event) => {
62
+ * event.preventDefault();
63
+ * void form.handleSubmit();
64
+ * }}
65
+ * >
66
+ * ...
67
+ * </Form>
68
+ * ```
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * // With validation modes
73
+ * // Fields validate when they lose focus
74
+ * <Form validationMode="onBlur">
75
+ * ...
76
+ * </Form>
77
+ *
78
+ * // Fields validate as user types
79
+ * <Form validationMode="onChange">
80
+ * ...
81
+ * </Form>
82
+ * ```
83
+ *
84
+ * @see {@link https://base-ui.com/react/components/form | Base UI Form}
85
+ */
86
+ declare function Form({
87
+ className,
88
+ ref,
89
+ ...props
90
+ }: FormProps & {
91
+ ref?: React.Ref<HTMLFormElement>;
92
+ }): React.JSX.Element;
93
+ //#endregion
94
+ export { Form, FormProps };
@@ -0,0 +1,88 @@
1
+ import "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Form as Form$1 } from "@base-ui/react/form";
4
+ //#region src/components/Form.tsx
5
+ /**
6
+ * A form component that provides consolidated error handling and validation
7
+ * for form controls. Works seamlessly with the Field component.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * // Basic usage with Field components
12
+ * <Form onFormSubmit={(values) => console.log(values)}>
13
+ * <Field.Root name="username">
14
+ * <Field.Label>Username</Field.Label>
15
+ * <Field.Control required />
16
+ * <Field.Error match="valueMissing">Username is required</Field.Error>
17
+ * </Field.Root>
18
+ *
19
+ * <Field.Root name="email">
20
+ * <Field.Label>Email</Field.Label>
21
+ * <Field.Control type="email" required />
22
+ * <Field.Error match="valueMissing">Email is required</Field.Error>
23
+ * <Field.Error match="typeMismatch">Invalid email format</Field.Error>
24
+ * </Field.Root>
25
+ *
26
+ * <Button type="submit">Submit</Button>
27
+ * </Form>
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * // With external/server errors
33
+ * const [errors, setErrors] = useState({});
34
+ *
35
+ * async function handleSubmit(values) {
36
+ * const result = await api.submit(values);
37
+ * if (result.errors) {
38
+ * setErrors(result.errors); // { email: "Already registered" }
39
+ * }
40
+ * }
41
+ *
42
+ * <Form errors={errors} onFormSubmit={handleSubmit}>
43
+ * <Field.Root name="email">
44
+ * <Field.Control type="email" />
45
+ * <Field.Error />
46
+ * </Field.Root>
47
+ * </Form>
48
+ * ```
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * // Native submit handlers remain native, so TanStack Form can own state.
53
+ * <Form
54
+ * onSubmit={(event) => {
55
+ * event.preventDefault();
56
+ * void form.handleSubmit();
57
+ * }}
58
+ * >
59
+ * ...
60
+ * </Form>
61
+ * ```
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * // With validation modes
66
+ * // Fields validate when they lose focus
67
+ * <Form validationMode="onBlur">
68
+ * ...
69
+ * </Form>
70
+ *
71
+ * // Fields validate as user types
72
+ * <Form validationMode="onChange">
73
+ * ...
74
+ * </Form>
75
+ * ```
76
+ *
77
+ * @see {@link https://base-ui.com/react/components/form | Base UI Form}
78
+ */
79
+ function Form({ className = "", ref, ...props }) {
80
+ return /* @__PURE__ */ jsx(Form$1, {
81
+ ref,
82
+ "data-slot": "form",
83
+ className: ["form", className].filter(Boolean).join(" "),
84
+ ...props
85
+ });
86
+ }
87
+ //#endregion
88
+ export { Form };
@@ -0,0 +1,13 @@
1
+ //#region src/components/GithubMotionMark.d.ts
2
+ /**
3
+ * Small GitHub motion mark used next to install or repository connection text.
4
+ */
5
+ declare function GithubMotionMark({
6
+ className,
7
+ size
8
+ }: {
9
+ readonly className?: string;
10
+ readonly size?: number;
11
+ }): import("react").JSX.Element;
12
+ //#endregion
13
+ export { GithubMotionMark };