@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.
- package/dist/Button-QCM8ZKgR.d.ts +98 -0
- package/dist/CodeBlock-CttHhWcb.js +356 -0
- package/dist/CodeBlock-V6pgafSS.d.ts +174 -0
- package/dist/Select-CRsKCJ9x.d.ts +200 -0
- package/dist/class-names-9UtZwb0J.js +12 -0
- package/dist/components/Accordion.d.ts +81 -0
- package/dist/components/Accordion.js +97 -0
- package/dist/components/AgentConnection.d.ts +69 -0
- package/dist/components/AgentConnection.js +176 -0
- package/dist/components/AlertDialog.d.ts +148 -0
- package/dist/components/AlertDialog.js +141 -0
- package/dist/components/Artifact.d.ts +128 -0
- package/dist/components/Artifact.js +115 -0
- package/dist/components/Autocomplete.d.ts +186 -0
- package/dist/components/Autocomplete.js +186 -0
- package/dist/components/Avatar.d.ts +134 -0
- package/dist/components/Avatar.js +118 -0
- package/dist/components/Badge.d.ts +68 -0
- package/dist/components/Badge.js +108 -0
- package/dist/components/Button.d.ts +2 -0
- package/dist/components/Button.js +73 -0
- package/dist/components/Card.d.ts +87 -0
- package/dist/components/Card.js +81 -0
- package/dist/components/ChainOfThought.d.ts +153 -0
- package/dist/components/ChainOfThought.js +157 -0
- package/dist/components/Checkbox.d.ts +35 -0
- package/dist/components/Checkbox.js +47 -0
- package/dist/components/CheckboxGroup.d.ts +76 -0
- package/dist/components/CheckboxGroup.js +69 -0
- package/dist/components/CodeBlock.d.ts +2 -0
- package/dist/components/CodeBlock.js +2 -0
- package/dist/components/Collapsible.d.ts +127 -0
- package/dist/components/Collapsible.js +103 -0
- package/dist/components/Combobox.d.ts +177 -0
- package/dist/components/Combobox.js +179 -0
- package/dist/components/Commit.d.ts +265 -0
- package/dist/components/Commit.js +282 -0
- package/dist/components/Context.d.ts +129 -0
- package/dist/components/Context.js +309 -0
- package/dist/components/ContextMenu.d.ts +282 -0
- package/dist/components/ContextMenu.js +270 -0
- package/dist/components/Conversation.d.ts +166 -0
- package/dist/components/Conversation.js +202 -0
- package/dist/components/Dialog.d.ts +120 -0
- package/dist/components/Dialog.js +114 -0
- package/dist/components/EnvironmentVariables.d.ts +176 -0
- package/dist/components/EnvironmentVariables.js +221 -0
- package/dist/components/Field.d.ts +281 -0
- package/dist/components/Field.js +274 -0
- package/dist/components/Fieldset.d.ts +93 -0
- package/dist/components/Fieldset.js +81 -0
- package/dist/components/FileTree.d.ts +116 -0
- package/dist/components/FileTree.js +310 -0
- package/dist/components/Form.d.ts +94 -0
- package/dist/components/Form.js +88 -0
- package/dist/components/GithubMotionMark.d.ts +13 -0
- package/dist/components/GithubMotionMark.js +23 -0
- package/dist/components/Input.d.ts +33 -0
- package/dist/components/Input.js +27 -0
- package/dist/components/Label.d.ts +44 -0
- package/dist/components/Label.js +41 -0
- package/dist/components/Menu.d.ts +395 -0
- package/dist/components/Menu.js +338 -0
- package/dist/components/Menubar.d.ts +331 -0
- package/dist/components/Menubar.js +299 -0
- package/dist/components/Message.d.ts +216 -0
- package/dist/components/Message.js +245 -0
- package/dist/components/Meter.d.ts +151 -0
- package/dist/components/Meter.js +121 -0
- package/dist/components/ModelSelector.d.ts +198 -0
- package/dist/components/ModelSelector.js +306 -0
- package/dist/components/NaniteScene.d.ts +33 -0
- package/dist/components/NaniteScene.js +405 -0
- package/dist/components/NavigationMenu.d.ts +256 -0
- package/dist/components/NavigationMenu.js +228 -0
- package/dist/components/NumberField.d.ts +159 -0
- package/dist/components/NumberField.js +123 -0
- package/dist/components/Popover.d.ts +278 -0
- package/dist/components/Popover.js +245 -0
- package/dist/components/PreviewCard.d.ts +156 -0
- package/dist/components/PreviewCard.js +156 -0
- package/dist/components/PricingPage.d.ts +209 -0
- package/dist/components/PricingPage.js +506 -0
- package/dist/components/Progress.d.ts +58 -0
- package/dist/components/Progress.js +51 -0
- package/dist/components/PromptInput.d.ts +399 -0
- package/dist/components/PromptInput.js +737 -0
- package/dist/components/Queue.d.ts +241 -0
- package/dist/components/Queue.js +225 -0
- package/dist/components/RadioGroup.d.ts +78 -0
- package/dist/components/RadioGroup.js +72 -0
- package/dist/components/Reasoning.d.ts +88 -0
- package/dist/components/Reasoning.js +187 -0
- package/dist/components/ScrollArea.d.ts +160 -0
- package/dist/components/ScrollArea.js +145 -0
- package/dist/components/Select.d.ts +2 -0
- package/dist/components/Select.js +260 -0
- package/dist/components/Separator.d.ts +45 -0
- package/dist/components/Separator.js +40 -0
- package/dist/components/Shell.d.ts +163 -0
- package/dist/components/Shell.js +137 -0
- package/dist/components/Slider.d.ts +120 -0
- package/dist/components/Slider.js +115 -0
- package/dist/components/Sources.d.ts +91 -0
- package/dist/components/Sources.js +121 -0
- package/dist/components/Stepper.d.ts +190 -0
- package/dist/components/Stepper.js +315 -0
- package/dist/components/Switch.d.ts +57 -0
- package/dist/components/Switch.js +55 -0
- package/dist/components/Tabs.d.ts +84 -0
- package/dist/components/Tabs.js +78 -0
- package/dist/components/Task.d.ts +100 -0
- package/dist/components/Task.js +120 -0
- package/dist/components/Terminal.d.ts +118 -0
- package/dist/components/Terminal.js +234 -0
- package/dist/components/TestResults.d.ts +236 -0
- package/dist/components/TestResults.js +346 -0
- package/dist/components/Toast.d.ts +192 -0
- package/dist/components/Toast.js +163 -0
- package/dist/components/Toggle.d.ts +69 -0
- package/dist/components/Toggle.js +66 -0
- package/dist/components/ToggleGroup.d.ts +69 -0
- package/dist/components/ToggleGroup.js +99 -0
- package/dist/components/Tool.d.ts +119 -0
- package/dist/components/Tool.js +192 -0
- package/dist/components/Toolbar.d.ts +162 -0
- package/dist/components/Toolbar.js +126 -0
- package/dist/components/Tooltip.d.ts +81 -0
- package/dist/components/Tooltip.js +74 -0
- package/dist/components/WebPreview.d.ts +143 -0
- package/dist/components/WebPreview.js +280 -0
- package/dist/components/useStickToBottom.d.ts +30 -0
- package/dist/components/useStickToBottom.js +95 -0
- package/dist/copy-button-BIATcZWZ.d.ts +16 -0
- package/dist/copy-button-BNgclDrO.js +43 -0
- package/dist/icons-BsWc8g4E.js +221 -0
- package/dist/styles/accordion.css +10 -10
- package/dist/styles/agent-connection.css +18 -17
- package/dist/styles/alert-dialog.css +48 -29
- package/dist/styles/artifact.css +10 -10
- package/dist/styles/autocomplete.css +25 -24
- package/dist/styles/avatar.css +96 -6
- package/dist/styles/badge.css +78 -14
- package/dist/styles/base.css +9 -9
- package/dist/styles/button.css +57 -38
- package/dist/styles/card.css +57 -10
- package/dist/styles/chain-of-thought.css +47 -33
- package/dist/styles/checkbox.css +24 -10
- package/dist/styles/code-block.css +22 -15
- package/dist/styles/collapsible.css +14 -12
- package/dist/styles/combobox.css +26 -25
- package/dist/styles/commit.css +49 -24
- package/dist/styles/context-menu.css +70 -16
- package/dist/styles/context.css +15 -15
- package/dist/styles/conversation.css +12 -12
- package/dist/styles/dialog.css +52 -16
- package/dist/styles/environment-variables.css +19 -19
- package/dist/styles/field.css +184 -22
- package/dist/styles/fieldset.css +5 -4
- package/dist/styles/file-tree.css +17 -17
- package/dist/styles/index.css.d.ts +1 -0
- package/dist/styles/input.css +45 -11
- package/dist/styles/label.css +21 -4
- package/dist/styles/menu.css +55 -32
- package/dist/styles/menubar.css +80 -28
- package/dist/styles/message.css +22 -13
- package/dist/styles/meter.css +8 -8
- package/dist/styles/model-selector.css +33 -21
- package/dist/styles/navigation-menu.css +26 -24
- package/dist/styles/number-field.css +20 -18
- package/dist/styles/popover.css +38 -28
- package/dist/styles/preview-card.css +15 -13
- package/dist/styles/pricing-page.css +53 -53
- package/dist/styles/progress.css +7 -7
- package/dist/styles/prompt-input.css +73 -24
- package/dist/styles/queue.css +58 -32
- package/dist/styles/radio.css +26 -11
- package/dist/styles/reasoning.css +15 -11
- package/dist/styles/scroll-area.css +6 -6
- package/dist/styles/scrollbars.css +4 -4
- package/dist/styles/select.css +84 -25
- package/dist/styles/separator.css +1 -1
- package/dist/styles/shell.css +21 -20
- package/dist/styles/slider.css +35 -11
- package/dist/styles/sources.css +20 -20
- package/dist/styles/stepper.css +22 -22
- package/dist/styles/switch.css +29 -13
- package/dist/styles/tabs.css +23 -16
- package/dist/styles/task.css +27 -23
- package/dist/styles/terminal.css +16 -13
- package/dist/styles/test-results.css +79 -32
- package/dist/styles/toast.css +26 -25
- package/dist/styles/toggle-group.css +12 -12
- package/dist/styles/toggle.css +29 -11
- package/dist/styles/tool.css +54 -32
- package/dist/styles/toolbar.css +30 -28
- package/dist/styles/tooltip.css +10 -8
- package/dist/styles/web-preview.css +37 -21
- package/dist/utils/structured-code.d.ts +10 -0
- package/dist/utils/structured-code.js +81 -0
- package/package.json +16 -7
- package/dist/index.d.ts +0 -7236
- 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 };
|