@tarviks/lexical-rich-editor 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5137,6 +5137,7 @@ function useDrag(onMove, onEnd, interactingRef) {
5137
5137
  interactingRef.current = false;
5138
5138
  }, 0);
5139
5139
  }
5140
+ onEnd?.();
5140
5141
  };
5141
5142
  window.addEventListener("mousemove", move);
5142
5143
  window.addEventListener("mouseup", up);
@@ -5145,11 +5146,18 @@ function useDrag(onMove, onEnd, interactingRef) {
5145
5146
  );
5146
5147
  return start;
5147
5148
  }
5148
- var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5149
+ var ColorPickerControl = ({ value, title, disabled, onChange, icon, onOpenChange }) => {
5149
5150
  const [open, setOpen] = React9__namespace.useState(false);
5150
5151
  const btnRef = React9__namespace.useRef(null);
5152
+ const setOpenAndNotify = React9__namespace.useCallback(
5153
+ (next) => {
5154
+ setOpen(next);
5155
+ onOpenChange?.(next);
5156
+ },
5157
+ [onOpenChange]
5158
+ );
5151
5159
  const interactingRef = React9__namespace.useRef(false);
5152
- const handleDismiss = React9__namespace.useCallback(() => setOpen(false), []);
5160
+ const handleDismiss = React9__namespace.useCallback(() => setOpenAndNotify(false), [setOpenAndNotify]);
5153
5161
  const preventDismissOnEvent = React9__namespace.useCallback(
5154
5162
  (ev) => {
5155
5163
  if (interactingRef.current) return true;
@@ -5205,17 +5213,33 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5205
5213
  setS(next.s);
5206
5214
  setV(next.v);
5207
5215
  }, [value, open]);
5216
+ const updateHexFromHsv = React9__namespace.useCallback((hh, ss, vv) => {
5217
+ const rgb = hsvToRgb(hh, ss, vv);
5218
+ const nextHex = rgbToHex(rgb.r, rgb.g, rgb.b);
5219
+ setHex(nextHex);
5220
+ return nextHex;
5221
+ }, []);
5208
5222
  const commitHsv = React9__namespace.useCallback(
5209
5223
  (hh, ss, vv, close) => {
5210
- const rgb = hsvToRgb(hh, ss, vv);
5211
- const nextHex = rgbToHex(rgb.r, rgb.g, rgb.b);
5212
- setHex(nextHex);
5224
+ const nextHex = updateHexFromHsv(hh, ss, vv);
5213
5225
  console.log("[AO-ColorPicker]", title, "commitHsv -> onChange", { nextHex, close: !!close });
5214
5226
  onChange(nextHex);
5215
- if (close) setOpen(false);
5227
+ if (close) setOpenAndNotify(false);
5216
5228
  },
5217
- [onChange, title]
5229
+ [onChange, title, setOpenAndNotify, updateHexFromHsv]
5218
5230
  );
5231
+ const hRef = React9__namespace.useRef(h);
5232
+ const sRef = React9__namespace.useRef(s);
5233
+ const vRef = React9__namespace.useRef(v);
5234
+ React9__namespace.useEffect(() => {
5235
+ hRef.current = h;
5236
+ }, [h]);
5237
+ React9__namespace.useEffect(() => {
5238
+ sRef.current = s;
5239
+ }, [s]);
5240
+ React9__namespace.useEffect(() => {
5241
+ vRef.current = v;
5242
+ }, [v]);
5219
5243
  const svRef = React9__namespace.useRef(null);
5220
5244
  const onSVMove = React9__namespace.useCallback(
5221
5245
  (clientX, clientY) => {
@@ -5227,11 +5251,16 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5227
5251
  const vv = rect.height === 0 ? 0 : 1 - y / rect.height;
5228
5252
  setS(ss);
5229
5253
  setV(vv);
5230
- commitHsv(h, ss, vv);
5254
+ sRef.current = ss;
5255
+ vRef.current = vv;
5256
+ updateHexFromHsv(hRef.current, ss, vv);
5231
5257
  },
5232
- [h, commitHsv]
5258
+ [updateHexFromHsv]
5233
5259
  );
5234
- const startSV = useDrag(onSVMove, void 0, interactingRef);
5260
+ const commitSV = React9__namespace.useCallback(() => {
5261
+ commitHsv(hRef.current, sRef.current, vRef.current);
5262
+ }, [commitHsv]);
5263
+ const startSV = useDrag(onSVMove, commitSV, interactingRef);
5235
5264
  const hueRef = React9__namespace.useRef(null);
5236
5265
  const onHueMove = React9__namespace.useCallback(
5237
5266
  (clientX) => {
@@ -5240,11 +5269,15 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5240
5269
  const x = clamp3(clientX - rect.left, 0, rect.width);
5241
5270
  const hh = rect.width === 0 ? 0 : x / rect.width * 360;
5242
5271
  setH(hh);
5243
- commitHsv(hh, s, v);
5272
+ hRef.current = hh;
5273
+ updateHexFromHsv(hh, sRef.current, vRef.current);
5244
5274
  },
5245
- [s, v, commitHsv]
5275
+ [updateHexFromHsv]
5246
5276
  );
5247
- const startHue = useDrag((x) => onHueMove(x), void 0, interactingRef);
5277
+ const commitHue = React9__namespace.useCallback(() => {
5278
+ commitHsv(hRef.current, sRef.current, vRef.current);
5279
+ }, [commitHsv]);
5280
+ const startHue = useDrag((x) => onHueMove(x), commitHue, interactingRef);
5248
5281
  const svThumb = React9__namespace.useMemo(() => ({ left: `${s * 100}%`, top: `${(1 - v) * 100}%` }), [s, v]);
5249
5282
  const hueThumb = React9__namespace.useMemo(() => ({ left: `${h / 360 * 100}%` }), [h]);
5250
5283
  const hueColor = React9__namespace.useMemo(() => {
@@ -5273,7 +5306,7 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5273
5306
  wasOpen: open,
5274
5307
  activeElementBeforeToggle: document.activeElement?.tagName
5275
5308
  });
5276
- setOpen((p) => !p);
5309
+ setOpenAndNotify(!open);
5277
5310
  }
5278
5311
  }
5279
5312
  ),
@@ -5368,7 +5401,7 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon }) => {
5368
5401
  }
5369
5402
  }
5370
5403
  ),
5371
- /* @__PURE__ */ jsxRuntime.jsx(react.DefaultButton, { type: "button", text: "Close", onClick: () => setOpen(false) })
5404
+ /* @__PURE__ */ jsxRuntime.jsx(react.DefaultButton, { type: "button", text: "Close", onClick: () => setOpenAndNotify(false) })
5372
5405
  ] })
5373
5406
  ] })
5374
5407
  }
@@ -5413,53 +5446,68 @@ var ColorPickerPlugin = ({ disabled }) => {
5413
5446
  )
5414
5447
  );
5415
5448
  }, [editor]);
5449
+ const wasEditorActiveRef = React9__namespace.default.useRef(false);
5450
+ const handleOpenChange = (open) => {
5451
+ if (open) {
5452
+ const root = editor.getRootElement();
5453
+ wasEditorActiveRef.current = !!root && (document.activeElement === root || root.contains(document.activeElement));
5454
+ } else if (wasEditorActiveRef.current) {
5455
+ editor.focus();
5456
+ }
5457
+ };
5416
5458
  const applyStyle = (args) => {
5417
5459
  if (disabled) return;
5418
- const root = editor.getRootElement();
5419
- const editorIsActive = !!lastRangeSelectionRef.current && !!root && (document.activeElement === root || root.contains(document.activeElement));
5420
5460
  console.log("[AO-ColorPicker] applyStyle called", {
5421
5461
  property: args.property,
5422
5462
  color: args.color,
5423
5463
  hasSavedSelection: !!lastRangeSelectionRef.current,
5424
5464
  savedSelectionIsCollapsed: lastRangeSelectionRef.current?.isCollapsed() ?? null,
5425
- editorIsActive,
5465
+ wasEditorActiveAtOpen: wasEditorActiveRef.current,
5426
5466
  activeElementTag: document.activeElement?.tagName,
5427
- activeElementClass: document.activeElement?.className,
5428
- rootIsActiveElement: document.activeElement === root,
5429
- rootContainsActiveElement: !!root && root.contains(document.activeElement)
5467
+ activeElementClass: document.activeElement?.className
5430
5468
  });
5431
- if (editorIsActive) editor.focus();
5432
- editor.update(() => {
5433
- const saved = lastRangeSelectionRef.current;
5434
- if (saved) {
5435
- lexical.$setSelection(saved.clone());
5436
- }
5437
- const selection$1 = lexical.$getSelection();
5438
- const isRange = lexical.$isRangeSelection(selection$1);
5439
- console.log("[AO-ColorPicker] applyStyle inside editor.update", {
5440
- hadSavedSelection: !!saved,
5441
- selectionAfterRestoreIsRange: isRange,
5442
- selectionAfterRestoreIsCollapsed: isRange ? selection$1.isCollapsed() : null
5443
- });
5444
- if (isRange) {
5445
- selection.$patchStyleText(selection$1, { [args.property]: args.color });
5446
- const verify = selection.$getSelectionStyleValueForProperty(
5447
- selection$1,
5448
- args.property,
5449
- "<none>"
5450
- );
5451
- console.log("[AO-ColorPicker] applyStyle after patchStyleText, readback in same update", {
5452
- property: args.property,
5453
- appliedColor: args.color,
5454
- readBack: verify
5469
+ editor.update(
5470
+ () => {
5471
+ const saved = lastRangeSelectionRef.current;
5472
+ if (saved) {
5473
+ lexical.$setSelection(saved.clone());
5474
+ }
5475
+ const selection$1 = lexical.$getSelection();
5476
+ const isRange = lexical.$isRangeSelection(selection$1);
5477
+ console.log("[AO-ColorPicker] applyStyle inside editor.update", {
5478
+ hadSavedSelection: !!saved,
5479
+ selectionAfterRestoreIsRange: isRange,
5480
+ selectionAfterRestoreIsCollapsed: isRange ? selection$1.isCollapsed() : null
5455
5481
  });
5456
- } else {
5457
- console.warn(
5458
- "[AO-ColorPicker] applyStyle: no range selection available \u2014 style was NOT applied",
5459
- { property: args.property, color: args.color }
5460
- );
5461
- }
5462
- });
5482
+ if (isRange) {
5483
+ selection.$patchStyleText(selection$1, { [args.property]: args.color });
5484
+ const verify = selection.$getSelectionStyleValueForProperty(
5485
+ selection$1,
5486
+ args.property,
5487
+ "<none>"
5488
+ );
5489
+ console.log("[AO-ColorPicker] applyStyle after patchStyleText, readback in same update", {
5490
+ property: args.property,
5491
+ appliedColor: args.color,
5492
+ readBack: verify
5493
+ });
5494
+ } else {
5495
+ console.warn(
5496
+ "[AO-ColorPicker] applyStyle: no range selection available \u2014 style was NOT applied",
5497
+ { property: args.property, color: args.color }
5498
+ );
5499
+ }
5500
+ },
5501
+ // Without this tag, Lexical's reconciler force-focuses the editor root
5502
+ // whenever this update's selection diff finds the root isn't already
5503
+ // focused (see Lexical.dev.mjs ~8112) — which it never is while the
5504
+ // color picker's Callout legitimately holds focus. That forced focus
5505
+ // then fights Fluent's Callout for focus on every single drag-driven
5506
+ // commit, repeatedly bouncing focus (and, via FocusEventsPlugin,
5507
+ // nulling and restoring the selection) between the editor and the
5508
+ // popover until the drag's tracked color desynced from the cursor.
5509
+ { tag: lexical.SKIP_SELECTION_FOCUS_TAG }
5510
+ );
5463
5511
  };
5464
5512
  const containerStyle = disabled ? {
5465
5513
  display: "flex",
@@ -5483,7 +5531,8 @@ var ColorPickerPlugin = ({ disabled }) => {
5483
5531
  title: "Text color",
5484
5532
  disabled,
5485
5533
  icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.TextColorRegular, { style: { color: iconColor } }),
5486
- onChange: (c) => applyStyle({ property: "color", color: c })
5534
+ onChange: (c) => applyStyle({ property: "color", color: c }),
5535
+ onOpenChange: handleOpenChange
5487
5536
  }
5488
5537
  ),
5489
5538
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5493,7 +5542,8 @@ var ColorPickerPlugin = ({ disabled }) => {
5493
5542
  title: "Background color",
5494
5543
  disabled,
5495
5544
  icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.PaintBucket16Filled, { style: { color: iconColor } }),
5496
- onChange: (c) => applyStyle({ property: "background-color", color: c })
5545
+ onChange: (c) => applyStyle({ property: "background-color", color: c }),
5546
+ onOpenChange: handleOpenChange
5497
5547
  }
5498
5548
  )
5499
5549
  ] });