composeai 0.1.3 → 0.1.5

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/index.cjs CHANGED
@@ -797,11 +797,11 @@ function EditorShell({
797
797
  }) {
798
798
  const { classNames, sx, dir } = useComposerContext();
799
799
  const isMarkdown = mode === "markdown";
800
- const editorClass = multiline ? "composer-editor min-h-[44px] max-h-56 scrollbar-thin overflow-y-auto px-5 py-3.5" : "composer-editor composer-editor--inline h-9 overflow-x-auto overflow-y-hidden whitespace-nowrap px-2 leading-9";
800
+ const editorClass = multiline ? "composer-editor composer-editor--multiline" : "composer-editor composer-editor--inline";
801
801
  const editor = slotProps("editor", editorClass, classNames, sx);
802
802
  const editorResolved = resolveSx(sx?.editor);
803
803
  const placeholderBase = mirrorEditorPadding(editorResolved);
804
- const placeholderClass = multiline ? "composer-placeholder pointer-events-none absolute inset-x-0 top-0 select-none px-5 py-3.5 text-[15px] leading-relaxed text-muted-foreground" : "composer-placeholder pointer-events-none absolute inset-y-0 inset-x-0 select-none px-2 text-[15px] leading-9 text-muted-foreground truncate";
804
+ const placeholderClass = multiline ? "composer-placeholder composer-placeholder--multiline" : "composer-placeholder composer-placeholder--inline";
805
805
  const placeholderProps = slotProps(
806
806
  "placeholder",
807
807
  placeholderClass,
@@ -815,9 +815,9 @@ function EditorShell({
815
815
  "div",
816
816
  {
817
817
  className: cn(
818
- "composer-editor-block relative min-w-0",
818
+ "composer-editor-block",
819
819
  // Inline: the editor block is the flex child that fills the row.
820
- !multiline && "flex-1"
820
+ !multiline && "composer-editor-block--inline"
821
821
  ),
822
822
  children: isMarkdown ? /* @__PURE__ */ jsxRuntime.jsx(
823
823
  LexicalRichTextPlugin.RichTextPlugin,
@@ -839,10 +839,10 @@ function EditorShell({
839
839
  if (!multiline) {
840
840
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
841
841
  header,
842
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-inline-row flex items-center gap-1 px-2 py-1.5", children: [
843
- toolbar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-inline-toolbar flex shrink-0 items-center", children: toolbar }),
842
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-inline-row", children: [
843
+ toolbar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-inline-toolbar", children: toolbar }),
844
844
  editorBlock,
845
- sendButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-inline-send flex shrink-0 items-center", children: sendButton })
845
+ sendButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-inline-send", children: sendButton })
846
846
  ] }),
847
847
  /* @__PURE__ */ jsxRuntime.jsx(LexicalHistoryPlugin.HistoryPlugin, {})
848
848
  ] });
@@ -850,7 +850,7 @@ function EditorShell({
850
850
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
851
851
  header,
852
852
  editorBlock,
853
- (toolbar || sendButton) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 pb-2.5", children: [
853
+ (toolbar || sendButton) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-toolbar-row", children: [
854
854
  toolbar ?? /* @__PURE__ */ jsxRuntime.jsx("span", {}),
855
855
  sendButton
856
856
  ] }),
@@ -1399,7 +1399,8 @@ function wrapByFormat(text, format) {
1399
1399
  if (format & FORMAT_BIT.strike) out = `~~${out}~~`;
1400
1400
  return out;
1401
1401
  }
1402
- function toMarkdown(editor) {
1402
+ function toMarkdown(editor, opts) {
1403
+ const linkedMention = opts?.linkedMention === true;
1403
1404
  return editor.getEditorState().read(() => {
1404
1405
  const root = lexical.$getRoot();
1405
1406
  let usingLive = true;
@@ -1424,7 +1425,13 @@ function toMarkdown(editor) {
1424
1425
  let out = "";
1425
1426
  for (const child of paragraph.getChildren()) {
1426
1427
  if ($isMentionNode(child)) {
1427
- out += `${child.getMentionPrefix()}${child.getMentionLabel()}`;
1428
+ const prefix = child.getMentionPrefix();
1429
+ const label = child.getMentionLabel();
1430
+ if (linkedMention) {
1431
+ out += `[${prefix}${label}](mention:${child.getMentionId()})`;
1432
+ } else {
1433
+ out += `${prefix}${label}`;
1434
+ }
1428
1435
  continue;
1429
1436
  }
1430
1437
  if (lexical.$isLineBreakNode(child)) {
@@ -2344,14 +2351,15 @@ function ImageLightbox({ src, alt, onClose }) {
2344
2351
  {
2345
2352
  role: "dialog",
2346
2353
  "aria-modal": "true",
2347
- className: "fixed inset-0 z-50 flex items-center justify-center p-6",
2354
+ "data-composer-scope": "",
2355
+ className: "composer-lightbox",
2348
2356
  style: tokenStyle,
2349
2357
  children: [
2350
2358
  /* @__PURE__ */ jsxRuntime.jsx(
2351
2359
  "div",
2352
2360
  {
2353
2361
  "aria-hidden": true,
2354
- className: "absolute inset-0 bg-foreground/70 backdrop-blur-sm",
2362
+ className: "composer-lightbox-backdrop",
2355
2363
  onClick: onClose
2356
2364
  }
2357
2365
  ),
@@ -2361,18 +2369,11 @@ function ImageLightbox({ src, alt, onClose }) {
2361
2369
  type: "button",
2362
2370
  onClick: onClose,
2363
2371
  "aria-label": "Close",
2364
- className: "absolute end-5 top-5 flex h-9 w-9 items-center justify-center rounded-full bg-card text-foreground shadow-soft transition-colors hover:bg-accent",
2365
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-4 w-4" })
2372
+ className: "composer-lightbox-close",
2373
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
2366
2374
  }
2367
2375
  ),
2368
- /* @__PURE__ */ jsxRuntime.jsx(
2369
- "img",
2370
- {
2371
- src,
2372
- alt,
2373
- className: "relative max-h-[85vh] max-w-[85vw] rounded-lg object-contain shadow-xl"
2374
- }
2375
- )
2376
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt, className: "composer-lightbox-img" })
2376
2377
  ]
2377
2378
  }
2378
2379
  ) });
@@ -2500,16 +2501,16 @@ function MermaidPlugin() {
2500
2501
  if (diagrams.length === 0) return null;
2501
2502
  const preview = slotProps(
2502
2503
  "mermaidPreview",
2503
- "border-t border-border/60 bg-muted/30 px-4 py-3",
2504
+ "composer-mermaid",
2504
2505
  classNames,
2505
2506
  sx
2506
2507
  );
2507
2508
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...preview, children: [
2508
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1.5 flex items-center gap-1.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: [
2509
- /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-3 w-3" }),
2509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-mermaid-head", children: [
2510
+ /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, {}),
2510
2511
  "Diagram preview"
2511
2512
  ] }),
2512
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 overflow-x-auto scrollbar-thin", children: diagrams.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
2513
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-row", children: diagrams.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
2513
2514
  DiagramTile,
2514
2515
  {
2515
2516
  diagram: d,
@@ -2534,9 +2535,9 @@ function ConsumerTile({
2534
2535
  content = renderDiagram({ code: diagram.code, language: "mermaid" });
2535
2536
  } catch (err) {
2536
2537
  console.error("[composeai] renderDiagram threw", err);
2537
- content = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-24 w-40 items-center justify-center px-2 text-center text-[10px] text-destructive", children: err instanceof Error ? err.message.slice(0, 80) : "Render failed" });
2538
+ content = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-msg composer-mermaid-msg--error", children: err instanceof Error ? err.message.slice(0, 80) : "Render failed" });
2538
2539
  }
2539
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 overflow-hidden rounded-lg border border-border bg-card", children: content });
2540
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-tile", children: content });
2540
2541
  }
2541
2542
  function MermaidTile({ diagram }) {
2542
2543
  const { icons } = useComposerContext();
@@ -2583,24 +2584,22 @@ function MermaidTile({ diagram }) {
2583
2584
  type: "button",
2584
2585
  onClick: () => svg && setZoom(true),
2585
2586
  "aria-label": "Zoom diagram",
2586
- className: "group/dia relative shrink-0 overflow-hidden rounded-lg border border-border bg-card transition-colors hover:border-primary/40",
2587
+ className: "composer-mermaid-tile",
2587
2588
  children: svg ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2588
2589
  /* @__PURE__ */ jsxRuntime.jsx(
2589
2590
  "div",
2590
2591
  {
2591
- className: "h-24 w-40 [&_svg]:h-full [&_svg]:w-full",
2592
+ className: "composer-mermaid-svg",
2592
2593
  dangerouslySetInnerHTML: { __html: svg }
2593
2594
  }
2594
2595
  ),
2595
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute end-1 top-1 flex h-5 w-5 items-center justify-center rounded-full bg-foreground/70 text-background opacity-0 transition-opacity group-hover/dia:opacity-100", children: /* @__PURE__ */ jsxRuntime.jsx(ZoomIcon, { className: "h-3 w-3" }) })
2596
- ] }) : mermaidMissing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid h-24 w-40 place-items-center px-3 text-center text-[11px] leading-snug text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2596
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-mermaid-zoom", children: /* @__PURE__ */ jsxRuntime.jsx(ZoomIcon, {}) })
2597
+ ] }) : mermaidMissing ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-msg", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2597
2598
  "Install ",
2598
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "rounded bg-muted px-1 font-mono", children: "mermaid" }),
2599
- " ",
2600
- "or pass",
2601
- " ",
2602
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "rounded bg-muted px-1 font-mono", children: "renderDiagram" })
2603
- ] }) }) : error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid h-24 w-40 place-items-center px-2 text-center text-[10px] leading-snug text-destructive", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: error.slice(0, 80) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid h-24 w-40 place-items-center text-[10px] text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Rendering\u2026" }) })
2599
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "composer-mermaid-code", children: "mermaid" }),
2600
+ " or pass ",
2601
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "composer-mermaid-code", children: "renderDiagram" })
2602
+ ] }) }) : error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-msg composer-mermaid-msg--error", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: error.slice(0, 80) }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-mermaid-msg", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Rendering\u2026" }) })
2604
2603
  }
2605
2604
  ),
2606
2605
  zoom && svg && /* @__PURE__ */ jsxRuntime.jsx(
@@ -2639,7 +2638,7 @@ function SlashMenu({
2639
2638
  );
2640
2639
  const menu = slotProps(
2641
2640
  "slashMenu",
2642
- "z-50 w-72 origin-top animate-slide-up overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-soft",
2641
+ "composer-menu composer-menu--slash",
2643
2642
  classNames,
2644
2643
  sx
2645
2644
  );
@@ -2653,10 +2652,10 @@ function SlashMenu({
2653
2652
  "aria-label": "Slash commands",
2654
2653
  "aria-busy": isLoading || void 0,
2655
2654
  ...menu,
2656
- children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { ref: listRef, className: "max-h-72 overflow-y-auto scrollbar-thin py-1", children: [
2655
+ children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { ref: listRef, className: "composer-menu-list", children: [
2657
2656
  showSkeleton && /* @__PURE__ */ jsxRuntime.jsx(SlashSkeleton, { rows: 4 }),
2658
2657
  Object.entries(grouped).map(([group, entries]) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
2659
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-1 pt-2 text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: group }),
2658
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "composer-menu-group", children: group }),
2660
2659
  /* @__PURE__ */ jsxRuntime.jsx("ul", { children: entries.map(({ item, index }) => /* @__PURE__ */ jsxRuntime.jsxs(
2661
2660
  "li",
2662
2661
  {
@@ -2668,19 +2667,15 @@ function SlashMenu({
2668
2667
  onSelect(index);
2669
2668
  },
2670
2669
  onMouseEnter: () => onHover(index),
2671
- className: cn(
2672
- "flex cursor-pointer items-center gap-2.5 px-2.5 py-1.5 text-sm",
2673
- selectedIndex === index ? "bg-accent text-accent-foreground" : "text-foreground",
2674
- classNames?.slashItem
2675
- ),
2670
+ className: cn("composer-menu-item", classNames?.slashItem),
2676
2671
  style: itemStyle,
2677
2672
  children: [
2678
- item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: item.icon }),
2679
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
2680
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: item.label }),
2681
- item.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: item.description })
2673
+ item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-icon", children: item.icon }),
2674
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-menu-text", children: [
2675
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-label", children: item.label }),
2676
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-desc", children: item.description })
2682
2677
  ] }),
2683
- item.shortcut && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ms-auto rounded border border-border bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground", children: item.shortcut })
2678
+ item.shortcut && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-shortcut", children: item.shortcut })
2684
2679
  ]
2685
2680
  },
2686
2681
  item.id
@@ -2691,35 +2686,28 @@ function SlashMenu({
2691
2686
  );
2692
2687
  }
2693
2688
  function SlashSkeleton({ rows = 4 }) {
2694
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { "aria-hidden": "true", className: "px-2.5 py-1.5", children: [
2695
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-0.5 pb-1.5 pt-0.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-2 w-16 animate-pulse rounded bg-muted/70" }) }),
2696
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2697
- "li",
2698
- {
2699
- className: "flex items-center gap-2.5 rounded-md px-0 py-1.5",
2700
- children: [
2701
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-7 w-7 shrink-0 animate-pulse rounded-md bg-muted" }),
2702
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
2703
- /* @__PURE__ */ jsxRuntime.jsx(
2704
- "span",
2705
- {
2706
- className: "h-2.5 animate-pulse rounded bg-muted",
2707
- style: { width: `${50 + i * 19 % 35}%` }
2708
- }
2709
- ),
2710
- /* @__PURE__ */ jsxRuntime.jsx(
2711
- "span",
2712
- {
2713
- className: "h-2 animate-pulse rounded bg-muted/70",
2714
- style: { width: `${30 + i * 13 % 30}%` }
2715
- }
2716
- )
2717
- ] })
2718
- ]
2719
- },
2720
- i
2721
- )) }),
2722
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading commands\u2026" })
2689
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { "aria-hidden": "true", className: "composer-skel-row", children: [
2690
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-skel-grouplabel composer-pulse" }),
2691
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "composer-skel-group", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "composer-skel-line", children: [
2692
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-skel-avatar composer-skel-avatar--square composer-pulse" }),
2693
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-skel-text", children: [
2694
+ /* @__PURE__ */ jsxRuntime.jsx(
2695
+ "span",
2696
+ {
2697
+ className: "composer-skel-bar composer-pulse",
2698
+ style: { width: `${50 + i * 19 % 35}%` }
2699
+ }
2700
+ ),
2701
+ /* @__PURE__ */ jsxRuntime.jsx(
2702
+ "span",
2703
+ {
2704
+ className: "composer-skel-bar--sm composer-pulse",
2705
+ style: { width: `${30 + i * 13 % 30}%` }
2706
+ }
2707
+ )
2708
+ ] })
2709
+ ] }, i)) }),
2710
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-sr-only", children: "Loading commands\u2026" })
2723
2711
  ] });
2724
2712
  }
2725
2713
  var MARGIN = 8;
@@ -2886,6 +2874,7 @@ function SmartPopover({ children, gap = 6 }) {
2886
2874
  "div",
2887
2875
  {
2888
2876
  ref,
2877
+ "data-composer-scope": "",
2889
2878
  "data-composer-popover-placement": placement?.bottom !== void 0 ? "above-composer" : "below",
2890
2879
  dir: placement?.rtl ? "rtl" : "ltr",
2891
2880
  style: mergedStyle,
@@ -3035,14 +3024,14 @@ function Avatar({ src, alt, size = 28, className }) {
3035
3024
  return /* @__PURE__ */ jsxRuntime.jsx(
3036
3025
  "span",
3037
3026
  {
3038
- className: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-primary/10 text-xs font-semibold text-primary" + (className ? ` ${className}` : ""),
3027
+ className: "composer-avatar" + (className ? ` ${className}` : ""),
3039
3028
  style: { width: size, height: size },
3040
3029
  children: showImage ? /* @__PURE__ */ jsxRuntime.jsx(
3041
3030
  "img",
3042
3031
  {
3043
3032
  src,
3044
3033
  alt,
3045
- className: "h-full w-full object-cover",
3034
+ className: "composer-avatar-img",
3046
3035
  onError: () => setErrored(true)
3047
3036
  }
3048
3037
  ) : initial
@@ -3064,12 +3053,7 @@ function MentionMenu({
3064
3053
  );
3065
3054
  if (el) el.scrollIntoView({ block: "nearest" });
3066
3055
  }, [selectedIndex]);
3067
- const menu = slotProps(
3068
- "mentionMenu",
3069
- "z-50 w-64 origin-top animate-slide-up overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-soft",
3070
- classNames,
3071
- sx
3072
- );
3056
+ const menu = slotProps("mentionMenu", "composer-menu", classNames, sx);
3073
3057
  const itemStyle = react.useMemo(() => resolveSx(sx?.mentionItem), [sx]);
3074
3058
  const showSkeleton = isLoading && options.length === 0;
3075
3059
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -3080,7 +3064,7 @@ function MentionMenu({
3080
3064
  "aria-label": "Mentions",
3081
3065
  "aria-busy": isLoading || void 0,
3082
3066
  ...menu,
3083
- children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { ref: listRef, className: "max-h-72 overflow-y-auto scrollbar-thin py-1", children: [
3067
+ children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { ref: listRef, className: "composer-menu-list", children: [
3084
3068
  showSkeleton ? /* @__PURE__ */ jsxRuntime.jsx(MentionSkeleton, { rows: 3 }) : null,
3085
3069
  options.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(
3086
3070
  "li",
@@ -3093,17 +3077,13 @@ function MentionMenu({
3093
3077
  onSelect(index);
3094
3078
  },
3095
3079
  onMouseEnter: () => onHover(index),
3096
- className: cn(
3097
- "flex cursor-pointer items-center gap-2.5 px-2.5 py-1.5 text-sm",
3098
- selectedIndex === index ? "bg-accent text-accent-foreground" : "text-foreground",
3099
- classNames?.mentionItem
3100
- ),
3080
+ className: cn("composer-menu-item", classNames?.mentionItem),
3101
3081
  style: itemStyle,
3102
3082
  children: [
3103
- item.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: item.avatarUrl, alt: item.label }) : item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary", children: item.icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary", children: item.label.slice(0, 1).toUpperCase() }),
3104
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
3105
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: item.label }),
3106
- item.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: item.description })
3083
+ item.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx(Avatar, { src: item.avatarUrl, alt: item.label }) : item.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-avatar", children: item.icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-avatar", children: item.label.slice(0, 1).toUpperCase() }),
3084
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-menu-text", children: [
3085
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-label", children: item.label }),
3086
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-menu-desc", children: item.description })
3107
3087
  ] })
3108
3088
  ]
3109
3089
  },
@@ -3114,34 +3094,27 @@ function MentionMenu({
3114
3094
  );
3115
3095
  }
3116
3096
  function MentionSkeleton({ rows = 3 }) {
3117
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { "aria-hidden": "true", className: "px-2.5 py-1.5", children: [
3118
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs(
3119
- "li",
3120
- {
3121
- className: "flex items-center gap-2.5 rounded-md px-0 py-1.5",
3122
- children: [
3123
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-7 w-7 shrink-0 animate-pulse rounded-full bg-muted" }),
3124
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
3125
- /* @__PURE__ */ jsxRuntime.jsx(
3126
- "span",
3127
- {
3128
- className: "h-2.5 animate-pulse rounded bg-muted",
3129
- style: { width: `${60 + i * 17 % 30}%` }
3130
- }
3131
- ),
3132
- /* @__PURE__ */ jsxRuntime.jsx(
3133
- "span",
3134
- {
3135
- className: "h-2 animate-pulse rounded bg-muted/70",
3136
- style: { width: `${35 + i * 23 % 25}%` }
3137
- }
3138
- )
3139
- ] })
3140
- ]
3141
- },
3142
- i
3143
- )) }),
3144
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading suggestions\u2026" })
3097
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { "aria-hidden": "true", className: "composer-skel-row", children: [
3098
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "composer-skel-group", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "composer-skel-line", children: [
3099
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-skel-avatar composer-pulse" }),
3100
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-skel-text", children: [
3101
+ /* @__PURE__ */ jsxRuntime.jsx(
3102
+ "span",
3103
+ {
3104
+ className: "composer-skel-bar composer-pulse",
3105
+ style: { width: `${60 + i * 17 % 30}%` }
3106
+ }
3107
+ ),
3108
+ /* @__PURE__ */ jsxRuntime.jsx(
3109
+ "span",
3110
+ {
3111
+ className: "composer-skel-bar--sm composer-pulse",
3112
+ style: { width: `${35 + i * 23 % 25}%` }
3113
+ }
3114
+ )
3115
+ ] })
3116
+ ] }, i)) }),
3117
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-sr-only", children: "Loading suggestions\u2026" })
3145
3118
  ] });
3146
3119
  }
3147
3120
  var MentionOption = class extends LexicalTypeaheadMenuPlugin.MenuOption {
@@ -3368,14 +3341,14 @@ function GhostOverlay({ typed, remainder, multiline }) {
3368
3341
  setContainer(block);
3369
3342
  }, [editor]);
3370
3343
  if (!container) return null;
3371
- const paddingClass = multiline ? "composer-ghost-overlay--multiline px-5 py-3.5" : "composer-ghost-overlay--inline px-2 leading-9";
3344
+ const paddingClass = multiline ? "composer-ghost-overlay--multiline" : "composer-ghost-overlay--inline";
3372
3345
  return reactDom.createPortal(
3373
3346
  /* @__PURE__ */ jsxRuntime.jsxs(
3374
3347
  "div",
3375
3348
  {
3376
3349
  "aria-hidden": true,
3377
3350
  "data-composer-ghost": "",
3378
- className: `composer-ghost-overlay pointer-events-none absolute inset-0 select-none ${paddingClass}`,
3351
+ className: `composer-ghost-overlay ${paddingClass}`,
3379
3352
  children: [
3380
3353
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-ghost-overlay-typed", "aria-hidden": true, children: typed }),
3381
3354
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-ghost-suggestion", children: remainder })
@@ -3407,7 +3380,7 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3407
3380
  if (isImage) {
3408
3381
  const chip2 = slotProps(
3409
3382
  "attachmentChip",
3410
- "group/chip relative h-16 w-16 overflow-hidden rounded-xl border border-border bg-muted",
3383
+ "composer-chip composer-chip--image",
3411
3384
  classNames,
3412
3385
  sx
3413
3386
  );
@@ -3417,23 +3390,23 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3417
3390
  {
3418
3391
  src: attachment.previewUrl,
3419
3392
  alt: attachment.name,
3420
- className: "h-full w-full object-cover"
3393
+ className: "composer-chip-img"
3421
3394
  }
3422
3395
  ),
3423
3396
  isUploading && /* @__PURE__ */ jsxRuntime.jsx(
3424
3397
  "div",
3425
3398
  {
3426
3399
  "aria-label": "Uploading",
3427
- className: "absolute inset-0 grid place-items-center bg-foreground/50",
3428
- children: /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "h-5 w-5 animate-spin text-background" })
3400
+ className: "composer-chip-overlay composer-chip-overlay--uploading",
3401
+ children: /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "composer-spin" })
3429
3402
  }
3430
3403
  ),
3431
3404
  isFailed && /* @__PURE__ */ jsxRuntime.jsx(
3432
3405
  "div",
3433
3406
  {
3434
3407
  "aria-label": "Upload failed",
3435
- className: "absolute inset-0 grid place-items-center bg-destructive/55",
3436
- children: /* @__PURE__ */ jsxRuntime.jsx(WarningIcon, { className: "h-5 w-5 text-destructive-foreground" })
3408
+ className: "composer-chip-overlay composer-chip-overlay--failed",
3409
+ children: /* @__PURE__ */ jsxRuntime.jsx(WarningIcon, {})
3437
3410
  }
3438
3411
  ),
3439
3412
  !isUploading && !isFailed && /* @__PURE__ */ jsxRuntime.jsx(
@@ -3442,8 +3415,8 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3442
3415
  type: "button",
3443
3416
  onClick: onZoom,
3444
3417
  "aria-label": `Zoom ${attachment.name}`,
3445
- className: "absolute inset-0 flex items-center justify-center bg-foreground/40 opacity-0 transition-opacity group-hover/chip:opacity-100",
3446
- children: /* @__PURE__ */ jsxRuntime.jsx(ZoomIcon, { className: "h-4 w-4 text-background" })
3418
+ className: "composer-chip-zoom",
3419
+ children: /* @__PURE__ */ jsxRuntime.jsx(ZoomIcon, {})
3447
3420
  }
3448
3421
  ),
3449
3422
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3452,8 +3425,9 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3452
3425
  type: "button",
3453
3426
  onClick: onRemove,
3454
3427
  "aria-label": `Remove ${attachment.name}`,
3455
- className: "absolute end-1 top-1 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-foreground text-background transition-opacity " + (isUploading || isFailed ? "opacity-100" : "opacity-0 group-hover/chip:opacity-100"),
3456
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-3 w-3", strokeWidth: 2.5 })
3428
+ className: "composer-chip-remove",
3429
+ "data-visible": isUploading || isFailed ? "" : void 0,
3430
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { strokeWidth: 2.5 })
3457
3431
  }
3458
3432
  )
3459
3433
  ] });
@@ -3461,27 +3435,15 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3461
3435
  const KindIcon = attachment.kind === "audio" ? AudioIcon : FileIcon;
3462
3436
  const chip = slotProps(
3463
3437
  "attachmentChip",
3464
- "group/chip flex items-center gap-2 rounded-xl border bg-card ps-2 pe-1 py-1.5 " + (isFailed ? "border-destructive/60" : "border-border"),
3438
+ "composer-chip composer-chip--file",
3465
3439
  classNames,
3466
3440
  sx
3467
3441
  );
3468
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...chip, title: titleText, children: [
3469
- /* @__PURE__ */ jsxRuntime.jsx(
3470
- "span",
3471
- {
3472
- className: "flex h-8 w-8 items-center justify-center rounded-md " + (isFailed ? "bg-destructive/15 text-destructive" : "bg-muted text-muted-foreground"),
3473
- children: isUploading ? /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "h-4 w-4 animate-spin" }) : isFailed ? /* @__PURE__ */ jsxRuntime.jsx(WarningIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(KindIcon, { className: "h-4 w-4" })
3474
- }
3475
- ),
3476
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col", children: [
3477
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[160px] truncate text-xs font-medium leading-tight", children: attachment.name }),
3478
- /* @__PURE__ */ jsxRuntime.jsx(
3479
- "span",
3480
- {
3481
- className: "text-[10px] " + (isFailed ? "text-destructive" : "text-muted-foreground"),
3482
- children: isUploading ? "Uploading\u2026" : isFailed ? attachment.error || "Upload failed" : formatBytes(attachment.size)
3483
- }
3484
- )
3442
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...chip, "data-failed": isFailed ? "" : void 0, title: titleText, children: [
3443
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-chip-icon", "data-failed": isFailed ? "" : void 0, children: isUploading ? /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "composer-spin" }) : isFailed ? /* @__PURE__ */ jsxRuntime.jsx(WarningIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(KindIcon, {}) }),
3444
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-chip-text", children: [
3445
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-chip-name", children: attachment.name }),
3446
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-chip-meta", "data-failed": isFailed ? "" : void 0, children: isUploading ? "Uploading\u2026" : isFailed ? attachment.error || "Upload failed" : formatBytes(attachment.size) })
3485
3447
  ] }),
3486
3448
  /* @__PURE__ */ jsxRuntime.jsx(
3487
3449
  "button",
@@ -3489,8 +3451,8 @@ function AttachmentChip({ attachment, onRemove, onZoom }) {
3489
3451
  type: "button",
3490
3452
  onClick: onRemove,
3491
3453
  "aria-label": `Remove ${attachment.name}`,
3492
- className: "flex h-6 w-6 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
3493
- children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-3.5 w-3.5" })
3454
+ className: "composer-chip-remove-inline",
3455
+ children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
3494
3456
  }
3495
3457
  )
3496
3458
  ] });
@@ -3501,7 +3463,7 @@ function AttachmentTray() {
3501
3463
  if (attachments.length === 0) return null;
3502
3464
  const tray = slotProps(
3503
3465
  "attachmentTray",
3504
- "flex flex-wrap gap-2 px-4 pt-3",
3466
+ "composer-attachment-tray",
3505
3467
  classNames,
3506
3468
  sx
3507
3469
  );
@@ -3526,10 +3488,10 @@ function AttachmentTray() {
3526
3488
  ] });
3527
3489
  }
3528
3490
  var sideClasses = {
3529
- top: "bottom-full left-1/2 mb-2 -translate-x-1/2",
3530
- bottom: "top-full left-1/2 mt-2 -translate-x-1/2",
3531
- left: "end-full top-1/2 me-2 -translate-y-1/2",
3532
- right: "start-full top-1/2 ms-2 -translate-y-1/2"
3491
+ top: "composer-tooltip--top",
3492
+ bottom: "composer-tooltip--bottom",
3493
+ left: "composer-tooltip--left",
3494
+ right: "composer-tooltip--right"
3533
3495
  };
3534
3496
  function Tooltip({
3535
3497
  children,
@@ -3567,18 +3529,14 @@ function Tooltip({
3567
3529
  children
3568
3530
  }
3569
3531
  );
3570
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex", children: [
3532
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-tooltip-wrap", children: [
3571
3533
  trigger,
3572
3534
  open && /* @__PURE__ */ jsxRuntime.jsx(
3573
3535
  "span",
3574
3536
  {
3575
3537
  id,
3576
3538
  role: "tooltip",
3577
- className: cn(
3578
- "absolute z-50 whitespace-nowrap rounded-md bg-foreground px-2 py-1 text-xs text-background shadow-md",
3579
- sideClasses[side],
3580
- className
3581
- ),
3539
+ className: cn("composer-tooltip", sideClasses[side], className),
3582
3540
  children: content
3583
3541
  }
3584
3542
  )
@@ -3728,7 +3686,7 @@ function VoiceButton() {
3728
3686
  }
3729
3687
  };
3730
3688
  const isRecording = state === "recording" || state === "starting";
3731
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
3689
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-voice", children: [
3732
3690
  /* @__PURE__ */ jsxRuntime.jsx(
3733
3691
  Tooltip,
3734
3692
  {
@@ -3742,17 +3700,16 @@ function VoiceButton() {
3742
3700
  "aria-pressed": isRecording,
3743
3701
  onClick: () => isRecording ? stop() : void start(),
3744
3702
  className: cn(
3745
- "flex h-8 w-8 items-center justify-center rounded-full transition-colors",
3746
- isRecording ? "bg-destructive/10 text-destructive ring-1 ring-destructive/40" : "text-muted-foreground hover:bg-accent hover:text-foreground",
3703
+ "composer-toolbar-btn composer-voice-btn",
3747
3704
  classNames?.toolbarButton
3748
3705
  ),
3749
- children: state === "transcribing" ? /* @__PURE__ */ jsxRuntime.jsx(VoiceRecordingIcon, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(VoiceIcon, { className: cn("h-4 w-4", isRecording && "animate-pulse") })
3706
+ children: state === "transcribing" ? /* @__PURE__ */ jsxRuntime.jsx(VoiceRecordingIcon, { className: "composer-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(VoiceIcon, { className: cn(isRecording && "composer-pulse") })
3750
3707
  }
3751
3708
  )
3752
3709
  }
3753
3710
  ),
3754
- isRecording && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 rounded-full bg-destructive/10 px-2 py-0.5 text-[11px] font-mono font-medium tabular-nums text-destructive", children: [
3755
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-1.5 w-1.5 animate-pulse rounded-full bg-destructive" }),
3711
+ isRecording && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-voice-timer", children: [
3712
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-voice-dot composer-pulse" }),
3756
3713
  formatSeconds(elapsed)
3757
3714
  ] })
3758
3715
  ] });
@@ -3850,7 +3807,7 @@ function AttachmentTypePicker({
3850
3807
  react.useEffect(() => {
3851
3808
  if (open) setActiveIndex(0);
3852
3809
  }, [open]);
3853
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
3810
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "composer-attach-picker", children: [
3854
3811
  /* @__PURE__ */ jsxRuntime.jsx(
3855
3812
  "input",
3856
3813
  {
@@ -3877,7 +3834,7 @@ function AttachmentTypePicker({
3877
3834
  onClick: () => setOpen((o) => !o),
3878
3835
  className: triggerClassName,
3879
3836
  style: triggerStyle,
3880
- children: /* @__PURE__ */ jsxRuntime.jsx(TriggerIcon, { className: "h-4 w-4" })
3837
+ children: /* @__PURE__ */ jsxRuntime.jsx(TriggerIcon, {})
3881
3838
  }
3882
3839
  ),
3883
3840
  open && /* @__PURE__ */ jsxRuntime.jsx(
@@ -3888,11 +3845,7 @@ function AttachmentTypePicker({
3888
3845
  role: "menu",
3889
3846
  "aria-label": "Attachment types",
3890
3847
  "data-composer-popover": "open",
3891
- className: cn(
3892
- "composer-popover-in absolute bottom-full start-0 z-30 mb-2 min-w-[200px] overflow-hidden",
3893
- "rounded-xl border border-border bg-popover p-1 text-popover-foreground",
3894
- "shadow-soft"
3895
- ),
3848
+ className: "composer-popover-in composer-attach-menu",
3896
3849
  children: types.map((type, index) => {
3897
3850
  const active = index === activeIndex;
3898
3851
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3904,16 +3857,14 @@ function AttachmentTypePicker({
3904
3857
  role: "menuitem",
3905
3858
  type: "button",
3906
3859
  tabIndex: active ? 0 : -1,
3860
+ "data-active": active ? "" : void 0,
3907
3861
  onMouseEnter: () => setActiveIndex(index),
3908
3862
  onClick: () => pick(index),
3909
- className: cn(
3910
- "flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-start text-sm transition-colors",
3911
- active ? "bg-accent text-accent-foreground" : "text-foreground hover:bg-accent/60"
3912
- ),
3863
+ className: "composer-attach-item",
3913
3864
  children: [
3914
- type.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center text-muted-foreground", children: type.icon }) : null,
3915
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate font-medium", children: type.label }),
3916
- type.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-mono text-[11px] text-muted-foreground", children: type.description }) : null
3865
+ type.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-attach-item-icon", children: type.icon }) : null,
3866
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-attach-item-label", children: type.label }),
3867
+ type.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-attach-item-desc", children: type.description }) : null
3917
3868
  ]
3918
3869
  },
3919
3870
  type.id
@@ -3923,7 +3874,7 @@ function AttachmentTypePicker({
3923
3874
  )
3924
3875
  ] });
3925
3876
  }
3926
- var TOOLBAR_BTN_BASE = "flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground";
3877
+ var TOOLBAR_BTN_BASE = "composer-toolbar-btn";
3927
3878
  function Toolbar({ extras }) {
3928
3879
  const {
3929
3880
  features,
@@ -3942,7 +3893,7 @@ function Toolbar({ extras }) {
3942
3893
  const showFileBtn = attachmentsEnabled && attachmentsConfig.file !== false;
3943
3894
  const showImageBtn = attachmentsEnabled && attachmentsConfig.image !== false;
3944
3895
  const hasTypePicker = showFileBtn && Array.isArray(attachmentsConfig.types) && attachmentsConfig.types.length > 0;
3945
- const toolbar = slotProps("toolbar", "flex items-center gap-1", classNames, sx);
3896
+ const toolbar = slotProps("toolbar", "composer-toolbar", classNames, sx);
3946
3897
  const toolbarBtn = slotProps("toolbarButton", TOOLBAR_BTN_BASE, classNames, sx);
3947
3898
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ...toolbar, children: [
3948
3899
  showFileBtn && !hasTypePicker && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -3968,7 +3919,7 @@ function Toolbar({ extras }) {
3968
3919
  "aria-label": "Attach file",
3969
3920
  onClick: () => fileInputRef.current?.click(),
3970
3921
  ...toolbarBtn,
3971
- children: /* @__PURE__ */ jsxRuntime.jsx(AttachIcon, { className: "h-4 w-4" })
3922
+ children: /* @__PURE__ */ jsxRuntime.jsx(AttachIcon, {})
3972
3923
  }
3973
3924
  ) })
3974
3925
  ] }),
@@ -4005,7 +3956,7 @@ function Toolbar({ extras }) {
4005
3956
  "aria-label": "Add image",
4006
3957
  onClick: () => imageInputRef.current?.click(),
4007
3958
  ...toolbarBtn,
4008
- children: /* @__PURE__ */ jsxRuntime.jsx(ImageIcon, { className: "h-4 w-4" })
3959
+ children: /* @__PURE__ */ jsxRuntime.jsx(ImageIcon, {})
4009
3960
  }
4010
3961
  ) })
4011
3962
  ] }),
@@ -4016,13 +3967,9 @@ function Toolbar({ extras }) {
4016
3967
  type: "button",
4017
3968
  onClick: toggleWeb,
4018
3969
  "aria-pressed": webEnabled,
4019
- className: cn(
4020
- "ms-0.5 inline-flex h-8 items-center gap-1.5 rounded-full px-2.5 text-xs font-medium transition-colors",
4021
- webEnabled ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-accent hover:text-foreground",
4022
- classNames?.toolbarButton
4023
- ),
3970
+ className: cn("composer-web-btn", classNames?.toolbarButton),
4024
3971
  children: [
4025
- /* @__PURE__ */ jsxRuntime.jsx(WebIcon, { className: "h-3.5 w-3.5" }),
3972
+ /* @__PURE__ */ jsxRuntime.jsx(WebIcon, {}),
4026
3973
  "Web"
4027
3974
  ]
4028
3975
  }
@@ -4036,7 +3983,7 @@ function SendButton({ canSend, isStreaming, onSend, onStop }) {
4036
3983
  if (isStreaming) {
4037
3984
  const stop = slotProps(
4038
3985
  "stopButton",
4039
- "inline-flex h-9 w-9 items-center justify-center rounded-full bg-foreground text-background transition-transform hover:scale-105",
3986
+ "composer-send-btn composer-send-btn--stop",
4040
3987
  classNames,
4041
3988
  sx
4042
3989
  );
@@ -4051,17 +3998,9 @@ function SendButton({ canSend, isStreaming, onSend, onStop }) {
4051
3998
  }
4052
3999
  );
4053
4000
  }
4054
- return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onStop, "aria-label": "Stop generating", ...stop, children: /* @__PURE__ */ jsxRuntime.jsx(StopIcon, { className: "h-3.5 w-3.5 fill-current" }) });
4001
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onStop, "aria-label": "Stop generating", ...stop, children: /* @__PURE__ */ jsxRuntime.jsx(StopIcon, {}) });
4055
4002
  }
4056
- const send = slotProps(
4057
- "sendButton",
4058
- [
4059
- "inline-flex h-9 w-9 items-center justify-center rounded-full transition-all",
4060
- canSend ? "bg-foreground text-background shadow-sm hover:scale-105" : "bg-muted text-muted-foreground/60"
4061
- ],
4062
- classNames,
4063
- sx
4064
- );
4003
+ const send = slotProps("sendButton", "composer-send-btn", classNames, sx);
4065
4004
  if (slots.sendButton) {
4066
4005
  const Slot = slots.sendButton;
4067
4006
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -4082,14 +4021,14 @@ function SendButton({ canSend, isStreaming, onSend, onStop }) {
4082
4021
  disabled: !canSend,
4083
4022
  "aria-label": "Send message",
4084
4023
  ...send,
4085
- children: /* @__PURE__ */ jsxRuntime.jsx(SendIcon, { className: "h-4 w-4", strokeWidth: 2.5 })
4024
+ children: /* @__PURE__ */ jsxRuntime.jsx(SendIcon, { strokeWidth: 2.5 })
4086
4025
  }
4087
4026
  );
4088
4027
  }
4089
4028
  function noop() {
4090
4029
  }
4091
4030
  function Key({ children }) {
4092
- return /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "rounded border border-border bg-card px-1 py-0.5 font-mono text-[10px]", children });
4031
+ return /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "composer-kbd", children });
4093
4032
  }
4094
4033
  function formatShortcut(spec) {
4095
4034
  const parts = spec.split("+").map((s) => s.trim().toLowerCase()).filter(Boolean);
@@ -4180,19 +4119,14 @@ function HintBar({ hint }) {
4180
4119
  ] });
4181
4120
  }, [focusShortcut]);
4182
4121
  if (!hint) return null;
4183
- const hintProps = slotProps(
4184
- "hint",
4185
- "text-center text-[11px] text-muted-foreground",
4186
- classNames,
4187
- sx
4188
- );
4122
+ const hintProps = slotProps("hint", "composer-hint", classNames, sx);
4189
4123
  return /* @__PURE__ */ jsxRuntime.jsx("p", { ...hintProps, children: hint === true ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4190
4124
  "AI can make mistakes \u2014 verify important info.",
4191
- defaultShortcuts ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden sm:inline", children: [
4125
+ defaultShortcuts ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "composer-hint-sm", children: [
4192
4126
  " ",
4193
4127
  defaultShortcuts
4194
4128
  ] }) : null,
4195
- focusHint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden md:inline", children: focusHint }) : null
4129
+ focusHint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-hint-md", children: focusHint }) : null
4196
4130
  ] }) : hint });
4197
4131
  }
4198
4132
  var DEFAULT_MAX = 3;
@@ -4223,35 +4157,20 @@ function QuickPrompts({ prompts }) {
4223
4157
  prompts.onSelect?.(prompt);
4224
4158
  runPrompt(prompt, behavior);
4225
4159
  };
4226
- return /* @__PURE__ */ jsxRuntime.jsx(
4227
- "div",
4160
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": "Quick prompts", className: "composer-prompts", children: display.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
4161
+ "button",
4228
4162
  {
4229
- role: "group",
4230
- "aria-label": "Quick prompts",
4231
- className: "flex flex-wrap items-center gap-2 px-1 pb-1",
4232
- children: display.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
4233
- "button",
4234
- {
4235
- type: "button",
4236
- onClick: () => handleClick(p),
4237
- title: p,
4238
- className: cn(
4239
- "group inline-flex max-w-full items-center gap-1.5 rounded-full",
4240
- "border border-border bg-card/60 px-3 py-1.5 text-xs",
4241
- "text-muted-foreground backdrop-blur transition-all",
4242
- "hover:-translate-y-px hover:border-primary/40 hover:bg-card",
4243
- "hover:text-foreground hover:shadow-sm",
4244
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
4245
- ),
4246
- children: [
4247
- /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-3 w-3 shrink-0 text-primary opacity-70 group-hover:opacity-100" }),
4248
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", style: { maxWidth: "32ch" }, children: p })
4249
- ]
4250
- },
4251
- p
4252
- ))
4253
- }
4254
- );
4163
+ type: "button",
4164
+ onClick: () => handleClick(p),
4165
+ title: p,
4166
+ className: "composer-prompt",
4167
+ children: [
4168
+ /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, {}),
4169
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "composer-prompt-text", style: { maxWidth: "32ch" }, children: p })
4170
+ ]
4171
+ },
4172
+ p
4173
+ )) });
4255
4174
  }
4256
4175
  function useComposerHandle(ref, onSubmit) {
4257
4176
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
@@ -4401,7 +4320,7 @@ var Composer = react.forwardRef(function Composer2(props, ref) {
4401
4320
  if (!derived && !tokens) return void 0;
4402
4321
  return tokensToStyle({ ...derived, ...tokens });
4403
4322
  }, [color, tokens]);
4404
- const root = slotProps("root", "space-y-2", classNames, sx);
4323
+ const root = slotProps("root", "composer-root", classNames, sx);
4405
4324
  const rootStyle = react.useMemo(
4406
4325
  () => ({ ...tokenStyle, ...root.style, ...style }),
4407
4326
  [tokenStyle, root.style, style]
@@ -4429,6 +4348,7 @@ var Composer = react.forwardRef(function Composer2(props, ref) {
4429
4348
  "div",
4430
4349
  {
4431
4350
  dir,
4351
+ "data-composer-scope": "",
4432
4352
  className: cn(root.className, className),
4433
4353
  style: Object.keys(rootStyle).length ? rootStyle : void 0,
4434
4354
  children: [
@@ -4485,16 +4405,7 @@ function ComposerCard({
4485
4405
  multiline
4486
4406
  }) {
4487
4407
  const { webEnabled, isDraggingFiles, classNames, sx } = useComposerContext();
4488
- const card = slotProps(
4489
- "card",
4490
- [
4491
- "group relative border border-border bg-card shadow-soft transition-all focus-within:border-primary/40 focus-within:shadow-glow",
4492
- webEnabled && "ring-1 ring-primary/20",
4493
- isDraggingFiles && "ring-2 ring-primary/60"
4494
- ],
4495
- classNames,
4496
- sx
4497
- );
4408
+ const card = slotProps("card", "composer-card", classNames, sx);
4498
4409
  const initialConfig = react.useMemo(
4499
4410
  () => ({
4500
4411
  namespace: "composeai",
@@ -4512,6 +4423,8 @@ function ComposerCard({
4512
4423
  {
4513
4424
  "data-composer-root": "",
4514
4425
  "data-composer-inline": multiline ? void 0 : "",
4426
+ "data-composer-web": webEnabled ? "" : void 0,
4427
+ "data-composer-dragging": isDraggingFiles ? "" : void 0,
4515
4428
  ...card,
4516
4429
  children: [
4517
4430
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4519,7 +4432,7 @@ function ComposerCard({
4519
4432
  {
4520
4433
  "aria-hidden": true,
4521
4434
  "data-composer-overlay": "",
4522
- className: "pointer-events-none absolute inset-0 opacity-0 transition-opacity group-focus-within:opacity-100",
4435
+ className: "composer-overlay-glow",
4523
4436
  style: {
4524
4437
  background: "linear-gradient(135deg, hsl(var(--primary)/0.08) 0%, transparent 40%, hsl(var(--primary)/0.06) 100%)"
4525
4438
  }
@@ -4530,7 +4443,7 @@ function ComposerCard({
4530
4443
  {
4531
4444
  "aria-hidden": true,
4532
4445
  "data-composer-overlay": "",
4533
- className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center bg-primary/5 text-sm font-medium text-primary backdrop-blur-[1px]",
4446
+ className: "composer-overlay-drop",
4534
4447
  children: "Drop to attach"
4535
4448
  }
4536
4449
  ),
@@ -4593,9 +4506,10 @@ function ComposerInner({
4593
4506
  if (isStreaming) return;
4594
4507
  if (uploadsBlocking) return;
4595
4508
  let payload = null;
4509
+ const linkedMention = typeof features.mentions === "object" && !!features.mentions.linkedMention;
4596
4510
  editor.getEditorState().read(() => {
4597
4511
  const { text, mentions } = collectPlainAndMentions(editor);
4598
- const markdown = toMarkdown(editor);
4512
+ const markdown = toMarkdown(editor, { linkedMention });
4599
4513
  const trimmed = text.trim();
4600
4514
  if (!trimmed) {
4601
4515
  if (attachments.length === 0) return;
@@ -4729,14 +4643,14 @@ function MermaidSlot() {
4729
4643
  function SuggestionRow({ items, onSelect, className }) {
4730
4644
  const { icons } = useComposerContext();
4731
4645
  const { sparkle: SparkleIcon } = icons;
4732
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap justify-center gap-2", className), children: items.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
4646
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("composer-suggestions", className), children: items.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
4733
4647
  "button",
4734
4648
  {
4735
4649
  type: "button",
4736
4650
  onClick: () => onSelect(s),
4737
- className: "group inline-flex items-center gap-1.5 rounded-full border border-border bg-card/60 px-3.5 py-1.5 text-xs text-muted-foreground backdrop-blur transition-all hover:-translate-y-px hover:border-primary/40 hover:bg-card hover:text-foreground hover:shadow-sm",
4651
+ className: "composer-suggestion",
4738
4652
  children: [
4739
- /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-3 w-3 text-primary opacity-70 group-hover:opacity-100" }),
4653
+ /* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, {}),
4740
4654
  s
4741
4655
  ]
4742
4656
  },