@handled-ai/design-system 0.20.16 → 0.20.17

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.
@@ -20,12 +20,10 @@ interface CommentComposerProps {
20
20
  avatarUrl?: string | null;
21
21
  };
22
22
  placeholder?: string;
23
- /** Compact spacing for the case-panel timeline surface. Defaults preserve the standard composer sizing. */
24
- density?: "default" | "case-panel";
25
23
  /** Hint shown in the footer; defaults to the internal-note reassurance. */
26
24
  hint?: string;
27
25
  className?: string;
28
26
  }
29
- declare function CommentComposer({ onPost, author, placeholder, density, hint, className, }: CommentComposerProps): React.JSX.Element;
27
+ declare function CommentComposer({ onPost, author, placeholder, hint, className, }: CommentComposerProps): React.JSX.Element;
30
28
 
31
29
  export { CommentComposer, type CommentComposerProps };
@@ -13,7 +13,6 @@ function CommentComposer({
13
13
  onPost,
14
14
  author,
15
15
  placeholder = "Add a comment or internal note\u2026",
16
- density = "default",
17
16
  hint = "Internal note: only your team sees this",
18
17
  className
19
18
  }) {
@@ -22,8 +21,6 @@ function CommentComposer({
22
21
  const [focused, setFocused] = React.useState(false);
23
22
  const open = focused || text.length > 0;
24
23
  const canPost = text.trim().length > 0;
25
- const hasDraft = text.length > 0;
26
- const compact = density === "case-panel";
27
24
  const post = () => {
28
25
  const value = text.trim();
29
26
  if (!value) return;
@@ -62,11 +59,10 @@ function CommentComposer({
62
59
  onChange: (e) => setText(e.target.value),
63
60
  onFocus: () => setFocused(true),
64
61
  placeholder,
65
- rows: compact ? hasDraft ? 3 : 1 : open ? 4 : 1,
62
+ rows: open ? 4 : 1,
66
63
  className: cn(
67
- "resize-none rounded-none border-0 bg-transparent px-5 text-[15px] leading-6 shadow-none outline-none placeholder:text-muted-foreground/60 focus-visible:ring-0 focus-visible:ring-offset-0",
68
- compact ? open ? "py-4" : "py-3" : "py-4",
69
- compact ? hasDraft ? "!min-h-28" : open ? "!min-h-[76px]" : "!min-h-12" : open ? "min-h-32" : "min-h-14"
64
+ "resize-none rounded-none border-0 bg-transparent px-5 py-4 text-[15px] leading-6 shadow-none outline-none placeholder:text-muted-foreground/60 focus-visible:ring-0 focus-visible:ring-offset-0",
65
+ open ? "min-h-32" : "min-h-14"
70
66
  ),
71
67
  onKeyDown: (e) => {
72
68
  if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
@@ -76,7 +72,7 @@ function CommentComposer({
76
72
  }
77
73
  }
78
74
  ),
79
- open ? /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-3 border-t border-border bg-muted/10 px-5", compact ? "py-3.5" : "py-4"), children: [
75
+ open ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-border bg-muted/10 px-5 py-4", children: [
80
76
  /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2 text-sm text-muted-foreground", children: [
81
77
  /* @__PURE__ */ jsx(Lock, { size: 16, strokeWidth: 1.75 }),
82
78
  " ",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/comment-composer.tsx"],"sourcesContent":["\"use client\"\n\n/**\n * comment-composer.tsx — an internal-note composer for the case activity\n * timeline. Posting a comment prepends an `operatorNote` event to the log\n * (wired by the consumer). Collapses to a single line; expands on focus or\n * when it has text. ⌘↵ / Ctrl↵ posts.\n *\n * Presentational: `onPost` does the work (the consumer persists the note and\n * adds it to the timeline). Reuses Avatar / Button / Textarea primitives.\n */\n\nimport * as React from \"react\"\nimport { Lock } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport { getInitials } from \"../lib/user-display\"\nimport { Avatar, AvatarFallback, AvatarImage } from \"./avatar\"\nimport { Button } from \"./button\"\nimport { Textarea } from \"./textarea\"\n\nexport interface CommentComposerProps {\n /** Called with the trimmed note text when the operator posts. */\n onPost: (text: string) => void\n /** Current operator (for the avatar). */\n author?: { name?: string; email?: string; avatarUrl?: string | null }\n placeholder?: string\n /** Compact spacing for the case-panel timeline surface. Defaults preserve the standard composer sizing. */\n density?: \"default\" | \"case-panel\"\n /** Hint shown in the footer; defaults to the internal-note reassurance. */\n hint?: string\n className?: string\n}\n\nfunction CommentComposer({\n onPost,\n author,\n placeholder = \"Add a comment or internal note…\",\n density = \"default\",\n hint = \"Internal note: only your team sees this\",\n className,\n}: CommentComposerProps) {\n const [text, setText] = React.useState(\"\")\n const [focused, setFocused] = React.useState(false)\n const open = focused || text.length > 0\n const canPost = text.trim().length > 0\n const hasDraft = text.length > 0\n const compact = density === \"case-panel\"\n\n const post = () => {\n const value = text.trim()\n if (!value) return\n onPost(value)\n setText(\"\")\n setFocused(false)\n }\n\n return (\n <div\n data-slot=\"comment-composer\"\n data-open={open ? \"true\" : undefined}\n className={cn(\n \"flex items-start gap-4 rounded-xl transition-colors\",\n className\n )}\n >\n <Avatar size=\"sm\" className=\"mt-1\">\n {author?.avatarUrl ? <AvatarImage src={author.avatarUrl} alt={author.name ?? \"You\"} /> : null}\n <AvatarFallback className=\"bg-slate-700 text-[10px] font-semibold uppercase text-white dark:bg-slate-200 dark:text-slate-900\">\n {getInitials({ name: author?.name, email: author?.email })}\n </AvatarFallback>\n </Avatar>\n\n <div\n data-slot=\"comment-composer-shell\"\n className={cn(\n \"min-w-0 flex-1 rounded-xl border border-border bg-background transition-[box-shadow,border-color]\",\n open ? \"overflow-hidden shadow-sm\" : \"shadow-none\"\n )}\n >\n <Textarea\n data-slot=\"comment-composer-input\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n onFocus={() => setFocused(true)}\n placeholder={placeholder}\n rows={compact ? (hasDraft ? 3 : 1) : (open ? 4 : 1)}\n className={cn(\n \"resize-none rounded-none border-0 bg-transparent px-5 text-[15px] leading-6 shadow-none outline-none placeholder:text-muted-foreground/60 focus-visible:ring-0 focus-visible:ring-offset-0\",\n compact ? (open ? \"py-4\" : \"py-3\") : \"py-4\",\n compact\n ? hasDraft\n ? \"!min-h-28\"\n : open\n ? \"!min-h-[76px]\"\n : \"!min-h-12\"\n : open\n ? \"min-h-32\"\n : \"min-h-14\"\n )}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault()\n post()\n }\n }}\n />\n\n {open ? (\n <div className={cn(\"flex items-center justify-between gap-3 border-t border-border bg-muted/10 px-5\", compact ? \"py-3.5\" : \"py-4\")}>\n <span className=\"inline-flex items-center gap-2 text-sm text-muted-foreground\">\n <Lock size={16} strokeWidth={1.75} /> {hint}\n </span>\n <span className=\"flex items-center gap-3\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"px-2 text-sm font-medium text-muted-foreground hover:bg-transparent hover:text-foreground\"\n onClick={() => {\n setText(\"\")\n setFocused(false)\n }}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={!canPost}\n onClick={post}\n className=\"rounded-lg bg-foreground px-4 text-sm font-semibold text-background shadow-none hover:bg-foreground/90\"\n >\n Comment\n <kbd className=\"ml-1 rounded px-1 text-[10px] text-background/70\">⌘↵</kbd>\n </Button>\n </span>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nexport { CommentComposer }\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/comment-composer.tsx"],"sourcesContent":["\"use client\"\n\n/**\n * comment-composer.tsx — an internal-note composer for the case activity\n * timeline. Posting a comment prepends an `operatorNote` event to the log\n * (wired by the consumer). Collapses to a single line; expands on focus or\n * when it has text. ⌘↵ / Ctrl↵ posts.\n *\n * Presentational: `onPost` does the work (the consumer persists the note and\n * adds it to the timeline). Reuses Avatar / Button / Textarea primitives.\n */\n\nimport * as React from \"react\"\nimport { Lock } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport { getInitials } from \"../lib/user-display\"\nimport { Avatar, AvatarFallback, AvatarImage } from \"./avatar\"\nimport { Button } from \"./button\"\nimport { Textarea } from \"./textarea\"\n\nexport interface CommentComposerProps {\n /** Called with the trimmed note text when the operator posts. */\n onPost: (text: string) => void\n /** Current operator (for the avatar). */\n author?: { name?: string; email?: string; avatarUrl?: string | null }\n placeholder?: string\n /** Hint shown in the footer; defaults to the internal-note reassurance. */\n hint?: string\n className?: string\n}\n\nfunction CommentComposer({\n onPost,\n author,\n placeholder = \"Add a comment or internal note…\",\n hint = \"Internal note: only your team sees this\",\n className,\n}: CommentComposerProps) {\n const [text, setText] = React.useState(\"\")\n const [focused, setFocused] = React.useState(false)\n const open = focused || text.length > 0\n const canPost = text.trim().length > 0\n\n const post = () => {\n const value = text.trim()\n if (!value) return\n onPost(value)\n setText(\"\")\n setFocused(false)\n }\n\n return (\n <div\n data-slot=\"comment-composer\"\n data-open={open ? \"true\" : undefined}\n className={cn(\n \"flex items-start gap-4 rounded-xl transition-colors\",\n className\n )}\n >\n <Avatar size=\"sm\" className=\"mt-1\">\n {author?.avatarUrl ? <AvatarImage src={author.avatarUrl} alt={author.name ?? \"You\"} /> : null}\n <AvatarFallback className=\"bg-slate-700 text-[10px] font-semibold uppercase text-white dark:bg-slate-200 dark:text-slate-900\">\n {getInitials({ name: author?.name, email: author?.email })}\n </AvatarFallback>\n </Avatar>\n\n <div\n data-slot=\"comment-composer-shell\"\n className={cn(\n \"min-w-0 flex-1 rounded-xl border border-border bg-background transition-[box-shadow,border-color]\",\n open ? \"overflow-hidden shadow-sm\" : \"shadow-none\"\n )}\n >\n <Textarea\n data-slot=\"comment-composer-input\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n onFocus={() => setFocused(true)}\n placeholder={placeholder}\n rows={open ? 4 : 1}\n className={cn(\n \"resize-none rounded-none border-0 bg-transparent px-5 py-4 text-[15px] leading-6 shadow-none outline-none placeholder:text-muted-foreground/60 focus-visible:ring-0 focus-visible:ring-offset-0\",\n open ? \"min-h-32\" : \"min-h-14\"\n )}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault()\n post()\n }\n }}\n />\n\n {open ? (\n <div className=\"flex items-center justify-between gap-3 border-t border-border bg-muted/10 px-5 py-4\">\n <span className=\"inline-flex items-center gap-2 text-sm text-muted-foreground\">\n <Lock size={16} strokeWidth={1.75} /> {hint}\n </span>\n <span className=\"flex items-center gap-3\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"px-2 text-sm font-medium text-muted-foreground hover:bg-transparent hover:text-foreground\"\n onClick={() => {\n setText(\"\")\n setFocused(false)\n }}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={!canPost}\n onClick={post}\n className=\"rounded-lg bg-foreground px-4 text-sm font-semibold text-background shadow-none hover:bg-foreground/90\"\n >\n Comment\n <kbd className=\"ml-1 rounded px-1 text-[10px] text-background/70\">⌘↵</kbd>\n </Button>\n </span>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nexport { CommentComposer }\n"],"mappings":";AA6DM,SACuB,KADvB;AAjDN,YAAY,WAAW;AACvB,SAAS,YAAY;AAErB,SAAS,UAAU;AACnB,SAAS,mBAAmB;AAC5B,SAAS,QAAQ,gBAAgB,mBAAmB;AACpD,SAAS,cAAc;AACvB,SAAS,gBAAgB;AAazB,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,OAAO;AAAA,EACP;AACF,GAAyB;AAtCzB;AAuCE,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,EAAE;AACzC,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAClD,QAAM,OAAO,WAAW,KAAK,SAAS;AACtC,QAAM,UAAU,KAAK,KAAK,EAAE,SAAS;AAErC,QAAM,OAAO,MAAM;AACjB,UAAM,QAAQ,KAAK,KAAK;AACxB,QAAI,CAAC,MAAO;AACZ,WAAO,KAAK;AACZ,YAAQ,EAAE;AACV,eAAW,KAAK;AAAA,EAClB;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,aAAW,OAAO,SAAS;AAAA,MAC3B,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,6BAAC,UAAO,MAAK,MAAK,WAAU,QACzB;AAAA,4CAAQ,aAAY,oBAAC,eAAY,KAAK,OAAO,WAAW,MAAK,YAAO,SAAP,YAAe,OAAO,IAAK;AAAA,UACzF,oBAAC,kBAAe,WAAU,qGACvB,sBAAY,EAAE,MAAM,iCAAQ,MAAM,OAAO,iCAAQ,MAAM,CAAC,GAC3D;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,WAAW;AAAA,cACT;AAAA,cACA,OAAO,8BAA8B;AAAA,YACvC;AAAA,YAEA;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,aAAU;AAAA,kBACV,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,kBACvC,SAAS,MAAM,WAAW,IAAI;AAAA,kBAC9B;AAAA,kBACA,MAAM,OAAO,IAAI;AAAA,kBACjB,WAAW;AAAA,oBACT;AAAA,oBACA,OAAO,aAAa;AAAA,kBACtB;AAAA,kBACA,WAAW,CAAC,MAAM;AAChB,yBAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,SAAS;AACjD,wBAAE,eAAe;AACjB,2BAAK;AAAA,oBACP;AAAA,kBACF;AAAA;AAAA,cACF;AAAA,cAEC,OACC,qBAAC,SAAI,WAAU,wFACb;AAAA,qCAAC,UAAK,WAAU,gEACd;AAAA,sCAAC,QAAK,MAAM,IAAI,aAAa,MAAM;AAAA,kBAAE;AAAA,kBAAE;AAAA,mBACzC;AAAA,gBACA,qBAAC,UAAK,WAAU,2BACd;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBACV,SAAS,MAAM;AACb,gCAAQ,EAAE;AACV,mCAAW,KAAK;AAAA,sBAClB;AAAA,sBACD;AAAA;AAAA,kBAED;AAAA,kBACA;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,MAAK;AAAA,sBACL,UAAU,CAAC;AAAA,sBACX,SAAS;AAAA,sBACT,WAAU;AAAA,sBACX;AAAA;AAAA,wBAEC,oBAAC,SAAI,WAAU,oDAAmD,0BAAE;AAAA;AAAA;AAAA,kBACtE;AAAA,mBACF;AAAA,iBACF,IACE;AAAA;AAAA;AAAA,QACN;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -1,9 +1,16 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  type RichTextAction = "undo" | "redo" | "font" | "bold" | "italic" | "underline" | "align" | "list" | "delete";
4
+ interface RichTextFontOption {
5
+ label: string;
6
+ value: string;
7
+ }
4
8
  interface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
5
9
  onAction?: (action: RichTextAction) => void;
10
+ fontOptions?: RichTextFontOption[];
11
+ selectedFontFamily?: string;
12
+ onFontFamilyChange?: (fontFamily: string) => void;
6
13
  }
7
- declare function RichTextToolbar({ onAction, className, ...rest }: RichTextToolbarProps): React.JSX.Element;
14
+ declare function RichTextToolbar({ onAction, className, fontOptions, selectedFontFamily, onFontFamilyChange, ...rest }: RichTextToolbarProps): React.JSX.Element;
8
15
 
9
- export { type RichTextAction, RichTextToolbar, type RichTextToolbarProps };
16
+ export { type RichTextAction, type RichTextFontOption, RichTextToolbar, type RichTextToolbarProps };
@@ -33,6 +33,7 @@ var __objRest = (source, exclude) => {
33
33
  return target;
34
34
  };
35
35
  import { jsx, jsxs } from "react/jsx-runtime";
36
+ import * as React from "react";
36
37
  import { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from "lucide-react";
37
38
  import { cn } from "../lib/utils.js";
38
39
  function ToolbarButton({
@@ -55,7 +56,35 @@ function ToolbarButton({
55
56
  );
56
57
  }
57
58
  function RichTextToolbar(_a) {
58
- var _b = _a, { onAction, className } = _b, rest = __objRest(_b, ["onAction", "className"]);
59
+ var _b = _a, {
60
+ onAction,
61
+ className,
62
+ fontOptions,
63
+ selectedFontFamily,
64
+ onFontFamilyChange
65
+ } = _b, rest = __objRest(_b, [
66
+ "onAction",
67
+ "className",
68
+ "fontOptions",
69
+ "selectedFontFamily",
70
+ "onFontFamilyChange"
71
+ ]);
72
+ var _a2, _b2;
73
+ const [fontMenuOpen, setFontMenuOpen] = React.useState(false);
74
+ const fontMenuRef = React.useRef(null);
75
+ const selectedFontOption = (_a2 = fontOptions == null ? void 0 : fontOptions.find((option) => option.value === selectedFontFamily)) != null ? _a2 : fontOptions == null ? void 0 : fontOptions[0];
76
+ const fontLabel = (_b2 = selectedFontOption == null ? void 0 : selectedFontOption.label) != null ? _b2 : "Sans Serif";
77
+ const hasFontMenu = Boolean((fontOptions == null ? void 0 : fontOptions.length) && onFontFamilyChange);
78
+ React.useEffect(() => {
79
+ if (!fontMenuOpen) return;
80
+ function handleDocumentMouseDown(event) {
81
+ var _a3;
82
+ if ((_a3 = fontMenuRef.current) == null ? void 0 : _a3.contains(event.target)) return;
83
+ setFontMenuOpen(false);
84
+ }
85
+ document.addEventListener("mousedown", handleDocumentMouseDown);
86
+ return () => document.removeEventListener("mousedown", handleDocumentMouseDown);
87
+ }, [fontMenuOpen]);
59
88
  return /* @__PURE__ */ jsxs(
60
89
  "div",
61
90
  __spreadProps(__spreadValues({
@@ -69,21 +98,51 @@ function RichTextToolbar(_a) {
69
98
  /* @__PURE__ */ jsx(ToolbarButton, { action: "undo", icon: Undo2, label: "Undo", onAction }),
70
99
  /* @__PURE__ */ jsx(ToolbarButton, { action: "redo", icon: Redo2, label: "Redo", onAction }),
71
100
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-border mx-1", "aria-hidden": "true" }),
72
- /* @__PURE__ */ jsxs(
73
- "button",
74
- {
75
- type: "button",
76
- "data-slot": "rich-text-toolbar-button",
77
- onClick: () => onAction == null ? void 0 : onAction("font"),
78
- "aria-label": "Font family",
79
- "aria-haspopup": "true",
80
- className: "text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1",
81
- children: [
82
- "Sans Serif",
83
- /* @__PURE__ */ jsx(ChevronDown, { size: 10 })
84
- ]
85
- }
86
- ),
101
+ /* @__PURE__ */ jsxs("div", { className: "relative", ref: fontMenuRef, children: [
102
+ /* @__PURE__ */ jsxs(
103
+ "button",
104
+ {
105
+ type: "button",
106
+ "data-slot": "rich-text-toolbar-button",
107
+ onClick: () => {
108
+ onAction == null ? void 0 : onAction("font");
109
+ if (hasFontMenu) setFontMenuOpen((open) => !open);
110
+ },
111
+ "aria-label": "Font family",
112
+ "aria-haspopup": "menu",
113
+ "aria-expanded": hasFontMenu ? fontMenuOpen : void 0,
114
+ className: "text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1",
115
+ children: [
116
+ fontLabel,
117
+ /* @__PURE__ */ jsx(ChevronDown, { size: 10 })
118
+ ]
119
+ }
120
+ ),
121
+ hasFontMenu && fontMenuOpen ? /* @__PURE__ */ jsx(
122
+ "div",
123
+ {
124
+ role: "menu",
125
+ "aria-label": "Font family",
126
+ className: "absolute left-0 bottom-full z-50 mb-1 min-w-32 overflow-hidden rounded-md border border-border bg-background py-1 shadow-md",
127
+ children: fontOptions.map((option) => /* @__PURE__ */ jsx(
128
+ "button",
129
+ {
130
+ type: "button",
131
+ role: "menuitemradio",
132
+ "aria-checked": option.value === selectedFontFamily,
133
+ className: "block w-full px-2.5 py-1.5 text-left text-xs text-foreground hover:bg-muted/60",
134
+ style: { fontFamily: option.value },
135
+ onClick: () => {
136
+ onFontFamilyChange == null ? void 0 : onFontFamilyChange(option.value);
137
+ setFontMenuOpen(false);
138
+ },
139
+ children: option.label
140
+ },
141
+ option.value
142
+ ))
143
+ }
144
+ ) : null
145
+ ] }),
87
146
  /* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-border mx-1", "aria-hidden": "true" }),
88
147
  /* @__PURE__ */ jsx(ToolbarButton, { action: "bold", icon: Bold, label: "Bold", onAction }),
89
148
  /* @__PURE__ */ jsx(ToolbarButton, { action: "italic", icon: Italic, label: "Italic", onAction }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/rich-text-toolbar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\n\ntype RichTextAction =\n | \"undo\" | \"redo\"\n | \"font\"\n | \"bold\" | \"italic\" | \"underline\"\n | \"align\" | \"list\"\n | \"delete\"\n\ninterface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n onAction?: (action: RichTextAction) => void\n}\n\nfunction ToolbarButton({\n action,\n icon: Icon,\n label,\n extraClassName,\n onAction,\n}: {\n action: RichTextAction\n icon: LucideIcon\n label: string\n extraClassName?: string\n onAction?: (action: RichTextAction) => void\n}) {\n return (\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(action)}\n aria-label={label}\n className={cn(\"p-1.5 rounded hover:bg-muted/50 cursor-pointer text-muted-foreground\", extraClassName)}\n >\n <Icon size={14} />\n </button>\n )\n}\n\nfunction RichTextToolbar({ onAction, className, ...rest }: RichTextToolbarProps) {\n return (\n <div\n data-slot=\"rich-text-toolbar\"\n role=\"toolbar\"\n aria-label=\"Rich text formatting\"\n className={cn(\"px-3 py-1.5 flex items-center justify-between\", className)}\n {...rest}\n >\n <div className=\"flex items-center gap-0.5\">\n <ToolbarButton action=\"undo\" icon={Undo2} label=\"Undo\" onAction={onAction} />\n <ToolbarButton action=\"redo\" icon={Redo2} label=\"Redo\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(\"font\")}\n aria-label=\"Font family\"\n aria-haspopup=\"true\"\n className=\"text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1\"\n >\n Sans Serif\n <ChevronDown size={10} />\n </button>\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"bold\" icon={Bold} label=\"Bold\" onAction={onAction} />\n <ToolbarButton action=\"italic\" icon={Italic} label=\"Italic\" onAction={onAction} />\n <ToolbarButton action=\"underline\" icon={Underline} label=\"Underline\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"align\" icon={AlignLeft} label=\"Align left\" onAction={onAction} />\n <ToolbarButton action=\"list\" icon={List} label=\"List\" onAction={onAction} />\n </div>\n\n <ToolbarButton action=\"delete\" icon={Trash2} label=\"Delete\" extraClassName=\"hover:text-destructive\" onAction={onAction} />\n </div>\n )\n}\n\nexport { RichTextToolbar, type RichTextToolbarProps, type RichTextAction }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCM,cAoBE,YApBF;AApCN,SAAS,OAAO,OAAO,MAAM,QAAQ,WAAW,WAAW,MAAM,QAAQ,mBAAmB;AAE5F,SAAS,UAAU;AAanB,SAAS,cAAc;AAAA,EACrB;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,SAAS,MAAM,qCAAW;AAAA,MAC1B,cAAY;AAAA,MACZ,WAAW,GAAG,wEAAwE,cAAc;AAAA,MAEpG,8BAAC,QAAK,MAAM,IAAI;AAAA;AAAA,EAClB;AAEJ;AAEA,SAAS,gBAAgB,IAAwD;AAAxD,eAAE,YAAU,UA7CrC,IA6CyB,IAA0B,iBAA1B,IAA0B,CAAxB,YAAU;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAW,GAAG,iDAAiD,SAAS;AAAA,OACpE,OALL;AAAA,MAOC;AAAA,6BAAC,SAAI,WAAU,6BACb;AAAA,8BAAC,iBAAc,QAAO,QAAO,MAAM,OAAO,OAAM,QAAO,UAAoB;AAAA,UAC3E,oBAAC,iBAAc,QAAO,QAAO,MAAM,OAAO,OAAM,QAAO,UAAoB;AAAA,UAE3E,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE5D;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAU;AAAA,cACV,SAAS,MAAM,qCAAW;AAAA,cAC1B,cAAW;AAAA,cACX,iBAAc;AAAA,cACd,WAAU;AAAA,cACX;AAAA;AAAA,gBAEC,oBAAC,eAAY,MAAM,IAAI;AAAA;AAAA;AAAA,UACzB;AAAA,UAEA,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE5D,oBAAC,iBAAc,QAAO,QAAO,MAAM,MAAM,OAAM,QAAO,UAAoB;AAAA,UAC1E,oBAAC,iBAAc,QAAO,UAAS,MAAM,QAAQ,OAAM,UAAS,UAAoB;AAAA,UAChF,oBAAC,iBAAc,QAAO,aAAY,MAAM,WAAW,OAAM,aAAY,UAAoB;AAAA,UAEzF,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE5D,oBAAC,iBAAc,QAAO,SAAQ,MAAM,WAAW,OAAM,cAAa,UAAoB;AAAA,UACtF,oBAAC,iBAAc,QAAO,QAAO,MAAM,MAAM,OAAM,QAAO,UAAoB;AAAA,WAC5E;AAAA,QAEA,oBAAC,iBAAc,QAAO,UAAS,MAAM,QAAQ,OAAM,UAAS,gBAAe,0BAAyB,UAAoB;AAAA;AAAA;AAAA,EAC1H;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components/rich-text-toolbar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\n\ntype RichTextAction =\n | \"undo\" | \"redo\"\n | \"font\"\n | \"bold\" | \"italic\" | \"underline\"\n | \"align\" | \"list\"\n | \"delete\"\n\ninterface RichTextFontOption {\n label: string\n value: string\n}\n\ninterface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n onAction?: (action: RichTextAction) => void\n fontOptions?: RichTextFontOption[]\n selectedFontFamily?: string\n onFontFamilyChange?: (fontFamily: string) => void\n}\n\nfunction ToolbarButton({\n action,\n icon: Icon,\n label,\n extraClassName,\n onAction,\n}: {\n action: RichTextAction\n icon: LucideIcon\n label: string\n extraClassName?: string\n onAction?: (action: RichTextAction) => void\n}) {\n return (\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(action)}\n aria-label={label}\n className={cn(\"p-1.5 rounded hover:bg-muted/50 cursor-pointer text-muted-foreground\", extraClassName)}\n >\n <Icon size={14} />\n </button>\n )\n}\n\nfunction RichTextToolbar({\n onAction,\n className,\n fontOptions,\n selectedFontFamily,\n onFontFamilyChange,\n ...rest\n}: RichTextToolbarProps) {\n const [fontMenuOpen, setFontMenuOpen] = React.useState(false)\n const fontMenuRef = React.useRef<HTMLDivElement | null>(null)\n const selectedFontOption = fontOptions?.find((option) => option.value === selectedFontFamily) ?? fontOptions?.[0]\n const fontLabel = selectedFontOption?.label ?? \"Sans Serif\"\n const hasFontMenu = Boolean(fontOptions?.length && onFontFamilyChange)\n\n React.useEffect(() => {\n if (!fontMenuOpen) return\n\n function handleDocumentMouseDown(event: MouseEvent) {\n if (fontMenuRef.current?.contains(event.target as Node)) return\n setFontMenuOpen(false)\n }\n\n document.addEventListener(\"mousedown\", handleDocumentMouseDown)\n return () => document.removeEventListener(\"mousedown\", handleDocumentMouseDown)\n }, [fontMenuOpen])\n\n return (\n <div\n data-slot=\"rich-text-toolbar\"\n role=\"toolbar\"\n aria-label=\"Rich text formatting\"\n className={cn(\"px-3 py-1.5 flex items-center justify-between\", className)}\n {...rest}\n >\n <div className=\"flex items-center gap-0.5\">\n <ToolbarButton action=\"undo\" icon={Undo2} label=\"Undo\" onAction={onAction} />\n <ToolbarButton action=\"redo\" icon={Redo2} label=\"Redo\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <div className=\"relative\" ref={fontMenuRef}>\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => {\n onAction?.(\"font\")\n if (hasFontMenu) setFontMenuOpen((open) => !open)\n }}\n aria-label=\"Font family\"\n aria-haspopup=\"menu\"\n aria-expanded={hasFontMenu ? fontMenuOpen : undefined}\n className=\"text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1\"\n >\n {fontLabel}\n <ChevronDown size={10} />\n </button>\n\n {hasFontMenu && fontMenuOpen ? (\n <div\n role=\"menu\"\n aria-label=\"Font family\"\n className=\"absolute left-0 bottom-full z-50 mb-1 min-w-32 overflow-hidden rounded-md border border-border bg-background py-1 shadow-md\"\n >\n {fontOptions!.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={option.value === selectedFontFamily}\n className=\"block w-full px-2.5 py-1.5 text-left text-xs text-foreground hover:bg-muted/60\"\n style={{ fontFamily: option.value }}\n onClick={() => {\n onFontFamilyChange?.(option.value)\n setFontMenuOpen(false)\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"bold\" icon={Bold} label=\"Bold\" onAction={onAction} />\n <ToolbarButton action=\"italic\" icon={Italic} label=\"Italic\" onAction={onAction} />\n <ToolbarButton action=\"underline\" icon={Underline} label=\"Underline\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"align\" icon={AlignLeft} label=\"Align left\" onAction={onAction} />\n <ToolbarButton action=\"list\" icon={List} label=\"List\" onAction={onAction} />\n </div>\n\n <ToolbarButton action=\"delete\" icon={Trash2} label=\"Delete\" extraClassName=\"hover:text-destructive\" onAction={onAction} />\n </div>\n )\n}\n\nexport { RichTextToolbar, type RichTextToolbarProps, type RichTextAction, type RichTextFontOption }\n"],"mappings":"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","names":["_a","_b"]}
package/dist/index.d.ts CHANGED
@@ -70,7 +70,7 @@ export { QuickActionModal, QuickActionPriority, QuickActionTaskDraft, QuickActio
70
70
  export { ActiveVariant, QuickActionSidebarNav, SidebarNavItem, SidebarNavSection, SidebarUserProfile, UserMenuItem } from './components/quick-action-sidebar-nav.js';
71
71
  export { RecommendedAction, RecommendedActionsSection } from './components/recommended-actions-section.js';
72
72
  export { ReportCard, ReportCardProps } from './components/report-card.js';
73
- export { RichTextAction, RichTextToolbar, RichTextToolbarProps } from './components/rich-text-toolbar.js';
73
+ export { RichTextAction, RichTextFontOption, RichTextToolbar, RichTextToolbarProps } from './components/rich-text-toolbar.js';
74
74
  export { ScoreAnalysisModal, ScoreAnalysisModalProps, ScoreAnalysisPanel, getScoreLabel } from './components/score-analysis-modal.js';
75
75
  export { ScoreBreakdown, ScoreBreakdownProps, ScoreFactor } from './components/score-breakdown.js';
76
76
  export { ScoreFeedback, useScoreFeedback } from './components/score-feedback.js';
@@ -172,9 +172,8 @@ function TimelineSection({
172
172
  type: "button",
173
173
  onClick: () => setShowSystemEvents((prev) => !prev),
174
174
  className: cn(
175
- "inline-flex shrink-0 cursor-pointer items-center rounded-full border transition-colors",
176
- isCasePanel ? "gap-2 px-2.5 py-1 text-xs font-medium" : "gap-3 px-3.5 py-2 text-sm font-semibold",
177
- showSystemEvents ? isCasePanel ? "border-border bg-muted text-foreground shadow-sm hover:bg-muted/80" : "border-foreground bg-foreground text-background shadow-sm hover:bg-foreground/90" : "border-border bg-background text-muted-foreground shadow-sm hover:bg-muted/40 hover:text-foreground"
175
+ "inline-flex shrink-0 cursor-pointer items-center gap-3 rounded-full border px-3.5 py-2 text-sm font-semibold transition-colors",
176
+ showSystemEvents ? "border-foreground bg-foreground text-background shadow-sm hover:bg-foreground/90" : "border-border bg-background text-muted-foreground shadow-sm hover:bg-muted/40 hover:text-foreground"
178
177
  ),
179
178
  "aria-pressed": showSystemEvents,
180
179
  "aria-label": toggleHelp,
@@ -185,9 +184,8 @@ function TimelineSection({
185
184
  "span",
186
185
  {
187
186
  className: cn(
188
- "relative inline-flex shrink-0 items-center rounded-full p-0.5 transition-colors",
189
- isCasePanel ? "h-3.5 w-7" : "h-4 w-8",
190
- showSystemEvents ? "bg-teal-600" : "bg-muted-foreground/25"
187
+ "relative inline-flex h-4 w-8 shrink-0 items-center rounded-full p-0.5 transition-colors",
188
+ showSystemEvents ? "bg-teal-600" : "bg-muted-foreground/30"
191
189
  ),
192
190
  "aria-hidden": "true",
193
191
  "data-testid": "system-events-indicator",
@@ -195,9 +193,8 @@ function TimelineSection({
195
193
  "span",
196
194
  {
197
195
  className: cn(
198
- "block rounded-full bg-white shadow-sm transition-transform",
199
- isCasePanel ? "h-2.5 w-2.5" : "h-3 w-3",
200
- showSystemEvents ? isCasePanel ? "translate-x-3.5" : "translate-x-4" : "translate-x-0"
196
+ "block h-3 w-3 rounded-full bg-white shadow-sm transition-transform",
197
+ showSystemEvents ? "translate-x-4" : "translate-x-0"
201
198
  )
202
199
  }
203
200
  )
@@ -207,7 +204,7 @@ function TimelineSection({
207
204
  !showSystemEvents ? /* @__PURE__ */ jsx(
208
205
  "span",
209
206
  {
210
- className: cn("inline-flex items-center justify-center rounded-full bg-muted px-1.5 font-bold tabular-nums text-muted-foreground", isCasePanel ? "min-w-5 text-[11px]" : "min-w-[22px] text-xs"),
207
+ className: "inline-flex min-w-[22px] items-center justify-center rounded-full bg-muted px-1.5 text-xs font-bold tabular-nums text-muted-foreground",
211
208
  "data-testid": "hidden-count-badge",
212
209
  children: hiddenCount
213
210
  }
@@ -307,7 +304,6 @@ function DetailView({
307
304
  timelineSystemEventsHiddenHint,
308
305
  timelineSystemEventsVisibleHint
309
306
  ]);
310
- const isCasePanelV2 = sectionLayout === "case-panel-v2";
311
307
  const [showTimeline, setShowTimeline] = React.useState(false);
312
308
  const [extraActions, setExtraActions] = React.useState([]);
313
309
  const sysEvtDefaultVisible = (_a = sysEvtConfig == null ? void 0 : sysEvtConfig.defaultVisible) != null ? _a : false;
@@ -315,13 +311,7 @@ function DetailView({
315
311
  const [showSystemEvents, setShowSystemEvents] = React.useState(sysEvtDefaultVisible);
316
312
  const initialReadDoneRef = React.useRef(false);
317
313
  React.useEffect(() => {
318
- if (isCasePanelV2) {
319
- setShowSystemEvents(sysEvtDefaultVisible);
320
- initialReadDoneRef.current = true;
321
- return;
322
- }
323
314
  if (!sysEvtStorageKey) {
324
- setShowSystemEvents(sysEvtDefaultVisible);
325
315
  initialReadDoneRef.current = true;
326
316
  return;
327
317
  }
@@ -329,22 +319,19 @@ function DetailView({
329
319
  const stored = localStorage.getItem(sysEvtStorageKey);
330
320
  if (stored !== null) {
331
321
  setShowSystemEvents(stored === "true");
332
- } else {
333
- setShowSystemEvents(sysEvtDefaultVisible);
334
322
  }
335
323
  } catch (e) {
336
- setShowSystemEvents(sysEvtDefaultVisible);
337
324
  }
338
325
  initialReadDoneRef.current = true;
339
- }, [isCasePanelV2, item.id, sysEvtDefaultVisible, sysEvtStorageKey]);
326
+ }, [sysEvtStorageKey]);
340
327
  React.useEffect(() => {
341
- if (!sysEvtStorageKey || isCasePanelV2) return;
328
+ if (!sysEvtStorageKey) return;
342
329
  if (!initialReadDoneRef.current) return;
343
330
  try {
344
331
  localStorage.setItem(sysEvtStorageKey, String(showSystemEvents));
345
332
  } catch (e) {
346
333
  }
347
- }, [isCasePanelV2, showSystemEvents, sysEvtStorageKey]);
334
+ }, [showSystemEvents, sysEvtStorageKey]);
348
335
  React.useEffect(() => {
349
336
  setShowTimeline(false);
350
337
  setExtraActions([]);
@@ -377,6 +364,7 @@ function DetailView({
377
364
  [suggestedActions]
378
365
  );
379
366
  const timeChipToneClass = signalData.timeChipTone === "red" ? "border-red-300 bg-red-50 text-red-700 hover:bg-red-50" : signalData.timeChipTone === "amber" ? "border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-50" : "hover:bg-muted/50";
367
+ const isCasePanelV2 = sectionLayout === "case-panel-v2";
380
368
  const metadataChips = /* @__PURE__ */ jsxs(Fragment, { children: [
381
369
  /* @__PURE__ */ jsx(
382
370
  SignalPriorityPopover,
@@ -538,11 +526,9 @@ function DetailView({
538
526
  /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(SignalApproval.Actions, {}) })
539
527
  ] })
540
528
  ] }) : null,
541
- /* @__PURE__ */ jsxs("div", { "data-slot": "case-panel-workflow-stack", className: "space-y-10", children: [
542
- renderAfterScore == null ? void 0 : renderAfterScore(item),
543
- renderPrimaryAction == null ? void 0 : renderPrimaryAction(item),
544
- renderCommentArea ? /* @__PURE__ */ jsx("div", { "data-slot": "case-panel-comment-area", children: renderCommentArea(item) }) : null
545
- ] }),
529
+ renderAfterScore == null ? void 0 : renderAfterScore(item),
530
+ renderPrimaryAction == null ? void 0 : renderPrimaryAction(item),
531
+ renderCommentArea == null ? void 0 : renderCommentArea(item),
546
532
  timelineSection
547
533
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
548
534
  renderAfterScore == null ? void 0 : renderAfterScore(item),