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