camox 0.40.0 → 0.41.1

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.
Files changed (108) hide show
  1. package/dist/components/PlatformLabel.js +62 -0
  2. package/dist/core/components/lexical/GradientNode.js +126 -0
  3. package/dist/core/components/lexical/InlineLexicalEditor.js +37 -56
  4. package/dist/core/components/lexical/InlineStylesPlugin.js +183 -0
  5. package/dist/core/components/lexical/SelectionBroadcaster.js +49 -46
  6. package/dist/core/components/lexical/SidebarLexicalEditor.js +197 -151
  7. package/dist/core/components/lexical/editorConfig.js +25 -7
  8. package/dist/core/components/lexical/selectTextLink.js +21 -0
  9. package/dist/core/createApp.d.ts +30 -17
  10. package/dist/core/createApp.js +14 -3
  11. package/dist/core/createBlock.d.ts +2 -2
  12. package/dist/core/createBlock.js +17 -28
  13. package/dist/core/createLayout.d.ts +48 -4
  14. package/dist/core/createLayout.js +51 -23
  15. package/dist/core/derivedRoutes.js +36 -0
  16. package/dist/core/editing/BlockEditingRuntime.js +4 -4
  17. package/dist/core/editing/CompleteBlockEditingRuntime.js +5 -5
  18. package/dist/core/editing/createEditableBlock.d.ts +9 -8
  19. package/dist/core/editing/createEditableBlock.js +265 -403
  20. package/dist/core/hooks/useIsEditable.js +4 -7
  21. package/dist/core/hooks/useRequireDraftSource.js +7 -11
  22. package/dist/core/lib/lexicalReact.d.ts +1 -26
  23. package/dist/core/lib/lexicalReact.js +46 -60
  24. package/dist/core/lib/lexicalState.js +164 -81
  25. package/dist/core/lib/modifierFormats.js +4 -15
  26. package/dist/core/lib/textStyles.d.ts +27 -0
  27. package/dist/core/lib/textStyles.js +47 -0
  28. package/dist/features/navigation/navigation.d.ts +2 -0
  29. package/dist/features/navigation/navigation.js +51 -46
  30. package/dist/features/page/DerivedPageContent.js +61 -0
  31. package/dist/features/page/PublishedPageContent.js +52 -83
  32. package/dist/features/page/SharedLayoutContent.js +66 -0
  33. package/dist/features/preview/CamoxPreview.d.ts +16 -1
  34. package/dist/features/preview/CamoxPreview.js +246 -290
  35. package/dist/features/preview/DerivedPreview.js +134 -0
  36. package/dist/features/preview/EditablePageExperience.js +25 -8
  37. package/dist/features/preview/components/AddBlockSidebar.js +43 -33
  38. package/dist/features/preview/components/AssetLightbox.js +1 -1
  39. package/dist/features/preview/components/BlockActionsPopover.js +8 -8
  40. package/dist/features/preview/components/BlockThumbnail.js +192 -0
  41. package/dist/features/preview/components/CreatePageModal.js +123 -115
  42. package/dist/features/preview/components/DerivedLayoutDialog.js +100 -0
  43. package/dist/features/preview/components/DerivedLayoutSidebar.d.ts +5 -0
  44. package/dist/features/preview/components/DerivedLayoutSidebar.js +160 -0
  45. package/dist/features/preview/components/DerivedPageInfoSidebar.js +57 -0
  46. package/dist/features/preview/components/FieldToolbar.js +42 -20
  47. package/dist/features/preview/components/Frame.js +133 -140
  48. package/dist/features/preview/components/LeftSidebar.js +42 -38
  49. package/dist/features/preview/components/LinkFieldEditor.js +3 -4
  50. package/dist/features/preview/components/MobilePreviewDrawer.js +4 -4
  51. package/dist/features/preview/components/Overlays.js +59 -47
  52. package/dist/features/preview/components/PageEditorSidebar.js +194 -203
  53. package/dist/features/preview/components/PageInfoSidebar.js +63 -55
  54. package/dist/features/preview/components/PageNavigatorSidebar.js +34 -483
  55. package/dist/features/preview/components/PagePicker.js +205 -153
  56. package/dist/features/preview/components/PageTree.js +366 -340
  57. package/dist/features/preview/components/PreviewActivation.js +78 -0
  58. package/dist/features/preview/components/PreviewPanel.js +98 -68
  59. package/dist/features/preview/components/PreviewToolbar.js +224 -241
  60. package/dist/features/preview/components/PreviewToolbarSpacer.js +43 -0
  61. package/dist/features/preview/components/PublicationRow.js +425 -0
  62. package/dist/features/preview/components/PublishDialog.js +180 -97
  63. package/dist/features/preview/components/RightSidebar.js +19 -34
  64. package/dist/features/preview/components/previewStyles.js +8 -0
  65. package/dist/features/preview/components/useUpdateBlockPosition.js +7 -13
  66. package/dist/features/preview/previewConstants.js +8 -0
  67. package/dist/features/preview/previewStore.js +18 -39
  68. package/dist/features/preview/publication.js +71 -0
  69. package/dist/features/provider/AuthenticatedCamoxProvider.js +2 -1
  70. package/dist/features/provider/CoreCamoxProvider.js +11 -2
  71. package/dist/features/provider/LocalhostPreviewProvider.js +6 -7
  72. package/dist/features/provider/useAdminShortcuts.js +5 -4
  73. package/dist/features/routes/pageRuntime.d.ts +10 -0
  74. package/dist/features/routes/pageRuntime.js +7 -9
  75. package/dist/features/runtime/PreviewDocumentContext.js +7 -0
  76. package/dist/features/runtime/RuntimeChrome.js +149 -0
  77. package/dist/features/runtime/SharedChromeContext.js +7 -0
  78. package/dist/features/runtime/navigationRequest.js +21 -0
  79. package/dist/features/runtime/navigationTarget.js +23 -0
  80. package/dist/features/runtime/pageApp.js +196 -121
  81. package/dist/features/runtime/pageNavigation.js +79 -130
  82. package/dist/features/runtime/runtime.d.ts +11 -0
  83. package/dist/features/runtime/runtime.js +183 -47
  84. package/dist/features/runtime/studioApp.d.ts +2 -11
  85. package/dist/features/runtime/studioApp.js +14 -177
  86. package/dist/features/studio/CamoxStudio.js +27 -13
  87. package/dist/features/studio/components/Navbar.js +80 -74
  88. package/dist/features/studio/components/UserButton.js +4 -4
  89. package/dist/features/studio/studioTheme.js +25 -0
  90. package/dist/features/studio/useTheme.js +94 -109
  91. package/dist/features/vite/appGeneration.js +12 -3
  92. package/dist/features/vite/definitionsSync.js +4 -2
  93. package/dist/features/vite/layoutGeneration.js +38 -0
  94. package/dist/features/vite/runtimeDev.js +3 -1
  95. package/dist/lib/auth.js +15 -13
  96. package/dist/lib/normalized-data.js +4 -4
  97. package/dist/lib/platform.js +13 -0
  98. package/dist/lib/utils.js +90 -38
  99. package/dist/studio-overlays.css +5 -40
  100. package/dist/studio.css +1 -1
  101. package/package.json +8 -4
  102. package/skills/camox/SKILL.md +2 -0
  103. package/skills/camox/references/block-definitions.md +31 -12
  104. package/skills/camox/references/layout-definitions.md +2 -0
  105. package/dist/core/lib/modifiers.js +0 -24
  106. package/dist/features/preview/components/DraftSwitchDialog.js +0 -66
  107. package/dist/features/preview/previewQueryFns.js +0 -23
  108. package/dist/features/runtime/studioNavigation.js +0 -120
@@ -1,14 +1,17 @@
1
+ import { FORMAT_FLAGS } from "../../lib/modifierFormats.js";
1
2
  import { isHttpTextLinkTarget } from "../../lib/textLinks.js";
3
+ import { lexicalStateToMarkdown } from "../../lib/lexicalState.js";
2
4
  import { INPUT_BASE_STYLES, INPUT_FOCUS_STYLES, cn } from "../../../lib/utils.js";
3
5
  import { TextLinkPopover } from "./TextLinkPopover.js";
4
- import { FORMAT_FLAGS } from "../../lib/modifierFormats.js";
5
- import { lexicalStateToMarkdown } from "../../lib/lexicalState.js";
6
+ import { $selectionHasGradient, $toggleGradient } from "./GradientNode.js";
6
7
  import { createEditorConfig, normalizeLexicalState } from "./editorConfig.js";
8
+ import { InlineStylesPlugin } from "./InlineStylesPlugin.js";
9
+ import { selectTextLink } from "./selectTextLink.js";
7
10
  import { c } from "react/compiler-runtime";
8
11
  import * as React from "react";
9
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
13
  import { Button } from "@camox/ui/button";
11
- import { Bold, Italic } from "lucide-react";
14
+ import { Blend, Bold, Italic, Underline } from "lucide-react";
12
15
  import { FloatingToolbar } from "@camox/ui/floating-toolbar";
13
16
  import { Toggle } from "@camox/ui/toggle";
14
17
  import { $createLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
@@ -24,9 +27,9 @@ import { $createTextNode, $getSelection, $isRangeSelection, $setSelection, COMMA
24
27
  //#region src/core/components/lexical/SidebarLexicalEditor.tsx
25
28
  function EnterAsLineBreakHandler() {
26
29
  const $ = c(4);
27
- if ($[0] !== "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2") {
30
+ if ($[0] !== "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05") {
28
31
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
29
- $[0] = "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2";
32
+ $[0] = "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05";
30
33
  }
31
34
  const [editor] = useLexicalComposerContext();
32
35
  let t0;
@@ -50,9 +53,9 @@ function EnterAsLineBreakHandler() {
50
53
  }
51
54
  function ExternalStateSync(t0) {
52
55
  const $ = c(6);
53
- if ($[0] !== "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2") {
56
+ if ($[0] !== "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05") {
54
57
  for (let $i = 0; $i < 6; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
55
- $[0] = "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2";
58
+ $[0] = "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05";
56
59
  }
57
60
  const { value, isSyncingRef } = t0;
58
61
  const [editor] = useLexicalComposerContext();
@@ -87,10 +90,10 @@ function ExternalStateSync(t0) {
87
90
  return null;
88
91
  }
89
92
  function SidebarFloatingTextToolbar() {
90
- const $ = c(66);
91
- if ($[0] !== "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2") {
92
- for (let $i = 0; $i < 66; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
93
- $[0] = "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2";
93
+ const $ = c(72);
94
+ if ($[0] !== "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05") {
95
+ for (let $i = 0; $i < 72; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
96
+ $[0] = "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05";
94
97
  }
95
98
  const [editor] = useLexicalComposerContext();
96
99
  const [open, setOpen] = React.useState(false);
@@ -112,6 +115,7 @@ function SidebarFloatingTextToolbar() {
112
115
  let t1;
113
116
  if ($[2] !== editor || $[3] !== open) {
114
117
  t1 = () => {
118
+ if (open) return;
115
119
  const root = editor.getRootElement();
116
120
  const nativeSelection = window.getSelection();
117
121
  if (!root || !nativeSelection || nativeSelection.rangeCount === 0 || nativeSelection.isCollapsed) {
@@ -139,6 +143,8 @@ function SidebarFloatingTextToolbar() {
139
143
  setSelectedText(selection.getTextContent());
140
144
  if (selection.hasFormat("bold")) activeFormats = activeFormats | FORMAT_FLAGS.bold;
141
145
  if (selection.hasFormat("italic")) activeFormats = activeFormats | FORMAT_FLAGS.italic;
146
+ if (selection.hasFormat("underline")) activeFormats = activeFormats | FORMAT_FLAGS.underline;
147
+ if ($selectionHasGradient()) activeFormats = activeFormats | FORMAT_FLAGS.gradient;
142
148
  let node = selection.anchor.getNode();
143
149
  while (node) {
144
150
  if (node.getType?.() === "link") {
@@ -201,8 +207,7 @@ function SidebarFloatingTextToolbar() {
201
207
  }
202
208
  React.useEffect(t4, t5);
203
209
  let t6;
204
- let t7;
205
- if ($[13] !== editor || $[14] !== updateToolbar) {
210
+ if ($[13] !== editor) {
206
211
  t6 = () => editor.registerRootListener((root_1) => {
207
212
  if (!root_1) return;
208
213
  const handleLinkClick = (event) => {
@@ -210,8 +215,7 @@ function SidebarFloatingTextToolbar() {
210
215
  if (!(target instanceof HTMLElement)) return;
211
216
  const anchor = target.closest("a");
212
217
  if (!anchor || !root_1.contains(anchor)) return;
213
- const href = anchor.getAttribute("href");
214
- if (!href) return;
218
+ if (!(anchor.dataset.camoxLinkTarget ?? anchor.getAttribute("href"))) return;
215
219
  event.preventDefault();
216
220
  event.stopPropagation();
217
221
  const rect_0 = anchor.getBoundingClientRect();
@@ -219,54 +223,56 @@ function SidebarFloatingTextToolbar() {
219
223
  top: rect_0.bottom + 8,
220
224
  left: rect_0.left + rect_0.width / 2
221
225
  });
222
- const doc_0 = root_1.ownerDocument;
223
- const range_0 = doc_0.createRange();
224
- range_0.selectNodeContents(anchor);
225
- const selection_0 = doc_0.getSelection();
226
- selection_0?.removeAllRanges();
227
- selection_0?.addRange(range_0);
228
- root_1.focus();
229
- setSelectedText(selection_0?.toString() ?? "");
230
- setLinkTarget(href);
226
+ const link = selectTextLink(editor, anchor);
227
+ if (!link) return;
228
+ lastSelectionRef.current = link.selection;
229
+ setSelectedText(link.text);
230
+ setLinkTarget(link.target);
231
231
  setOpen(true);
232
- updateToolbar();
233
232
  };
234
233
  root_1.addEventListener("click", handleLinkClick);
235
234
  return () => root_1.removeEventListener("click", handleLinkClick);
236
235
  });
237
- t7 = [editor, updateToolbar];
238
236
  $[13] = editor;
239
- $[14] = updateToolbar;
240
- $[15] = t6;
241
- $[16] = t7;
242
- } else {
243
- t6 = $[15];
244
- t7 = $[16];
245
- }
237
+ $[14] = t6;
238
+ } else t6 = $[14];
239
+ let t7;
240
+ if ($[15] !== editor || $[16] !== updateToolbar) {
241
+ t7 = [editor, updateToolbar];
242
+ $[15] = editor;
243
+ $[16] = updateToolbar;
244
+ $[17] = t7;
245
+ } else t7 = $[17];
246
246
  React.useEffect(t6, t7);
247
247
  let t8;
248
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
248
+ if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
249
249
  t8 = () => {
250
- const selection_1 = $getSelection();
251
- if ($isRangeSelection(selection_1) && !selection_1.isCollapsed()) return;
250
+ const selection_0 = $getSelection();
251
+ if ($isRangeSelection(selection_0) && !selection_0.isCollapsed()) return;
252
252
  if (!lastSelectionRef.current) return;
253
253
  $setSelection(lastSelectionRef.current.clone());
254
254
  };
255
- $[17] = t8;
256
- } else t8 = $[17];
255
+ $[18] = t8;
256
+ } else t8 = $[18];
257
257
  const restoreSelection = t8;
258
258
  let t9;
259
- if ($[18] !== editor) {
259
+ if ($[19] !== editor) {
260
260
  t9 = (formatKey) => {
261
- editor.update(restoreSelection);
262
- editor.dispatchCommand(FORMAT_TEXT_COMMAND, formatKey);
261
+ editor.update(() => {
262
+ restoreSelection();
263
+ if (formatKey === "gradient") {
264
+ $toggleGradient();
265
+ return;
266
+ }
267
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, formatKey);
268
+ });
263
269
  };
264
- $[18] = editor;
265
- $[19] = t9;
266
- } else t9 = $[19];
270
+ $[19] = editor;
271
+ $[20] = t9;
272
+ } else t9 = $[20];
267
273
  const applyFormat = t9;
268
274
  let t10;
269
- if ($[20] !== editor) {
275
+ if ($[21] !== editor) {
270
276
  t10 = (target_0, text) => {
271
277
  editor.update(() => {
272
278
  restoreSelection();
@@ -278,32 +284,32 @@ function SidebarFloatingTextToolbar() {
278
284
  editor.dispatchCommand(TOGGLE_LINK_COMMAND, target_0);
279
285
  return;
280
286
  }
281
- const selection_2 = $getSelection();
282
- if (!$isRangeSelection(selection_2)) return;
287
+ const selection_1 = $getSelection();
288
+ if (!$isRangeSelection(selection_1)) return;
283
289
  const linkNode = $createLinkNode(target_0);
284
290
  linkNode.append($createTextNode(text));
285
- selection_2.insertNodes([linkNode]);
291
+ selection_1.insertNodes([linkNode]);
286
292
  });
287
293
  setOpen(false);
288
294
  setLinkClickAnchor(null);
289
295
  };
290
- $[20] = editor;
291
- $[21] = t10;
292
- } else t10 = $[21];
296
+ $[21] = editor;
297
+ $[22] = t10;
298
+ } else t10 = $[22];
293
299
  const applyTarget = t10;
294
300
  let t11;
295
- if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
301
+ if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
296
302
  t11 = (nextOpen) => {
297
303
  setOpen(nextOpen);
298
304
  if (!nextOpen) setLinkClickAnchor(null);
299
305
  };
300
- $[22] = t11;
301
- } else t11 = $[22];
306
+ $[23] = t11;
307
+ } else t11 = $[23];
302
308
  const handleOpenChange = t11;
303
309
  const handleMouseDown = _temp;
304
310
  if (linkClickAnchor) {
305
311
  let t12;
306
- if ($[23] !== linkClickAnchor.left || $[24] !== linkClickAnchor.top) {
312
+ if ($[24] !== linkClickAnchor.left || $[25] !== linkClickAnchor.top) {
307
313
  t12 = /* @__PURE__ */ jsx(Button, {
308
314
  type: "button",
309
315
  variant: "ghost",
@@ -316,18 +322,18 @@ function SidebarFloatingTextToolbar() {
316
322
  left: linkClickAnchor.left
317
323
  }
318
324
  });
319
- $[23] = linkClickAnchor.left;
320
- $[24] = linkClickAnchor.top;
321
- $[25] = t12;
322
- } else t12 = $[25];
325
+ $[24] = linkClickAnchor.left;
326
+ $[25] = linkClickAnchor.top;
327
+ $[26] = t12;
328
+ } else t12 = $[26];
323
329
  let t13;
324
- if ($[26] !== applyTarget) {
330
+ if ($[27] !== applyTarget) {
325
331
  t13 = () => applyTarget(null);
326
- $[26] = applyTarget;
327
- $[27] = t13;
328
- } else t13 = $[27];
332
+ $[27] = applyTarget;
333
+ $[28] = t13;
334
+ } else t13 = $[28];
329
335
  let t14;
330
- if ($[28] !== applyTarget || $[29] !== linkTarget || $[30] !== open || $[31] !== selectedText || $[32] !== t12 || $[33] !== t13) {
336
+ if ($[29] !== applyTarget || $[30] !== linkTarget || $[31] !== open || $[32] !== selectedText || $[33] !== t12 || $[34] !== t13) {
331
337
  t14 = /* @__PURE__ */ jsx(TextLinkPopover, {
332
338
  open,
333
339
  onOpenChange: handleOpenChange,
@@ -337,42 +343,42 @@ function SidebarFloatingTextToolbar() {
337
343
  onSave: applyTarget,
338
344
  onUnlink: t13
339
345
  });
340
- $[28] = applyTarget;
341
- $[29] = linkTarget;
342
- $[30] = open;
343
- $[31] = selectedText;
344
- $[32] = t12;
345
- $[33] = t13;
346
- $[34] = t14;
347
- } else t14 = $[34];
346
+ $[29] = applyTarget;
347
+ $[30] = linkTarget;
348
+ $[31] = open;
349
+ $[32] = selectedText;
350
+ $[33] = t12;
351
+ $[34] = t13;
352
+ $[35] = t14;
353
+ } else t14 = $[35];
348
354
  return t14;
349
355
  }
350
356
  if (!toolbarState.visible) return null;
351
357
  let t12;
352
- if ($[35] !== toolbarState.left || $[36] !== toolbarState.top) {
358
+ if ($[36] !== toolbarState.left || $[37] !== toolbarState.top) {
353
359
  t12 = {
354
360
  top: toolbarState.top,
355
361
  left: toolbarState.left
356
362
  };
357
- $[35] = toolbarState.left;
358
- $[36] = toolbarState.top;
359
- $[37] = t12;
360
- } else t12 = $[37];
363
+ $[36] = toolbarState.left;
364
+ $[37] = toolbarState.top;
365
+ $[38] = t12;
366
+ } else t12 = $[38];
361
367
  const t13 = toolbarState.activeFormats & FORMAT_FLAGS.bold ? "on" : "off";
362
368
  const t14 = !!(toolbarState.activeFormats & FORMAT_FLAGS.bold);
363
369
  let t15;
364
- if ($[38] !== applyFormat) {
370
+ if ($[39] !== applyFormat) {
365
371
  t15 = () => applyFormat("bold");
366
- $[38] = applyFormat;
367
- $[39] = t15;
368
- } else t15 = $[39];
372
+ $[39] = applyFormat;
373
+ $[40] = t15;
374
+ } else t15 = $[40];
369
375
  let t16;
370
- if ($[40] === Symbol.for("react.memo_cache_sentinel")) {
376
+ if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
371
377
  t16 = /* @__PURE__ */ jsx(Bold, {});
372
- $[40] = t16;
373
- } else t16 = $[40];
378
+ $[41] = t16;
379
+ } else t16 = $[41];
374
380
  let t17;
375
- if ($[41] !== t13 || $[42] !== t14 || $[43] !== t15) {
381
+ if ($[42] !== t13 || $[43] !== t14 || $[44] !== t15) {
376
382
  t17 = /* @__PURE__ */ jsx(Toggle, {
377
383
  "data-state": t13,
378
384
  pressed: t14,
@@ -383,26 +389,26 @@ function SidebarFloatingTextToolbar() {
383
389
  onPressedChange: t15,
384
390
  children: t16
385
391
  });
386
- $[41] = t13;
387
- $[42] = t14;
388
- $[43] = t15;
389
- $[44] = t17;
390
- } else t17 = $[44];
392
+ $[42] = t13;
393
+ $[43] = t14;
394
+ $[44] = t15;
395
+ $[45] = t17;
396
+ } else t17 = $[45];
391
397
  const t18 = toolbarState.activeFormats & FORMAT_FLAGS.italic ? "on" : "off";
392
398
  const t19 = !!(toolbarState.activeFormats & FORMAT_FLAGS.italic);
393
399
  let t20;
394
- if ($[45] !== applyFormat) {
400
+ if ($[46] !== applyFormat) {
395
401
  t20 = () => applyFormat("italic");
396
- $[45] = applyFormat;
397
- $[46] = t20;
398
- } else t20 = $[46];
402
+ $[46] = applyFormat;
403
+ $[47] = t20;
404
+ } else t20 = $[47];
399
405
  let t21;
400
- if ($[47] === Symbol.for("react.memo_cache_sentinel")) {
406
+ if ($[48] === Symbol.for("react.memo_cache_sentinel")) {
401
407
  t21 = /* @__PURE__ */ jsx(Italic, {});
402
- $[47] = t21;
403
- } else t21 = $[47];
408
+ $[48] = t21;
409
+ } else t21 = $[48];
404
410
  let t22;
405
- if ($[48] !== t18 || $[49] !== t19 || $[50] !== t20) {
411
+ if ($[49] !== t18 || $[50] !== t19 || $[51] !== t20) {
406
412
  t22 = /* @__PURE__ */ jsx(Toggle, {
407
413
  "data-state": t18,
408
414
  pressed: t19,
@@ -413,64 +419,97 @@ function SidebarFloatingTextToolbar() {
413
419
  onPressedChange: t20,
414
420
  children: t21
415
421
  });
416
- $[48] = t18;
417
- $[49] = t19;
418
- $[50] = t20;
419
- $[51] = t22;
420
- } else t22 = $[51];
422
+ $[49] = t18;
423
+ $[50] = t19;
424
+ $[51] = t20;
425
+ $[52] = t22;
426
+ } else t22 = $[52];
421
427
  let t23;
422
- if ($[52] === Symbol.for("react.memo_cache_sentinel")) {
423
- t23 = /* @__PURE__ */ jsx(Button, {
428
+ if ($[53] === Symbol.for("react.memo_cache_sentinel")) {
429
+ t23 = [{
430
+ key: "underline",
431
+ label: "Underline",
432
+ icon: Underline
433
+ }, {
434
+ key: "gradient",
435
+ label: "Gradient",
436
+ icon: Blend
437
+ }];
438
+ $[53] = t23;
439
+ } else t23 = $[53];
440
+ let t24;
441
+ if ($[54] !== applyFormat || $[55] !== toolbarState.activeFormats) {
442
+ t24 = t23.map((t25) => {
443
+ const { key, label, icon: Icon } = t25;
444
+ return /* @__PURE__ */ jsx(Toggle, {
445
+ pressed: !!(toolbarState.activeFormats & FORMAT_FLAGS[key]),
446
+ variant: "default",
447
+ size: "sm",
448
+ className: "h-7 min-w-7 px-1.5",
449
+ "aria-label": label,
450
+ onPressedChange: () => applyFormat(key),
451
+ children: /* @__PURE__ */ jsx(Icon, {})
452
+ }, key);
453
+ });
454
+ $[54] = applyFormat;
455
+ $[55] = toolbarState.activeFormats;
456
+ $[56] = t24;
457
+ } else t24 = $[56];
458
+ let t25;
459
+ if ($[57] === Symbol.for("react.memo_cache_sentinel")) {
460
+ t25 = /* @__PURE__ */ jsx(Button, {
424
461
  type: "button",
425
462
  variant: "ghost",
426
463
  size: "sm",
427
464
  className: "text-foreground hover:text-foreground h-7 min-w-7 px-1.5"
428
465
  });
429
- $[52] = t23;
430
- } else t23 = $[52];
431
- let t24;
432
- if ($[53] !== applyTarget) {
433
- t24 = () => applyTarget(null);
434
- $[53] = applyTarget;
435
- $[54] = t24;
436
- } else t24 = $[54];
437
- let t25;
438
- if ($[55] !== applyTarget || $[56] !== linkTarget || $[57] !== open || $[58] !== selectedText || $[59] !== t24) {
439
- t25 = /* @__PURE__ */ jsx(TextLinkPopover, {
466
+ $[57] = t25;
467
+ } else t25 = $[57];
468
+ let t26;
469
+ if ($[58] !== applyTarget) {
470
+ t26 = () => applyTarget(null);
471
+ $[58] = applyTarget;
472
+ $[59] = t26;
473
+ } else t26 = $[59];
474
+ let t27;
475
+ if ($[60] !== applyTarget || $[61] !== linkTarget || $[62] !== open || $[63] !== selectedText || $[64] !== t26) {
476
+ t27 = /* @__PURE__ */ jsx(TextLinkPopover, {
440
477
  open,
441
478
  onOpenChange: handleOpenChange,
442
- trigger: t23,
479
+ trigger: t25,
443
480
  text: selectedText,
444
481
  target: linkTarget,
445
482
  onSave: applyTarget,
446
- onUnlink: t24
483
+ onUnlink: t26
447
484
  });
448
- $[55] = applyTarget;
449
- $[56] = linkTarget;
450
- $[57] = open;
451
- $[58] = selectedText;
452
- $[59] = t24;
453
- $[60] = t25;
454
- } else t25 = $[60];
455
- let t26;
456
- if ($[61] !== t12 || $[62] !== t17 || $[63] !== t22 || $[64] !== t25) {
457
- t26 = /* @__PURE__ */ jsxs(FloatingToolbar, {
485
+ $[60] = applyTarget;
486
+ $[61] = linkTarget;
487
+ $[62] = open;
488
+ $[63] = selectedText;
489
+ $[64] = t26;
490
+ $[65] = t27;
491
+ } else t27 = $[65];
492
+ let t28;
493
+ if ($[66] !== t12 || $[67] !== t17 || $[68] !== t22 || $[69] !== t24 || $[70] !== t27) {
494
+ t28 = /* @__PURE__ */ jsxs(FloatingToolbar, {
458
495
  onMouseDown: handleMouseDown,
459
496
  className: "fixed z-50 gap-0.5 rounded-lg p-1 shadow-lg",
460
497
  style: t12,
461
498
  children: [
462
499
  t17,
463
500
  t22,
464
- t25
501
+ t24,
502
+ t27
465
503
  ]
466
504
  });
467
- $[61] = t12;
468
- $[62] = t17;
469
- $[63] = t22;
470
- $[64] = t25;
471
- $[65] = t26;
472
- } else t26 = $[65];
473
- return t26;
505
+ $[66] = t12;
506
+ $[67] = t17;
507
+ $[68] = t22;
508
+ $[69] = t24;
509
+ $[70] = t27;
510
+ $[71] = t28;
511
+ } else t28 = $[71];
512
+ return t28;
474
513
  }
475
514
  function _temp(event_0) {
476
515
  const target_1 = event_0.target;
@@ -479,9 +518,9 @@ function _temp(event_0) {
479
518
  }
480
519
  function PasteUrlAsLinkHandler() {
481
520
  const $ = c(4);
482
- if ($[0] !== "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2") {
521
+ if ($[0] !== "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05") {
483
522
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
484
- $[0] = "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2";
523
+ $[0] = "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05";
485
524
  }
486
525
  const [editor] = useLexicalComposerContext();
487
526
  let t0;
@@ -513,6 +552,14 @@ function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
513
552
  const onChangeRef = React.useRef(onChange);
514
553
  onChangeRef.current = onChange;
515
554
  const isSyncingRef = React.useRef(false);
555
+ const pendingMarkdownRef = React.useRef(null);
556
+ const flushChange = React.useCallback(() => {
557
+ if (timerRef.current) clearTimeout(timerRef.current);
558
+ timerRef.current = null;
559
+ const markdown = pendingMarkdownRef.current;
560
+ pendingMarkdownRef.current = null;
561
+ if (markdown !== null) onChangeRef.current(markdown);
562
+ }, []);
516
563
  const config = React.useMemo(() => createEditorConfig(value), []);
517
564
  const handleChange = React.useCallback((editorState) => {
518
565
  if (isSyncingRef.current) {
@@ -520,15 +567,10 @@ function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
520
567
  return;
521
568
  }
522
569
  if (timerRef.current) clearTimeout(timerRef.current);
523
- timerRef.current = window.setTimeout(() => {
524
- onChangeRef.current(lexicalStateToMarkdown(editorState.toJSON()));
525
- }, 300);
526
- }, []);
527
- React.useEffect(() => {
528
- return () => {
529
- if (timerRef.current) clearTimeout(timerRef.current);
530
- };
531
- }, []);
570
+ pendingMarkdownRef.current = lexicalStateToMarkdown(editorState.toJSON());
571
+ timerRef.current = window.setTimeout(flushChange, 300);
572
+ }, [flushChange]);
573
+ React.useEffect(() => flushChange, [flushChange]);
532
574
  return /* @__PURE__ */ jsxs(LexicalComposer, {
533
575
  initialConfig: config,
534
576
  children: [
@@ -537,7 +579,10 @@ function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
537
579
  id,
538
580
  className: cn(INPUT_BASE_STYLES, INPUT_FOCUS_STYLES, "flex min-h-[80px] w-full px-3 py-2"),
539
581
  onFocus,
540
- onBlur
582
+ onBlur: () => {
583
+ flushChange();
584
+ onBlur?.();
585
+ }
541
586
  }),
542
587
  ErrorBoundary: LexicalErrorBoundary
543
588
  }),
@@ -553,15 +598,16 @@ function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
553
598
  }),
554
599
  /* @__PURE__ */ jsx(EnterAsLineBreakHandler, {}),
555
600
  /* @__PURE__ */ jsx(PasteUrlAsLinkHandler, {}),
556
- /* @__PURE__ */ jsx(SidebarFloatingTextToolbar, {})
601
+ /* @__PURE__ */ jsx(SidebarFloatingTextToolbar, {}),
602
+ /* @__PURE__ */ jsx(InlineStylesPlugin, {})
557
603
  ]
558
604
  });
559
605
  }
560
606
  function LexicalErrorBoundary(t0) {
561
607
  const $ = c(3);
562
- if ($[0] !== "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2") {
608
+ if ($[0] !== "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05") {
563
609
  for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
564
- $[0] = "487a2055e45cbfcdfeb0dfca78f86f0618f64602e19388a1a5bda9fa6e7197a2";
610
+ $[0] = "63fce41aab52cd282d26a73e81de9225d7bcf44f37fcaae7c81941ba12aafa05";
565
611
  }
566
612
  const { children } = t0;
567
613
  let t1;
@@ -1,16 +1,33 @@
1
1
  import { isLexicalState, markdownToLexicalState } from "../../lib/lexicalState.js";
2
+ import { GradientNode } from "./GradientNode.js";
2
3
  import { InlineParagraphNode } from "./InlineParagraphNode.js";
3
4
  import { LinkNode } from "@lexical/link";
4
5
  import { ParagraphNode } from "lexical";
5
6
 
6
7
  //#region src/core/components/lexical/editorConfig.ts
7
8
  function normalizeLexicalState(value) {
8
- if (typeof value === "object") {
9
- if (isLexicalState(value)) return JSON.stringify(value);
10
- return JSON.stringify(markdownToLexicalState(""));
11
- }
12
- if (isLexicalState(value)) return value;
13
- return JSON.stringify(markdownToLexicalState(value));
9
+ let state = markdownToLexicalState("");
10
+ if (isLexicalState(value)) state = typeof value === "string" ? JSON.parse(value) : value;
11
+ else if (typeof value === "string") state = markdownToLexicalState(value);
12
+ const paragraphs = state.root.children;
13
+ if (paragraphs.length <= 1) return JSON.stringify(state);
14
+ const children = paragraphs.flatMap((paragraph, index) => [...index ? [{
15
+ type: "linebreak",
16
+ version: 1
17
+ }, {
18
+ type: "linebreak",
19
+ version: 1
20
+ }] : [], ...paragraph.children ?? []]);
21
+ return JSON.stringify({
22
+ ...state,
23
+ root: {
24
+ ...state.root,
25
+ children: [{
26
+ ...paragraphs[0],
27
+ children
28
+ }]
29
+ }
30
+ });
14
31
  }
15
32
  function createEditorConfig(initialState) {
16
33
  return {
@@ -19,9 +36,10 @@ function createEditorConfig(initialState) {
19
36
  onError: (error) => {
20
37
  console.error("Lexical error:", error);
21
38
  },
22
- theme: { link: "camox-text-link" },
39
+ theme: {},
23
40
  nodes: [
24
41
  LinkNode,
42
+ GradientNode,
25
43
  InlineParagraphNode,
26
44
  {
27
45
  replace: ParagraphNode,
@@ -0,0 +1,21 @@
1
+ import { $isLinkNode } from "@lexical/link";
2
+ import { $getNearestNodeFromDOMNode } from "lexical";
3
+
4
+ //#region src/core/components/lexical/selectTextLink.ts
5
+ function selectTextLink(editor, anchor) {
6
+ let result = null;
7
+ editor.update(() => {
8
+ const node = $getNearestNodeFromDOMNode(anchor);
9
+ if (!$isLinkNode(node)) return;
10
+ const selection = node.select(0, node.getChildrenSize());
11
+ result = {
12
+ target: node.getURL(),
13
+ text: node.getTextContent(),
14
+ selection: selection.clone()
15
+ };
16
+ }, { discrete: true });
17
+ return result;
18
+ }
19
+
20
+ //#endregion
21
+ export { selectTextLink };