@burtson-labs/ui 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/components/composer.d.ts +12 -2
- package/dist/components/composer.js +2 -2
- package/dist/components/composer.js.map +1 -1
- package/dist/components/context-menu.d.ts +30 -0
- package/dist/components/context-menu.js +131 -0
- package/dist/components/context-menu.js.map +1 -0
- package/dist/components/dropdown-menu.js +5 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editor-tabs.d.ts +47 -0
- package/dist/components/editor-tabs.js +221 -0
- package/dist/components/editor-tabs.js.map +1 -0
- package/dist/components/menubar.d.ts +30 -0
- package/dist/components/menubar.js +140 -0
- package/dist/components/menubar.js.map +1 -0
- package/dist/components/onboarding-checklist.d.ts +26 -0
- package/dist/components/onboarding-checklist.js +106 -0
- package/dist/components/onboarding-checklist.js.map +1 -0
- package/dist/components/popover.d.ts +2 -0
- package/dist/components/popover.js +3 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/resizable.d.ts +33 -0
- package/dist/components/resizable.js +54 -0
- package/dist/components/resizable.js.map +1 -0
- package/dist/components/tour.d.ts +96 -0
- package/dist/components/tour.js +367 -0
- package/dist/components/tour.js.map +1 -0
- package/dist/components/tree-view.d.ts +76 -0
- package/dist/components/tree-view.js +286 -0
- package/dist/components/tree-view.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +10 -3
- package/dist/styles.css +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ npx shadcn@latest add https://ui.burtson.ai/r/button.json
|
|
|
58
58
|
|
|
59
59
|
## <picture><source media="(prefers-color-scheme: dark)" srcset="https://icons.burtson.ai/svg-white/panel-grid.svg"/><img src="https://icons.burtson.ai/svg-black/panel-grid.svg" align="center" alt=""/></picture> Components
|
|
60
60
|
|
|
61
|
-
Accordion · Alert · Alert Dialog · App Shell · Avatar · Badge · Breadcrumb · Button · Card · Checkbox · Collapsible · Combobox · Command · Copy Button · Dialog · Dropdown Menu · Empty State · Field · Icon Button · Input · Kbd · Label · Navigation Menu · Page Header · Pagination · Popover · Progress · Radio Group · Reasoning · Scroll Area · Secret Input · Select · Separator · Sheet · Skeleton · Slider · Spinner · Stat Card · Status · Steps · Switch · Table · Tabs · Textarea · Toast · Toaster · Toolbar · Tooltip
|
|
61
|
+
Accordion · Alert · Alert Dialog · App Shell · Avatar · Badge · Breadcrumb · Button · Card · Checkbox · Collapsible · Combobox · Command · Context Menu · Copy Button · Dialog · Dropdown Menu · Editor Tabs · Empty State · Field · Icon Button · Input · Kbd · Label · Menubar · Navigation Menu · Onboarding Checklist · Page Header · Pagination · Popover · Progress · Radio Group · Reasoning · Resizable · Scroll Area · Secret Input · Select · Separator · Sheet · Skeleton · Slider · Spinner · Stat Card · Status · Steps · Switch · Table · Tabs · Textarea · Toast · Toaster · Toolbar · Tooltip · Tour · Tree View
|
|
62
62
|
|
|
63
63
|
Live previews and code for each one are at [ui.burtson.ai](https://ui.burtson.ai/docs/components/button).
|
|
64
64
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
export interface ComposerProps extends Omit<React.ComponentProps<'form'>, 'onSubmit' | 'onChange'> {
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Clears after success. Reject a returned promise to retain the draft. The
|
|
5
|
+
* text can be empty when `attachmentCount` allows an attachment-only send.
|
|
6
|
+
*/
|
|
4
7
|
onSubmit: (text: string) => void | Promise<void>;
|
|
5
8
|
onSubmitError?: (error: unknown) => void;
|
|
6
9
|
submitErrorText?: string;
|
|
@@ -14,6 +17,13 @@ export interface ComposerProps extends Omit<React.ComponentProps<'form'>, 'onSub
|
|
|
14
17
|
placeholder?: string;
|
|
15
18
|
/** Attachment chips or a file button, shown under the text. */
|
|
16
19
|
attachments?: React.ReactNode;
|
|
20
|
+
/** Attachments ready to send. Above zero, an empty message can be sent. */
|
|
21
|
+
attachmentCount?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Extra gate on sending, e.g. false while an attachment is still parsing.
|
|
24
|
+
* Unlike `disabled`, the person can keep typing.
|
|
25
|
+
*/
|
|
26
|
+
canSubmit?: boolean;
|
|
17
27
|
/** Extra controls left of the send button (model picker, tools). */
|
|
18
28
|
actions?: React.ReactNode;
|
|
19
29
|
label?: string;
|
|
@@ -22,7 +32,7 @@ export interface ComposerProps extends Omit<React.ComponentProps<'form'>, 'onSub
|
|
|
22
32
|
* The message box: grows with its text, Enter sends, Shift+Enter adds a
|
|
23
33
|
* line, and it never sends mid-composition (IME input).
|
|
24
34
|
*/
|
|
25
|
-
declare function Composer({ onSubmit, onSubmitError, submitErrorText, value: controlled, onValueChange, streaming, onStop, disabled, placeholder, attachments, actions, label, className, ...props }: ComposerProps): React.JSX.Element;
|
|
35
|
+
declare function Composer({ onSubmit, onSubmitError, submitErrorText, value: controlled, onValueChange, streaming, onStop, disabled, placeholder, attachments, attachmentCount, canSubmit, actions, label, className, ...props }: ComposerProps): React.JSX.Element;
|
|
26
36
|
export interface SuggestionsProps extends Omit<React.ComponentProps<'div'>, 'onSelect'> {
|
|
27
37
|
items: string[];
|
|
28
38
|
onSelect: (item: string) => void;
|
|
@@ -9,7 +9,7 @@ import Square from "@burtson-labs/icons/react/square";
|
|
|
9
9
|
* The message box: grows with its text, Enter sends, Shift+Enter adds a
|
|
10
10
|
* line, and it never sends mid-composition (IME input).
|
|
11
11
|
*/
|
|
12
|
-
function Composer({ onSubmit, onSubmitError, submitErrorText = "Message could not be sent. Your draft is saved here. Try again.", value: controlled, onValueChange, streaming = false, onStop, disabled = false, placeholder = "Ask anything…", attachments, actions, label = "Message", className, ...props }) {
|
|
12
|
+
function Composer({ onSubmit, onSubmitError, submitErrorText = "Message could not be sent. Your draft is saved here. Try again.", value: controlled, onValueChange, streaming = false, onStop, disabled = false, placeholder = "Ask anything…", attachments, attachmentCount = 0, canSubmit = true, actions, label = "Message", className, ...props }) {
|
|
13
13
|
const [own, setOwn] = React.useState("");
|
|
14
14
|
const value = controlled ?? own;
|
|
15
15
|
const [pending, setPending] = React.useState(false);
|
|
@@ -31,7 +31,7 @@ function Composer({ onSubmit, onSubmitError, submitErrorText = "Message could no
|
|
|
31
31
|
if (controlled === void 0) setOwn(v);
|
|
32
32
|
onValueChange?.(v);
|
|
33
33
|
};
|
|
34
|
-
const canSend = !disabled && !streaming && !pending && value.trim().length > 0;
|
|
34
|
+
const canSend = canSubmit && !disabled && !streaming && !pending && (value.trim().length > 0 || attachmentCount > 0);
|
|
35
35
|
const send = async () => {
|
|
36
36
|
if (!canSend || sending.current) return;
|
|
37
37
|
const draft = value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composer.js","names":[],"sources":["../../src/components/composer.tsx"],"sourcesContent":["import ArrowUp from '@burtson-labs/icons/react/arrow-up';\nimport Square from '@burtson-labs/icons/react/square';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\n\nexport interface ComposerProps extends Omit<React.ComponentProps<'form'>, 'onSubmit' | 'onChange'> {\n
|
|
1
|
+
{"version":3,"file":"composer.js","names":[],"sources":["../../src/components/composer.tsx"],"sourcesContent":["import ArrowUp from '@burtson-labs/icons/react/arrow-up';\nimport Square from '@burtson-labs/icons/react/square';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\n\nexport interface ComposerProps extends Omit<React.ComponentProps<'form'>, 'onSubmit' | 'onChange'> {\n /**\n * Clears after success. Reject a returned promise to retain the draft. The\n * text can be empty when `attachmentCount` allows an attachment-only send.\n */\n onSubmit: (text: string) => void | Promise<void>;\n onSubmitError?: (error: unknown) => void;\n submitErrorText?: string;\n /** Controlled value; leave out to let the composer keep its own. */\n value?: string;\n onValueChange?: (value: string) => void;\n /** While a reply streams, the send button becomes Stop. */\n streaming?: boolean;\n onStop?: () => void;\n disabled?: boolean;\n placeholder?: string;\n /** Attachment chips or a file button, shown under the text. */\n attachments?: React.ReactNode;\n /** Attachments ready to send. Above zero, an empty message can be sent. */\n attachmentCount?: number;\n /**\n * Extra gate on sending, e.g. false while an attachment is still parsing.\n * Unlike `disabled`, the person can keep typing.\n */\n canSubmit?: boolean;\n /** Extra controls left of the send button (model picker, tools). */\n actions?: React.ReactNode;\n label?: string;\n}\n\n/**\n * The message box: grows with its text, Enter sends, Shift+Enter adds a\n * line, and it never sends mid-composition (IME input).\n */\nfunction Composer({\n onSubmit,\n onSubmitError,\n submitErrorText = 'Message could not be sent. Your draft is saved here. Try again.',\n value: controlled,\n onValueChange,\n streaming = false,\n onStop,\n disabled = false,\n placeholder = 'Ask anything…',\n attachments,\n attachmentCount = 0,\n canSubmit = true,\n actions,\n label = 'Message',\n className,\n ...props\n}: ComposerProps) {\n const [own, setOwn] = React.useState('');\n const value = controlled ?? own;\n const [pending, setPending] = React.useState(false);\n const [failed, setFailed] = React.useState(false);\n const sending = React.useRef(false);\n const latest = React.useRef(value);\n const mounted = React.useRef(true);\n const errorId = React.useId();\n React.useEffect(() => {\n latest.current = value;\n }, [value]);\n React.useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n };\n }, []);\n const setValue = (v: string) => {\n if (controlled === undefined) setOwn(v);\n onValueChange?.(v);\n };\n const canSend =\n canSubmit &&\n !disabled &&\n !streaming &&\n !pending &&\n (value.trim().length > 0 || attachmentCount > 0);\n const send = async () => {\n if (!canSend || sending.current) return;\n const draft = value;\n sending.current = true;\n setFailed(false);\n setPending(true);\n try {\n await onSubmit(draft.trim());\n if (mounted.current && latest.current === draft) setValue('');\n } catch (error) {\n if (mounted.current) setFailed(true);\n onSubmitError?.(error);\n } finally {\n sending.current = false;\n if (mounted.current) setPending(false);\n }\n };\n\n return (\n <form\n data-slot=\"composer\"\n onSubmit={(e) => {\n e.preventDefault();\n void send();\n }}\n className={cn(\n 'grid gap-2 rounded-lg border border-input bg-surface p-2 shadow-xs transition-[border-color,box-shadow] focus-within:border-brand focus-within:ring-[3px] focus-within:ring-ring/15 dark:bg-surface-raised',\n disabled && 'opacity-60',\n className,\n )}\n {...props}\n >\n <textarea\n aria-label={label}\n rows={1}\n value={value}\n disabled={disabled || pending}\n aria-describedby={failed ? errorId : undefined}\n aria-invalid={failed || undefined}\n placeholder={placeholder}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (\n e.key === 'Enter' &&\n !e.shiftKey &&\n !e.nativeEvent.isComposing &&\n e.nativeEvent.keyCode !== 229\n ) {\n e.preventDefault();\n void send();\n }\n }}\n className=\"field-sizing-content max-h-48 min-h-9 w-full resize-none bg-transparent px-2 py-1.5 text-base sm:text-sm leading-6 outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\"\n />\n {failed && (\n <p id={errorId} role=\"alert\" className=\"px-2 text-sm text-destructive\">\n {submitErrorText}\n </p>\n )}\n {attachments && <div className=\"flex flex-wrap gap-1.5 px-1\">{attachments}</div>}\n <div className=\"flex items-center gap-1\">\n {actions}\n <div className=\"ml-auto\">\n {streaming ? (\n <Button\n type=\"button\"\n size=\"icon-sm\"\n variant=\"secondary\"\n aria-label=\"Stop\"\n onClick={onStop}\n disabled={!onStop || disabled}\n >\n <Square className=\"fill-current\" />\n </Button>\n ) : (\n <Button\n type=\"submit\"\n size=\"icon-sm\"\n aria-label=\"Send\"\n loading={pending}\n disabled={!canSend}\n >\n <ArrowUp />\n </Button>\n )}\n </div>\n </div>\n </form>\n );\n}\n\nexport interface SuggestionsProps extends Omit<React.ComponentProps<'div'>, 'onSelect'> {\n items: string[];\n onSelect: (item: string) => void;\n}\n\n/** Starter prompts as chips. */\nfunction Suggestions({ items, onSelect, className, ...props }: SuggestionsProps) {\n return (\n <div\n data-slot=\"suggestions\"\n role=\"group\"\n aria-label=\"Suggestions\"\n className={cn('flex flex-wrap gap-2', className)}\n {...props}\n >\n {items.map((item) => (\n <button\n key={item}\n type=\"button\"\n onClick={() => onSelect(item)}\n className=\"animate-in rounded-full border border-border-strong bg-surface px-3 py-1.5 text-[13px] text-foreground outline-none transition-colors hover:border-brand/40 hover:bg-brand-soft hover:text-brand-soft-foreground focus-visible:ring-[3px] focus-visible:ring-ring/20\"\n >\n {item}\n </button>\n ))}\n </div>\n );\n}\n\nexport { Composer, Suggestions };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ContextMenu as ContextMenuPrimitive } from 'radix-ui';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* A right-click menu. Wrap the target in ContextMenuTrigger (use asChild to keep
|
|
5
|
+
* your element); the menu opens at the pointer, and from the keyboard with the
|
|
6
|
+
* context-menu key or Shift+F10 on the focused target. Same rows as
|
|
7
|
+
* DropdownMenu, so a command can appear in both.
|
|
8
|
+
*/
|
|
9
|
+
declare function ContextMenu(props: React.ComponentProps<typeof ContextMenuPrimitive.Root>): React.JSX.Element;
|
|
10
|
+
declare function ContextMenuTrigger(props: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>): React.JSX.Element;
|
|
11
|
+
declare function ContextMenuGroup(props: React.ComponentProps<typeof ContextMenuPrimitive.Group>): React.JSX.Element;
|
|
12
|
+
declare function ContextMenuContent({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Content>): React.JSX.Element;
|
|
13
|
+
declare function ContextMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
|
|
14
|
+
inset?: boolean;
|
|
15
|
+
variant?: 'default' | 'destructive';
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
declare function ContextMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>): React.JSX.Element;
|
|
18
|
+
declare function ContextMenuRadioGroup(props: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>): React.JSX.Element;
|
|
19
|
+
declare function ContextMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>): React.JSX.Element;
|
|
20
|
+
declare function ContextMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
|
|
21
|
+
inset?: boolean;
|
|
22
|
+
}): React.JSX.Element;
|
|
23
|
+
declare function ContextMenuSeparator({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>): React.JSX.Element;
|
|
24
|
+
declare function ContextMenuShortcut({ className, ...props }: React.ComponentProps<'span'>): React.JSX.Element;
|
|
25
|
+
declare function ContextMenuSub(props: React.ComponentProps<typeof ContextMenuPrimitive.Sub>): React.JSX.Element;
|
|
26
|
+
declare function ContextMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
|
|
27
|
+
inset?: boolean;
|
|
28
|
+
}): React.JSX.Element;
|
|
29
|
+
declare function ContextMenuSubContent({ className, ...props }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>): React.JSX.Element;
|
|
30
|
+
export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { menuItemClasses, surfaceClasses } from "./popover.js";
|
|
3
|
+
import { ContextMenu } from "radix-ui";
|
|
4
|
+
import "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import ChevronRight from "@burtson-labs/icons/react/chevron-right";
|
|
7
|
+
import Check from "@burtson-labs/icons/react/check";
|
|
8
|
+
//#region src/components/context-menu.tsx
|
|
9
|
+
/**
|
|
10
|
+
* A right-click menu. Wrap the target in ContextMenuTrigger (use asChild to keep
|
|
11
|
+
* your element); the menu opens at the pointer, and from the keyboard with the
|
|
12
|
+
* context-menu key or Shift+F10 on the focused target. Same rows as
|
|
13
|
+
* DropdownMenu, so a command can appear in both.
|
|
14
|
+
*/
|
|
15
|
+
function ContextMenu$1(props) {
|
|
16
|
+
return /* @__PURE__ */ jsx(ContextMenu.Root, {
|
|
17
|
+
"data-slot": "context-menu",
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function ContextMenuTrigger(props) {
|
|
22
|
+
return /* @__PURE__ */ jsx(ContextMenu.Trigger, {
|
|
23
|
+
"data-slot": "context-menu-trigger",
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function ContextMenuGroup(props) {
|
|
28
|
+
return /* @__PURE__ */ jsx(ContextMenu.Group, {
|
|
29
|
+
"data-slot": "context-menu-group",
|
|
30
|
+
...props
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function ContextMenuContent({ className, ...props }) {
|
|
34
|
+
return /* @__PURE__ */ jsx(ContextMenu.Portal, { children: /* @__PURE__ */ jsx(ContextMenu.Content, {
|
|
35
|
+
"data-slot": "context-menu-content",
|
|
36
|
+
className: cn(surfaceClasses, "max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1", className),
|
|
37
|
+
...props
|
|
38
|
+
}) });
|
|
39
|
+
}
|
|
40
|
+
function ContextMenuItem({ className, inset, variant = "default", ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsx(ContextMenu.Item, {
|
|
42
|
+
"data-slot": "context-menu-item",
|
|
43
|
+
"data-inset": inset || void 0,
|
|
44
|
+
"data-variant": variant,
|
|
45
|
+
className: cn(menuItemClasses, "data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive", className),
|
|
46
|
+
...props
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function ContextMenuCheckboxItem({ className, children, checked, ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsxs(ContextMenu.CheckboxItem, {
|
|
51
|
+
"data-slot": "context-menu-checkbox-item",
|
|
52
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
53
|
+
checked,
|
|
54
|
+
...props,
|
|
55
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
56
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
57
|
+
children: /* @__PURE__ */ jsx(ContextMenu.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, {
|
|
58
|
+
className: "size-4 text-foreground",
|
|
59
|
+
"aria-hidden": true
|
|
60
|
+
}) })
|
|
61
|
+
}), children]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function ContextMenuRadioGroup(props) {
|
|
65
|
+
return /* @__PURE__ */ jsx(ContextMenu.RadioGroup, {
|
|
66
|
+
"data-slot": "context-menu-radio-group",
|
|
67
|
+
...props
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function ContextMenuRadioItem({ className, children, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsxs(ContextMenu.RadioItem, {
|
|
72
|
+
"data-slot": "context-menu-radio-item",
|
|
73
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
74
|
+
...props,
|
|
75
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
76
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
77
|
+
children: /* @__PURE__ */ jsx(ContextMenu.ItemIndicator, { children: /* @__PURE__ */ jsx("span", { className: "block size-2 rounded-full bg-foreground" }) })
|
|
78
|
+
}), children]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function ContextMenuLabel({ className, inset, ...props }) {
|
|
82
|
+
return /* @__PURE__ */ jsx(ContextMenu.Label, {
|
|
83
|
+
"data-slot": "context-menu-label",
|
|
84
|
+
"data-inset": inset || void 0,
|
|
85
|
+
className: cn("px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8", className),
|
|
86
|
+
...props
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function ContextMenuSeparator({ className, ...props }) {
|
|
90
|
+
return /* @__PURE__ */ jsx(ContextMenu.Separator, {
|
|
91
|
+
"data-slot": "context-menu-separator",
|
|
92
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
93
|
+
...props
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function ContextMenuShortcut({ className, ...props }) {
|
|
97
|
+
return /* @__PURE__ */ jsx("span", {
|
|
98
|
+
"data-slot": "context-menu-shortcut",
|
|
99
|
+
className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className),
|
|
100
|
+
...props
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function ContextMenuSub(props) {
|
|
104
|
+
return /* @__PURE__ */ jsx(ContextMenu.Sub, {
|
|
105
|
+
"data-slot": "context-menu-sub",
|
|
106
|
+
...props
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function ContextMenuSubTrigger({ className, inset, children, ...props }) {
|
|
110
|
+
return /* @__PURE__ */ jsxs(ContextMenu.SubTrigger, {
|
|
111
|
+
"data-slot": "context-menu-sub-trigger",
|
|
112
|
+
"data-inset": inset || void 0,
|
|
113
|
+
className: cn(menuItemClasses, "data-[state=open]:bg-muted", className),
|
|
114
|
+
...props,
|
|
115
|
+
children: [children, /* @__PURE__ */ jsx(ChevronRight, {
|
|
116
|
+
className: "ml-auto size-4",
|
|
117
|
+
"aria-hidden": true
|
|
118
|
+
})]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function ContextMenuSubContent({ className, ...props }) {
|
|
122
|
+
return /* @__PURE__ */ jsx(ContextMenu.Portal, { children: /* @__PURE__ */ jsx(ContextMenu.SubContent, {
|
|
123
|
+
"data-slot": "context-menu-sub-content",
|
|
124
|
+
className: cn(surfaceClasses, "min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden p-1", className),
|
|
125
|
+
...props
|
|
126
|
+
}) });
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
export { ContextMenu$1 as ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=context-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.js","names":["ContextMenu","ContextMenuPrimitive","itemClasses"],"sources":["../../src/components/context-menu.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { ContextMenu as ContextMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\n/**\n * A right-click menu. Wrap the target in ContextMenuTrigger (use asChild to keep\n * your element); the menu opens at the pointer, and from the keyboard with the\n * context-menu key or Shift+F10 on the focused target. Same rows as\n * DropdownMenu, so a command can appear in both.\n */\nfunction ContextMenu(props: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {\n return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />;\n}\n\nfunction ContextMenuTrigger(props: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {\n return <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />;\n}\n\nfunction ContextMenuGroup(props: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {\n return <ContextMenuPrimitive.Group data-slot=\"context-menu-group\" {...props} />;\n}\n\nfunction ContextMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {\n return (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-slot=\"context-menu-content\"\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n}\n\nfunction ContextMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <ContextMenuPrimitive.Item\n data-slot=\"context-menu-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {\n return (\n <ContextMenuPrimitive.CheckboxItem\n data-slot=\"context-menu-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction ContextMenuRadioGroup(\n props: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>,\n) {\n return <ContextMenuPrimitive.RadioGroup data-slot=\"context-menu-radio-group\" {...props} />;\n}\n\nfunction ContextMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {\n return (\n <ContextMenuPrimitive.RadioItem\n data-slot=\"context-menu-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n );\n}\n\nfunction ContextMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & { inset?: boolean }) {\n return (\n <ContextMenuPrimitive.Label\n data-slot=\"context-menu-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {\n return (\n <ContextMenuPrimitive.Separator\n data-slot=\"context-menu-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction ContextMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"context-menu-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSub(props: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {\n return <ContextMenuPrimitive.Sub data-slot=\"context-menu-sub\" {...props} />;\n}\n\nfunction ContextMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <ContextMenuPrimitive.SubTrigger\n data-slot=\"context-menu-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-muted', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </ContextMenuPrimitive.SubTrigger>\n );\n}\n\nfunction ContextMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {\n return (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.SubContent\n data-slot=\"context-menu-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n}\n\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuGroup,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n};\n"],"mappings":"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"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import { surfaceClasses } from "./popover.js";
|
|
2
|
+
import { menuItemClasses, surfaceClasses } from "./popover.js";
|
|
3
3
|
import { DropdownMenu } from "radix-ui";
|
|
4
4
|
import "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import ChevronRight from "@burtson-labs/icons/react/chevron-right";
|
|
7
7
|
import Check from "@burtson-labs/icons/react/check";
|
|
8
8
|
//#region src/components/dropdown-menu.tsx
|
|
9
|
-
var itemClasses = "relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 text-[13px] outline-hidden select-none focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
10
9
|
function DropdownMenu$1(props) {
|
|
11
10
|
return /* @__PURE__ */ jsx(DropdownMenu.Root, {
|
|
12
11
|
"data-slot": "dropdown-menu",
|
|
@@ -38,14 +37,14 @@ function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
|
|
|
38
37
|
"data-slot": "dropdown-menu-item",
|
|
39
38
|
"data-inset": inset || void 0,
|
|
40
39
|
"data-variant": variant,
|
|
41
|
-
className: cn(
|
|
40
|
+
className: cn(menuItemClasses, "data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive", className),
|
|
42
41
|
...props
|
|
43
42
|
});
|
|
44
43
|
}
|
|
45
44
|
function DropdownMenuCheckboxItem({ className, children, checked, ...props }) {
|
|
46
45
|
return /* @__PURE__ */ jsxs(DropdownMenu.CheckboxItem, {
|
|
47
46
|
"data-slot": "dropdown-menu-checkbox-item",
|
|
48
|
-
className: cn(
|
|
47
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
49
48
|
checked,
|
|
50
49
|
...props,
|
|
51
50
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -66,7 +65,7 @@ function DropdownMenuRadioGroup(props) {
|
|
|
66
65
|
function DropdownMenuRadioItem({ className, children, ...props }) {
|
|
67
66
|
return /* @__PURE__ */ jsxs(DropdownMenu.RadioItem, {
|
|
68
67
|
"data-slot": "dropdown-menu-radio-item",
|
|
69
|
-
className: cn(
|
|
68
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
70
69
|
...props,
|
|
71
70
|
children: [/* @__PURE__ */ jsx("span", {
|
|
72
71
|
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
@@ -106,7 +105,7 @@ function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
|
|
|
106
105
|
return /* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, {
|
|
107
106
|
"data-slot": "dropdown-menu-sub-trigger",
|
|
108
107
|
"data-inset": inset || void 0,
|
|
109
|
-
className: cn(
|
|
108
|
+
className: cn(menuItemClasses, "data-[state=open]:bg-muted", className),
|
|
110
109
|
...props,
|
|
111
110
|
children: [children, /* @__PURE__ */ jsx(ChevronRight, {
|
|
112
111
|
className: "ml-auto size-4",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","DropdownMenuPrimitive"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { surfaceClasses } from './popover';\n\
|
|
1
|
+
{"version":3,"file":"dropdown-menu.js","names":["DropdownMenu","DropdownMenuPrimitive","itemClasses"],"sources":["../../src/components/dropdown-menu.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\nfunction DropdownMenu(props: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuTrigger(props: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />;\n}\n\nfunction DropdownMenuGroup(props: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup(\n props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,\n) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub(props: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-muted', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface EditorTab {
|
|
3
|
+
/** Stable identity, usually the file path. */
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Full path or context; the tooltip and the accessible description. */
|
|
7
|
+
description?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
/** Unsaved changes: a dot replaces the close button until hover. */
|
|
10
|
+
dirty?: boolean;
|
|
11
|
+
/** Default true. */
|
|
12
|
+
closeable?: boolean;
|
|
13
|
+
/** A preview tab that the next opened file replaces; shown in italics. */
|
|
14
|
+
preview?: boolean;
|
|
15
|
+
/** The id of the panel this tab shows, for aria-controls. */
|
|
16
|
+
controls?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface EditorTabsProps extends Omit<React.ComponentProps<'div'>, 'children' | 'aria-label'> {
|
|
19
|
+
tabs: EditorTab[];
|
|
20
|
+
activeId: string | null;
|
|
21
|
+
onActiveChange: (id: string) => void;
|
|
22
|
+
/**
|
|
23
|
+
* A request to close. The component never removes a tab itself: for a dirty
|
|
24
|
+
* tab, ask the person (save, discard, cancel) and then update `tabs`.
|
|
25
|
+
*/
|
|
26
|
+
onClose?: (id: string) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Reorder by drag or Ctrl+Shift+PageUp/PageDown. `toIndex` is the new position.
|
|
29
|
+
* Dragging uses pointer events, not HTML5 drag and drop, so it also works in
|
|
30
|
+
* desktop webviews (Tauri, Electron) that intercept native drags.
|
|
31
|
+
*/
|
|
32
|
+
onMove?: (id: string, toIndex: number) => void;
|
|
33
|
+
/** Required: e.g. "Open editors". */
|
|
34
|
+
'aria-label': string;
|
|
35
|
+
/** Right-hand slot for split, more and similar buttons. */
|
|
36
|
+
actions?: React.ReactNode;
|
|
37
|
+
/** Right-click on a tab. */
|
|
38
|
+
onTabContextMenu?: (id: string, event: React.MouseEvent) => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The strip of open files above an editor. One tab stop; Left/Right/Home/End
|
|
42
|
+
* move focus, Enter or Space opens, Delete asks to close, Ctrl+Shift+PageUp
|
|
43
|
+
* and PageDown move the tab. Middle-click closes. The strip scrolls when the
|
|
44
|
+
* tabs overflow and keeps the active tab in view.
|
|
45
|
+
*/
|
|
46
|
+
declare function EditorTabs({ tabs, activeId, onActiveChange, onClose, onMove, actions, onTabContextMenu, className, 'aria-label': ariaLabel, ...props }: EditorTabsProps): React.JSX.Element;
|
|
47
|
+
export { EditorTabs };
|