roosterjs 8.40.1 → 8.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2843,9 +2843,11 @@ function getElementBasedFormatState(editor, event) {
2843
2843
  canUnlink: !!editor.queryElements('a[href]', 1 /* OnSelection */)[0],
2844
2844
  canAddImageAltText: !!editor.queryElements('img', 1 /* OnSelection */)[0],
2845
2845
  isBlockQuote: !!editor.queryElements('blockquote', 1 /* OnSelection */)[0],
2846
+ isCodeBlock: !!editor.queryElements('pre>code', 1 /* OnSelection */)[0],
2846
2847
  isInTable: !!table,
2847
2848
  tableFormat: tableFormat,
2848
2849
  tableHasHeader: hasHeader,
2850
+ canMergeTableCell: canMergeTableCell(editor),
2849
2851
  };
2850
2852
  }
2851
2853
  exports.getElementBasedFormatState = getElementBasedFormatState;
@@ -2863,6 +2865,23 @@ function getFormatState(editor, event) {
2863
2865
  return __assign(__assign(__assign(__assign(__assign({}, editor.getPendableFormatState(false /* forceGetStateFromDom */)), getElementBasedFormatState(editor, event)), editor.getStyleBasedFormatState()), editor.getUndoState()), { isDarkMode: editor.isDarkMode(), zoomScale: editor.getZoomScale() });
2864
2866
  }
2865
2867
  exports.default = getFormatState;
2868
+ /**
2869
+ * Checks whether the editor selection range is starting and ending at a table element.
2870
+ * @param editor Editor Instance
2871
+ * @returns
2872
+ */
2873
+ var canMergeTableCell = function (editor) {
2874
+ var selection = editor.getSelectionRangeEx();
2875
+ var isATable = selection && selection.type === 1 /* TableSelection */;
2876
+ if (isATable && selection.coordinates) {
2877
+ var _a = selection.coordinates, firstCell = _a.firstCell, lastCell = _a.lastCell;
2878
+ if (firstCell.x !== lastCell.x || firstCell.y !== lastCell.y) {
2879
+ return true;
2880
+ }
2881
+ return false;
2882
+ }
2883
+ return false;
2884
+ };
2866
2885
 
2867
2886
 
2868
2887
  /***/ }),
@@ -3237,7 +3256,7 @@ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./
3237
3256
  **/
3238
3257
  function setBackgroundColor(editor, color) {
3239
3258
  (0, applyInlineStyle_1.default)(editor, function (element, isInnerNode) {
3240
- (0, roosterjs_editor_dom_1.setColor)(element, isInnerNode ? '' : color, true /*isBackground*/, editor.isDarkMode());
3259
+ (0, roosterjs_editor_dom_1.setColor)(element, isInnerNode ? '' : color, true /*isBackground*/, editor.isDarkMode(), false /*shouldAdaptFontColor*/, editor.getDarkColorHandler());
3241
3260
  }, 'setBackgroundColor');
3242
3261
  }
3243
3262
  exports.default = setBackgroundColor;
@@ -3542,7 +3561,7 @@ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./
3542
3561
  function setTextColor(editor, color, shouldApplyInlineStyle) {
3543
3562
  (0, applyListItemWrap_1.default)(editor, 'color', function (element, isInnerNode) {
3544
3563
  if (!shouldApplyInlineStyle || shouldApplyInlineStyle(element)) {
3545
- (0, roosterjs_editor_dom_1.setColor)(element, isInnerNode ? '' : color, false /*isBackground*/, editor.isDarkMode());
3564
+ (0, roosterjs_editor_dom_1.setColor)(element, isInnerNode ? '' : color, false /*isBackground*/, editor.isDarkMode(), false /*shouldAdaptFontColor*/, editor.getDarkColorHandler());
3546
3565
  }
3547
3566
  }, 'setTextColor');
3548
3567
  }
@@ -4025,7 +4044,7 @@ function applyCellShading(editor, color) {
4025
4044
  var regions = editor.getSelectedRegions();
4026
4045
  regions.forEach(function (region) {
4027
4046
  if ((0, roosterjs_editor_dom_1.safeInstanceOf)(region.rootNode, 'HTMLTableCellElement')) {
4028
- (0, roosterjs_editor_dom_1.setColor)(region.rootNode, color, true /* isBackgroundColor */, editor.isDarkMode(), true /** shouldAdaptFontColor */);
4047
+ (0, roosterjs_editor_dom_1.setColor)(region.rootNode, color, true /* isBackgroundColor */, editor.isDarkMode(), true /** shouldAdaptFontColor */, editor.getDarkColorHandler());
4029
4048
  (0, roosterjs_editor_dom_1.saveTableCellMetadata)(region.rootNode, { bgColorOverride: true });
4030
4049
  }
4031
4050
  });
@@ -5177,7 +5196,7 @@ var ensureTypeInContainer = function (core, position, keyboardEvent, applyFormat
5177
5196
  position = new roosterjs_editor_dom_1.Position(formatNode, 0 /* Begin */);
5178
5197
  }
5179
5198
  if (formatNode && core.lifecycle.defaultFormat) {
5180
- (0, roosterjs_editor_dom_1.applyFormat)(formatNode, core.lifecycle.defaultFormat, core.lifecycle.isDarkMode);
5199
+ (0, roosterjs_editor_dom_1.applyFormat)(formatNode, core.lifecycle.defaultFormat, core.lifecycle.isDarkMode, core.darkColorHandler);
5181
5200
  }
5182
5201
  // If this is triggered by a keyboard event, let's select the new position
5183
5202
  if (keyboardEvent) {
@@ -5273,7 +5292,7 @@ var getContent = function (core, mode) {
5273
5292
  else if (mode == 3 /* PlainText */) {
5274
5293
  content = (0, roosterjs_editor_dom_1.getTextContent)(root);
5275
5294
  }
5276
- else if (triggerExtractContentEvent || core.lifecycle.isDarkMode) {
5295
+ else if (triggerExtractContentEvent || core.lifecycle.isDarkMode || core.darkColorHandler) {
5277
5296
  var clonedRoot = cloneNode(root);
5278
5297
  clonedRoot.normalize();
5279
5298
  var originalRange = core.api.getSelectionRange(core, true /*tryGetFromCache*/);
@@ -5285,8 +5304,8 @@ var getContent = function (core, mode) {
5285
5304
  ? (0, roosterjs_editor_dom_1.getSelectionPath)(core.contentDiv, originalRange)
5286
5305
  : null;
5287
5306
  var range = path && (0, roosterjs_editor_dom_1.createRange)(clonedRoot, path.start, path.end);
5288
- if (core.lifecycle.isDarkMode) {
5289
- core.api.transformColor(core, clonedRoot, false /*includeSelf*/, null /*callback*/, 1 /* DarkToLight */);
5307
+ if (core.lifecycle.isDarkMode || core.darkColorHandler) {
5308
+ core.api.transformColor(core, clonedRoot, false /*includeSelf*/, null /*callback*/, 1 /* DarkToLight */, !!core.darkColorHandler);
5290
5309
  }
5291
5310
  if (triggerExtractContentEvent) {
5292
5311
  core.api.triggerEvent(core, {
@@ -5600,38 +5619,78 @@ var getStyleBasedFormatState = function (core, node) {
5600
5619
  ];
5601
5620
  }
5602
5621
  var styles = node ? (0, roosterjs_editor_dom_1.getComputedStyles)(node) : [];
5603
- var isDarkMode = core.lifecycle.isDarkMode;
5604
- var root = core.contentDiv;
5605
- var ogTextColorNode = isDarkMode &&
5606
- (override[2]
5607
- ? pendableFormatSpan
5608
- : (0, roosterjs_editor_dom_1.findClosestElementAncestor)(node, root, ORIGINAL_STYLE_COLOR_SELECTOR));
5609
- var ogBackgroundColorNode = isDarkMode &&
5610
- (override[3]
5611
- ? pendableFormatSpan
5612
- : (0, roosterjs_editor_dom_1.findClosestElementAncestor)(node, root, ORIGINAL_STYLE_BACK_COLOR_SELECTOR));
5613
- return {
5614
- fontName: override[0] || styles[0],
5615
- fontSize: override[1] || styles[1],
5616
- textColor: override[2] || styles[2],
5617
- backgroundColor: override[3] || styles[3],
5618
- textColors: ogTextColorNode
5619
- ? {
5620
- darkModeColor: override[2] || styles[2],
5621
- lightModeColor: ogTextColorNode.dataset["ogsc" /* OriginalStyleColor */] ||
5622
- ogTextColorNode.dataset["ogac" /* OriginalAttributeColor */] ||
5623
- styles[2],
5622
+ var contentDiv = core.contentDiv, darkColorHandler = core.darkColorHandler, isDarkMode = core.lifecycle.isDarkMode;
5623
+ if (darkColorHandler) {
5624
+ var styleTextColor = void 0;
5625
+ var styleBackColor = void 0;
5626
+ while (node &&
5627
+ (0, roosterjs_editor_dom_1.contains)(contentDiv, node, true /*treatSameNodeAsContain*/) &&
5628
+ !(styleTextColor && styleBackColor)) {
5629
+ if (node.nodeType == 1 /* Element */) {
5630
+ var element = node;
5631
+ styleTextColor = styleTextColor || element.style.getPropertyValue('color');
5632
+ styleBackColor =
5633
+ styleBackColor || element.style.getPropertyValue('background-color');
5624
5634
  }
5625
- : undefined,
5626
- backgroundColors: ogBackgroundColorNode
5627
- ? {
5628
- darkModeColor: override[3] || styles[3],
5629
- lightModeColor: ogBackgroundColorNode.dataset["ogsb" /* OriginalStyleBackgroundColor */] ||
5630
- ogBackgroundColorNode.dataset["ogab" /* OriginalAttributeBackgroundColor */] ||
5631
- styles[3],
5632
- }
5633
- : undefined,
5634
- };
5635
+ node = node.parentNode;
5636
+ }
5637
+ if (!core.lifecycle.isDarkMode && node == core.contentDiv) {
5638
+ styleTextColor = styleTextColor || styles[2];
5639
+ styleBackColor = styleBackColor || styles[3];
5640
+ }
5641
+ var textColor = darkColorHandler.parseColorValue(override[2] || styleTextColor);
5642
+ var backColor = darkColorHandler.parseColorValue(override[3] || styleBackColor);
5643
+ return {
5644
+ fontName: override[0] || styles[0],
5645
+ fontSize: override[1] || styles[1],
5646
+ textColor: textColor.lightModeColor,
5647
+ backgroundColor: backColor.lightModeColor,
5648
+ textColors: textColor.darkModeColor
5649
+ ? {
5650
+ lightModeColor: textColor.lightModeColor,
5651
+ darkModeColor: textColor.darkModeColor,
5652
+ }
5653
+ : undefined,
5654
+ backgroundColors: backColor.darkModeColor
5655
+ ? {
5656
+ lightModeColor: backColor.lightModeColor,
5657
+ darkModeColor: backColor.darkModeColor,
5658
+ }
5659
+ : undefined,
5660
+ };
5661
+ }
5662
+ else {
5663
+ var ogTextColorNode = isDarkMode &&
5664
+ (override[2]
5665
+ ? pendableFormatSpan
5666
+ : (0, roosterjs_editor_dom_1.findClosestElementAncestor)(node, contentDiv, ORIGINAL_STYLE_COLOR_SELECTOR));
5667
+ var ogBackgroundColorNode = isDarkMode &&
5668
+ (override[3]
5669
+ ? pendableFormatSpan
5670
+ : (0, roosterjs_editor_dom_1.findClosestElementAncestor)(node, contentDiv, ORIGINAL_STYLE_BACK_COLOR_SELECTOR));
5671
+ return {
5672
+ fontName: override[0] || styles[0],
5673
+ fontSize: override[1] || styles[1],
5674
+ textColor: override[2] || styles[2],
5675
+ backgroundColor: override[3] || styles[3],
5676
+ textColors: ogTextColorNode
5677
+ ? {
5678
+ darkModeColor: override[2] || styles[2],
5679
+ lightModeColor: ogTextColorNode.dataset["ogsc" /* OriginalStyleColor */] ||
5680
+ ogTextColorNode.dataset["ogac" /* OriginalAttributeColor */] ||
5681
+ styles[2],
5682
+ }
5683
+ : undefined,
5684
+ backgroundColors: ogBackgroundColorNode
5685
+ ? {
5686
+ darkModeColor: override[3] || styles[3],
5687
+ lightModeColor: ogBackgroundColorNode.dataset["ogsb" /* OriginalStyleBackgroundColor */] ||
5688
+ ogBackgroundColorNode.dataset["ogab" /* OriginalAttributeBackgroundColor */] ||
5689
+ styles[3],
5690
+ }
5691
+ : undefined,
5692
+ };
5693
+ }
5635
5694
  };
5636
5695
  exports.getStyleBasedFormatState = getStyleBasedFormatState;
5637
5696
 
@@ -6373,21 +6432,38 @@ var ColorAttributeName = [
6373
6432
  * Pass true to this value to force do color transformation even editor core is in light mode
6374
6433
  */
6375
6434
  var transformColor = function (core, rootNode, includeSelf, callback, direction, forceTransform) {
6435
+ var darkColorHandler = core.darkColorHandler;
6376
6436
  var elements = rootNode && (forceTransform || core.lifecycle.isDarkMode)
6377
6437
  ? getAll(rootNode, includeSelf)
6378
6438
  : [];
6379
6439
  callback === null || callback === void 0 ? void 0 : callback();
6380
- if (direction == 1 /* DarkToLight */) {
6381
- transformToLightMode(elements);
6382
- }
6383
- else if (core.lifecycle.onExternalContentTransform) {
6384
- elements.forEach(function (element) { return core.lifecycle.onExternalContentTransform(element); });
6440
+ if (darkColorHandler) {
6441
+ transformV2(elements, darkColorHandler, direction == 0 /* LightToDark */);
6385
6442
  }
6386
6443
  else {
6387
- transformToDarkMode(elements, core.lifecycle.getDarkColor);
6444
+ if (direction == 1 /* DarkToLight */) {
6445
+ transformToLightMode(elements);
6446
+ }
6447
+ else if (core.lifecycle.onExternalContentTransform) {
6448
+ elements.forEach(function (element) { return core.lifecycle.onExternalContentTransform(element); });
6449
+ }
6450
+ else {
6451
+ transformToDarkMode(elements, core.lifecycle.getDarkColor);
6452
+ }
6388
6453
  }
6389
6454
  };
6390
6455
  exports.transformColor = transformColor;
6456
+ function transformV2(elements, darkColorHandler, toDark) {
6457
+ elements.forEach(function (element) {
6458
+ ColorAttributeName.forEach(function (names, i) {
6459
+ var color = darkColorHandler.parseColorValue(element.style.getPropertyValue(names[0 /* CssColor */]) ||
6460
+ element.getAttribute(names[1 /* HtmlColor */])).lightModeColor;
6461
+ if (color && color != 'inherit') {
6462
+ (0, roosterjs_editor_dom_1.setColor)(element, color, i != 0, toDark, false /*shouldAdaptFontColor*/, darkColorHandler);
6463
+ }
6464
+ });
6465
+ });
6466
+ }
6391
6467
  function transformToLightMode(elements) {
6392
6468
  elements.forEach(function (element) {
6393
6469
  ColorAttributeName.forEach(function (names) {
@@ -7557,6 +7633,15 @@ var ImageSelection = /** @class */ (function () {
7557
7633
  }
7558
7634
  }
7559
7635
  break;
7636
+ case 5 /* MouseDown */:
7637
+ var mouseTarget = event.rawEvent.target;
7638
+ var mouseSelection = this.editor.getSelectionRangeEx();
7639
+ if (mouseSelection &&
7640
+ mouseSelection.type === 2 /* ImageSelection */ &&
7641
+ mouseSelection.image !== mouseTarget) {
7642
+ this.editor.select(null);
7643
+ }
7644
+ break;
7560
7645
  case 2 /* KeyUp */:
7561
7646
  var key = event.rawEvent.key;
7562
7647
  var keyDownSelection = this.editor.getSelectionRangeEx();
@@ -7656,10 +7741,12 @@ var LifecyclePlugin = /** @class */ (function () {
7656
7741
  this.adjustColor = options.doNotAdjustEditorColor
7657
7742
  ? function () { }
7658
7743
  : function () {
7744
+ var _a;
7659
7745
  var textColors = DARK_MODE_DEFAULT_FORMAT.textColors, backgroundColors = DARK_MODE_DEFAULT_FORMAT.backgroundColors;
7660
7746
  var isDarkMode = _this.state.isDarkMode;
7661
- (0, roosterjs_editor_dom_1.setColor)(contentDiv, textColors, false /*isBackground*/, isDarkMode);
7662
- (0, roosterjs_editor_dom_1.setColor)(contentDiv, backgroundColors, true /*isBackground*/, isDarkMode);
7747
+ var darkColorHandler = (_a = _this.editor) === null || _a === void 0 ? void 0 : _a.getDarkColorHandler();
7748
+ (0, roosterjs_editor_dom_1.setColor)(contentDiv, textColors, false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
7749
+ (0, roosterjs_editor_dom_1.setColor)(contentDiv, backgroundColors, true /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
7663
7750
  };
7664
7751
  this.state = {
7665
7752
  customData: {},
@@ -8139,7 +8226,10 @@ var PendingFormatStatePlugin = /** @class */ (function () {
8139
8226
  event.rawEvent.which <= 40 /* DOWN */) ||
8140
8227
  (this.state.pendableFormatPosition &&
8141
8228
  (currentPosition = this.getCurrentPosition()) &&
8142
- !this.state.pendableFormatPosition.equalTo(currentPosition))) {
8229
+ !this.state.pendableFormatPosition.equalTo(currentPosition)) ||
8230
+ (event.eventType == 7 /* ContentChanged */ &&
8231
+ (event.source == "SwitchToDarkMode" /* SwitchToDarkMode */ ||
8232
+ event.source == "SwitchToLightMode" /* SwitchToLightMode */))) {
8143
8233
  // If content or position is changed (by keyboard, mouse, or code),
8144
8234
  // check if current position is still the same with the cached one (if exist),
8145
8235
  // and clear cached format if position is changed since it is out-of-date now
@@ -8170,11 +8260,12 @@ var PendingFormatStatePlugin = /** @class */ (function () {
8170
8260
  span.appendChild(doc.createTextNode(ZERO_WIDTH_SPACE));
8171
8261
  span.style.setProperty('font-family', (_a = currentStyle.fontName) !== null && _a !== void 0 ? _a : null);
8172
8262
  span.style.setProperty('font-size', (_b = currentStyle.fontSize) !== null && _b !== void 0 ? _b : null);
8263
+ var darkColorHandler = this.editor.getDarkColorHandler();
8173
8264
  if (currentStyle.textColors || currentStyle.textColor) {
8174
- (0, roosterjs_editor_dom_1.setColor)(span, (currentStyle.textColors || currentStyle.textColor), false /*isBackground*/, isDarkMode);
8265
+ (0, roosterjs_editor_dom_1.setColor)(span, (currentStyle.textColors || currentStyle.textColor), false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
8175
8266
  }
8176
8267
  if (currentStyle.backgroundColors || currentStyle.backgroundColor) {
8177
- (0, roosterjs_editor_dom_1.setColor)(span, (currentStyle.backgroundColors || currentStyle.backgroundColor), true /*isBackground*/, isDarkMode);
8268
+ (0, roosterjs_editor_dom_1.setColor)(span, (currentStyle.backgroundColors || currentStyle.backgroundColor), true /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
8178
8269
  }
8179
8270
  }
8180
8271
  if (span) {
@@ -8675,6 +8766,98 @@ var removeCellsOutsideSelection = function (vTable) {
8675
8766
  exports.removeCellsOutsideSelection = removeCellsOutsideSelection;
8676
8767
 
8677
8768
 
8769
+ /***/ }),
8770
+
8771
+ /***/ "./packages/roosterjs-editor-core/lib/editor/DarkColorHandlerImpl.ts":
8772
+ /*!***************************************************************************!*\
8773
+ !*** ./packages/roosterjs-editor-core/lib/editor/DarkColorHandlerImpl.ts ***!
8774
+ \***************************************************************************/
8775
+ /*! no static exports found */
8776
+ /***/ (function(module, exports, __webpack_require__) {
8777
+
8778
+ "use strict";
8779
+
8780
+ Object.defineProperty(exports, "__esModule", { value: true });
8781
+ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
8782
+ var VARIABLE_REGEX = /^\s*var\(\s*(\-\-[a-zA-Z0-9\-_]+)\s*(?:,\s*(.*))?\)\s*$/;
8783
+ var VARIABLE_PREFIX = 'var(';
8784
+ var COLOR_VAR_PREFIX = 'darkColor';
8785
+ /**
8786
+ * @internal
8787
+ */
8788
+ var DarkColorHandlerImpl = /** @class */ (function () {
8789
+ function DarkColorHandlerImpl(contentDiv, getDarkColor) {
8790
+ this.contentDiv = contentDiv;
8791
+ this.getDarkColor = getDarkColor;
8792
+ this.knownColors = {};
8793
+ }
8794
+ /**
8795
+ * Given a light mode color value and an optional dark mode color value, register this color
8796
+ * so that editor can handle it, then return the CSS color value for current color mode.
8797
+ * @param lightModeColor Light mode color value
8798
+ * @param isDarkMode Whether current color mode is dark mode
8799
+ * @param darkModeColor Optional dark mode color value. If not passed, we will calculate one.
8800
+ */
8801
+ DarkColorHandlerImpl.prototype.registerColor = function (lightModeColor, isDarkMode, darkModeColor) {
8802
+ var parsedColor = this.parseColorValue(lightModeColor);
8803
+ var colorKey;
8804
+ if (parsedColor) {
8805
+ lightModeColor = parsedColor.lightModeColor;
8806
+ darkModeColor = parsedColor.darkModeColor || darkModeColor;
8807
+ colorKey = parsedColor.key;
8808
+ }
8809
+ if (isDarkMode && lightModeColor) {
8810
+ colorKey =
8811
+ colorKey || "--" + COLOR_VAR_PREFIX + "_" + lightModeColor.replace(/[^\d\w]/g, '_');
8812
+ if (!this.knownColors[colorKey]) {
8813
+ darkModeColor = darkModeColor || this.getDarkColor(lightModeColor);
8814
+ this.knownColors[colorKey] = { lightModeColor: lightModeColor, darkModeColor: darkModeColor };
8815
+ this.contentDiv.style.setProperty(colorKey, darkModeColor);
8816
+ }
8817
+ return "var(" + colorKey + ", " + lightModeColor + ")";
8818
+ }
8819
+ else {
8820
+ return lightModeColor;
8821
+ }
8822
+ };
8823
+ /**
8824
+ * Reset known color record, clean up registered color variables.
8825
+ */
8826
+ DarkColorHandlerImpl.prototype.reset = function () {
8827
+ var _this = this;
8828
+ (0, roosterjs_editor_dom_1.getObjectKeys)(this.knownColors).forEach(function (key) { return _this.contentDiv.style.removeProperty(key); });
8829
+ this.knownColors = {};
8830
+ };
8831
+ /**
8832
+ * Parse an existing color value, if it is in variable-based color format, extract color key,
8833
+ * light color and query related dark color if any
8834
+ * @param color The color string to parse
8835
+ */
8836
+ DarkColorHandlerImpl.prototype.parseColorValue = function (color) {
8837
+ var _a;
8838
+ var key;
8839
+ var lightModeColor = color || '';
8840
+ var darkModeColor;
8841
+ if (color) {
8842
+ var match = color.startsWith(VARIABLE_PREFIX) ? VARIABLE_REGEX.exec(color) : null;
8843
+ if (match) {
8844
+ if (match[2]) {
8845
+ key = match[1];
8846
+ lightModeColor = match[2];
8847
+ darkModeColor = (_a = this.knownColors[key]) === null || _a === void 0 ? void 0 : _a.darkModeColor;
8848
+ }
8849
+ else {
8850
+ lightModeColor = '';
8851
+ }
8852
+ }
8853
+ }
8854
+ return { key: key, lightModeColor: lightModeColor, darkModeColor: darkModeColor };
8855
+ };
8856
+ return DarkColorHandlerImpl;
8857
+ }());
8858
+ exports.default = DarkColorHandlerImpl;
8859
+
8860
+
8678
8861
  /***/ }),
8679
8862
 
8680
8863
  /***/ "./packages/roosterjs-editor-core/lib/editor/Editor.ts":
@@ -8699,6 +8882,7 @@ var __assign = (this && this.__assign) || function () {
8699
8882
  };
8700
8883
  Object.defineProperty(exports, "__esModule", { value: true });
8701
8884
  var createCorePlugins_1 = __webpack_require__(/*! ../corePlugins/createCorePlugins */ "./packages/roosterjs-editor-core/lib/corePlugins/createCorePlugins.ts");
8885
+ var DarkColorHandlerImpl_1 = __webpack_require__(/*! ./DarkColorHandlerImpl */ "./packages/roosterjs-editor-core/lib/editor/DarkColorHandlerImpl.ts");
8702
8886
  var coreApiMap_1 = __webpack_require__(/*! ../coreApi/coreApiMap */ "./packages/roosterjs-editor-core/lib/coreApi/coreApiMap.ts");
8703
8887
  var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
8704
8888
  /**
@@ -8741,6 +8925,9 @@ var Editor = /** @class */ (function () {
8741
8925
  ? [scrollContainer]
8742
8926
  : [scrollContainer, contentDiv]);
8743
8927
  }), imageSelectionBorderColor: options.imageSelectionBorderColor });
8928
+ if (this.isFeatureEnabled("VariableBasedDarkColor" /* VariableBasedDarkColor */)) {
8929
+ this.core.darkColorHandler = new DarkColorHandlerImpl_1.default(contentDiv, this.core.lifecycle.getDarkColor);
8930
+ }
8744
8931
  // 3. Initialize plugins
8745
8932
  this.core.plugins.forEach(function (plugin) { return plugin.initialize(_this); });
8746
8933
  // 4. Ensure user will type in a container node, not the editor content DIV
@@ -8750,10 +8937,12 @@ var Editor = /** @class */ (function () {
8750
8937
  * Dispose this editor, dispose all plugins and custom data
8751
8938
  */
8752
8939
  Editor.prototype.dispose = function () {
8940
+ var _a;
8753
8941
  var core = this.getCore();
8754
8942
  for (var i = core.plugins.length - 1; i >= 0; i--) {
8755
8943
  core.plugins[i].dispose();
8756
8944
  }
8945
+ (_a = core.darkColorHandler) === null || _a === void 0 ? void 0 : _a.reset();
8757
8946
  this.core = null;
8758
8947
  };
8759
8948
  /**
@@ -9464,6 +9653,12 @@ var Editor = /** @class */ (function () {
9464
9653
  var core = this.getCore();
9465
9654
  core.api.transformColor(core, node, true /*includeSelf*/, null /*callback*/, 0 /* LightToDark */);
9466
9655
  };
9656
+ /**
9657
+ * Get a darkColorHandler object for this editor. It will return null if experimental feature "VariableBasedDarkColor" is not enabled
9658
+ */
9659
+ Editor.prototype.getDarkColorHandler = function () {
9660
+ return this.getCore().darkColorHandler || null;
9661
+ };
9467
9662
  /**
9468
9663
  * Make the editor in "Shadow Edit" mode.
9469
9664
  * In Shadow Edit mode, all format change will finally be ignored.
@@ -18109,8 +18304,10 @@ var setColor_1 = __webpack_require__(/*! ./setColor */ "./packages/roosterjs-edi
18109
18304
  * Apply format to an HTML element
18110
18305
  * @param element The HTML element to apply format to
18111
18306
  * @param format The format to apply
18307
+ * @param isDarkMode Whether the content should be formatted in dark mode
18308
+ * @param darkColorHandler An optional dark color handler object. When it is passed, we will use this handler to do variable-based dark color instead of original dataset base dark color
18112
18309
  */
18113
- function applyFormat(element, format, isDarkMode) {
18310
+ function applyFormat(element, format, isDarkMode, darkColorHandler) {
18114
18311
  if (format) {
18115
18312
  var elementStyle = element.style;
18116
18313
  var fontFamily = format.fontFamily, fontSize = format.fontSize, textColor = format.textColor, textColors = format.textColors, backgroundColor = format.backgroundColor, backgroundColors = format.backgroundColors, bold = format.bold, italic = format.italic, underline = format.underline;
@@ -18121,16 +18318,16 @@ function applyFormat(element, format, isDarkMode) {
18121
18318
  elementStyle.fontSize = fontSize;
18122
18319
  }
18123
18320
  if (textColors) {
18124
- (0, setColor_1.default)(element, textColors, false /*isBackground*/, isDarkMode);
18321
+ (0, setColor_1.default)(element, textColors, false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
18125
18322
  }
18126
18323
  else if (textColor) {
18127
- (0, setColor_1.default)(element, textColor, false /*isBackground*/, isDarkMode);
18324
+ (0, setColor_1.default)(element, textColor, false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
18128
18325
  }
18129
18326
  if (backgroundColors) {
18130
- (0, setColor_1.default)(element, backgroundColors, true /*isBackground*/, isDarkMode);
18327
+ (0, setColor_1.default)(element, backgroundColors, true /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
18131
18328
  }
18132
18329
  else if (backgroundColor) {
18133
- (0, setColor_1.default)(element, backgroundColor, true /*isBackground*/, isDarkMode);
18330
+ (0, setColor_1.default)(element, backgroundColor, true /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
18134
18331
  }
18135
18332
  if (bold) {
18136
18333
  elementStyle.fontWeight = 'bold';
@@ -18367,7 +18564,7 @@ exports.KnownCreateElementData = (_a = {},
18367
18564
  },
18368
18565
  _a[6 /* ImageEditWrapper */] = {
18369
18566
  tag: 'span',
18370
- style: 'max-width:100%;position:fixed',
18567
+ style: 'max-width:100%;vertical-align:bottom',
18371
18568
  children: [
18372
18569
  {
18373
18570
  tag: 'div',
@@ -19384,28 +19581,35 @@ var TRANSPARENT_COLOR = 'transparent';
19384
19581
  * @param isBackgroundColor Whether set background color or text color
19385
19582
  * @param isDarkMode Whether current mode is dark mode. @default false
19386
19583
  * @param shouldAdaptTheFontColor Whether the font color needs to be adapted to be visible in a dark or bright background color. @default false
19387
- * @param defaultFontColor Set the default colors that needs to be set to the to be visible.
19584
+ * @param darkColorHandler An optional dark color handler object. When it is passed, we will use this handler to do variable-based dark color instead of original dataset base dark color
19388
19585
  */
19389
- function setColor(element, color, isBackgroundColor, isDarkMode, shouldAdaptTheFontColor) {
19586
+ function setColor(element, color, isBackgroundColor, isDarkMode, shouldAdaptTheFontColor, darkColorHandler) {
19390
19587
  var colorString = typeof color === 'string' ? color.trim() : '';
19391
19588
  var modeIndependentColor = typeof color === 'string' ? null : color;
19589
+ var cssName = isBackgroundColor ? 'background-color' : 'color';
19392
19590
  if (colorString || modeIndependentColor) {
19393
- element.style.setProperty(isBackgroundColor ? 'background-color' : 'color', (isDarkMode
19394
- ? modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.darkModeColor
19395
- : modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.lightModeColor) || colorString);
19396
- if (element.dataset) {
19397
- var dataSetName = isBackgroundColor
19398
- ? "ogsb" /* OriginalStyleBackgroundColor */
19399
- : "ogsc" /* OriginalStyleColor */;
19400
- if (!isDarkMode || color == TRANSPARENT_COLOR) {
19401
- delete element.dataset[dataSetName];
19402
- }
19403
- else if (modeIndependentColor) {
19404
- element.dataset[dataSetName] = modeIndependentColor.lightModeColor;
19591
+ if (darkColorHandler) {
19592
+ var colorValue = darkColorHandler.registerColor((modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.lightModeColor) || colorString, !!isDarkMode, modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.darkModeColor);
19593
+ element.style.setProperty(cssName, colorValue);
19594
+ }
19595
+ else {
19596
+ element.style.setProperty(cssName, (isDarkMode
19597
+ ? modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.darkModeColor
19598
+ : modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.lightModeColor) || colorString);
19599
+ if (element.dataset) {
19600
+ var dataSetName = isBackgroundColor
19601
+ ? "ogsb" /* OriginalStyleBackgroundColor */
19602
+ : "ogsc" /* OriginalStyleColor */;
19603
+ if (!isDarkMode || color == TRANSPARENT_COLOR) {
19604
+ delete element.dataset[dataSetName];
19605
+ }
19606
+ else if (modeIndependentColor) {
19607
+ element.dataset[dataSetName] = modeIndependentColor.lightModeColor;
19608
+ }
19405
19609
  }
19406
19610
  }
19407
19611
  if (isBackgroundColor && shouldAdaptTheFontColor) {
19408
- adaptFontColorToBackgroundColor(element, isDarkMode);
19612
+ adaptFontColorToBackgroundColor(element, (modeIndependentColor === null || modeIndependentColor === void 0 ? void 0 : modeIndependentColor.lightModeColor) || colorString, isDarkMode, darkColorHandler);
19409
19613
  }
19410
19614
  }
19411
19615
  }
@@ -19413,17 +19617,11 @@ exports.default = setColor;
19413
19617
  /**
19414
19618
  * Change the font color to white or some other color, so the text can be visible with a darker background
19415
19619
  * @param element The element that contains text.
19620
+ * @param lightModeBackgroundColor Existing background color in light mode
19621
+ * @param isDarkMode Whether the content is in dark mode
19622
+ * @param darkColorHandler An optional dark color handler object. When it is passed, we will use this handler to do variable-based dark color instead of original dataset base dark color
19416
19623
  */
19417
- function adaptFontColorToBackgroundColor(element, isDarkMode) {
19418
- var _a;
19419
- if ((_a = element.firstElementChild) === null || _a === void 0 ? void 0 : _a.hasAttribute('style')) {
19420
- return;
19421
- }
19422
- var backgroundColor = element.style.getPropertyValue('background-color');
19423
- var lightModeBackgroundColor = (isDarkMode &&
19424
- (element.dataset["ogsb" /* OriginalStyleBackgroundColor */] ||
19425
- element.dataset["ogab" /* OriginalAttributeBackgroundColor */])) ||
19426
- backgroundColor;
19624
+ function adaptFontColorToBackgroundColor(element, lightModeBackgroundColor, isDarkMode, darkColorHandler) {
19427
19625
  if (!lightModeBackgroundColor || lightModeBackgroundColor === TRANSPARENT) {
19428
19626
  return;
19429
19627
  }
@@ -19434,14 +19632,14 @@ function adaptFontColorToBackgroundColor(element, isDarkMode) {
19434
19632
  lightModeColor: WHITE,
19435
19633
  darkModeColor: GRAY,
19436
19634
  };
19437
- setColor(element, fontForDark, false /*isBackground*/, isDarkMode);
19635
+ setColor(element, fontForDark, false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
19438
19636
  break;
19439
19637
  case 0 /* BRIGHT */:
19440
19638
  var fontForLight = {
19441
19639
  lightModeColor: BLACK,
19442
19640
  darkModeColor: WHITE,
19443
19641
  };
19444
- setColor(element, fontForLight, false /*isBackground*/, isDarkMode);
19642
+ setColor(element, fontForLight, false /*isBackground*/, isDarkMode, false /*shouldAdaptFontColor*/, darkColorHandler);
19445
19643
  break;
19446
19644
  }
19447
19645
  }
@@ -22848,7 +23046,6 @@ var applyChange_1 = __webpack_require__(/*! ./editInfoUtils/applyChange */ "./pa
22848
23046
  var canRegenerateImage_1 = __webpack_require__(/*! ./api/canRegenerateImage */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/api/canRegenerateImage.ts");
22849
23047
  var DragAndDropHelper_1 = __webpack_require__(/*! ../../pluginUtils/DragAndDropHelper */ "./packages/roosterjs-editor-plugins/lib/pluginUtils/DragAndDropHelper.ts");
22850
23048
  var getGeneratedImageSize_1 = __webpack_require__(/*! ./editInfoUtils/getGeneratedImageSize */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/getGeneratedImageSize.ts");
22851
- var getLastZIndex_1 = __webpack_require__(/*! ./editInfoUtils/getLastZIndex */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/getLastZIndex.ts");
22852
23049
  var Cropper_1 = __webpack_require__(/*! ./imageEditors/Cropper */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/imageEditors/Cropper.ts");
22853
23050
  var editInfo_1 = __webpack_require__(/*! ./editInfoUtils/editInfo */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/editInfo.ts");
22854
23051
  var Rotator_1 = __webpack_require__(/*! ./imageEditors/Rotator */ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/imageEditors/Rotator.ts");
@@ -22917,14 +23114,11 @@ var ImageEdit = /** @class */ (function () {
22917
23114
  * Remove the temp wrapper of the image
22918
23115
  */
22919
23116
  this.removeWrapper = function () {
22920
- var _a, _b;
22921
- var doc = _this.editor.getDocument();
22922
- if (_this.zoomWrapper && ((_a = doc.body) === null || _a === void 0 ? void 0 : _a.contains(_this.zoomWrapper))) {
22923
- (_b = doc.body) === null || _b === void 0 ? void 0 : _b.removeChild(_this.zoomWrapper);
22924
- _this.toggleImageVisibility(_this.image, true /** showImage */);
23117
+ if (_this.editor.contains(_this.image) && _this.wrapper) {
23118
+ (0, roosterjs_editor_dom_1.unwrap)(_this.image.parentNode);
22925
23119
  }
22926
23120
  _this.wrapper = null;
22927
- _this.zoomWrapper = null;
23121
+ _this.shadowSpan = null;
22928
23122
  };
22929
23123
  /**
22930
23124
  * Update image edit elements to reflect current editing result
@@ -22937,12 +23131,14 @@ var ImageEdit = /** @class */ (function () {
22937
23131
  var cropContainers = getEditElements(wrapper, "r_cropC" /* CropContainer */);
22938
23132
  var cropOverlays = getEditElements(wrapper, "r_cropO" /* CropOverlay */);
22939
23133
  var resizeHandles = getEditElements(wrapper, "r_resizeH" /* ResizeHandle */);
23134
+ var rotateCenter = getEditElements(wrapper, "r_rotateC" /* RotateCenter */)[0];
23135
+ var rotateHandle = getEditElements(wrapper, "r_rotateH" /* RotateHandle */)[0];
22940
23136
  var cropHandles = getEditElements(wrapper, "r_cropH" /* CropHandle */);
22941
23137
  // Cropping and resizing will show different UI, so check if it is cropping here first
22942
- var isCropping = cropContainers.length == 1 && cropOverlays.length == 4;
23138
+ _this.isCropping = cropContainers.length == 1 && cropOverlays.length == 4;
22943
23139
  var _a = _this.editInfo, angleRad = _a.angleRad, bottomPercent = _a.bottomPercent, leftPercent = _a.leftPercent, rightPercent = _a.rightPercent, topPercent = _a.topPercent;
22944
23140
  // Width/height of the image
22945
- var _b = (0, getGeneratedImageSize_1.default)(_this.editInfo, isCropping), targetWidth = _b.targetWidth, targetHeight = _b.targetHeight, originalWidth = _b.originalWidth, originalHeight = _b.originalHeight, visibleWidth = _b.visibleWidth, visibleHeight = _b.visibleHeight;
23141
+ var _b = (0, getGeneratedImageSize_1.default)(_this.editInfo, _this.isCropping), targetWidth = _b.targetWidth, targetHeight = _b.targetHeight, originalWidth = _b.originalWidth, originalHeight = _b.originalHeight, visibleWidth = _b.visibleWidth, visibleHeight = _b.visibleHeight;
22946
23142
  var marginHorizontal = (targetWidth - visibleWidth) / 2;
22947
23143
  var marginVertical = (targetHeight - visibleHeight) / 2;
22948
23144
  var cropLeftPx = originalWidth * leftPercent;
@@ -22954,16 +23150,15 @@ var ImageEdit = /** @class */ (function () {
22954
23150
  wrapper.style.height = getPx(visibleHeight);
22955
23151
  wrapper.style.margin = marginVertical + "px " + marginHorizontal + "px";
22956
23152
  wrapper.style.transform = "rotate(" + angleRad + "rad)";
22957
- _this.zoomWrapper.style.width = getPx(visibleWidth);
22958
- _this.zoomWrapper.style.height = getPx(visibleHeight);
22959
- fitImageContainer(_this.editor, _this.zoomWrapper, angleRad);
23153
+ _this.wrapper.style.width = getPx(visibleWidth);
23154
+ _this.wrapper.style.height = getPx(visibleHeight);
22960
23155
  // Update the text-alignment to avoid the image to overflow if the parent element have align center or right
22961
23156
  // or if the direction is Right To Left
22962
23157
  wrapper.style.textAlign = isRtl(wrapper.parentNode) ? 'right' : 'left';
22963
23158
  // Update size of the image
22964
23159
  _this.clonedImage.style.width = getPx(originalWidth);
22965
23160
  _this.clonedImage.style.height = getPx(originalHeight);
22966
- if (isCropping) {
23161
+ if (_this.isCropping) {
22967
23162
  // For crop, we also need to set position of the overlays
22968
23163
  setSize(cropContainers[0], cropLeftPx, cropTopPx, cropRightPx, cropBottomPx, undefined, undefined);
22969
23164
  setSize(cropOverlays[0], 0, 0, cropRightPx, undefined, undefined, cropTopPx);
@@ -22983,6 +23178,7 @@ var ImageEdit = /** @class */ (function () {
22983
23178
  (0, Resizer_1.doubleCheckResize)(_this.editInfo, _this.options.preserveRatio, clientWidth, clientHeight);
22984
23179
  _this.updateWrapper();
22985
23180
  }
23181
+ (0, Rotator_1.updateRotateHandlePosition)(_this.editInfo, _this.editor.getVisibleViewport(), marginVertical, rotateCenter, rotateHandle);
22986
23182
  updateHandleCursor(resizeHandles, angleRad);
22987
23183
  }
22988
23184
  }
@@ -23005,8 +23201,16 @@ var ImageEdit = /** @class */ (function () {
23005
23201
  * @param editor Editor instance
23006
23202
  */
23007
23203
  ImageEdit.prototype.initialize = function (editor) {
23204
+ var _this = this;
23008
23205
  this.editor = editor;
23009
- this.disposer = editor.addDomEventHandler('blur', this.onBlur);
23206
+ this.disposer = editor.addDomEventHandler({
23207
+ blur: function () { return _this.onBlur; },
23208
+ dragstart: function (e) {
23209
+ if (_this.image) {
23210
+ e.preventDefault();
23211
+ }
23212
+ },
23213
+ });
23010
23214
  };
23011
23215
  /**
23012
23216
  * Dispose this plugin
@@ -23030,16 +23234,21 @@ var ImageEdit = /** @class */ (function () {
23030
23234
  }
23031
23235
  break;
23032
23236
  case 5 /* MouseDown */:
23033
- this.setEditingImage(null);
23237
+ // When left click in a image that already in editing mode, do not quit edit mode
23238
+ var mouseTarget = e.rawEvent.target;
23239
+ var button = e.rawEvent.button;
23240
+ if (this.shadowSpan !== mouseTarget ||
23241
+ (this.shadowSpan === mouseTarget && button !== 0) ||
23242
+ this.isCropping) {
23243
+ this.setEditingImage(null);
23244
+ }
23034
23245
  break;
23035
23246
  case 0 /* KeyDown */:
23036
23247
  this.setEditingImage(null);
23037
23248
  break;
23038
23249
  case 7 /* ContentChanged */:
23039
- if (e.source !== "Format" /* Format */) {
23040
- // After contentChanged event, the current image wrapper may not be valid any more, remove all of them if any
23041
- this.removeWrapper();
23042
- }
23250
+ //After contentChanged event, the current image wrapper may not be valid any more, remove all of them if any
23251
+ this.removeWrapper();
23043
23252
  break;
23044
23253
  case 8 /* ExtractContentWithDom */:
23045
23254
  // When extract content, remove all image info since they may not be valid when load the content again
@@ -23047,8 +23256,8 @@ var ImageEdit = /** @class */ (function () {
23047
23256
  (0, editInfo_1.deleteEditInfo)(img);
23048
23257
  });
23049
23258
  break;
23050
- case 14 /* Scroll */:
23051
- this.setEditingImage(null);
23259
+ case 12 /* BeforeDispose */:
23260
+ this.removeWrapper();
23052
23261
  break;
23053
23262
  }
23054
23263
  };
@@ -23079,6 +23288,7 @@ var ImageEdit = /** @class */ (function () {
23079
23288
  this.editInfo = null;
23080
23289
  this.lastSrc = null;
23081
23290
  this.clonedImage = null;
23291
+ this.isCropping = false;
23082
23292
  }
23083
23293
  if (!this.image && (image === null || image === void 0 ? void 0 : image.isContentEditable)) {
23084
23294
  // If there is new image to edit, enter editing mode for this image
@@ -23097,7 +23307,6 @@ var ImageEdit = /** @class */ (function () {
23097
23307
  // Init drag and drop
23098
23308
  this.dndHelpers = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], this.createDndHelpers("r_resizeH" /* ResizeHandle */, Resizer_1.Resizer), true), this.createDndHelpers("r_rotateH" /* RotateHandle */, Rotator_1.Rotator), true), this.createDndHelpers("r_cropH" /* CropHandle */, Cropper_1.Cropper), true), this.createDndHelpers("r_cropC" /* CropContainer */, Cropper_1.Cropper), true);
23099
23309
  this.editor.select(this.image);
23100
- this.toggleImageVisibility(this.image, false /** showImage */);
23101
23310
  }
23102
23311
  };
23103
23312
  /**
@@ -23110,18 +23319,12 @@ var ImageEdit = /** @class */ (function () {
23110
23319
  this.clonedImage.removeAttribute('id');
23111
23320
  this.wrapper = (0, roosterjs_editor_dom_1.createElement)(6 /* ImageEditWrapper */, this.image.ownerDocument);
23112
23321
  this.wrapper.firstChild.appendChild(this.clonedImage);
23113
- // keep the same vertical align
23114
- var originalVerticalAlign = getStylePropertyValue(this.image, 'vertical-align');
23115
- if (originalVerticalAlign) {
23116
- this.wrapper.style.verticalAlign = originalVerticalAlign;
23117
- }
23118
23322
  this.wrapper.style.display = roosterjs_editor_dom_1.Browser.isSafari ? 'inline-block' : 'inline-flex';
23119
23323
  // Cache current src so that we can compare it after edit see if src is changed
23120
23324
  this.lastSrc = this.image.getAttribute('src');
23121
23325
  // Set image src to original src to help show editing UI, also it will be used when regenerate image dataURL after editing
23122
23326
  this.clonedImage.src = this.editInfo.src;
23123
23327
  this.clonedImage.style.position = 'absolute';
23124
- this.clonedImage.style.maxWidth = null;
23125
23328
  // Get HTML for all edit elements (resize handle, rotate handle, crop handle and overlay, ...) and create HTML element
23126
23329
  var options = {
23127
23330
  borderColor: getColorString(this.options.borderColor, this.editor.isDarkMode()),
@@ -23143,24 +23346,15 @@ var ImageEdit = /** @class */ (function () {
23143
23346
  _this.wrapper.appendChild(element);
23144
23347
  }
23145
23348
  });
23146
- this.insertImageWrapper(this.editor, this.image, this.wrapper, this.editor.getZoomScale());
23147
- };
23148
- ImageEdit.prototype.toggleImageVisibility = function (image, showImage) {
23149
- var editorId = this.editor.getEditorDomAttribute('id');
23150
- var doc = this.editor.getDocument();
23151
- var editingId = 'editingId' + editorId;
23152
- if (showImage) {
23153
- (0, roosterjs_editor_dom_1.removeGlobalCssStyle)(doc, editingId);
23154
- }
23155
- else {
23156
- var cssRule = "#" + editorId + " #" + image.id + " {visibility: hidden}";
23157
- (0, roosterjs_editor_dom_1.setGlobalCssStyles)(doc, cssRule, editingId);
23158
- }
23349
+ this.insertImageWrapper(this.wrapper);
23159
23350
  };
23160
- ImageEdit.prototype.insertImageWrapper = function (editor, image, wrapper, scale) {
23161
- this.zoomWrapper = copyElementRect(image, createZoomWrapper(editor, wrapper, scale));
23162
- this.zoomWrapper.style.zIndex = "" + ((0, getLastZIndex_1.default)(editor.getScrollContainer()) + 1);
23163
- this.editor.getDocument().body.appendChild(this.zoomWrapper);
23351
+ ImageEdit.prototype.insertImageWrapper = function (wrapper) {
23352
+ this.shadowSpan = (0, roosterjs_editor_dom_1.wrap)(this.image, 'span');
23353
+ var shadowRoot = this.shadowSpan.attachShadow({
23354
+ mode: 'open',
23355
+ });
23356
+ this.shadowSpan.style.verticalAlign = 'bottom';
23357
+ shadowRoot.appendChild(wrapper);
23164
23358
  };
23165
23359
  /**
23166
23360
  * Create drag and drop helpers
@@ -23266,40 +23460,6 @@ function getColorString(color, isDarkMode) {
23266
23460
  }
23267
23461
  return isDarkMode ? color.darkModeColor.trim() : color.lightModeColor.trim();
23268
23462
  }
23269
- function fitImageContainer(editor, zoomWrapper, angle) {
23270
- var _a, _b;
23271
- var angleIndex = handleRadIndexCalculator(angle);
23272
- var isVertical = (angleIndex >= 2 && angleIndex < 4) || angleIndex >= 6;
23273
- var editorTop = (_b = (_a = editor.getScrollContainer()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) === null || _b === void 0 ? void 0 : _b.top;
23274
- var _c = zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.getBoundingClientRect(), top = _c.top, width = _c.width, height = _c.height;
23275
- if (editorTop > top) {
23276
- var rotatePercent = 100 * Math.abs(angle);
23277
- var zoomWrapperHeight = editorTop - top;
23278
- var zoomWrapperHeightPercent = isVertical
23279
- ? rotatePercent * (zoomWrapperHeight / width)
23280
- : 100 * (zoomWrapperHeight / height);
23281
- zoomWrapper.style.clipPath = "polygon(0 " + zoomWrapperHeightPercent + "%, 100% " + zoomWrapperHeightPercent + "%, 100% " + (isVertical ? rotatePercent : '100') + "%, 0 " + (isVertical ? rotatePercent : '100') + "%)";
23282
- }
23283
- }
23284
- function copyElementRect(originalElement, element) {
23285
- var _a = originalElement.getBoundingClientRect(), top = _a.top, left = _a.left, right = _a.right, bottom = _a.bottom;
23286
- element.style.top = top + "px";
23287
- element.style.bottom = bottom + "px";
23288
- element.style.right = right + "px";
23289
- element.style.left = left + "px";
23290
- return element;
23291
- }
23292
- function createZoomWrapper(editor, wrapper, scale) {
23293
- var zoomWrapper = editor.getDocument().createElement('div');
23294
- zoomWrapper.style.transform = "scale(" + (scale || 1) + ")";
23295
- zoomWrapper.style.transformOrigin = 'top left';
23296
- zoomWrapper.style.position = 'fixed';
23297
- zoomWrapper.appendChild(wrapper);
23298
- return zoomWrapper;
23299
- }
23300
- function getStylePropertyValue(element, property) {
23301
- return element.ownerDocument.defaultView.getComputedStyle(element).getPropertyValue(property);
23302
- }
23303
23463
 
23304
23464
 
23305
23465
  /***/ }),
@@ -23526,7 +23686,6 @@ function applyChange(editor, image, editInfo, previousSrc, wasResized, editingIm
23526
23686
  var _a = (0, getGeneratedImageSize_1.default)(editInfo), targetWidth = _a.targetWidth, targetHeight = _a.targetHeight;
23527
23687
  image.src = newSrc;
23528
23688
  if (wasResized || state == 3 /* FullyChanged */) {
23529
- image.style.maxWidth = 'initial';
23530
23689
  image.width = targetWidth;
23531
23690
  image.height = targetHeight;
23532
23691
  image.style.width = targetWidth + 'px';
@@ -23758,40 +23917,6 @@ function getGeneratedImageSize(editInfo, beforeCrop) {
23758
23917
  exports.default = getGeneratedImageSize;
23759
23918
 
23760
23919
 
23761
- /***/ }),
23762
-
23763
- /***/ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/getLastZIndex.ts":
23764
- /*!************************************************************************************************!*\
23765
- !*** ./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/getLastZIndex.ts ***!
23766
- \************************************************************************************************/
23767
- /*! no static exports found */
23768
- /***/ (function(module, exports, __webpack_require__) {
23769
-
23770
- "use strict";
23771
-
23772
- Object.defineProperty(exports, "__esModule", { value: true });
23773
- var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
23774
- /**
23775
- * @internal
23776
- * Search through from editor div to it's root for the latest z-index value
23777
- * @param editorDiv the editor div element
23778
- * @returns the z index value
23779
- */
23780
- function getLatestZIndex(editorDiv) {
23781
- var child = editorDiv;
23782
- var zIndex = 0;
23783
- while (child && (0, roosterjs_editor_dom_1.getTagOfNode)(child) !== 'BODY') {
23784
- var childZIndex = child.style.zIndex || getComputedStyle(child).zIndex;
23785
- if (childZIndex) {
23786
- zIndex = parseInt(child.style.zIndex);
23787
- }
23788
- child = child.parentElement;
23789
- }
23790
- return zIndex;
23791
- }
23792
- exports.default = getLatestZIndex;
23793
-
23794
-
23795
23920
  /***/ }),
23796
23921
 
23797
23922
  /***/ "./packages/roosterjs-editor-plugins/lib/plugins/ImageEdit/editInfoUtils/getTargetSizeByPercentage.ts":
@@ -24189,7 +24314,7 @@ var __assign = (this && this.__assign) || function () {
24189
24314
  return __assign.apply(this, arguments);
24190
24315
  };
24191
24316
  Object.defineProperty(exports, "__esModule", { value: true });
24192
- exports.getRotateHTML = exports.Rotator = void 0;
24317
+ exports.getRotateHTML = exports.updateRotateHandlePosition = exports.Rotator = void 0;
24193
24318
  var ROTATE_SIZE = 32;
24194
24319
  var ROTATE_GAP = 15;
24195
24320
  var DEG_PER_RAD = 180 / Math.PI;
@@ -24224,6 +24349,26 @@ exports.Rotator = {
24224
24349
  }
24225
24350
  },
24226
24351
  };
24352
+ /**
24353
+ * @internal
24354
+ * Move rotate handle. When image is very close to the border of editor, rotate handle may not be visible.
24355
+ * Fix it by reduce the distance from image to rotate handle
24356
+ */
24357
+ function updateRotateHandlePosition(editInfo, editorRect, marginVertical, rotateCenter, rotateHandle) {
24358
+ var _a;
24359
+ var top = ((_a = rotateHandle.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.top) - (editorRect === null || editorRect === void 0 ? void 0 : editorRect.top);
24360
+ var angleRad = editInfo.angleRad, heightPx = editInfo.heightPx;
24361
+ var cosAngle = Math.cos(angleRad);
24362
+ var adjustedDistance = cosAngle <= 0
24363
+ ? Number.MAX_SAFE_INTEGER
24364
+ : (top + heightPx / 2 + marginVertical) / cosAngle - heightPx / 2;
24365
+ var rotateGap = Math.max(Math.min(ROTATE_GAP, adjustedDistance), 0);
24366
+ var rotateTop = Math.max(Math.min(ROTATE_SIZE, adjustedDistance - rotateGap), 0);
24367
+ rotateCenter.style.top = -rotateGap + 'px';
24368
+ rotateCenter.style.height = rotateGap + 'px';
24369
+ rotateHandle.style.top = -rotateTop + 'px';
24370
+ }
24371
+ exports.updateRotateHandlePosition = updateRotateHandlePosition;
24227
24372
  /**
24228
24373
  * @internal
24229
24374
  * Get HTML for rotate elements, including the rotate handle with icon, and a line between the handle and the image
@@ -28539,7 +28684,7 @@ var Watermark = /** @class */ (function () {
28539
28684
  this.removeWatermark(wrapper);
28540
28685
  }
28541
28686
  else if (event.operation == 0 /* NewEntity */) {
28542
- (0, roosterjs_editor_dom_1.applyFormat)(wrapper, this.format, this.editor.isDarkMode());
28687
+ (0, roosterjs_editor_dom_1.applyFormat)(wrapper, this.format, this.editor.isDarkMode(), this.editor.getDarkColorHandler());
28543
28688
  wrapper.spellcheck = false;
28544
28689
  }
28545
28690
  }
@@ -29588,6 +29733,12 @@ var CompatibleExperimentalFeatures;
29588
29733
  * the block element (In most case, the DIV element) so keep the block element clean.
29589
29734
  */
29590
29735
  CompatibleExperimentalFeatures["DefaultFormatInSpan"] = "DefaultFormatInSpan";
29736
+ /**
29737
+ * Use variable-based dark mode solution rather than dataset-based solution.
29738
+ * When enable this feature, need to pass in a DarkModelHandler object to each call of setColor and applyFormat
29739
+ * if you need them work for dark mode
29740
+ */
29741
+ CompatibleExperimentalFeatures["VariableBasedDarkColor"] = "VariableBasedDarkColor";
29591
29742
  })(CompatibleExperimentalFeatures = exports.CompatibleExperimentalFeatures || (exports.CompatibleExperimentalFeatures = {}));
29592
29743
 
29593
29744