superdoc 1.0.0-beta.2 → 1.0.0-beta.4

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 (34) hide show
  1. package/dist/chunks/{PdfViewer-saAhozRR.es.js → PdfViewer-DUns3s8O.es.js} +2 -2
  2. package/dist/chunks/{PdfViewer-CeuX3gOe.cjs → PdfViewer-ZtwLhE_8.cjs} +1 -1
  3. package/dist/chunks/{eventemitter3-BZXKb7j7.es.js → eventemitter3-ByBH0NYV.es.js} +1 -1
  4. package/dist/chunks/{index-Sn-JVHIg-BCItIT88.es.js → index-BNGaD3Up-CQuoo1EF.es.js} +1 -1
  5. package/dist/chunks/{index-Sn-JVHIg-BxOp3gSx.cjs → index-BNGaD3Up-D2cRHMMk.cjs} +1 -1
  6. package/dist/chunks/{index-Dh5oVJua.cjs → index-BW38mdZF.cjs} +3 -3
  7. package/dist/chunks/{index-C0OeGje6.es.js → index-DIccWgYh.es.js} +6 -6
  8. package/dist/chunks/{jszip-Duxs2YMV.es.js → jszip-BwsONqK5.es.js} +1 -1
  9. package/dist/chunks/{super-editor.es-BKljkYUU.cjs → super-editor.es-C06-V-Iy.cjs} +736 -215
  10. package/dist/chunks/{super-editor.es-Dcz39nKY.es.js → super-editor.es-CtCHBIPE.es.js} +737 -216
  11. package/dist/chunks/{vue-B5QAf5pA.es.js → vue-CztqUvm1.es.js} +17 -17
  12. package/dist/chunks/xml-js-BZPSMmVo.es.js +2 -0
  13. package/dist/packages/superdoc/src/core/SuperDoc.d.ts +35 -2
  14. package/dist/packages/superdoc/src/core/SuperDoc.d.ts.map +1 -1
  15. package/dist/super-editor/ai-writer.es.js +2 -2
  16. package/dist/super-editor/chunks/{converter-BFGB7hqj.js → converter-ZJiSHoiq.js} +1 -1
  17. package/dist/super-editor/chunks/{docx-zipper-OPbzIk16.js → docx-zipper-B7FStorN.js} +1 -1
  18. package/dist/super-editor/chunks/{editor-CtI4XnMw.js → editor-DvepAjbe.js} +553 -181
  19. package/dist/super-editor/chunks/{index-Sn-JVHIg.js → index-BNGaD3Up.js} +1 -1
  20. package/dist/super-editor/chunks/{toolbar-BydALv4o.js → toolbar-CKXXbIQO.js} +2 -2
  21. package/dist/super-editor/converter.es.js +1 -1
  22. package/dist/super-editor/docx-zipper.es.js +2 -2
  23. package/dist/super-editor/editor.es.js +3 -3
  24. package/dist/super-editor/file-zipper.es.js +1 -1
  25. package/dist/super-editor/super-editor.es.js +217 -41
  26. package/dist/super-editor/toolbar.es.js +2 -2
  27. package/dist/super-editor.cjs +1 -1
  28. package/dist/super-editor.es.js +2 -2
  29. package/dist/superdoc.cjs +2 -2
  30. package/dist/superdoc.es.js +2 -2
  31. package/dist/superdoc.umd.js +738 -217
  32. package/dist/superdoc.umd.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunks/xml-js-CVyfrKaV.es.js +0 -2
@@ -1,4 +1,4 @@
1
- import { g as global$2, r as ref$1, c as createApp, a as computed, b as createElementBlock, o as openBlock, F as Fragment$1, d as renderList, n as normalizeClass, w as withModifiers, e as createCommentVNode, t as toDisplayString, f as createBaseVNode, i as inject, h as onBeforeMount, j as onMounted, k as onBeforeUnmount, l as watch, m as defineComponent, p as getCurrentInstance, q as onDeactivated, s as nextTick, u as createBlock, v as createVNode, x as unref, y as h, z as mergeProps, A as shallowRef, B as withCtx, C as createTextVNode, D as normalizeStyle, E as toRef, G as provide, H as cloneVNode, T as Text$2, I as withDirectives, J as watchEffect, K as vModelText, L as withKeys, M as reactive, N as readonly, O as Transition, P as vShow, Q as Comment, R as renderSlot, S as onActivated, U as Teleport, V as isVNode, W as onUnmounted, X as resolveDynamicComponent, Y as normalizeProps, Z as guardReactiveProps, _ as markRaw } from "./vue-B5QAf5pA.es.js";
1
+ import { g as global$2, r as ref$1, c as createApp, a as computed, b as createElementBlock, o as openBlock, F as Fragment$1, d as renderList, n as normalizeClass, w as withModifiers, e as createCommentVNode, t as toDisplayString, f as createBaseVNode, i as inject, h as onBeforeMount, j as onMounted, k as onBeforeUnmount, l as watch, m as getCurrentInstance, p as onDeactivated, q as nextTick, s as createBlock, u as createVNode, v as unref, x as normalizeStyle, y as defineComponent, z as h, A as mergeProps, B as shallowRef, C as withCtx, D as createTextVNode, E as toRef, G as provide, H as cloneVNode, T as Text$2, I as withDirectives, J as watchEffect, K as vModelText, L as withKeys, M as reactive, N as readonly, O as Transition, P as vShow, Q as Comment, R as renderSlot, S as onActivated, U as Teleport, V as isVNode, W as onUnmounted, X as markRaw, Y as resolveDynamicComponent, Z as normalizeProps, _ as guardReactiveProps } from "./vue-CztqUvm1.es.js";
2
2
  import * as Y from "yjs";
3
3
  import { UndoManager, Item as Item$2, ContentType, Text as Text$1, XmlElement, encodeStateAsUpdate } from "yjs";
4
4
  var __defProp$2 = Object.defineProperty;
@@ -35563,7 +35563,7 @@ const _SuperConverter = class _SuperConverter2 {
35563
35563
  static getStoredSuperdocVersion(docx) {
35564
35564
  return _SuperConverter2.getStoredCustomProperty(docx, "SuperdocVersion");
35565
35565
  }
35566
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.0.0-beta.2") {
35566
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.0.0-beta.4") {
35567
35567
  return _SuperConverter2.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
35568
35568
  }
35569
35569
  /**
@@ -38763,7 +38763,7 @@ var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "rea
38763
38763
  var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
38764
38764
  var __privateSet = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
38765
38765
  var __privateMethod$1 = (obj, member, method) => (__accessCheck$1(obj, member, "access private method"), method);
38766
- var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, dispatchWithFallback_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, getPluginKeyName_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, checkFonts_fn, determineUnsupportedFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _map, _editor2, _descriptors, _collections, _editorEntries, _maxCachedEditors, _editorAccessOrder, _pendingCreations, _cacheHits, _cacheMisses, _evictions, _HeaderFooterEditorManager_instances, hasConverter_fn, extractCollections_fn, collectDescriptors_fn, teardownMissingEditors_fn, teardownEditors_fn, createEditor_fn, createEditorContainer_fn, registerConverterEditor_fn, unregisterConverterEditor_fn, updateAccessOrder_fn, enforceCacheSizeLimit_fn, _manager, _mediaFiles, _blockCache, _HeaderFooterLayoutAdapter_instances, getBlocks_fn, getConverterContext_fn, _instances, _options, _editor3, _visibleHost, _viewportHost, _painterHost, _selectionOverlay, _hiddenHost, _layoutOptions, _layoutState, _domPainter, _layoutError, _layoutErrorState, _errorBanner, _errorBannerMessage, _telemetryEmitter, _renderScheduled, _pendingDocChange, _isRerendering, _selectionUpdateScheduled, _remoteCursorUpdateScheduled, _rafHandle, _editorListeners, _sectionMetadata, _documentMode, _inputBridge, _trackedChangesMode, _trackedChangesEnabled, _trackedChangesOverrides, _headerFooterManager, _headerFooterAdapter, _headerFooterIdentifier, _headerLayoutResults, _footerLayoutResults, _headerDecorationProvider, _footerDecorationProvider, _headerFooterManagerCleanups, _headerRegions, _footerRegions, _session, _activeHeaderFooterEditor, _hoverOverlay, _hoverTooltip, _modeBanner, _ariaLiveRegion, _hoverRegion, _clickCount, _lastClickTime, _lastClickPosition, _remoteCursorState, _remoteCursorDirty, _remoteCursorOverlay, _localSelectionLayer, _awarenessCleanup, _scrollCleanup, _remoteCursorRafHandle, _scrollTimeout, _PresentationEditor_instances, aggregateLayoutBounds_fn, safeCleanup_fn, setupEditorListeners_fn, setupCollaborationCursors_fn, normalizeAwarenessStates_fn, getFallbackColor_fn, getValidatedColor_fn, scheduleRemoteCursorUpdate_fn, scheduleRemoteCursorReRender_fn, updateRemoteCursors_fn, renderRemoteCursors_fn, renderRemoteCaret_fn, renderRemoteCursorLabel_fn, renderRemoteSelection_fn, setupPointerHandlers_fn, setupInputBridge_fn, initHeaderFooterRegistry_fn, _handlePointerDown, getFirstTextPosition_fn, registerPointerClick_fn, selectWordAt_fn, selectParagraphAt_fn, isWordCharacter_fn, _handlePointerMove, _handlePointerLeave, _handleDoubleClick, _handleKeyDown, focusHeaderFooterShortcut_fn, scheduleRerender_fn, flushRerenderQueue_fn, rerender_fn, ensurePainter_fn, scheduleSelectionUpdate_fn, updateSelection_fn, resolveLayoutOptions_fn, buildHeaderFooterInput_fn, computeHeaderFooterConstraints_fn, updateDecorationProviders_fn, createDecorationProvider_fn, computeDecorationBox_fn, rebuildHeaderFooterRegions_fn, hitTestHeaderFooterRegion_fn, pointInRegion_fn, activateHeaderFooterRegion_fn, enterHeaderFooterMode_fn, exitHeaderFooterMode_fn, getActiveDomTarget_fn, emitHeaderFooterModeChanged_fn, emitHeaderFooterEditingContext_fn, updateAwarenessSession_fn, updateModeBanner_fn, announce_fn, validateHeaderFooterEditPermission_fn, emitHeaderFooterEditBlocked_fn, resolveDescriptorForRegion_fn, getBodyPageHeight_fn, getHeaderFooterPageHeight_fn, renderSelectionRects_fn, renderHoverRegion_fn, clearHoverRegion_fn, renderCaretOverlay_fn, getHeaderFooterContext_fn, computeHeaderFooterSelectionRects_fn, computeHeaderFooterCaretRect_fn, syncTrackedChangesPreferences_fn, deriveTrackedChangesMode_fn, deriveTrackedChangesEnabled_fn, getTrackChangesPluginState_fn, computeDefaultLayoutDefaults_fn, parseColumns_fn, inchesToPx_fn, applyZoom_fn, createLayoutMetrics_fn, convertPageLocalToOverlayCoords_fn, normalizeClientPoint_fn, computeCaretLayoutRect_fn, findLineContainingPos_fn, lineHeightBeforeIndex_fn, getCurrentPageIndex_fn, findRegionForPage_fn, handleLayoutError_fn, decorateError_fn, showLayoutErrorBanner_fn, dismissErrorBanner_fn, createHiddenHost_fn, _windowRoot, _visibleHost2, _getTargetDom, _onTargetChanged, _listeners, _currentTarget, _PresentationInputBridge_instances, addListener_fn, dispatchToTarget_fn, forwardKeyboardEvent_fn, forwardTextEvent_fn, forwardCompositionEvent_fn, forwardContextMenu_fn, isEventOnActiveTarget_fn, _DocumentSectionView_instances, init_fn2, addToolTip_fn, _ParagraphNodeView_instances, updateHTMLAttributes_fn, updateDOMStyles_fn, updateListStyles_fn, initList_fn, checkIsList_fn, createMarker_fn, createSeparator_fn, calculateTabSeparatorStyle_fn, calculateMarkerStyle_fn, removeList_fn, getParagraphContext_fn, scheduleAnimation_fn, cancelScheduledAnimation_fn, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn;
38766
+ var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, dispatchWithFallback_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, getPluginKeyName_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, checkFonts_fn, determineUnsupportedFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _map, _editor2, _descriptors, _collections, _editorEntries, _maxCachedEditors, _editorAccessOrder, _pendingCreations, _cacheHits, _cacheMisses, _evictions, _HeaderFooterEditorManager_instances, hasConverter_fn, extractCollections_fn, collectDescriptors_fn, teardownMissingEditors_fn, teardownEditors_fn, createEditor_fn, createEditorContainer_fn, registerConverterEditor_fn, unregisterConverterEditor_fn, updateAccessOrder_fn, enforceCacheSizeLimit_fn, _manager, _mediaFiles, _blockCache, _HeaderFooterLayoutAdapter_instances, getBlocks_fn, getConverterContext_fn, _instances, _options, _editor3, _visibleHost, _viewportHost, _painterHost, _selectionOverlay, _hiddenHost, _layoutOptions, _layoutState, _domPainter, _layoutError, _layoutErrorState, _errorBanner, _errorBannerMessage, _telemetryEmitter, _renderScheduled, _pendingDocChange, _isRerendering, _selectionUpdateScheduled, _remoteCursorUpdateScheduled, _rafHandle, _editorListeners, _sectionMetadata, _documentMode, _inputBridge, _trackedChangesMode, _trackedChangesEnabled, _trackedChangesOverrides, _headerFooterManager, _headerFooterAdapter, _headerFooterIdentifier, _headerLayoutResults, _footerLayoutResults, _headerDecorationProvider, _footerDecorationProvider, _headerFooterManagerCleanups, _headerRegions, _footerRegions, _session, _activeHeaderFooterEditor, _hoverOverlay, _hoverTooltip, _modeBanner, _ariaLiveRegion, _hoverRegion, _clickCount, _lastClickTime, _lastClickPosition, _remoteCursorState, _remoteCursorDirty, _remoteCursorOverlay, _localSelectionLayer, _awarenessCleanup, _scrollCleanup, _remoteCursorRafHandle, _scrollTimeout, _PresentationEditor_instances, aggregateLayoutBounds_fn, safeCleanup_fn, setupEditorListeners_fn, setupCollaborationCursors_fn, normalizeAwarenessStates_fn, getFallbackColor_fn, getValidatedColor_fn, scheduleRemoteCursorUpdate_fn, scheduleRemoteCursorReRender_fn, updateRemoteCursors_fn, renderRemoteCursors_fn, renderRemoteCaret_fn, renderRemoteCursorLabel_fn, renderRemoteSelection_fn, setupPointerHandlers_fn, setupInputBridge_fn, initHeaderFooterRegistry_fn, _handlePointerDown, getFirstTextPosition_fn, registerPointerClick_fn, selectWordAt_fn, selectParagraphAt_fn, isWordCharacter_fn, _handlePointerMove, _handlePointerLeave, _handleDoubleClick, _handleKeyDown, focusHeaderFooterShortcut_fn, scheduleRerender_fn, flushRerenderQueue_fn, rerender_fn, ensurePainter_fn, scheduleSelectionUpdate_fn, updateSelection_fn, resolveLayoutOptions_fn, buildHeaderFooterInput_fn, computeHeaderFooterConstraints_fn, updateDecorationProviders_fn, createDecorationProvider_fn, computeDecorationBox_fn, rebuildHeaderFooterRegions_fn, hitTestHeaderFooterRegion_fn, pointInRegion_fn, activateHeaderFooterRegion_fn, enterHeaderFooterMode_fn, exitHeaderFooterMode_fn, getActiveDomTarget_fn, emitHeaderFooterModeChanged_fn, emitHeaderFooterEditingContext_fn, updateAwarenessSession_fn, updateModeBanner_fn, announce_fn, validateHeaderFooterEditPermission_fn, emitHeaderFooterEditBlocked_fn, resolveDescriptorForRegion_fn, getBodyPageHeight_fn, getHeaderFooterPageHeight_fn, renderSelectionRects_fn, renderHoverRegion_fn, clearHoverRegion_fn, renderCaretOverlay_fn, getHeaderFooterContext_fn, computeHeaderFooterSelectionRects_fn, computeHeaderFooterCaretRect_fn, syncTrackedChangesPreferences_fn, deriveTrackedChangesMode_fn, deriveTrackedChangesEnabled_fn, getTrackChangesPluginState_fn, computeDefaultLayoutDefaults_fn, parseColumns_fn, inchesToPx_fn, applyZoom_fn, createLayoutMetrics_fn, convertPageLocalToOverlayCoords_fn, normalizeClientPoint_fn, computeCaretLayoutRect_fn, findLineContainingPos_fn, lineHeightBeforeIndex_fn, getCurrentPageIndex_fn, findRegionForPage_fn, handleLayoutError_fn, decorateError_fn, showLayoutErrorBanner_fn, dismissErrorBanner_fn, createHiddenHost_fn, _windowRoot, _visibleHost2, _getTargetDom, _onTargetChanged, _listeners, _currentTarget, _destroyed, _PresentationInputBridge_instances, addListener_fn, dispatchToTarget_fn, forwardKeyboardEvent_fn, forwardTextEvent_fn, forwardCompositionEvent_fn, forwardContextMenu_fn, isEventOnActiveTarget_fn, _DocumentSectionView_instances, init_fn2, addToolTip_fn, _ParagraphNodeView_instances, updateHTMLAttributes_fn, updateDOMStyles_fn, updateListStyles_fn, initList_fn, checkIsList_fn, createMarker_fn, createSeparator_fn, calculateTabSeparatorStyle_fn, calculateMarkerStyle_fn, removeList_fn, getParagraphContext_fn, scheduleAnimation_fn, cancelScheduledAnimation_fn, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn;
38767
38767
  var GOOD_LEAF_SIZE = 200;
38768
38768
  var RopeSequence = function RopeSequence2() {
38769
38769
  };
@@ -52270,7 +52270,7 @@ const isHeadless = (editor) => {
52270
52270
  const shouldSkipNodeView = (editor) => {
52271
52271
  return isHeadless(editor);
52272
52272
  };
52273
- const summaryVersion = "1.0.0-beta.2";
52273
+ const summaryVersion = "1.0.0-beta.4";
52274
52274
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
52275
52275
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
52276
52276
  function mapAttributes(attrs) {
@@ -53049,7 +53049,7 @@ const _Editor = class _Editor2 extends EventEmitter$1 {
53049
53049
  { default: remarkStringify },
53050
53050
  { default: remarkGfm }
53051
53051
  ] = await Promise.all([
53052
- import("./index-Sn-JVHIg-BCItIT88.es.js"),
53052
+ import("./index-BNGaD3Up-CQuoo1EF.es.js"),
53053
53053
  import("./index-DRCvimau-Cw339678.es.js"),
53054
53054
  import("./index-C_x_N6Uh-DJn8hIEt.es.js"),
53055
53055
  import("./index-D_sWOSiG-DE96TaT5.es.js"),
@@ -53254,7 +53254,7 @@ const _Editor = class _Editor2 extends EventEmitter$1 {
53254
53254
  * Process collaboration migrations
53255
53255
  */
53256
53256
  processCollaborationMigrations() {
53257
- console.debug("[checkVersionMigrations] Current editor version", "1.0.0-beta.2");
53257
+ console.debug("[checkVersionMigrations] Current editor version", "1.0.0-beta.4");
53258
53258
  if (!this.options.ydoc) return;
53259
53259
  const metaMap = this.options.ydoc.getMap("meta");
53260
53260
  let docVersion = metaMap.get("version");
@@ -54873,6 +54873,50 @@ const resolveColorFromAttributes = (attrs, themeColors) => {
54873
54873
  }
54874
54874
  return void 0;
54875
54875
  };
54876
+ const MAX_DATA_ATTR_COUNT = 50;
54877
+ const MAX_DATA_ATTR_VALUE_LENGTH = 1e3;
54878
+ const MAX_DATA_ATTR_NAME_LENGTH = 100;
54879
+ const extractDataAttributes = (attrs) => {
54880
+ if (!attrs) return void 0;
54881
+ const result = {};
54882
+ let attrCount = 0;
54883
+ for (const [key2, value] of Object.entries(attrs)) {
54884
+ if (typeof key2 !== "string" || !key2.toLowerCase().startsWith("data-")) {
54885
+ continue;
54886
+ }
54887
+ if (attrCount >= MAX_DATA_ATTR_COUNT) {
54888
+ if (process$1$1.env.NODE_ENV === "development") {
54889
+ console.warn(`[PM-Adapter] Rejecting data attributes exceeding ${MAX_DATA_ATTR_COUNT} limit`);
54890
+ }
54891
+ break;
54892
+ }
54893
+ if (key2.length > MAX_DATA_ATTR_NAME_LENGTH) {
54894
+ if (process$1$1.env.NODE_ENV === "development") {
54895
+ console.warn(
54896
+ `[PM-Adapter] Rejecting data attribute name exceeding ${MAX_DATA_ATTR_NAME_LENGTH} chars: ${key2.substring(0, 50)}...`
54897
+ );
54898
+ }
54899
+ continue;
54900
+ }
54901
+ if (value == null) {
54902
+ continue;
54903
+ }
54904
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
54905
+ const stringValue = String(value);
54906
+ if (stringValue.length > MAX_DATA_ATTR_VALUE_LENGTH) {
54907
+ if (process$1$1.env.NODE_ENV === "development") {
54908
+ console.warn(
54909
+ `[PM-Adapter] Rejecting data attribute value exceeding ${MAX_DATA_ATTR_VALUE_LENGTH} chars for key: ${key2}`
54910
+ );
54911
+ }
54912
+ continue;
54913
+ }
54914
+ result[key2] = stringValue;
54915
+ attrCount++;
54916
+ }
54917
+ }
54918
+ return Object.keys(result).length > 0 ? result : void 0;
54919
+ };
54876
54920
  const normalizeRunMarkList = (value) => {
54877
54921
  if (!value) return void 0;
54878
54922
  let entries = value;
@@ -55041,6 +55085,19 @@ const sanitizeFontFamily = (fontFamily2) => {
55041
55085
  }
55042
55086
  return sanitized;
55043
55087
  };
55088
+ const normalizeFontSizePx = (value) => {
55089
+ if (isFiniteNumber(value)) return value;
55090
+ if (typeof value !== "string") return void 0;
55091
+ const trimmed = value.trim();
55092
+ if (!trimmed) return void 0;
55093
+ const numeric = Number.parseFloat(trimmed);
55094
+ if (!Number.isFinite(numeric)) return void 0;
55095
+ const unit = trimmed.match(/[a-zA-Z%]+$/)?.[0]?.toLowerCase();
55096
+ if (unit === "pt") {
55097
+ return ptToPx(numeric);
55098
+ }
55099
+ return numeric;
55100
+ };
55044
55101
  const applyTextStyleMark = (run2, attrs, themeColors) => {
55045
55102
  const resolvedColor = resolveColorFromAttributes(attrs, themeColors);
55046
55103
  if (resolvedColor) {
@@ -55052,11 +55109,9 @@ const applyTextStyleMark = (run2, attrs, themeColors) => {
55052
55109
  run2.fontFamily = sanitized;
55053
55110
  }
55054
55111
  }
55055
- if (isFiniteNumber(attrs.fontSize)) {
55056
- const size2 = Number(attrs.fontSize);
55057
- if (size2 >= 1 && size2 <= 1e3) {
55058
- run2.fontSize = size2;
55059
- }
55112
+ const fontSizePx = normalizeFontSizePx(attrs.fontSize);
55113
+ if (fontSizePx !== void 0 && fontSizePx >= 1 && fontSizePx <= 1e3) {
55114
+ run2.fontSize = fontSizePx;
55060
55115
  }
55061
55116
  if (isFiniteNumber(attrs.letterSpacing)) {
55062
55117
  const spacing = Number(attrs.letterSpacing);
@@ -55070,6 +55125,7 @@ const DEFAULT_HYPERLINK_CONFIG = {
55070
55125
  };
55071
55126
  const applyMarksToRun = (run2, marks, hyperlinkConfig = DEFAULT_HYPERLINK_CONFIG, themeColors) => {
55072
55127
  marks.forEach((mark) => {
55128
+ const forwardedDataAttrs = extractDataAttributes(mark.attrs);
55073
55129
  try {
55074
55130
  switch (mark.type) {
55075
55131
  case TRACK_INSERT_MARK:
@@ -55164,6 +55220,9 @@ const applyMarksToRun = (run2, marks, hyperlinkConfig = DEFAULT_HYPERLINK_CONFIG
55164
55220
  console.warn(`[PM-Adapter] Failed to apply mark ${mark.type}:`, error);
55165
55221
  }
55166
55222
  }
55223
+ if (forwardedDataAttrs) {
55224
+ run2.dataAttrs = { ...run2.dataAttrs ?? {}, ...forwardedDataAttrs };
55225
+ }
55167
55226
  });
55168
55227
  };
55169
55228
  function textNodeToRun(textNode, positions, defaultFont, defaultSize, inheritedMarks = [], sdtMetadata, hyperlinkConfig = DEFAULT_HYPERLINK_CONFIG$1, themeColors) {
@@ -55187,8 +55246,9 @@ function tabNodeToRun(node, positions, tabIndex, paragraph) {
55187
55246
  const pos = positions.get(node);
55188
55247
  if (!pos) return null;
55189
55248
  const paragraphAttrs = paragraph.attrs ?? {};
55190
- const tabStops = Array.isArray(paragraphAttrs.tabStops) ? paragraphAttrs.tabStops : void 0;
55191
- const indent = paragraphAttrs.indent;
55249
+ const paragraphProps = typeof paragraphAttrs.paragraphProperties === "object" && paragraphAttrs.paragraphProperties !== null ? paragraphAttrs.paragraphProperties : {};
55250
+ const tabStops = Array.isArray(paragraphAttrs.tabStops) && paragraphAttrs.tabStops.length ? paragraphAttrs.tabStops : Array.isArray(paragraphProps.tabStops) ? paragraphProps.tabStops : void 0;
55251
+ const indent = paragraphAttrs.indent ?? paragraphProps.indent ?? void 0;
55192
55252
  return {
55193
55253
  kind: "tab",
55194
55254
  text: " ",
@@ -55502,6 +55562,9 @@ const normalizeParagraphSpacing = (value) => {
55502
55562
  const afterRaw = pickNumber(source.after);
55503
55563
  const lineRaw = pickNumber(source.line);
55504
55564
  const lineRule = normalizeLineRule(source.lineRule);
55565
+ const beforeAutospacing = toBooleanFlag(source.beforeAutospacing ?? source.beforeAutoSpacing);
55566
+ const afterAutospacing = toBooleanFlag(source.afterAutospacing ?? source.afterAutoSpacing);
55567
+ const contextualSpacing = toBooleanFlag(source.contextualSpacing);
55505
55568
  const before = beforeRaw != null ? twipsToPx$1(beforeRaw) : pickNumber(source.lineSpaceBefore);
55506
55569
  const after = afterRaw != null ? twipsToPx$1(afterRaw) : pickNumber(source.lineSpaceAfter);
55507
55570
  const line = normalizeLineValue(lineRaw, lineRule);
@@ -55509,8 +55572,24 @@ const normalizeParagraphSpacing = (value) => {
55509
55572
  if (after != null) spacing.after = after;
55510
55573
  if (line != null) spacing.line = line;
55511
55574
  if (lineRule) spacing.lineRule = lineRule;
55575
+ if (beforeAutospacing != null) spacing.beforeAutospacing = beforeAutospacing;
55576
+ if (afterAutospacing != null) spacing.afterAutospacing = afterAutospacing;
55577
+ if (contextualSpacing != null) spacing.contextualSpacing = contextualSpacing;
55512
55578
  return Object.keys(spacing).length > 0 ? spacing : void 0;
55513
55579
  };
55580
+ const toBooleanFlag = (value) => {
55581
+ if (value === true || value === false) return value;
55582
+ if (typeof value === "string") {
55583
+ const normalized = value.trim().toLowerCase();
55584
+ if (["true", "1", "on", "yes"].includes(normalized)) return true;
55585
+ if (["false", "0", "off", "no"].includes(normalized)) return false;
55586
+ }
55587
+ if (typeof value === "number") {
55588
+ if (value === 1) return true;
55589
+ if (value === 0) return false;
55590
+ }
55591
+ return void 0;
55592
+ };
55514
55593
  const normalizeLineValue = (value, lineRule) => {
55515
55594
  if (value == null) return void 0;
55516
55595
  if (lineRule === "auto") {
@@ -56883,15 +56962,17 @@ const hydrateParagraphStyleAttrs = (para, context, preResolved) => {
56883
56962
  return null;
56884
56963
  }
56885
56964
  const attrs = para.attrs ?? {};
56886
- const styleId = typeof attrs.styleId === "string" && attrs.styleId.trim() ? attrs.styleId : null;
56965
+ const paragraphProps = typeof attrs.paragraphProperties === "object" && attrs.paragraphProperties !== null ? attrs.paragraphProperties : {};
56966
+ const styleIdSource = attrs.styleId ?? paragraphProps.styleId;
56967
+ const styleId = typeof styleIdSource === "string" && styleIdSource.trim() ? styleIdSource : null;
56887
56968
  if (!styleId) {
56888
56969
  return null;
56889
56970
  }
56890
56971
  const inlineProps = {
56891
56972
  styleId,
56892
- numberingProperties: cloneIfObject(attrs.numberingProperties),
56893
- indent: cloneIfObject(attrs.indent),
56894
- spacing: cloneIfObject(attrs.spacing)
56973
+ numberingProperties: cloneIfObject(attrs.numberingProperties ?? paragraphProps.numberingProperties),
56974
+ indent: cloneIfObject(attrs.indent ?? paragraphProps.indent),
56975
+ spacing: cloneIfObject(attrs.spacing ?? paragraphProps.spacing)
56895
56976
  };
56896
56977
  const resolverParams = {
56897
56978
  docx: context.docx,
@@ -57169,13 +57250,17 @@ const computeWordLayoutForParagraph = (paragraphAttrs, numberingProps, styleCont
57169
57250
  };
57170
57251
  const computeParagraphAttrs = (para, styleContext, listCounterContext, converterContext, hydrationOverride) => {
57171
57252
  const attrs = para.attrs ?? {};
57253
+ const paragraphProps = typeof attrs.paragraphProperties === "object" && attrs.paragraphProperties !== null ? attrs.paragraphProperties : {};
57172
57254
  const hydrated = hydrationOverride ?? hydrateParagraphStyleAttrs(para, converterContext);
57173
- const spacingSource = attrs.spacing !== void 0 ? attrs.spacing : hydrated?.spacing;
57255
+ const spacingSource = attrs.spacing !== void 0 ? attrs.spacing : paragraphProps.spacing !== void 0 ? paragraphProps.spacing : hydrated?.spacing;
57174
57256
  const normalizedSpacing = normalizeParagraphSpacing(spacingSource);
57175
- const indentSource = attrs.indent ?? hydrated?.indent;
57257
+ const indentSource = attrs.indent ?? paragraphProps.indent ?? hydrated?.indent;
57176
57258
  const normalizedIndent = normalizePxIndent(indentSource) ?? normalizeParagraphIndent(indentSource ?? attrs.textIndent);
57177
- const styleNodeAttrs = hydrated?.tabStops && !attrs.tabStops && !attrs.tabs ? { ...attrs, tabStops: hydrated.tabStops } : attrs;
57259
+ const styleNodeAttrs = hydrated?.tabStops && !attrs.tabStops && !attrs.tabs ? { ...attrs, tabStops: hydrated.tabStops } : !attrs.tabStops && paragraphProps.tabStops ? { ...attrs, tabStops: paragraphProps.tabStops } : attrs;
57178
57260
  const styleNode = buildStyleNodeFromAttrs(styleNodeAttrs, normalizedSpacing, normalizedIndent);
57261
+ if (styleNodeAttrs.styleId == null && paragraphProps.styleId) {
57262
+ styleNode.styleId = paragraphProps.styleId;
57263
+ }
57179
57264
  const computed2 = resolveStyle(styleNode, styleContext);
57180
57265
  const { spacing, indent } = resolveSpacingIndent(computed2.paragraph, computed2.numbering);
57181
57266
  const paragraphAttrs = {};
@@ -57200,6 +57285,18 @@ const computeParagraphAttrs = (para, styleContext, listCounterContext, converter
57200
57285
  }
57201
57286
  const spacingPx = spacingPtToPx(spacing, normalizedSpacing);
57202
57287
  if (spacingPx) paragraphAttrs.spacing = spacingPx;
57288
+ if (normalizedSpacing?.beforeAutospacing != null || normalizedSpacing?.afterAutospacing != null) {
57289
+ paragraphAttrs.spacing = paragraphAttrs.spacing ?? {};
57290
+ if (normalizedSpacing?.beforeAutospacing != null) {
57291
+ paragraphAttrs.spacing.beforeAutospacing = normalizedSpacing.beforeAutospacing;
57292
+ }
57293
+ if (normalizedSpacing?.afterAutospacing != null) {
57294
+ paragraphAttrs.spacing.afterAutospacing = normalizedSpacing.afterAutospacing;
57295
+ }
57296
+ }
57297
+ if (normalizedSpacing?.contextualSpacing != null) {
57298
+ paragraphAttrs.contextualSpacing = normalizedSpacing.contextualSpacing;
57299
+ }
57203
57300
  const hasExplicitIndent = Boolean(normalizedIndent);
57204
57301
  const hasNumberingIndent = Boolean(computed2.numbering?.indent?.left || computed2.numbering?.indent?.hanging);
57205
57302
  if (hasExplicitIndent || hasNumberingIndent || bidi && adjustRightInd) {
@@ -57218,10 +57315,20 @@ const computeParagraphAttrs = (para, styleContext, listCounterContext, converter
57218
57315
  if (borders) paragraphAttrs.borders = borders;
57219
57316
  const shading = normalizeParagraphShading(attrs.shading ?? hydrated?.shading);
57220
57317
  if (shading) paragraphAttrs.shading = shading;
57318
+ const keepNext = paragraphProps.keepNext ?? hydrated?.keepNext ?? attrs.keepNext;
57319
+ if (keepNext === true) paragraphAttrs.keepNext = true;
57320
+ const keepLines = paragraphProps.keepLines ?? hydrated?.keepLines ?? attrs.keepLines;
57321
+ if (keepLines === true) paragraphAttrs.keepLines = true;
57221
57322
  const paragraphDecimalSeparator = styleContext.defaults?.decimalSeparator ?? DEFAULT_DECIMAL_SEPARATOR$2;
57222
57323
  if (paragraphDecimalSeparator !== DEFAULT_DECIMAL_SEPARATOR$2) {
57223
57324
  paragraphAttrs.decimalSeparator = paragraphDecimalSeparator;
57224
57325
  }
57326
+ const styleIdAttr = typeof attrs.styleId === "string" ? attrs.styleId : void 0;
57327
+ if (styleIdAttr) {
57328
+ paragraphAttrs.styleId = styleIdAttr;
57329
+ } else if (paragraphProps.styleId) {
57330
+ paragraphAttrs.styleId = paragraphProps.styleId;
57331
+ }
57225
57332
  const paraIntervalTwips = pickNumber(attrs.tabIntervalTwips) ?? (() => {
57226
57333
  const px = pickNumber(attrs.tabIntervalPx);
57227
57334
  return px != null ? Math.round(px * 15) : void 0;
@@ -57258,7 +57365,7 @@ const computeParagraphAttrs = (para, styleContext, listCounterContext, converter
57258
57365
  paragraphAttrs.floatAlignment = xAlign;
57259
57366
  }
57260
57367
  }
57261
- const numberingSource = attrs.numberingProperties ?? hydrated?.numberingProperties;
57368
+ const numberingSource = attrs.numberingProperties ?? paragraphProps.numberingProperties ?? hydrated?.numberingProperties;
57262
57369
  const rawNumberingProps = toAdapterNumberingProps(numberingSource);
57263
57370
  if (rawNumberingProps) {
57264
57371
  const numberingProps = rawNumberingProps;
@@ -57911,13 +58018,29 @@ const extractRunStyleId = (runProperties) => {
57911
58018
  return null;
57912
58019
  };
57913
58020
  const isTextRun$1 = (run2) => run2.kind !== "tab";
58021
+ const dataAttrsCompatible = (a, b2) => {
58022
+ const aAttrs = a.dataAttrs;
58023
+ const bAttrs = b2.dataAttrs;
58024
+ if (!aAttrs && !bAttrs) return true;
58025
+ if (!aAttrs || !bAttrs) return false;
58026
+ const aKeys = Object.keys(aAttrs).sort();
58027
+ const bKeys = Object.keys(bAttrs).sort();
58028
+ if (aKeys.length !== bKeys.length) return false;
58029
+ for (let i = 0; i < aKeys.length; i++) {
58030
+ const key2 = aKeys[i];
58031
+ if (key2 !== bKeys[i] || aAttrs[key2] !== bAttrs[key2]) {
58032
+ return false;
58033
+ }
58034
+ }
58035
+ return true;
58036
+ };
57914
58037
  function mergeAdjacentRuns(runs) {
57915
58038
  if (runs.length <= 1) return runs;
57916
58039
  const merged = [];
57917
58040
  let current = runs[0];
57918
58041
  for (let i = 1; i < runs.length; i++) {
57919
58042
  const next = runs[i];
57920
- const canMerge = isTextRun$1(current) && isTextRun$1(next) && !current.token && !next.token && current.pmStart != null && current.pmEnd != null && next.pmStart != null && next.pmEnd != null && current.pmEnd === next.pmStart && current.fontFamily === next.fontFamily && current.fontSize === next.fontSize && current.bold === next.bold && current.italic === next.italic && current.underline === next.underline && current.strike === next.strike && current.color === next.color && current.highlight === next.highlight && (current.letterSpacing ?? 0) === (next.letterSpacing ?? 0) && trackedChangesCompatible(current, next);
58043
+ const canMerge = isTextRun$1(current) && isTextRun$1(next) && !current.token && !next.token && current.pmStart != null && current.pmEnd != null && next.pmStart != null && next.pmEnd != null && current.pmEnd === next.pmStart && current.fontFamily === next.fontFamily && current.fontSize === next.fontSize && current.bold === next.bold && current.italic === next.italic && current.underline === next.underline && current.strike === next.strike && current.color === next.color && current.highlight === next.highlight && (current.letterSpacing ?? 0) === (next.letterSpacing ?? 0) && trackedChangesCompatible(current, next) && dataAttrsCompatible(current, next);
57921
58044
  if (canMerge) {
57922
58045
  const currText = current.text ?? "";
57923
58046
  const nextText = next.text ?? "";
@@ -57934,10 +58057,62 @@ function mergeAdjacentRuns(runs) {
57934
58057
  merged.push(current);
57935
58058
  return merged;
57936
58059
  }
58060
+ const applyBaseRunDefaults = (run2, defaults, fallbackFont, fallbackSize) => {
58061
+ if (!run2) return;
58062
+ if (defaults.fontFamily && run2.fontFamily === fallbackFont) {
58063
+ run2.fontFamily = defaults.fontFamily;
58064
+ }
58065
+ if (defaults.fontSizePx != null && run2.fontSize === fallbackSize) {
58066
+ run2.fontSize = defaults.fontSizePx;
58067
+ }
58068
+ if (defaults.color && !run2.color) {
58069
+ run2.color = defaults.color;
58070
+ }
58071
+ if (defaults.letterSpacing != null && run2.letterSpacing == null) {
58072
+ run2.letterSpacing = defaults.letterSpacing;
58073
+ }
58074
+ if (defaults.bold && run2.bold === void 0) {
58075
+ run2.bold = true;
58076
+ }
58077
+ if (defaults.italic && run2.italic === void 0) {
58078
+ run2.italic = true;
58079
+ }
58080
+ if (defaults.underline && !run2.underline) {
58081
+ run2.underline = defaults.underline;
58082
+ }
58083
+ };
57937
58084
  function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defaultSize, styleContext, listCounterContext, trackedChanges, bookmarks, hyperlinkConfig = DEFAULT_HYPERLINK_CONFIG$1, themeColors, converters, converterContext) {
57938
58085
  const baseBlockId = nextBlockId("paragraph");
57939
- const paragraphStyleId = typeof para.attrs?.styleId === "string" ? para.attrs.styleId : null;
58086
+ const paragraphProps = typeof para.attrs?.paragraphProperties === "object" && para.attrs.paragraphProperties !== null ? para.attrs.paragraphProperties : {};
58087
+ const paragraphStyleId = typeof para.attrs?.styleId === "string" && para.attrs.styleId.trim() ? para.attrs.styleId : typeof paragraphProps.styleId === "string" && paragraphProps.styleId.trim() ? paragraphProps.styleId : null;
57940
58088
  const paragraphHydration = converterContext ? hydrateParagraphStyleAttrs(para, converterContext) : null;
58089
+ let baseRunDefaults = {};
58090
+ try {
58091
+ const spacingSource = para.attrs?.spacing !== void 0 ? para.attrs.spacing : paragraphProps.spacing !== void 0 ? paragraphProps.spacing : paragraphHydration?.spacing;
58092
+ const indentSource = para.attrs?.indent ?? paragraphProps.indent ?? paragraphHydration?.indent;
58093
+ const normalizedSpacing = normalizeParagraphSpacing(spacingSource);
58094
+ const normalizedIndent = normalizePxIndent(indentSource) ?? normalizeParagraphIndent(indentSource ?? para.attrs?.textIndent);
58095
+ const styleNodeAttrs = paragraphHydration?.tabStops && !para.attrs?.tabStops && !para.attrs?.tabs ? { ...para.attrs ?? {}, tabStops: paragraphHydration.tabStops } : para.attrs ?? {};
58096
+ const styleNode = buildStyleNodeFromAttrs(styleNodeAttrs, normalizedSpacing, normalizedIndent);
58097
+ if (styleNodeAttrs.styleId == null && paragraphProps.styleId) {
58098
+ styleNode.styleId = paragraphProps.styleId;
58099
+ }
58100
+ const resolved = resolveStyle(styleNode, styleContext);
58101
+ baseRunDefaults = {
58102
+ fontFamily: resolved.character.font?.family,
58103
+ fontSizePx: ptToPx(resolved.character.font?.size),
58104
+ color: resolved.character.color,
58105
+ bold: resolved.character.font?.weight != null ? resolved.character.font.weight >= 600 : void 0,
58106
+ italic: resolved.character.font?.italic,
58107
+ underline: resolved.character.underline ? {
58108
+ style: resolved.character.underline.style,
58109
+ color: resolved.character.underline.color
58110
+ } : void 0,
58111
+ letterSpacing: ptToPx(resolved.character.letterSpacing)
58112
+ };
58113
+ } catch {
58114
+ baseRunDefaults = {};
58115
+ }
57941
58116
  const paragraphAttrs = computeParagraphAttrs(
57942
58117
  para,
57943
58118
  styleContext,
@@ -57945,6 +58120,18 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
57945
58120
  converterContext,
57946
58121
  paragraphHydration
57947
58122
  );
58123
+ if (paragraphAttrs?.spacing) {
58124
+ const spacing = { ...paragraphAttrs.spacing };
58125
+ const effectiveFontSize = baseRunDefaults.fontSizePx ?? defaultSize;
58126
+ const isList2 = Boolean(paragraphAttrs.numberingProperties);
58127
+ if (spacing.beforeAutospacing) {
58128
+ spacing.before = isList2 ? 0 : Math.max(0, Number(spacing.before ?? 0) + effectiveFontSize * 0.5);
58129
+ }
58130
+ if (spacing.afterAutospacing) {
58131
+ spacing.after = isList2 ? 0 : Math.max(0, Number(spacing.after ?? 0) + effectiveFontSize * 0.5);
58132
+ }
58133
+ paragraphAttrs.spacing = spacing;
58134
+ }
57948
58135
  const linkedStyleResolver = createLinkedStyleResolver(converterContext?.linkedStyles);
57949
58136
  const blocks = [];
57950
58137
  if (hasPageBreakBefore(para)) {
@@ -58022,6 +58209,7 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
58022
58209
  );
58023
58210
  const inlineStyleId = getInlineStyleId(inheritedMarks);
58024
58211
  applyRunStyles2(run2, inlineStyleId, activeRunStyleId);
58212
+ applyBaseRunDefaults(run2, baseRunDefaults, defaultFont, defaultSize);
58025
58213
  currentRuns.push(run2);
58026
58214
  return;
58027
58215
  }
@@ -58057,6 +58245,7 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
58057
58245
  );
58058
58246
  const inlineStyleId = getInlineStyleId(inheritedMarks);
58059
58247
  applyRunStyles2(run2, inlineStyleId, activeRunStyleId);
58248
+ applyBaseRunDefaults(run2, baseRunDefaults, defaultFont, defaultSize);
58060
58249
  currentRuns.push(run2);
58061
58250
  }
58062
58251
  }
@@ -58094,6 +58283,7 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
58094
58283
  );
58095
58284
  const inlineStyleId = getInlineStyleId(mergedMarks);
58096
58285
  applyRunStyles2(tokenRun, inlineStyleId, activeRunStyleId);
58286
+ applyBaseRunDefaults(tokenRun, baseRunDefaults, defaultFont, defaultSize);
58097
58287
  if (pageRefPos) {
58098
58288
  tokenRun.pmStart = pageRefPos.start;
58099
58289
  tokenRun.pmEnd = pageRefPos.end;
@@ -58152,6 +58342,7 @@ function paragraphToFlowBlocks$1(para, nextBlockId, positions, defaultFont, defa
58152
58342
  }
58153
58343
  const inlineStyleId = getInlineStyleId(inheritedMarks);
58154
58344
  applyRunStyles2(tokenRun, inlineStyleId, activeRunStyleId);
58345
+ applyBaseRunDefaults(tokenRun, baseRunDefaults, defaultFont, defaultSize);
58155
58346
  currentRuns.push(tokenRun);
58156
58347
  }
58157
58348
  return;
@@ -60180,7 +60371,9 @@ function layoutParagraphBlock(ctx2, anchors) {
60180
60371
  let lines = normalizeLines(measure);
60181
60372
  let fromLine = 0;
60182
60373
  const spacing = block.attrs?.spacing ?? {};
60183
- const spacingBefore = Math.max(0, Number(spacing.before ?? spacing.lineSpaceBefore ?? 0));
60374
+ const styleId = block.attrs?.styleId;
60375
+ const contextualSpacing = Boolean(block.attrs?.contextualSpacing);
60376
+ let spacingBefore = Math.max(0, Number(spacing.before ?? spacing.lineSpaceBefore ?? 0));
60184
60377
  const spacingAfter = Math.max(0, Number(spacing.after ?? spacing.lineSpaceAfter ?? 0));
60185
60378
  let appliedSpacingBefore = spacingBefore === 0;
60186
60379
  let lastState = null;
@@ -60196,6 +60389,15 @@ function layoutParagraphBlock(ctx2, anchors) {
60196
60389
  while (fromLine < lines.length) {
60197
60390
  let state2 = ensurePage();
60198
60391
  if (state2.trailingSpacing == null) state2.trailingSpacing = 0;
60392
+ if (contextualSpacing) {
60393
+ const prevStyle = state2.lastParagraphStyleId;
60394
+ if (styleId && prevStyle && prevStyle === styleId) {
60395
+ spacingBefore = 0;
60396
+ }
60397
+ }
60398
+ if (contextualSpacing && state2.lastParagraphStyleId && styleId && state2.lastParagraphStyleId === styleId) {
60399
+ spacingBefore = 0;
60400
+ }
60199
60401
  if (!appliedSpacingBefore && spacingBefore > 0) {
60200
60402
  while (!appliedSpacingBefore) {
60201
60403
  const prevTrailing = state2.trailingSpacing ?? 0;
@@ -60364,6 +60566,7 @@ function layoutParagraphBlock(ctx2, anchors) {
60364
60566
  } else {
60365
60567
  lastState.trailingSpacing = 0;
60366
60568
  }
60569
+ lastState.lastParagraphStyleId = styleId;
60367
60570
  }
60368
60571
  }
60369
60572
  function layoutImageBlock({
@@ -60602,7 +60805,8 @@ function createPaginator(opts) {
60602
60805
  contentBottom,
60603
60806
  constraintBoundaries: [],
60604
60807
  activeConstraintIndex: -1,
60605
- trailingSpacing: 0
60808
+ trailingSpacing: 0,
60809
+ lastParagraphStyleId: void 0
60606
60810
  };
60607
60811
  states.push(state2);
60608
60812
  pages.push(state2.page);
@@ -60624,6 +60828,7 @@ function createPaginator(opts) {
60624
60828
  state2.cursorY = state2.topMargin;
60625
60829
  }
60626
60830
  state2.trailingSpacing = 0;
60831
+ state2.lastParagraphStyleId = void 0;
60627
60832
  return state2;
60628
60833
  }
60629
60834
  return startNewPage();
@@ -65166,8 +65371,59 @@ const _DomPainter = class _DomPainter2 {
65166
65371
  this.headerProvider = header;
65167
65372
  this.footerProvider = footer;
65168
65373
  }
65169
- setData(blocks, measures) {
65374
+ /**
65375
+ * Updates the painter's block and measure data.
65376
+ *
65377
+ * @param blocks - Main document blocks
65378
+ * @param measures - Measures corresponding to main document blocks
65379
+ * @param headerBlocks - Optional header blocks from header/footer layout results
65380
+ * @param headerMeasures - Optional measures corresponding to header blocks
65381
+ * @param footerBlocks - Optional footer blocks from header/footer layout results
65382
+ * @param footerMeasures - Optional measures corresponding to footer blocks
65383
+ */
65384
+ setData(blocks, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures) {
65385
+ if (blocks.length !== measures.length) {
65386
+ throw new Error(
65387
+ `setData: blocks and measures arrays must have the same length. Got blocks.length=${blocks.length}, measures.length=${measures.length}`
65388
+ );
65389
+ }
65390
+ const hasHeaderBlocks = headerBlocks !== void 0;
65391
+ const hasHeaderMeasures = headerMeasures !== void 0;
65392
+ if (hasHeaderBlocks !== hasHeaderMeasures) {
65393
+ throw new Error(
65394
+ `setData: headerBlocks and headerMeasures must both be provided or both be omitted. Got headerBlocks=${hasHeaderBlocks ? "provided" : "omitted"}, headerMeasures=${hasHeaderMeasures ? "provided" : "omitted"}`
65395
+ );
65396
+ }
65397
+ if (hasHeaderBlocks && hasHeaderMeasures && headerBlocks.length !== headerMeasures.length) {
65398
+ throw new Error(
65399
+ `setData: headerBlocks and headerMeasures arrays must have the same length. Got headerBlocks.length=${headerBlocks.length}, headerMeasures.length=${headerMeasures.length}`
65400
+ );
65401
+ }
65402
+ const hasFooterBlocks = footerBlocks !== void 0;
65403
+ const hasFooterMeasures = footerMeasures !== void 0;
65404
+ if (hasFooterBlocks !== hasFooterMeasures) {
65405
+ throw new Error(
65406
+ `setData: footerBlocks and footerMeasures must both be provided or both be omitted. Got footerBlocks=${hasFooterBlocks ? "provided" : "omitted"}, footerMeasures=${hasFooterMeasures ? "provided" : "omitted"}`
65407
+ );
65408
+ }
65409
+ if (hasFooterBlocks && hasFooterMeasures && footerBlocks.length !== footerMeasures.length) {
65410
+ throw new Error(
65411
+ `setData: footerBlocks and footerMeasures arrays must have the same length. Got footerBlocks.length=${footerBlocks.length}, footerMeasures.length=${footerMeasures.length}`
65412
+ );
65413
+ }
65170
65414
  const nextLookup = this.buildBlockLookup(blocks, measures);
65415
+ if (headerBlocks && headerMeasures) {
65416
+ const headerLookup = this.buildBlockLookup(headerBlocks, headerMeasures);
65417
+ headerLookup.forEach((entry, id) => {
65418
+ nextLookup.set(id, entry);
65419
+ });
65420
+ }
65421
+ if (footerBlocks && footerMeasures) {
65422
+ const footerLookup = this.buildBlockLookup(footerBlocks, footerMeasures);
65423
+ footerLookup.forEach((entry, id) => {
65424
+ nextLookup.set(id, entry);
65425
+ });
65426
+ }
65171
65427
  const changed = /* @__PURE__ */ new Set();
65172
65428
  nextLookup.forEach((entry, id) => {
65173
65429
  const previous = this.blockLookup.get(id);
@@ -65490,6 +65746,14 @@ const _DomPainter = class _DomPainter2 {
65490
65746
  container.style.height = `${data.height}px`;
65491
65747
  container.style.top = `${Math.max(0, offset2)}px`;
65492
65748
  container.style.zIndex = "1";
65749
+ let footerYOffset = 0;
65750
+ if (kind === "footer" && data.fragments.length > 0) {
65751
+ const contentHeight = typeof data.contentHeight === "number" ? data.contentHeight : data.fragments.reduce((max2, f2) => {
65752
+ const fragHeight = "height" in f2 && typeof f2.height === "number" ? f2.height : this.estimateFragmentHeight(f2);
65753
+ return Math.max(max2, f2.y + Math.max(0, fragHeight));
65754
+ }, 0);
65755
+ footerYOffset = Math.max(0, data.height - contentHeight);
65756
+ }
65493
65757
  const context = {
65494
65758
  pageNumber: page.number,
65495
65759
  totalPages: this.totalPages,
@@ -65498,6 +65762,10 @@ const _DomPainter = class _DomPainter2 {
65498
65762
  };
65499
65763
  data.fragments.forEach((fragment) => {
65500
65764
  const fragEl = this.renderFragment(fragment, context);
65765
+ if (footerYOffset > 0) {
65766
+ const currentTop = parseFloat(fragEl.style.top) || fragment.y;
65767
+ fragEl.style.top = `${currentTop + footerYOffset}px`;
65768
+ }
65501
65769
  container.appendChild(fragEl);
65502
65770
  });
65503
65771
  if (!existing) {
@@ -65775,147 +66043,162 @@ const _DomPainter = class _DomPainter2 {
65775
66043
  return el;
65776
66044
  }
65777
66045
  renderListItemFragment(fragment, context) {
65778
- const lookup2 = this.blockLookup.get(fragment.blockId);
65779
- if (!lookup2 || lookup2.block.kind !== "list" || lookup2.measure.kind !== "list") {
65780
- throw new Error(`DomPainter: missing list data for fragment ${fragment.blockId}`);
65781
- }
65782
- if (!this.doc) {
65783
- throw new Error("DomPainter: document is not available");
66046
+ try {
66047
+ const lookup2 = this.blockLookup.get(fragment.blockId);
66048
+ if (!lookup2 || lookup2.block.kind !== "list" || lookup2.measure.kind !== "list") {
66049
+ throw new Error(`DomPainter: missing list data for fragment ${fragment.blockId}`);
66050
+ }
66051
+ if (!this.doc) {
66052
+ throw new Error("DomPainter: document is not available");
66053
+ }
66054
+ const block = lookup2.block;
66055
+ const measure = lookup2.measure;
66056
+ const item = block.items.find((entry) => entry.id === fragment.itemId);
66057
+ const itemMeasure = measure.items.find((entry) => entry.itemId === fragment.itemId);
66058
+ if (!item || !itemMeasure) {
66059
+ throw new Error(`DomPainter: missing list item ${fragment.itemId}`);
66060
+ }
66061
+ const fragmentEl = this.doc.createElement("div");
66062
+ fragmentEl.classList.add(CLASS_NAMES.fragment, `${CLASS_NAMES.fragment}-list-item`);
66063
+ applyStyles$2(fragmentEl, fragmentStyles);
66064
+ fragmentEl.style.left = `${fragment.x - fragment.markerWidth}px`;
66065
+ fragmentEl.style.top = `${fragment.y}px`;
66066
+ fragmentEl.style.width = `${fragment.markerWidth + fragment.width}px`;
66067
+ fragmentEl.dataset.blockId = fragment.blockId;
66068
+ fragmentEl.dataset.itemId = fragment.itemId;
66069
+ const paragraphMetadata = item.paragraph.attrs?.sdt;
66070
+ this.applySdtDataset(fragmentEl, paragraphMetadata);
66071
+ if (fragment.continuesFromPrev) {
66072
+ fragmentEl.dataset.continuesFromPrev = "true";
66073
+ }
66074
+ if (fragment.continuesOnNext) {
66075
+ fragmentEl.dataset.continuesOnNext = "true";
66076
+ }
66077
+ const markerEl = this.doc.createElement("span");
66078
+ markerEl.classList.add("superdoc-list-marker");
66079
+ const wordLayout = item.paragraph.attrs?.wordLayout;
66080
+ const marker = wordLayout?.marker;
66081
+ if (marker) {
66082
+ markerEl.textContent = marker.markerText ?? null;
66083
+ markerEl.style.display = "inline-block";
66084
+ markerEl.style.width = `${Math.max(0, fragment.markerWidth - LIST_MARKER_GAP$1)}px`;
66085
+ markerEl.style.paddingRight = `${LIST_MARKER_GAP$1}px`;
66086
+ markerEl.style.textAlign = marker.justification ?? "";
66087
+ markerEl.style.fontFamily = marker.run.fontFamily;
66088
+ markerEl.style.fontSize = `${marker.run.fontSize}px`;
66089
+ if (marker.run.bold) markerEl.style.fontWeight = "bold";
66090
+ if (marker.run.italic) markerEl.style.fontStyle = "italic";
66091
+ if (marker.run.color) markerEl.style.color = marker.run.color;
66092
+ if (marker.run.letterSpacing) markerEl.style.letterSpacing = `${marker.run.letterSpacing}px`;
66093
+ } else {
66094
+ markerEl.textContent = item.marker.text;
66095
+ markerEl.style.display = "inline-block";
66096
+ markerEl.style.width = `${Math.max(0, fragment.markerWidth - LIST_MARKER_GAP$1)}px`;
66097
+ markerEl.style.paddingRight = `${LIST_MARKER_GAP$1}px`;
66098
+ if (item.marker.align) {
66099
+ markerEl.style.textAlign = item.marker.align;
66100
+ }
66101
+ }
66102
+ fragmentEl.appendChild(markerEl);
66103
+ const contentEl = this.doc.createElement("div");
66104
+ contentEl.classList.add("superdoc-list-content");
66105
+ this.applySdtDataset(contentEl, paragraphMetadata);
66106
+ contentEl.style.display = "inline-block";
66107
+ contentEl.style.width = `${fragment.width}px`;
66108
+ const lines = itemMeasure.paragraph.lines.slice(fragment.fromLine, fragment.toLine);
66109
+ const contentAttrs = wordLayout ? item.paragraph.attrs : stripListIndent(item.paragraph.attrs);
66110
+ applyParagraphBlockStyles(contentEl, contentAttrs);
66111
+ lines.forEach((line) => {
66112
+ const lineEl = this.renderLine(item.paragraph, line, context);
66113
+ contentEl.appendChild(lineEl);
66114
+ });
66115
+ fragmentEl.appendChild(contentEl);
66116
+ return fragmentEl;
66117
+ } catch (error) {
66118
+ console.error("[DomPainter] List item fragment rendering failed:", { fragment, error });
66119
+ return this.createErrorPlaceholder(fragment.blockId, error);
65784
66120
  }
65785
- const block = lookup2.block;
65786
- const measure = lookup2.measure;
65787
- const item = block.items.find((entry) => entry.id === fragment.itemId);
65788
- const itemMeasure = measure.items.find((entry) => entry.itemId === fragment.itemId);
65789
- if (!item || !itemMeasure) {
65790
- throw new Error(`DomPainter: missing list item ${fragment.itemId}`);
65791
- }
65792
- const fragmentEl = this.doc.createElement("div");
65793
- fragmentEl.classList.add(CLASS_NAMES.fragment, `${CLASS_NAMES.fragment}-list-item`);
65794
- applyStyles$2(fragmentEl, fragmentStyles);
65795
- fragmentEl.style.left = `${fragment.x - fragment.markerWidth}px`;
65796
- fragmentEl.style.top = `${fragment.y}px`;
65797
- fragmentEl.style.width = `${fragment.markerWidth + fragment.width}px`;
65798
- fragmentEl.dataset.blockId = fragment.blockId;
65799
- fragmentEl.dataset.itemId = fragment.itemId;
65800
- const paragraphMetadata = item.paragraph.attrs?.sdt;
65801
- this.applySdtDataset(fragmentEl, paragraphMetadata);
65802
- if (fragment.continuesFromPrev) {
65803
- fragmentEl.dataset.continuesFromPrev = "true";
65804
- }
65805
- if (fragment.continuesOnNext) {
65806
- fragmentEl.dataset.continuesOnNext = "true";
65807
- }
65808
- const markerEl = this.doc.createElement("span");
65809
- markerEl.classList.add("superdoc-list-marker");
65810
- const wordLayout = item.paragraph.attrs?.wordLayout;
65811
- if (wordLayout?.marker) {
65812
- const marker = wordLayout.marker;
65813
- markerEl.textContent = marker.markerText;
65814
- markerEl.style.display = "inline-block";
65815
- markerEl.style.width = `${Math.max(0, fragment.markerWidth - LIST_MARKER_GAP$1)}px`;
65816
- markerEl.style.paddingRight = `${LIST_MARKER_GAP$1}px`;
65817
- markerEl.style.textAlign = marker.justification;
65818
- markerEl.style.fontFamily = marker.run.fontFamily;
65819
- markerEl.style.fontSize = `${marker.run.fontSize}px`;
65820
- if (marker.run.bold) markerEl.style.fontWeight = "bold";
65821
- if (marker.run.italic) markerEl.style.fontStyle = "italic";
65822
- if (marker.run.color) markerEl.style.color = marker.run.color;
65823
- if (marker.run.letterSpacing) markerEl.style.letterSpacing = `${marker.run.letterSpacing}px`;
65824
- } else {
65825
- markerEl.textContent = item.marker.text;
65826
- markerEl.style.display = "inline-block";
65827
- markerEl.style.width = `${Math.max(0, fragment.markerWidth - LIST_MARKER_GAP$1)}px`;
65828
- markerEl.style.paddingRight = `${LIST_MARKER_GAP$1}px`;
65829
- if (item.marker.align) {
65830
- markerEl.style.textAlign = item.marker.align;
65831
- }
65832
- }
65833
- fragmentEl.appendChild(markerEl);
65834
- const contentEl = this.doc.createElement("div");
65835
- contentEl.classList.add("superdoc-list-content");
65836
- this.applySdtDataset(contentEl, paragraphMetadata);
65837
- contentEl.style.display = "inline-block";
65838
- contentEl.style.width = `${fragment.width}px`;
65839
- const lines = itemMeasure.paragraph.lines.slice(fragment.fromLine, fragment.toLine);
65840
- const contentAttrs = wordLayout ? item.paragraph.attrs : stripListIndent(item.paragraph.attrs);
65841
- applyParagraphBlockStyles(contentEl, contentAttrs);
65842
- lines.forEach((line) => {
65843
- const lineEl = this.renderLine(item.paragraph, line, context);
65844
- contentEl.appendChild(lineEl);
65845
- });
65846
- fragmentEl.appendChild(contentEl);
65847
- return fragmentEl;
65848
66121
  }
65849
66122
  renderImageFragment(fragment) {
65850
- const lookup2 = this.blockLookup.get(fragment.blockId);
65851
- if (!lookup2 || lookup2.block.kind !== "image" || lookup2.measure.kind !== "image") {
65852
- throw new Error(`DomPainter: missing image block for fragment ${fragment.blockId}`);
65853
- }
65854
- if (!this.doc) {
65855
- throw new Error("DomPainter: document is not available");
65856
- }
65857
- const block = lookup2.block;
65858
- const fragmentEl = this.doc.createElement("div");
65859
- fragmentEl.classList.add(CLASS_NAMES.fragment);
65860
- applyStyles$2(fragmentEl, fragmentStyles);
65861
- this.applyFragmentFrame(fragmentEl, fragment);
65862
- fragmentEl.style.height = `${fragment.height}px`;
65863
- this.applySdtDataset(fragmentEl, block.attrs?.sdt);
65864
- this.applyContainerSdtDataset(fragmentEl, block.attrs?.containerSdt);
65865
- if (fragment.isAnchored && fragment.zIndex != null) {
65866
- fragmentEl.style.zIndex = String(fragment.zIndex);
65867
- }
65868
- const img = this.doc.createElement("img");
65869
- if (block.src) {
65870
- img.src = block.src;
66123
+ try {
66124
+ const lookup2 = this.blockLookup.get(fragment.blockId);
66125
+ if (!lookup2 || lookup2.block.kind !== "image" || lookup2.measure.kind !== "image") {
66126
+ throw new Error(`DomPainter: missing image block for fragment ${fragment.blockId}`);
66127
+ }
66128
+ if (!this.doc) {
66129
+ throw new Error("DomPainter: document is not available");
66130
+ }
66131
+ const block = lookup2.block;
66132
+ const fragmentEl = this.doc.createElement("div");
66133
+ fragmentEl.classList.add(CLASS_NAMES.fragment);
66134
+ applyStyles$2(fragmentEl, fragmentStyles);
66135
+ this.applyFragmentFrame(fragmentEl, fragment);
66136
+ fragmentEl.style.height = `${fragment.height}px`;
66137
+ this.applySdtDataset(fragmentEl, block.attrs?.sdt);
66138
+ this.applyContainerSdtDataset(fragmentEl, block.attrs?.containerSdt);
66139
+ if (fragment.isAnchored && fragment.zIndex != null) {
66140
+ fragmentEl.style.zIndex = String(fragment.zIndex);
66141
+ }
66142
+ const img = this.doc.createElement("img");
66143
+ if (block.src) {
66144
+ img.src = block.src;
66145
+ }
66146
+ img.alt = block.alt ?? "";
66147
+ img.style.width = "100%";
66148
+ img.style.height = "100%";
66149
+ img.style.objectFit = block.objectFit ?? "contain";
66150
+ img.style.display = block.display === "inline" ? "inline-block" : "block";
66151
+ fragmentEl.appendChild(img);
66152
+ return fragmentEl;
66153
+ } catch (error) {
66154
+ console.error("[DomPainter] Image fragment rendering failed:", { fragment, error });
66155
+ return this.createErrorPlaceholder(fragment.blockId, error);
65871
66156
  }
65872
- img.alt = block.alt ?? "";
65873
- img.style.width = "100%";
65874
- img.style.height = "100%";
65875
- img.style.objectFit = block.objectFit ?? "contain";
65876
- img.style.display = block.display === "inline" ? "inline-block" : "block";
65877
- fragmentEl.appendChild(img);
65878
- return fragmentEl;
65879
66157
  }
65880
66158
  renderDrawingFragment(fragment) {
65881
- const lookup2 = this.blockLookup.get(fragment.blockId);
65882
- if (!lookup2 || lookup2.block.kind !== "drawing" || lookup2.measure.kind !== "drawing") {
65883
- throw new Error(`DomPainter: missing drawing block for fragment ${fragment.blockId}`);
65884
- }
65885
- if (!this.doc) {
65886
- throw new Error("DomPainter: document is not available");
66159
+ try {
66160
+ const lookup2 = this.blockLookup.get(fragment.blockId);
66161
+ if (!lookup2 || lookup2.block.kind !== "drawing" || lookup2.measure.kind !== "drawing") {
66162
+ throw new Error(`DomPainter: missing drawing block for fragment ${fragment.blockId}`);
66163
+ }
66164
+ if (!this.doc) {
66165
+ throw new Error("DomPainter: document is not available");
66166
+ }
66167
+ const block = lookup2.block;
66168
+ const isVectorShapeBlock = block.kind === "drawing" && block.drawingKind === "vectorShape";
66169
+ const fragmentEl = this.doc.createElement("div");
66170
+ fragmentEl.classList.add(CLASS_NAMES.fragment, "superdoc-drawing-fragment");
66171
+ applyStyles$2(fragmentEl, fragmentStyles);
66172
+ this.applyFragmentFrame(fragmentEl, fragment);
66173
+ fragmentEl.style.height = `${fragment.height}px`;
66174
+ fragmentEl.style.position = "absolute";
66175
+ if (fragment.isAnchored && fragment.zIndex != null) {
66176
+ fragmentEl.style.zIndex = String(fragment.zIndex);
66177
+ }
66178
+ const innerWrapper = this.doc.createElement("div");
66179
+ innerWrapper.classList.add("superdoc-drawing-inner");
66180
+ innerWrapper.style.position = "absolute";
66181
+ innerWrapper.style.left = "50%";
66182
+ innerWrapper.style.top = "50%";
66183
+ innerWrapper.style.width = `${fragment.geometry.width}px`;
66184
+ innerWrapper.style.height = `${fragment.geometry.height}px`;
66185
+ innerWrapper.style.transformOrigin = "center";
66186
+ const scale = fragment.scale ?? 1;
66187
+ const transforms = ["translate(-50%, -50%)"];
66188
+ if (!isVectorShapeBlock) {
66189
+ transforms.push(`rotate(${fragment.geometry.rotation ?? 0}deg)`);
66190
+ transforms.push(`scaleX(${fragment.geometry.flipH ? -1 : 1})`);
66191
+ transforms.push(`scaleY(${fragment.geometry.flipV ? -1 : 1})`);
66192
+ }
66193
+ transforms.push(`scale(${scale})`);
66194
+ innerWrapper.style.transform = transforms.join(" ");
66195
+ innerWrapper.appendChild(this.renderDrawingContent(block, fragment));
66196
+ fragmentEl.appendChild(innerWrapper);
66197
+ return fragmentEl;
66198
+ } catch (error) {
66199
+ console.error("[DomPainter] Drawing fragment rendering failed:", { fragment, error });
66200
+ return this.createErrorPlaceholder(fragment.blockId, error);
65887
66201
  }
65888
- const block = lookup2.block;
65889
- const isVectorShapeBlock = block.kind === "drawing" && block.drawingKind === "vectorShape";
65890
- const fragmentEl = this.doc.createElement("div");
65891
- fragmentEl.classList.add(CLASS_NAMES.fragment, "superdoc-drawing-fragment");
65892
- applyStyles$2(fragmentEl, fragmentStyles);
65893
- this.applyFragmentFrame(fragmentEl, fragment);
65894
- fragmentEl.style.height = `${fragment.height}px`;
65895
- fragmentEl.style.position = "absolute";
65896
- if (fragment.isAnchored && fragment.zIndex != null) {
65897
- fragmentEl.style.zIndex = String(fragment.zIndex);
65898
- }
65899
- const innerWrapper = this.doc.createElement("div");
65900
- innerWrapper.classList.add("superdoc-drawing-inner");
65901
- innerWrapper.style.position = "absolute";
65902
- innerWrapper.style.left = "50%";
65903
- innerWrapper.style.top = "50%";
65904
- innerWrapper.style.width = `${fragment.geometry.width}px`;
65905
- innerWrapper.style.height = `${fragment.geometry.height}px`;
65906
- innerWrapper.style.transformOrigin = "center";
65907
- const scale = fragment.scale ?? 1;
65908
- const transforms = ["translate(-50%, -50%)"];
65909
- if (!isVectorShapeBlock) {
65910
- transforms.push(`rotate(${fragment.geometry.rotation ?? 0}deg)`);
65911
- transforms.push(`scaleX(${fragment.geometry.flipH ? -1 : 1})`);
65912
- transforms.push(`scaleY(${fragment.geometry.flipV ? -1 : 1})`);
65913
- }
65914
- transforms.push(`scale(${scale})`);
65915
- innerWrapper.style.transform = transforms.join(" ");
65916
- innerWrapper.appendChild(this.renderDrawingContent(block, fragment));
65917
- fragmentEl.appendChild(innerWrapper);
65918
- return fragmentEl;
65919
66202
  }
65920
66203
  renderDrawingContent(block, fragment) {
65921
66204
  if (!this.doc) {
@@ -66350,6 +66633,7 @@ const _DomPainter = class _DomPainter2 {
66350
66633
  }
66351
66634
  applyRunStyles(elem, run2, isActiveLink);
66352
66635
  elem.style.zIndex = "1";
66636
+ applyRunDataAttributes(elem, run2.dataAttrs);
66353
66637
  if (run2.pmStart != null) elem.dataset.pmStart = String(run2.pmStart);
66354
66638
  if (run2.pmEnd != null) elem.dataset.pmEnd = String(run2.pmEnd);
66355
66639
  if (trackedConfig) {
@@ -66548,6 +66832,33 @@ const _DomPainter = class _DomPainter2 {
66548
66832
  }
66549
66833
  }
66550
66834
  }
66835
+ /**
66836
+ * Estimates the height of a fragment when explicit height is not available.
66837
+ *
66838
+ * This method provides fallback height calculations for footer bottom-alignment
66839
+ * by consulting measure data for paragraphs and list items, or using the
66840
+ * fragment's height property for tables, images, and drawings.
66841
+ *
66842
+ * @param fragment - The fragment to estimate height for
66843
+ * @returns Estimated height in pixels, or 0 if height cannot be determined
66844
+ */
66845
+ estimateFragmentHeight(fragment) {
66846
+ const lookup2 = this.blockLookup.get(fragment.blockId);
66847
+ const measure = lookup2?.measure;
66848
+ if (fragment.kind === "para" && measure?.kind === "paragraph") {
66849
+ return measure.totalHeight;
66850
+ }
66851
+ if (fragment.kind === "list-item" && measure?.kind === "list") {
66852
+ return measure.totalHeight;
66853
+ }
66854
+ if (fragment.kind === "table") {
66855
+ return fragment.height;
66856
+ }
66857
+ if (fragment.kind === "image" || fragment.kind === "drawing") {
66858
+ return fragment.height;
66859
+ }
66860
+ return 0;
66861
+ }
66551
66862
  buildBlockLookup(blocks, measures) {
66552
66863
  if (blocks.length !== measures.length) {
66553
66864
  throw new Error("DomPainter requires the same number of blocks and measures");
@@ -66730,6 +67041,12 @@ const deriveBlockVersion = (block) => {
66730
67041
  run2.kind !== "tab" && run2.bold ? 1 : 0,
66731
67042
  run2.kind !== "tab" && run2.italic ? 1 : 0,
66732
67043
  run2.kind !== "tab" ? run2.color ?? "" : "",
67044
+ // Text decorations - ensures DOM updates when decoration properties change.
67045
+ run2.kind !== "tab" ? run2.underline?.style ?? "" : "",
67046
+ run2.kind !== "tab" ? run2.underline?.color ?? "" : "",
67047
+ run2.kind !== "tab" && run2.strike ? 1 : 0,
67048
+ run2.kind !== "tab" ? run2.highlight ?? "" : "",
67049
+ run2.kind !== "tab" && run2.letterSpacing != null ? run2.letterSpacing : "",
66733
67050
  run2.pmStart ?? "",
66734
67051
  run2.pmEnd ?? "",
66735
67052
  run2.kind !== "tab" ? run2.token ?? "" : ""
@@ -66824,6 +67141,20 @@ const applyRunStyles = (element, run2, isLink = false) => {
66824
67141
  element.style.textDecorationLine = decorations.join(" ");
66825
67142
  }
66826
67143
  };
67144
+ const applyRunDataAttributes = (element, dataAttrs) => {
67145
+ if (!dataAttrs) return;
67146
+ Object.entries(dataAttrs).forEach(([key2, value]) => {
67147
+ if (typeof key2 !== "string" || !key2.toLowerCase().startsWith("data-")) return;
67148
+ if (typeof value !== "string") return;
67149
+ try {
67150
+ element.setAttribute(key2, value);
67151
+ } catch (error) {
67152
+ if (process$1$1.env.NODE_ENV === "development") {
67153
+ console.warn(`[DomPainter] Failed to set data attribute "${key2}":`, error);
67154
+ }
67155
+ }
67156
+ });
67157
+ };
66827
67158
  const applyParagraphBlockStyles = (element, attrs) => {
66828
67159
  if (!attrs) return;
66829
67160
  if (attrs.alignment) {
@@ -66996,8 +67327,8 @@ const createDomPainter = (options) => {
66996
67327
  paint(layout, mount2) {
66997
67328
  painter.paint(layout, mount2);
66998
67329
  },
66999
- setData(blocks, measures) {
67000
- painter.setData(blocks, measures);
67330
+ setData(blocks, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures) {
67331
+ painter.setData(blocks, measures, headerBlocks, headerMeasures, footerBlocks, footerMeasures);
67001
67332
  },
67002
67333
  // Non-standard extension for demo app to avoid re-instantiating on provider changes
67003
67334
  setProviders(header, footer) {
@@ -70386,7 +70717,30 @@ rerender_fn = async function() {
70386
70717
  if (typeof painter.setProviders === "function") {
70387
70718
  painter.setProviders(__privateGet$1(this, _headerDecorationProvider), __privateGet$1(this, _footerDecorationProvider));
70388
70719
  }
70389
- painter.setData?.(blocks, measures);
70720
+ const headerBlocks = [];
70721
+ const headerMeasures = [];
70722
+ if (headerLayouts) {
70723
+ for (const headerResult of headerLayouts) {
70724
+ headerBlocks.push(...headerResult.blocks);
70725
+ headerMeasures.push(...headerResult.measures);
70726
+ }
70727
+ }
70728
+ const footerBlocks = [];
70729
+ const footerMeasures = [];
70730
+ if (footerLayouts) {
70731
+ for (const footerResult of footerLayouts) {
70732
+ footerBlocks.push(...footerResult.blocks);
70733
+ footerMeasures.push(...footerResult.measures);
70734
+ }
70735
+ }
70736
+ painter.setData?.(
70737
+ blocks,
70738
+ measures,
70739
+ headerBlocks.length > 0 ? headerBlocks : void 0,
70740
+ headerMeasures.length > 0 ? headerMeasures : void 0,
70741
+ footerBlocks.length > 0 ? footerBlocks : void 0,
70742
+ footerMeasures.length > 0 ? footerMeasures : void 0
70743
+ );
70390
70744
  painter.paint(layout, __privateGet$1(this, _painterHost));
70391
70745
  __privateSet(this, _layoutError, null);
70392
70746
  __privateSet(this, _layoutErrorState, "healthy");
@@ -70556,7 +70910,8 @@ createDecorationProvider_fn = function(kind, layout) {
70556
70910
  const finalHeaderId = headerId ?? fallbackId ?? void 0;
70557
70911
  return {
70558
70912
  fragments: slotPage.fragments,
70559
- height: variant.layout.height ?? box.height,
70913
+ height: box.height,
70914
+ contentHeight: variant.layout.height ?? box.height,
70560
70915
  offset: box.offset,
70561
70916
  marginLeft: box.x,
70562
70917
  contentWidth: box.width,
@@ -70583,18 +70938,19 @@ computeDecorationBox_fn = function(kind, pageMargins, pageHeight) {
70583
70938
  const left2 = margins.left ?? DEFAULT_MARGINS.left;
70584
70939
  const right2 = margins.right ?? DEFAULT_MARGINS.right;
70585
70940
  const width = Math.max(pageSize.w - (left2 + right2), 1);
70586
- const defaultHeight = kind === "header" ? margins.top ?? DEFAULT_MARGINS.top : margins.bottom ?? DEFAULT_MARGINS.bottom;
70587
- const { headerSpace, footerSpace } = extractHeaderFooterSpace(margins);
70588
- const target = kind === "header" ? headerSpace : footerSpace;
70589
- const height = Math.max(target || defaultHeight || 1, 1);
70590
70941
  const totalHeight = pageHeight ?? pageSize.h;
70591
- const offset2 = kind === "header" ? 0 : Math.max(0, totalHeight - height);
70592
- return {
70593
- x: left2,
70594
- width,
70595
- height,
70596
- offset: offset2
70597
- };
70942
+ if (kind === "header") {
70943
+ const headerMargin = margins.header ?? 0;
70944
+ const topMargin = margins.top ?? DEFAULT_MARGINS.top ?? 0;
70945
+ const height = Math.max(topMargin - headerMargin, 1);
70946
+ return { x: left2, width, height, offset: headerMargin };
70947
+ } else {
70948
+ const footerMargin = margins.footer ?? 0;
70949
+ const bottomMargin = margins.bottom ?? DEFAULT_MARGINS.bottom ?? 0;
70950
+ const height = Math.max(bottomMargin - footerMargin, 1);
70951
+ const offset2 = Math.max(0, totalHeight - footerMargin - height);
70952
+ return { x: left2, width, height, offset: offset2 };
70953
+ }
70598
70954
  };
70599
70955
  rebuildHeaderFooterRegions_fn = function(layout) {
70600
70956
  __privateGet$1(this, _headerRegions).clear();
@@ -70811,7 +71167,8 @@ getHeaderFooterPageHeight_fn = function() {
70811
71167
  return context.layout.pageSize?.h ?? context.region.height ?? 1;
70812
71168
  };
70813
71169
  renderSelectionRects_fn = function(rects) {
70814
- if (!__privateGet$1(this, _selectionOverlay)) {
71170
+ const localSelectionLayer = __privateGet$1(this, _localSelectionLayer);
71171
+ if (!localSelectionLayer) {
70815
71172
  return;
70816
71173
  }
70817
71174
  const pageHeight = __privateMethod$1(this, _PresentationEditor_instances, getBodyPageHeight_fn).call(this);
@@ -70822,7 +71179,7 @@ renderSelectionRects_fn = function(rects) {
70822
71179
  if (!coords) {
70823
71180
  return;
70824
71181
  }
70825
- const highlight = __privateGet$1(this, _selectionOverlay).ownerDocument?.createElement("div");
71182
+ const highlight = localSelectionLayer.ownerDocument?.createElement("div");
70826
71183
  if (!highlight) {
70827
71184
  return;
70828
71185
  }
@@ -70835,7 +71192,7 @@ renderSelectionRects_fn = function(rects) {
70835
71192
  highlight.style.backgroundColor = "rgba(51, 132, 255, 0.35)";
70836
71193
  highlight.style.borderRadius = "2px";
70837
71194
  highlight.style.pointerEvents = "none";
70838
- __privateGet$1(this, _selectionOverlay).appendChild(highlight);
71195
+ localSelectionLayer.appendChild(highlight);
70839
71196
  });
70840
71197
  };
70841
71198
  renderHoverRegion_fn = function(region) {
@@ -71285,6 +71642,7 @@ class PresentationInputBridge {
71285
71642
  __privateAdd$1(this, _onTargetChanged);
71286
71643
  __privateAdd$1(this, _listeners);
71287
71644
  __privateAdd$1(this, _currentTarget, null);
71645
+ __privateAdd$1(this, _destroyed, false);
71288
71646
  __privateSet(this, _windowRoot, windowRoot);
71289
71647
  __privateSet(this, _visibleHost2, visibleHost);
71290
71648
  __privateSet(this, _getTargetDom, getTargetDom);
@@ -71312,9 +71670,13 @@ class PresentationInputBridge {
71312
71670
  });
71313
71671
  __privateSet(this, _listeners, []);
71314
71672
  __privateSet(this, _currentTarget, null);
71673
+ __privateSet(this, _destroyed, true);
71315
71674
  }
71316
71675
  notifyTargetChanged() {
71317
71676
  var _a2;
71677
+ if (__privateGet$1(this, _destroyed)) {
71678
+ return;
71679
+ }
71318
71680
  const nextTarget = __privateGet$1(this, _getTargetDom).call(this);
71319
71681
  if (nextTarget === __privateGet$1(this, _currentTarget)) {
71320
71682
  return;
@@ -71344,6 +71706,7 @@ _getTargetDom = /* @__PURE__ */ new WeakMap();
71344
71706
  _onTargetChanged = /* @__PURE__ */ new WeakMap();
71345
71707
  _listeners = /* @__PURE__ */ new WeakMap();
71346
71708
  _currentTarget = /* @__PURE__ */ new WeakMap();
71709
+ _destroyed = /* @__PURE__ */ new WeakMap();
71347
71710
  _PresentationInputBridge_instances = /* @__PURE__ */ new WeakSet();
71348
71711
  addListener_fn = function(type2, handler2, target) {
71349
71712
  const bound = handler2.bind(this);
@@ -71351,12 +71714,21 @@ addListener_fn = function(type2, handler2, target) {
71351
71714
  target.addEventListener(type2, bound, true);
71352
71715
  };
71353
71716
  dispatchToTarget_fn = function(originalEvent, synthetic) {
71717
+ if (__privateGet$1(this, _destroyed)) return;
71354
71718
  const target = __privateGet$1(this, _getTargetDom).call(this);
71355
71719
  __privateSet(this, _currentTarget, target);
71356
71720
  if (!target) return;
71357
- const canceled = !target.dispatchEvent(synthetic) || synthetic.defaultPrevented;
71358
- if (canceled) {
71359
- originalEvent.preventDefault();
71721
+ const isConnected = target.isConnected;
71722
+ if (isConnected === false) return;
71723
+ try {
71724
+ const canceled = !target.dispatchEvent(synthetic) || synthetic.defaultPrevented;
71725
+ if (canceled) {
71726
+ originalEvent.preventDefault();
71727
+ }
71728
+ } catch (error) {
71729
+ if (process$1$1.env.NODE_ENV === "development") {
71730
+ console.warn("[PresentationEditor] Failed to dispatch event to target:", error);
71731
+ }
71360
71732
  }
71361
71733
  };
71362
71734
  forwardKeyboardEvent_fn = function(event) {
@@ -100246,7 +100618,7 @@ var __accessCheck = (obj, member, msg2) => member.has(obj) || __typeError("Canno
100246
100618
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
100247
100619
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
100248
100620
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
100249
- var _SuperToolbar_instances, initToolbarGroups_fn, _interceptedCommands, makeToolbarItems_fn, initDefaultFonts_fn, updateHighlightColors_fn, deactivateAll_fn, updateToolbarHistory_fn, enrichTrackedChanges_fn, runCommandWithArgumentOnly_fn;
100621
+ var _MARK_TOGGLE_NAMES, _SuperToolbar_instances, initToolbarGroups_fn, _interceptedCommands, makeToolbarItems_fn, initDefaultFonts_fn, updateHighlightColors_fn, deactivateAll_fn, updateToolbarHistory_fn, enrichTrackedChanges_fn, runCommandWithArgumentOnly_fn, syncStickyMarksFromState_fn, restoreStickyMarksIfNeeded_fn, ensureStoredMarksForMarkToggle_fn;
100250
100622
  var eventemitter3 = { exports: {} };
100251
100623
  var hasRequiredEventemitter3;
100252
100624
  function requireEventemitter3() {
@@ -100465,7 +100837,7 @@ const useToolbarItem = (options) => {
100465
100837
  if (!Array.isArray(options.options)) throw new Error("Invalid toolbar item options - " + options.options);
100466
100838
  nestedOptions.value?.push(...options.options);
100467
100839
  }
100468
- const activate = (attrs, ...args) => {
100840
+ const activate = (attrs = {}, ...args) => {
100469
100841
  onActivate(attrs, ...args);
100470
100842
  if (suppressActiveHighlight.value) return;
100471
100843
  active.value = true;
@@ -102737,7 +103109,7 @@ const isNegatedMark = (name, attrs = {}) => {
102737
103109
  if (typeof checker !== "function") return false;
102738
103110
  return Boolean(checker(attrs));
102739
103111
  };
102740
- class SuperToolbar extends EventEmitter2 {
103112
+ const _SuperToolbar = class _SuperToolbar2 extends EventEmitter2 {
102741
103113
  /**
102742
103114
  * Creates a new SuperToolbar instance
102743
103115
  * @param {ToolbarConfig} config - The configuration for the toolbar
@@ -102781,11 +103153,11 @@ class SuperToolbar extends EventEmitter2 {
102781
103153
  const isSmallScreen = window.matchMedia("(max-width: 834px)").matches;
102782
103154
  if (isMobileDevice && isSmallScreen) {
102783
103155
  layers.style.transformOrigin = "0 0";
102784
- layers.style.transform = `scale(${parseInt(argument) / 100})`;
103156
+ layers.style.transform = `scale(${parseInt(argument, 10) / 100})`;
102785
103157
  } else {
102786
- layers.style.zoom = parseInt(argument) / 100;
103158
+ layers.style.zoom = parseInt(argument, 10) / 100;
102787
103159
  }
102788
- this.superdoc.superdocStore.activeZoom = parseInt(argument);
103160
+ this.superdoc.superdocStore.activeZoom = parseInt(argument, 10);
102789
103161
  },
102790
103162
  /**
102791
103163
  * Sets the document mode
@@ -102867,31 +103239,37 @@ class SuperToolbar extends EventEmitter2 {
102867
103239
  * @returns {Promise<void>}
102868
103240
  */
102869
103241
  startImageUpload: async () => {
102870
- let open = getFileOpener();
102871
- let result = await open();
102872
- if (!result?.file) {
102873
- return;
102874
- }
102875
- const { size: size2, file } = await checkAndProcessImage({
102876
- file: result.file,
102877
- getMaxContentSize: () => this.activeEditor.getMaxContentSize()
102878
- });
102879
- if (!file) {
102880
- return;
103242
+ try {
103243
+ let open = getFileOpener();
103244
+ let result = await open();
103245
+ if (!result?.file) {
103246
+ return;
103247
+ }
103248
+ const { size: size2, file } = await checkAndProcessImage({
103249
+ file: result.file,
103250
+ getMaxContentSize: () => this.activeEditor.getMaxContentSize()
103251
+ });
103252
+ if (!file) {
103253
+ return;
103254
+ }
103255
+ const id = {};
103256
+ replaceSelectionWithImagePlaceholder({
103257
+ view: this.activeEditor.view,
103258
+ editorOptions: this.activeEditor.options,
103259
+ id
103260
+ });
103261
+ await uploadAndInsertImage({
103262
+ editor: this.activeEditor,
103263
+ view: this.activeEditor.view,
103264
+ file,
103265
+ size: size2,
103266
+ id
103267
+ });
103268
+ } catch (error) {
103269
+ const err = new Error("[super-toolbar 🎨] Image upload failed");
103270
+ this.emit("exception", { error: err, editor: this.activeEditor, originalError: error });
103271
+ console.error(err, error);
102881
103272
  }
102882
- const id = {};
102883
- replaceSelectionWithImagePlaceholder({
102884
- view: this.activeEditor.view,
102885
- editorOptions: this.activeEditor.options,
102886
- id
102887
- });
102888
- await uploadAndInsertImage({
102889
- editor: this.activeEditor,
102890
- view: this.activeEditor.view,
102891
- file,
102892
- size: size2,
102893
- id
102894
- });
102895
103273
  },
102896
103274
  /**
102897
103275
  * Increases text indentation or list level
@@ -103060,6 +103438,13 @@ class SuperToolbar extends EventEmitter2 {
103060
103438
  };
103061
103439
  this.config.hideButtons = config2.hideButtons ?? true;
103062
103440
  this.config.responsiveToContainer = config2.responsiveToContainer ?? false;
103441
+ this.pendingMarkCommands = [];
103442
+ this.stickyStoredMarks = null;
103443
+ this._boundEditorHandlers = {
103444
+ transaction: null,
103445
+ selectionUpdate: null,
103446
+ focus: null
103447
+ };
103063
103448
  if (!this.config.selector && this.config.element) {
103064
103449
  this.config.selector = this.config.element;
103065
103450
  }
@@ -103119,12 +103504,28 @@ class SuperToolbar extends EventEmitter2 {
103119
103504
  }
103120
103505
  /**
103121
103506
  * The toolbar expects an active Super Editor instance.
103122
- * @param {Object} editor - The editor instance to attach to the toolbar
103507
+ * Removes listeners from the previous editor (if any) before attaching to the new one.
103508
+ * @param {Object|null} editor - The editor instance to attach to the toolbar, or null to detach
103123
103509
  * @returns {void}
103124
103510
  */
103125
103511
  setActiveEditor(editor) {
103512
+ if (this.activeEditor && this._boundEditorHandlers.transaction) {
103513
+ this.activeEditor.off("transaction", this._boundEditorHandlers.transaction);
103514
+ this.activeEditor.off("selectionUpdate", this._boundEditorHandlers.selectionUpdate);
103515
+ this.activeEditor.off("focus", this._boundEditorHandlers.focus);
103516
+ this._boundEditorHandlers.transaction = null;
103517
+ this._boundEditorHandlers.selectionUpdate = null;
103518
+ this._boundEditorHandlers.focus = null;
103519
+ }
103126
103520
  this.activeEditor = editor;
103127
- this.activeEditor.on("transaction", this.onEditorTransaction.bind(this));
103521
+ if (editor) {
103522
+ this._boundEditorHandlers.transaction = this.onEditorTransaction.bind(this);
103523
+ this._boundEditorHandlers.selectionUpdate = this.onEditorSelectionUpdate.bind(this);
103524
+ this._boundEditorHandlers.focus = this.onEditorFocus.bind(this);
103525
+ this.activeEditor.on("transaction", this._boundEditorHandlers.transaction);
103526
+ this.activeEditor.on("selectionUpdate", this._boundEditorHandlers.selectionUpdate);
103527
+ this.activeEditor.on("focus", this._boundEditorHandlers.focus);
103528
+ }
103128
103529
  }
103129
103530
  /**
103130
103531
  * Get toolbar items by group name
@@ -103272,15 +103673,28 @@ class SuperToolbar extends EventEmitter2 {
103272
103673
  * @returns {*} The result of the executed command, undefined if no result is returned
103273
103674
  */
103274
103675
  emitCommand({ item, argument, option }) {
103676
+ const hasFocusFn = this.activeEditor?.view?.hasFocus;
103677
+ const wasFocused = Boolean(typeof hasFocusFn === "function" && hasFocusFn.call(this.activeEditor.view));
103678
+ const { command: command2 } = item;
103679
+ const isMarkToggle = this.isMarkToggle(item);
103680
+ if (!wasFocused && isMarkToggle) {
103681
+ this.pendingMarkCommands.push({ command: command2, argument, item });
103682
+ item?.activate?.();
103683
+ if (this.activeEditor && !this.activeEditor.options.isHeaderOrFooter) {
103684
+ this.activeEditor.focus();
103685
+ }
103686
+ return;
103687
+ }
103275
103688
  if (this.activeEditor && !this.activeEditor.options.isHeaderOrFooter) {
103276
103689
  this.activeEditor.focus();
103277
103690
  }
103278
- const { command: command2 } = item;
103279
103691
  if (!command2) {
103280
103692
  return;
103281
103693
  }
103282
103694
  if (command2 in __privateGet(this, _interceptedCommands)) {
103283
- return __privateGet(this, _interceptedCommands)[command2]({ item, argument });
103695
+ const result = __privateGet(this, _interceptedCommands)[command2]({ item, argument });
103696
+ if (isMarkToggle) __privateMethod(this, _SuperToolbar_instances, syncStickyMarksFromState_fn).call(this);
103697
+ return result;
103284
103698
  }
103285
103699
  if (this.activeEditor && this.activeEditor.commands && command2 in this.activeEditor.commands) {
103286
103700
  this.activeEditor.commands[command2](argument);
@@ -103291,9 +103705,67 @@ class SuperToolbar extends EventEmitter2 {
103291
103705
  this.emit("exception", { error, editor: this.activeEditor });
103292
103706
  throw error;
103293
103707
  }
103708
+ if (isMarkToggle) __privateMethod(this, _SuperToolbar_instances, syncStickyMarksFromState_fn).call(this);
103294
103709
  this.updateToolbarState();
103295
103710
  }
103296
- }
103711
+ /**
103712
+ * Processes and executes pending mark commands when editor selection updates.
103713
+ * This is triggered by the editor's 'selectionUpdate' event after focus is restored.
103714
+ * Clears the pending queue after execution.
103715
+ * @returns {void}
103716
+ */
103717
+ onEditorSelectionUpdate() {
103718
+ if (!this.activeEditor) return;
103719
+ if (this.pendingMarkCommands.length) {
103720
+ const pending = this.pendingMarkCommands;
103721
+ this.pendingMarkCommands = [];
103722
+ pending.forEach(({ command: command2, argument, item }) => {
103723
+ if (!command2) return;
103724
+ try {
103725
+ if (command2 in __privateGet(this, _interceptedCommands)) {
103726
+ __privateGet(this, _interceptedCommands)[command2]({ item, argument });
103727
+ } else if (this.activeEditor.commands && command2 in this.activeEditor.commands) {
103728
+ this.activeEditor.commands[command2](argument);
103729
+ }
103730
+ __privateMethod(this, _SuperToolbar_instances, ensureStoredMarksForMarkToggle_fn).call(this, { command: command2, argument });
103731
+ } catch (error) {
103732
+ const err = new Error(`[super-toolbar 🎨] Failed to execute pending command: ${command2}`);
103733
+ this.emit("exception", { error: err, editor: this.activeEditor, originalError: error });
103734
+ console.error(err, error);
103735
+ }
103736
+ });
103737
+ __privateMethod(this, _SuperToolbar_instances, syncStickyMarksFromState_fn).call(this);
103738
+ this.updateToolbarState();
103739
+ return;
103740
+ }
103741
+ const restored = __privateMethod(this, _SuperToolbar_instances, restoreStickyMarksIfNeeded_fn).call(this);
103742
+ if (restored) this.updateToolbarState();
103743
+ }
103744
+ /**
103745
+ * Handles editor focus events by flushing any pending mark commands.
103746
+ * This is triggered by the editor's 'focus' event.
103747
+ * @returns {void}
103748
+ */
103749
+ onEditorFocus() {
103750
+ if (this.pendingMarkCommands.length) {
103751
+ this.onEditorSelectionUpdate();
103752
+ return;
103753
+ }
103754
+ const restored = __privateMethod(this, _SuperToolbar_instances, restoreStickyMarksIfNeeded_fn).call(this);
103755
+ if (restored) this.updateToolbarState();
103756
+ }
103757
+ /**
103758
+ * Determines if a toolbar item represents a mark toggle command.
103759
+ * Mark toggles include text formatting commands like bold, italic, underline, etc.
103760
+ * @param {ToolbarItem} item - The toolbar item to check
103761
+ * @returns {boolean} True if the item is a mark toggle, false otherwise
103762
+ */
103763
+ isMarkToggle(item) {
103764
+ const name = item?.name?.value;
103765
+ return __privateGet(_SuperToolbar2, _MARK_TOGGLE_NAMES).has(name);
103766
+ }
103767
+ };
103768
+ _MARK_TOGGLE_NAMES = /* @__PURE__ */ new WeakMap();
103297
103769
  _SuperToolbar_instances = /* @__PURE__ */ new WeakSet();
103298
103770
  initToolbarGroups_fn = function() {
103299
103771
  if (this.config.groups && !Array.isArray(this.config.groups) && Object.keys(this.config.groups).length) {
@@ -103406,6 +103878,55 @@ runCommandWithArgumentOnly_fn = function({ item, argument, noArgumentCallback =
103406
103878
  this.updateToolbarState();
103407
103879
  }
103408
103880
  };
103881
+ syncStickyMarksFromState_fn = function() {
103882
+ if (!this.activeEditor) return;
103883
+ const { selection, storedMarks } = this.activeEditor.state || {};
103884
+ if (!selection?.empty) return;
103885
+ this.stickyStoredMarks = storedMarks?.length ? [...storedMarks] : null;
103886
+ };
103887
+ restoreStickyMarksIfNeeded_fn = function() {
103888
+ if (!this.activeEditor) return false;
103889
+ if (!this.stickyStoredMarks?.length) return false;
103890
+ const { state: state2, view } = this.activeEditor;
103891
+ const { selection, storedMarks } = state2 || {};
103892
+ if (!selection?.empty) return false;
103893
+ if (storedMarks?.length) return false;
103894
+ if (!view?.dispatch || !state2?.tr) return false;
103895
+ const hasActiveMarkToggle = getActiveFormatting(this.activeEditor).some(
103896
+ (mark) => __privateGet(_SuperToolbar, _MARK_TOGGLE_NAMES).has(mark.name)
103897
+ );
103898
+ if (hasActiveMarkToggle) return false;
103899
+ const tr = state2.tr.setStoredMarks(this.stickyStoredMarks);
103900
+ view.dispatch(tr);
103901
+ return true;
103902
+ };
103903
+ ensureStoredMarksForMarkToggle_fn = function({ command: command2, argument }) {
103904
+ if (!this.activeEditor) return;
103905
+ if (!this.activeEditor.state?.selection?.empty) return;
103906
+ if (this.activeEditor.state?.storedMarks?.length) return;
103907
+ if (command2 !== "setFontSize") return;
103908
+ const { state: state2, view } = this.activeEditor;
103909
+ const textStyleMark = state2.schema?.marks?.textStyle;
103910
+ if (!textStyleMark || !view?.dispatch || !state2?.tr) return;
103911
+ const [value, unit] = parseSizeUnit(argument ?? "");
103912
+ if (Number.isNaN(value)) return;
103913
+ const clamped = Math.min(96, Math.max(8, Number(value)));
103914
+ const resolvedUnit = unit || "pt";
103915
+ const mark = textStyleMark.create({ fontSize: `${clamped}${resolvedUnit}` });
103916
+ const tr = state2.tr.setStoredMarks([mark]);
103917
+ view.dispatch(tr);
103918
+ };
103919
+ __privateAdd(_SuperToolbar, _MARK_TOGGLE_NAMES, /* @__PURE__ */ new Set([
103920
+ "bold",
103921
+ "italic",
103922
+ "underline",
103923
+ "strike",
103924
+ "highlight",
103925
+ "color",
103926
+ "fontSize",
103927
+ "fontFamily"
103928
+ ]));
103929
+ let SuperToolbar = _SuperToolbar;
103409
103930
  const onMarginClickCursorChange = (event, editor) => {
103410
103931
  const y2 = event.clientY;
103411
103932
  const x2 = event.clientX;