@bikdotai/bik-component-library 0.0.853 → 0.0.855
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/cjs/components/add-variableV2/AddDataPill.js +10 -0
- package/dist/cjs/components/add-variableV2/AddDataPill.js.map +1 -0
- package/dist/cjs/components/agent-builder/AgentBuilder.js +1 -1
- package/dist/cjs/components/agent-builder/AgentBuilder.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/ConfigToolPanel.js +11 -11
- package/dist/cjs/components/agent-builder/components/ConfigToolPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/CreateSubAgentPanel.js +5 -5
- package/dist/cjs/components/agent-builder/components/CreateSubAgentPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/MentionEditor.js +7 -1
- package/dist/cjs/components/agent-builder/components/MentionEditor.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/MentionField.js +1 -1
- package/dist/cjs/components/agent-builder/components/MentionField.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/MentionPicker.js +41 -14
- package/dist/cjs/components/agent-builder/components/MentionPicker.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js +6 -5
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/ToolInstructionsField.js +2 -2
- package/dist/cjs/components/agent-builder/components/ToolInstructionsField.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/VariableInlineField.js +65 -0
- package/dist/cjs/components/agent-builder/components/VariableInlineField.js.map +1 -0
- package/dist/cjs/components/agent-builder/components/VariableTriggerArea.js +10 -0
- package/dist/cjs/components/agent-builder/components/VariableTriggerArea.js.map +1 -0
- package/dist/cjs/components/agent-builder/constants/tools.js +1 -1
- package/dist/cjs/components/agent-builder/constants/tools.js.map +1 -1
- package/dist/cjs/components/agent-builder/context/AgentBuilderContext.js +1 -1
- package/dist/cjs/components/agent-builder/context/AgentBuilderContext.js.map +1 -1
- package/dist/cjs/components/agent-builder/steps/Step3HowItResponds.js +1 -1
- package/dist/cjs/components/agent-builder/steps/Step3HowItResponds.js.map +1 -1
- package/dist/cjs/components/agent-builder/utils/mentionSerialization.js +4 -4
- package/dist/cjs/components/agent-builder/utils/mentionSerialization.js.map +1 -1
- package/dist/cjs/components/toaster/Toaster.js +1 -1
- package/dist/cjs/components/toaster/Toaster.js.map +1 -1
- package/dist/cjs/components/toaster/Toaster.styled.js +7 -7
- package/dist/cjs/components/toaster/Toaster.styled.js.map +1 -1
- package/dist/cjs/components/variable-picker-v3/Content.js +1 -1
- package/dist/cjs/components/variable-picker-v3/Content.js.map +1 -1
- package/dist/cjs/editor/BikEditor.js +1 -1
- package/dist/cjs/editor/BikEditor.js.map +1 -1
- package/dist/cjs/editor/BikEditor.styles.js +8 -0
- package/dist/cjs/editor/BikEditor.styles.js.map +1 -1
- package/dist/cjs/editor/BikEditor.types.js.map +1 -1
- package/dist/cjs/editor/extensions/mention/MentionDropdown.js +1 -1
- package/dist/cjs/editor/extensions/mention/MentionDropdown.js.map +1 -1
- package/dist/cjs/editor/extensions/mention/MentionExtension.js +1 -1
- package/dist/cjs/editor/extensions/mention/MentionExtension.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/esm/components/add-variableV2/AddDataPill.d.ts +24 -0
- package/dist/esm/components/add-variableV2/AddDataPill.js +33 -0
- package/dist/esm/components/add-variableV2/AddDataPill.js.map +1 -0
- package/dist/esm/components/add-variableV2/index.d.ts +1 -0
- package/dist/esm/components/agent-builder/AgentBuilder.js +76 -74
- package/dist/esm/components/agent-builder/AgentBuilder.js.map +1 -1
- package/dist/esm/components/agent-builder/AgentBuilder.model.d.ts +8 -0
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.d.ts +8 -0
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.js +182 -136
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.d.ts +3 -0
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.js +195 -188
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/MentionEditor.d.ts +12 -0
- package/dist/esm/components/agent-builder/components/MentionEditor.js +144 -103
- package/dist/esm/components/agent-builder/components/MentionEditor.js.map +1 -1
- package/dist/esm/components/agent-builder/components/MentionField.js +48 -45
- package/dist/esm/components/agent-builder/components/MentionField.js.map +1 -1
- package/dist/esm/components/agent-builder/components/MentionPicker.d.ts +14 -1
- package/dist/esm/components/agent-builder/components/MentionPicker.js +286 -218
- package/dist/esm/components/agent-builder/components/MentionPicker.js.map +1 -1
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.d.ts +8 -0
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js +192 -176
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/ToolInstructionsField.d.ts +9 -0
- package/dist/esm/components/agent-builder/components/ToolInstructionsField.js +67 -48
- package/dist/esm/components/agent-builder/components/ToolInstructionsField.js.map +1 -1
- package/dist/esm/components/agent-builder/components/VariableInlineField.d.ts +26 -0
- package/dist/esm/components/agent-builder/components/VariableInlineField.js +149 -0
- package/dist/esm/components/agent-builder/components/VariableInlineField.js.map +1 -0
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.d.ts +46 -0
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.js +118 -0
- package/dist/esm/components/agent-builder/components/VariableTriggerArea.js.map +1 -0
- package/dist/esm/components/agent-builder/constants/tools.d.ts +1 -1
- package/dist/esm/components/agent-builder/constants/tools.js +14 -13
- package/dist/esm/components/agent-builder/constants/tools.js.map +1 -1
- package/dist/esm/components/agent-builder/context/AgentBuilderContext.d.ts +7 -0
- package/dist/esm/components/agent-builder/context/AgentBuilderContext.js +99 -96
- package/dist/esm/components/agent-builder/context/AgentBuilderContext.js.map +1 -1
- package/dist/esm/components/agent-builder/steps/Step3HowItResponds.js +164 -160
- package/dist/esm/components/agent-builder/steps/Step3HowItResponds.js.map +1 -1
- package/dist/esm/components/agent-builder/utils/mentionSerialization.d.ts +14 -4
- package/dist/esm/components/agent-builder/utils/mentionSerialization.js +54 -36
- package/dist/esm/components/agent-builder/utils/mentionSerialization.js.map +1 -1
- package/dist/esm/components/toaster/Toaster.js +30 -25
- package/dist/esm/components/toaster/Toaster.js.map +1 -1
- package/dist/esm/components/toaster/Toaster.styled.js +5 -5
- package/dist/esm/components/toaster/Toaster.styled.js.map +1 -1
- package/dist/esm/components/variable-picker-v3/Content.js +16 -15
- package/dist/esm/components/variable-picker-v3/Content.js.map +1 -1
- package/dist/esm/editor/BikEditor.js +40 -34
- package/dist/esm/editor/BikEditor.js.map +1 -1
- package/dist/esm/editor/BikEditor.styles.js +20 -12
- package/dist/esm/editor/BikEditor.styles.js.map +1 -1
- package/dist/esm/editor/BikEditor.types.d.ts +9 -0
- package/dist/esm/editor/BikEditor.types.js.map +1 -1
- package/dist/esm/editor/extensions/mention/MentionDropdown.js +28 -28
- package/dist/esm/editor/extensions/mention/MentionDropdown.js.map +1 -1
- package/dist/esm/editor/extensions/mention/MentionExtension.js +23 -19
- package/dist/esm/editor/extensions/mention/MentionExtension.js.map +1 -1
- package/dist/esm/icons/index.d.ts +25 -25
- package/dist/esm/index.js +543 -541
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsxs as u, jsx as d } from "react/jsx-runtime";
|
|
2
2
|
import { getMarkRange as Ee } from "../node_modules/@tiptap/core/dist/index.js";
|
|
3
|
-
import { useEditor as
|
|
4
|
-
import { forwardRef as
|
|
3
|
+
import { useEditor as Te, EditorContent as ee } from "@tiptap/react";
|
|
4
|
+
import { forwardRef as Ae, useState as x, useRef as a, useEffect as Ie, useImperativeHandle as Je } from "react";
|
|
5
5
|
import { BodyCaption as te } from "../components/TypographyStyle.js";
|
|
6
|
-
import { BikEditorShell as
|
|
6
|
+
import { BikEditorShell as Me, BikJsonHeader as Re, BikJsonBody as Le, BikJsonEmptyState as Oe, BikJsonError as Fe } from "./BikEditor.styles.js";
|
|
7
7
|
import { DEFAULT_FORMAT_STATE as ne } from "./BikEditor.types.js";
|
|
8
|
-
import { buildJsonCodeBlockHtml as je, buildSectionedContent as oe, normalizeHtml as i, extractActiveFormats as re, extractContent as se, getCodeBlockText as g, parseJson as p, extractBodyContent as ze, extractSectionContent as Ne, setCodeBlockText as
|
|
8
|
+
import { buildJsonCodeBlockHtml as je, buildSectionedContent as oe, normalizeHtml as i, extractActiveFormats as re, extractContent as se, getCodeBlockText as g, parseJson as p, extractBodyContent as ze, extractSectionContent as Ne, setCodeBlockText as v, findSectionEndPos as ie, findSectionStartPos as He, setSectionContentInEditor as I, insertInlineHtml as we } from "./BikEditor.utils.js";
|
|
9
9
|
import { buildExtensions as Pe } from "./extensions/buildExtensions.js";
|
|
10
10
|
import { LinkBubbleMenu as De } from "./floating/LinkBubbleMenu.js";
|
|
11
11
|
import qe from "../icons/BIK AI specific/WandSparkles.js";
|
|
@@ -14,10 +14,10 @@ import $e from "../icons/Actions/Common actions/Code.js";
|
|
|
14
14
|
import We from "../icons/Informational/General/Info.js";
|
|
15
15
|
function Ve(k) {
|
|
16
16
|
return Object.entries(k).map(
|
|
17
|
-
([
|
|
17
|
+
([b, C]) => `${b.replace(/([A-Z])/g, (y) => `-${y.toLowerCase()}`)}:${C}`
|
|
18
18
|
).join(";");
|
|
19
19
|
}
|
|
20
|
-
const _e = (k,
|
|
20
|
+
const _e = (k, b) => {
|
|
21
21
|
const {
|
|
22
22
|
initialContent: C,
|
|
23
23
|
sections: y,
|
|
@@ -32,10 +32,10 @@ const _e = (k, v) => {
|
|
|
32
32
|
slashCommands: S,
|
|
33
33
|
link: me,
|
|
34
34
|
onPaste: fe,
|
|
35
|
-
onReady:
|
|
36
|
-
onChange:
|
|
35
|
+
onReady: M,
|
|
36
|
+
onChange: R,
|
|
37
37
|
onSend: E,
|
|
38
|
-
onFocus:
|
|
38
|
+
onFocus: L,
|
|
39
39
|
onBlur: O,
|
|
40
40
|
onSelectionChange: F,
|
|
41
41
|
minHeight: ge,
|
|
@@ -45,19 +45,19 @@ const _e = (k, v) => {
|
|
|
45
45
|
editorClassName: j,
|
|
46
46
|
editorStyle: z,
|
|
47
47
|
renderJsonError: N
|
|
48
|
-
} = k, m = !!B?.jsonMode, [f, H] = x(null), [Se, w] = x(!1), [
|
|
48
|
+
} = k, m = !!B?.jsonMode, [f, H] = x(null), [Se, w] = x(!1), [T, P] = x(
|
|
49
49
|
m && !(C ?? "").trim()
|
|
50
50
|
), [ke, D] = x(!1), ye = m ? je(C ?? "") : y?.length ? oe(
|
|
51
51
|
i(C ?? ""),
|
|
52
52
|
y.map((e) => ({ ...e, content: i(e.content) }))
|
|
53
|
-
) : i(C ?? ""),
|
|
54
|
-
U.current =
|
|
55
|
-
const $ = a(
|
|
56
|
-
$.current =
|
|
53
|
+
) : i(C ?? ""), A = a([]), q = a(!1), U = a(M);
|
|
54
|
+
U.current = M;
|
|
55
|
+
const $ = a(R);
|
|
56
|
+
$.current = R;
|
|
57
57
|
const W = a(F);
|
|
58
58
|
W.current = F;
|
|
59
|
-
const V = a(ne), _ = a(
|
|
60
|
-
_.current =
|
|
59
|
+
const V = a(ne), _ = a(L);
|
|
60
|
+
_.current = L;
|
|
61
61
|
const Q = a(O);
|
|
62
62
|
Q.current = O;
|
|
63
63
|
const Z = a(E);
|
|
@@ -68,7 +68,7 @@ const _e = (k, v) => {
|
|
|
68
68
|
K.current = l?.teams ?? [];
|
|
69
69
|
const X = a(S?.items ?? []);
|
|
70
70
|
X.current = S?.items ?? [];
|
|
71
|
-
const n =
|
|
71
|
+
const n = Te({
|
|
72
72
|
extensions: Pe({
|
|
73
73
|
features: B,
|
|
74
74
|
placeholder: k.placeholder,
|
|
@@ -122,15 +122,15 @@ const _e = (k, v) => {
|
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
function s(e) {
|
|
125
|
-
n ? e(n) :
|
|
125
|
+
n ? e(n) : A.current.push(e);
|
|
126
126
|
}
|
|
127
127
|
Ie(() => {
|
|
128
|
-
if (n && (
|
|
128
|
+
if (n && (A.current.length > 0 && A.current.splice(0).forEach((t) => t(n)), q.current || (q.current = !0, U.current?.()), m)) {
|
|
129
129
|
const e = g(n), t = p(e);
|
|
130
130
|
H(t.valid ? null : t), P(!e.trim());
|
|
131
131
|
}
|
|
132
132
|
}, [n, m]), Je(
|
|
133
|
-
|
|
133
|
+
b,
|
|
134
134
|
() => ({
|
|
135
135
|
// ── Focus ────────────────────────────────────────────────────────
|
|
136
136
|
focus: (e) => s((t) => t.commands.focus(e)),
|
|
@@ -295,10 +295,10 @@ const _e = (k, v) => {
|
|
|
295
295
|
n && (t !== void 0 ? n.chain().focus().extendMarkRange("link").command(({ tr: o, state: r }) => {
|
|
296
296
|
const { from: c, to: h } = o.selection, Y = r.schema.marks.link;
|
|
297
297
|
if (!Y) return !1;
|
|
298
|
-
const
|
|
298
|
+
const ve = r.schema.text(t, [
|
|
299
299
|
Y.create({ href: e })
|
|
300
|
-
]),
|
|
301
|
-
return o.replaceWith(c, h, [
|
|
300
|
+
]), be = r.schema.text(" ");
|
|
301
|
+
return o.replaceWith(c, h, [ve, be]), !0;
|
|
302
302
|
}).run() : n.chain().focus().extendMarkRange("link").setLink({ href: e }).insertContent(" ").run());
|
|
303
303
|
},
|
|
304
304
|
updateLink: (e) => n?.chain().focus().extendMarkRange("link").setLink({ href: e }).run(),
|
|
@@ -306,6 +306,12 @@ const _e = (k, v) => {
|
|
|
306
306
|
insertEmoji: (e) => n?.chain().focus().insertContent(e).run(),
|
|
307
307
|
insertVariable: (e) => n?.chain().focus().insertContent(`{{${e}}}`).run(),
|
|
308
308
|
insertHtml: (e) => n?.commands.insertContent(i(e)),
|
|
309
|
+
openMentionMenu: (e = "@") => {
|
|
310
|
+
if (!n)
|
|
311
|
+
return;
|
|
312
|
+
const { to: t } = n.state.selection, o = t > 1 ? n.state.doc.textBetween(t - 1, t) : "", r = o !== "" && !/\s/.test(o);
|
|
313
|
+
n.chain().focus().setTextSelection(t).insertContent(r ? ` ${e}` : e).run();
|
|
314
|
+
},
|
|
309
315
|
undo: () => n?.chain().focus().undo().run(),
|
|
310
316
|
redo: () => n?.chain().focus().redo().run(),
|
|
311
317
|
canUndo: () => n?.can().undo() ?? !1,
|
|
@@ -317,16 +323,16 @@ const _e = (k, v) => {
|
|
|
317
323
|
// ── JSON body ─────────────────────────────────────────────────────
|
|
318
324
|
json: B?.jsonMode ? {
|
|
319
325
|
getText: () => n ? g(n) : "",
|
|
320
|
-
setText: (e) => s((t) =>
|
|
326
|
+
setText: (e) => s((t) => v(t, e)),
|
|
321
327
|
parse: () => p(n ? g(n) : ""),
|
|
322
328
|
isValid: () => p(n ? g(n) : "").valid,
|
|
323
329
|
format: (e = 2) => s((t) => {
|
|
324
330
|
const { valid: o, value: r } = p(g(t));
|
|
325
|
-
!o || r === null ||
|
|
331
|
+
!o || r === null || v(t, JSON.stringify(r, null, e));
|
|
326
332
|
}),
|
|
327
333
|
minify: () => s((e) => {
|
|
328
334
|
const { valid: t, value: o } = p(g(e));
|
|
329
|
-
!t || o === null ||
|
|
335
|
+
!t || o === null || v(e, JSON.stringify(o));
|
|
330
336
|
})
|
|
331
337
|
} : void 0
|
|
332
338
|
}),
|
|
@@ -336,12 +342,12 @@ const _e = (k, v) => {
|
|
|
336
342
|
const Be = () => {
|
|
337
343
|
if (!n) return;
|
|
338
344
|
const { valid: e, value: t } = p(g(n));
|
|
339
|
-
!e || t === null ||
|
|
345
|
+
!e || t === null || v(n, JSON.stringify(t, null, 2));
|
|
340
346
|
}, xe = () => {
|
|
341
347
|
n && (navigator.clipboard?.writeText(g(n)), w(!0), setTimeout(() => w(!1), 1500));
|
|
342
348
|
};
|
|
343
349
|
return n ? /* @__PURE__ */ u(
|
|
344
|
-
|
|
350
|
+
Me,
|
|
345
351
|
{
|
|
346
352
|
minHeight: ge,
|
|
347
353
|
maxHeight: he,
|
|
@@ -350,7 +356,7 @@ const _e = (k, v) => {
|
|
|
350
356
|
style: pe,
|
|
351
357
|
className: Ce,
|
|
352
358
|
children: [
|
|
353
|
-
m && /* @__PURE__ */ u(
|
|
359
|
+
m && /* @__PURE__ */ u(Re, { children: [
|
|
354
360
|
/* @__PURE__ */ d("span", { className: "bik-json-header-label", children: "JSON" }),
|
|
355
361
|
/* @__PURE__ */ u("div", { className: "bik-json-header-actions", children: [
|
|
356
362
|
/* @__PURE__ */ u(
|
|
@@ -358,7 +364,7 @@ const _e = (k, v) => {
|
|
|
358
364
|
{
|
|
359
365
|
type: "button",
|
|
360
366
|
onClick: Be,
|
|
361
|
-
disabled: !!f ||
|
|
367
|
+
disabled: !!f || T,
|
|
362
368
|
title: "Format JSON",
|
|
363
369
|
children: [
|
|
364
370
|
/* @__PURE__ */ d(qe, { size: 16 }),
|
|
@@ -371,7 +377,7 @@ const _e = (k, v) => {
|
|
|
371
377
|
{
|
|
372
378
|
type: "button",
|
|
373
379
|
onClick: xe,
|
|
374
|
-
disabled:
|
|
380
|
+
disabled: T,
|
|
375
381
|
title: "Copy JSON",
|
|
376
382
|
children: [
|
|
377
383
|
/* @__PURE__ */ d(Ue, { size: 16 }),
|
|
@@ -381,9 +387,9 @@ const _e = (k, v) => {
|
|
|
381
387
|
)
|
|
382
388
|
] })
|
|
383
389
|
] }),
|
|
384
|
-
m ? /* @__PURE__ */ u(
|
|
390
|
+
m ? /* @__PURE__ */ u(Le, { $error: !!f, children: [
|
|
385
391
|
/* @__PURE__ */ d(ee, { editor: n }),
|
|
386
|
-
|
|
392
|
+
T && !ke && /* @__PURE__ */ u(Oe, { "aria-hidden": !0, children: [
|
|
387
393
|
/* @__PURE__ */ d($e, { size: 20 }),
|
|
388
394
|
/* @__PURE__ */ d("span", { children: k.placeholder ?? "Type or paste JSON here" })
|
|
389
395
|
] })
|
|
@@ -405,7 +411,7 @@ const _e = (k, v) => {
|
|
|
405
411
|
]
|
|
406
412
|
}
|
|
407
413
|
) : null;
|
|
408
|
-
}, Qe =
|
|
414
|
+
}, Qe = Ae(
|
|
409
415
|
_e
|
|
410
416
|
);
|
|
411
417
|
Qe.displayName = "BikEditor";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BikEditor.js","sources":["../../../src/editor/BikEditor.tsx"],"sourcesContent":["'use client';\n\n/**\n * IMPLEMENTATION LAYER — TipTap-specific.\n * If the underlying editor is swapped, this file changes; BikEditor.types.ts and\n * src/editor/index.ts (the consumer contract) do NOT change.\n */\nimport { Editor, getMarkRange } from '@tiptap/core';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport React, {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { BodyCaption } from '@src/components/TypographyStyle';\nimport { Code, Copy, Info, WandSparkles } from '../icons';\nimport {\n\tBikEditorShell,\n\tBikJsonBody,\n\tBikJsonEmptyState,\n\tBikJsonError,\n\tBikJsonHeader,\n} from './BikEditor.styles';\nimport {\n\tBikEditorProps,\n\tBikEditorRef,\n\tDEFAULT_FORMAT_STATE,\n\tFormatState,\n\tJsonParseResult,\n} from './BikEditor.types';\nimport {\n\tbuildJsonCodeBlockHtml,\n\tbuildSectionedContent,\n\textractActiveFormats,\n\textractBodyContent,\n\textractContent,\n\textractSectionContent,\n\tfindSectionEndPos,\n\tfindSectionStartPos,\n\tgetCodeBlockText,\n\tinsertInlineHtml,\n\tnormalizeHtml,\n\tparseJson,\n\tsetCodeBlockText,\n\tsetSectionContentInEditor,\n} from './BikEditor.utils';\nimport { buildExtensions } from './extensions/buildExtensions';\nimport { LinkBubbleMenu } from './floating/LinkBubbleMenu';\n\n/** Convert React.CSSProperties to an inline CSS string for editorProps.attributes. */\nfunction cssToString(style: React.CSSProperties): string {\n\treturn Object.entries(style)\n\t\t.map(\n\t\t\t([k, v]) => `${k.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`)}:${v}`,\n\t\t)\n\t\t.join(';');\n}\n\nconst BikEditorInner = (\n\tprops: BikEditorProps,\n\tref: React.Ref<BikEditorRef>,\n) => {\n\tconst {\n\t\tinitialContent,\n\t\tsections,\n\t\tfeatures,\n\t\tdisabled,\n\t\tmaxCharacters,\n\t\tcharacterLimit,\n\t\tcharacterLimitHard,\n\t\tshortcuts,\n\t\tsendShortcut,\n\t\tmentions,\n\t\tslashCommands,\n\t\tlink,\n\t\tonPaste,\n\t\tonReady,\n\t\tonChange,\n\t\tonSend,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonSelectionChange,\n\t\tminHeight,\n\t\tmaxHeight,\n\t\tstyle,\n\t\tclassName,\n\t\teditorClassName,\n\t\teditorStyle,\n\t\trenderJsonError,\n\t} = props;\n\n\tconst isJsonMode = !!features?.jsonMode;\n\n\t// Live JSON parse error, shown inside the editor when jsonMode is on.\n\t// null = valid (or not applicable) → nothing rendered.\n\tconst [jsonError, setJsonError] = useState<JsonParseResult | null>(null);\n\t// Transient \"Copied\" state for the jsonMode copy button.\n\tconst [jsonCopied, setJsonCopied] = useState(false);\n\t// jsonMode: no content yet → centered code-glyph + placeholder overlay.\n\tconst [jsonEmpty, setJsonEmpty] = useState(\n\t\tisJsonMode && !(initialContent ?? '').trim(),\n\t);\n\t// jsonMode: hide the placeholder overlay while the editor is focused, so\n\t// clicking in gives a clean field to type into.\n\tconst [jsonFocused, setJsonFocused] = useState(false);\n\n\t// JSON body mode: treat initialContent as raw JSON text and wrap it in a code\n\t// block. Skips section/HTML normalisation entirely.\n\tconst initialEditorContent = isJsonMode\n\t\t? buildJsonCodeBlockHtml(initialContent ?? '')\n\t\t: sections?.length\n\t\t? buildSectionedContent(\n\t\t\t\tnormalizeHtml(initialContent ?? ''),\n\t\t\t\tsections.map((s) => ({ ...s, content: normalizeHtml(s.content) })),\n\t\t )\n\t\t: normalizeHtml(initialContent ?? '');\n\n\t// ── Command queue ─────────────────────────────────────────────────────────\n\t// TipTap's useEditor initializes asynchronously; the editor instance is null\n\t// until the first commit. Any imperative method called before the editor is\n\t// ready is enqueued here and flushed automatically once it becomes non-null.\n\t// Consumers never need setTimeout or readiness guards.\n\tconst pendingQueue = useRef<Array<(e: Editor) => void>>([]);\n\tconst hasCalledOnReady = useRef(false);\n\t// Keep stable refs to all callbacks so useEditor receives the same function\n\t// identity on every render — prevents TipTap from re-registering event\n\t// handlers every time the parent re-renders with new inline function props.\n\tconst onReadyRef = useRef(onReady);\n\tonReadyRef.current = onReady;\n\tconst onChangeRef = useRef(onChange);\n\tonChangeRef.current = onChange;\n\tconst onSelectionChangeRef = useRef(onSelectionChange);\n\tonSelectionChangeRef.current = onSelectionChange;\n\tconst prevFormatsRef = useRef<FormatState>(DEFAULT_FORMAT_STATE);\n\tconst onFocusRef = useRef(onFocus);\n\tonFocusRef.current = onFocus;\n\tconst onBlurRef = useRef(onBlur);\n\tonBlurRef.current = onBlur;\n\tconst onSendRef = useRef(onSend);\n\tonSendRef.current = onSend;\n\tconst agentMentionsRef = useRef(mentions?.agents ?? []);\n\tagentMentionsRef.current = mentions?.agents ?? [];\n\tconst teamMentionsRef = useRef(mentions?.teams ?? []);\n\tteamMentionsRef.current = mentions?.teams ?? [];\n\tconst slashCommandsRef = useRef(slashCommands?.items ?? []);\n\tslashCommandsRef.current = slashCommands?.items ?? [];\n\n\tconst editor = useEditor({\n\t\textensions: buildExtensions({\n\t\t\tfeatures,\n\t\t\tplaceholder: props.placeholder,\n\t\t\tmaxCharacters,\n\t\t\tcharacterLimit,\n\t\t\tcharacterLimitHard,\n\t\t\thasSections: (sections?.length ?? 0) > 0,\n\t\t\tmentions: {\n\t\t\t\tagents: mentions ? agentMentionsRef : undefined,\n\t\t\t\tteams: mentions ? teamMentionsRef : undefined,\n\t\t\t},\n\t\t\tslashCommands: slashCommands ? slashCommandsRef : undefined,\n\t\t\tonPaste,\n\t\t\tonSend: onSend ? (snapshot) => onSendRef.current?.(snapshot) : undefined,\n\t\t\tsendShortcut,\n\t\t\tshortcuts,\n\t\t\tonMentionSelected: mentions?.onSelect,\n\t\t\tonSlashCommandSelected: slashCommands?.onSelect,\n\t\t\trenderMentionItem: mentions?.renderItem,\n\t\t\trenderMentionDropdown: mentions?.renderDropdown,\n\t\t\tremoveMentionTriggerOnDismiss: mentions?.removeTriggerOnDismiss,\n\t\t\trenderMentionChipIcon: mentions?.renderChipIcon,\n\t\t\trenderSlashCommandItem: slashCommands?.renderItem,\n\t\t\trenderSlashCommandDropdown: slashCommands?.renderDropdown,\n\t\t}),\n\t\tcontent: initialEditorContent,\n\t\teditable: !disabled,\n\t\timmediatelyRender: false, // SSR-safe — NEVER remove this\n\t\teditorProps: {\n\t\t\tattributes: {\n\t\t\t\t...(editorClassName ? { class: editorClassName } : {}),\n\t\t\t\t...(editorStyle ? { style: cssToString(editorStyle) } : {}),\n\t\t\t},\n\t\t},\n\t\tonUpdate: ({ editor: e }) => {\n\t\t\tonChangeRef.current?.(extractContent(e));\n\t\t\tif (isJsonMode) {\n\t\t\t\tconst text = getCodeBlockText(e);\n\t\t\t\tconst result = parseJson(text);\n\t\t\t\tsetJsonError(result.valid ? null : result);\n\t\t\t\tsetJsonEmpty(!text.trim());\n\t\t\t}\n\t\t},\n\t\tonTransaction: ({ editor: e }) => {\n\t\t\tconst next = extractActiveFormats(e);\n\t\t\tconst prev = prevFormatsRef.current;\n\t\t\tconst changed =\n\t\t\t\tprev.bold !== next.bold ||\n\t\t\t\tprev.italic !== next.italic ||\n\t\t\t\tprev.underline !== next.underline ||\n\t\t\t\tprev.strike !== next.strike ||\n\t\t\t\tprev.bulletList !== next.bulletList ||\n\t\t\t\tprev.orderedList !== next.orderedList ||\n\t\t\t\tprev.blockquote !== next.blockquote ||\n\t\t\t\tprev.codeBlock !== next.codeBlock ||\n\t\t\t\tprev.superscript !== next.superscript ||\n\t\t\t\tprev.subscript !== next.subscript ||\n\t\t\t\tprev.textAlign !== next.textAlign ||\n\t\t\t\tprev.fontFamily !== next.fontFamily ||\n\t\t\t\tprev.fontSize !== next.fontSize ||\n\t\t\t\tprev.color !== next.color ||\n\t\t\t\tprev.highlight !== next.highlight ||\n\t\t\t\tprev.link?.href !== next.link?.href;\n\t\t\tif (changed) {\n\t\t\t\tprevFormatsRef.current = next;\n\t\t\t\tonSelectionChangeRef.current?.(next);\n\t\t\t}\n\t\t},\n\t\tonFocus: () => {\n\t\t\tsetJsonFocused(true);\n\t\t\tonFocusRef.current?.();\n\t\t},\n\t\tonBlur: () => {\n\t\t\tsetJsonFocused(false);\n\t\t\tonBlurRef.current?.();\n\t\t},\n\t});\n\n\t// ── enqueue ───────────────────────────────────────────────────────────────\n\t// Run immediately if the editor is ready; otherwise defer to the queue.\n\t// Closures passed to enqueue MUST capture all parameters explicitly —\n\t// they must NOT close over `editor` (which would be null at enqueue time).\n\tfunction enqueue(op: (e: Editor) => void): void {\n\t\tif (editor) {\n\t\t\top(editor);\n\t\t} else {\n\t\t\tpendingQueue.current.push(op);\n\t\t}\n\t}\n\n\t// Flush the pending queue and fire onReady when editor transitions null → ready.\n\tuseEffect(() => {\n\t\tif (!editor) return;\n\t\tif (pendingQueue.current.length > 0) {\n\t\t\tconst queue = pendingQueue.current.splice(0);\n\t\t\tqueue.forEach((op) => op(editor));\n\t\t}\n\t\tif (!hasCalledOnReady.current) {\n\t\t\thasCalledOnReady.current = true;\n\t\t\tonReadyRef.current?.();\n\t\t}\n\t\t// Surface an error for invalid initialContent immediately on mount.\n\t\tif (isJsonMode) {\n\t\t\tconst text = getCodeBlockText(editor);\n\t\t\tconst result = parseJson(text);\n\t\t\tsetJsonError(result.valid ? null : result);\n\t\t\tsetJsonEmpty(!text.trim());\n\t\t}\n\t}, [editor, isJsonMode]);\n\n\tuseImperativeHandle(\n\t\tref,\n\t\t() => ({\n\t\t\t// ── Focus ────────────────────────────────────────────────────────\n\t\t\tfocus: (position) => enqueue((e) => e.commands.focus(position)),\n\t\t\tblur: () => enqueue((e) => e.commands.blur()),\n\n\t\t\t// ── Content ──────────────────────────────────────────────────────\n\t\t\tclearContent: () => enqueue((e) => e.commands.clearContent(true)),\n\t\t\tsetContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.setContent(normalised, { emitUpdate: true }));\n\t\t\t},\n\t\t\tinsertContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContent(normalised));\n\t\t\t},\n\t\t\tinsertInlineContent: (html) => {\n\t\t\t\tenqueue((e) => insertInlineHtml(e, html));\n\t\t\t},\n\t\t\tinsertAtStart: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContentAt(1, normalised));\n\t\t\t},\n\t\t\tinsertBlock: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) =>\n\t\t\t\t\te.commands.insertContentAt(e.state.doc.content.size, normalised),\n\t\t\t\t);\n\t\t\t},\n\t\t\tappendInline: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\t// doc.content.size is after the last </p> (block boundary).\n\t\t\t\t// Subtract 1 to land inside the last paragraph so text appends\n\t\t\t\t// inline rather than being wrapped in a new paragraph each call.\n\t\t\t\tenqueue((e) =>\n\t\t\t\t\te.commands.insertContentAt(e.state.doc.content.size - 1, normalised),\n\t\t\t\t);\n\t\t\t},\n\t\t\t// Backwards-compatible aliases\n\t\t\tinsertAtEnd(html) {\n\t\t\t\tthis.insertBlock(html);\n\t\t\t},\n\t\t\tappendContent(html) {\n\t\t\t\tthis.appendInline(html);\n\t\t\t},\n\t\t\tgetContent: () =>\n\t\t\t\teditor\n\t\t\t\t\t? extractContent(editor)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\t\t\tgetJSON: () => editor?.getJSON() ?? null,\n\t\t\tgetMentions: () => {\n\t\t\t\tconst agentIds = new Set<string>();\n\t\t\t\tconst teamIds = new Set<string>();\n\t\t\t\tif (!editor) return { agentIds: [], teamIds: [] };\n\t\t\t\teditor.state.doc.descendants((node) => {\n\t\t\t\t\tif (node.type.name === 'mentionAgent' && node.attrs['id'] != null) {\n\t\t\t\t\t\tagentIds.add(String(node.attrs['id']));\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tnode.type.name === 'mentionTeam' &&\n\t\t\t\t\t\tnode.attrs['id'] != null\n\t\t\t\t\t) {\n\t\t\t\t\t\tteamIds.add(String(node.attrs['id']));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn { agentIds: Array.from(agentIds), teamIds: Array.from(teamIds) };\n\t\t\t},\n\n\t\t\t// ── Selection ────────────────────────────────────────────────────\n\t\t\tgetCursorPosition: () => {\n\t\t\t\tif (!editor) return { from: 0, to: 0 };\n\t\t\t\tconst { from, to } = editor.state.selection;\n\t\t\t\treturn { from, to };\n\t\t\t},\n\t\t\tinsertAtPosition: (pos, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContentAt(pos, normalised));\n\t\t\t},\n\t\t\tgetSelectedText: () => {\n\t\t\t\tif (!editor) return '';\n\t\t\t\tconst { state } = editor;\n\t\t\t\tconst { from, to, empty } = state.selection;\n\t\t\t\tif (!empty) {\n\t\t\t\t\treturn state.doc.textBetween(from, to, ' ');\n\t\t\t\t}\n\t\t\t\t// When the cursor is inside a link with nothing selected, return the\n\t\t\t\t// full link text — useful for pre-filling a link modal's text field.\n\t\t\t\tconst linkMarkType = state.schema.marks['link'];\n\t\t\t\tif (linkMarkType) {\n\t\t\t\t\tconst range = getMarkRange(state.doc.resolve(from), linkMarkType);\n\t\t\t\t\tif (range) {\n\t\t\t\t\t\treturn state.doc.textBetween(range.from, range.to, ' ');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn '';\n\t\t\t},\n\n\t\t\t// ── Character count ───────────────────────────────────────────────\n\t\t\tgetCharacterCount: () => ({\n\t\t\t\tcount:\n\t\t\t\t\teditor?.storage.characterCount?.characters?.() ??\n\t\t\t\t\teditor?.getText().length ??\n\t\t\t\t\t0,\n\t\t\t\tlimit: maxCharacters ?? null,\n\t\t\t}),\n\n\t\t\t// ── Sections ─────────────────────────────────────────────────────\n\t\t\tgetSectionContent: (sectionId) =>\n\t\t\t\teditor\n\t\t\t\t\t? extractSectionContent(editor, sectionId)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\n\t\t\tsetSectionContent: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, sectionId, normalised));\n\t\t\t},\n\n\t\t\tfocusSection: (sectionId) => {\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tif (sectionId === 'body') {\n\t\t\t\t\t\tlet endOfBody = e.state.doc.content.size - 1;\n\t\t\t\t\t\te.state.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tnode.type.name === 'sectionDivider' &&\n\t\t\t\t\t\t\t\tendOfBody === e.state.doc.content.size - 1\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tendOfBody = pos - 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn endOfBody === e.state.doc.content.size - 1;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (endOfBody < 1) endOfBody = 1;\n\t\t\t\t\t\te.chain().focus().setTextSelection(endOfBody).run();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet targetPos = -1;\n\t\t\t\t\te.state.doc.descendants((node, pos) => {\n\t\t\t\t\t\tif (targetPos !== -1) return false;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tnode.type.name === 'sectionDivider' &&\n\t\t\t\t\t\t\tnode.attrs['sectionId'] === sectionId\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// pos + nodeSize lands right after the divider;\n\t\t\t\t\t\t\t// +1 more puts us inside the first paragraph of that section.\n\t\t\t\t\t\t\ttargetPos = pos + node.nodeSize + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (targetPos !== -1) {\n\t\t\t\t\t\te.chain().focus().setTextSelection(targetPos).run();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\n\t\t\tclearSection: (sectionId) => {\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, sectionId, '<p></p>'));\n\t\t\t},\n\n\t\t\t// ── Convenience body shorthands ───────────────────────────────────\n\t\t\tgetBodyContent: () =>\n\t\t\t\teditor\n\t\t\t\t\t? extractBodyContent(editor)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\t\t\tsetBodyContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, 'body', normalised));\n\t\t\t},\n\t\t\tsetBodyAndSections: (body, sections) => {\n\t\t\t\tconst html = buildSectionedContent(\n\t\t\t\t\tnormalizeHtml(body),\n\t\t\t\t\tsections.map((s) => ({\n\t\t\t\t\t\tid: s.id,\n\t\t\t\t\t\tcontent: normalizeHtml(s.content),\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tenqueue((e) => e.commands.setContent(html, { emitUpdate: true }));\n\t\t\t},\n\t\t\tappendBodyContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\t// findSectionEndPos returns the position of the first divider (or\n\t\t\t\t// doc.content.size), which is the block boundary after the last </p>.\n\t\t\t\t// Subtract 1 to stay inside the last paragraph so successive calls\n\t\t\t\t// append inline text rather than creating a new paragraph each time.\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst boundaryPos = findSectionEndPos(e, 'body');\n\t\t\t\t\te.commands.insertContentAt(boundaryPos - 1, normalised, {\n\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\tinsertAtSectionStart: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst pos = findSectionStartPos(e, sectionId);\n\t\t\t\t\tif (pos !== -1)\n\t\t\t\t\t\te.commands.insertContentAt(pos, normalised, {\n\t\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\tinsertAtSectionEnd: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst pos = findSectionEndPos(e, sectionId);\n\t\t\t\t\te.commands.insertContentAt(pos, normalised, {\n\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\t// ── Formats & actions ─────────────────────────────────────────────\n\t\t\tgetActiveFormats: () =>\n\t\t\t\teditor ? extractActiveFormats(editor) : DEFAULT_FORMAT_STATE,\n\t\t\tactions: {\n\t\t\t\ttoggleBold: () => editor?.chain().focus().toggleBold().run(),\n\t\t\t\ttoggleItalic: () => editor?.chain().focus().toggleItalic().run(),\n\t\t\t\ttoggleUnderline: () => editor?.chain().focus().toggleUnderline().run(),\n\t\t\t\ttoggleStrike: () => editor?.chain().focus().toggleStrike().run(),\n\t\t\t\ttoggleBulletList: () =>\n\t\t\t\t\teditor?.chain().focus().toggleBulletList().run(),\n\t\t\t\ttoggleOrderedList: () =>\n\t\t\t\t\teditor?.chain().focus().toggleOrderedList().run(),\n\t\t\t\ttoggleBlockquote: () =>\n\t\t\t\t\teditor?.chain().focus().toggleBlockquote().run(),\n\t\t\t\ttoggleCodeBlock: () => editor?.chain().focus().toggleCodeBlock().run(),\n\t\t\t\tsetTextAlign: (align) =>\n\t\t\t\t\teditor?.chain().focus().setTextAlign(align).run(),\n\t\t\t\tsetFontFamily: (font) =>\n\t\t\t\t\teditor?.chain().focus().setFontFamily(font).run(),\n\t\t\t\tsetFontSize: (size) => editor?.chain().focus().setFontSize(size).run(),\n\t\t\t\tsetColor: (color) => editor?.chain().focus().setColor(color).run(),\n\t\t\t\tsetHighlight: (color) =>\n\t\t\t\t\teditor?.chain().focus().toggleHighlight({ color }).run(),\n\t\t\t\tunsetColor: () => editor?.chain().focus().unsetColor().run(),\n\t\t\t\tunsetHighlight: () => editor?.chain().focus().unsetHighlight().run(),\n\t\t\t\tsetLink: (href, text) => {\n\t\t\t\t\tif (!editor) return;\n\t\t\t\t\tif (text !== undefined) {\n\t\t\t\t\t\teditor\n\t\t\t\t\t\t\t.chain()\n\t\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t\t.command(({ tr, state }) => {\n\t\t\t\t\t\t\t\tconst { from, to } = tr.selection;\n\t\t\t\t\t\t\t\tconst linkMarkType = state.schema.marks['link'];\n\t\t\t\t\t\t\t\tif (!linkMarkType) return false;\n\t\t\t\t\t\t\t\tconst linkNode = state.schema.text(text, [\n\t\t\t\t\t\t\t\t\tlinkMarkType.create({ href }),\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\tconst space = state.schema.text(' ');\n\t\t\t\t\t\t\t\ttr.replaceWith(from, to, [linkNode, space]);\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.run();\n\t\t\t\t\t} else {\n\t\t\t\t\t\teditor\n\t\t\t\t\t\t\t.chain()\n\t\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t\t.setLink({ href })\n\t\t\t\t\t\t\t.insertContent(' ')\n\t\t\t\t\t\t\t.run();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tupdateLink: (href) =>\n\t\t\t\t\teditor\n\t\t\t\t\t\t?.chain()\n\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t.setLink({ href })\n\t\t\t\t\t\t.run(),\n\t\t\t\tremoveLink: () =>\n\t\t\t\t\teditor?.chain().focus().extendMarkRange('link').unsetLink().run(),\n\t\t\t\tinsertEmoji: (emoji) =>\n\t\t\t\t\teditor?.chain().focus().insertContent(emoji).run(),\n\t\t\t\tinsertVariable: (variableName) =>\n\t\t\t\t\teditor?.chain().focus().insertContent(`{{${variableName}}}`).run(),\n\t\t\t\tinsertHtml: (html) =>\n\t\t\t\t\teditor?.commands.insertContent(normalizeHtml(html)),\n\t\t\t\tundo: () => editor?.chain().focus().undo().run(),\n\t\t\t\tredo: () => editor?.chain().focus().redo().run(),\n\t\t\t\tcanUndo: () => editor?.can().undo() ?? false,\n\t\t\t\tcanRedo: () => editor?.can().redo() ?? false,\n\t\t\t\ttoggleSuperscript: () =>\n\t\t\t\t\teditor?.chain().focus().toggleSuperscript().run(),\n\t\t\t\ttoggleSubscript: () => editor?.chain().focus().toggleSubscript().run(),\n\t\t\t\tinsertImage: (src) => editor?.chain().focus().setImage({ src }).run(),\n\t\t\t},\n\n\t\t\t// ── JSON body ─────────────────────────────────────────────────────\n\t\t\tjson: features?.jsonMode\n\t\t\t\t? {\n\t\t\t\t\t\tgetText: () => (editor ? getCodeBlockText(editor) : ''),\n\t\t\t\t\t\tsetText: (raw) => enqueue((e) => setCodeBlockText(e, raw)),\n\t\t\t\t\t\tparse: () => parseJson(editor ? getCodeBlockText(editor) : ''),\n\t\t\t\t\t\tisValid: () =>\n\t\t\t\t\t\t\tparseJson(editor ? getCodeBlockText(editor) : '').valid,\n\t\t\t\t\t\tformat: (indent = 2) =>\n\t\t\t\t\t\t\tenqueue((e) => {\n\t\t\t\t\t\t\t\tconst { valid, value } = parseJson(getCodeBlockText(e));\n\t\t\t\t\t\t\t\tif (!valid || value === null) return;\n\t\t\t\t\t\t\t\tsetCodeBlockText(e, JSON.stringify(value, null, indent));\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tminify: () =>\n\t\t\t\t\t\t\tenqueue((e) => {\n\t\t\t\t\t\t\t\tconst { valid, value } = parseJson(getCodeBlockText(e));\n\t\t\t\t\t\t\t\tif (!valid || value === null) return;\n\t\t\t\t\t\t\t\tsetCodeBlockText(e, JSON.stringify(value));\n\t\t\t\t\t\t\t}),\n\t\t\t\t }\n\t\t\t\t: undefined,\n\t\t}),\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t[editor],\n\t);\n\n\t// ── jsonMode floating actions ────────────────────────────────────────────\n\t// Beautify pretty-prints in place (no-op / disabled while the JSON is broken);\n\t// Copy writes the raw text to the clipboard with transient feedback.\n\tconst handleJsonBeautify = () => {\n\t\tif (!editor) return;\n\t\tconst { valid, value } = parseJson(getCodeBlockText(editor));\n\t\tif (!valid || value === null) return;\n\t\tsetCodeBlockText(editor, JSON.stringify(value, null, 2));\n\t};\n\tconst handleJsonCopy = () => {\n\t\tif (!editor) return;\n\t\tvoid navigator.clipboard?.writeText(getCodeBlockText(editor));\n\t\tsetJsonCopied(true);\n\t\tsetTimeout(() => setJsonCopied(false), 1500);\n\t};\n\n\tif (!editor) return null;\n\n\treturn (\n\t\t<BikEditorShell\n\t\t\tminHeight={minHeight}\n\t\t\tmaxHeight={maxHeight}\n\t\t\ttightParagraphs={!features?.richPaste}\n\t\t\tjsonMode={isJsonMode}\n\t\t\tstyle={style}\n\t\t\tclassName={className}\n\t\t>\n\t\t\t{isJsonMode && (\n\t\t\t\t<BikJsonHeader>\n\t\t\t\t\t<span className=\"bik-json-header-label\">JSON</span>\n\t\t\t\t\t<div className=\"bik-json-header-actions\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={handleJsonBeautify}\n\t\t\t\t\t\t\tdisabled={!!jsonError || jsonEmpty}\n\t\t\t\t\t\t\ttitle=\"Format JSON\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<WandSparkles size={16} />\n\t\t\t\t\t\t\t<BodyCaption>Beautify</BodyCaption>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={handleJsonCopy}\n\t\t\t\t\t\t\tdisabled={jsonEmpty}\n\t\t\t\t\t\t\ttitle=\"Copy JSON\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Copy size={16} />\n\t\t\t\t\t\t\t{jsonCopied && <BodyCaption>Copied</BodyCaption>}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</BikJsonHeader>\n\t\t\t)}\n\t\t\t{isJsonMode ? (\n\t\t\t\t<BikJsonBody $error={!!jsonError}>\n\t\t\t\t\t<EditorContent editor={editor} />\n\t\t\t\t\t{jsonEmpty && !jsonFocused && (\n\t\t\t\t\t\t<BikJsonEmptyState aria-hidden>\n\t\t\t\t\t\t\t<Code size={20} />\n\t\t\t\t\t\t\t<span>{props.placeholder ?? 'Type or paste JSON here'}</span>\n\t\t\t\t\t\t</BikJsonEmptyState>\n\t\t\t\t\t)}\n\t\t\t\t</BikJsonBody>\n\t\t\t) : (\n\t\t\t\t<EditorContent editor={editor} />\n\t\t\t)}\n\t\t\t<LinkBubbleMenu editor={editor} renderLinkTooltip={link?.renderTooltip} />\n\t\t\t{isJsonMode && jsonError ? (\n\t\t\t\trenderJsonError ? (\n\t\t\t\t\trenderJsonError(jsonError)\n\t\t\t\t) : (\n\t\t\t\t\t<BikJsonError>\n\t\t\t\t\t\t<Info size={16} />\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{jsonError.line != null && (\n\t\t\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\t\t\tLine {jsonError.line}\n\t\t\t\t\t\t\t\t\t{jsonError.column != null\n\t\t\t\t\t\t\t\t\t\t? `, column ${jsonError.column}`\n\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{jsonError.error}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</BikJsonError>\n\t\t\t\t)\n\t\t\t) : null}\n\t\t</BikEditorShell>\n\t);\n};\n\nexport const BikEditor = forwardRef<BikEditorRef, BikEditorProps>(\n\tBikEditorInner,\n);\nBikEditor.displayName = 'BikEditor';\n"],"names":["cssToString","style","k","v","c","BikEditorInner","props","ref","initialContent","sections","features","disabled","maxCharacters","characterLimit","characterLimitHard","shortcuts","sendShortcut","mentions","slashCommands","link","onPaste","onReady","onChange","onSend","onFocus","onBlur","onSelectionChange","minHeight","maxHeight","className","editorClassName","editorStyle","renderJsonError","isJsonMode","jsonError","setJsonError","useState","jsonCopied","setJsonCopied","jsonEmpty","setJsonEmpty","jsonFocused","setJsonFocused","initialEditorContent","buildJsonCodeBlockHtml","buildSectionedContent","normalizeHtml","s","pendingQueue","useRef","hasCalledOnReady","onReadyRef","onChangeRef","onSelectionChangeRef","prevFormatsRef","DEFAULT_FORMAT_STATE","onFocusRef","onBlurRef","onSendRef","agentMentionsRef","teamMentionsRef","slashCommandsRef","editor","useEditor","buildExtensions","snapshot","extractContent","text","getCodeBlockText","result","parseJson","next","extractActiveFormats","prev","enqueue","op","useEffect","useImperativeHandle","position","e","html","normalised","insertInlineHtml","agentIds","teamIds","node","from","to","pos","state","empty","linkMarkType","range","getMarkRange","sectionId","extractSectionContent","setSectionContentInEditor","endOfBody","targetPos","extractBodyContent","body","boundaryPos","findSectionEndPos","findSectionStartPos","align","font","size","color","href","tr","linkNode","space","emoji","variableName","src","raw","setCodeBlockText","indent","valid","value","handleJsonBeautify","handleJsonCopy","jsxs","BikEditorShell","BikJsonHeader","jsx","WandSparkles","BodyCaption","Copy","BikJsonBody","EditorContent","BikJsonEmptyState","Code","LinkBubbleMenu","BikJsonError","Info","BikEditor","forwardRef"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BikEditor.js","sources":["../../../src/editor/BikEditor.tsx"],"sourcesContent":["'use client';\n\n/**\n * IMPLEMENTATION LAYER — TipTap-specific.\n * If the underlying editor is swapped, this file changes; BikEditor.types.ts and\n * src/editor/index.ts (the consumer contract) do NOT change.\n */\nimport { Editor, getMarkRange } from '@tiptap/core';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport React, {\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState,\n} from 'react';\nimport { BodyCaption } from '@src/components/TypographyStyle';\nimport { Code, Copy, Info, WandSparkles } from '../icons';\nimport {\n\tBikEditorShell,\n\tBikJsonBody,\n\tBikJsonEmptyState,\n\tBikJsonError,\n\tBikJsonHeader,\n} from './BikEditor.styles';\nimport {\n\tBikEditorProps,\n\tBikEditorRef,\n\tDEFAULT_FORMAT_STATE,\n\tFormatState,\n\tJsonParseResult,\n} from './BikEditor.types';\nimport {\n\tbuildJsonCodeBlockHtml,\n\tbuildSectionedContent,\n\textractActiveFormats,\n\textractBodyContent,\n\textractContent,\n\textractSectionContent,\n\tfindSectionEndPos,\n\tfindSectionStartPos,\n\tgetCodeBlockText,\n\tinsertInlineHtml,\n\tnormalizeHtml,\n\tparseJson,\n\tsetCodeBlockText,\n\tsetSectionContentInEditor,\n} from './BikEditor.utils';\nimport { buildExtensions } from './extensions/buildExtensions';\nimport { LinkBubbleMenu } from './floating/LinkBubbleMenu';\n\n/** Convert React.CSSProperties to an inline CSS string for editorProps.attributes. */\nfunction cssToString(style: React.CSSProperties): string {\n\treturn Object.entries(style)\n\t\t.map(\n\t\t\t([k, v]) => `${k.replace(/([A-Z])/g, (c) => `-${c.toLowerCase()}`)}:${v}`,\n\t\t)\n\t\t.join(';');\n}\n\nconst BikEditorInner = (\n\tprops: BikEditorProps,\n\tref: React.Ref<BikEditorRef>,\n) => {\n\tconst {\n\t\tinitialContent,\n\t\tsections,\n\t\tfeatures,\n\t\tdisabled,\n\t\tmaxCharacters,\n\t\tcharacterLimit,\n\t\tcharacterLimitHard,\n\t\tshortcuts,\n\t\tsendShortcut,\n\t\tmentions,\n\t\tslashCommands,\n\t\tlink,\n\t\tonPaste,\n\t\tonReady,\n\t\tonChange,\n\t\tonSend,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonSelectionChange,\n\t\tminHeight,\n\t\tmaxHeight,\n\t\tstyle,\n\t\tclassName,\n\t\teditorClassName,\n\t\teditorStyle,\n\t\trenderJsonError,\n\t} = props;\n\n\tconst isJsonMode = !!features?.jsonMode;\n\n\t// Live JSON parse error, shown inside the editor when jsonMode is on.\n\t// null = valid (or not applicable) → nothing rendered.\n\tconst [jsonError, setJsonError] = useState<JsonParseResult | null>(null);\n\t// Transient \"Copied\" state for the jsonMode copy button.\n\tconst [jsonCopied, setJsonCopied] = useState(false);\n\t// jsonMode: no content yet → centered code-glyph + placeholder overlay.\n\tconst [jsonEmpty, setJsonEmpty] = useState(\n\t\tisJsonMode && !(initialContent ?? '').trim(),\n\t);\n\t// jsonMode: hide the placeholder overlay while the editor is focused, so\n\t// clicking in gives a clean field to type into.\n\tconst [jsonFocused, setJsonFocused] = useState(false);\n\n\t// JSON body mode: treat initialContent as raw JSON text and wrap it in a code\n\t// block. Skips section/HTML normalisation entirely.\n\tconst initialEditorContent = isJsonMode\n\t\t? buildJsonCodeBlockHtml(initialContent ?? '')\n\t\t: sections?.length\n\t\t? buildSectionedContent(\n\t\t\t\tnormalizeHtml(initialContent ?? ''),\n\t\t\t\tsections.map((s) => ({ ...s, content: normalizeHtml(s.content) })),\n\t\t )\n\t\t: normalizeHtml(initialContent ?? '');\n\n\t// ── Command queue ─────────────────────────────────────────────────────────\n\t// TipTap's useEditor initializes asynchronously; the editor instance is null\n\t// until the first commit. Any imperative method called before the editor is\n\t// ready is enqueued here and flushed automatically once it becomes non-null.\n\t// Consumers never need setTimeout or readiness guards.\n\tconst pendingQueue = useRef<Array<(e: Editor) => void>>([]);\n\tconst hasCalledOnReady = useRef(false);\n\t// Keep stable refs to all callbacks so useEditor receives the same function\n\t// identity on every render — prevents TipTap from re-registering event\n\t// handlers every time the parent re-renders with new inline function props.\n\tconst onReadyRef = useRef(onReady);\n\tonReadyRef.current = onReady;\n\tconst onChangeRef = useRef(onChange);\n\tonChangeRef.current = onChange;\n\tconst onSelectionChangeRef = useRef(onSelectionChange);\n\tonSelectionChangeRef.current = onSelectionChange;\n\tconst prevFormatsRef = useRef<FormatState>(DEFAULT_FORMAT_STATE);\n\tconst onFocusRef = useRef(onFocus);\n\tonFocusRef.current = onFocus;\n\tconst onBlurRef = useRef(onBlur);\n\tonBlurRef.current = onBlur;\n\tconst onSendRef = useRef(onSend);\n\tonSendRef.current = onSend;\n\tconst agentMentionsRef = useRef(mentions?.agents ?? []);\n\tagentMentionsRef.current = mentions?.agents ?? [];\n\tconst teamMentionsRef = useRef(mentions?.teams ?? []);\n\tteamMentionsRef.current = mentions?.teams ?? [];\n\tconst slashCommandsRef = useRef(slashCommands?.items ?? []);\n\tslashCommandsRef.current = slashCommands?.items ?? [];\n\n\tconst editor = useEditor({\n\t\textensions: buildExtensions({\n\t\t\tfeatures,\n\t\t\tplaceholder: props.placeholder,\n\t\t\tmaxCharacters,\n\t\t\tcharacterLimit,\n\t\t\tcharacterLimitHard,\n\t\t\thasSections: (sections?.length ?? 0) > 0,\n\t\t\tmentions: {\n\t\t\t\tagents: mentions ? agentMentionsRef : undefined,\n\t\t\t\tteams: mentions ? teamMentionsRef : undefined,\n\t\t\t},\n\t\t\tslashCommands: slashCommands ? slashCommandsRef : undefined,\n\t\t\tonPaste,\n\t\t\tonSend: onSend ? (snapshot) => onSendRef.current?.(snapshot) : undefined,\n\t\t\tsendShortcut,\n\t\t\tshortcuts,\n\t\t\tonMentionSelected: mentions?.onSelect,\n\t\t\tonSlashCommandSelected: slashCommands?.onSelect,\n\t\t\trenderMentionItem: mentions?.renderItem,\n\t\t\trenderMentionDropdown: mentions?.renderDropdown,\n\t\t\tremoveMentionTriggerOnDismiss: mentions?.removeTriggerOnDismiss,\n\t\t\trenderMentionChipIcon: mentions?.renderChipIcon,\n\t\t\trenderSlashCommandItem: slashCommands?.renderItem,\n\t\t\trenderSlashCommandDropdown: slashCommands?.renderDropdown,\n\t\t}),\n\t\tcontent: initialEditorContent,\n\t\teditable: !disabled,\n\t\timmediatelyRender: false, // SSR-safe — NEVER remove this\n\t\teditorProps: {\n\t\t\tattributes: {\n\t\t\t\t...(editorClassName ? { class: editorClassName } : {}),\n\t\t\t\t...(editorStyle ? { style: cssToString(editorStyle) } : {}),\n\t\t\t},\n\t\t},\n\t\tonUpdate: ({ editor: e }) => {\n\t\t\tonChangeRef.current?.(extractContent(e));\n\t\t\tif (isJsonMode) {\n\t\t\t\tconst text = getCodeBlockText(e);\n\t\t\t\tconst result = parseJson(text);\n\t\t\t\tsetJsonError(result.valid ? null : result);\n\t\t\t\tsetJsonEmpty(!text.trim());\n\t\t\t}\n\t\t},\n\t\tonTransaction: ({ editor: e }) => {\n\t\t\tconst next = extractActiveFormats(e);\n\t\t\tconst prev = prevFormatsRef.current;\n\t\t\tconst changed =\n\t\t\t\tprev.bold !== next.bold ||\n\t\t\t\tprev.italic !== next.italic ||\n\t\t\t\tprev.underline !== next.underline ||\n\t\t\t\tprev.strike !== next.strike ||\n\t\t\t\tprev.bulletList !== next.bulletList ||\n\t\t\t\tprev.orderedList !== next.orderedList ||\n\t\t\t\tprev.blockquote !== next.blockquote ||\n\t\t\t\tprev.codeBlock !== next.codeBlock ||\n\t\t\t\tprev.superscript !== next.superscript ||\n\t\t\t\tprev.subscript !== next.subscript ||\n\t\t\t\tprev.textAlign !== next.textAlign ||\n\t\t\t\tprev.fontFamily !== next.fontFamily ||\n\t\t\t\tprev.fontSize !== next.fontSize ||\n\t\t\t\tprev.color !== next.color ||\n\t\t\t\tprev.highlight !== next.highlight ||\n\t\t\t\tprev.link?.href !== next.link?.href;\n\t\t\tif (changed) {\n\t\t\t\tprevFormatsRef.current = next;\n\t\t\t\tonSelectionChangeRef.current?.(next);\n\t\t\t}\n\t\t},\n\t\tonFocus: () => {\n\t\t\tsetJsonFocused(true);\n\t\t\tonFocusRef.current?.();\n\t\t},\n\t\tonBlur: () => {\n\t\t\tsetJsonFocused(false);\n\t\t\tonBlurRef.current?.();\n\t\t},\n\t});\n\n\t// ── enqueue ───────────────────────────────────────────────────────────────\n\t// Run immediately if the editor is ready; otherwise defer to the queue.\n\t// Closures passed to enqueue MUST capture all parameters explicitly —\n\t// they must NOT close over `editor` (which would be null at enqueue time).\n\tfunction enqueue(op: (e: Editor) => void): void {\n\t\tif (editor) {\n\t\t\top(editor);\n\t\t} else {\n\t\t\tpendingQueue.current.push(op);\n\t\t}\n\t}\n\n\t// Flush the pending queue and fire onReady when editor transitions null → ready.\n\tuseEffect(() => {\n\t\tif (!editor) return;\n\t\tif (pendingQueue.current.length > 0) {\n\t\t\tconst queue = pendingQueue.current.splice(0);\n\t\t\tqueue.forEach((op) => op(editor));\n\t\t}\n\t\tif (!hasCalledOnReady.current) {\n\t\t\thasCalledOnReady.current = true;\n\t\t\tonReadyRef.current?.();\n\t\t}\n\t\t// Surface an error for invalid initialContent immediately on mount.\n\t\tif (isJsonMode) {\n\t\t\tconst text = getCodeBlockText(editor);\n\t\t\tconst result = parseJson(text);\n\t\t\tsetJsonError(result.valid ? null : result);\n\t\t\tsetJsonEmpty(!text.trim());\n\t\t}\n\t}, [editor, isJsonMode]);\n\n\tuseImperativeHandle(\n\t\tref,\n\t\t() => ({\n\t\t\t// ── Focus ────────────────────────────────────────────────────────\n\t\t\tfocus: (position) => enqueue((e) => e.commands.focus(position)),\n\t\t\tblur: () => enqueue((e) => e.commands.blur()),\n\n\t\t\t// ── Content ──────────────────────────────────────────────────────\n\t\t\tclearContent: () => enqueue((e) => e.commands.clearContent(true)),\n\t\t\tsetContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.setContent(normalised, { emitUpdate: true }));\n\t\t\t},\n\t\t\tinsertContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContent(normalised));\n\t\t\t},\n\t\t\tinsertInlineContent: (html) => {\n\t\t\t\tenqueue((e) => insertInlineHtml(e, html));\n\t\t\t},\n\t\t\tinsertAtStart: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContentAt(1, normalised));\n\t\t\t},\n\t\t\tinsertBlock: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) =>\n\t\t\t\t\te.commands.insertContentAt(e.state.doc.content.size, normalised),\n\t\t\t\t);\n\t\t\t},\n\t\t\tappendInline: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\t// doc.content.size is after the last </p> (block boundary).\n\t\t\t\t// Subtract 1 to land inside the last paragraph so text appends\n\t\t\t\t// inline rather than being wrapped in a new paragraph each call.\n\t\t\t\tenqueue((e) =>\n\t\t\t\t\te.commands.insertContentAt(e.state.doc.content.size - 1, normalised),\n\t\t\t\t);\n\t\t\t},\n\t\t\t// Backwards-compatible aliases\n\t\t\tinsertAtEnd(html) {\n\t\t\t\tthis.insertBlock(html);\n\t\t\t},\n\t\t\tappendContent(html) {\n\t\t\t\tthis.appendInline(html);\n\t\t\t},\n\t\t\tgetContent: () =>\n\t\t\t\teditor\n\t\t\t\t\t? extractContent(editor)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\t\t\tgetJSON: () => editor?.getJSON() ?? null,\n\t\t\tgetMentions: () => {\n\t\t\t\tconst agentIds = new Set<string>();\n\t\t\t\tconst teamIds = new Set<string>();\n\t\t\t\tif (!editor) return { agentIds: [], teamIds: [] };\n\t\t\t\teditor.state.doc.descendants((node) => {\n\t\t\t\t\tif (node.type.name === 'mentionAgent' && node.attrs['id'] != null) {\n\t\t\t\t\t\tagentIds.add(String(node.attrs['id']));\n\t\t\t\t\t} else if (\n\t\t\t\t\t\tnode.type.name === 'mentionTeam' &&\n\t\t\t\t\t\tnode.attrs['id'] != null\n\t\t\t\t\t) {\n\t\t\t\t\t\tteamIds.add(String(node.attrs['id']));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\treturn { agentIds: Array.from(agentIds), teamIds: Array.from(teamIds) };\n\t\t\t},\n\n\t\t\t// ── Selection ────────────────────────────────────────────────────\n\t\t\tgetCursorPosition: () => {\n\t\t\t\tif (!editor) return { from: 0, to: 0 };\n\t\t\t\tconst { from, to } = editor.state.selection;\n\t\t\t\treturn { from, to };\n\t\t\t},\n\t\t\tinsertAtPosition: (pos, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => e.commands.insertContentAt(pos, normalised));\n\t\t\t},\n\t\t\tgetSelectedText: () => {\n\t\t\t\tif (!editor) return '';\n\t\t\t\tconst { state } = editor;\n\t\t\t\tconst { from, to, empty } = state.selection;\n\t\t\t\tif (!empty) {\n\t\t\t\t\treturn state.doc.textBetween(from, to, ' ');\n\t\t\t\t}\n\t\t\t\t// When the cursor is inside a link with nothing selected, return the\n\t\t\t\t// full link text — useful for pre-filling a link modal's text field.\n\t\t\t\tconst linkMarkType = state.schema.marks['link'];\n\t\t\t\tif (linkMarkType) {\n\t\t\t\t\tconst range = getMarkRange(state.doc.resolve(from), linkMarkType);\n\t\t\t\t\tif (range) {\n\t\t\t\t\t\treturn state.doc.textBetween(range.from, range.to, ' ');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn '';\n\t\t\t},\n\n\t\t\t// ── Character count ───────────────────────────────────────────────\n\t\t\tgetCharacterCount: () => ({\n\t\t\t\tcount:\n\t\t\t\t\teditor?.storage.characterCount?.characters?.() ??\n\t\t\t\t\teditor?.getText().length ??\n\t\t\t\t\t0,\n\t\t\t\tlimit: maxCharacters ?? null,\n\t\t\t}),\n\n\t\t\t// ── Sections ─────────────────────────────────────────────────────\n\t\t\tgetSectionContent: (sectionId) =>\n\t\t\t\teditor\n\t\t\t\t\t? extractSectionContent(editor, sectionId)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\n\t\t\tsetSectionContent: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, sectionId, normalised));\n\t\t\t},\n\n\t\t\tfocusSection: (sectionId) => {\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tif (sectionId === 'body') {\n\t\t\t\t\t\tlet endOfBody = e.state.doc.content.size - 1;\n\t\t\t\t\t\te.state.doc.descendants((node, pos) => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tnode.type.name === 'sectionDivider' &&\n\t\t\t\t\t\t\t\tendOfBody === e.state.doc.content.size - 1\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tendOfBody = pos - 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn endOfBody === e.state.doc.content.size - 1;\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (endOfBody < 1) endOfBody = 1;\n\t\t\t\t\t\te.chain().focus().setTextSelection(endOfBody).run();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet targetPos = -1;\n\t\t\t\t\te.state.doc.descendants((node, pos) => {\n\t\t\t\t\t\tif (targetPos !== -1) return false;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tnode.type.name === 'sectionDivider' &&\n\t\t\t\t\t\t\tnode.attrs['sectionId'] === sectionId\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// pos + nodeSize lands right after the divider;\n\t\t\t\t\t\t\t// +1 more puts us inside the first paragraph of that section.\n\t\t\t\t\t\t\ttargetPos = pos + node.nodeSize + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (targetPos !== -1) {\n\t\t\t\t\t\te.chain().focus().setTextSelection(targetPos).run();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\n\t\t\tclearSection: (sectionId) => {\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, sectionId, '<p></p>'));\n\t\t\t},\n\n\t\t\t// ── Convenience body shorthands ───────────────────────────────────\n\t\t\tgetBodyContent: () =>\n\t\t\t\teditor\n\t\t\t\t\t? extractBodyContent(editor)\n\t\t\t\t\t: { html: '', text: '', isEmpty: true, characterCount: 0 },\n\t\t\tsetBodyContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => setSectionContentInEditor(e, 'body', normalised));\n\t\t\t},\n\t\t\tsetBodyAndSections: (body, sections) => {\n\t\t\t\tconst html = buildSectionedContent(\n\t\t\t\t\tnormalizeHtml(body),\n\t\t\t\t\tsections.map((s) => ({\n\t\t\t\t\t\tid: s.id,\n\t\t\t\t\t\tcontent: normalizeHtml(s.content),\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tenqueue((e) => e.commands.setContent(html, { emitUpdate: true }));\n\t\t\t},\n\t\t\tappendBodyContent: (html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\t// findSectionEndPos returns the position of the first divider (or\n\t\t\t\t// doc.content.size), which is the block boundary after the last </p>.\n\t\t\t\t// Subtract 1 to stay inside the last paragraph so successive calls\n\t\t\t\t// append inline text rather than creating a new paragraph each time.\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst boundaryPos = findSectionEndPos(e, 'body');\n\t\t\t\t\te.commands.insertContentAt(boundaryPos - 1, normalised, {\n\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\tinsertAtSectionStart: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst pos = findSectionStartPos(e, sectionId);\n\t\t\t\t\tif (pos !== -1)\n\t\t\t\t\t\te.commands.insertContentAt(pos, normalised, {\n\t\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\tinsertAtSectionEnd: (sectionId, html) => {\n\t\t\t\tconst normalised = normalizeHtml(html);\n\t\t\t\tenqueue((e) => {\n\t\t\t\t\tconst pos = findSectionEndPos(e, sectionId);\n\t\t\t\t\te.commands.insertContentAt(pos, normalised, {\n\t\t\t\t\t\tparseOptions: { preserveWhitespace: true },\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t},\n\t\t\t// ── Formats & actions ─────────────────────────────────────────────\n\t\t\tgetActiveFormats: () =>\n\t\t\t\teditor ? extractActiveFormats(editor) : DEFAULT_FORMAT_STATE,\n\t\t\tactions: {\n\t\t\t\ttoggleBold: () => editor?.chain().focus().toggleBold().run(),\n\t\t\t\ttoggleItalic: () => editor?.chain().focus().toggleItalic().run(),\n\t\t\t\ttoggleUnderline: () => editor?.chain().focus().toggleUnderline().run(),\n\t\t\t\ttoggleStrike: () => editor?.chain().focus().toggleStrike().run(),\n\t\t\t\ttoggleBulletList: () =>\n\t\t\t\t\teditor?.chain().focus().toggleBulletList().run(),\n\t\t\t\ttoggleOrderedList: () =>\n\t\t\t\t\teditor?.chain().focus().toggleOrderedList().run(),\n\t\t\t\ttoggleBlockquote: () =>\n\t\t\t\t\teditor?.chain().focus().toggleBlockquote().run(),\n\t\t\t\ttoggleCodeBlock: () => editor?.chain().focus().toggleCodeBlock().run(),\n\t\t\t\tsetTextAlign: (align) =>\n\t\t\t\t\teditor?.chain().focus().setTextAlign(align).run(),\n\t\t\t\tsetFontFamily: (font) =>\n\t\t\t\t\teditor?.chain().focus().setFontFamily(font).run(),\n\t\t\t\tsetFontSize: (size) => editor?.chain().focus().setFontSize(size).run(),\n\t\t\t\tsetColor: (color) => editor?.chain().focus().setColor(color).run(),\n\t\t\t\tsetHighlight: (color) =>\n\t\t\t\t\teditor?.chain().focus().toggleHighlight({ color }).run(),\n\t\t\t\tunsetColor: () => editor?.chain().focus().unsetColor().run(),\n\t\t\t\tunsetHighlight: () => editor?.chain().focus().unsetHighlight().run(),\n\t\t\t\tsetLink: (href, text) => {\n\t\t\t\t\tif (!editor) return;\n\t\t\t\t\tif (text !== undefined) {\n\t\t\t\t\t\teditor\n\t\t\t\t\t\t\t.chain()\n\t\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t\t.command(({ tr, state }) => {\n\t\t\t\t\t\t\t\tconst { from, to } = tr.selection;\n\t\t\t\t\t\t\t\tconst linkMarkType = state.schema.marks['link'];\n\t\t\t\t\t\t\t\tif (!linkMarkType) return false;\n\t\t\t\t\t\t\t\tconst linkNode = state.schema.text(text, [\n\t\t\t\t\t\t\t\t\tlinkMarkType.create({ href }),\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\tconst space = state.schema.text(' ');\n\t\t\t\t\t\t\t\ttr.replaceWith(from, to, [linkNode, space]);\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.run();\n\t\t\t\t\t} else {\n\t\t\t\t\t\teditor\n\t\t\t\t\t\t\t.chain()\n\t\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t\t.setLink({ href })\n\t\t\t\t\t\t\t.insertContent(' ')\n\t\t\t\t\t\t\t.run();\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tupdateLink: (href) =>\n\t\t\t\t\teditor\n\t\t\t\t\t\t?.chain()\n\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t.extendMarkRange('link')\n\t\t\t\t\t\t.setLink({ href })\n\t\t\t\t\t\t.run(),\n\t\t\t\tremoveLink: () =>\n\t\t\t\t\teditor?.chain().focus().extendMarkRange('link').unsetLink().run(),\n\t\t\t\tinsertEmoji: (emoji) =>\n\t\t\t\t\teditor?.chain().focus().insertContent(emoji).run(),\n\t\t\t\tinsertVariable: (variableName) =>\n\t\t\t\t\teditor?.chain().focus().insertContent(`{{${variableName}}}`).run(),\n\t\t\t\tinsertHtml: (html) =>\n\t\t\t\t\teditor?.commands.insertContent(normalizeHtml(html)),\n\t\t\t\topenMentionMenu: (char = '@') => {\n\t\t\t\t\tif (!editor) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Collapse to the selection's END first — insertContent over a live\n\t\t\t\t\t// selection would REPLACE the selected text with the trigger char.\n\t\t\t\t\tconst { to } = editor.state.selection;\n\t\t\t\t\tconst prev = to > 1 ? editor.state.doc.textBetween(to - 1, to) : '';\n\t\t\t\t\tconst needsSpace = prev !== '' && !/\\s/.test(prev);\n\t\t\t\t\teditor\n\t\t\t\t\t\t.chain()\n\t\t\t\t\t\t.focus()\n\t\t\t\t\t\t.setTextSelection(to)\n\t\t\t\t\t\t.insertContent(needsSpace ? ` ${char}` : char)\n\t\t\t\t\t\t.run();\n\t\t\t\t},\n\t\t\t\tundo: () => editor?.chain().focus().undo().run(),\n\t\t\t\tredo: () => editor?.chain().focus().redo().run(),\n\t\t\t\tcanUndo: () => editor?.can().undo() ?? false,\n\t\t\t\tcanRedo: () => editor?.can().redo() ?? false,\n\t\t\t\ttoggleSuperscript: () =>\n\t\t\t\t\teditor?.chain().focus().toggleSuperscript().run(),\n\t\t\t\ttoggleSubscript: () => editor?.chain().focus().toggleSubscript().run(),\n\t\t\t\tinsertImage: (src) => editor?.chain().focus().setImage({ src }).run(),\n\t\t\t},\n\n\t\t\t// ── JSON body ─────────────────────────────────────────────────────\n\t\t\tjson: features?.jsonMode\n\t\t\t\t? {\n\t\t\t\t\t\tgetText: () => (editor ? getCodeBlockText(editor) : ''),\n\t\t\t\t\t\tsetText: (raw) => enqueue((e) => setCodeBlockText(e, raw)),\n\t\t\t\t\t\tparse: () => parseJson(editor ? getCodeBlockText(editor) : ''),\n\t\t\t\t\t\tisValid: () =>\n\t\t\t\t\t\t\tparseJson(editor ? getCodeBlockText(editor) : '').valid,\n\t\t\t\t\t\tformat: (indent = 2) =>\n\t\t\t\t\t\t\tenqueue((e) => {\n\t\t\t\t\t\t\t\tconst { valid, value } = parseJson(getCodeBlockText(e));\n\t\t\t\t\t\t\t\tif (!valid || value === null) return;\n\t\t\t\t\t\t\t\tsetCodeBlockText(e, JSON.stringify(value, null, indent));\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tminify: () =>\n\t\t\t\t\t\t\tenqueue((e) => {\n\t\t\t\t\t\t\t\tconst { valid, value } = parseJson(getCodeBlockText(e));\n\t\t\t\t\t\t\t\tif (!valid || value === null) return;\n\t\t\t\t\t\t\t\tsetCodeBlockText(e, JSON.stringify(value));\n\t\t\t\t\t\t\t}),\n\t\t\t\t }\n\t\t\t\t: undefined,\n\t\t}),\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t[editor],\n\t);\n\n\t// ── jsonMode floating actions ────────────────────────────────────────────\n\t// Beautify pretty-prints in place (no-op / disabled while the JSON is broken);\n\t// Copy writes the raw text to the clipboard with transient feedback.\n\tconst handleJsonBeautify = () => {\n\t\tif (!editor) return;\n\t\tconst { valid, value } = parseJson(getCodeBlockText(editor));\n\t\tif (!valid || value === null) return;\n\t\tsetCodeBlockText(editor, JSON.stringify(value, null, 2));\n\t};\n\tconst handleJsonCopy = () => {\n\t\tif (!editor) return;\n\t\tvoid navigator.clipboard?.writeText(getCodeBlockText(editor));\n\t\tsetJsonCopied(true);\n\t\tsetTimeout(() => setJsonCopied(false), 1500);\n\t};\n\n\tif (!editor) return null;\n\n\treturn (\n\t\t<BikEditorShell\n\t\t\tminHeight={minHeight}\n\t\t\tmaxHeight={maxHeight}\n\t\t\ttightParagraphs={!features?.richPaste}\n\t\t\tjsonMode={isJsonMode}\n\t\t\tstyle={style}\n\t\t\tclassName={className}\n\t\t>\n\t\t\t{isJsonMode && (\n\t\t\t\t<BikJsonHeader>\n\t\t\t\t\t<span className=\"bik-json-header-label\">JSON</span>\n\t\t\t\t\t<div className=\"bik-json-header-actions\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={handleJsonBeautify}\n\t\t\t\t\t\t\tdisabled={!!jsonError || jsonEmpty}\n\t\t\t\t\t\t\ttitle=\"Format JSON\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<WandSparkles size={16} />\n\t\t\t\t\t\t\t<BodyCaption>Beautify</BodyCaption>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={handleJsonCopy}\n\t\t\t\t\t\t\tdisabled={jsonEmpty}\n\t\t\t\t\t\t\ttitle=\"Copy JSON\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Copy size={16} />\n\t\t\t\t\t\t\t{jsonCopied && <BodyCaption>Copied</BodyCaption>}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</BikJsonHeader>\n\t\t\t)}\n\t\t\t{isJsonMode ? (\n\t\t\t\t<BikJsonBody $error={!!jsonError}>\n\t\t\t\t\t<EditorContent editor={editor} />\n\t\t\t\t\t{jsonEmpty && !jsonFocused && (\n\t\t\t\t\t\t<BikJsonEmptyState aria-hidden>\n\t\t\t\t\t\t\t<Code size={20} />\n\t\t\t\t\t\t\t<span>{props.placeholder ?? 'Type or paste JSON here'}</span>\n\t\t\t\t\t\t</BikJsonEmptyState>\n\t\t\t\t\t)}\n\t\t\t\t</BikJsonBody>\n\t\t\t) : (\n\t\t\t\t<EditorContent editor={editor} />\n\t\t\t)}\n\t\t\t<LinkBubbleMenu editor={editor} renderLinkTooltip={link?.renderTooltip} />\n\t\t\t{isJsonMode && jsonError ? (\n\t\t\t\trenderJsonError ? (\n\t\t\t\t\trenderJsonError(jsonError)\n\t\t\t\t) : (\n\t\t\t\t\t<BikJsonError>\n\t\t\t\t\t\t<Info size={16} />\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t{jsonError.line != null && (\n\t\t\t\t\t\t\t\t<strong>\n\t\t\t\t\t\t\t\t\tLine {jsonError.line}\n\t\t\t\t\t\t\t\t\t{jsonError.column != null\n\t\t\t\t\t\t\t\t\t\t? `, column ${jsonError.column}`\n\t\t\t\t\t\t\t\t\t\t: ''}\n\t\t\t\t\t\t\t\t\t:{' '}\n\t\t\t\t\t\t\t\t</strong>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{jsonError.error}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</BikJsonError>\n\t\t\t\t)\n\t\t\t) : null}\n\t\t</BikEditorShell>\n\t);\n};\n\nexport const BikEditor = forwardRef<BikEditorRef, BikEditorProps>(\n\tBikEditorInner,\n);\nBikEditor.displayName = 'BikEditor';\n"],"names":["cssToString","style","k","v","c","BikEditorInner","props","ref","initialContent","sections","features","disabled","maxCharacters","characterLimit","characterLimitHard","shortcuts","sendShortcut","mentions","slashCommands","link","onPaste","onReady","onChange","onSend","onFocus","onBlur","onSelectionChange","minHeight","maxHeight","className","editorClassName","editorStyle","renderJsonError","isJsonMode","jsonError","setJsonError","useState","jsonCopied","setJsonCopied","jsonEmpty","setJsonEmpty","jsonFocused","setJsonFocused","initialEditorContent","buildJsonCodeBlockHtml","buildSectionedContent","normalizeHtml","s","pendingQueue","useRef","hasCalledOnReady","onReadyRef","onChangeRef","onSelectionChangeRef","prevFormatsRef","DEFAULT_FORMAT_STATE","onFocusRef","onBlurRef","onSendRef","agentMentionsRef","teamMentionsRef","slashCommandsRef","editor","useEditor","buildExtensions","snapshot","extractContent","text","getCodeBlockText","result","parseJson","next","extractActiveFormats","prev","enqueue","op","useEffect","useImperativeHandle","position","e","html","normalised","insertInlineHtml","agentIds","teamIds","node","from","to","pos","state","empty","linkMarkType","range","getMarkRange","sectionId","extractSectionContent","setSectionContentInEditor","endOfBody","targetPos","extractBodyContent","body","boundaryPos","findSectionEndPos","findSectionStartPos","align","font","size","color","href","tr","linkNode","space","emoji","variableName","char","needsSpace","src","raw","setCodeBlockText","indent","valid","value","handleJsonBeautify","handleJsonCopy","jsxs","BikEditorShell","BikJsonHeader","jsx","WandSparkles","BodyCaption","Copy","BikJsonBody","EditorContent","BikJsonEmptyState","Code","LinkBubbleMenu","BikJsonError","Info","BikEditor","forwardRef"],"mappings":";;;;;;;;;;;;;;AAoDA,SAASA,GAAYC,GAAoC;AACxD,SAAO,OAAO,QAAQA,CAAK,EACzB;AAAA,IACA,CAAC,CAACC,GAAGC,CAAC,MAAM,GAAGD,EAAE,QAAQ,YAAY,CAACE,MAAM,IAAIA,EAAE,YAAA,CAAa,EAAE,CAAC,IAAID,CAAC;AAAA,EAAA,EAEvE,KAAK,GAAG;AACX;AAEA,MAAME,KAAiB,CACtBC,GACAC,MACI;AACJ,QAAM;AAAA,IACL,gBAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,eAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,oBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,cAAAC;AAAA,IACA,UAAAC;AAAA,IACA,eAAAC;AAAA,IACA,MAAAC;AAAA,IACA,SAAAC;AAAA,IACA,SAAAC;AAAA,IACA,UAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,QAAAC;AAAA,IACA,mBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,WAAAC;AAAA,IACA,OAAA3B;AAAA,IACA,WAAA4B;AAAA,IACA,iBAAAC;AAAA,IACA,aAAAC;AAAA,IACA,iBAAAC;AAAA,EAAA,IACG1B,GAEE2B,IAAa,CAAC,CAACvB,GAAU,UAIzB,CAACwB,GAAWC,CAAY,IAAIC,EAAiC,IAAI,GAEjE,CAACC,IAAYC,CAAa,IAAIF,EAAS,EAAK,GAE5C,CAACG,GAAWC,CAAY,IAAIJ;AAAA,IACjCH,KAAc,EAAEzB,KAAkB,IAAI,KAAA;AAAA,EAAK,GAItC,CAACiC,IAAaC,CAAc,IAAIN,EAAS,EAAK,GAI9CO,KAAuBV,IAC1BW,GAAuBpC,KAAkB,EAAE,IAC3CC,GAAU,SACVoC;AAAA,IACAC,EAActC,KAAkB,EAAE;AAAA,IAClCC,EAAS,IAAI,CAACsC,OAAO,EAAE,GAAGA,GAAG,SAASD,EAAcC,EAAE,OAAO,IAAI;AAAA,EAAA,IAEjED,EAActC,KAAkB,EAAE,GAO/BwC,IAAeC,EAAmC,EAAE,GACpDC,IAAmBD,EAAO,EAAK,GAI/BE,IAAaF,EAAO5B,CAAO;AACjC,EAAA8B,EAAW,UAAU9B;AACrB,QAAM+B,IAAcH,EAAO3B,CAAQ;AACnC,EAAA8B,EAAY,UAAU9B;AACtB,QAAM+B,IAAuBJ,EAAOvB,CAAiB;AACrD,EAAA2B,EAAqB,UAAU3B;AAC/B,QAAM4B,IAAiBL,EAAoBM,EAAoB,GACzDC,IAAaP,EAAOzB,CAAO;AACjC,EAAAgC,EAAW,UAAUhC;AACrB,QAAMiC,IAAYR,EAAOxB,CAAM;AAC/B,EAAAgC,EAAU,UAAUhC;AACpB,QAAMiC,IAAYT,EAAO1B,CAAM;AAC/B,EAAAmC,EAAU,UAAUnC;AACpB,QAAMoC,IAAmBV,EAAOhC,GAAU,UAAU,CAAA,CAAE;AACtD,EAAA0C,EAAiB,UAAU1C,GAAU,UAAU,CAAA;AAC/C,QAAM2C,IAAkBX,EAAOhC,GAAU,SAAS,CAAA,CAAE;AACpD,EAAA2C,EAAgB,UAAU3C,GAAU,SAAS,CAAA;AAC7C,QAAM4C,IAAmBZ,EAAO/B,GAAe,SAAS,CAAA,CAAE;AAC1D,EAAA2C,EAAiB,UAAU3C,GAAe,SAAS,CAAA;AAEnD,QAAM4C,IAASC,GAAU;AAAA,IACxB,YAAYC,GAAgB;AAAA,MAC3B,UAAAtD;AAAA,MACA,aAAaJ,EAAM;AAAA,MACnB,eAAAM;AAAA,MACA,gBAAAC;AAAA,MACA,oBAAAC;AAAA,MACA,cAAcL,GAAU,UAAU,KAAK;AAAA,MACvC,UAAU;AAAA,QACT,QAAQQ,IAAW0C,IAAmB;AAAA,QACtC,OAAO1C,IAAW2C,IAAkB;AAAA,MAAA;AAAA,MAErC,eAAe1C,IAAgB2C,IAAmB;AAAA,MAClD,SAAAzC;AAAA,MACA,QAAQG,IAAS,CAAC0C,MAAaP,EAAU,UAAUO,CAAQ,IAAI;AAAA,MAC/D,cAAAjD;AAAA,MACA,WAAAD;AAAA,MACA,mBAAmBE,GAAU;AAAA,MAC7B,wBAAwBC,GAAe;AAAA,MACvC,mBAAmBD,GAAU;AAAA,MAC7B,uBAAuBA,GAAU;AAAA,MACjC,+BAA+BA,GAAU;AAAA,MACzC,uBAAuBA,GAAU;AAAA,MACjC,wBAAwBC,GAAe;AAAA,MACvC,4BAA4BA,GAAe;AAAA,IAAA,CAC3C;AAAA,IACD,SAASyB;AAAA,IACT,UAAU,CAAChC;AAAA,IACX,mBAAmB;AAAA;AAAA,IACnB,aAAa;AAAA,MACZ,YAAY;AAAA,QACX,GAAImB,IAAkB,EAAE,OAAOA,EAAA,IAAoB,CAAA;AAAA,QACnD,GAAIC,IAAc,EAAE,OAAO/B,GAAY+B,CAAW,EAAA,IAAM,CAAA;AAAA,MAAC;AAAA,IAC1D;AAAA,IAED,UAAU,CAAC,EAAE,QAAQ,QAAQ;AAE5B,UADAqB,EAAY,UAAUc,GAAe,CAAC,CAAC,GACnCjC,GAAY;AACf,cAAMkC,IAAOC,EAAiB,CAAC,GACzBC,IAASC,EAAUH,CAAI;AAC7B,QAAAhC,EAAakC,EAAO,QAAQ,OAAOA,CAAM,GACzC7B,EAAa,CAAC2B,EAAK,MAAM;AAAA,MAC1B;AAAA,IACD;AAAA,IACA,eAAe,CAAC,EAAE,QAAQ,QAAQ;AACjC,YAAMI,IAAOC,GAAqB,CAAC,GAC7BC,IAAOnB,EAAe;AAkB5B,OAhBCmB,EAAK,SAASF,EAAK,QACnBE,EAAK,WAAWF,EAAK,UACrBE,EAAK,cAAcF,EAAK,aACxBE,EAAK,WAAWF,EAAK,UACrBE,EAAK,eAAeF,EAAK,cACzBE,EAAK,gBAAgBF,EAAK,eAC1BE,EAAK,eAAeF,EAAK,cACzBE,EAAK,cAAcF,EAAK,aACxBE,EAAK,gBAAgBF,EAAK,eAC1BE,EAAK,cAAcF,EAAK,aACxBE,EAAK,cAAcF,EAAK,aACxBE,EAAK,eAAeF,EAAK,cACzBE,EAAK,aAAaF,EAAK,YACvBE,EAAK,UAAUF,EAAK,SACpBE,EAAK,cAAcF,EAAK,aACxBE,EAAK,MAAM,SAASF,EAAK,MAAM,UAE/BjB,EAAe,UAAUiB,GACzBlB,EAAqB,UAAUkB,CAAI;AAAA,IAErC;AAAA,IACA,SAAS,MAAM;AACd,MAAA7B,EAAe,EAAI,GACnBc,EAAW,UAAA;AAAA,IACZ;AAAA,IACA,QAAQ,MAAM;AACb,MAAAd,EAAe,EAAK,GACpBe,EAAU,UAAA;AAAA,IACX;AAAA,EAAA,CACA;AAMD,WAASiB,EAAQC,GAA+B;AAC/C,IAAIb,IACHa,EAAGb,CAAM,IAETd,EAAa,QAAQ,KAAK2B,CAAE;AAAA,EAE9B;AAGA,EAAAC,GAAU,MAAM;AACf,QAAKd,MACDd,EAAa,QAAQ,SAAS,KACnBA,EAAa,QAAQ,OAAO,CAAC,EACrC,QAAQ,CAAC2B,MAAOA,EAAGb,CAAM,CAAC,GAE5BZ,EAAiB,YACrBA,EAAiB,UAAU,IAC3BC,EAAW,UAAA,IAGRlB,IAAY;AACf,YAAMkC,IAAOC,EAAiBN,CAAM,GAC9BO,IAASC,EAAUH,CAAI;AAC7B,MAAAhC,EAAakC,EAAO,QAAQ,OAAOA,CAAM,GACzC7B,EAAa,CAAC2B,EAAK,MAAM;AAAA,IAC1B;AAAA,EACD,GAAG,CAACL,GAAQ7B,CAAU,CAAC,GAEvB4C;AAAA,IACCtE;AAAA,IACA,OAAO;AAAA;AAAA,MAEN,OAAO,CAACuE,MAAaJ,EAAQ,CAACK,MAAMA,EAAE,SAAS,MAAMD,CAAQ,CAAC;AAAA,MAC9D,MAAM,MAAMJ,EAAQ,CAAC,MAAM,EAAE,SAAS,MAAM;AAAA;AAAA,MAG5C,cAAc,MAAMA,EAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAI,CAAC;AAAA,MAChE,YAAY,CAACM,MAAS;AACrB,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMA,EAAE,SAAS,WAAWE,GAAY,EAAE,YAAY,GAAA,CAAM,CAAC;AAAA,MACvE;AAAA,MACA,eAAe,CAACD,MAAS;AACxB,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMA,EAAE,SAAS,cAAcE,CAAU,CAAC;AAAA,MACpD;AAAA,MACA,qBAAqB,CAACD,MAAS;AAC9B,QAAAN,EAAQ,CAACK,MAAMG,GAAiBH,GAAGC,CAAI,CAAC;AAAA,MACzC;AAAA,MACA,eAAe,CAACA,MAAS;AACxB,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMA,EAAE,SAAS,gBAAgB,GAAGE,CAAU,CAAC;AAAA,MACzD;AAAA,MACA,aAAa,CAACD,MAAS;AACtB,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN;AAAA,UAAQ,CAACK,MACRA,EAAE,SAAS,gBAAgBA,EAAE,MAAM,IAAI,QAAQ,MAAME,CAAU;AAAA,QAAA;AAAA,MAEjE;AAAA,MACA,cAAc,CAACD,MAAS;AACvB,cAAMC,IAAanC,EAAckC,CAAI;AAIrC,QAAAN;AAAA,UAAQ,CAACK,MACRA,EAAE,SAAS,gBAAgBA,EAAE,MAAM,IAAI,QAAQ,OAAO,GAAGE,CAAU;AAAA,QAAA;AAAA,MAErE;AAAA;AAAA,MAEA,YAAYD,GAAM;AACjB,aAAK,YAAYA,CAAI;AAAA,MACtB;AAAA,MACA,cAAcA,GAAM;AACnB,aAAK,aAAaA,CAAI;AAAA,MACvB;AAAA,MACA,YAAY,MACXlB,IACGI,GAAeJ,CAAM,IACrB,EAAE,MAAM,IAAI,MAAM,IAAI,SAAS,IAAM,gBAAgB,EAAA;AAAA,MACzD,SAAS,MAAMA,GAAQ,QAAA,KAAa;AAAA,MACpC,aAAa,MAAM;AAClB,cAAMqB,wBAAe,IAAA,GACfC,wBAAc,IAAA;AACpB,eAAKtB,KACLA,EAAO,MAAM,IAAI,YAAY,CAACuB,MAAS;AACtC,UAAIA,EAAK,KAAK,SAAS,kBAAkBA,EAAK,MAAM,MAAS,OAC5DF,EAAS,IAAI,OAAOE,EAAK,MAAM,EAAK,CAAC,IAErCA,EAAK,KAAK,SAAS,iBACnBA,EAAK,MAAM,MAAS,QAEpBD,EAAQ,IAAI,OAAOC,EAAK,MAAM,EAAK,CAAC;AAAA,QAEtC,CAAC,GACM,EAAE,UAAU,MAAM,KAAKF,CAAQ,GAAG,SAAS,MAAM,KAAKC,CAAO,EAAA,KAXhD,EAAE,UAAU,CAAA,GAAI,SAAS,GAAC;AAAA,MAY/C;AAAA;AAAA,MAGA,mBAAmB,MAAM;AACxB,YAAI,CAACtB,EAAQ,QAAO,EAAE,MAAM,GAAG,IAAI,EAAA;AACnC,cAAM,EAAE,MAAAwB,GAAM,IAAAC,EAAA,IAAOzB,EAAO,MAAM;AAClC,eAAO,EAAE,MAAAwB,GAAM,IAAAC,EAAA;AAAA,MAChB;AAAA,MACA,kBAAkB,CAACC,GAAKR,MAAS;AAChC,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMA,EAAE,SAAS,gBAAgBS,GAAKP,CAAU,CAAC;AAAA,MAC3D;AAAA,MACA,iBAAiB,MAAM;AACtB,YAAI,CAACnB,EAAQ,QAAO;AACpB,cAAM,EAAE,OAAA2B,MAAU3B,GACZ,EAAE,MAAAwB,GAAM,IAAAC,GAAI,OAAAG,EAAA,IAAUD,EAAM;AAClC,YAAI,CAACC;AACJ,iBAAOD,EAAM,IAAI,YAAYH,GAAMC,GAAI,GAAG;AAI3C,cAAMI,IAAeF,EAAM,OAAO,MAAM;AACxC,YAAIE,GAAc;AACjB,gBAAMC,IAAQC,GAAaJ,EAAM,IAAI,QAAQH,CAAI,GAAGK,CAAY;AAChE,cAAIC;AACH,mBAAOH,EAAM,IAAI,YAAYG,EAAM,MAAMA,EAAM,IAAI,GAAG;AAAA,QAExD;AACA,eAAO;AAAA,MACR;AAAA;AAAA,MAGA,mBAAmB,OAAO;AAAA,QACzB,OACC9B,GAAQ,QAAQ,gBAAgB,kBAChCA,GAAQ,UAAU,UAClB;AAAA,QACD,OAAOlD,KAAiB;AAAA,MAAA;AAAA;AAAA,MAIzB,mBAAmB,CAACkF,MACnBhC,IACGiC,GAAsBjC,GAAQgC,CAAS,IACvC,EAAE,MAAM,IAAI,MAAM,IAAI,SAAS,IAAM,gBAAgB,EAAA;AAAA,MAEzD,mBAAmB,CAACA,GAAWd,MAAS;AACvC,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMiB,EAA0BjB,GAAGe,GAAWb,CAAU,CAAC;AAAA,MACnE;AAAA,MAEA,cAAc,CAACa,MAAc;AAC5B,QAAApB,EAAQ,CAACK,MAAM;AACd,cAAIe,MAAc,QAAQ;AACzB,gBAAIG,IAAYlB,EAAE,MAAM,IAAI,QAAQ,OAAO;AAC3C,YAAAA,EAAE,MAAM,IAAI,YAAY,CAACM,GAAMG,OAE7BH,EAAK,KAAK,SAAS,oBACnBY,MAAclB,EAAE,MAAM,IAAI,QAAQ,OAAO,MAEzCkB,IAAYT,IAAM,IAEZS,MAAclB,EAAE,MAAM,IAAI,QAAQ,OAAO,EAChD,GACGkB,IAAY,MAAGA,IAAY,IAC/BlB,EAAE,QAAQ,MAAA,EAAQ,iBAAiBkB,CAAS,EAAE,IAAA;AAC9C;AAAA,UACD;AACA,cAAIC,IAAY;AAChB,UAAAnB,EAAE,MAAM,IAAI,YAAY,CAACM,GAAMG,MAAQ;AACtC,gBAAIU,MAAc,GAAI,QAAO;AAC7B,YACCb,EAAK,KAAK,SAAS,oBACnBA,EAAK,MAAM,cAAiBS,MAI5BI,IAAYV,IAAMH,EAAK,WAAW;AAAA,UAEpC,CAAC,GACGa,MAAc,MACjBnB,EAAE,QAAQ,MAAA,EAAQ,iBAAiBmB,CAAS,EAAE,IAAA;AAAA,QAEhD,CAAC;AAAA,MACF;AAAA,MAEA,cAAc,CAACJ,MAAc;AAC5B,QAAApB,EAAQ,CAACK,MAAMiB,EAA0BjB,GAAGe,GAAW,SAAS,CAAC;AAAA,MAClE;AAAA;AAAA,MAGA,gBAAgB,MACfhC,IACGqC,GAAmBrC,CAAM,IACzB,EAAE,MAAM,IAAI,MAAM,IAAI,SAAS,IAAM,gBAAgB,EAAA;AAAA,MACzD,gBAAgB,CAACkB,MAAS;AACzB,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAMiB,EAA0BjB,GAAG,QAAQE,CAAU,CAAC;AAAA,MAChE;AAAA,MACA,oBAAoB,CAACmB,GAAM3F,MAAa;AACvC,cAAMuE,IAAOnC;AAAA,UACZC,EAAcsD,CAAI;AAAA,UAClB3F,EAAS,IAAI,CAACsC,OAAO;AAAA,YACpB,IAAIA,EAAE;AAAA,YACN,SAASD,EAAcC,EAAE,OAAO;AAAA,UAAA,EAC/B;AAAA,QAAA;AAEH,QAAA2B,EAAQ,CAACK,MAAMA,EAAE,SAAS,WAAWC,GAAM,EAAE,YAAY,GAAA,CAAM,CAAC;AAAA,MACjE;AAAA,MACA,mBAAmB,CAACA,MAAS;AAC5B,cAAMC,IAAanC,EAAckC,CAAI;AAKrC,QAAAN,EAAQ,CAACK,MAAM;AACd,gBAAMsB,IAAcC,GAAkBvB,GAAG,MAAM;AAC/C,UAAAA,EAAE,SAAS,gBAAgBsB,IAAc,GAAGpB,GAAY;AAAA,YACvD,cAAc,EAAE,oBAAoB,GAAA;AAAA,UAAK,CACzC;AAAA,QACF,CAAC;AAAA,MACF;AAAA,MACA,sBAAsB,CAACa,GAAWd,MAAS;AAC1C,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAM;AACd,gBAAMS,IAAMe,GAAoBxB,GAAGe,CAAS;AAC5C,UAAIN,MAAQ,MACXT,EAAE,SAAS,gBAAgBS,GAAKP,GAAY;AAAA,YAC3C,cAAc,EAAE,oBAAoB,GAAA;AAAA,UAAK,CACzC;AAAA,QACH,CAAC;AAAA,MACF;AAAA,MACA,oBAAoB,CAACa,GAAWd,MAAS;AACxC,cAAMC,IAAanC,EAAckC,CAAI;AACrC,QAAAN,EAAQ,CAACK,MAAM;AACd,gBAAMS,IAAMc,GAAkBvB,GAAGe,CAAS;AAC1C,UAAAf,EAAE,SAAS,gBAAgBS,GAAKP,GAAY;AAAA,YAC3C,cAAc,EAAE,oBAAoB,GAAA;AAAA,UAAK,CACzC;AAAA,QACF,CAAC;AAAA,MACF;AAAA;AAAA,MAEA,kBAAkB,MACjBnB,IAASU,GAAqBV,CAAM,IAAIP;AAAA,MACzC,SAAS;AAAA,QACR,YAAY,MAAMO,GAAQ,MAAA,EAAQ,QAAQ,WAAA,EAAa,IAAA;AAAA,QACvD,cAAc,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,aAAA,EAAe,IAAA;AAAA,QAC3D,iBAAiB,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,gBAAA,EAAkB,IAAA;AAAA,QACjE,cAAc,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,aAAA,EAAe,IAAA;AAAA,QAC3D,kBAAkB,MACjBA,GAAQ,MAAA,EAAQ,QAAQ,iBAAA,EAAmB,IAAA;AAAA,QAC5C,mBAAmB,MAClBA,GAAQ,MAAA,EAAQ,QAAQ,kBAAA,EAAoB,IAAA;AAAA,QAC7C,kBAAkB,MACjBA,GAAQ,MAAA,EAAQ,QAAQ,iBAAA,EAAmB,IAAA;AAAA,QAC5C,iBAAiB,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,gBAAA,EAAkB,IAAA;AAAA,QACjE,cAAc,CAAC0C,MACd1C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,aAAa0C,CAAK,EAAE,IAAA;AAAA,QAC7C,eAAe,CAACC,MACf3C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,cAAc2C,CAAI,EAAE,IAAA;AAAA,QAC7C,aAAa,CAACC,MAAS5C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,YAAY4C,CAAI,EAAE,IAAA;AAAA,QACjE,UAAU,CAACC,MAAU7C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,SAAS6C,CAAK,EAAE,IAAA;AAAA,QAC7D,cAAc,CAACA,MACd7C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,gBAAgB,EAAE,OAAA6C,EAAA,CAAO,EAAE,IAAA;AAAA,QACpD,YAAY,MAAM7C,GAAQ,MAAA,EAAQ,QAAQ,WAAA,EAAa,IAAA;AAAA,QACvD,gBAAgB,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,eAAA,EAAiB,IAAA;AAAA,QAC/D,SAAS,CAAC8C,GAAMzC,MAAS;AACxB,UAAKL,MACDK,MAAS,SACZL,EACE,MAAA,EACA,MAAA,EACA,gBAAgB,MAAM,EACtB,QAAQ,CAAC,EAAE,IAAA+C,GAAI,OAAApB,EAAA,MAAY;AAC3B,kBAAM,EAAE,MAAAH,GAAM,IAAAC,EAAA,IAAOsB,EAAG,WAClBlB,IAAeF,EAAM,OAAO,MAAM;AACxC,gBAAI,CAACE,EAAc,QAAO;AAC1B,kBAAMmB,KAAWrB,EAAM,OAAO,KAAKtB,GAAM;AAAA,cACxCwB,EAAa,OAAO,EAAE,MAAAiB,EAAA,CAAM;AAAA,YAAA,CAC5B,GACKG,KAAQtB,EAAM,OAAO,KAAK,GAAG;AACnC,mBAAAoB,EAAG,YAAYvB,GAAMC,GAAI,CAACuB,IAAUC,EAAK,CAAC,GACnC;AAAA,UACR,CAAC,EACA,IAAA,IAEFjD,EACE,MAAA,EACA,MAAA,EACA,gBAAgB,MAAM,EACtB,QAAQ,EAAE,MAAA8C,GAAM,EAChB,cAAc,GAAG,EACjB,IAAA;AAAA,QAEJ;AAAA,QACA,YAAY,CAACA,MACZ9C,GACG,MAAA,EACD,MAAA,EACA,gBAAgB,MAAM,EACtB,QAAQ,EAAE,MAAA8C,EAAA,CAAM,EAChB,IAAA;AAAA,QACH,YAAY,MACX9C,GAAQ,MAAA,EAAQ,MAAA,EAAQ,gBAAgB,MAAM,EAAE,UAAA,EAAY,IAAA;AAAA,QAC7D,aAAa,CAACkD,MACblD,GAAQ,MAAA,EAAQ,MAAA,EAAQ,cAAckD,CAAK,EAAE,IAAA;AAAA,QAC9C,gBAAgB,CAACC,MAChBnD,GAAQ,MAAA,EAAQ,MAAA,EAAQ,cAAc,KAAKmD,CAAY,IAAI,EAAE,IAAA;AAAA,QAC9D,YAAY,CAACjC,MACZlB,GAAQ,SAAS,cAAchB,EAAckC,CAAI,CAAC;AAAA,QACnD,iBAAiB,CAACkC,IAAO,QAAQ;AAChC,cAAI,CAACpD;AACJ;AAID,gBAAM,EAAE,IAAAyB,EAAA,IAAOzB,EAAO,MAAM,WACtBW,IAAOc,IAAK,IAAIzB,EAAO,MAAM,IAAI,YAAYyB,IAAK,GAAGA,CAAE,IAAI,IAC3D4B,IAAa1C,MAAS,MAAM,CAAC,KAAK,KAAKA,CAAI;AACjD,UAAAX,EACE,MAAA,EACA,MAAA,EACA,iBAAiByB,CAAE,EACnB,cAAc4B,IAAa,IAAID,CAAI,KAAKA,CAAI,EAC5C,IAAA;AAAA,QACH;AAAA,QACA,MAAM,MAAMpD,GAAQ,MAAA,EAAQ,QAAQ,KAAA,EAAO,IAAA;AAAA,QAC3C,MAAM,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,KAAA,EAAO,IAAA;AAAA,QAC3C,SAAS,MAAMA,GAAQ,IAAA,EAAM,UAAU;AAAA,QACvC,SAAS,MAAMA,GAAQ,IAAA,EAAM,UAAU;AAAA,QACvC,mBAAmB,MAClBA,GAAQ,MAAA,EAAQ,QAAQ,kBAAA,EAAoB,IAAA;AAAA,QAC7C,iBAAiB,MAAMA,GAAQ,MAAA,EAAQ,QAAQ,gBAAA,EAAkB,IAAA;AAAA,QACjE,aAAa,CAACsD,MAAQtD,GAAQ,MAAA,EAAQ,MAAA,EAAQ,SAAS,EAAE,KAAAsD,EAAA,CAAK,EAAE,IAAA;AAAA,MAAI;AAAA;AAAA,MAIrE,MAAM1G,GAAU,WACb;AAAA,QACA,SAAS,MAAOoD,IAASM,EAAiBN,CAAM,IAAI;AAAA,QACpD,SAAS,CAACuD,MAAQ3C,EAAQ,CAACK,MAAMuC,EAAiBvC,GAAGsC,CAAG,CAAC;AAAA,QACzD,OAAO,MAAM/C,EAAUR,IAASM,EAAiBN,CAAM,IAAI,EAAE;AAAA,QAC7D,SAAS,MACRQ,EAAUR,IAASM,EAAiBN,CAAM,IAAI,EAAE,EAAE;AAAA,QACnD,QAAQ,CAACyD,IAAS,MACjB7C,EAAQ,CAACK,MAAM;AACd,gBAAM,EAAE,OAAAyC,GAAO,OAAAC,EAAA,IAAUnD,EAAUF,EAAiBW,CAAC,CAAC;AACtD,UAAI,CAACyC,KAASC,MAAU,QACxBH,EAAiBvC,GAAG,KAAK,UAAU0C,GAAO,MAAMF,CAAM,CAAC;AAAA,QACxD,CAAC;AAAA,QACF,QAAQ,MACP7C,EAAQ,CAAC,MAAM;AACd,gBAAM,EAAE,OAAA8C,GAAO,OAAAC,EAAA,IAAUnD,EAAUF,EAAiB,CAAC,CAAC;AACtD,UAAI,CAACoD,KAASC,MAAU,QACxBH,EAAiB,GAAG,KAAK,UAAUG,CAAK,CAAC;AAAA,QAC1C,CAAC;AAAA,MAAA,IAEF;AAAA,IAAA;AAAA;AAAA,IAGJ,CAAC3D,CAAM;AAAA,EAAA;AAMR,QAAM4D,KAAqB,MAAM;AAChC,QAAI,CAAC5D,EAAQ;AACb,UAAM,EAAE,OAAA0D,GAAO,OAAAC,EAAA,IAAUnD,EAAUF,EAAiBN,CAAM,CAAC;AAC3D,IAAI,CAAC0D,KAASC,MAAU,QACxBH,EAAiBxD,GAAQ,KAAK,UAAU2D,GAAO,MAAM,CAAC,CAAC;AAAA,EACxD,GACME,KAAiB,MAAM;AAC5B,IAAK7D,MACA,UAAU,WAAW,UAAUM,EAAiBN,CAAM,CAAC,GAC5DxB,EAAc,EAAI,GAClB,WAAW,MAAMA,EAAc,EAAK,GAAG,IAAI;AAAA,EAC5C;AAEA,SAAKwB,IAGJ,gBAAA8D;AAAA,IAACC;AAAA,IAAA;AAAA,MACA,WAAAlG;AAAA,MACA,WAAAC;AAAA,MACA,iBAAiB,CAAClB,GAAU;AAAA,MAC5B,UAAUuB;AAAA,MACV,OAAAhC;AAAA,MACA,WAAA4B;AAAA,MAEC,UAAA;AAAA,QAAAI,uBACC6F,IAAA,EACA,UAAA;AAAA,UAAA,gBAAAC,EAAC,QAAA,EAAK,WAAU,yBAAwB,UAAA,QAAI;AAAA,UAC5C,gBAAAH,EAAC,OAAA,EAAI,WAAU,2BACd,UAAA;AAAA,YAAA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACA,MAAK;AAAA,gBACL,SAASF;AAAA,gBACT,UAAU,CAAC,CAACxF,KAAaK;AAAA,gBACzB,OAAM;AAAA,gBAEN,UAAA;AAAA,kBAAA,gBAAAwF,EAACC,IAAA,EAAa,MAAM,GAAA,CAAI;AAAA,kBACxB,gBAAAD,EAACE,MAAY,UAAA,WAAA,CAAQ;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,YAEtB,gBAAAL;AAAA,cAAC;AAAA,cAAA;AAAA,gBACA,MAAK;AAAA,gBACL,SAASD;AAAA,gBACT,UAAUpF;AAAA,gBACV,OAAM;AAAA,gBAEN,UAAA;AAAA,kBAAA,gBAAAwF,EAACG,IAAA,EAAK,MAAM,GAAA,CAAI;AAAA,kBACf7F,MAAc,gBAAA0F,EAACE,IAAA,EAAY,UAAA,SAAA,CAAM;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACnC,EAAA,CACD;AAAA,QAAA,GACD;AAAA,QAEAhG,IACA,gBAAA2F,EAACO,IAAA,EAAY,QAAQ,CAAC,CAACjG,GACtB,UAAA;AAAA,UAAA,gBAAA6F,EAACK,MAAc,QAAAtE,GAAgB;AAAA,UAC9BvB,KAAa,CAACE,MACd,gBAAAmF,EAACS,IAAA,EAAkB,eAAW,IAC7B,UAAA;AAAA,YAAA,gBAAAN,EAACO,IAAA,EAAK,MAAM,GAAA,CAAI;AAAA,YAChB,gBAAAP,EAAC,QAAA,EAAM,UAAAzH,EAAM,eAAe,0BAAA,CAA0B;AAAA,UAAA,EAAA,CACvD;AAAA,QAAA,EAAA,CAEF,IAEA,gBAAAyH,EAACK,IAAA,EAAc,QAAAtE,EAAA,CAAgB;AAAA,QAEhC,gBAAAiE,EAACQ,IAAA,EAAe,QAAAzE,GAAgB,mBAAmB3C,IAAM,eAAe;AAAA,QACvEc,KAAcC,IACdF,IACCA,EAAgBE,CAAS,sBAExBsG,IAAA,EACA,UAAA;AAAA,UAAA,gBAAAT,EAACU,IAAA,EAAK,MAAM,GAAA,CAAI;AAAA,4BACf,QAAA,EACC,UAAA;AAAA,YAAAvG,EAAU,QAAQ,QAClB,gBAAA0F,EAAC,UAAA,EAAO,UAAA;AAAA,cAAA;AAAA,cACD1F,EAAU;AAAA,cACfA,EAAU,UAAU,OAClB,YAAYA,EAAU,MAAM,KAC5B;AAAA,cAAG;AAAA,cACJ;AAAA,YAAA,GACH;AAAA,YAEAA,EAAU;AAAA,UAAA,EAAA,CACZ;AAAA,QAAA,EAAA,CACD,IAEE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,IAtEc;AAyErB,GAEawG,KAAYC;AAAA,EACxBtI;AACD;AACAqI,GAAU,cAAc;"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import o, { css as i } from "styled-components";
|
|
2
2
|
import { COLORS as e, BASE_COLORS as r } from "../constants/Theme.js";
|
|
3
|
-
const s =
|
|
3
|
+
const s = o.div`
|
|
4
4
|
position: relative;
|
|
5
5
|
width: 100%;
|
|
6
6
|
|
|
7
7
|
.ProseMirror {
|
|
8
|
-
min-height: ${({ minHeight:
|
|
9
|
-
max-height: ${({ maxHeight:
|
|
8
|
+
min-height: ${({ minHeight: t }) => t ?? "60px"};
|
|
9
|
+
max-height: ${({ maxHeight: t }) => t ?? "none"};
|
|
10
10
|
overflow-y: auto;
|
|
11
11
|
outline: none;
|
|
12
12
|
font-size: 14px;
|
|
@@ -23,7 +23,7 @@ const s = t.div`
|
|
|
23
23
|
no paragraph-gap concept — paragraphs are tight (margin:0) regardless of
|
|
24
24
|
typed vs pasted. (A margin:0 attr still overrides to tight either way.) */
|
|
25
25
|
p {
|
|
26
|
-
margin: ${({ tightParagraphs:
|
|
26
|
+
margin: ${({ tightParagraphs: t }) => t ? "0" : "1em 0"};
|
|
27
27
|
padding: 0;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -91,6 +91,14 @@ const s = t.div`
|
|
|
91
91
|
border-radius: 4px;
|
|
92
92
|
font-weight: 500;
|
|
93
93
|
}
|
|
94
|
+
/* Variables render as the raw token ({{a.b.c}}) in brand purple — matching
|
|
95
|
+
the literal-text variable decoration, not a chip. */
|
|
96
|
+
.bik-mention[data-kind='variable'] {
|
|
97
|
+
color: ${e.content.brand};
|
|
98
|
+
background: transparent;
|
|
99
|
+
padding: 0;
|
|
100
|
+
font-weight: 500;
|
|
101
|
+
}
|
|
94
102
|
.bik-variable {
|
|
95
103
|
}
|
|
96
104
|
|
|
@@ -99,7 +107,7 @@ const s = t.div`
|
|
|
99
107
|
bar owns the top rounded border, the code area (BikJsonBody) owns its own
|
|
100
108
|
full border so it can recolour on focus / error without touching the
|
|
101
109
|
header. */
|
|
102
|
-
${({ jsonMode:
|
|
110
|
+
${({ jsonMode: t }) => t && i`
|
|
103
111
|
/* The code block IS the editor surface, sitting below the header bar.
|
|
104
112
|
White fills the scroller down to the min-height (no blank strip below
|
|
105
113
|
short JSON); the header owns the grey. */
|
|
@@ -202,7 +210,7 @@ const s = t.div`
|
|
|
202
210
|
text-decoration-color: #6366f1;
|
|
203
211
|
}
|
|
204
212
|
}
|
|
205
|
-
`, d =
|
|
213
|
+
`, d = o.div`
|
|
206
214
|
display: flex;
|
|
207
215
|
align-items: center;
|
|
208
216
|
justify-content: space-between;
|
|
@@ -250,18 +258,18 @@ const s = t.div`
|
|
|
250
258
|
cursor: not-allowed;
|
|
251
259
|
}
|
|
252
260
|
}
|
|
253
|
-
`, l =
|
|
261
|
+
`, l = o.div`
|
|
254
262
|
position: relative;
|
|
255
263
|
overflow: hidden;
|
|
256
264
|
background: ${e.surface.standard};
|
|
257
265
|
border: 1px solid
|
|
258
|
-
${({ $error:
|
|
266
|
+
${({ $error: t }) => t ? e.content.negative : e.stroke.primary};
|
|
259
267
|
border-radius: 0 0 4px 4px;
|
|
260
268
|
|
|
261
269
|
&:focus-within {
|
|
262
|
-
border-color: ${({ $error:
|
|
270
|
+
border-color: ${({ $error: t }) => t ? e.content.negative : r.brand[800]};
|
|
263
271
|
}
|
|
264
|
-
`, p =
|
|
272
|
+
`, p = o.div`
|
|
265
273
|
position: absolute;
|
|
266
274
|
inset: 0;
|
|
267
275
|
display: flex;
|
|
@@ -274,7 +282,7 @@ const s = t.div`
|
|
|
274
282
|
line-height: 20px;
|
|
275
283
|
pointer-events: none;
|
|
276
284
|
user-select: none;
|
|
277
|
-
`, h =
|
|
285
|
+
`, h = o.div`
|
|
278
286
|
display: flex;
|
|
279
287
|
align-items: flex-start;
|
|
280
288
|
gap: 8px;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BikEditor.styles.js","sources":["../../../src/editor/BikEditor.styles.ts"],"sourcesContent":["import styled, { css } from 'styled-components';\nimport { BASE_COLORS, COLORS } from '../constants/Theme';\n\nexport const BikEditorShell = styled.div<{\n\tminHeight?: string;\n\tmaxHeight?: string;\n\ttightParagraphs?: boolean;\n\tjsonMode?: boolean;\n}>`\n\tposition: relative;\n\twidth: 100%;\n\n\t.ProseMirror {\n\t\tmin-height: ${({ minHeight }) => minHeight ?? '60px'};\n\t\tmax-height: ${({ maxHeight }) => maxHeight ?? 'none'};\n\t\toverflow-y: auto;\n\t\toutline: none;\n\t\tfont-size: 14px;\n\t\tline-height: 1.5;\n\t\tword-break: break-word;\n\n\t\t/* Paragraph spacing.\n\t\t Email/signature (rich): paragraphs carry the browser-default 1em block\n\t\t margin — the SAME spacing the sent HTML gets (we emit plain <p>, which\n\t\t renders against the default <p> margin in Gmail and our email viewer),\n\t\t so editor view == emitted HTML == Gmail. A single Enter = a new\n\t\t paragraph with a visible gap, like pasted Gmail/ChatGPT/Docs content.\n\t\t Other channels (WhatsApp/IG/FB/comments) are plain-text messaging, with\n\t\t no paragraph-gap concept — paragraphs are tight (margin:0) regardless of\n\t\t typed vs pasted. (A margin:0 attr still overrides to tight either way.) */\n\t\tp {\n\t\t\tmargin: ${({ tightParagraphs }) => (tightParagraphs ? '0' : '1em 0')};\n\t\t\tpadding: 0;\n\t\t}\n\n\t\tul,\n\t\tol {\n\t\t\tmargin: 0;\n\t\t\tpadding-left: 1.5em;\n\t\t}\n\n\t\tli + li {\n\t\t\tmargin-top: 2px;\n\t\t}\n\n\t\t/* The empty placeholder paragraph shouldn't inherit the rich-mode 1em\n\t\t block margin (email/SMTP/signature) — otherwise the placeholder text\n\t\t is pushed down. Real (non-empty) paragraphs keep their spacing. */\n\t\tp.is-editor-empty:first-child {\n\t\t\tmargin: 0;\n\t\t}\n\n\t\tp.is-editor-empty:first-child::before {\n\t\t\tcontent: attr(data-placeholder);\n\t\t\tfloat: left;\n\t\t\tcolor: #adb5bd;\n\t\t\tpointer-events: none;\n\t\t\theight: 0;\n\t\t}\n\n\t\t/* hidden in-flow copy of the placeholder so a multi-line\n\t\t placeholder grows the editor instead of showing a scrollbar (the\n\t\t zero-height float above adds no height). -1lh cancels the caret line. */\n\t\tp.is-editor-empty:first-child::after {\n\t\t\tcontent: attr(data-placeholder);\n\t\t\tdisplay: block;\n\t\t\tvisibility: hidden;\n\t\t\tpointer-events: none;\n\t\t\tmargin-top: -1.5em; /* one line at the editor's line-height: 1.5 */\n\t\t\tmargin-top: -1lh;\n\t\t}\n\n\t\t/* Characters pasted beyond the soft character limit — rendered grey so the\n\t\t overflow is visible but clearly marked (see CharacterLimitExtension). */\n\t\t.bik-editor-overflow {\n\t\t\tcolor: ${COLORS.content.placeholder};\n\t\t}\n\t}\n\n\t.bik-mention {\n\t\tcolor: ${COLORS.content.brand};\n\t\tpadding: 1px 4px;\n\t}\n\t.bik-mention--team {\n\t\tcolor: ${COLORS.content.brand};\n\t}\n\t/* Typed mention chips (agent-builder): distinct colour per reference kind. */\n\t.bik-mention[data-kind='tool'] {\n\t\tcolor: #616161;\n\t\tbackground: #fafafa;\n\t\tborder-radius: 4px;\n\t\tfont-weight: 500;\n\t}\n\t.bik-mention[data-kind='subagent'] {\n\t\tcolor: #28458f;\n\t\tbackground: #e5f2ff;\n\t\tborder-radius: 4px;\n\t\tfont-weight: 500;\n\t}\n\t.bik-variable {\n\t}\n\n\t/* JSON body mode — scoped so normal-mode code blocks keep their default look\n\t (no reserved gutter, no monospace override). The frame is split: the header\n\t bar owns the top rounded border, the code area (BikJsonBody) owns its own\n\t full border so it can recolour on focus / error without touching the\n\t header. */\n\t${({ jsonMode }) =>\n\t\tjsonMode &&\n\t\tcss`\n\t\t\t/* The code block IS the editor surface, sitting below the header bar.\n\t\t\t White fills the scroller down to the min-height (no blank strip below\n\t\t\t short JSON); the header owns the grey. */\n\t\t\t.ProseMirror {\n\t\t\t\tpadding: 0;\n\t\t\t\tbackground: ${COLORS.surface.standard};\n\t\t\t}\n\t\t\t/* ProseMirror appends an empty trailing paragraph AFTER the code block\n\t\t\t (a <p><br class=\"ProseMirror-trailingBreak\"></p> caret-escape node).\n\t\t\t In JSON mode there's nothing to escape to — it only renders as a blank\n\t\t\t line under the JSON, which is the \"extra space at the bottom\". Hide it. */\n\t\t\t.ProseMirror pre + p {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t\t.ProseMirror pre {\n\t\t\t\tposition: relative;\n\t\t\t\tmargin: 0;\n\t\t\t\tbackground: transparent;\n\t\t\t\t/* Left padding reserves the line-number gutter; the gutter sits in it.\n\t\t\t\t Compact default (2-digit line numbers); JsonCodeBlockView widens\n\t\t\t\t both this and the gutter inline as the line count grows more digits. */\n\t\t\t\tpadding: 12px 12px 12px 3em;\n\t\t\t\tfont-family: 'SFMono-Regular', ui-monospace, 'JetBrains Mono', Menlo,\n\t\t\t\t\tConsolas, 'Liberation Mono', monospace;\n\t\t\t\tfont-size: 13px;\n\t\t\t\t/* INTEGER-px line box (not 1.6 ⇒ 20.8px). Browsers snap text line boxes\n\t\t\t\t to whole device pixels but not the gutter's flex-item heights, so a\n\t\t\t\t fractional line-height drifts them apart ~0.2px/line — by a couple\n\t\t\t\t thousand lines the gutter is hundreds of px short and the last lines\n\t\t\t\t lose their numbers. A whole-px line box on BOTH keeps them locked. */\n\t\t\t\tline-height: 21px;\n\t\t\t\twhite-space: pre;\n\t\t\t\toverflow-x: auto;\n\t\t\t\ttab-size: 2;\n\t\t\t}\n\t\t\t.ProseMirror pre code {\n\t\t\t\tbackground: none;\n\t\t\t\tpadding: 0;\n\t\t\t\tfont-size: inherit;\n\t\t\t\tcolor: #1f2328;\n\t\t\t}\n\t\t\t/* Line-number gutter — a contenteditable=false sibling of <code> rendered\n\t\t\t by the code-block node view (JsonCodeBlockView), absolutely positioned\n\t\t\t into the reserved left padding. It scrolls with <pre> as one block, so\n\t\t\t numbers stay aligned with their lines. Stacked right borders form one\n\t\t\t continuous divider. */\n\t\t\t.bik-json-gutter {\n\t\t\t\tposition: absolute;\n\t\t\t\tleft: 0;\n\t\t\t\ttop: 12px; /* == the code block's padding-top */\n\t\t\t\t/* Compact default (2-digit); JsonCodeBlockView sets the exact width\n\t\t\t\t inline from the line-number digit count, staying inside the pre's\n\t\t\t\t reserved left padding. */\n\t\t\t\twidth: 2.3em;\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\tuser-select: none;\n\t\t\t\t-webkit-user-select: none;\n\t\t\t\tpointer-events: none;\n\t\t\t}\n\t\t\t.bik-json-lineno {\n\t\t\t\tbox-sizing: border-box;\n\t\t\t\theight: 21px; /* == the code line box (whole px) so rows never drift */\n\t\t\t\tline-height: 21px;\n\t\t\t\tpadding-right: 0.7em;\n\t\t\t\ttext-align: right;\n\t\t\t\t/* Never let a line number break across two lines. */\n\t\t\t\twhite-space: nowrap;\n\t\t\t\tcolor: ${COLORS.content.placeholder};\n\t\t\t\tborder-right: 1px solid ${COLORS.stroke.primary};\n\t\t\t}\n\t\t\t.bik-json-key {\n\t\t\t\tcolor: #0550ae;\n\t\t\t}\n\t\t\t.bik-json-string {\n\t\t\t\tcolor: #0a7d33;\n\t\t\t}\n\t\t\t.bik-json-number {\n\t\t\t\tcolor: #b5590a;\n\t\t\t}\n\t\t\t.bik-json-boolean,\n\t\t\t.bik-json-null {\n\t\t\t\tcolor: #8250df;\n\t\t\t\tfont-weight: 500;\n\t\t\t}\n\t\t\t.bik-json-punct {\n\t\t\t\tcolor: #57606a;\n\t\t\t}\n\t\t`}\n\n\ta,\n\t.bik-link {\n\t\tcolor: #4f46e5;\n\t\ttext-decoration: underline;\n\t\ttext-decoration-color: #a5b4fc;\n\t\ttext-underline-offset: 2px;\n\t\tcursor: pointer;\n\t\t&:hover {\n\t\t\tcolor: #3730a3;\n\t\t\ttext-decoration-color: #6366f1;\n\t\t}\n\t}\n`;\n\n/**\n * jsonMode header bar: a \"JSON\" label on the left and the Beautify / Copy actions\n * on the right. Owns the frame's top rounded border (no bottom edge — the code\n * area below draws its own top border, so the seam stays a single line even when\n * it recolours on focus/error). Grey fill sets it apart from the white code\n * surface below.\n */\nexport const BikJsonHeader = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tbackground: ${COLORS.surface.subdued};\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-bottom: none;\n\tborder-radius: 4px 4px 0 0;\n\n\t.bik-json-header-label {\n\t\tfont-family: inherit;\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t\tcolor: ${COLORS.content.secondary};\n\t\tuser-select: none;\n\t}\n\n\t.bik-json-header-actions {\n\t\tdisplay: flex;\n\t\tgap: 8px;\n\t}\n\n\tbutton {\n\t\tdisplay: inline-flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\t\theight: 28px;\n\t\tpadding: 0 8px;\n\t\tfont-family: inherit;\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tcolor: ${COLORS.content.secondary};\n\t\tbackground: ${COLORS.surface.standard};\n\t\tborder: 1px solid ${COLORS.stroke.primary};\n\t\tborder-radius: 4px;\n\t\tcursor: pointer;\n\n\t\t&:hover:not(:disabled) {\n\t\t\tbackground: ${COLORS.surface.subdued};\n\t\t}\n\t\t&:disabled {\n\t\t\topacity: 0.5;\n\t\t\tcursor: not-allowed;\n\t\t}\n\t}\n`;\n\n/**\n * jsonMode code surface below the header. Owns the recolourable border: brand on\n * focus, negative when the JSON is invalid (error wins over focus).\n */\nexport const BikJsonBody = styled.div<{ $error?: boolean }>`\n\tposition: relative;\n\toverflow: hidden;\n\tbackground: ${COLORS.surface.standard};\n\tborder: 1px solid\n\t\t${({ $error }) =>\n\t\t\t$error ? COLORS.content.negative : COLORS.stroke.primary};\n\tborder-radius: 0 0 4px 4px;\n\n\t&:focus-within {\n\t\tborder-color: ${({ $error }) =>\n\t\t\t$error ? COLORS.content.negative : BASE_COLORS.brand['800']};\n\t}\n`;\n\n/**\n * jsonMode empty state: a centered code glyph + placeholder line over the code\n * area. Pointer-events off so clicks focus the editor.\n */\nexport const BikJsonEmptyState = styled.div`\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tcolor: ${COLORS.content.placeholder};\n\tfont-size: 14px;\n\tline-height: 20px;\n\tpointer-events: none;\n\tuser-select: none;\n`;\n\n/**\n * JSON parse-error alert rendered by BikEditor in jsonMode: a standalone rounded\n * card below the code area.\n */\nexport const BikJsonError = styled.div`\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tpadding: 12px;\n\t/* Match the surrounding UI text — without this the card falls back to the\n\t browser default serif instead of the app font. */\n\tfont-family: Inter;\n\tfont-size: 12px;\n\tline-height: 16px;\n\tcolor: ${COLORS.content.negative};\n\tbackground: ${COLORS.background.negative.light};\n\tborder: 1px solid ${COLORS.stroke.negative.lightAlt};\n\tborder-radius: 4px;\n\tword-break: break-word;\n\n\tsvg {\n\t\tflex-shrink: 0;\n\t}\n\n\tstrong {\n\t\tfont-weight: 600;\n\t}\n`;\n"],"names":["BikEditorShell","styled","minHeight","maxHeight","tightParagraphs","COLORS","jsonMode","css","BikJsonHeader","BikJsonBody","$error","BASE_COLORS","BikJsonEmptyState","BikJsonError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BikEditor.styles.js","sources":["../../../src/editor/BikEditor.styles.ts"],"sourcesContent":["import styled, { css } from 'styled-components';\nimport { BASE_COLORS, COLORS } from '../constants/Theme';\n\nexport const BikEditorShell = styled.div<{\n\tminHeight?: string;\n\tmaxHeight?: string;\n\ttightParagraphs?: boolean;\n\tjsonMode?: boolean;\n}>`\n\tposition: relative;\n\twidth: 100%;\n\n\t.ProseMirror {\n\t\tmin-height: ${({ minHeight }) => minHeight ?? '60px'};\n\t\tmax-height: ${({ maxHeight }) => maxHeight ?? 'none'};\n\t\toverflow-y: auto;\n\t\toutline: none;\n\t\tfont-size: 14px;\n\t\tline-height: 1.5;\n\t\tword-break: break-word;\n\n\t\t/* Paragraph spacing.\n\t\t Email/signature (rich): paragraphs carry the browser-default 1em block\n\t\t margin — the SAME spacing the sent HTML gets (we emit plain <p>, which\n\t\t renders against the default <p> margin in Gmail and our email viewer),\n\t\t so editor view == emitted HTML == Gmail. A single Enter = a new\n\t\t paragraph with a visible gap, like pasted Gmail/ChatGPT/Docs content.\n\t\t Other channels (WhatsApp/IG/FB/comments) are plain-text messaging, with\n\t\t no paragraph-gap concept — paragraphs are tight (margin:0) regardless of\n\t\t typed vs pasted. (A margin:0 attr still overrides to tight either way.) */\n\t\tp {\n\t\t\tmargin: ${({ tightParagraphs }) => (tightParagraphs ? '0' : '1em 0')};\n\t\t\tpadding: 0;\n\t\t}\n\n\t\tul,\n\t\tol {\n\t\t\tmargin: 0;\n\t\t\tpadding-left: 1.5em;\n\t\t}\n\n\t\tli + li {\n\t\t\tmargin-top: 2px;\n\t\t}\n\n\t\t/* The empty placeholder paragraph shouldn't inherit the rich-mode 1em\n\t\t block margin (email/SMTP/signature) — otherwise the placeholder text\n\t\t is pushed down. Real (non-empty) paragraphs keep their spacing. */\n\t\tp.is-editor-empty:first-child {\n\t\t\tmargin: 0;\n\t\t}\n\n\t\tp.is-editor-empty:first-child::before {\n\t\t\tcontent: attr(data-placeholder);\n\t\t\tfloat: left;\n\t\t\tcolor: #adb5bd;\n\t\t\tpointer-events: none;\n\t\t\theight: 0;\n\t\t}\n\n\t\t/* hidden in-flow copy of the placeholder so a multi-line\n\t\t placeholder grows the editor instead of showing a scrollbar (the\n\t\t zero-height float above adds no height). -1lh cancels the caret line. */\n\t\tp.is-editor-empty:first-child::after {\n\t\t\tcontent: attr(data-placeholder);\n\t\t\tdisplay: block;\n\t\t\tvisibility: hidden;\n\t\t\tpointer-events: none;\n\t\t\tmargin-top: -1.5em; /* one line at the editor's line-height: 1.5 */\n\t\t\tmargin-top: -1lh;\n\t\t}\n\n\t\t/* Characters pasted beyond the soft character limit — rendered grey so the\n\t\t overflow is visible but clearly marked (see CharacterLimitExtension). */\n\t\t.bik-editor-overflow {\n\t\t\tcolor: ${COLORS.content.placeholder};\n\t\t}\n\t}\n\n\t.bik-mention {\n\t\tcolor: ${COLORS.content.brand};\n\t\tpadding: 1px 4px;\n\t}\n\t.bik-mention--team {\n\t\tcolor: ${COLORS.content.brand};\n\t}\n\t/* Typed mention chips (agent-builder): distinct colour per reference kind. */\n\t.bik-mention[data-kind='tool'] {\n\t\tcolor: #616161;\n\t\tbackground: #fafafa;\n\t\tborder-radius: 4px;\n\t\tfont-weight: 500;\n\t}\n\t.bik-mention[data-kind='subagent'] {\n\t\tcolor: #28458f;\n\t\tbackground: #e5f2ff;\n\t\tborder-radius: 4px;\n\t\tfont-weight: 500;\n\t}\n\t/* Variables render as the raw token ({{a.b.c}}) in brand purple — matching\n\t the literal-text variable decoration, not a chip. */\n\t.bik-mention[data-kind='variable'] {\n\t\tcolor: ${COLORS.content.brand};\n\t\tbackground: transparent;\n\t\tpadding: 0;\n\t\tfont-weight: 500;\n\t}\n\t.bik-variable {\n\t}\n\n\t/* JSON body mode — scoped so normal-mode code blocks keep their default look\n\t (no reserved gutter, no monospace override). The frame is split: the header\n\t bar owns the top rounded border, the code area (BikJsonBody) owns its own\n\t full border so it can recolour on focus / error without touching the\n\t header. */\n\t${({ jsonMode }) =>\n\t\tjsonMode &&\n\t\tcss`\n\t\t\t/* The code block IS the editor surface, sitting below the header bar.\n\t\t\t White fills the scroller down to the min-height (no blank strip below\n\t\t\t short JSON); the header owns the grey. */\n\t\t\t.ProseMirror {\n\t\t\t\tpadding: 0;\n\t\t\t\tbackground: ${COLORS.surface.standard};\n\t\t\t}\n\t\t\t/* ProseMirror appends an empty trailing paragraph AFTER the code block\n\t\t\t (a <p><br class=\"ProseMirror-trailingBreak\"></p> caret-escape node).\n\t\t\t In JSON mode there's nothing to escape to — it only renders as a blank\n\t\t\t line under the JSON, which is the \"extra space at the bottom\". Hide it. */\n\t\t\t.ProseMirror pre + p {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t\t.ProseMirror pre {\n\t\t\t\tposition: relative;\n\t\t\t\tmargin: 0;\n\t\t\t\tbackground: transparent;\n\t\t\t\t/* Left padding reserves the line-number gutter; the gutter sits in it.\n\t\t\t\t Compact default (2-digit line numbers); JsonCodeBlockView widens\n\t\t\t\t both this and the gutter inline as the line count grows more digits. */\n\t\t\t\tpadding: 12px 12px 12px 3em;\n\t\t\t\tfont-family: 'SFMono-Regular', ui-monospace, 'JetBrains Mono', Menlo,\n\t\t\t\t\tConsolas, 'Liberation Mono', monospace;\n\t\t\t\tfont-size: 13px;\n\t\t\t\t/* INTEGER-px line box (not 1.6 ⇒ 20.8px). Browsers snap text line boxes\n\t\t\t\t to whole device pixels but not the gutter's flex-item heights, so a\n\t\t\t\t fractional line-height drifts them apart ~0.2px/line — by a couple\n\t\t\t\t thousand lines the gutter is hundreds of px short and the last lines\n\t\t\t\t lose their numbers. A whole-px line box on BOTH keeps them locked. */\n\t\t\t\tline-height: 21px;\n\t\t\t\twhite-space: pre;\n\t\t\t\toverflow-x: auto;\n\t\t\t\ttab-size: 2;\n\t\t\t}\n\t\t\t.ProseMirror pre code {\n\t\t\t\tbackground: none;\n\t\t\t\tpadding: 0;\n\t\t\t\tfont-size: inherit;\n\t\t\t\tcolor: #1f2328;\n\t\t\t}\n\t\t\t/* Line-number gutter — a contenteditable=false sibling of <code> rendered\n\t\t\t by the code-block node view (JsonCodeBlockView), absolutely positioned\n\t\t\t into the reserved left padding. It scrolls with <pre> as one block, so\n\t\t\t numbers stay aligned with their lines. Stacked right borders form one\n\t\t\t continuous divider. */\n\t\t\t.bik-json-gutter {\n\t\t\t\tposition: absolute;\n\t\t\t\tleft: 0;\n\t\t\t\ttop: 12px; /* == the code block's padding-top */\n\t\t\t\t/* Compact default (2-digit); JsonCodeBlockView sets the exact width\n\t\t\t\t inline from the line-number digit count, staying inside the pre's\n\t\t\t\t reserved left padding. */\n\t\t\t\twidth: 2.3em;\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\tuser-select: none;\n\t\t\t\t-webkit-user-select: none;\n\t\t\t\tpointer-events: none;\n\t\t\t}\n\t\t\t.bik-json-lineno {\n\t\t\t\tbox-sizing: border-box;\n\t\t\t\theight: 21px; /* == the code line box (whole px) so rows never drift */\n\t\t\t\tline-height: 21px;\n\t\t\t\tpadding-right: 0.7em;\n\t\t\t\ttext-align: right;\n\t\t\t\t/* Never let a line number break across two lines. */\n\t\t\t\twhite-space: nowrap;\n\t\t\t\tcolor: ${COLORS.content.placeholder};\n\t\t\t\tborder-right: 1px solid ${COLORS.stroke.primary};\n\t\t\t}\n\t\t\t.bik-json-key {\n\t\t\t\tcolor: #0550ae;\n\t\t\t}\n\t\t\t.bik-json-string {\n\t\t\t\tcolor: #0a7d33;\n\t\t\t}\n\t\t\t.bik-json-number {\n\t\t\t\tcolor: #b5590a;\n\t\t\t}\n\t\t\t.bik-json-boolean,\n\t\t\t.bik-json-null {\n\t\t\t\tcolor: #8250df;\n\t\t\t\tfont-weight: 500;\n\t\t\t}\n\t\t\t.bik-json-punct {\n\t\t\t\tcolor: #57606a;\n\t\t\t}\n\t\t`}\n\n\ta,\n\t.bik-link {\n\t\tcolor: #4f46e5;\n\t\ttext-decoration: underline;\n\t\ttext-decoration-color: #a5b4fc;\n\t\ttext-underline-offset: 2px;\n\t\tcursor: pointer;\n\t\t&:hover {\n\t\t\tcolor: #3730a3;\n\t\t\ttext-decoration-color: #6366f1;\n\t\t}\n\t}\n`;\n\n/**\n * jsonMode header bar: a \"JSON\" label on the left and the Beautify / Copy actions\n * on the right. Owns the frame's top rounded border (no bottom edge — the code\n * area below draws its own top border, so the seam stays a single line even when\n * it recolours on focus/error). Grey fill sets it apart from the white code\n * surface below.\n */\nexport const BikJsonHeader = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tpadding: 8px 12px;\n\tbackground: ${COLORS.surface.subdued};\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-bottom: none;\n\tborder-radius: 4px 4px 0 0;\n\n\t.bik-json-header-label {\n\t\tfont-family: inherit;\n\t\tfont-size: 14px;\n\t\tline-height: 20px;\n\t\tfont-weight: 400;\n\t\tcolor: ${COLORS.content.secondary};\n\t\tuser-select: none;\n\t}\n\n\t.bik-json-header-actions {\n\t\tdisplay: flex;\n\t\tgap: 8px;\n\t}\n\n\tbutton {\n\t\tdisplay: inline-flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\t\theight: 28px;\n\t\tpadding: 0 8px;\n\t\tfont-family: inherit;\n\t\tfont-size: 12px;\n\t\tline-height: 16px;\n\t\tcolor: ${COLORS.content.secondary};\n\t\tbackground: ${COLORS.surface.standard};\n\t\tborder: 1px solid ${COLORS.stroke.primary};\n\t\tborder-radius: 4px;\n\t\tcursor: pointer;\n\n\t\t&:hover:not(:disabled) {\n\t\t\tbackground: ${COLORS.surface.subdued};\n\t\t}\n\t\t&:disabled {\n\t\t\topacity: 0.5;\n\t\t\tcursor: not-allowed;\n\t\t}\n\t}\n`;\n\n/**\n * jsonMode code surface below the header. Owns the recolourable border: brand on\n * focus, negative when the JSON is invalid (error wins over focus).\n */\nexport const BikJsonBody = styled.div<{ $error?: boolean }>`\n\tposition: relative;\n\toverflow: hidden;\n\tbackground: ${COLORS.surface.standard};\n\tborder: 1px solid\n\t\t${({ $error }) =>\n\t\t\t$error ? COLORS.content.negative : COLORS.stroke.primary};\n\tborder-radius: 0 0 4px 4px;\n\n\t&:focus-within {\n\t\tborder-color: ${({ $error }) =>\n\t\t\t$error ? COLORS.content.negative : BASE_COLORS.brand['800']};\n\t}\n`;\n\n/**\n * jsonMode empty state: a centered code glyph + placeholder line over the code\n * area. Pointer-events off so clicks focus the editor.\n */\nexport const BikJsonEmptyState = styled.div`\n\tposition: absolute;\n\tinset: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tcolor: ${COLORS.content.placeholder};\n\tfont-size: 14px;\n\tline-height: 20px;\n\tpointer-events: none;\n\tuser-select: none;\n`;\n\n/**\n * JSON parse-error alert rendered by BikEditor in jsonMode: a standalone rounded\n * card below the code area.\n */\nexport const BikJsonError = styled.div`\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tpadding: 12px;\n\t/* Match the surrounding UI text — without this the card falls back to the\n\t browser default serif instead of the app font. */\n\tfont-family: Inter;\n\tfont-size: 12px;\n\tline-height: 16px;\n\tcolor: ${COLORS.content.negative};\n\tbackground: ${COLORS.background.negative.light};\n\tborder: 1px solid ${COLORS.stroke.negative.lightAlt};\n\tborder-radius: 4px;\n\tword-break: break-word;\n\n\tsvg {\n\t\tflex-shrink: 0;\n\t}\n\n\tstrong {\n\t\tfont-weight: 600;\n\t}\n`;\n"],"names":["BikEditorShell","styled","minHeight","maxHeight","tightParagraphs","COLORS","jsonMode","css","BikJsonHeader","BikJsonBody","$error","BASE_COLORS","BikJsonEmptyState","BikJsonError"],"mappings":"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"}
|
|
@@ -428,6 +428,15 @@ export interface EditorActions {
|
|
|
428
428
|
insertVariable: (variableName: string) => void;
|
|
429
429
|
/** Inserts arbitrary HTML at the current cursor position. */
|
|
430
430
|
insertHtml: (html: string) => void;
|
|
431
|
+
/**
|
|
432
|
+
* Opens the `@` / `#` mention menu at the cursor, exactly as if the user
|
|
433
|
+
* typed the trigger character — the same dropdown, selection handling and
|
|
434
|
+
* trigger-stripping apply. Inserts a leading space first when the cursor
|
|
435
|
+
* sits directly after a non-space character (the suggestion plugin only
|
|
436
|
+
* fires after whitespace). No-op when the matching mention list wasn't
|
|
437
|
+
* configured.
|
|
438
|
+
*/
|
|
439
|
+
openMentionMenu: (char?: '@' | '#') => void;
|
|
431
440
|
undo: () => void;
|
|
432
441
|
redo: () => void;
|
|
433
442
|
canUndo: () => boolean;
|