@particle-academy/react-fancy 3.0.1 → 3.2.0

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
@@ -9223,11 +9223,11 @@ function computeTicks(min, max, count = 5) {
9223
9223
  }
9224
9224
  return ticks;
9225
9225
  }
9226
- function niceNum(range2, round) {
9226
+ function niceNum(range2, round2) {
9227
9227
  const exponent = Math.floor(Math.log10(range2));
9228
9228
  const fraction = range2 / Math.pow(10, exponent);
9229
9229
  let niceFraction;
9230
- if (round) {
9230
+ if (round2) {
9231
9231
  if (fraction < 1.5) niceFraction = 1;
9232
9232
  else if (fraction < 3) niceFraction = 2;
9233
9233
  else if (fraction < 7) niceFraction = 5;
@@ -11840,6 +11840,1277 @@ TreeNavRoot.displayName = "TreeNav";
11840
11840
  var TreeNav = Object.assign(TreeNavRoot, {
11841
11841
  Node: TreeNode
11842
11842
  });
11843
+ var CONFIDENCE_TIERS = [
11844
+ { min: 0.85, color: "#10b981", label: "high" },
11845
+ { min: 0.6, color: "#f59e0b", label: "medium" },
11846
+ { min: 0, color: "#ef4444", label: "low" }
11847
+ ];
11848
+ function tier(c) {
11849
+ return CONFIDENCE_TIERS.find((t) => c >= t.min) ?? CONFIDENCE_TIERS[2];
11850
+ }
11851
+ function ReasonTag({
11852
+ value,
11853
+ reason,
11854
+ confidence = 1,
11855
+ sources = [],
11856
+ by,
11857
+ theme = "dot",
11858
+ pinned = false,
11859
+ onFollowUp,
11860
+ className
11861
+ }) {
11862
+ const t = tier(confidence);
11863
+ const trigger = theme === "chip" ? /* @__PURE__ */ jsxRuntime.jsxs(
11864
+ "span",
11865
+ {
11866
+ className: `inline-flex cursor-help items-center gap-1 rounded-full px-2 py-0.5 text-[12px] font-medium ${className ?? ""}`,
11867
+ style: { backgroundColor: t.color + "22", color: t.color },
11868
+ children: [
11869
+ /* @__PURE__ */ jsxRuntime.jsx(
11870
+ "span",
11871
+ {
11872
+ className: "h-1.5 w-1.5 rounded-full",
11873
+ style: { backgroundColor: t.color }
11874
+ }
11875
+ ),
11876
+ value,
11877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] opacity-70", children: "?" })
11878
+ ]
11879
+ }
11880
+ ) : theme === "underline" ? /* @__PURE__ */ jsxRuntime.jsxs(
11881
+ "span",
11882
+ {
11883
+ className: `cursor-help underline decoration-dotted underline-offset-2 ${className ?? ""}`,
11884
+ style: { textDecorationColor: t.color },
11885
+ children: [
11886
+ value,
11887
+ /* @__PURE__ */ jsxRuntime.jsx(
11888
+ "span",
11889
+ {
11890
+ className: "ml-0.5 font-mono text-[10px]",
11891
+ style: { color: t.color },
11892
+ children: "?"
11893
+ }
11894
+ )
11895
+ ]
11896
+ }
11897
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `inline-flex cursor-help items-baseline gap-1 ${className ?? ""}`, children: [
11898
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: value }),
11899
+ /* @__PURE__ */ jsxRuntime.jsx(
11900
+ "span",
11901
+ {
11902
+ className: "inline-block h-1.5 w-1.5 rounded-full align-middle",
11903
+ style: { backgroundColor: t.color },
11904
+ title: "reason available"
11905
+ }
11906
+ )
11907
+ ] });
11908
+ if (pinned) {
11909
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex flex-col items-start gap-0.5 align-top", children: [
11910
+ trigger,
11911
+ /* @__PURE__ */ jsxRuntime.jsx(
11912
+ "span",
11913
+ {
11914
+ className: "block max-w-[280px] rounded border-l-2 pl-2 text-[11px] leading-snug text-zinc-600 dark:text-zinc-300",
11915
+ style: { borderColor: t.color },
11916
+ children: reason
11917
+ }
11918
+ )
11919
+ ] });
11920
+ }
11921
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { hover: true, children: [
11922
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { children: trigger }),
11923
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 space-y-2 text-sm", children: [
11924
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
11925
+ /* @__PURE__ */ jsxRuntime.jsxs(
11926
+ "span",
11927
+ {
11928
+ className: "text-[10px] font-semibold uppercase tracking-wider",
11929
+ style: { color: t.color },
11930
+ children: [
11931
+ t.label,
11932
+ " confidence \xB7 ",
11933
+ (confidence * 100).toFixed(0),
11934
+ "%"
11935
+ ]
11936
+ }
11937
+ ),
11938
+ by && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto font-mono text-[10px] text-zinc-400", children: [
11939
+ "@",
11940
+ by
11941
+ ] })
11942
+ ] }),
11943
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[13px] leading-snug text-zinc-700 dark:text-zinc-200", children: reason }),
11944
+ sources.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
11945
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] uppercase tracking-wider text-zinc-400", children: "sources" }),
11946
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-0.5 space-y-0.5 text-[12px]", children: sources.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: s.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "text-violet-600 hover:underline", href: s.href, children: s.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-600 dark:text-zinc-300", children: s.label }) }, i)) })
11947
+ ] }),
11948
+ onFollowUp && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(Action, { size: "sm", variant: "ghost", onClick: onFollowUp, children: "ask follow-up" }) })
11949
+ ] }) })
11950
+ ] });
11951
+ }
11952
+ function MoodMeter({
11953
+ min,
11954
+ max,
11955
+ step,
11956
+ value,
11957
+ confidence,
11958
+ onChange,
11959
+ posted,
11960
+ width = 320,
11961
+ height = 220,
11962
+ showGrid = true,
11963
+ color = "#0ea5e9",
11964
+ postedColor = "#a855f7",
11965
+ prefix = "",
11966
+ suffix = "",
11967
+ formatValue,
11968
+ className
11969
+ }) {
11970
+ const ref = react.useRef(null);
11971
+ const [dragging, setDragging] = react.useState(false);
11972
+ const snapStep = step ?? (max - min) / 100;
11973
+ const fmt = react.useCallback(
11974
+ (v) => {
11975
+ if (formatValue) return formatValue(v);
11976
+ const num = snapStep < 1 ? v.toFixed(2) : Math.round(v).toString();
11977
+ return `${prefix}${num}${suffix}`;
11978
+ },
11979
+ [formatValue, snapStep, prefix, suffix]
11980
+ );
11981
+ const set = react.useCallback(
11982
+ (clientX, clientY) => {
11983
+ const el = ref.current;
11984
+ if (!el) return;
11985
+ const rect = el.getBoundingClientRect();
11986
+ const x = clamp((clientX - rect.left) / rect.width, 0, 1);
11987
+ const y = clamp((clientY - rect.top) / rect.height, 0, 1);
11988
+ const raw = min + x * (max - min);
11989
+ const snapped = round(raw, snapStep, min);
11990
+ const c = clamp(1 - y, 0, 1);
11991
+ onChange(snapped, Math.round(c * 100) / 100);
11992
+ },
11993
+ [min, max, snapStep, onChange]
11994
+ );
11995
+ const onPointerDown = (e) => {
11996
+ e.target.setPointerCapture?.(e.pointerId);
11997
+ setDragging(true);
11998
+ set(e.clientX, e.clientY);
11999
+ };
12000
+ const onPointerMove = (e) => {
12001
+ if (!dragging) return;
12002
+ set(e.clientX, e.clientY);
12003
+ };
12004
+ const onPointerUp = () => setDragging(false);
12005
+ const xPct = (value - min) / (max - min) * 100;
12006
+ const yPct = (1 - confidence) * 100;
12007
+ const haloR = 18 + (1 - confidence) * 70;
12008
+ const pxPct = posted ? (posted.value - min) / (max - min) * 100 : 0;
12009
+ const pyPct = posted ? (1 - posted.confidence) * 100 : 0;
12010
+ const pHaloR = posted ? 16 + (1 - posted.confidence) * 60 : 0;
12011
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12012
+ "div",
12013
+ {
12014
+ ref,
12015
+ onPointerDown,
12016
+ onPointerMove,
12017
+ onPointerUp,
12018
+ onPointerCancel: onPointerUp,
12019
+ className: `relative cursor-crosshair touch-none select-none overflow-hidden rounded-md border border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-950 ${className ?? ""}`,
12020
+ style: { width, height },
12021
+ children: [
12022
+ showGrid && /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "pointer-events-none absolute inset-0 h-full w-full", "aria-hidden": true, children: [
12023
+ [0.25, 0.5, 0.75].map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
12024
+ "line",
12025
+ {
12026
+ x1: `${p * 100}%`,
12027
+ x2: `${p * 100}%`,
12028
+ y1: "0",
12029
+ y2: "100%",
12030
+ stroke: "#a1a1aa",
12031
+ strokeOpacity: 0.18,
12032
+ strokeDasharray: "3 4"
12033
+ },
12034
+ `v${i}`
12035
+ )),
12036
+ [0.25, 0.5, 0.75].map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
12037
+ "line",
12038
+ {
12039
+ x1: "0",
12040
+ x2: "100%",
12041
+ y1: `${p * 100}%`,
12042
+ y2: `${p * 100}%`,
12043
+ stroke: "#a1a1aa",
12044
+ strokeOpacity: 0.18,
12045
+ strokeDasharray: "3 4"
12046
+ },
12047
+ `h${i}`
12048
+ ))
12049
+ ] }),
12050
+ showGrid && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12051
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute left-1.5 top-1.5 text-[10px] uppercase tracking-wider text-zinc-400", children: "\u2191 sure" }),
12052
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute bottom-1.5 left-1.5 text-[10px] uppercase tracking-wider text-zinc-400", children: "\u2193 unsure" }),
12053
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute right-1.5 top-1.5 text-[10px] uppercase tracking-wider text-zinc-400", children: [
12054
+ fmt(max),
12055
+ " \u2192"
12056
+ ] }),
12057
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute bottom-1.5 right-1.5 text-[10px] uppercase tracking-wider text-zinc-400", children: [
12058
+ "\u2190 ",
12059
+ fmt(min)
12060
+ ] })
12061
+ ] }),
12062
+ posted && /* @__PURE__ */ jsxRuntime.jsx(
12063
+ Handle,
12064
+ {
12065
+ xPct: pxPct,
12066
+ yPct: pyPct,
12067
+ haloR: pHaloR,
12068
+ color: postedColor,
12069
+ dashed: true,
12070
+ label: "agent"
12071
+ }
12072
+ ),
12073
+ /* @__PURE__ */ jsxRuntime.jsx(
12074
+ Handle,
12075
+ {
12076
+ xPct,
12077
+ yPct,
12078
+ haloR,
12079
+ color,
12080
+ label: fmt(value)
12081
+ }
12082
+ )
12083
+ ]
12084
+ }
12085
+ );
12086
+ }
12087
+ function Handle({
12088
+ xPct,
12089
+ yPct,
12090
+ haloR,
12091
+ color,
12092
+ dashed = false,
12093
+ label
12094
+ }) {
12095
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12096
+ /* @__PURE__ */ jsxRuntime.jsx(
12097
+ "div",
12098
+ {
12099
+ className: "pointer-events-none absolute -translate-x-1/2 -translate-y-1/2 rounded-full",
12100
+ style: {
12101
+ left: `${xPct}%`,
12102
+ top: `${yPct}%`,
12103
+ width: haloR * 2,
12104
+ height: haloR * 2,
12105
+ background: color + (dashed ? "11" : "22"),
12106
+ border: dashed ? `1px dashed ${color}` : "none"
12107
+ }
12108
+ }
12109
+ ),
12110
+ /* @__PURE__ */ jsxRuntime.jsx(
12111
+ "div",
12112
+ {
12113
+ className: "pointer-events-none absolute -translate-x-1/2 -translate-y-1/2 rounded-full ring-2 ring-white dark:ring-zinc-900",
12114
+ style: {
12115
+ left: `${xPct}%`,
12116
+ top: `${yPct}%`,
12117
+ width: 14,
12118
+ height: 14,
12119
+ background: color,
12120
+ opacity: dashed ? 0.6 : 1
12121
+ }
12122
+ }
12123
+ ),
12124
+ /* @__PURE__ */ jsxRuntime.jsx(
12125
+ "div",
12126
+ {
12127
+ className: "pointer-events-none absolute -translate-x-1/2 rounded px-1.5 py-0.5 font-mono text-[10px]",
12128
+ style: {
12129
+ left: `${xPct}%`,
12130
+ top: `calc(${yPct}% + 14px)`,
12131
+ color
12132
+ },
12133
+ children: label
12134
+ }
12135
+ )
12136
+ ] });
12137
+ }
12138
+ function clamp(n, lo, hi) {
12139
+ return Math.max(lo, Math.min(hi, n));
12140
+ }
12141
+ function round(n, step, min) {
12142
+ if (step >= 1) return Math.round(n);
12143
+ return Math.round((n - min) / step) * step + min;
12144
+ }
12145
+ var DEFAULT_MENTION_COLOR = {
12146
+ agent: "#a855f7",
12147
+ file: "#10b981",
12148
+ person: "#3b82f6"
12149
+ };
12150
+ function PromptInput({
12151
+ budgetTokens,
12152
+ commands = [],
12153
+ mentions = [],
12154
+ showHint = true,
12155
+ onSubmit,
12156
+ placeholder = "Ask anything. Type / for commands, @ for mentions. \u2318/Ctrl+Enter to send.",
12157
+ charsPerToken = 4,
12158
+ mentionColor,
12159
+ maxHeight = 280,
12160
+ aboveInput
12161
+ }) {
12162
+ const [text, setText] = react.useState("");
12163
+ const [attachments, setAttachments] = react.useState([]);
12164
+ const [picker, setPicker] = react.useState(null);
12165
+ const taRef = react.useRef(null);
12166
+ const [dragOver, setDragOver] = react.useState(false);
12167
+ const colors = mentionColor ?? DEFAULT_MENTION_COLOR;
12168
+ const tokens = react.useMemo(
12169
+ () => Math.ceil(text.length / Math.max(1, charsPerToken)),
12170
+ [text, charsPerToken]
12171
+ );
12172
+ const ratio = Math.min(1, tokens / budgetTokens);
12173
+ const meterColor = ratio < 0.6 ? "#10b981" : ratio < 0.85 ? "#f59e0b" : "#ef4444";
12174
+ const filteredCmds = react.useMemo(
12175
+ () => picker?.kind === "cmd" ? commands.filter(
12176
+ (c) => c.name.slice(1).toLowerCase().startsWith(picker.query.toLowerCase())
12177
+ ) : [],
12178
+ [picker, commands]
12179
+ );
12180
+ const filteredMentions = react.useMemo(
12181
+ () => picker?.kind === "mention" ? mentions.filter(
12182
+ (m) => m.name.toLowerCase().includes(picker.query.toLowerCase())
12183
+ ) : [],
12184
+ [picker, mentions]
12185
+ );
12186
+ const items = picker?.kind === "cmd" ? filteredCmds : picker?.kind === "mention" ? filteredMentions : [];
12187
+ react.useEffect(() => {
12188
+ const ta = taRef.current;
12189
+ if (!ta) return;
12190
+ ta.style.height = "auto";
12191
+ ta.style.height = Math.min(maxHeight, ta.scrollHeight) + "px";
12192
+ }, [text, maxHeight]);
12193
+ const updateText = (next, caret) => {
12194
+ setText(next);
12195
+ let triggerIdx = -1;
12196
+ let triggerKind = null;
12197
+ for (let i = caret - 1; i >= 0; i--) {
12198
+ const ch = next[i];
12199
+ if (ch === "@") {
12200
+ triggerKind = "mention";
12201
+ triggerIdx = i;
12202
+ break;
12203
+ }
12204
+ if (ch === "/" && (i === 0 || /\s/.test(next[i - 1] ?? ""))) {
12205
+ triggerKind = "cmd";
12206
+ triggerIdx = i;
12207
+ break;
12208
+ }
12209
+ if (/\s/.test(ch)) break;
12210
+ }
12211
+ if (triggerKind !== null && triggerIdx >= 0) {
12212
+ const query = next.slice(triggerIdx + 1, caret);
12213
+ setPicker({ kind: triggerKind, start: triggerIdx, query, cursor: 0 });
12214
+ } else {
12215
+ setPicker(null);
12216
+ }
12217
+ };
12218
+ const insertChoice = (i) => {
12219
+ if (!picker || items.length === 0) return;
12220
+ const choice = items[i] ?? items[0];
12221
+ const insert = picker.kind === "cmd" ? choice.name + " " : `@${choice.id} `;
12222
+ const before = text.slice(0, picker.start);
12223
+ const after = text.slice(picker.start + 1 + picker.query.length);
12224
+ const next = before + insert + after;
12225
+ setText(next);
12226
+ setPicker(null);
12227
+ requestAnimationFrame(() => {
12228
+ const ta = taRef.current;
12229
+ if (!ta) return;
12230
+ ta.focus();
12231
+ const pos = before.length + insert.length;
12232
+ ta.setSelectionRange(pos, pos);
12233
+ });
12234
+ };
12235
+ const submit = () => {
12236
+ if (!text.trim() && attachments.length === 0) return;
12237
+ onSubmit(text, attachments);
12238
+ setText("");
12239
+ setAttachments([]);
12240
+ setPicker(null);
12241
+ };
12242
+ const onKeyDown = (e) => {
12243
+ if (picker) {
12244
+ if (e.key === "ArrowDown") {
12245
+ e.preventDefault();
12246
+ setPicker(
12247
+ (p) => p ? { ...p, cursor: Math.min(items.length - 1, p.cursor + 1) } : p
12248
+ );
12249
+ return;
12250
+ }
12251
+ if (e.key === "ArrowUp") {
12252
+ e.preventDefault();
12253
+ setPicker((p) => p ? { ...p, cursor: Math.max(0, p.cursor - 1) } : p);
12254
+ return;
12255
+ }
12256
+ if (e.key === "Enter" && !e.metaKey && !e.ctrlKey && items.length > 0) {
12257
+ e.preventDefault();
12258
+ insertChoice(picker.cursor);
12259
+ return;
12260
+ }
12261
+ if (e.key === "Escape") {
12262
+ e.preventDefault();
12263
+ setPicker(null);
12264
+ return;
12265
+ }
12266
+ }
12267
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
12268
+ e.preventDefault();
12269
+ submit();
12270
+ }
12271
+ };
12272
+ const onDrop = (e) => {
12273
+ e.preventDefault();
12274
+ setDragOver(false);
12275
+ const files = Array.from(e.dataTransfer.files);
12276
+ setAttachments((cur) => [
12277
+ ...cur,
12278
+ ...files.map((f) => ({
12279
+ id: `${f.name}-${Date.now()}-${Math.random()}`,
12280
+ name: f.name,
12281
+ bytes: f.size
12282
+ }))
12283
+ ]);
12284
+ };
12285
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12286
+ "div",
12287
+ {
12288
+ onDragOver: (e) => {
12289
+ e.preventDefault();
12290
+ setDragOver(true);
12291
+ },
12292
+ onDragLeave: () => setDragOver(false),
12293
+ onDrop,
12294
+ className: `relative rounded-md border transition ${dragOver ? "border-violet-400 bg-violet-50/50 dark:border-violet-600 dark:bg-violet-950/30" : "border-zinc-200 dark:border-zinc-800"} bg-white dark:bg-zinc-900`,
12295
+ children: [
12296
+ aboveInput && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-zinc-200 dark:border-zinc-800", children: aboveInput }),
12297
+ attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 border-b border-zinc-200 px-3 py-2 dark:border-zinc-800", children: attachments.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
12298
+ "span",
12299
+ {
12300
+ className: "inline-flex items-center gap-1.5 rounded-md bg-zinc-100 px-2 py-0.5 text-[11px] dark:bg-zinc-800",
12301
+ children: [
12302
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u{1F4CE}" }),
12303
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: a.name }),
12304
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400", children: fmtSize(a.bytes) }),
12305
+ /* @__PURE__ */ jsxRuntime.jsx(
12306
+ "button",
12307
+ {
12308
+ onClick: () => setAttachments((cur) => cur.filter((x) => x.id !== a.id)),
12309
+ className: "opacity-50 hover:opacity-100",
12310
+ "aria-label": "Remove attachment",
12311
+ children: "\xD7"
12312
+ }
12313
+ )
12314
+ ]
12315
+ },
12316
+ a.id
12317
+ )) }),
12318
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
12319
+ /* @__PURE__ */ jsxRuntime.jsx(
12320
+ "textarea",
12321
+ {
12322
+ ref: taRef,
12323
+ value: text,
12324
+ onChange: (e) => updateText(e.target.value, e.target.selectionStart),
12325
+ onKeyDown,
12326
+ placeholder,
12327
+ spellCheck: false,
12328
+ className: "block w-full resize-none bg-transparent px-3 py-2.5 text-[14px] leading-relaxed outline-none placeholder:text-zinc-400",
12329
+ rows: 3
12330
+ }
12331
+ ),
12332
+ picker && items.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-full left-2 z-10 mb-1 w-72 overflow-hidden rounded-md border border-zinc-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-900", children: [
12333
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-zinc-100 bg-zinc-50 px-2 py-1 text-[10px] font-semibold uppercase tracking-wider text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950", children: [
12334
+ picker.kind === "cmd" ? "Commands" : "Mention",
12335
+ " \xB7 ",
12336
+ items.length
12337
+ ] }),
12338
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "max-h-56 overflow-y-auto", children: items.map((item, i) => {
12339
+ const active = i === picker.cursor;
12340
+ if (picker.kind === "cmd") {
12341
+ const c = item;
12342
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12343
+ "li",
12344
+ {
12345
+ onMouseDown: (e) => {
12346
+ e.preventDefault();
12347
+ insertChoice(i);
12348
+ },
12349
+ onMouseEnter: () => setPicker((p) => p ? { ...p, cursor: i } : p),
12350
+ className: `cursor-pointer px-2 py-1.5 text-[12px] ${active ? "bg-violet-100 dark:bg-violet-900/30" : "hover:bg-zinc-50 dark:hover:bg-zinc-800"}`,
12351
+ children: [
12352
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-mono font-medium text-violet-700 dark:text-violet-300", children: c.name }),
12353
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-zinc-500", children: c.hint })
12354
+ ]
12355
+ },
12356
+ c.name
12357
+ );
12358
+ }
12359
+ const m = item;
12360
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12361
+ "li",
12362
+ {
12363
+ onMouseDown: (e) => {
12364
+ e.preventDefault();
12365
+ insertChoice(i);
12366
+ },
12367
+ onMouseEnter: () => setPicker((p) => p ? { ...p, cursor: i } : p),
12368
+ className: `flex cursor-pointer items-center gap-2 px-2 py-1.5 text-[12px] ${active ? "bg-violet-100 dark:bg-violet-900/30" : "hover:bg-zinc-50 dark:hover:bg-zinc-800"}`,
12369
+ children: [
12370
+ /* @__PURE__ */ jsxRuntime.jsx(
12371
+ "span",
12372
+ {
12373
+ className: "h-2 w-2 rounded-full",
12374
+ style: { backgroundColor: colors[m.kind] ?? "#71717a" }
12375
+ }
12376
+ ),
12377
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: m.name }),
12378
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto text-[10px] uppercase tracking-wider text-zinc-400", children: m.kind })
12379
+ ]
12380
+ },
12381
+ m.id
12382
+ );
12383
+ }) })
12384
+ ] })
12385
+ ] }),
12386
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-t border-zinc-200 bg-zinc-50/60 px-3 py-2 dark:border-zinc-800 dark:bg-zinc-900/40", children: [
12387
+ /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: "Drop files here, or click", children: /* @__PURE__ */ jsxRuntime.jsx(
12388
+ Action,
12389
+ {
12390
+ variant: "ghost",
12391
+ size: "sm",
12392
+ onClick: () => {
12393
+ },
12394
+ children: "\u{1F4CE} attach"
12395
+ }
12396
+ ) }),
12397
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-2 flex items-center gap-1.5", children: [
12398
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-24 overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700", children: /* @__PURE__ */ jsxRuntime.jsx(
12399
+ "div",
12400
+ {
12401
+ className: "h-full rounded-full transition-all",
12402
+ style: { width: `${ratio * 100}%`, backgroundColor: meterColor }
12403
+ }
12404
+ ) }),
12405
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[11px]", style: { color: meterColor }, children: [
12406
+ fmtTokens(tokens),
12407
+ " / ",
12408
+ fmtTokens(budgetTokens)
12409
+ ] })
12410
+ ] }),
12411
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-2", children: [
12412
+ showHint && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden text-[10px] text-zinc-500 sm:inline", children: [
12413
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "rounded border border-zinc-300 bg-zinc-50 px-1 py-0.5 font-mono text-[9px] text-zinc-700 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300", children: "\u2318" }),
12414
+ " ",
12415
+ "+",
12416
+ " ",
12417
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "rounded border border-zinc-300 bg-zinc-50 px-1 py-0.5 font-mono text-[9px] text-zinc-700 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300", children: "Enter" }),
12418
+ " ",
12419
+ "to send"
12420
+ ] }),
12421
+ /* @__PURE__ */ jsxRuntime.jsx(Action, { color: "violet", size: "sm", onClick: submit, children: "send \u2192" })
12422
+ ] })
12423
+ ] })
12424
+ ]
12425
+ }
12426
+ );
12427
+ }
12428
+ function fmtTokens(n) {
12429
+ if (n < 1e3) return `${n}`;
12430
+ return `${(n / 1e3).toFixed(1)}k`;
12431
+ }
12432
+ function fmtSize(b) {
12433
+ if (b < 1024) return `${b} B`;
12434
+ if (b < 1024 * 1024) return `${(b / 1024).toFixed(0)} KB`;
12435
+ return `${(b / 1024 / 1024).toFixed(1)} MB`;
12436
+ }
12437
+ function ChatDrawer({
12438
+ tabs,
12439
+ activeTabId,
12440
+ onTabChange,
12441
+ open = true,
12442
+ onToggle,
12443
+ children,
12444
+ minBodyHeight = 140,
12445
+ className
12446
+ }) {
12447
+ const handleToggle = react.useCallback(() => {
12448
+ onToggle?.(!open);
12449
+ }, [onToggle, open]);
12450
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
12451
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-2", children: [
12452
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5", children: tabs.map((tab, i) => {
12453
+ const active = tab.id === activeTabId;
12454
+ const number = tab.number === null ? null : tab.number ?? i + 1;
12455
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12456
+ "button",
12457
+ {
12458
+ type: "button",
12459
+ onClick: () => onTabChange(tab.id),
12460
+ className: [
12461
+ "group inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[12px] font-medium transition",
12462
+ active ? "border-violet-500 bg-violet-500 text-white" : "border-zinc-200 bg-transparent text-zinc-700 hover:border-zinc-300 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-300 dark:hover:border-zinc-600 dark:hover:bg-zinc-800"
12463
+ ].join(" "),
12464
+ "aria-pressed": active,
12465
+ children: [
12466
+ number !== null && /* @__PURE__ */ jsxRuntime.jsx(
12467
+ "span",
12468
+ {
12469
+ className: [
12470
+ "inline-flex h-4 w-4 items-center justify-center rounded-full text-[10px] font-semibold",
12471
+ active ? "bg-white/20 text-white" : "bg-zinc-200 text-zinc-600 group-hover:bg-zinc-300 dark:bg-zinc-700 dark:text-zinc-300"
12472
+ ].join(" "),
12473
+ children: number
12474
+ }
12475
+ ),
12476
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate max-w-[180px]", children: tab.label })
12477
+ ]
12478
+ },
12479
+ tab.id
12480
+ );
12481
+ }) }),
12482
+ /* @__PURE__ */ jsxRuntime.jsx(
12483
+ "button",
12484
+ {
12485
+ type: "button",
12486
+ onClick: handleToggle,
12487
+ "aria-label": open ? "Collapse drawer" : "Expand drawer",
12488
+ "aria-expanded": open,
12489
+ className: "ml-auto inline-flex h-6 w-6 items-center justify-center rounded-full text-zinc-400 transition hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200",
12490
+ children: /* @__PURE__ */ jsxRuntime.jsx(
12491
+ Icon,
12492
+ {
12493
+ name: open ? "chevron-down" : "chevron-up",
12494
+ className: "h-3.5 w-3.5"
12495
+ }
12496
+ )
12497
+ }
12498
+ )
12499
+ ] }),
12500
+ open && /* @__PURE__ */ jsxRuntime.jsx(
12501
+ "div",
12502
+ {
12503
+ className: "px-2.5 pb-2.5",
12504
+ style: { minHeight: minBodyHeight },
12505
+ children
12506
+ }
12507
+ )
12508
+ ] });
12509
+ }
12510
+ function defaultKeyOf(item) {
12511
+ if (item && typeof item === "object") {
12512
+ const r = item;
12513
+ if (typeof r.name === "string") return r.name;
12514
+ if (typeof r.id === "string") return r.id;
12515
+ }
12516
+ return String(item);
12517
+ }
12518
+ function defaultFilter(item, query) {
12519
+ if (!query) return true;
12520
+ return defaultKeyOf(item).toLowerCase().includes(query.toLowerCase());
12521
+ }
12522
+ function detectTrigger(text, caret, triggerChars) {
12523
+ for (let i = caret - 1; i >= 0; i--) {
12524
+ const ch = text[i];
12525
+ if (ch === void 0) break;
12526
+ if (triggerChars.has(ch)) {
12527
+ if (i === 0 || /\s/.test(text[i - 1])) {
12528
+ return {
12529
+ char: ch,
12530
+ start: i,
12531
+ end: caret,
12532
+ query: text.slice(i + 1, caret)
12533
+ };
12534
+ }
12535
+ return null;
12536
+ }
12537
+ if (/\s/.test(ch)) return null;
12538
+ }
12539
+ return null;
12540
+ }
12541
+ function InputTag({
12542
+ adapter,
12543
+ triggers,
12544
+ maxItems = 8,
12545
+ placement = "bottom-left",
12546
+ className,
12547
+ style,
12548
+ onPick
12549
+ }) {
12550
+ const triggerChars = react.useMemo(() => new Set(Object.keys(triggers)), [triggers]);
12551
+ const [active, setActive] = react.useState(null);
12552
+ const [cursor, setCursor] = react.useState(0);
12553
+ const [anchorRect, setAnchorRect] = react.useState(null);
12554
+ const stateRef = react.useRef({ text: "", caretIndex: 0 });
12555
+ const activeRef = react.useRef(null);
12556
+ const cursorRef = react.useRef(0);
12557
+ activeRef.current = active;
12558
+ cursorRef.current = cursor;
12559
+ const items = react.useMemo(() => {
12560
+ if (!active) return [];
12561
+ const cfg2 = triggers[active.char];
12562
+ if (!cfg2) return [];
12563
+ const filter = cfg2.filter ?? defaultFilter;
12564
+ const out = [];
12565
+ for (const item of cfg2.items) {
12566
+ if (filter(item, active.query)) out.push(item);
12567
+ if (out.length >= maxItems) break;
12568
+ }
12569
+ return out;
12570
+ }, [active, triggers, maxItems]);
12571
+ react.useEffect(() => {
12572
+ return adapter.subscribe((s) => {
12573
+ stateRef.current = s;
12574
+ const next = detectTrigger(s.text, s.caretIndex, triggerChars);
12575
+ setActive((prev) => {
12576
+ if (!prev || !next || prev.char !== next.char || prev.start !== next.start) {
12577
+ setCursor(0);
12578
+ }
12579
+ return next;
12580
+ });
12581
+ if (next) setAnchorRect(adapter.getAnchorRect());
12582
+ });
12583
+ }, [adapter, triggerChars]);
12584
+ react.useLayoutEffect(() => {
12585
+ if (!active) return;
12586
+ const update = () => setAnchorRect(adapter.getAnchorRect());
12587
+ update();
12588
+ window.addEventListener("scroll", update, true);
12589
+ window.addEventListener("resize", update);
12590
+ return () => {
12591
+ window.removeEventListener("scroll", update, true);
12592
+ window.removeEventListener("resize", update);
12593
+ };
12594
+ }, [active, adapter]);
12595
+ react.useEffect(() => {
12596
+ if (cursor >= items.length) setCursor(Math.max(0, items.length - 1));
12597
+ }, [items.length, cursor]);
12598
+ const pickItem = react.useCallback(
12599
+ (item) => {
12600
+ const cur = activeRef.current;
12601
+ if (!cur) return;
12602
+ const cfg2 = triggers[cur.char];
12603
+ if (!cfg2) return;
12604
+ const replacement = cfg2.insert(item, cur.query);
12605
+ adapter.replaceRange(cur.start, cur.end, replacement);
12606
+ onPick?.({ triggerChar: cur.char, query: cur.query, item });
12607
+ setActive(null);
12608
+ },
12609
+ [adapter, triggers, onPick]
12610
+ );
12611
+ react.useEffect(() => {
12612
+ return adapter.onKey((e) => {
12613
+ const cur = activeRef.current;
12614
+ if (!cur) return false;
12615
+ const visible = items;
12616
+ switch (e.key) {
12617
+ case "ArrowDown":
12618
+ if (visible.length === 0) return false;
12619
+ setCursor((c) => (c + 1) % visible.length);
12620
+ return true;
12621
+ case "ArrowUp":
12622
+ if (visible.length === 0) return false;
12623
+ setCursor((c) => (c - 1 + visible.length) % visible.length);
12624
+ return true;
12625
+ case "Enter":
12626
+ case "Tab": {
12627
+ if (visible.length === 0) return false;
12628
+ const idx = Math.min(cursorRef.current, visible.length - 1);
12629
+ pickItem(visible[idx]);
12630
+ return true;
12631
+ }
12632
+ case "Escape":
12633
+ setActive(null);
12634
+ return true;
12635
+ default:
12636
+ return false;
12637
+ }
12638
+ });
12639
+ }, [adapter, items, pickItem]);
12640
+ if (!active || !anchorRect || items.length === 0) return null;
12641
+ const cfg = triggers[active.char];
12642
+ if (!cfg) return null;
12643
+ const popStyle = computePopoverStyle(anchorRect, placement);
12644
+ return /* @__PURE__ */ jsxRuntime.jsxs(
12645
+ "div",
12646
+ {
12647
+ role: "listbox",
12648
+ "aria-label": cfg.label ?? `Pick a ${active.char === "/" ? "command" : "mention"}`,
12649
+ className: [
12650
+ "fixed z-50 w-72 overflow-hidden rounded-md border border-zinc-200 bg-white shadow-lg dark:border-zinc-700 dark:bg-zinc-900",
12651
+ className ?? ""
12652
+ ].filter(Boolean).join(" "),
12653
+ style: { ...popStyle, ...style },
12654
+ children: [
12655
+ (cfg.label || active.query) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-zinc-100 bg-zinc-50 px-2 py-1 text-[10px] font-semibold uppercase tracking-wider text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950", children: [
12656
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: cfg.label ?? labelForChar(active.char) }),
12657
+ active.query && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[10px] normal-case tracking-normal text-zinc-400", children: [
12658
+ active.char,
12659
+ active.query
12660
+ ] })
12661
+ ] }),
12662
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "max-h-60 overflow-y-auto", children: items.map((item, i) => {
12663
+ const renderer = cfg.render ?? ((it) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: defaultKeyOf(it) }));
12664
+ const active2 = i === cursor;
12665
+ const key = (cfg.keyOf ?? defaultKeyOf)(item);
12666
+ return /* @__PURE__ */ jsxRuntime.jsx(
12667
+ "li",
12668
+ {
12669
+ role: "option",
12670
+ "aria-selected": active2,
12671
+ onMouseDown: (e) => {
12672
+ e.preventDefault();
12673
+ pickItem(item);
12674
+ },
12675
+ onMouseEnter: () => setCursor(i),
12676
+ className: [
12677
+ "cursor-pointer px-2 py-1.5 text-[12px]",
12678
+ active2 ? "bg-violet-100 dark:bg-violet-900/30" : "hover:bg-zinc-50 dark:hover:bg-zinc-800"
12679
+ ].join(" "),
12680
+ children: renderer(item, active2)
12681
+ },
12682
+ key
12683
+ );
12684
+ }) })
12685
+ ]
12686
+ }
12687
+ );
12688
+ }
12689
+ function labelForChar(ch) {
12690
+ if (ch === "/") return "Commands";
12691
+ if (ch === "@") return "Mentions";
12692
+ if (ch === "#") return "Tags";
12693
+ if (ch === ":") return "Emoji";
12694
+ return `Trigger ${ch}`;
12695
+ }
12696
+ function computePopoverStyle(anchor, placement) {
12697
+ const offset = 4;
12698
+ switch (placement) {
12699
+ case "bottom-right":
12700
+ return { top: anchor.bottom + offset, right: window.innerWidth - anchor.right };
12701
+ case "top-left":
12702
+ return { bottom: window.innerHeight - anchor.top + offset, left: anchor.left };
12703
+ case "top-right":
12704
+ return { bottom: window.innerHeight - anchor.top + offset, right: window.innerWidth - anchor.right };
12705
+ case "bottom-left":
12706
+ default:
12707
+ return { top: anchor.bottom + offset, left: anchor.left };
12708
+ }
12709
+ }
12710
+
12711
+ // src/components/InputTag/adapters.ts
12712
+ function nativeValueSetter(el) {
12713
+ const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
12714
+ const desc = Object.getOwnPropertyDescriptor(proto, "value");
12715
+ if (!desc?.set) return null;
12716
+ return desc.set.bind(el);
12717
+ }
12718
+ function replaceInValueElement(el, start, end, replacement) {
12719
+ const current = el.value;
12720
+ const next = current.slice(0, start) + replacement + current.slice(end);
12721
+ const setter = nativeValueSetter(el);
12722
+ if (setter) {
12723
+ setter(next);
12724
+ } else {
12725
+ el.value = next;
12726
+ }
12727
+ el.dispatchEvent(new Event("input", { bubbles: true }));
12728
+ const caret = start + replacement.length;
12729
+ el.setSelectionRange(caret, caret);
12730
+ el.focus();
12731
+ }
12732
+ function valueElementAdapter(ref) {
12733
+ return {
12734
+ subscribe(fn) {
12735
+ const handler = () => {
12736
+ const el2 = ref.current;
12737
+ if (!el2) return;
12738
+ fn({
12739
+ text: el2.value,
12740
+ caretIndex: el2.selectionStart ?? el2.value.length
12741
+ });
12742
+ };
12743
+ const el = ref.current;
12744
+ if (el) {
12745
+ el.addEventListener("input", handler);
12746
+ el.addEventListener("click", handler);
12747
+ el.addEventListener("keyup", handler);
12748
+ el.addEventListener("focus", handler);
12749
+ }
12750
+ return () => {
12751
+ const el2 = ref.current;
12752
+ if (el2) {
12753
+ el2.removeEventListener("input", handler);
12754
+ el2.removeEventListener("click", handler);
12755
+ el2.removeEventListener("keyup", handler);
12756
+ el2.removeEventListener("focus", handler);
12757
+ }
12758
+ };
12759
+ },
12760
+ replaceRange(start, end, replacement) {
12761
+ const el = ref.current;
12762
+ if (!el) return;
12763
+ replaceInValueElement(el, start, end, replacement);
12764
+ },
12765
+ getAnchorRect() {
12766
+ const el = ref.current;
12767
+ return el ? el.getBoundingClientRect() : null;
12768
+ },
12769
+ onKey(handler) {
12770
+ const fn = (e) => {
12771
+ if (handler(e)) {
12772
+ e.preventDefault();
12773
+ e.stopPropagation();
12774
+ }
12775
+ };
12776
+ const el = ref.current;
12777
+ if (el) el.addEventListener("keydown", fn);
12778
+ return () => {
12779
+ const el2 = ref.current;
12780
+ if (el2) el2.removeEventListener("keydown", fn);
12781
+ };
12782
+ }
12783
+ };
12784
+ }
12785
+ function textareaAdapter(ref) {
12786
+ return valueElementAdapter(ref);
12787
+ }
12788
+ function inputAdapter(ref) {
12789
+ return valueElementAdapter(ref);
12790
+ }
12791
+ function contentEditableAdapter(ref) {
12792
+ function caretIndex(el) {
12793
+ const sel = window.getSelection();
12794
+ if (!sel || sel.rangeCount === 0) return 0;
12795
+ const range2 = sel.getRangeAt(0).cloneRange();
12796
+ range2.selectNodeContents(el);
12797
+ range2.setEnd(sel.focusNode, sel.focusOffset);
12798
+ return range2.toString().length;
12799
+ }
12800
+ function setCaret(el, index) {
12801
+ const sel = window.getSelection();
12802
+ if (!sel) return;
12803
+ const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
12804
+ let remaining = index;
12805
+ let node = walker.nextNode();
12806
+ while (node) {
12807
+ const len = (node.textContent ?? "").length;
12808
+ if (remaining <= len) {
12809
+ const range3 = document.createRange();
12810
+ range3.setStart(node, remaining);
12811
+ range3.collapse(true);
12812
+ sel.removeAllRanges();
12813
+ sel.addRange(range3);
12814
+ return;
12815
+ }
12816
+ remaining -= len;
12817
+ node = walker.nextNode();
12818
+ }
12819
+ const range2 = document.createRange();
12820
+ range2.selectNodeContents(el);
12821
+ range2.collapse(false);
12822
+ sel.removeAllRanges();
12823
+ sel.addRange(range2);
12824
+ }
12825
+ return {
12826
+ subscribe(fn) {
12827
+ const handler = () => {
12828
+ const el2 = ref.current;
12829
+ if (!el2) return;
12830
+ fn({ text: el2.textContent ?? "", caretIndex: caretIndex(el2) });
12831
+ };
12832
+ const el = ref.current;
12833
+ if (el) {
12834
+ el.addEventListener("input", handler);
12835
+ el.addEventListener("click", handler);
12836
+ el.addEventListener("keyup", handler);
12837
+ el.addEventListener("focus", handler);
12838
+ }
12839
+ return () => {
12840
+ const el2 = ref.current;
12841
+ if (el2) {
12842
+ el2.removeEventListener("input", handler);
12843
+ el2.removeEventListener("click", handler);
12844
+ el2.removeEventListener("keyup", handler);
12845
+ el2.removeEventListener("focus", handler);
12846
+ }
12847
+ };
12848
+ },
12849
+ replaceRange(start, end, replacement) {
12850
+ const el = ref.current;
12851
+ if (!el) return;
12852
+ const current = el.textContent ?? "";
12853
+ const next = current.slice(0, start) + replacement + current.slice(end);
12854
+ el.textContent = next;
12855
+ setCaret(el, start + replacement.length);
12856
+ el.dispatchEvent(new Event("input", { bubbles: true }));
12857
+ el.focus();
12858
+ },
12859
+ getAnchorRect() {
12860
+ const el = ref.current;
12861
+ return el ? el.getBoundingClientRect() : null;
12862
+ },
12863
+ onKey(handler) {
12864
+ const fn = (e) => {
12865
+ if (handler(e)) {
12866
+ e.preventDefault();
12867
+ e.stopPropagation();
12868
+ }
12869
+ };
12870
+ const el = ref.current;
12871
+ if (el) el.addEventListener("keydown", fn);
12872
+ return () => {
12873
+ const el2 = ref.current;
12874
+ if (el2) el2.removeEventListener("keydown", fn);
12875
+ };
12876
+ }
12877
+ };
12878
+ }
12879
+ function controlledAdapter(opts) {
12880
+ let listener = null;
12881
+ let keyHandler = null;
12882
+ const installKey = () => {
12883
+ const el = opts.anchorRef.current;
12884
+ if (!el || !keyHandler) return () => {
12885
+ };
12886
+ const fn = (e) => {
12887
+ if (keyHandler && keyHandler(e)) {
12888
+ e.preventDefault();
12889
+ e.stopPropagation();
12890
+ }
12891
+ };
12892
+ el.addEventListener("keydown", fn);
12893
+ return () => el.removeEventListener("keydown", fn);
12894
+ };
12895
+ return {
12896
+ notify(state) {
12897
+ listener?.(state);
12898
+ },
12899
+ subscribe(fn) {
12900
+ listener = fn;
12901
+ return () => {
12902
+ if (listener === fn) listener = null;
12903
+ };
12904
+ },
12905
+ replaceRange(start, end, replacement) {
12906
+ opts.onReplaceRange(start, end, replacement);
12907
+ },
12908
+ getAnchorRect() {
12909
+ const el = opts.anchorRef.current;
12910
+ return el ? el.getBoundingClientRect() : null;
12911
+ },
12912
+ onKey(handler) {
12913
+ keyHandler = handler;
12914
+ const uninstall = installKey();
12915
+ return () => {
12916
+ if (keyHandler === handler) keyHandler = null;
12917
+ uninstall();
12918
+ };
12919
+ }
12920
+ };
12921
+ }
12922
+ function MagicWand({
12923
+ value,
12924
+ onValueChange,
12925
+ actions,
12926
+ appearance = "floating",
12927
+ autoHide = true,
12928
+ rows = 6,
12929
+ placeholder,
12930
+ onAction
12931
+ }) {
12932
+ const taRef = react.useRef(null);
12933
+ const wandRef = react.useRef(null);
12934
+ const [sel, setSel] = react.useState(null);
12935
+ const [pos, setPos] = react.useState(null);
12936
+ const [busy, setBusy] = react.useState(null);
12937
+ const measureSelection = react.useCallback(() => {
12938
+ const ta = taRef.current;
12939
+ if (!ta) return;
12940
+ const start = ta.selectionStart ?? 0;
12941
+ const end = ta.selectionEnd ?? 0;
12942
+ if (start === end) {
12943
+ setSel(null);
12944
+ setPos(null);
12945
+ return;
12946
+ }
12947
+ const text = ta.value.slice(start, end);
12948
+ setSel({ start, end, text });
12949
+ const rect = caretRect(ta, start, end);
12950
+ if (rect) setPos({ x: rect.x, y: rect.y });
12951
+ }, []);
12952
+ react.useEffect(() => {
12953
+ if (!autoHide) return;
12954
+ const onScroll = () => {
12955
+ setSel(null);
12956
+ setPos(null);
12957
+ };
12958
+ window.addEventListener("scroll", onScroll, true);
12959
+ return () => window.removeEventListener("scroll", onScroll, true);
12960
+ }, [autoHide]);
12961
+ react.useEffect(() => {
12962
+ if (!autoHide) return;
12963
+ const onDocMouseDown = (e) => {
12964
+ if (wandRef.current?.contains(e.target)) return;
12965
+ if (taRef.current?.contains(e.target)) return;
12966
+ setSel(null);
12967
+ setPos(null);
12968
+ };
12969
+ document.addEventListener("mousedown", onDocMouseDown);
12970
+ return () => document.removeEventListener("mousedown", onDocMouseDown);
12971
+ }, [autoHide]);
12972
+ const handleAction = async (action) => {
12973
+ if (!sel) return;
12974
+ setBusy(action.id);
12975
+ try {
12976
+ const replacement = await action.run(sel.text, sel);
12977
+ const next = value.slice(0, sel.start) + replacement + value.slice(sel.end);
12978
+ onValueChange(next);
12979
+ onAction?.(action, sel, replacement);
12980
+ } finally {
12981
+ setBusy(null);
12982
+ setSel(null);
12983
+ setPos(null);
12984
+ }
12985
+ };
12986
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
12987
+ /* @__PURE__ */ jsxRuntime.jsx(
12988
+ Textarea,
12989
+ {
12990
+ ref: taRef,
12991
+ value,
12992
+ onValueChange,
12993
+ onSelect: measureSelection,
12994
+ onKeyUp: measureSelection,
12995
+ onMouseUp: measureSelection,
12996
+ rows,
12997
+ placeholder
12998
+ }
12999
+ ),
13000
+ sel && pos && /* @__PURE__ */ jsxRuntime.jsx(
13001
+ Wand,
13002
+ {
13003
+ ref: wandRef,
13004
+ pos,
13005
+ actions,
13006
+ appearance,
13007
+ busy,
13008
+ onAction: handleAction,
13009
+ selectionLength: sel.text.length
13010
+ }
13011
+ )
13012
+ ] });
13013
+ }
13014
+ function Wand({
13015
+ ref,
13016
+ pos,
13017
+ actions,
13018
+ appearance,
13019
+ busy,
13020
+ onAction,
13021
+ selectionLength
13022
+ }) {
13023
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13024
+ "div",
13025
+ {
13026
+ ref,
13027
+ className: "absolute z-20 -translate-x-1/2 -translate-y-full",
13028
+ style: { left: pos.x, top: pos.y - 6 },
13029
+ children: [
13030
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 rounded-full border border-violet-300 bg-white px-1.5 py-1 shadow-lg ring-1 ring-violet-200 dark:border-violet-700 dark:bg-zinc-900 dark:ring-violet-900", children: [
13031
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1 mr-0.5 inline-flex items-center gap-1 text-[10px] font-medium text-violet-700 dark:text-violet-300", children: [
13032
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2726" }),
13033
+ appearance === "floating" && /* @__PURE__ */ jsxRuntime.jsxs(Badge, { color: "violet", children: [
13034
+ selectionLength,
13035
+ " chars"
13036
+ ] })
13037
+ ] }),
13038
+ actions.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
13039
+ Action,
13040
+ {
13041
+ size: "sm",
13042
+ variant: "ghost",
13043
+ onClick: () => onAction(a),
13044
+ disabled: busy !== null,
13045
+ title: a.hint,
13046
+ children: [
13047
+ busy === a.id ? "\u2026" : appearance === "pill" ? a.label[0] : a.label,
13048
+ appearance === "floating" && a.tag && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 rounded-full bg-zinc-100 px-1 text-[9px] font-medium text-zinc-500 dark:bg-zinc-800", children: a.tag })
13049
+ ]
13050
+ },
13051
+ a.id
13052
+ ))
13053
+ ] }),
13054
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-1/2 top-full -translate-x-1/2 -translate-y-px", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 w-2 rotate-45 border-b border-r border-violet-300 bg-white dark:border-violet-700 dark:bg-zinc-900" }) })
13055
+ ]
13056
+ }
13057
+ );
13058
+ }
13059
+ function caretRect(ta, start, end) {
13060
+ const div = document.createElement("div");
13061
+ const style = getComputedStyle(ta);
13062
+ const props = [
13063
+ "boxSizing",
13064
+ "width",
13065
+ "height",
13066
+ "overflowX",
13067
+ "overflowY",
13068
+ "borderTopWidth",
13069
+ "borderRightWidth",
13070
+ "borderBottomWidth",
13071
+ "borderLeftWidth",
13072
+ "paddingTop",
13073
+ "paddingRight",
13074
+ "paddingBottom",
13075
+ "paddingLeft",
13076
+ "fontStyle",
13077
+ "fontVariant",
13078
+ "fontWeight",
13079
+ "fontStretch",
13080
+ "fontSize",
13081
+ "fontSizeAdjust",
13082
+ "lineHeight",
13083
+ "fontFamily",
13084
+ "textAlign",
13085
+ "textTransform",
13086
+ "textIndent",
13087
+ "letterSpacing",
13088
+ "wordSpacing",
13089
+ "tabSize"
13090
+ ];
13091
+ for (const p of props) div.style[p] = style[p];
13092
+ div.style.position = "absolute";
13093
+ div.style.top = "-9999px";
13094
+ div.style.left = "-9999px";
13095
+ div.style.whiteSpace = "pre-wrap";
13096
+ div.style.wordWrap = "break-word";
13097
+ const value = ta.value;
13098
+ div.textContent = value.substring(0, start);
13099
+ const startSpan = document.createElement("span");
13100
+ startSpan.textContent = value.substring(start, end) || ".";
13101
+ div.appendChild(startSpan);
13102
+ document.body.appendChild(div);
13103
+ const taRect = ta.getBoundingClientRect();
13104
+ const parentRect = ta.offsetParent?.getBoundingClientRect() ?? taRect;
13105
+ const spanRect = startSpan.getBoundingClientRect();
13106
+ const divRect = div.getBoundingClientRect();
13107
+ const offsetX = spanRect.left - divRect.left;
13108
+ const offsetY = spanRect.top - divRect.top;
13109
+ document.body.removeChild(div);
13110
+ const x = taRect.left - parentRect.left + offsetX + spanRect.width / 2;
13111
+ const y = taRect.top - parentRect.top + offsetY - ta.scrollTop;
13112
+ return { x, y };
13113
+ }
11843
13114
 
11844
13115
  exports.Accordion = Accordion;
11845
13116
  exports.AccordionPanel = AccordionPanel;
@@ -11857,6 +13128,7 @@ exports.Callout = Callout;
11857
13128
  exports.Card = Card;
11858
13129
  exports.Carousel = Carousel;
11859
13130
  exports.Chart = Chart;
13131
+ exports.ChatDrawer = ChatDrawer;
11860
13132
  exports.Checkbox = Checkbox;
11861
13133
  exports.CheckboxGroup = CheckboxGroup;
11862
13134
  exports.ColorPicker = ColorPicker;
@@ -11877,10 +13149,13 @@ exports.FileUpload = FileUpload;
11877
13149
  exports.Heading = Heading;
11878
13150
  exports.Icon = Icon;
11879
13151
  exports.Input = Input;
13152
+ exports.InputTag = InputTag;
11880
13153
  exports.Kanban = Kanban;
13154
+ exports.MagicWand = MagicWand;
11881
13155
  exports.Menu = Menu2;
11882
13156
  exports.MobileMenu = MobileMenu;
11883
13157
  exports.Modal = Modal;
13158
+ exports.MoodMeter = MoodMeter;
11884
13159
  exports.MultiSwitch = MultiSwitch;
11885
13160
  exports.Navbar = Navbar;
11886
13161
  exports.OtpInput = OtpInput;
@@ -11890,7 +13165,9 @@ exports.Popover = Popover;
11890
13165
  exports.Portal = Portal;
11891
13166
  exports.Profile = Profile;
11892
13167
  exports.Progress = Progress;
13168
+ exports.PromptInput = PromptInput;
11893
13169
  exports.RadioGroup = RadioGroup;
13170
+ exports.ReasonTag = ReasonTag;
11894
13171
  exports.SKIN_TONES = SKIN_TONES;
11895
13172
  exports.Select = Select;
11896
13173
  exports.Separator = Separator;
@@ -11910,8 +13187,11 @@ exports.TreeNav = TreeNav;
11910
13187
  exports.applyTone = applyTone;
11911
13188
  exports.cn = cn;
11912
13189
  exports.configureIcons = configureIcons;
13190
+ exports.contentEditableAdapter = contentEditableAdapter;
13191
+ exports.controlledAdapter = controlledAdapter;
11913
13192
  exports.find = find;
11914
13193
  exports.hasSkinTones = hasSkinTones;
13194
+ exports.inputAdapter = inputAdapter;
11915
13195
  exports.registerExtension = registerExtension;
11916
13196
  exports.registerExtensions = registerExtensions;
11917
13197
  exports.registerIconSet = registerIconSet;
@@ -11921,6 +13201,7 @@ exports.sanitizeHref = sanitizeHref;
11921
13201
  exports.sanitizeHtml = sanitizeHtml;
11922
13202
  exports.search = search;
11923
13203
  exports.skinTones = skinTones;
13204
+ exports.textareaAdapter = textareaAdapter;
11924
13205
  exports.useAccordion = useAccordion;
11925
13206
  exports.useAccordionPanel = useAccordionPanel;
11926
13207
  exports.useAccordionSection = useAccordionSection;