oasis-editor 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { n as normalizeSelection, g as getParagraphs, c as createEditorParagraphFromRuns, a as createEditorStyledRun, b as getParagraphLength, d as getParagraphText, e as getActiveZone, f as getDocumentSections, h as getActiveSectionIndex, p as positionToParagraphOffset, i as paragraphOffsetToPosition, j as clampPosition, k as findParagraphIndex, l as createCollapsedSelection, m as isSelectionCollapsed, o as createEditorParagraph, q as getBlockParagraphs, r as findParagraphTableLocation, s as buildTableCellLayout, t as createEditorTableCell, u as createEditorTable, v as createEditorTableRow, w as underlineStyleToCssDecorationStyle, x as resolveImageSrc, y as createEditorFootnote, z as createFootnoteReferenceRun, A as renumberFootnotes, B as iterateFootnoteReferenceRuns, C as getFootnoteDisplayMarker, D as createSignal, E as createEffect, F as onCleanup, G as buildCanvasLayoutSnapshot, H as on, I as onMount, J as debounce, K as unwrap, L as getDocumentParagraphs, M as getDocumentSectionsCanonical, N as createEditorDocument, O as getPageContentWidth, P as getDocumentPageSettings, Q as getTableCellContentWidthForParagraph, R as resolveResizedDimensions, S as resolveTextBoxRenderHeight, T as resolveEffectiveParagraphStyle, U as resolveEffectiveTextStyleForParagraph, V as iterateEndnoteReferenceRuns, W as JSZip, X as imageContentTypeDefaults, Y as imageExtensionFromMime, Z as pxToPt$1, _ as textStyleToFontSizePt, $ as PX_PER_POINT, a0 as DEFAULT_FONT_SIZE_PX, a1 as isDoubleUnderlineStyle, a2 as isWavyUnderlineStyle, a3 as underlineStyleLineWidthPx, a4 as underlineStyleDashArray, a5 as getListLabelInset, a6 as getParagraphBorderInsets, a7 as buildSegmentTable, a8 as buildCanvasTableLayout, a9 as normalizeFamily, aa as ROBOTO_FONT_FILES, ab as loadFontAsset, ac as OFFICE_COMPAT_FONT_FAMILIES, ad as buildSfnt, ae as defaultFontDecoderRegistry, af as SfntFontProgram, ag as collectPdfFontFamilies, ah as projectDocumentLayout, ai as getPageHeaderZoneTop, aj as getPageBodyTop, ak as findFootnoteReference, al as FOOTNOTE_MARKER_GUTTER_PX, am as resolveImporterForFile, an as createEditorStateFromDocument, ao as getDocumentParagraphsCanonical, ap as getToolbarStyleState, aq as STANDARD_FONT_SIZES_PT, ar as fontSizePxToPt, as as probeLocalFontFamilies, at as createInitialEditorState, au as parseFontSizePtToPx, av as formatFontSizePt, aw as listKindForTag, ax as isParagraphTag, ay as collectInlineRuns, az as parseParagraphStyle, aA as t, aB as preciseFontModeVersion, aC as isPreciseFontModeEnabled, aD as togglePreciseFontMode, aE as createDefaultToolbarPreset, aF as defaultMenuItems, aG as MenuRegistry, aH as createToolbarRegistry, aI as Editor, aJ as resolveCommandRef, aK as commandRefName, aL as InlineShell, aM as BalloonShell, aN as DocumentShell, aO as createMemo, aP as getCaretRectFromSnapshot, aQ as getParagraphRectFromSnapshot, aR as createComponent, aS as CaretOverlay, aT as Show, aU as createRenderEffect, aV as style, aW as setAttribute, aX as setStyleProperty, aY as memo, aZ as template, a_ as insert, a$ as use, b0 as addEventListener, b1 as Dialog, b2 as delegateEvents, b3 as className, b4 as For, b5 as UNDERLINE_STYLE_OPTIONS, b6 as Tabs, b7 as measureParagraphMinContentWidthPx, b8 as getEditableBlocksForZone, b9 as findParagraphLocation, ba as createSectionBoundaryParagraph, bb as normalizePageSettings, bc as DEFAULT_EDITOR_PAGE_SETTINGS, bd as markStart, be as markEnd, bf as getParagraphEntries, bg as getParagraphById, bh as PluginUiHost, bi as OasisEditorEditor, bj as perfTimer, bk as OasisBrandMark, bl as setPreciseFontPreference, bm as setWelcomeSeen, bn as enablePreciseFontMode, bo as createOasisEditorClient, bp as setLocale, bq as startLongTaskObserver, br as installGlobalReport, bs as applyStoredPreciseFontPreference, bt as getWelcomeSeen, bu as isLocalFontAccessSupported, bv as EDITOR_SCROLL_PADDING_PX, bw as Toolbar, bx as OasisEditorLoading, by as createEditorLogger, bz as getCachedCanvasImage, bA as registerDomStatsSurface } from "./index-D1GDOw-0.js";
4
+ import { n as normalizeSelection, g as getParagraphs, c as createEditorParagraphFromRuns, a as createEditorStyledRun, b as getParagraphLength, d as getParagraphText, e as getActiveZone, f as getDocumentSections, h as getActiveSectionIndex, p as positionToParagraphOffset, i as paragraphOffsetToPosition, j as clampPosition, k as findParagraphIndex, l as createCollapsedSelection, m as isSelectionCollapsed, o as createEditorParagraph, q as getBlockParagraphs, r as findParagraphTableLocation, s as buildTableCellLayout, t as createEditorTableCell, u as createEditorTable, v as createEditorTableRow, w as underlineStyleToCssDecorationStyle, x as resolveImageSrc, y as createEditorFootnote, z as createFootnoteReferenceRun, A as renumberFootnotes, B as iterateFootnoteReferenceRuns, C as getFootnoteDisplayMarker, D as createSignal, E as createEffect, F as onCleanup, G as buildCanvasLayoutSnapshot, H as on, I as onMount, J as debounce, K as unwrap, L as getDocumentParagraphs, M as getDocumentSectionsCanonical, N as createEditorDocument, O as getPageContentWidth, P as getDocumentPageSettings, Q as getTableCellContentWidthForParagraph, R as resolveResizedDimensions, S as resolveTextBoxRenderHeight, T as resolveEffectiveParagraphStyle, U as resolveEffectiveTextStyleForParagraph, V as iterateEndnoteReferenceRuns, W as JSZip, X as imageContentTypeDefaults, Y as imageExtensionFromMime, Z as pxToPt$1, _ as buildSegmentTable, $ as buildCanvasTableLayout, a0 as resolveFloatingObjectRect, a1 as getTextBoxFloatingGeometry, a2 as getPresetPathSegments, a3 as projectBlocksLayout, a4 as textStyleToFontSizePt, a5 as PX_PER_POINT, a6 as DEFAULT_FONT_SIZE_PX, a7 as isDoubleUnderlineStyle, a8 as isWavyUnderlineStyle, a9 as underlineStyleLineWidthPx, aa as underlineStyleDashArray, ab as getListLabelInset, ac as getParagraphBorderInsets, ad as normalizeFamily, ae as ROBOTO_FONT_FILES, af as loadFontAsset, ag as OFFICE_COMPAT_FONT_FAMILIES, ah as buildSfnt, ai as defaultFontDecoderRegistry, aj as SfntFontProgram, ak as collectPdfFontFamilies, al as projectDocumentLayout, am as getPageHeaderZoneTop, an as getPageBodyTop, ao as findFootnoteReference, ap as FOOTNOTE_MARKER_GUTTER_PX, aq as resolveImporterForFile, ar as createEditorStateFromDocument, as as getDocumentParagraphsCanonical, at as getToolbarStyleState, au as STANDARD_FONT_SIZES_PT, av as fontSizePxToPt, aw as probeLocalFontFamilies, ax as createInitialEditorState, ay as parseFontSizePtToPx, az as formatFontSizePt, aA as listKindForTag, aB as isParagraphTag, aC as collectInlineRuns, aD as parseParagraphStyle, aE as t, aF as preciseFontModeVersion, aG as isPreciseFontModeEnabled, aH as togglePreciseFontMode, aI as nextFontSizePt, aJ as previousFontSizePt, aK as fontSizePtToPx, aL as createDefaultToolbarPreset, aM as defaultMenuItems, aN as MenuRegistry, aO as createToolbarRegistry, aP as Editor, aQ as resolveCommandRef, aR as commandRefName, aS as InlineShell, aT as BalloonShell, aU as DocumentShell, aV as createMemo, aW as getCaretRectFromSnapshot, aX as getParagraphRectFromSnapshot, aY as createComponent, aZ as CaretOverlay, a_ as Show, a$ as createRenderEffect, b0 as style, b1 as setAttribute, b2 as setStyleProperty, b3 as memo, b4 as template, b5 as insert, b6 as use, b7 as addEventListener, b8 as Dialog, b9 as delegateEvents, ba as className, bb as For, bc as UNDERLINE_STYLE_OPTIONS, bd as Tabs, be as measureParagraphMinContentWidthPx, bf as getEditableBlocksForZone, bg as findParagraphLocation, bh as createSectionBoundaryParagraph, bi as normalizePageSettings, bj as DEFAULT_EDITOR_PAGE_SETTINGS, bk as markStart, bl as markEnd, bm as getParagraphEntries, bn as getParagraphById, bo as PluginUiHost, bp as OasisEditorEditor, bq as perfTimer, br as OasisBrandMark, bs as setPreciseFontPreference, bt as setWelcomeSeen, bu as enablePreciseFontMode, bv as createOasisEditorClient, bw as setLocale, bx as startLongTaskObserver, by as installGlobalReport, bz as applyStoredPreciseFontPreference, bA as getWelcomeSeen, bB as isLocalFontAccessSupported, bC as EDITOR_SCROLL_PADDING_PX, bD as Toolbar, bE as OasisEditorLoading, bF as createEditorLogger, bG as getCachedCanvasImage, bH as registerDomStatsSurface } from "./index-L71R0x7D.js";
5
5
  function getSelectedObjectRun(state, predicate) {
6
6
  const normalized = normalizeSelection(state);
7
7
  if (normalized.isCollapsed || normalized.startIndex !== normalized.endIndex || normalized.endParagraphOffset - normalized.startParagraphOffset !== 1) {
@@ -1240,6 +1240,43 @@ function resizeSelectedTextBox(state, width, height, options = {}) {
1240
1240
  )
1241
1241
  );
1242
1242
  }
1243
+ const SHAPE_DEFAULT_WIDTH = 150;
1244
+ const SHAPE_DEFAULT_HEIGHT = 100;
1245
+ const SHAPE_DEFAULT_FILL = "#4472C4";
1246
+ const SHAPE_DEFAULT_BORDER_COLOR = "#2F528F";
1247
+ const SHAPE_DEFAULT_BORDER_WIDTH_PT = 1;
1248
+ function insertShapeAtSelection(state, preset) {
1249
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
1250
+ const { paragraph, index, offset } = getFocusParagraph(collapsedState);
1251
+ const textBox = {
1252
+ width: SHAPE_DEFAULT_WIDTH,
1253
+ height: SHAPE_DEFAULT_HEIGHT,
1254
+ blocks: [createEditorParagraph("")],
1255
+ shape: {
1256
+ preset,
1257
+ fill: SHAPE_DEFAULT_FILL,
1258
+ borderColor: SHAPE_DEFAULT_BORDER_COLOR,
1259
+ borderWidthPt: SHAPE_DEFAULT_BORDER_WIDTH_PT
1260
+ },
1261
+ floating: wrapPresetToFloating(void 0, "front")
1262
+ };
1263
+ const insertedRun = createEditorStyledRun(
1264
+ "",
1265
+ getStyleAtOffset(paragraph, offset),
1266
+ void 0,
1267
+ textBox
1268
+ );
1269
+ const nextParagraph = insertRunsAtOffset(paragraph, offset, [insertedRun]);
1270
+ const paragraphs = getParagraphs(collapsedState);
1271
+ const nextParagraphs = paragraphs.map(
1272
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : cloneParagraph(candidate)
1273
+ );
1274
+ return cloneStateWithParagraphs(
1275
+ collapsedState,
1276
+ nextParagraphs,
1277
+ withSelection(paragraphOffsetToPosition(nextParagraph, offset + 1))
1278
+ );
1279
+ }
1243
1280
  function cloneFragmentRuns(runs) {
1244
1281
  return runs.map(cloneRun);
1245
1282
  }
@@ -1739,6 +1776,121 @@ function toggleTextStyle(state, key) {
1739
1776
  preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
1740
1777
  );
1741
1778
  }
1779
+ function isLetter(char) {
1780
+ return new RegExp("\\p{L}", "u").test(char);
1781
+ }
1782
+ function toSentenceCase(text) {
1783
+ let result = "";
1784
+ let capitalizeNext = true;
1785
+ for (const char of text.toLowerCase()) {
1786
+ if (capitalizeNext && isLetter(char)) {
1787
+ result += char.toUpperCase();
1788
+ capitalizeNext = false;
1789
+ } else {
1790
+ result += char;
1791
+ if (char === "." || char === "!" || char === "?") {
1792
+ capitalizeNext = true;
1793
+ }
1794
+ }
1795
+ }
1796
+ return result;
1797
+ }
1798
+ function toCapitalizedWords(text) {
1799
+ let result = "";
1800
+ let prevIsLetter = false;
1801
+ for (const char of text) {
1802
+ const letter = isLetter(char);
1803
+ result += letter && !prevIsLetter ? char.toUpperCase() : char;
1804
+ prevIsLetter = letter;
1805
+ }
1806
+ return result;
1807
+ }
1808
+ function toToggledCase(text) {
1809
+ let result = "";
1810
+ for (const char of text) {
1811
+ const upper = char.toUpperCase();
1812
+ const lower = char.toLowerCase();
1813
+ if (char === lower && char !== upper) {
1814
+ result += upper;
1815
+ } else if (char === upper && char !== lower) {
1816
+ result += lower;
1817
+ } else {
1818
+ result += char;
1819
+ }
1820
+ }
1821
+ return result;
1822
+ }
1823
+ function applyCaseTransform(text, mode) {
1824
+ switch (mode) {
1825
+ case "lower":
1826
+ return text.toLowerCase();
1827
+ case "upper":
1828
+ return text.toUpperCase();
1829
+ case "capitalize":
1830
+ return toCapitalizedWords(text);
1831
+ case "toggle":
1832
+ return toToggledCase(text);
1833
+ case "sentence":
1834
+ default:
1835
+ return toSentenceCase(text);
1836
+ }
1837
+ }
1838
+ function transformSelectedText(state, transform) {
1839
+ const normalized = normalizeSelection(state);
1840
+ if (normalized.isCollapsed) {
1841
+ return state;
1842
+ }
1843
+ const paragraphs = getParagraphs(state);
1844
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
1845
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
1846
+ return paragraph;
1847
+ }
1848
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
1849
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
1850
+ const selectedText = sliceRuns(paragraph, startOffset, endOffset).map((run) => run.text).join("");
1851
+ const transformed = transform(selectedText);
1852
+ let cursor = 0;
1853
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
1854
+ const length = run.text.length;
1855
+ const nextText = transformed.slice(cursor, cursor + length);
1856
+ cursor += length;
1857
+ return { ...run, text: nextText };
1858
+ });
1859
+ });
1860
+ return cloneStateWithParagraphs(
1861
+ state,
1862
+ nextParagraphs,
1863
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
1864
+ );
1865
+ }
1866
+ function changeSelectedTextCase(state, mode) {
1867
+ return transformSelectedText(state, (text) => applyCaseTransform(text, mode));
1868
+ }
1869
+ function clearSelectedTextFormatting(state) {
1870
+ const normalized = normalizeSelection(state);
1871
+ if (normalized.isCollapsed) {
1872
+ return state;
1873
+ }
1874
+ const paragraphs = getParagraphs(state);
1875
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
1876
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
1877
+ return paragraph;
1878
+ }
1879
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
1880
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
1881
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
1882
+ var _a;
1883
+ const link = (_a = run.styles) == null ? void 0 : _a.link;
1884
+ const styles = link != null && link !== "" ? { link } : {};
1885
+ return { ...run, styles };
1886
+ });
1887
+ });
1888
+ return cloneStateWithParagraphs(
1889
+ state,
1890
+ nextParagraphs,
1891
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
1892
+ );
1893
+ }
1742
1894
  function setTextStyleValue(state, key, value) {
1743
1895
  const normalized = normalizeSelection(state);
1744
1896
  if (normalized.isCollapsed) {
@@ -3934,6 +4086,28 @@ function createEditorCommandsController(deps) {
3934
4086
  );
3935
4087
  focusInput();
3936
4088
  };
4089
+ const applyChangeTextCaseCommand = (mode) => {
4090
+ if (selectionCollapsed()) {
4091
+ return;
4092
+ }
4093
+ clearPreferredColumn();
4094
+ resetTransactionGrouping();
4095
+ applySelectionAwareTextCommand(
4096
+ (current) => changeSelectedTextCase(current, mode)
4097
+ );
4098
+ focusInput();
4099
+ };
4100
+ const applyClearFormattingCommand = () => {
4101
+ if (selectionCollapsed()) {
4102
+ return;
4103
+ }
4104
+ clearPreferredColumn();
4105
+ resetTransactionGrouping();
4106
+ applySelectionAwareTextCommand(
4107
+ (current) => clearSelectedTextFormatting(current)
4108
+ );
4109
+ focusInput();
4110
+ };
3937
4111
  const applyParagraphStyleCommand = (key, value) => {
3938
4112
  clearPreferredColumn();
3939
4113
  resetTransactionGrouping();
@@ -4083,6 +4257,8 @@ function createEditorCommandsController(deps) {
4083
4257
  return {
4084
4258
  applyBooleanStyleCommand,
4085
4259
  applyValueStyleCommand,
4260
+ applyChangeTextCaseCommand,
4261
+ applyClearFormattingCommand,
4086
4262
  applyParagraphStyleCommand,
4087
4263
  toggleParagraphFlagCommand,
4088
4264
  applyParagraphListCommand,
@@ -9495,6 +9671,268 @@ function borderDashArray(type) {
9495
9671
  return void 0;
9496
9672
  }
9497
9673
  }
9674
+ function drawCellEdge(writer, pageIndex, border, x1, y1, x2, y2) {
9675
+ if (border.type === "none" || border.width <= 0) {
9676
+ return;
9677
+ }
9678
+ writer.drawLine(pageIndex, {
9679
+ x1: pxToPt$1(x1),
9680
+ y1: pxToPt$1(y1),
9681
+ x2: pxToPt$1(x2),
9682
+ y2: pxToPt$1(y2),
9683
+ stroke: border.color,
9684
+ lineWidth: pxToPt$1(border.width),
9685
+ dashArray: borderDashArray(border.type)
9686
+ });
9687
+ }
9688
+ function drawCellBorders(writer, pageIndex, cell, originX, originY) {
9689
+ const left = originX + cell.left;
9690
+ const top = originY + cell.top;
9691
+ const right = left + cell.width;
9692
+ const bottom = top + cell.height;
9693
+ drawCellEdge(writer, pageIndex, cell.borders.top, left, top, right, top);
9694
+ drawCellEdge(
9695
+ writer,
9696
+ pageIndex,
9697
+ cell.borders.right,
9698
+ right,
9699
+ top,
9700
+ right,
9701
+ bottom
9702
+ );
9703
+ drawCellEdge(
9704
+ writer,
9705
+ pageIndex,
9706
+ cell.borders.bottom,
9707
+ left,
9708
+ bottom,
9709
+ right,
9710
+ bottom
9711
+ );
9712
+ drawCellEdge(writer, pageIndex, cell.borders.left, left, top, left, bottom);
9713
+ }
9714
+ async function drawTableBlock(writer, pageIndex, block, document2, originX, originY, contentWidth, fontRegistry, listOrdinals) {
9715
+ if (block.sourceBlock.type !== "table") {
9716
+ return;
9717
+ }
9718
+ const sourceTable = block.sourceBlock;
9719
+ const segmentTable = block.tableSegment ? buildSegmentTable(sourceTable, block.tableSegment) : sourceTable;
9720
+ if (segmentTable.rows.length === 0) {
9721
+ return;
9722
+ }
9723
+ const stateStub = { document: document2 };
9724
+ const tableLayout = buildCanvasTableLayout({
9725
+ table: segmentTable,
9726
+ state: stateStub,
9727
+ pageIndex: 0,
9728
+ originX: 0,
9729
+ originY: 0,
9730
+ contentWidth,
9731
+ estimatedHeight: block.estimatedHeight
9732
+ });
9733
+ for (const cell of tableLayout.cells) {
9734
+ if (!cell.shading) continue;
9735
+ writer.drawRect(pageIndex, {
9736
+ x: pxToPt$1(originX + cell.left),
9737
+ y: pxToPt$1(originY + cell.top),
9738
+ width: pxToPt$1(cell.width),
9739
+ height: pxToPt$1(cell.height),
9740
+ fill: cell.shading
9741
+ });
9742
+ }
9743
+ for (const cell of tableLayout.cells) {
9744
+ drawCellBorders(writer, pageIndex, cell, originX, originY);
9745
+ }
9746
+ for (const cell of tableLayout.cells) {
9747
+ for (const paragraphLayout of cell.paragraphs) {
9748
+ await drawParagraph(
9749
+ writer,
9750
+ pageIndex,
9751
+ paragraphLayout.paragraph,
9752
+ paragraphLayout.lines,
9753
+ document2,
9754
+ originX + paragraphLayout.originX,
9755
+ originY + paragraphLayout.originY,
9756
+ fontRegistry,
9757
+ listOrdinals
9758
+ );
9759
+ }
9760
+ }
9761
+ }
9762
+ function getPadding(textBox) {
9763
+ var _a, _b, _c, _d;
9764
+ return {
9765
+ left: ((_a = textBox.body) == null ? void 0 : _a.paddingLeft) ?? 0,
9766
+ top: ((_b = textBox.body) == null ? void 0 : _b.paddingTop) ?? 0,
9767
+ right: ((_c = textBox.body) == null ? void 0 : _c.paddingRight) ?? 0,
9768
+ bottom: ((_d = textBox.body) == null ? void 0 : _d.paddingBottom) ?? 0
9769
+ };
9770
+ }
9771
+ function drawShapeGeometry(writer, pageIndex, textBox, xPx, yPx, widthPx, heightPx) {
9772
+ var _a, _b, _c, _d;
9773
+ const segments = getPresetPathSegments(
9774
+ (_a = textBox.shape) == null ? void 0 : _a.preset,
9775
+ pxToPt$1(xPx),
9776
+ pxToPt$1(yPx),
9777
+ pxToPt$1(widthPx),
9778
+ pxToPt$1(heightPx)
9779
+ );
9780
+ const fill = (_b = textBox.shape) == null ? void 0 : _b.fill;
9781
+ const borderColor = (_c = textBox.shape) == null ? void 0 : _c.borderColor;
9782
+ const borderWidthPt = ((_d = textBox.shape) == null ? void 0 : _d.borderWidthPt) ?? (borderColor ? 0.75 : 0);
9783
+ writer.drawPath(pageIndex, {
9784
+ segments,
9785
+ fill,
9786
+ stroke: borderColor && borderWidthPt > 0 ? borderColor : void 0,
9787
+ lineWidth: borderWidthPt
9788
+ });
9789
+ }
9790
+ async function drawTextBoxContent(writer, textBox, ctx, xPx, yPx, widthPx, heightPx) {
9791
+ var _a;
9792
+ if (textBox.blocks.length === 0) {
9793
+ return;
9794
+ }
9795
+ const padding = getPadding(textBox);
9796
+ const innerX = xPx + padding.left;
9797
+ const innerY = yPx + padding.top;
9798
+ const innerWidth = Math.max(1, widthPx - padding.left - padding.right);
9799
+ const innerHeight = Math.max(1, heightPx - padding.top - padding.bottom);
9800
+ const pages = projectBlocksLayout({
9801
+ blocks: textBox.blocks,
9802
+ pageSettings: {
9803
+ width: innerWidth,
9804
+ height: innerHeight,
9805
+ orientation: "portrait",
9806
+ margins: {
9807
+ top: 0,
9808
+ right: 0,
9809
+ bottom: 0,
9810
+ left: 0,
9811
+ header: 0,
9812
+ footer: 0,
9813
+ gutter: 0
9814
+ }
9815
+ },
9816
+ maxPageHeight: innerHeight,
9817
+ styles: ctx.document.styles,
9818
+ pageOffset: ctx.pageIndex
9819
+ });
9820
+ const blocks = ((_a = pages[0]) == null ? void 0 : _a.blocks) ?? [];
9821
+ if (blocks.length === 0) {
9822
+ return;
9823
+ }
9824
+ const listOrdinals = /* @__PURE__ */ new Map();
9825
+ writer.saveGraphicsState(ctx.pageIndex);
9826
+ writer.clipRect(
9827
+ ctx.pageIndex,
9828
+ pxToPt$1(innerX),
9829
+ pxToPt$1(innerY),
9830
+ pxToPt$1(innerWidth),
9831
+ pxToPt$1(innerHeight)
9832
+ );
9833
+ let cursorY = innerY;
9834
+ for (const block of blocks) {
9835
+ if (block.sourceBlock.type === "paragraph" && block.layout) {
9836
+ await drawParagraph(
9837
+ writer,
9838
+ ctx.pageIndex,
9839
+ block.sourceBlock,
9840
+ block.layout.lines,
9841
+ ctx.document,
9842
+ innerX,
9843
+ cursorY,
9844
+ ctx.fontRegistry,
9845
+ listOrdinals
9846
+ );
9847
+ } else if (block.sourceBlock.type === "table") {
9848
+ await drawTableBlock(
9849
+ writer,
9850
+ ctx.pageIndex,
9851
+ block,
9852
+ ctx.document,
9853
+ innerX,
9854
+ cursorY,
9855
+ innerWidth,
9856
+ ctx.fontRegistry,
9857
+ listOrdinals
9858
+ );
9859
+ }
9860
+ cursorY += Math.max(0, block.estimatedHeight);
9861
+ }
9862
+ writer.restoreGraphicsState(ctx.pageIndex);
9863
+ }
9864
+ async function paintTextBox(writer, textBox, ctx, xPx, yPx, widthPx, heightPx) {
9865
+ const rotation = textBox.rotation;
9866
+ if (rotation) {
9867
+ writer.saveGraphicsState(ctx.pageIndex);
9868
+ writer.rotateAbout(
9869
+ ctx.pageIndex,
9870
+ pxToPt$1(xPx + widthPx / 2),
9871
+ pxToPt$1(yPx + heightPx / 2),
9872
+ rotation
9873
+ );
9874
+ }
9875
+ drawShapeGeometry(
9876
+ writer,
9877
+ ctx.pageIndex,
9878
+ textBox,
9879
+ xPx,
9880
+ yPx,
9881
+ widthPx,
9882
+ heightPx
9883
+ );
9884
+ await drawTextBoxContent(writer, textBox, ctx, xPx, yPx, widthPx, heightPx);
9885
+ if (rotation) {
9886
+ writer.restoreGraphicsState(ctx.pageIndex);
9887
+ }
9888
+ }
9889
+ async function drawFloatingTextBoxesForParagraph(options) {
9890
+ const {
9891
+ writer,
9892
+ document: document2,
9893
+ fontRegistry,
9894
+ pageIndex,
9895
+ lines,
9896
+ pageSettings,
9897
+ contentLeft,
9898
+ contentTop,
9899
+ contentWidth,
9900
+ paragraphTop
9901
+ } = options;
9902
+ for (const line of lines) {
9903
+ const slotByOffset = new Map(
9904
+ line.slots.map((slot) => [slot.offset, slot])
9905
+ );
9906
+ for (const fragment of line.fragments) {
9907
+ const textBox = fragment.textBox;
9908
+ if (!(textBox == null ? void 0 : textBox.floating)) {
9909
+ continue;
9910
+ }
9911
+ const slot = slotByOffset.get(fragment.startOffset);
9912
+ const anchorLeft = contentLeft + ((slot == null ? void 0 : slot.left) ?? 0);
9913
+ const lineTop = paragraphTop + line.top;
9914
+ const rect = resolveFloatingObjectRect({
9915
+ object: getTextBoxFloatingGeometry(textBox),
9916
+ pageSettings,
9917
+ contentLeft,
9918
+ contentTop,
9919
+ contentWidth,
9920
+ paragraphTop,
9921
+ lineTop,
9922
+ anchorLeft
9923
+ });
9924
+ await paintTextBox(
9925
+ writer,
9926
+ textBox,
9927
+ { document: document2, fontRegistry, pageIndex },
9928
+ rect.x,
9929
+ rect.y,
9930
+ rect.width,
9931
+ rect.height
9932
+ );
9933
+ }
9934
+ }
9935
+ }
9498
9936
  const imageResourceCache = /* @__PURE__ */ new WeakMap();
9499
9937
  function parseDataUrl(src) {
9500
9938
  const match = /^data:([^;,]+)(;base64)?,(.*)$/i.exec(src);
@@ -9874,6 +10312,25 @@ function drawTabLeaders(writer, pageIndex, paragraph, line, fragment, document2,
9874
10312
  });
9875
10313
  }
9876
10314
  }
10315
+ async function drawInlineTextBoxFragment(writer, pageIndex, line, fragment, document2, originX, originY, fontRegistry) {
10316
+ const textBox = fragment.textBox;
10317
+ if (!textBox || textBox.floating) {
10318
+ return;
10319
+ }
10320
+ const slot = line.slots.find((candidate) => candidate.offset === fragment.startOffset) ?? line.slots.find((candidate) => candidate.offset >= fragment.startOffset);
10321
+ if (!slot) {
10322
+ return;
10323
+ }
10324
+ await paintTextBox(
10325
+ writer,
10326
+ textBox,
10327
+ { document: document2, fontRegistry, pageIndex },
10328
+ originX + slot.left,
10329
+ originY + line.top + line.height - textBox.height,
10330
+ textBox.width,
10331
+ textBox.height
10332
+ );
10333
+ }
9877
10334
  async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, document2, originX, originY, fontRegistry) {
9878
10335
  var _a;
9879
10336
  if (fragment.image) {
@@ -9901,6 +10358,19 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
9901
10358
  });
9902
10359
  return;
9903
10360
  }
10361
+ if (fragment.textBox) {
10362
+ await drawInlineTextBoxFragment(
10363
+ writer,
10364
+ pageIndex,
10365
+ line,
10366
+ fragment,
10367
+ document2,
10368
+ originX,
10369
+ originY,
10370
+ fontRegistry
10371
+ );
10372
+ return;
10373
+ }
9904
10374
  const styles = resolveEffectiveTextStyleForParagraph(
9905
10375
  fragment.styles,
9906
10376
  (_a = paragraph.style) == null ? void 0 : _a.styleId,
@@ -10246,98 +10716,11 @@ async function drawParagraph(writer, pageIndex, paragraph, lines, document2, ori
10246
10716
  }
10247
10717
  }
10248
10718
  }
10249
- function drawCellEdge(writer, pageIndex, border, x1, y1, x2, y2) {
10250
- if (border.type === "none" || border.width <= 0) {
10251
- return;
10252
- }
10253
- writer.drawLine(pageIndex, {
10254
- x1: pxToPt$1(x1),
10255
- y1: pxToPt$1(y1),
10256
- x2: pxToPt$1(x2),
10257
- y2: pxToPt$1(y2),
10258
- stroke: border.color,
10259
- lineWidth: pxToPt$1(border.width),
10260
- dashArray: borderDashArray(border.type)
10261
- });
10262
- }
10263
- function drawCellBorders(writer, pageIndex, cell, originX, originY) {
10264
- const left = originX + cell.left;
10265
- const top = originY + cell.top;
10266
- const right = left + cell.width;
10267
- const bottom = top + cell.height;
10268
- drawCellEdge(writer, pageIndex, cell.borders.top, left, top, right, top);
10269
- drawCellEdge(
10270
- writer,
10271
- pageIndex,
10272
- cell.borders.right,
10273
- right,
10274
- top,
10275
- right,
10276
- bottom
10277
- );
10278
- drawCellEdge(
10279
- writer,
10280
- pageIndex,
10281
- cell.borders.bottom,
10282
- left,
10283
- bottom,
10284
- right,
10285
- bottom
10286
- );
10287
- drawCellEdge(writer, pageIndex, cell.borders.left, left, top, left, bottom);
10288
- }
10289
- async function drawTableBlock(writer, pageIndex, block, document2, originX, originY, contentWidth, fontRegistry, listOrdinals) {
10290
- if (block.sourceBlock.type !== "table") {
10291
- return;
10292
- }
10293
- const sourceTable = block.sourceBlock;
10294
- const segmentTable = block.tableSegment ? buildSegmentTable(sourceTable, block.tableSegment) : sourceTable;
10295
- if (segmentTable.rows.length === 0) {
10296
- return;
10297
- }
10298
- const stateStub = { document: document2 };
10299
- const tableLayout = buildCanvasTableLayout({
10300
- table: segmentTable,
10301
- state: stateStub,
10302
- pageIndex: 0,
10303
- originX: 0,
10304
- originY: 0,
10305
- contentWidth,
10306
- estimatedHeight: block.estimatedHeight
10307
- });
10308
- for (const cell of tableLayout.cells) {
10309
- if (!cell.shading) continue;
10310
- writer.drawRect(pageIndex, {
10311
- x: pxToPt$1(originX + cell.left),
10312
- y: pxToPt$1(originY + cell.top),
10313
- width: pxToPt$1(cell.width),
10314
- height: pxToPt$1(cell.height),
10315
- fill: cell.shading
10316
- });
10317
- }
10318
- for (const cell of tableLayout.cells) {
10319
- drawCellBorders(writer, pageIndex, cell, originX, originY);
10320
- }
10321
- for (const cell of tableLayout.cells) {
10322
- for (const paragraphLayout of cell.paragraphs) {
10323
- await drawParagraph(
10324
- writer,
10325
- pageIndex,
10326
- paragraphLayout.paragraph,
10327
- paragraphLayout.lines,
10328
- document2,
10329
- originX + paragraphLayout.originX,
10330
- originY + paragraphLayout.originY,
10331
- fontRegistry,
10332
- listOrdinals
10333
- );
10334
- }
10335
- }
10336
- }
10337
- async function drawBlockList(writer, pageIndex, blocks, document2, originX, originY, contentWidth, fontRegistry, listOrdinals) {
10719
+ async function drawBlockList(writer, pageIndex, blocks, document2, originX, originY, contentWidth, fontRegistry, listOrdinals, pageSettings) {
10338
10720
  if (!blocks || blocks.length === 0) {
10339
10721
  return;
10340
10722
  }
10723
+ const contentTop = originY;
10341
10724
  let cursorY = originY;
10342
10725
  for (const block of blocks) {
10343
10726
  if (block.sourceBlock.type === "paragraph" && block.layout) {
@@ -10368,6 +10751,20 @@ async function drawBlockList(writer, pageIndex, blocks, document2, originX, orig
10368
10751
  fontRegistry,
10369
10752
  listOrdinals
10370
10753
  );
10754
+ if (pageSettings) {
10755
+ await drawFloatingTextBoxesForParagraph({
10756
+ writer,
10757
+ document: document2,
10758
+ fontRegistry,
10759
+ pageIndex,
10760
+ lines: block.layout.lines,
10761
+ pageSettings,
10762
+ contentLeft: originX,
10763
+ contentTop,
10764
+ contentWidth,
10765
+ paragraphTop: boxTop
10766
+ });
10767
+ }
10371
10768
  } else if (block.sourceBlock.type === "table") {
10372
10769
  await drawTableBlock(
10373
10770
  writer,
@@ -11068,6 +11465,103 @@ class OasisPdfWriter {
11068
11465
  );
11069
11466
  page.commands.push(commands.join("\n"));
11070
11467
  }
11468
+ // Fills/strokes an arbitrary path. Segment coordinates are in points with a
11469
+ // top-left origin (callers convert px→pt, like drawRect/drawLine); the y axis
11470
+ // is flipped here to the PDF bottom-left origin.
11471
+ drawPath(pageIndex, options) {
11472
+ const page = this.pages[pageIndex];
11473
+ if (!page || options.segments.length === 0) {
11474
+ return;
11475
+ }
11476
+ if (!options.fill && !options.stroke) {
11477
+ return;
11478
+ }
11479
+ const flip = (yy) => page.height - yy;
11480
+ const commands = ["q"];
11481
+ if (options.fill) {
11482
+ commands.push(colorCommand(options.fill, "rg", [1, 1, 1]));
11483
+ }
11484
+ if (options.stroke) {
11485
+ commands.push(colorCommand(options.stroke, "RG", [0, 0, 0]));
11486
+ commands.push(`${formatNumber(options.lineWidth ?? 1)} w`);
11487
+ }
11488
+ for (const segment of options.segments) {
11489
+ switch (segment.type) {
11490
+ case "move":
11491
+ commands.push(
11492
+ `${formatNumber(segment.x)} ${formatNumber(flip(segment.y))} m`
11493
+ );
11494
+ break;
11495
+ case "line":
11496
+ commands.push(
11497
+ `${formatNumber(segment.x)} ${formatNumber(flip(segment.y))} l`
11498
+ );
11499
+ break;
11500
+ case "cubic":
11501
+ commands.push(
11502
+ `${formatNumber(segment.x1)} ${formatNumber(flip(segment.y1))} ${formatNumber(segment.x2)} ${formatNumber(flip(segment.y2))} ${formatNumber(segment.x)} ${formatNumber(flip(segment.y))} c`
11503
+ );
11504
+ break;
11505
+ case "close":
11506
+ commands.push("h");
11507
+ break;
11508
+ }
11509
+ }
11510
+ if (options.fill && options.stroke) {
11511
+ commands.push("B");
11512
+ } else if (options.fill) {
11513
+ commands.push("f");
11514
+ } else {
11515
+ commands.push("S");
11516
+ }
11517
+ commands.push("Q");
11518
+ page.commands.push(commands.join("\n"));
11519
+ }
11520
+ // Saves the graphics state (`q`). Pair with restoreGraphicsState. Any draw
11521
+ // commands emitted in between inherit the current transform/clip.
11522
+ saveGraphicsState(pageIndex) {
11523
+ const page = this.pages[pageIndex];
11524
+ if (page) {
11525
+ page.commands.push("q");
11526
+ }
11527
+ }
11528
+ restoreGraphicsState(pageIndex) {
11529
+ const page = this.pages[pageIndex];
11530
+ if (page) {
11531
+ page.commands.push("Q");
11532
+ }
11533
+ }
11534
+ // Concatenates a clockwise rotation (in degrees, matching the canvas/editor
11535
+ // convention) about a top-left-origin point onto the current CTM. Must sit
11536
+ // inside a saveGraphicsState/restoreGraphicsState pair.
11537
+ rotateAbout(pageIndex, centerX, centerY, degrees) {
11538
+ const page = this.pages[pageIndex];
11539
+ if (!page || !degrees) {
11540
+ return;
11541
+ }
11542
+ const cyf = page.height - centerY;
11543
+ const radians = -degrees * Math.PI / 180;
11544
+ const cos = Math.cos(radians);
11545
+ const sin = Math.sin(radians);
11546
+ const e = centerX - centerX * cos + cyf * sin;
11547
+ const f = cyf - centerX * sin - cyf * cos;
11548
+ page.commands.push(
11549
+ `${formatNumber(cos)} ${formatNumber(sin)} ${formatNumber(-sin)} ${formatNumber(cos)} ${formatNumber(e)} ${formatNumber(f)} cm`
11550
+ );
11551
+ }
11552
+ // Intersects the clip path with a rectangle (top-left origin). Must sit inside
11553
+ // a saveGraphicsState/restoreGraphicsState pair so the clip can be undone.
11554
+ clipRect(pageIndex, x, y, width, height) {
11555
+ const page = this.pages[pageIndex];
11556
+ if (!page || width <= 0 || height <= 0) {
11557
+ return;
11558
+ }
11559
+ page.commands.push(
11560
+ `${formatNumber(x)} ${formatNumber(page.height - y - height)} ${formatNumber(width)} ${formatNumber(height)} re`,
11561
+ "W",
11562
+ "n"
11563
+ );
11564
+ }
11071
11565
  drawText(pageIndex, options) {
11072
11566
  const page = this.pages[pageIndex];
11073
11567
  if (!page || options.text.length === 0) {
@@ -11420,7 +11914,8 @@ async function exportEditorDocumentToPdf(document2) {
11420
11914
  page.headerTop ?? getPageHeaderZoneTop(page.pageSettings),
11421
11915
  contentWidth,
11422
11916
  fontRegistry,
11423
- listOrdinals
11917
+ listOrdinals,
11918
+ page.pageSettings
11424
11919
  );
11425
11920
  await drawBlockList(
11426
11921
  writer,
@@ -11431,7 +11926,8 @@ async function exportEditorDocumentToPdf(document2) {
11431
11926
  page.bodyTop ?? getPageBodyTop(page.pageSettings),
11432
11927
  contentWidth,
11433
11928
  fontRegistry,
11434
- listOrdinals
11929
+ listOrdinals,
11930
+ page.pageSettings
11435
11931
  );
11436
11932
  await drawBlockList(
11437
11933
  writer,
@@ -11442,7 +11938,8 @@ async function exportEditorDocumentToPdf(document2) {
11442
11938
  page.footerTop ?? page.bodyBottom ?? page.pageSettings.height,
11443
11939
  contentWidth,
11444
11940
  fontRegistry,
11445
- listOrdinals
11941
+ listOrdinals,
11942
+ page.pageSettings
11446
11943
  );
11447
11944
  if (page.footnoteBlocks && page.footnoteBlocks.length > 0 && page.footnoteTop !== void 0) {
11448
11945
  if (page.footnoteSeparatorTop !== void 0) {
@@ -39935,11 +40432,13 @@ function numOrNull(payload) {
39935
40432
  function buildCoreFormattingCommands({
39936
40433
  gate,
39937
40434
  style: style2,
40435
+ selection,
39938
40436
  history,
39939
40437
  formatting,
39940
40438
  link,
39941
40439
  command,
39942
- valueCommand
40440
+ valueCommand,
40441
+ actionCommand
39943
40442
  }) {
39944
40443
  const s = style2.state;
39945
40444
  return {
@@ -40040,6 +40539,18 @@ function buildCoreFormattingCommands({
40040
40539
  },
40041
40540
  () => formatFontSizePt(s().fontSize)
40042
40541
  ),
40542
+ increaseFontSize: command("increaseFontSize", formatting.increaseFontSize),
40543
+ decreaseFontSize: command("decreaseFontSize", formatting.decreaseFontSize),
40544
+ changeTextCase: actionCommand(
40545
+ "changeTextCase",
40546
+ (p) => {
40547
+ formatting.changeTextCase(p ?? "sentence");
40548
+ },
40549
+ () => ({
40550
+ isEnabled: gate.isCommandEnabled("changeTextCase") && !selection.isCollapsed()
40551
+ })
40552
+ ),
40553
+ clearFormatting: command("clearFormatting", formatting.clearFormatting),
40043
40554
  setColor: valueCommand(
40044
40555
  "setColor",
40045
40556
  (p) => formatting.setColor(p ?? null),
@@ -40104,6 +40615,10 @@ function buildDocumentAndBrowserCommands({
40104
40615
  () => document2.importDocument()
40105
40616
  ),
40106
40617
  insertImage: actionCommand("insertImage", () => document2.insertImage()),
40618
+ insertShape: actionCommand(
40619
+ "insertShape",
40620
+ (p) => document2.insertShape(String(p))
40621
+ ),
40107
40622
  unlink: actionCommand(
40108
40623
  "unlink",
40109
40624
  () => link.remove(),
@@ -40327,11 +40842,13 @@ function createEssentialsPlugin(deps) {
40327
40842
  ...buildCoreFormattingCommands({
40328
40843
  gate: deps.gate,
40329
40844
  style: deps.style,
40845
+ selection: deps.selection,
40330
40846
  history: deps.history,
40331
40847
  formatting: deps.formatting,
40332
40848
  link: deps.link,
40333
40849
  command,
40334
- valueCommand
40850
+ valueCommand,
40851
+ actionCommand
40335
40852
  }),
40336
40853
  ...buildDocumentAndBrowserCommands({
40337
40854
  gate: deps.gate,
@@ -40364,6 +40881,21 @@ function createEditorEssentialsRuntimePlugin(options) {
40364
40881
  const essentialsStyle = {
40365
40882
  state: () => options.styleController.toolbarStyleState()
40366
40883
  };
40884
+ const essentialsSelection = {
40885
+ isCollapsed: () => isSelectionCollapsed(options.state().selection)
40886
+ };
40887
+ const stepFontSize = (direction) => {
40888
+ const currentPx = Number(
40889
+ options.styleController.toolbarStyleState().fontSize
40890
+ );
40891
+ const currentPt = Number.isFinite(currentPx) && currentPx > 0 ? fontSizePxToPt(currentPx) : 11;
40892
+ const nextPt = direction === "increase" ? nextFontSizePt(currentPt) : previousFontSizePt(currentPt);
40893
+ options.styleController.applyToolbarValueStyleCommand(
40894
+ "fontSize",
40895
+ fontSizePtToPx(nextPt)
40896
+ );
40897
+ return true;
40898
+ };
40367
40899
  const essentialsHistory = {
40368
40900
  canUndo: () => options.undoStack().length > 0,
40369
40901
  canRedo: () => options.redoStack().length > 0,
@@ -40453,6 +40985,18 @@ function createEditorEssentialsRuntimePlugin(options) {
40453
40985
  value
40454
40986
  ), true),
40455
40987
  setFontSize: (value) => (options.styleController.applyToolbarValueStyleCommand("fontSize", value), true),
40988
+ increaseFontSize: () => stepFontSize("increase"),
40989
+ decreaseFontSize: () => stepFontSize("decrease"),
40990
+ changeTextCase: (mode) => (options.commandsController.applyChangeTextCaseCommand(mode), true),
40991
+ clearFormatting: () => {
40992
+ if (isSelectionCollapsed(options.state().selection)) {
40993
+ options.styleController.clearPendingCaretTextStyle();
40994
+ options.focusInput();
40995
+ return true;
40996
+ }
40997
+ options.commandsController.applyClearFormattingCommand();
40998
+ return true;
40999
+ },
40456
41000
  setColor: (value) => (options.styleController.applyToolbarValueStyleCommand("color", value), true),
40457
41001
  setHighlight: (value) => (options.styleController.applyToolbarValueStyleCommand("highlight", value), true),
40458
41002
  setTextShading: (value) => (options.styleController.applyToolbarValueStyleCommand("shading", value), true),
@@ -40481,7 +41025,10 @@ function createEditorEssentialsRuntimePlugin(options) {
40481
41025
  insertImage: () => {
40482
41026
  var _a;
40483
41027
  return (_a = options.imageInputRef()) == null ? void 0 : _a.click();
40484
- }
41028
+ },
41029
+ insertShape: (preset) => options.applyTransactionalState(
41030
+ (current) => insertShapeAtSelection(current, preset)
41031
+ )
40485
41032
  };
40486
41033
  const essentialsLink = {
40487
41034
  prompt: () => options.commandsController.promptForLink(),
@@ -40708,6 +41255,7 @@ function createEditorEssentialsRuntimePlugin(options) {
40708
41255
  return createEssentialsPlugin({
40709
41256
  gate: essentialsGate,
40710
41257
  style: essentialsStyle,
41258
+ selection: essentialsSelection,
40711
41259
  history: essentialsHistory,
40712
41260
  formatting: essentialsFormatting,
40713
41261
  document: essentialsDocument,