@ctrl-ui/react 0.9.16 → 0.9.18

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 (66) hide show
  1. package/dist/action-bar.d.ts +2 -2
  2. package/dist/action-bar.js +34 -15
  3. package/dist/activity.d.ts +1 -1
  4. package/dist/activity.js +1 -1
  5. package/dist/audio-device-select.js +1 -1
  6. package/dist/audio-recorder.js +1 -1
  7. package/dist/blocks/agent-run-sidebar.js +1 -1
  8. package/dist/blocks/agent-run.js +1 -1
  9. package/dist/blocks/coding-agent.js +1 -1
  10. package/dist/blocks/design-canvas-inspector.js +1 -1
  11. package/dist/blocks/design-canvas.js +1 -1
  12. package/dist/blocks/discussion.js +1 -1
  13. package/dist/blocks/file-explorer.js +1 -1
  14. package/dist/blocks/settings.js +1 -1
  15. package/dist/blocks/theme-toggle.js +1 -1
  16. package/dist/chat-composer-attachment.js +1 -1
  17. package/dist/chat-composer.js +1 -1
  18. package/dist/chat-layout.js +1 -1
  19. package/dist/context.js +1 -1
  20. package/dist/filter-bar/parts.js +1 -1
  21. package/dist/inline-citation.js +1 -1
  22. package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
  23. package/dist/knob-contracts/sidebar-knobs.js +7 -0
  24. package/dist/markdown-editor/context.d.ts +2 -0
  25. package/dist/markdown-editor/drag-handle.js +1 -1
  26. package/dist/markdown-editor/extensions.d.ts +14 -4
  27. package/dist/markdown-editor/extensions.js +39 -34
  28. package/dist/markdown-editor/suggestions.js +4 -5
  29. package/dist/markdown-editor/toolbar.d.ts +1 -1
  30. package/dist/markdown-editor/toolbar.js +5 -6
  31. package/dist/markdown-editor.d.ts +7 -1
  32. package/dist/markdown-editor.js +16 -6
  33. package/dist/source-badge.js +1 -1
  34. package/dist/styles/index.css +1 -0
  35. package/dist/styles/recipes/action-bar.css +12 -3
  36. package/dist/styles/recipes/popup-controls.css +3 -3
  37. package/dist/styles/recipes/resizable.css +15 -0
  38. package/dist/styles/recipes/sidebar-panes.css +192 -0
  39. package/dist/styles/recipes/sidebar-parts.css +61 -3
  40. package/dist/task-list.js +1 -1
  41. package/dist/tool-approval.js +1 -1
  42. package/dist/ui/accordion.js +1 -1
  43. package/dist/ui/breadcrumb.js +1 -1
  44. package/dist/ui/code.js +1 -1
  45. package/dist/ui/dropzone.js +1 -1
  46. package/dist/ui/emoji-picker.js +1 -1
  47. package/dist/ui/flow.js +1 -1
  48. package/dist/ui/hover-card.d.ts +3 -1
  49. package/dist/ui/hover-card.js +2 -2
  50. package/dist/ui/infinite-canvas.js +1 -1
  51. package/dist/ui/pagination.js +1 -1
  52. package/dist/ui/resizable.d.ts +3 -1
  53. package/dist/ui/resizable.js +3 -1
  54. package/dist/ui/rich-tooltip.js +1 -1
  55. package/dist/ui/sidebar-menu.js +6 -6
  56. package/dist/ui/sidebar-mobile.js +1 -1
  57. package/dist/ui/sidebar-provider.d.ts +2 -0
  58. package/dist/ui/sidebar-provider.js +7 -1
  59. package/dist/ui/sidebar.d.ts +12 -0
  60. package/dist/ui/sidebar.js +34 -9
  61. package/dist/ui/spinner.js +1 -1
  62. package/dist/ui/stepper.js +1 -1
  63. package/dist/ui/toast.js +1 -1
  64. package/dist/ui/tree.js +1 -1
  65. package/dist/user-ask.js +1 -1
  66. package/package.json +1 -1
@@ -41,10 +41,10 @@ export type ActionBarCopyProps = ActionBarItemBaseProps & {
41
41
  copyFailedLabel?: string;
42
42
  resetDelay?: number;
43
43
  };
44
- export declare function ActionBarCopy({ value, children, copiedChildren, copiedAriaLabel, copyFailedLabel, resetDelay, disabled, onClick, ...props }: ActionBarCopyProps): import("react").JSX.Element;
44
+ export declare function ActionBarCopy({ value, children, copiedChildren, copiedAriaLabel, copyFailedLabel, resetDelay, disabled, onClick, "aria-label": ariaLabel, ...props }: ActionBarCopyProps): import("react").JSX.Element;
45
45
  export type ActionBarEditProps = ActionBarItemBaseProps & {
46
46
  value?: ActionBarCopyValue;
47
47
  children?: NonNullable<ReactNode>;
48
48
  };
49
- export declare function ActionBarEdit({ value, children, disabled, onClick, ...props }: ActionBarEditProps): import("react").JSX.Element;
49
+ export declare function ActionBarEdit({ value, children, disabled, onClick, "aria-label": ariaLabel, ...props }: ActionBarEditProps): import("react").JSX.Element;
50
50
  //#endregion
@@ -5,6 +5,7 @@ import { Button } from "./ui/button.js";
5
5
  import { LiveStatus } from "./ui/live-status.js";
6
6
  import { Swap, SwapItem } from "./ui/swap.js";
7
7
  import { Toolbar } from "@base-ui/react/toolbar";
8
+ import { CheckIcon, CopyIcon, PencilIcon } from "lucide-react";
8
9
  import { createContext, useContext } from "react";
9
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
11
  //#region src/action-bar.tsx
@@ -48,7 +49,7 @@ function ActionBarItem({ icon, children, active, disabled, ...props }) {
48
49
  })
49
50
  });
50
51
  }
51
- function ActionBarCopy({ value, children = "Copy", copiedChildren = "Copied", copiedAriaLabel = "Copied to clipboard", copyFailedLabel = "Couldn't copy. Select the text and copy it manually.", resetDelay = 1200, disabled, onClick, ...props }) {
52
+ function ActionBarCopy({ value, children, copiedChildren, copiedAriaLabel = "Copied to clipboard", copyFailedLabel = "Couldn't copy. Select the text and copy it manually.", resetDelay = 1200, disabled, onClick, "aria-label": ariaLabel, ...props }) {
52
53
  const { copyValue: contextCopyValue, onCopy, onCopyError } = useContext(ActionBarContext);
53
54
  const copyValue = value ?? contextCopyValue;
54
55
  const { status, copyToClipboard } = useCopyToClipboard({
@@ -71,27 +72,36 @@ function ActionBarCopy({ value, children = "Copy", copiedChildren = "Copied", co
71
72
  let copyStatus = "";
72
73
  if (copied) copyStatus = copiedAriaLabel;
73
74
  else if (status === "failed") copyStatus = copyFailedLabel;
74
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(ActionBarItem, {
75
+ const isIconOnly = children === void 0;
76
+ const swap = /* @__PURE__ */ jsxs(Swap, {
77
+ value: copied ? "copied" : "idle",
78
+ children: [/* @__PURE__ */ jsx(SwapItem, {
79
+ value: "idle",
80
+ children: children ?? /* @__PURE__ */ jsx(CopyIcon, { "aria-hidden": "true" })
81
+ }), /* @__PURE__ */ jsx(SwapItem, {
82
+ value: "copied",
83
+ "aria-hidden": "true",
84
+ children: copiedChildren ?? (isIconOnly ? /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }) : "Copied")
85
+ })]
86
+ });
87
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [isIconOnly ? /* @__PURE__ */ jsx(ActionBarItem, {
88
+ "aria-label": ariaLabel ?? "Copy",
89
+ icon: swap,
90
+ disabled: disabled ?? !copyValue,
91
+ onClick: handleClick,
92
+ ...props
93
+ }) : /* @__PURE__ */ jsxs(ActionBarItem, {
94
+ "aria-label": ariaLabel,
75
95
  disabled: disabled ?? !copyValue,
76
96
  onClick: handleClick,
77
97
  ...props,
78
- children: [/* @__PURE__ */ jsxs(Swap, {
79
- value: copied ? "copied" : "idle",
80
- children: [/* @__PURE__ */ jsx(SwapItem, {
81
- value: "idle",
82
- children
83
- }), /* @__PURE__ */ jsx(SwapItem, {
84
- value: "copied",
85
- "aria-hidden": "true",
86
- children: copiedChildren
87
- })]
88
- }), copied ? /* @__PURE__ */ jsx("span", {
98
+ children: [swap, copied ? /* @__PURE__ */ jsx("span", {
89
99
  className: "sr-only",
90
100
  children
91
101
  }) : null]
92
102
  }), /* @__PURE__ */ jsx(LiveStatus, { message: copyStatus })] });
93
103
  }
94
- function ActionBarEdit({ value, children = "Edit", disabled, onClick, ...props }) {
104
+ function ActionBarEdit({ value, children, disabled, onClick, "aria-label": ariaLabel, ...props }) {
95
105
  const { copyValue, editValue: contextEditValue, onEdit, onEditError } = useContext(ActionBarContext);
96
106
  const editValue = value ?? contextEditValue ?? copyValue;
97
107
  async function handleClick(event) {
@@ -105,8 +115,17 @@ function ActionBarEdit({ value, children = "Edit", disabled, onClick, ...props }
105
115
  onEditError?.(error);
106
116
  }
107
117
  }
118
+ const itemDisabled = disabled ?? (editValue === void 0 || !onEdit);
119
+ if (children === void 0) return /* @__PURE__ */ jsx(ActionBarItem, {
120
+ "aria-label": ariaLabel ?? "Edit",
121
+ icon: /* @__PURE__ */ jsx(PencilIcon, { "aria-hidden": "true" }),
122
+ disabled: itemDisabled,
123
+ onClick: handleClick,
124
+ ...props
125
+ });
108
126
  return /* @__PURE__ */ jsx(ActionBarItem, {
109
- disabled: disabled ?? (editValue === void 0 || !onEdit),
127
+ "aria-label": ariaLabel,
128
+ disabled: itemDisabled,
110
129
  onClick: handleClick,
111
130
  ...props,
112
131
  children
@@ -1,8 +1,8 @@
1
1
  import { ActivityKnobStyle } from "./knob-contracts/activity-knobs.js";
2
2
  import { CollapsibleContent, CollapsibleProps, CollapsibleTrigger } from "./ui/collapsible.js";
3
3
  import { ScrollAreaProps } from "./ui/scroll-area.js";
4
- import { CSSProperties, ComponentProps, ReactNode } from "react";
5
4
  import { ChevronRight } from "lucide-react";
5
+ import { CSSProperties, ComponentProps, ReactNode } from "react";
6
6
  //#region src/activity.d.ts
7
7
  export type ActivityState = "pending" | "running" | "waiting" | "success" | "error";
8
8
  export type ActivityKind = "default" | "tool" | "reasoning" | "signal";
package/dist/activity.js CHANGED
@@ -3,9 +3,9 @@ import { cn } from "./lib/cn.js";
3
3
  import { LiveStatus } from "./ui/live-status.js";
4
4
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible.js";
5
5
  import { ScrollArea } from "./ui/scroll-area.js";
6
+ import { Check, ChevronRight, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
6
7
  import { createContext, useContext } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import { Check, ChevronRight, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
9
9
  //#region src/activity.tsx
10
10
  const activityStatusLabels = {
11
11
  pending: "Pending",
@@ -3,9 +3,9 @@ import { cn } from "./lib/cn.js";
3
3
  import { Button } from "./ui/button.js";
4
4
  import { Select, SelectContent, SelectItem, SelectTrigger } from "./ui/select.js";
5
5
  import { Text } from "./ui/typography.js";
6
+ import { MicIcon, Volume2Icon } from "lucide-react";
6
7
  import { createContext, use, useState } from "react";
7
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { MicIcon, Volume2Icon } from "lucide-react";
9
9
  //#region src/audio-device-select.tsx
10
10
  const AUDIO_DEVICE_COPY = {
11
11
  input: {
@@ -5,9 +5,9 @@ import { LiveStatus } from "./ui/live-status.js";
5
5
  import { AudioVisualizer } from "./audio-visualizer.js";
6
6
  import { useAudioRecorder } from "./hooks/use-audio-recorder.js";
7
7
  import { formatAudioRecorderDuration } from "./lib/format-audio-recorder-duration.js";
8
+ import { CheckIcon, MicIcon, XIcon } from "lucide-react";
8
9
  import { createContext, use, useRef, useState } from "react";
9
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { CheckIcon, MicIcon, XIcon } from "lucide-react";
11
11
  //#region src/audio-recorder.tsx
12
12
  const AudioRecorderContext = createContext(null);
13
13
  const AudioRecorderTriggerRefContext = createContext(null);
@@ -4,8 +4,8 @@ import { useSidebar } from "../ui/sidebar-provider.js";
4
4
  import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
5
5
  import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarRail } from "../ui/sidebar.js";
6
6
  import { agentRunStatusLabels } from "./agent-run-status.js";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { BotIcon, CheckIcon, CircleAlertIcon, CircleDashedIcon, CirclePauseIcon, CircleSlashIcon, LoaderCircleIcon, PlusIcon } from "lucide-react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/blocks/agent-run-sidebar.tsx
10
10
  const runStatusIcons = {
11
11
  running: /* @__PURE__ */ jsx(LoaderCircleIcon, {
@@ -11,9 +11,9 @@ import { agentRunStatusColors, agentRunStatusLabels, agentRunStepLabels } from "
11
11
  import { AgentRunSidebar } from "./agent-run-sidebar.js";
12
12
  import { Card, CardAction, CardContent, CardHeader } from "../ui/card.js";
13
13
  import { Timeline, TimelineContent, TimelineDescription, TimelineIndicator, TimelineItem, TimelineMeta, TimelineSeparator, TimelineTitle } from "../ui/timeline.js";
14
+ import { Check, Circle, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
14
15
  import { createContext, useContext, useId } from "react";
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
16
- import { Check, Circle, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
17
17
  //#region src/blocks/agent-run.tsx
18
18
  const AgentRunLayoutContext = createContext("viewport");
19
19
  function useHeadingLevels() {
@@ -8,8 +8,8 @@ import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
8
8
  import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub } from "../ui/sidebar-menu.js";
9
9
  import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarRail, SidebarTrigger } from "../ui/sidebar.js";
10
10
  import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "../ui/item.js";
11
- import { jsx, jsxs } from "react/jsx-runtime";
12
11
  import { BotIcon, ChevronRightIcon, CircleIcon, FolderIcon, PlusIcon, SearchIcon } from "lucide-react";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
13
  //#region src/blocks/coding-agent.tsx
14
14
  function CodingAgentBlock({ appName = "Agent", brand, sidebarTop, navigation = [], projects, activeTaskId, activeTaskTitle = "New task", onNavigationSelect, onTaskSelect, onNewTask, onSearch, headerActions, sidebarFooter, children, layout = "viewport", className, style, ...props }) {
15
15
  const providerStyle = {
@@ -11,9 +11,9 @@ import { ColorPickerEyeDropper, ColorPickerInput } from "../ui/color-picker-valu
11
11
  import { ColorPicker, ColorPickerContent, ColorPickerTrigger } from "../ui/color-picker.js";
12
12
  import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "../ui/empty.js";
13
13
  import { Toggle } from "../ui/toggle.js";
14
+ import { BlendIcon, EyeIcon, EyeOffIcon, Link2Icon, MinusIcon, PlusIcon, RotateCwIcon, SquareRoundCornerIcon, Unlink2Icon } from "lucide-react";
14
15
  import { useState } from "react";
15
16
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
- import { BlendIcon, EyeIcon, EyeOffIcon, Link2Icon, MinusIcon, PlusIcon, RotateCwIcon, SquareRoundCornerIcon, Unlink2Icon } from "lucide-react";
17
17
  //#region src/blocks/design-canvas-inspector.tsx
18
18
  const WHOLE_NUMBER_FORMAT = {
19
19
  useGrouping: false,
@@ -10,9 +10,9 @@ import { DesignCanvasInspector } from "./design-canvas-inspector.js";
10
10
  import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "../ui/toolbar.js";
11
11
  import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
12
12
  import { ResizableFloatingPanel } from "../ui/resizable.js";
13
+ import { CircleIcon, FrameIcon, HandIcon, LayersIcon, MousePointer2Icon, SlidersHorizontalIcon, SquareIcon, TypeIcon } from "lucide-react";
13
14
  import { useRef, useState } from "react";
14
15
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
- import { CircleIcon, FrameIcon, HandIcon, LayersIcon, MousePointer2Icon, SlidersHorizontalIcon, SquareIcon, TypeIcon } from "lucide-react";
16
16
  //#region src/blocks/design-canvas.tsx
17
17
  const TOOLS = [
18
18
  {
@@ -6,9 +6,9 @@ import { ChatMessageReplies } from "../chat-message/social.js";
6
6
  import { ChatMessage, ChatMessageActions, ChatMessageAuthor, ChatMessageAvatar, ChatMessageBody, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessageRow, ChatMessageTime } from "../chat-message.js";
7
7
  import { Markdown } from "../ui/markdown.js";
8
8
  import { Kbd, KbdGroup } from "../ui/kbd.js";
9
+ import { CornerDownRightIcon } from "lucide-react";
9
10
  import { Suspense, lazy, useState } from "react";
10
11
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
- import { CornerDownRightIcon } from "lucide-react";
12
12
  //#region src/blocks/discussion.tsx
13
13
  const DiscussionMarkdownInput = lazy(() => import("./discussion-markdown-input.js"));
14
14
  function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondaryAction, hint = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(KbdGroup, { children: [/* @__PURE__ */ jsx(Kbd, { children: "⌘" }), /* @__PURE__ */ jsx(Kbd, { children: "Enter" })] }), /* @__PURE__ */ jsx("span", { children: "to post" })] }), autoFocus, format = "plain", onUploadImage, mentions, onSubmit, ...props }) {
@@ -15,9 +15,9 @@ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "../ui/resi
15
15
  import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
16
16
  import { groupFileExplorerItems, orderFileExplorerEntries, resolveFileExplorer, searchFileExplorer } from "./file-explorer-data.js";
17
17
  import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "../ui/breadcrumb.js";
18
+ import { ChevronLeftIcon, ChevronRightIcon, FileIcon, FolderIcon, MoreHorizontalIcon, SearchIcon, XIcon } from "lucide-react";
18
19
  import { Fragment, useEffect, useId, useRef, useState } from "react";
19
20
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
20
- import { ChevronLeftIcon, ChevronRightIcon, FileIcon, FolderIcon, MoreHorizontalIcon, SearchIcon, XIcon } from "lucide-react";
21
21
  //#region src/blocks/file-explorer.tsx
22
22
  function defaultSearchStatusLabel(count, query) {
23
23
  if (count === 0) return `No results for “${query}”`;
@@ -13,9 +13,9 @@ import { Input } from "../ui/input.js";
13
13
  import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "../ui/empty.js";
14
14
  import { searchSettings } from "./settings-data.js";
15
15
  import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSet } from "../ui/field.js";
16
+ import { ArrowLeftIcon, SearchIcon, XIcon } from "lucide-react";
16
17
  import { useEffect, useId, useState } from "react";
17
18
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
18
- import { ArrowLeftIcon, SearchIcon, XIcon } from "lucide-react";
19
19
  //#region src/blocks/settings.tsx
20
20
  function SettingsBlock({ pages, activePageId, defaultActivePageId, onActivePageChange, backAction, searchPlaceholder = "Search settings", searchLabel = "Search settings", layout = "viewport", className, style, ...props }) {
21
21
  const [internalPageId, setInternalPageId] = useState(defaultActivePageId ?? pages[0]?.id);
@@ -3,9 +3,9 @@ import { Button } from "../ui/button.js";
3
3
  import { Text } from "../ui/typography.js";
4
4
  import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
5
5
  import { Switch } from "../ui/switch.js";
6
+ import { ChevronDownIcon, MonitorIcon, MoonIcon, SunIcon } from "lucide-react";
6
7
  import { useId } from "react";
7
8
  import { jsx, jsxs } from "react/jsx-runtime";
8
- import { ChevronDownIcon, MonitorIcon, MoonIcon, SunIcon } from "lucide-react";
9
9
  //#region src/blocks/theme-toggle.tsx
10
10
  const systemThemeOption = {
11
11
  value: "system",
@@ -4,9 +4,9 @@ import { Button } from "./ui/button.js";
4
4
  import { LiveStatus } from "./ui/live-status.js";
5
5
  import { ScrollArea } from "./ui/scroll-area.js";
6
6
  import { Spinner } from "./ui/spinner.js";
7
+ import { XIcon } from "lucide-react";
7
8
  import { createContext, useContext, useLayoutEffect, useState } from "react";
8
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
- import { XIcon } from "lucide-react";
10
10
  //#region src/chat-composer-attachment.tsx
11
11
  const ChatComposerAttachmentContext = createContext(null);
12
12
  function useChatComposerAttachmentContext() {
@@ -5,9 +5,9 @@ import { useSkin } from "./skin-provider.js";
5
5
  import { Button } from "./ui/button.js";
6
6
  import { Spinner } from "./ui/spinner.js";
7
7
  import { useChatComposer } from "./hooks/use-chat-composer.js";
8
+ import { Square } from "lucide-react";
8
9
  import { createContext, useContext, useEffect, useRef } from "react";
9
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { Square } from "lucide-react";
11
11
  //#region src/chat-composer.tsx
12
12
  const ChatComposerContext = createContext(null);
13
13
  function useChatComposerContext() {
@@ -6,10 +6,10 @@ import { LiveStatus } from "./ui/live-status.js";
6
6
  import { ScrollArea } from "./ui/scroll-area.js";
7
7
  import { ChatThreadAnnounceContext } from "./hooks/use-chat-message.js";
8
8
  import { useChatThreadScroll } from "./hooks/use-chat-thread-scroll.js";
9
+ import { ArrowDown } from "lucide-react";
9
10
  import { createContext, useContext, useState } from "react";
10
11
  import { useRender } from "@base-ui/react/use-render";
11
12
  import { jsx, jsxs } from "react/jsx-runtime";
12
- import { ArrowDown } from "lucide-react";
13
13
  //#region src/chat-layout.tsx
14
14
  const chromeSizing = {
15
15
  panel: "mx-auto min-h-[640px] max-w-3xl",
package/dist/context.js CHANGED
@@ -4,9 +4,9 @@ import { Button } from "./ui/button.js";
4
4
  import { ScrollArea } from "./ui/scroll-area.js";
5
5
  import { deriveContextModel } from "./context-model.js";
6
6
  import { Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger } from "./ui/popover.js";
7
+ import { X } from "lucide-react";
7
8
  import { createContext, useContext, useId, useMemo } from "react";
8
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
- import { X } from "lucide-react";
10
10
  //#region src/context.tsx
11
11
  const ContextValueContext = createContext(null);
12
12
  function useContextValue() {
@@ -4,10 +4,10 @@ import { Button } from "../ui/button.js";
4
4
  import { useFilterBarContext } from "./context.js";
5
5
  import { describeFilter, formatFilterValue } from "./model.js";
6
6
  import { FilterBarEditor, FilterBarInlineInput } from "./editor.js";
7
+ import { PlusIcon, XIcon } from "lucide-react";
7
8
  import { useEffect, useId, useRef } from "react";
8
9
  import { useRender } from "@base-ui/react/use-render";
9
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { PlusIcon, XIcon } from "lucide-react";
11
11
  //#region src/filter-bar/parts.tsx
12
12
  function chipSegments(item, field, operator, draft) {
13
13
  const segments = [{
@@ -4,9 +4,9 @@ import { Button } from "./ui/button.js";
4
4
  import { LiveStatus } from "./ui/live-status.js";
5
5
  import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover.js";
6
6
  import { SourceFavicon, sourceHostname } from "./source-badge.js";
7
+ import { ArrowLeft, ArrowRight, ExternalLink } from "lucide-react";
7
8
  import { createContext, useContext, useRef, useState } from "react";
8
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
- import { ArrowLeft, ArrowRight, ExternalLink } from "lucide-react";
10
10
  //#region src/inline-citation.tsx
11
11
  const defaultViewSourcesLabel = (count) => count === 1 ? "view 1 source" : `view ${count} sources`;
12
12
  const defaultPositionLabel = (position, count) => `Source ${position} of ${count}`;
@@ -1,4 +1,4 @@
1
1
  //#region src/knob-contracts/sidebar-knobs.d.ts
2
- export declare const sidebarKnobs: readonly ["--cui-sidebar-nav-height", "--cui-sidebar-nav-background", "--cui-sidebar-nav-foreground", "--cui-sidebar-nav-border-color", "--cui-sidebar-nav-border-width", "--cui-sidebar-nav-shadow", "--cui-sidebar-nav-item-radius", "--cui-sidebar-nav-item-active-background", "--cui-sidebar-nav-item-active-foreground", "--cui-sidebar-nav-gap", "--cui-sidebar-menu-badge-height", "--cui-sidebar-menu-badge-background", "--cui-sidebar-menu-badge-foreground", "--cui-sidebar-header-border-width", "--cui-sidebar-header-border-color", "--cui-sidebar-rail-divider-background", "--cui-sidebar-wrapper-background", "--cui-sidebar-wrapper-background-image", "--cui-sidebar-inner-background", "--cui-sidebar-inner-border-color", "--cui-sidebar-inner-background-image", "--cui-sidebar-inner-backdrop-filter", "--cui-sidebar-container-border-width", "--cui-sidebar-inner-border-width", "--cui-sidebar-inner-radius", "--cui-sidebar-inner-shadow", "--cui-sidebar-header-background", "--cui-sidebar-header-shadow", "--cui-sidebar-inset-background", "--cui-sidebar-inset-background-image", "--cui-sidebar-inset-shadow", "--cui-sidebar-inset-border-color", "--cui-sidebar-inset-border-width", "--cui-sidebar-inset-radius", "--cui-sidebar-inset-inset", "--cui-sidebar-menu-button-radius", "--cui-sidebar-group-label-foreground", "--cui-sidebar-menu-button-foreground", "--cui-sidebar-menu-button-hover-background", "--cui-sidebar-menu-button-hover-foreground", "--cui-sidebar-menu-button-hover-shadow", "--cui-sidebar-menu-button-active-background", "--cui-sidebar-menu-button-active-foreground", "--cui-sidebar-menu-button-active-shadow", "--cui-sidebar-menu-button-track-active-foreground", "--cui-sidebar-menu-button-height", "--cui-sidebar-menu-button-padding-block", "--cui-sidebar-menu-button-padding-inline", "--cui-sidebar-menu-button-font-size", "--cui-sidebar-menu-button-font-weight", "--cui-sidebar-menu-button-active-font-weight", "--cui-sidebar-group-label-font-size", "--cui-sidebar-group-label-font-weight", "--cui-sidebar-group-label-letter-spacing", "--cui-sidebar-group-label-text-transform", "--cui-sidebar-group-label-padding", "--cui-sidebar-skip-link-background", "--cui-sidebar-skip-link-foreground", "--cui-sidebar-skip-link-radius", "--cui-sidebar-skip-link-shadow", "--cui-sidebar-menu-button-background", "--cui-sidebar-menu-button-shadow"];
2
+ export declare const sidebarKnobs: readonly ["--cui-sidebar-nav-height", "--cui-sidebar-nav-background", "--cui-sidebar-nav-foreground", "--cui-sidebar-nav-border-color", "--cui-sidebar-nav-border-width", "--cui-sidebar-nav-shadow", "--cui-sidebar-nav-item-radius", "--cui-sidebar-nav-item-active-background", "--cui-sidebar-nav-item-active-foreground", "--cui-sidebar-nav-gap", "--cui-sidebar-icon-rail-border-width", "--cui-sidebar-icon-rail-border-color", "--cui-sidebar-raised-background", "--cui-sidebar-raised-border-width", "--cui-sidebar-raised-border-color", "--cui-sidebar-raised-radius", "--cui-sidebar-raised-shadow", "--cui-sidebar-menu-badge-height", "--cui-sidebar-menu-badge-background", "--cui-sidebar-menu-badge-foreground", "--cui-sidebar-header-border-width", "--cui-sidebar-header-border-color", "--cui-sidebar-rail-divider-background", "--cui-sidebar-wrapper-background", "--cui-sidebar-wrapper-background-image", "--cui-sidebar-inner-background", "--cui-sidebar-inner-border-color", "--cui-sidebar-inner-background-image", "--cui-sidebar-inner-backdrop-filter", "--cui-sidebar-container-border-width", "--cui-sidebar-inner-border-width", "--cui-sidebar-inner-radius", "--cui-sidebar-inner-shadow", "--cui-sidebar-header-background", "--cui-sidebar-header-shadow", "--cui-sidebar-inset-background", "--cui-sidebar-inset-background-image", "--cui-sidebar-inset-shadow", "--cui-sidebar-inset-border-color", "--cui-sidebar-inset-border-width", "--cui-sidebar-inset-radius", "--cui-sidebar-inset-inset", "--cui-sidebar-menu-button-radius", "--cui-sidebar-group-label-foreground", "--cui-sidebar-menu-button-foreground", "--cui-sidebar-menu-button-hover-background", "--cui-sidebar-menu-button-hover-foreground", "--cui-sidebar-menu-button-hover-shadow", "--cui-sidebar-menu-button-active-background", "--cui-sidebar-menu-button-active-foreground", "--cui-sidebar-menu-button-active-shadow", "--cui-sidebar-menu-button-track-active-foreground", "--cui-sidebar-menu-button-height", "--cui-sidebar-menu-button-padding-block", "--cui-sidebar-menu-button-padding-inline", "--cui-sidebar-menu-button-font-size", "--cui-sidebar-menu-button-font-weight", "--cui-sidebar-menu-button-active-font-weight", "--cui-sidebar-group-label-font-size", "--cui-sidebar-group-label-font-weight", "--cui-sidebar-group-label-letter-spacing", "--cui-sidebar-group-label-text-transform", "--cui-sidebar-group-label-padding", "--cui-sidebar-skip-link-background", "--cui-sidebar-skip-link-foreground", "--cui-sidebar-skip-link-radius", "--cui-sidebar-skip-link-shadow", "--cui-sidebar-menu-button-background", "--cui-sidebar-menu-button-shadow"];
3
3
  export type SidebarKnobStyle = Partial<Record<(typeof sidebarKnobs)[number], string>>;
4
4
  //#endregion
@@ -10,6 +10,13 @@ const sidebarKnobs = [
10
10
  "--cui-sidebar-nav-item-active-background",
11
11
  "--cui-sidebar-nav-item-active-foreground",
12
12
  "--cui-sidebar-nav-gap",
13
+ "--cui-sidebar-icon-rail-border-width",
14
+ "--cui-sidebar-icon-rail-border-color",
15
+ "--cui-sidebar-raised-background",
16
+ "--cui-sidebar-raised-border-width",
17
+ "--cui-sidebar-raised-border-color",
18
+ "--cui-sidebar-raised-radius",
19
+ "--cui-sidebar-raised-shadow",
13
20
  "--cui-sidebar-menu-badge-height",
14
21
  "--cui-sidebar-menu-badge-background",
15
22
  "--cui-sidebar-menu-badge-foreground",
@@ -1,3 +1,4 @@
1
+ import { MarkdownUrlPolicy } from "./extensions.js";
1
2
  import { MarkdownImageUpload } from "./uploads.js";
2
3
  import { Editor } from "@tiptap/core";
3
4
  //#region src/markdown-editor/context.d.ts
@@ -7,6 +8,7 @@ export type MarkdownEditorContextValue = {
7
8
  source: boolean;
8
9
  markdown: string;
9
10
  sourceRequired: boolean;
11
+ isUrlAllowed: MarkdownUrlPolicy;
10
12
  setSource: (source: boolean) => void;
11
13
  setMarkdown: (value: string) => void;
12
14
  setContentAttributes: (attributes: Record<string, string>) => void;
@@ -3,9 +3,9 @@ import { Button } from "../ui/button.js";
3
3
  import { LiveStatus } from "../ui/live-status.js";
4
4
  import { useMarkdownEditor } from "./context.js";
5
5
  import { createDragPreview } from "./drag-preview.js";
6
+ import { GripVerticalIcon } from "lucide-react";
6
7
  import { useEffect, useRef, useState } from "react";
7
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { GripVerticalIcon } from "lucide-react";
9
9
  import { NodeSelection } from "@tiptap/pm/state";
10
10
  import { closeHistory } from "@tiptap/pm/history";
11
11
  //#region src/markdown-editor/drag-handle.tsx
@@ -1,10 +1,20 @@
1
- import { Extension, JSONContent, Node } from "@tiptap/core";
1
+ import { Extension, Extensions, JSONContent, Node } from "@tiptap/core";
2
2
  import { MarkdownManager } from "@tiptap/markdown";
3
3
  //#region src/markdown-editor/extensions.d.ts
4
4
  export declare function isEditorUrl(value: string, image?: boolean): boolean;
5
+ export type MarkdownUrlKind = "link" | "image";
6
+ /** Decides which URLs the editor keeps. Content with a refused URL stays in source mode, so nothing is dropped. */
7
+ export type MarkdownUrlPolicy = (url: string, kind: MarkdownUrlKind) => boolean;
8
+ /** Web apps only keep URLs that still resolve after a reload: HTTP(S), mailto, root-relative paths and anchors. */
9
+ export declare const persistentUrlPolicy: MarkdownUrlPolicy;
10
+ export type MarkdownExtensionOptions = {
11
+ /** Extra TipTap extensions, applied after the built-in Markdown set. */
12
+ extensions?: Extensions;
13
+ isUrlAllowed?: MarkdownUrlPolicy;
14
+ };
5
15
  export declare const ImageUpload: Node<any, any>;
6
- export declare function markdownExtensions(): (Extension<any, any> | Extension<import("@tiptap/markdown").MarkdownExtensionOptions, import("@tiptap/markdown").MarkdownExtensionStorage> | Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | Extension<import("@tiptap/extension-table").TableKitOptions, any> | Node<any, any> | Node<import("@tiptap/extension-image").ImageOptions, any> | Node<import("@tiptap/extension-paragraph").ParagraphOptions, any> | Node<import("@tiptap/extension-list").TaskItemOptions, any> | Node<import("@tiptap/extension-list").TaskListOptions, any>)[];
7
- export declare function createMarkdownCodec(): MarkdownManager;
8
- export declare function requiresMarkdownSource(markdown: string, codec: MarkdownManager): boolean;
16
+ export declare function markdownExtensions({ extensions, isUrlAllowed }?: MarkdownExtensionOptions): (import("@tiptap/core").AnyExtension | Extension<import("@tiptap/markdown").MarkdownExtensionOptions, import("@tiptap/markdown").MarkdownExtensionStorage> | Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | Extension<import("@tiptap/extension-table").TableKitOptions, any> | Node<any, any> | Node<import("@tiptap/extension-image").ImageOptions, any> | Node<import("@tiptap/extension-paragraph").ParagraphOptions, any> | Node<import("@tiptap/extension-list").TaskItemOptions, any> | Node<import("@tiptap/extension-list").TaskListOptions, any>)[];
17
+ export declare function createMarkdownCodec(options?: MarkdownExtensionOptions): MarkdownManager;
18
+ export declare function requiresMarkdownSource(markdown: string, codec: MarkdownManager, isUrlAllowed?: MarkdownUrlPolicy): boolean;
9
19
  export declare function hasMarkdownContent(document: JSONContent): boolean;
10
20
  //#endregion
@@ -42,27 +42,31 @@ function isEditorUrl(value, image = false) {
42
42
  return false;
43
43
  }
44
44
  }
45
- const SafeImage = Image.extend({
46
- renderMarkdown: (node) => {
47
- const src = String(node.attrs?.src ?? "").replace(/[()]/g, (character) => `\\${character}`);
48
- const alt = String(node.attrs?.alt ?? "").replace(/[\\[\]]/g, (character) => `\\${character}`);
49
- const title = String(node.attrs?.title ?? "").replace(/[\\"]/g, (character) => `\\${character}`);
50
- return title ? `![${alt}](${src} "${title}")` : `![${alt}](${src})`;
51
- },
52
- addAttributes() {
53
- return {
54
- ...this.parent?.(),
55
- src: {
56
- default: null,
57
- parseHTML: (element) => {
58
- const src = element.getAttribute("src") ?? "";
59
- return isEditorUrl(src, true) ? src : null;
60
- },
61
- renderHTML: (attributes) => ({ src: isEditorUrl(attributes.src ?? "", true) ? attributes.src : void 0 })
62
- }
63
- };
64
- }
65
- });
45
+ /** Web apps only keep URLs that still resolve after a reload: HTTP(S), mailto, root-relative paths and anchors. */
46
+ const persistentUrlPolicy = (url, kind) => isEditorUrl(url, kind === "image");
47
+ function safeImage(isUrlAllowed) {
48
+ return Image.extend({
49
+ renderMarkdown: (node) => {
50
+ const src = String(node.attrs?.src ?? "").replace(/[()]/g, (character) => `\\${character}`);
51
+ const alt = String(node.attrs?.alt ?? "").replace(/[\\[\]]/g, (character) => `\\${character}`);
52
+ const title = String(node.attrs?.title ?? "").replace(/[\\"]/g, (character) => `\\${character}`);
53
+ return title ? `![${alt}](${src} "${title}")` : `![${alt}](${src})`;
54
+ },
55
+ addAttributes() {
56
+ return {
57
+ ...this.parent?.(),
58
+ src: {
59
+ default: null,
60
+ parseHTML: (element) => {
61
+ const src = element.getAttribute("src") ?? "";
62
+ return isUrlAllowed(src, "image") ? src : null;
63
+ },
64
+ renderHTML: (attributes) => ({ src: isUrlAllowed(attributes.src ?? "", "image") ? attributes.src : void 0 })
65
+ }
66
+ };
67
+ }
68
+ });
69
+ }
66
70
  const MarkdownParagraph = Paragraph.extend({ parseMarkdown: (token, helpers) => {
67
71
  const content = helpers.parseInline(token.tokens ?? []);
68
72
  const first = content[0];
@@ -88,19 +92,19 @@ const ImageUpload = Node.create({
88
92
  ],
89
93
  renderMarkdown: () => ""
90
94
  });
91
- function markdownExtensions() {
95
+ function markdownExtensions({ extensions = [], isUrlAllowed = persistentUrlPolicy } = {}) {
92
96
  return [
93
97
  StarterKit.configure({
94
98
  underline: false,
95
99
  paragraph: false,
96
100
  link: {
97
101
  openOnClick: false,
98
- isAllowedUri: (url) => isEditorUrl(url)
102
+ isAllowedUri: (url) => isUrlAllowed(url, "link")
99
103
  }
100
104
  }),
101
105
  MarkdownParagraph,
102
106
  MarkdownHeadings,
103
- SafeImage.configure({
107
+ safeImage(isUrlAllowed).configure({
104
108
  allowBase64: false,
105
109
  inline: true
106
110
  }),
@@ -111,11 +115,12 @@ function markdownExtensions() {
111
115
  }),
112
116
  TableKit.configure({ table: { resizable: false } }),
113
117
  ImageUpload,
114
- Markdown
118
+ Markdown,
119
+ ...extensions
115
120
  ];
116
121
  }
117
- function createMarkdownCodec() {
118
- return new MarkdownManager({ extensions: markdownExtensions() });
122
+ function createMarkdownCodec(options) {
123
+ return new MarkdownManager({ extensions: markdownExtensions(options) });
119
124
  }
120
125
  const supportedTokens = /* @__PURE__ */ new Set([
121
126
  "space",
@@ -140,17 +145,17 @@ const supportedTokens = /* @__PURE__ */ new Set([
140
145
  "taskList",
141
146
  "taskItem"
142
147
  ]);
143
- function unsupportedToken(value) {
144
- if (Array.isArray(value)) return value.some(unsupportedToken);
148
+ function unsupportedToken(value, isUrlAllowed) {
149
+ if (Array.isArray(value)) return value.some((item) => unsupportedToken(item, isUrlAllowed));
145
150
  if (typeof value !== "object" || value === null) return false;
146
151
  if ("type" in value && typeof value.type === "string") {
147
152
  if (!supportedTokens.has(value.type)) return true;
148
- if ((value.type === "image" || value.type === "link") && "href" in value && typeof value.href === "string" && !isEditorUrl(value.href, value.type === "image")) return true;
153
+ if ((value.type === "image" || value.type === "link") && "href" in value && typeof value.href === "string" && !isUrlAllowed(value.href, value.type)) return true;
149
154
  }
150
- return Object.values(value).some(unsupportedToken);
155
+ return Object.values(value).some((item) => unsupportedToken(item, isUrlAllowed));
151
156
  }
152
- function requiresMarkdownSource(markdown, codec) {
153
- return unsupportedToken(codec.instance.lexer(markdown));
157
+ function requiresMarkdownSource(markdown, codec, isUrlAllowed = persistentUrlPolicy) {
158
+ return unsupportedToken(codec.instance.lexer(markdown), isUrlAllowed);
154
159
  }
155
160
  function hasMarkdownContent(document) {
156
161
  if (document.type === "image") return true;
@@ -158,4 +163,4 @@ function hasMarkdownContent(document) {
158
163
  return document.content?.some(hasMarkdownContent) ?? false;
159
164
  }
160
165
  //#endregion
161
- export { ImageUpload, createMarkdownCodec, hasMarkdownContent, isEditorUrl, markdownExtensions, requiresMarkdownSource };
166
+ export { ImageUpload, createMarkdownCodec, hasMarkdownContent, isEditorUrl, markdownExtensions, persistentUrlPolicy, requiresMarkdownSource };
@@ -2,12 +2,11 @@
2
2
  import { LiveStatus } from "../ui/live-status.js";
3
3
  import { isComposingKey, useTriggerMenu } from "../hooks/use-trigger-menu.js";
4
4
  import { useMarkdownEditor } from "./context.js";
5
- import { isEditorUrl } from "./extensions.js";
6
5
  import { detectTrigger } from "../lib/trigger-detect.js";
7
6
  import { TriggerMenu, TriggerMenuEmpty, TriggerMenuIcon, TriggerMenuItem, TriggerMenuList } from "../ui/trigger-menu.js";
7
+ import { Heading1Icon, Heading2Icon, Heading3Icon, ListChecksIcon, ListIcon, ListOrderedIcon, MinusIcon, QuoteIcon, SquareCodeIcon, TextIcon, UserIcon } from "lucide-react";
8
8
  import { useEffect, useEffectEvent, useRef } from "react";
9
9
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
- import { Heading1Icon, Heading2Icon, Heading3Icon, ListChecksIcon, ListIcon, ListOrderedIcon, MinusIcon, QuoteIcon, SquareCodeIcon, TextIcon, UserIcon } from "lucide-react";
11
10
  //#region src/markdown-editor/suggestions.tsx
12
11
  const blockCommands = [
13
12
  {
@@ -94,7 +93,7 @@ function readTrigger(editor) {
94
93
  }
95
94
  function MarkdownEditorSuggestions({ mentions = [], onMentionSelect }) {
96
95
  const activeItem = useRef(null);
97
- const { editor, disabled, source } = useMarkdownEditor();
96
+ const { editor, disabled, source, isUrlAllowed } = useMarkdownEditor();
98
97
  const enabled = Boolean(editor) && !disabled && !source;
99
98
  const controller = useTriggerMenu({
100
99
  triggers: [{
@@ -113,7 +112,7 @@ function MarkdownEditorSuggestions({ mentions = [], onMentionSelect }) {
113
112
  to: match.end
114
113
  };
115
114
  if (match.char === "/" && item.command) item.command(editor.chain().focus().deleteRange(range)).run();
116
- if (match.char === "@" && item.href && isEditorUrl(item.href)) {
115
+ if (match.char === "@" && item.href && isUrlAllowed(item.href, "link")) {
117
116
  editor.chain().focus().insertContentAt(range, [{
118
117
  type: "text",
119
118
  text: `@${item.label}`,
@@ -212,7 +211,7 @@ function MarkdownEditorSuggestions({ mentions = [], onMentionSelect }) {
212
211
  children: controller.items.map((item, index) => /* @__PURE__ */ jsxs(TriggerMenuItem, {
213
212
  id: controller.optionId(index),
214
213
  active: index === controller.activeIndex,
215
- disabled: item.disabled || item.href !== void 0 && !isEditorUrl(item.href),
214
+ disabled: item.disabled || item.href !== void 0 && !isUrlAllowed(item.href, "link"),
216
215
  ref: index === controller.activeIndex ? activeItem : void 0,
217
216
  onPointerMove: () => controller.setActiveIndex(index),
218
217
  onClick: () => controller.select(item),
@@ -1,5 +1,5 @@
1
- import { MouseEventHandler, ReactNode } from "react";
2
1
  import { BoldIcon } from "lucide-react";
2
+ import { MouseEventHandler, ReactNode } from "react";
3
3
  //#region src/markdown-editor/toolbar.d.ts
4
4
  type MarkdownEditorFormatAction = {
5
5
  label: string;