oasis-editor 0.0.44 → 0.0.46

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 getParagraphLength, b as createEditorRun, d as getDocumentSections, e as createEditorStyledRun, f as getParagraphText, h as getActiveZone, i as getActiveSectionIndex, p as positionToParagraphOffset, j as paragraphOffsetToPosition, k as clampPosition, l as findParagraphIndex, m as createCollapsedSelection, o as isSelectionCollapsed, E as EMU_PER_PX, q as createEditorParagraph, r as getBlockParagraphs, s as findParagraphTableLocation, t as buildTableCellLayout, P as PT_PER_PX, u as createEditorTableCell, v as createEditorTableRow, w as createEditorTable, x as underlineStyleToCssDecorationStyle, y as resolveImageSrc, z as createEditorFootnote, A as createFootnoteReferenceRun, B as renumberFootnotes, C as iterateFootnoteReferenceRuns, D as getFootnoteDisplayMarker, F as createSignal, G as createEffect, H as onCleanup, I as buildCanvasLayoutSnapshot, J as on, K as onMount, L as debounce, M as unwrap, N as getDocumentParagraphs, O as getDocumentSectionsCanonical, Q as createEditorDocument, R as getPageContentWidth, S as getDocumentPageSettings, T as getTableCellContentWidthForParagraph, U as resolveResizedDimensions, V as resolveTextBoxRenderHeight, W as TWIPS_PER_POINT, X as PX_PER_INCH, Y as TWIPS_PER_INCH, Z as resolveEffectiveParagraphStyle, _ as resolveEffectiveTextStyleForParagraph, $ as EMU_PER_PT, a0 as iterateEndnoteReferenceRuns, a1 as JSZip, a2 as imageContentTypeDefaults, a3 as imageExtensionFromMime, a4 as pxToPt$1, a5 as resolveFloatingObjectRect, a6 as getTextBoxFloatingGeometry, a7 as getPresetPathSegments, a8 as projectBlocksLayout, a9 as buildListLabels, aa as textStyleToFontSizePt, ab as PX_PER_POINT, ac as DEFAULT_FONT_SIZE_PX, ad as isDoubleUnderlineStyle, ae as isWavyUnderlineStyle, af as underlineStyleLineWidthPx, ag as underlineStyleDashArray, ah as resolveListLabel, ai as getListLabelInset, aj as getAlignedListLabelInset, ak as getParagraphBorderInsets, al as buildSegmentTable, am as buildCanvasTableLayout, an as normalizeFamily, ao as ROBOTO_FONT_FILES, ap as loadFontAsset, aq as OFFICE_COMPAT_FONT_FAMILIES, ar as buildSfnt, as as defaultFontDecoderRegistry, at as SfntFontProgram, au as collectPdfFontFamilies, av as projectDocumentLayout, aw as getPageHeaderZoneTop, ax as getPageBodyTop, ay as getPageColumnRects, az as findFootnoteReference, aA as FOOTNOTE_MARKER_GUTTER_PX, aB as resolveImporterForFile, aC as createEditorStateFromDocument, aD as getDocumentParagraphsCanonical, aE as getToolbarStyleState, aF as STANDARD_FONT_SIZES_PT, aG as fontSizePxToPt, aH as probeLocalFontFamilies, aI as createInitialEditorState, aJ as parseFontSizePtToPx, aK as formatFontSizePt, aL as listKindForTag, aM as isParagraphTag, aN as collectInlineRuns, aO as parseParagraphStyle, aP as getCachedCanvasImage, aQ as getHeadingLevel, aR as preciseFontModeVersion, aS as isPreciseFontModeEnabled, aT as togglePreciseFontMode, aU as nextFontSizePt, aV as previousFontSizePt, aW as fontSizePtToPx, aX as createDefaultToolbarPreset, aY as MenuRegistry, aZ as createToolbarRegistry, a_ as Editor, a$ as resolveCommandRef, b0 as commandRefName, b1 as InlineShell, b2 as BalloonShell, b3 as DocumentShell, b4 as createMemo, b5 as getCaretRectFromSnapshot, b6 as getParagraphRectFromSnapshot, b7 as createComponent, b8 as CaretOverlay, b9 as Show, ba as createRenderEffect, bb as style, bc as setAttribute, bd as setStyleProperty, be as memo, bf as template, bg as useI18n, bh as insert, bi as use, bj as addEventListener, bk as Dialog, bl as delegateEvents, bm as className, bn as For, bo as UNDERLINE_STYLE_OPTIONS, bp as Tabs, bq as measureParagraphMinContentWidthPx, br as getEditableBlocksForZone, bs as findParagraphLocation, bt as createSectionBoundaryParagraph, bu as normalizePageSettings, bv as DEFAULT_EDITOR_PAGE_SETTINGS, bw as markStart, bx as markEnd, by as getParagraphEntries, bz as getParagraphById, bA as PluginUiHost, bB as OasisEditorEditor, bC as perfTimer, bD as OasisBrandMark, bE as setPreciseFontPreference, bF as setWelcomeSeen, bG as enablePreciseFontMode, bH as createOasisEditorClient, bI as createEditorZoom, bJ as startLongTaskObserver, bK as installGlobalReport, bL as applyStoredPreciseFontPreference, bM as getWelcomeSeen, bN as isLocalFontAccessSupported, bO as EDITOR_SCROLL_PADDING_PX, bP as Toolbar, bQ as OasisEditorLoading, bR as I18nProvider, bS as createEditorLogger, bT as createTranslator, bU as registerDomStatsSurface } from "./index-c-mRZBWM.js";
4
+ import { n as normalizeSelection, g as getParagraphs, c as createEditorParagraphFromRuns, a as getParagraphLength, b as createEditorRun, d as getDocumentSections, e as createEditorStyledRun, f as getParagraphText, h as getActiveZone, i as getActiveSectionIndex, p as positionToParagraphOffset, j as paragraphOffsetToPosition, k as clampPosition, l as findParagraphIndex, m as createCollapsedSelection, o as isSelectionCollapsed, E as EMU_PER_PX, q as createEditorParagraph, r as getBlockParagraphs, s as createEditorFootnote, t as createFootnoteReferenceRun, u as renumberFootnotes, v as iterateFootnoteReferenceRuns, w as getFootnoteDisplayMarker, x as findParagraphTableLocation, y as buildTableCellLayout, z as createSignal, A as createEffect, B as onCleanup, C as buildCanvasLayoutSnapshot, D as on, F as onMount, G as debounce, H as unwrap, I as getDocumentParagraphs, P as PT_PER_PX, J as createEditorTableCell, K as createEditorTableRow, L as createEditorTable, M as getDocumentSectionsCanonical, N as createEditorDocument, O as getPageContentWidth, Q as getDocumentPageSettings, R as getTableCellContentWidthForParagraph, S as resolveResizedDimensions, T as resolveImageSrc, U as resolveTextBoxRenderHeight, V as TWIPS_PER_POINT, W as PX_PER_INCH, X as TWIPS_PER_INCH, Y as resolveEffectiveParagraphStyle, Z as resolveEffectiveTextStyleForParagraph, _ as EMU_PER_PT, $ as iterateEndnoteReferenceRuns, a0 as JSZip, a1 as imageContentTypeDefaults, a2 as imageExtensionFromMime, a3 as pxToPt$1, a4 as resolveFloatingObjectRect, a5 as getTextBoxFloatingGeometry, a6 as getPresetPathSegments, a7 as projectBlocksLayout, a8 as buildListLabels, a9 as textStyleToFontSizePt, aa as PX_PER_POINT, ab as DEFAULT_FONT_SIZE_PX, ac as isDoubleUnderlineStyle, ad as isWavyUnderlineStyle, ae as underlineStyleLineWidthPx, af as underlineStyleDashArray, ag as resolveListLabel, ah as getListLabelInset, ai as getAlignedListLabelInset, aj as getParagraphBorderInsets, ak as buildSegmentTable, al as buildCanvasTableLayout, am as normalizeFamily, an as ROBOTO_FONT_FILES, ao as loadFontAsset, ap as OFFICE_COMPAT_FONT_FAMILIES, aq as buildSfnt, ar as defaultFontDecoderRegistry, as as SfntFontProgram, at as collectPdfFontFamilies, au as projectDocumentLayout, av as getPageHeaderZoneTop, aw as getPageBodyTop, ax as getPageColumnRects, ay as findFootnoteReference, az as FOOTNOTE_MARKER_GUTTER_PX, aA as resolveImporterForFile, aB as createEditorStateFromDocument, aC as getDocumentParagraphsCanonical, aD as getToolbarStyleState, aE as STANDARD_FONT_SIZES_PT, aF as fontSizePxToPt, aG as probeLocalFontFamilies, aH as createInitialEditorState, aI as parseFontSizePtToPx, aJ as formatFontSizePt, aK as underlineStyleToCssDecorationStyle, aL as listKindForTag, aM as isParagraphTag, aN as collectInlineRuns, aO as parseParagraphStyle, aP as getCachedCanvasImage, aQ as getHeadingLevel, aR as preciseFontModeVersion, aS as isPreciseFontModeEnabled, aT as togglePreciseFontMode, aU as nextFontSizePt, aV as previousFontSizePt, aW as fontSizePtToPx, aX as createDefaultToolbarPreset, aY as MenuRegistry, aZ as createToolbarRegistry, a_ as Editor, a$ as resolveCommandRef, b0 as commandRefName, b1 as InlineShell, b2 as BalloonShell, b3 as DocumentShell, b4 as createMemo, b5 as getCaretRectFromSnapshot, b6 as getParagraphRectFromSnapshot, b7 as createComponent, b8 as CaretOverlay, b9 as Show, ba as createRenderEffect, bb as style, bc as setAttribute, bd as setStyleProperty, be as memo, bf as template, bg as useI18n, bh as insert, bi as use, bj as addEventListener, bk as Dialog, bl as delegateEvents, bm as className, bn as For, bo as UNDERLINE_STYLE_OPTIONS, bp as Tabs, bq as measureParagraphMinContentWidthPx, br as getEditableBlocksForZone, bs as findParagraphLocation, bt as createSectionBoundaryParagraph, bu as normalizePageSettings, bv as DEFAULT_EDITOR_PAGE_SETTINGS, bw as markStart, bx as markEnd, by as getParagraphEntries, bz as getParagraphById, bA as PluginUiHost, bB as OasisEditorEditor, bC as perfTimer, bD as OasisBrandMark, bE as setPreciseFontPreference, bF as setWelcomeSeen, bG as enablePreciseFontMode, bH as createOasisEditorClient, bI as createEditorZoom, bJ as startLongTaskObserver, bK as installGlobalReport, bL as applyStoredPreciseFontPreference, bM as getWelcomeSeen, bN as isLocalFontAccessSupported, bO as EDITOR_SCROLL_PADDING_PX, bP as Toolbar, bQ as OasisEditorLoading, bR as I18nProvider, bS as createEditorLogger, bT as createTranslator, bU as registerDomStatsSurface } from "./index-Cz7QAkQ8.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) {
@@ -1440,535 +1440,400 @@ function resizeSelectedTextBox(state, width, height, options = {}) {
1440
1440
  )
1441
1441
  );
1442
1442
  }
1443
- const SHAPE_DEFAULT_WIDTH = 150;
1444
- const SHAPE_DEFAULT_HEIGHT = 100;
1445
- const SHAPE_DEFAULT_FILL = "#4472C4";
1446
- const SHAPE_DEFAULT_BORDER_COLOR = "#2F528F";
1447
- const SHAPE_DEFAULT_BORDER_WIDTH_PT = 1;
1448
- function insertShapeAtSelection(state, preset) {
1449
- const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
1450
- const { paragraph, index, offset } = getFocusParagraph(collapsedState);
1451
- const textBox = {
1452
- width: SHAPE_DEFAULT_WIDTH,
1453
- height: SHAPE_DEFAULT_HEIGHT,
1454
- blocks: [createEditorParagraph("")],
1455
- shape: {
1456
- preset,
1457
- fill: SHAPE_DEFAULT_FILL,
1458
- borderColor: SHAPE_DEFAULT_BORDER_COLOR,
1459
- borderWidthPt: SHAPE_DEFAULT_BORDER_WIDTH_PT
1460
- },
1461
- floating: wrapPresetToFloating(void 0, "front")
1443
+ function cloneBlock(block) {
1444
+ return block.type === "paragraph" ? {
1445
+ ...block,
1446
+ runs: block.runs.map((run) => ({
1447
+ ...run,
1448
+ styles: run.styles ? { ...run.styles } : void 0,
1449
+ image: run.image ? { ...run.image } : void 0,
1450
+ field: run.field ? { ...run.field } : void 0,
1451
+ revision: run.revision ? { ...run.revision } : void 0,
1452
+ footnoteReference: run.footnoteReference ? { ...run.footnoteReference } : void 0,
1453
+ endnoteReference: run.endnoteReference ? { ...run.endnoteReference } : void 0
1454
+ })),
1455
+ style: block.style ? { ...block.style } : void 0,
1456
+ list: block.list ? { ...block.list } : void 0
1457
+ } : {
1458
+ ...block,
1459
+ style: block.style ? {
1460
+ ...block.style,
1461
+ defaultCellMargins: block.style.defaultCellMargins ? { ...block.style.defaultCellMargins } : void 0,
1462
+ floating: block.style.floating ? { ...block.style.floating } : void 0,
1463
+ revisionXml: block.style.revisionXml ? [...block.style.revisionXml] : void 0
1464
+ } : void 0,
1465
+ tblGridChangeXml: block.tblGridChangeXml,
1466
+ rows: block.rows.map((row) => ({
1467
+ ...row,
1468
+ style: row.style ? {
1469
+ ...row.style,
1470
+ revisionXml: row.style.revisionXml ? [...row.style.revisionXml] : void 0
1471
+ } : void 0,
1472
+ cells: row.cells.map((cell) => ({
1473
+ ...cell,
1474
+ colSpan: cell.colSpan ?? void 0,
1475
+ rowSpan: cell.rowSpan ?? void 0,
1476
+ vMerge: cell.vMerge ?? void 0,
1477
+ style: cell.style ? {
1478
+ ...cell.style,
1479
+ revisionXml: cell.style.revisionXml ? [...cell.style.revisionXml] : void 0
1480
+ } : void 0,
1481
+ blocks: cell.blocks.map((paragraph) => ({
1482
+ ...paragraph,
1483
+ runs: paragraph.runs.map((run) => ({
1484
+ ...run,
1485
+ styles: run.styles ? { ...run.styles } : void 0,
1486
+ image: run.image ? { ...run.image } : void 0,
1487
+ field: run.field ? { ...run.field } : void 0,
1488
+ revision: run.revision ? { ...run.revision } : void 0,
1489
+ footnoteReference: run.footnoteReference ? { ...run.footnoteReference } : void 0,
1490
+ endnoteReference: run.endnoteReference ? { ...run.endnoteReference } : void 0
1491
+ })),
1492
+ style: paragraph.style ? { ...paragraph.style } : void 0,
1493
+ list: paragraph.list ? { ...paragraph.list } : void 0
1494
+ }))
1495
+ }))
1496
+ }))
1462
1497
  };
1463
- const insertedRun = createEditorStyledRun(
1464
- "",
1465
- getStyleAtOffset(paragraph, offset),
1466
- void 0,
1467
- textBox
1468
- );
1469
- const nextParagraph = insertRunsAtOffset(paragraph, offset, [insertedRun]);
1470
- const paragraphs = getParagraphs(collapsedState);
1471
- const nextParagraphs = paragraphs.map(
1472
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : cloneParagraph(candidate)
1473
- );
1474
- return cloneStateWithParagraphs(
1475
- collapsedState,
1476
- nextParagraphs,
1477
- withSelection(paragraphOffsetToPosition(nextParagraph, offset + 1))
1478
- );
1479
1498
  }
1480
- function cloneFragmentRuns(runs) {
1481
- return runs.map(cloneRun);
1499
+ function cloneSection(section) {
1500
+ var _a, _b, _c, _d, _e, _f;
1501
+ return {
1502
+ ...section,
1503
+ blocks: section.blocks.map(cloneBlock),
1504
+ header: (_a = section.header) == null ? void 0 : _a.map(cloneBlock),
1505
+ firstPageHeader: (_b = section.firstPageHeader) == null ? void 0 : _b.map(cloneBlock),
1506
+ evenPageHeader: (_c = section.evenPageHeader) == null ? void 0 : _c.map(cloneBlock),
1507
+ footer: (_d = section.footer) == null ? void 0 : _d.map(cloneBlock),
1508
+ firstPageFooter: (_e = section.firstPageFooter) == null ? void 0 : _e.map(cloneBlock),
1509
+ evenPageFooter: (_f = section.evenPageFooter) == null ? void 0 : _f.map(cloneBlock)
1510
+ };
1482
1511
  }
1483
- function getRunsLength(runs) {
1484
- return runs.reduce((total, run) => total + run.text.length, 0);
1512
+ function cloneFootnote(footnote) {
1513
+ return {
1514
+ ...footnote,
1515
+ blocks: footnote.blocks.map(cloneBlock)
1516
+ };
1485
1517
  }
1486
- function collectSelectionFragments(state) {
1487
- const normalized = normalizeSelection(state);
1488
- if (normalized.isCollapsed) {
1489
- return [];
1490
- }
1491
- const paragraphs = getParagraphs(state);
1492
- const fragments = [];
1493
- for (let index = normalized.startIndex; index <= normalized.endIndex; index += 1) {
1494
- const paragraph = paragraphs[index];
1495
- const startOffset = index === normalized.startIndex ? normalized.startParagraphOffset : 0;
1496
- const endOffset = index === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
1497
- const runs = sliceRuns(paragraph, startOffset, endOffset);
1498
- fragments.push({
1499
- paragraphTemplate: cloneParagraph(paragraph),
1500
- runs
1501
- });
1518
+ function cloneFootnotes(footnotes) {
1519
+ var _a, _b;
1520
+ if (!footnotes) return void 0;
1521
+ const nextItems = {};
1522
+ for (const [id, footnote] of Object.entries(footnotes.items)) {
1523
+ nextItems[id] = cloneFootnote(footnote);
1502
1524
  }
1503
- return fragments;
1525
+ return {
1526
+ items: nextItems,
1527
+ settings: footnotes.settings ? { ...footnotes.settings } : void 0,
1528
+ separator: (_a = footnotes.separator) == null ? void 0 : _a.map(cloneBlock),
1529
+ continuationSeparator: (_b = footnotes.continuationSeparator) == null ? void 0 : _b.map(cloneBlock)
1530
+ };
1504
1531
  }
1505
- function insertFragmentsAtPosition(state, targetPosition, fragments) {
1506
- if (fragments.length === 0) {
1507
- return state;
1508
- }
1509
- const paragraphs = getParagraphs(state);
1510
- const targetIndex = paragraphs.findIndex(
1511
- (paragraph) => paragraph.id === targetPosition.paragraphId
1512
- );
1513
- if (targetIndex === -1) {
1514
- return state;
1515
- }
1516
- const targetParagraph = paragraphs[targetIndex];
1517
- const targetOffset = positionToParagraphOffset(
1518
- targetParagraph,
1519
- targetPosition
1520
- );
1521
- const firstRuns = cloneFragmentRuns(fragments[0].runs);
1522
- if (fragments.length === 1) {
1523
- const nextTarget = insertRunsAtOffset(
1524
- targetParagraph,
1525
- targetOffset,
1526
- firstRuns
1527
- );
1528
- const nextParagraphs2 = paragraphs.map(
1529
- (candidate, index) => index === targetIndex ? nextTarget : candidate
1530
- );
1531
- const insertedLength = getRunsLength(firstRuns);
1532
- const anchor2 = paragraphOffsetToPosition(nextTarget, targetOffset);
1533
- const focus2 = paragraphOffsetToPosition(
1534
- nextTarget,
1535
- targetOffset + insertedLength
1536
- );
1537
- return cloneStateWithParagraphs(state, nextParagraphs2, {
1538
- anchor: anchor2,
1539
- focus: focus2
1540
- });
1541
- }
1542
- const beforeRuns = sliceRuns(targetParagraph, 0, targetOffset);
1543
- const afterRuns = sliceRuns(
1544
- targetParagraph,
1545
- targetOffset,
1546
- getParagraphLength(targetParagraph)
1547
- );
1548
- const lastFragment = fragments[fragments.length - 1];
1549
- const middleFragments = fragments.slice(1, -1);
1550
- const firstInserted = buildParagraphFromRuns(
1551
- cloneParagraph(fragments[0].paragraphTemplate),
1552
- [...beforeRuns, ...firstRuns],
1553
- getStyleAtOffset(targetParagraph, targetOffset)
1554
- );
1555
- const insertedMiddle = middleFragments.map(
1556
- (fragment) => buildParagraphFromRuns(
1557
- cloneParagraph(fragment.paragraphTemplate),
1558
- cloneFragmentRuns(fragment.runs)
1559
- )
1560
- );
1561
- const lastInserted = buildParagraphFromRuns(
1562
- cloneParagraph(lastFragment.paragraphTemplate),
1563
- [...cloneFragmentRuns(lastFragment.runs), ...afterRuns],
1564
- getStyleAtOffset(targetParagraph, targetOffset)
1565
- );
1566
- const nextParagraphs = [
1567
- ...paragraphs.slice(0, targetIndex),
1568
- firstInserted,
1569
- ...insertedMiddle,
1570
- lastInserted,
1571
- ...paragraphs.slice(targetIndex + 1)
1572
- ];
1573
- const anchor = paragraphOffsetToPosition(
1574
- firstInserted,
1575
- getRunsLength(beforeRuns)
1576
- );
1577
- const focus = paragraphOffsetToPosition(
1578
- lastInserted,
1579
- getRunsLength(lastFragment.runs)
1580
- );
1581
- return cloneStateWithParagraphs(state, nextParagraphs, { anchor, focus });
1532
+ function cloneEndnote(endnote) {
1533
+ return {
1534
+ ...endnote,
1535
+ blocks: endnote.blocks.map(cloneBlock)
1536
+ };
1582
1537
  }
1583
- function isTargetInsideSelection(state, targetPosition) {
1584
- const normalized = normalizeSelection(state);
1585
- if (normalized.isCollapsed) {
1586
- return false;
1587
- }
1588
- const paragraphs = getParagraphs(state);
1589
- const targetIndex = paragraphs.findIndex(
1590
- (paragraph2) => paragraph2.id === targetPosition.paragraphId
1591
- );
1592
- if (targetIndex === -1) {
1593
- return false;
1594
- }
1595
- if (targetIndex < normalized.startIndex || targetIndex > normalized.endIndex) {
1596
- return false;
1597
- }
1598
- const paragraph = paragraphs[targetIndex];
1599
- const targetOffset = positionToParagraphOffset(paragraph, targetPosition);
1600
- if (targetIndex === normalized.startIndex && targetOffset < normalized.startParagraphOffset) {
1601
- return false;
1602
- }
1603
- if (targetIndex === normalized.endIndex && targetOffset > normalized.endParagraphOffset) {
1604
- return false;
1538
+ function cloneEndnotes(endnotes) {
1539
+ var _a, _b;
1540
+ if (!endnotes) return void 0;
1541
+ const nextItems = {};
1542
+ for (const [id, endnote] of Object.entries(endnotes.items)) {
1543
+ nextItems[id] = cloneEndnote(endnote);
1605
1544
  }
1606
- return true;
1545
+ return {
1546
+ items: nextItems,
1547
+ settings: endnotes.settings ? { ...endnotes.settings } : void 0,
1548
+ separator: (_a = endnotes.separator) == null ? void 0 : _a.map(cloneBlock),
1549
+ continuationSeparator: (_b = endnotes.continuationSeparator) == null ? void 0 : _b.map(cloneBlock)
1550
+ };
1607
1551
  }
1608
- function mapTargetAfterDelete(state, targetPosition) {
1609
- const normalized = normalizeSelection(state);
1610
- const paragraphs = getParagraphs(state);
1611
- const targetIndex = paragraphs.findIndex(
1612
- (paragraph) => paragraph.id === targetPosition.paragraphId
1613
- );
1614
- if (targetIndex === -1) {
1615
- return targetPosition;
1616
- }
1617
- const targetParagraph = paragraphs[targetIndex];
1618
- const targetOffset = positionToParagraphOffset(
1619
- targetParagraph,
1620
- targetPosition
1621
- );
1622
- if (normalized.startIndex === normalized.endIndex) {
1623
- if (targetIndex !== normalized.startIndex || targetOffset <= normalized.endParagraphOffset) {
1624
- return targetPosition;
1552
+ function cloneEditorState(source) {
1553
+ var _a;
1554
+ return {
1555
+ ...source,
1556
+ document: {
1557
+ ...source.document,
1558
+ sections: (_a = source.document.sections) == null ? void 0 : _a.map(cloneSection),
1559
+ footnotes: cloneFootnotes(source.document.footnotes),
1560
+ endnotes: cloneEndnotes(source.document.endnotes)
1561
+ },
1562
+ selection: {
1563
+ anchor: { ...source.selection.anchor },
1564
+ focus: { ...source.selection.focus }
1565
+ },
1566
+ activeSectionIndex: source.activeSectionIndex ?? 0,
1567
+ activeZone: source.activeZone ?? "main",
1568
+ activeFootnoteId: source.activeFootnoteId
1569
+ };
1570
+ }
1571
+ function moveBlockToPosition(state, blockId, targetPosition) {
1572
+ var _a;
1573
+ let movedBlock;
1574
+ const removeFromBlocks = (blocks) => {
1575
+ const idx = blocks.findIndex((b) => b.id === blockId);
1576
+ if (idx >= 0) {
1577
+ movedBlock = blocks[idx];
1578
+ return [...blocks.slice(0, idx), ...blocks.slice(idx + 1)];
1625
1579
  }
1626
- const startParagraph = paragraphs[normalized.startIndex];
1627
- return paragraphOffsetToPosition(
1628
- startParagraph,
1629
- targetOffset - (normalized.endParagraphOffset - normalized.startParagraphOffset)
1630
- );
1580
+ return blocks;
1581
+ };
1582
+ const removeFromSections = (sections) => {
1583
+ return sections.map((s) => ({
1584
+ ...s,
1585
+ blocks: removeFromBlocks(s.blocks),
1586
+ header: s.header ? removeFromBlocks(s.header) : void 0,
1587
+ footer: s.footer ? removeFromBlocks(s.footer) : void 0
1588
+ }));
1589
+ };
1590
+ const nextDocument = { ...state.document };
1591
+ if (nextDocument.sections && nextDocument.sections.length > 0) {
1592
+ nextDocument.sections = removeFromSections(nextDocument.sections);
1631
1593
  }
1632
- return targetPosition;
1633
- }
1634
- function moveOrCopySelectionToPosition(state, targetPosition, options = {}) {
1635
- const normalized = normalizeSelection(state);
1636
- if (normalized.isCollapsed) {
1594
+ if (!movedBlock) {
1637
1595
  return state;
1638
1596
  }
1639
- if (isTargetInsideSelection(state, targetPosition)) {
1640
- return state;
1597
+ const targetId = targetPosition.paragraphId;
1598
+ if (movedBlock.type === "table") {
1599
+ const internalParagraphs = getBlockParagraphs(movedBlock);
1600
+ if (internalParagraphs.some((p) => p.id === targetId)) {
1601
+ return state;
1602
+ }
1641
1603
  }
1642
- const fragments = collectSelectionFragments(state);
1643
- if (fragments.length === 0) {
1644
- return state;
1604
+ const insertIntoBlocks = (blocks) => {
1605
+ const idx = blocks.findIndex((b) => {
1606
+ if (b.id === targetId) return true;
1607
+ if (b.type === "table") {
1608
+ return getBlockParagraphs(b).some((p) => p.id === targetId);
1609
+ }
1610
+ return false;
1611
+ });
1612
+ if (idx < 0) return { nextBlocks: blocks, found: false };
1613
+ const nextBlocks = [
1614
+ ...blocks.slice(0, idx),
1615
+ movedBlock,
1616
+ ...blocks.slice(idx)
1617
+ ];
1618
+ return { nextBlocks, found: true };
1619
+ };
1620
+ const activeIdx = getActiveSectionIndex(state);
1621
+ const zone = getActiveZone(state);
1622
+ const activeSection = (_a = nextDocument.sections) == null ? void 0 : _a[activeIdx];
1623
+ const section = { ...activeSection };
1624
+ let found = false;
1625
+ if (zone === "header") {
1626
+ const res = insertIntoBlocks(section.header ?? []);
1627
+ section.header = res.nextBlocks;
1628
+ found = res.found;
1629
+ } else if (zone === "footer") {
1630
+ const res = insertIntoBlocks(section.footer ?? []);
1631
+ section.footer = res.nextBlocks;
1632
+ found = res.found;
1633
+ } else {
1634
+ const res = insertIntoBlocks(section.blocks);
1635
+ section.blocks = res.nextBlocks;
1636
+ found = res.found;
1645
1637
  }
1646
- if (options.copy) {
1647
- return insertFragmentsAtPosition(state, targetPosition, fragments);
1638
+ if (!found) {
1639
+ section.blocks = [...section.blocks, movedBlock];
1648
1640
  }
1649
- const mappedTarget = mapTargetAfterDelete(state, targetPosition);
1650
- const deleted = deleteSelectionRange(state);
1651
- return insertFragmentsAtPosition(deleted, mappedTarget, fragments);
1641
+ nextDocument.sections = [...nextDocument.sections ?? []];
1642
+ nextDocument.sections[activeIdx] = section;
1643
+ return {
1644
+ ...state,
1645
+ document: nextDocument
1646
+ };
1652
1647
  }
1653
- function insertTextAtSelection(state, text, styleOverride) {
1654
- if (text.length === 0) {
1655
- return state;
1656
- }
1648
+ function splitBlockAtSelection(state) {
1657
1649
  const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
1658
1650
  const { paragraph, index, offset } = getFocusParagraph(collapsedState);
1659
- const styles = styleOverride ? { ...styleOverride } : getStyleAtOffset(paragraph, offset);
1660
- const insertedRun = {
1661
- id: `run:${Math.random().toString(36).slice(2, 9)}`,
1662
- text,
1663
- styles
1664
- };
1665
- if (collapsedState.trackChangesEnabled) {
1666
- insertedRun.revision = {
1667
- id: `rev:${Math.random().toString(36).slice(2, 9)}`,
1668
- type: "insert",
1669
- author: "User",
1670
- date: Date.now()
1671
- };
1672
- }
1673
- const nextParagraph = insertRunsAtOffset(paragraph, offset, [insertedRun]);
1674
- const paragraphs = getParagraphs(collapsedState);
1675
- const nextParagraphs = paragraphs.map(
1676
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : candidate
1651
+ const firstParagraph = buildParagraphFromRuns(
1652
+ paragraph,
1653
+ sliceRuns(paragraph, 0, offset),
1654
+ getStyleAtOffset(paragraph, offset)
1677
1655
  );
1656
+ const secondRuns = sliceRuns(
1657
+ paragraph,
1658
+ offset,
1659
+ getParagraphLength(paragraph)
1660
+ );
1661
+ const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
1662
+ paragraph,
1663
+ secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
1664
+ ) : (() => {
1665
+ const emptyParagraph = createEditorParagraph("");
1666
+ emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
1667
+ emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
1668
+ return emptyParagraph;
1669
+ })();
1670
+ const paragraphs = getParagraphs(collapsedState);
1671
+ const nextParagraphs = [
1672
+ ...cloneParagraphs(paragraphs.slice(0, index)),
1673
+ firstParagraph,
1674
+ nextParagraph,
1675
+ ...cloneParagraphs(paragraphs.slice(index + 1))
1676
+ ];
1678
1677
  return cloneStateWithParagraphs(
1679
1678
  collapsedState,
1680
1679
  nextParagraphs,
1681
- withSelection(
1682
- paragraphOffsetToPosition(nextParagraph, offset + text.length)
1683
- )
1680
+ withSelection(paragraphOffsetToPosition(nextParagraph, 0))
1684
1681
  );
1685
1682
  }
1686
- function insertPlainTextAtSelection(state, text, styleOverride) {
1687
- if (text.length === 0) {
1688
- return state;
1689
- }
1690
- const normalizedText = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
1691
- if (!normalizedText.includes("\n")) {
1692
- return insertTextAtSelection(state, normalizedText, styleOverride);
1693
- }
1683
+ function insertPageBreakAtSelection(state) {
1694
1684
  const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
1695
1685
  const { paragraph, index, offset } = getFocusParagraph(collapsedState);
1696
- const lines = normalizedText.split("\n");
1697
- const insertionStyles = getStyleAtOffset(paragraph, offset);
1698
- const beforeRuns = sliceRuns(paragraph, 0, offset);
1699
1686
  const firstParagraph = buildParagraphFromRuns(
1700
1687
  paragraph,
1701
- [...beforeRuns, createEditorStyledRun(lines[0], insertionStyles)],
1702
- insertionStyles
1688
+ sliceRuns(paragraph, 0, offset),
1689
+ getStyleAtOffset(paragraph, offset)
1703
1690
  );
1704
- const tailRuns = sliceRuns(paragraph, offset, getParagraphLength(paragraph));
1705
- const middleParagraphs = lines.slice(1, -1).map(
1706
- (line) => createParagraphFromRuns([{ text: line, styles: insertionStyles }])
1691
+ const secondRuns = sliceRuns(
1692
+ paragraph,
1693
+ offset,
1694
+ getParagraphLength(paragraph)
1707
1695
  );
1708
- const lastParagraph = createParagraphFromRuns([
1709
- { text: lines[lines.length - 1], styles: insertionStyles },
1710
- ...tailRuns.map((run) => ({ text: run.text, styles: run.styles }))
1711
- ]);
1696
+ const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
1697
+ paragraph,
1698
+ secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
1699
+ ) : (() => {
1700
+ const emptyParagraph = createEditorParagraph("");
1701
+ emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
1702
+ emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
1703
+ return emptyParagraph;
1704
+ })();
1705
+ nextParagraph.style = {
1706
+ ...paragraph.style ?? {},
1707
+ pageBreakBefore: true
1708
+ };
1712
1709
  const paragraphs = getParagraphs(collapsedState);
1713
1710
  const nextParagraphs = [
1714
- ...paragraphs.slice(0, index),
1711
+ ...cloneParagraphs(paragraphs.slice(0, index)),
1715
1712
  firstParagraph,
1716
- ...middleParagraphs,
1717
- lastParagraph,
1718
- ...paragraphs.slice(index + 1)
1713
+ nextParagraph,
1714
+ ...cloneParagraphs(paragraphs.slice(index + 1))
1719
1715
  ];
1720
1716
  return cloneStateWithParagraphs(
1721
1717
  collapsedState,
1722
1718
  nextParagraphs,
1723
- withSelection(
1724
- paragraphOffsetToPosition(lastParagraph, lines[lines.length - 1].length)
1725
- )
1719
+ withSelection(paragraphOffsetToPosition(nextParagraph, 0))
1726
1720
  );
1727
1721
  }
1728
- function deleteBackward(state) {
1729
- var _a;
1730
- if (!isSelectionCollapsed(state.selection)) {
1731
- return deleteSelectionRange(state);
1722
+ function insertSectionBreakAtSelection(state, breakType) {
1723
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
1724
+ const { paragraph, offset } = getFocusParagraph(collapsedState);
1725
+ const sections = getDocumentSections(collapsedState.document);
1726
+ const activeSectionIndex = getActiveSectionIndex(collapsedState);
1727
+ const zone = getActiveZone(collapsedState);
1728
+ if (zone !== "main") {
1729
+ return state;
1732
1730
  }
1733
- const { paragraph, index, offset } = getFocusParagraph(state);
1734
- const paragraphs = getParagraphs(state);
1735
- if (offset > 0) {
1736
- if (state.trackChangesEnabled) {
1737
- const runs = paragraph.runs;
1738
- let consumed = 0;
1739
- let targetRunIndex = -1;
1740
- let runOffset = -1;
1741
- for (let i = 0; i < runs.length; i += 1) {
1742
- const nextConsumed = consumed + runs[i].text.length;
1743
- if (offset <= nextConsumed) {
1744
- targetRunIndex = i;
1745
- runOffset = offset - consumed;
1746
- break;
1747
- }
1748
- consumed = nextConsumed;
1749
- }
1750
- if (targetRunIndex !== -1) {
1751
- const targetRun = runs[targetRunIndex];
1752
- if (((_a = targetRun.revision) == null ? void 0 : _a.type) === "insert") {
1753
- const nextRuns2 = [
1754
- ...sliceRuns(paragraph, 0, offset - 1),
1755
- ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
1756
- ];
1757
- const nextParagraph3 = buildParagraphFromRuns(paragraph, nextRuns2);
1758
- const nextParagraphs4 = paragraphs.map(
1759
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph3 : candidate
1760
- );
1761
- return cloneStateWithParagraphs(
1762
- state,
1763
- nextParagraphs4,
1764
- withSelection(paragraphOffsetToPosition(nextParagraph3, offset - 1))
1765
- );
1766
- }
1767
- const charToDelete = targetRun.text[runOffset - 1];
1768
- const deletionRun = {
1769
- id: `run:${Math.random().toString(36).slice(2, 9)}`,
1770
- text: charToDelete,
1771
- styles: { ...targetRun.styles },
1772
- revision: {
1773
- id: `rev:${Math.random().toString(36).slice(2, 9)}`,
1774
- type: "delete",
1775
- author: "User",
1776
- date: Date.now()
1777
- }
1778
- };
1779
- const nextRuns = [
1780
- ...sliceRuns(paragraph, 0, offset - 1),
1781
- deletionRun,
1782
- ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
1783
- ];
1784
- const nextParagraph2 = buildParagraphFromRuns(paragraph, nextRuns);
1785
- const nextParagraphs3 = paragraphs.map(
1786
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph2 : candidate
1787
- );
1788
- return cloneStateWithParagraphs(
1789
- state,
1790
- nextParagraphs3,
1791
- withSelection(paragraphOffsetToPosition(nextParagraph2, offset - 1))
1792
- );
1793
- }
1794
- }
1795
- const nextParagraph = buildParagraphFromRuns(
1796
- paragraph,
1797
- [
1798
- ...sliceRuns(paragraph, 0, offset - 1),
1799
- ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
1800
- ],
1801
- getStyleAtOffset(paragraph, offset - 1)
1802
- );
1803
- const nextParagraphs2 = paragraphs.map(
1804
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : candidate
1805
- );
1806
- return cloneStateWithParagraphs(
1807
- state,
1808
- nextParagraphs2,
1809
- withSelection(paragraphOffsetToPosition(nextParagraph, offset - 1))
1810
- );
1731
+ const section = sections[activeSectionIndex];
1732
+ if (!section) {
1733
+ return state;
1811
1734
  }
1812
- if (index === 0) {
1735
+ const blockIndex = section.blocks.findIndex((block) => {
1736
+ if (block.type === "paragraph") {
1737
+ return block.id === paragraph.id;
1738
+ }
1739
+ return false;
1740
+ });
1741
+ if (blockIndex === -1) {
1813
1742
  return state;
1814
1743
  }
1815
- const previousParagraph = paragraphs[index - 1];
1816
- const mergedParagraph = buildParagraphFromRuns(previousParagraph, [
1817
- ...previousParagraph.runs.map(cloneRun),
1818
- ...paragraph.runs.map(cloneRun)
1819
- ]);
1820
- const nextParagraphs = [
1821
- ...paragraphs.slice(0, index - 1),
1822
- mergedParagraph,
1823
- ...paragraphs.slice(index + 1)
1824
- ];
1825
- return cloneStateWithParagraphs(
1826
- state,
1827
- nextParagraphs,
1828
- withSelection(
1829
- paragraphOffsetToPosition(
1830
- mergedParagraph,
1831
- getParagraphLength(previousParagraph)
1832
- )
1833
- )
1744
+ const beforeBlocks = section.blocks.slice(0, blockIndex);
1745
+ const afterBlocks = section.blocks.slice(blockIndex + 1);
1746
+ const firstParagraph = buildParagraphFromRuns(
1747
+ paragraph,
1748
+ sliceRuns(paragraph, 0, offset),
1749
+ getStyleAtOffset(paragraph, offset)
1750
+ );
1751
+ const secondRuns = sliceRuns(
1752
+ paragraph,
1753
+ offset,
1754
+ getParagraphLength(paragraph)
1834
1755
  );
1756
+ const secondParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
1757
+ paragraph,
1758
+ secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
1759
+ ) : (() => {
1760
+ const emptyParagraph = createEditorParagraph("");
1761
+ emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
1762
+ emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
1763
+ return emptyParagraph;
1764
+ })();
1765
+ const newSectionId = `section:${Math.random().toString(36).slice(2, 9)}`;
1766
+ const newSection = {
1767
+ id: newSectionId,
1768
+ blocks: [secondParagraph, ...afterBlocks],
1769
+ pageSettings: { ...section.pageSettings },
1770
+ header: section.header ? cloneBlocks(section.header) : void 0,
1771
+ footer: section.footer ? cloneBlocks(section.footer) : void 0,
1772
+ breakType
1773
+ };
1774
+ const updatedSection = {
1775
+ ...section,
1776
+ blocks: [...beforeBlocks, firstParagraph]
1777
+ };
1778
+ const nextSections = [
1779
+ ...sections.slice(0, activeSectionIndex),
1780
+ updatedSection,
1781
+ newSection,
1782
+ ...sections.slice(activeSectionIndex + 1)
1783
+ ];
1784
+ return {
1785
+ ...collapsedState,
1786
+ document: {
1787
+ ...collapsedState.document,
1788
+ sections: nextSections
1789
+ },
1790
+ activeSectionIndex: activeSectionIndex + 1,
1791
+ selection: withSelection(paragraphOffsetToPosition(secondParagraph, 0))
1792
+ };
1835
1793
  }
1836
- function deleteForward(state) {
1794
+ function updateSectionSettings(state, sectionIndex, settings) {
1837
1795
  var _a;
1838
- if (!isSelectionCollapsed(state.selection)) {
1839
- return deleteSelectionRange(state);
1796
+ const sections = getDocumentSections(state.document);
1797
+ if (sectionIndex < 0 || sectionIndex >= sections.length) {
1798
+ return state;
1840
1799
  }
1841
- const { paragraph, index, offset } = getFocusParagraph(state);
1842
- const paragraphs = getParagraphs(state);
1843
- if (offset < getParagraphLength(paragraph)) {
1844
- if (state.trackChangesEnabled) {
1845
- const runs = paragraph.runs;
1846
- let consumed = 0;
1847
- let targetRunIndex = -1;
1848
- let runOffset = -1;
1849
- for (let i = 0; i < runs.length; i += 1) {
1850
- const nextConsumed = consumed + runs[i].text.length;
1851
- if (offset < nextConsumed) {
1852
- targetRunIndex = i;
1853
- runOffset = offset - consumed;
1854
- break;
1855
- }
1856
- consumed = nextConsumed;
1857
- }
1858
- if (targetRunIndex !== -1) {
1859
- const targetRun = runs[targetRunIndex];
1860
- if (((_a = targetRun.revision) == null ? void 0 : _a.type) === "insert") {
1861
- const nextRuns2 = [
1862
- ...sliceRuns(paragraph, 0, offset),
1863
- ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
1864
- ];
1865
- const nextParagraph4 = buildParagraphFromRuns(paragraph, nextRuns2);
1866
- const nextParagraphs4 = paragraphs.map(
1867
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph4 : candidate
1868
- );
1869
- return cloneStateWithParagraphs(
1870
- state,
1871
- nextParagraphs4,
1872
- withSelection(paragraphOffsetToPosition(nextParagraph4, offset))
1873
- );
1874
- }
1875
- const charToDelete = targetRun.text[runOffset];
1876
- const deletionRun = {
1877
- id: `run:${Math.random().toString(36).slice(2, 9)}`,
1878
- text: charToDelete,
1879
- styles: { ...targetRun.styles },
1880
- revision: {
1881
- id: `rev:${Math.random().toString(36).slice(2, 9)}`,
1882
- type: "delete",
1883
- author: "User",
1884
- date: Date.now()
1885
- }
1886
- };
1887
- const nextRuns = [
1888
- ...sliceRuns(paragraph, 0, offset),
1889
- deletionRun,
1890
- ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
1891
- ];
1892
- const nextParagraph3 = buildParagraphFromRuns(paragraph, nextRuns);
1893
- const nextParagraphs3 = paragraphs.map(
1894
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph3 : candidate
1895
- );
1896
- return cloneStateWithParagraphs(
1897
- state,
1898
- nextParagraphs3,
1899
- withSelection(paragraphOffsetToPosition(nextParagraph3, offset))
1900
- );
1800
+ const nextSections = [...sections];
1801
+ nextSections[sectionIndex] = {
1802
+ ...nextSections[sectionIndex],
1803
+ ...settings,
1804
+ pageSettings: {
1805
+ ...nextSections[sectionIndex].pageSettings,
1806
+ ...settings.pageSettings ?? {},
1807
+ margins: {
1808
+ ...nextSections[sectionIndex].pageSettings.margins,
1809
+ ...((_a = settings.pageSettings) == null ? void 0 : _a.margins) ?? {}
1901
1810
  }
1902
1811
  }
1903
- const nextParagraph2 = buildParagraphFromRuns(
1904
- paragraph,
1905
- [
1906
- ...sliceRuns(paragraph, 0, offset),
1907
- ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
1908
- ],
1909
- getStyleAtOffset(paragraph, offset)
1910
- );
1911
- const nextParagraphs2 = paragraphs.map(
1912
- (candidate, candidateIndex) => candidateIndex === index ? nextParagraph2 : candidate
1913
- );
1914
- return cloneStateWithParagraphs(
1915
- state,
1916
- nextParagraphs2,
1917
- withSelection(paragraphOffsetToPosition(nextParagraph2, offset))
1918
- );
1919
- }
1920
- if (index >= paragraphs.length - 1) {
1921
- return state;
1922
- }
1923
- const nextParagraph = paragraphs[index + 1];
1924
- const mergedParagraph = buildParagraphFromRuns(paragraph, [
1925
- ...paragraph.runs.map(cloneRun),
1926
- ...nextParagraph.runs.map(cloneRun)
1927
- ]);
1928
- const nextParagraphs = [
1929
- ...paragraphs.slice(0, index),
1930
- mergedParagraph,
1931
- ...paragraphs.slice(index + 2)
1932
- ];
1933
- return cloneStateWithParagraphs(
1934
- state,
1935
- nextParagraphs,
1936
- withSelection(paragraphOffsetToPosition(mergedParagraph, offset))
1937
- );
1812
+ };
1813
+ return {
1814
+ ...state,
1815
+ document: {
1816
+ ...state.document,
1817
+ sections: nextSections
1818
+ }
1819
+ };
1938
1820
  }
1939
- function toggleTextStyle(state, key) {
1821
+ function setParagraphNamedStyle(state, styleId) {
1822
+ return setParagraphStyle(state, "styleId", styleId);
1823
+ }
1824
+ function setParagraphStyle(state, key, value) {
1940
1825
  const normalized = normalizeSelection(state);
1941
- if (normalized.isCollapsed) {
1942
- return state;
1943
- }
1944
1826
  const paragraphs = getParagraphs(state);
1945
- const touchedParagraphs = paragraphs.slice(
1946
- normalized.startIndex,
1947
- normalized.endIndex + 1
1948
- );
1949
- const touchedRuns = touchedParagraphs.flatMap((paragraph, relativeIndex) => {
1950
- const paragraphIndex = normalized.startIndex + relativeIndex;
1951
- const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
1952
- const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
1953
- return sliceRuns(paragraph, startOffset, endOffset);
1954
- }).filter((run) => run.text.length > 0);
1955
- if (touchedRuns.length === 0) {
1956
- return state;
1957
- }
1958
- const shouldEnable = !touchedRuns.every((run) => {
1959
- var _a;
1960
- return Boolean((_a = run.styles) == null ? void 0 : _a[key]);
1961
- });
1827
+ const startIndex = normalized.startIndex;
1828
+ const endIndex = normalized.endIndex;
1962
1829
  const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
1963
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
1964
- return paragraph;
1830
+ if (paragraphIndex < startIndex || paragraphIndex > endIndex) {
1831
+ return cloneParagraph(paragraph);
1965
1832
  }
1966
- const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
1967
- const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
1968
- return mapRunsInRange(paragraph, startOffset, endOffset, (run) => ({
1969
- ...run,
1970
- styles: setBooleanStyle(run.styles, key, shouldEnable)
1971
- }));
1833
+ return {
1834
+ ...cloneParagraph(paragraph),
1835
+ style: setParagraphStyleValue(paragraph.style, key, value)
1836
+ };
1972
1837
  });
1973
1838
  return cloneStateWithParagraphs(
1974
1839
  state,
@@ -1976,1996 +1841,1259 @@ function toggleTextStyle(state, key) {
1976
1841
  preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
1977
1842
  );
1978
1843
  }
1979
- function isLetter(char) {
1980
- return new RegExp("\\p{L}", "u").test(char);
1844
+ function setStateSelection(state, selection) {
1845
+ return {
1846
+ document: state.document,
1847
+ selection
1848
+ };
1981
1849
  }
1982
- function toSentenceCase(text) {
1983
- let result = "";
1984
- let capitalizeNext = true;
1985
- for (const char of text.toLowerCase()) {
1986
- if (capitalizeNext && isLetter(char)) {
1987
- result += char.toUpperCase();
1988
- capitalizeNext = false;
1989
- } else {
1990
- result += char;
1991
- if (char === "." || char === "!" || char === "?") {
1992
- capitalizeNext = true;
1993
- }
1994
- }
1850
+ function moveVertical(state, delta) {
1851
+ if (!isSelectionCollapsed(state.selection)) {
1852
+ return collapseToBoundary(state, delta < 0 ? "start" : "end");
1995
1853
  }
1996
- return result;
1997
- }
1998
- function toCapitalizedWords(text) {
1999
- let result = "";
2000
- let prevIsLetter = false;
2001
- for (const char of text) {
2002
- const letter = isLetter(char);
2003
- result += letter && !prevIsLetter ? char.toUpperCase() : char;
2004
- prevIsLetter = letter;
1854
+ const { index, offset } = getFocusParagraph(state);
1855
+ const paragraphs = getParagraphs(state);
1856
+ const nextIndex = index + delta;
1857
+ if (nextIndex < 0 || nextIndex >= paragraphs.length) {
1858
+ return state;
2005
1859
  }
2006
- return result;
1860
+ const nextParagraph = paragraphs[nextIndex];
1861
+ return setStateSelection(
1862
+ state,
1863
+ withSelection(
1864
+ paragraphOffsetToPosition(
1865
+ nextParagraph,
1866
+ Math.min(offset, getParagraphLength(nextParagraph))
1867
+ )
1868
+ )
1869
+ );
2007
1870
  }
2008
- function toToggledCase(text) {
2009
- let result = "";
2010
- for (const char of text) {
2011
- const upper = char.toUpperCase();
2012
- const lower = char.toLowerCase();
2013
- if (char === lower && char !== upper) {
2014
- result += upper;
2015
- } else if (char === upper && char !== lower) {
2016
- result += lower;
2017
- } else {
2018
- result += char;
2019
- }
1871
+ function moveFocusHorizontally(state, delta) {
1872
+ const focus = clampPosition(state, state.selection.focus);
1873
+ const paragraphs = getParagraphs(state);
1874
+ const index = findParagraphIndex(paragraphs, focus.paragraphId);
1875
+ const paragraph = paragraphs[index];
1876
+ const paragraphOffset = positionToParagraphOffset(paragraph, focus);
1877
+ const paragraphLength = getParagraphLength(paragraph);
1878
+ if (delta < 0 && paragraphOffset > 0) {
1879
+ return setStateSelection(state, {
1880
+ anchor: state.selection.anchor,
1881
+ focus: paragraphOffsetToPosition(paragraph, paragraphOffset - 1)
1882
+ });
2020
1883
  }
2021
- return result;
2022
- }
2023
- function applyCaseTransform(text, mode) {
2024
- switch (mode) {
2025
- case "lower":
2026
- return text.toLowerCase();
2027
- case "upper":
2028
- return text.toUpperCase();
2029
- case "capitalize":
2030
- return toCapitalizedWords(text);
2031
- case "toggle":
2032
- return toToggledCase(text);
2033
- case "sentence":
2034
- default:
2035
- return toSentenceCase(text);
1884
+ if (delta > 0 && paragraphOffset < paragraphLength) {
1885
+ return setStateSelection(state, {
1886
+ anchor: state.selection.anchor,
1887
+ focus: paragraphOffsetToPosition(paragraph, paragraphOffset + 1)
1888
+ });
1889
+ }
1890
+ if (delta < 0 && index > 0) {
1891
+ const previousParagraph = paragraphs[index - 1];
1892
+ return setStateSelection(state, {
1893
+ anchor: state.selection.anchor,
1894
+ focus: paragraphOffsetToPosition(
1895
+ previousParagraph,
1896
+ getParagraphLength(previousParagraph)
1897
+ )
1898
+ });
1899
+ }
1900
+ if (delta > 0 && index < paragraphs.length - 1) {
1901
+ const nextParagraph = paragraphs[index + 1];
1902
+ return setStateSelection(state, {
1903
+ anchor: state.selection.anchor,
1904
+ focus: paragraphOffsetToPosition(nextParagraph, 0)
1905
+ });
2036
1906
  }
1907
+ return state;
2037
1908
  }
2038
- function transformSelectedText(state, transform) {
2039
- const normalized = normalizeSelection(state);
2040
- if (normalized.isCollapsed) {
1909
+ function moveFocusVertical(state, delta) {
1910
+ const focus = clampPosition(state, state.selection.focus);
1911
+ const paragraphs = getParagraphs(state);
1912
+ const index = findParagraphIndex(paragraphs, focus.paragraphId);
1913
+ const paragraph = paragraphs[index];
1914
+ const paragraphOffset = positionToParagraphOffset(paragraph, focus);
1915
+ const nextIndex = index + delta;
1916
+ if (nextIndex < 0 || nextIndex >= paragraphs.length) {
2041
1917
  return state;
2042
1918
  }
2043
- const paragraphs = getParagraphs(state);
2044
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2045
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2046
- return paragraph;
2047
- }
2048
- const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2049
- const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2050
- const selectedText = sliceRuns(paragraph, startOffset, endOffset).map((run) => run.text).join("");
2051
- const transformed = transform(selectedText);
2052
- let cursor = 0;
2053
- return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
2054
- const length = run.text.length;
2055
- const nextText = transformed.slice(cursor, cursor + length);
2056
- cursor += length;
2057
- return { ...run, text: nextText };
2058
- });
1919
+ const nextParagraph = paragraphs[nextIndex];
1920
+ return setStateSelection(state, {
1921
+ anchor: state.selection.anchor,
1922
+ focus: paragraphOffsetToPosition(
1923
+ nextParagraph,
1924
+ Math.min(paragraphOffset, getParagraphLength(nextParagraph))
1925
+ )
2059
1926
  });
2060
- return cloneStateWithParagraphs(
2061
- state,
2062
- nextParagraphs,
2063
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2064
- );
2065
- }
2066
- function changeSelectedTextCase(state, mode) {
2067
- return transformSelectedText(state, (text) => applyCaseTransform(text, mode));
2068
1927
  }
2069
- function clearSelectedTextFormatting(state) {
1928
+ function getSelectedText(state) {
2070
1929
  const normalized = normalizeSelection(state);
2071
1930
  if (normalized.isCollapsed) {
2072
- return state;
1931
+ return "";
2073
1932
  }
2074
1933
  const paragraphs = getParagraphs(state);
2075
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2076
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2077
- return paragraph;
2078
- }
2079
- const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2080
- const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2081
- return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
2082
- var _a;
2083
- const link = (_a = run.styles) == null ? void 0 : _a.link;
2084
- const styles = link != null && link !== "" ? { link } : {};
2085
- return { ...run, styles };
2086
- });
2087
- });
2088
- return cloneStateWithParagraphs(
2089
- state,
2090
- nextParagraphs,
2091
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
1934
+ if (normalized.startIndex === normalized.endIndex) {
1935
+ const paragraph = paragraphs[normalized.startIndex];
1936
+ const text = getParagraphText(paragraph);
1937
+ return text.slice(
1938
+ normalized.startParagraphOffset,
1939
+ normalized.endParagraphOffset
1940
+ );
1941
+ }
1942
+ const parts = [];
1943
+ const startParagraph = paragraphs[normalized.startIndex];
1944
+ const endParagraph = paragraphs[normalized.endIndex];
1945
+ parts.push(
1946
+ getParagraphText(startParagraph).slice(normalized.startParagraphOffset)
1947
+ );
1948
+ for (let index = normalized.startIndex + 1; index < normalized.endIndex; index += 1) {
1949
+ parts.push(getParagraphText(paragraphs[index]));
1950
+ }
1951
+ parts.push(
1952
+ getParagraphText(endParagraph).slice(0, normalized.endParagraphOffset)
2092
1953
  );
1954
+ return parts.join("\n");
2093
1955
  }
2094
- function setTextStyleValue(state, key, value) {
2095
- const normalized = normalizeSelection(state);
2096
- if (normalized.isCollapsed) {
2097
- return state;
1956
+ function setSelection(state, selection) {
1957
+ return {
1958
+ ...state,
1959
+ selection: {
1960
+ anchor: clampPosition(state, selection.anchor),
1961
+ focus: clampPosition(state, selection.focus)
1962
+ }
1963
+ };
1964
+ }
1965
+ function moveSelectionLeft(state) {
1966
+ if (!isSelectionCollapsed(state.selection)) {
1967
+ return collapseToBoundary(state, "start");
2098
1968
  }
1969
+ const { paragraph, index, offset } = getFocusParagraph(state);
2099
1970
  const paragraphs = getParagraphs(state);
2100
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2101
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2102
- return paragraph;
2103
- }
2104
- const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2105
- const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2106
- return mapRunsInRange(paragraph, startOffset, endOffset, (run) => ({
2107
- ...run,
2108
- styles: setValueStyle(run.styles, key, value)
2109
- }));
2110
- });
2111
- return cloneStateWithParagraphs(
2112
- state,
2113
- nextParagraphs,
2114
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2115
- );
2116
- }
2117
- function moveBlockToPosition(state, blockId, targetPosition) {
2118
- var _a;
2119
- let movedBlock;
2120
- const removeFromBlocks = (blocks) => {
2121
- const idx = blocks.findIndex((b) => b.id === blockId);
2122
- if (idx >= 0) {
2123
- movedBlock = blocks[idx];
2124
- return [...blocks.slice(0, idx), ...blocks.slice(idx + 1)];
2125
- }
2126
- return blocks;
2127
- };
2128
- const removeFromSections = (sections) => {
2129
- return sections.map((s) => ({
2130
- ...s,
2131
- blocks: removeFromBlocks(s.blocks),
2132
- header: s.header ? removeFromBlocks(s.header) : void 0,
2133
- footer: s.footer ? removeFromBlocks(s.footer) : void 0
2134
- }));
2135
- };
2136
- const nextDocument = { ...state.document };
2137
- if (nextDocument.sections && nextDocument.sections.length > 0) {
2138
- nextDocument.sections = removeFromSections(nextDocument.sections);
1971
+ if (offset > 0) {
1972
+ return {
1973
+ document: state.document,
1974
+ selection: withSelection(
1975
+ paragraphOffsetToPosition(paragraph, offset - 1)
1976
+ )
1977
+ };
2139
1978
  }
2140
- if (!movedBlock) {
1979
+ if (index === 0) {
2141
1980
  return state;
2142
1981
  }
2143
- const targetId = targetPosition.paragraphId;
2144
- if (movedBlock.type === "table") {
2145
- const internalParagraphs = getBlockParagraphs(movedBlock);
2146
- if (internalParagraphs.some((p) => p.id === targetId)) {
2147
- return state;
2148
- }
2149
- }
2150
- const insertIntoBlocks = (blocks) => {
2151
- const idx = blocks.findIndex((b) => {
2152
- if (b.id === targetId) return true;
2153
- if (b.type === "table") {
2154
- return getBlockParagraphs(b).some((p) => p.id === targetId);
2155
- }
2156
- return false;
2157
- });
2158
- if (idx < 0) return { nextBlocks: blocks, found: false };
2159
- const nextBlocks = [
2160
- ...blocks.slice(0, idx),
2161
- movedBlock,
2162
- ...blocks.slice(idx)
2163
- ];
2164
- return { nextBlocks, found: true };
1982
+ const previousParagraph = paragraphs[index - 1];
1983
+ return {
1984
+ document: state.document,
1985
+ selection: withSelection(
1986
+ paragraphOffsetToPosition(
1987
+ previousParagraph,
1988
+ getParagraphLength(previousParagraph)
1989
+ )
1990
+ )
2165
1991
  };
2166
- const activeIdx = getActiveSectionIndex(state);
2167
- const zone = getActiveZone(state);
2168
- const activeSection = (_a = nextDocument.sections) == null ? void 0 : _a[activeIdx];
2169
- const section = { ...activeSection };
2170
- let found = false;
2171
- if (zone === "header") {
2172
- const res = insertIntoBlocks(section.header ?? []);
2173
- section.header = res.nextBlocks;
2174
- found = res.found;
2175
- } else if (zone === "footer") {
2176
- const res = insertIntoBlocks(section.footer ?? []);
2177
- section.footer = res.nextBlocks;
2178
- found = res.found;
2179
- } else {
2180
- const res = insertIntoBlocks(section.blocks);
2181
- section.blocks = res.nextBlocks;
2182
- found = res.found;
1992
+ }
1993
+ function moveSelectionRight(state) {
1994
+ if (!isSelectionCollapsed(state.selection)) {
1995
+ return collapseToBoundary(state, "end");
2183
1996
  }
2184
- if (!found) {
2185
- section.blocks = [...section.blocks, movedBlock];
1997
+ const { paragraph, index, offset } = getFocusParagraph(state);
1998
+ const paragraphs = getParagraphs(state);
1999
+ const paragraphLength = getParagraphLength(paragraph);
2000
+ if (offset < paragraphLength) {
2001
+ return {
2002
+ document: state.document,
2003
+ selection: withSelection(
2004
+ paragraphOffsetToPosition(paragraph, offset + 1)
2005
+ )
2006
+ };
2186
2007
  }
2187
- nextDocument.sections = [...nextDocument.sections ?? []];
2188
- nextDocument.sections[activeIdx] = section;
2008
+ if (index >= paragraphs.length - 1) {
2009
+ return state;
2010
+ }
2011
+ const nextParagraph = paragraphs[index + 1];
2189
2012
  return {
2190
- ...state,
2191
- document: nextDocument
2013
+ document: state.document,
2014
+ selection: withSelection(paragraphOffsetToPosition(nextParagraph, 0))
2192
2015
  };
2193
2016
  }
2194
- function splitBlockAtSelection(state) {
2195
- const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2196
- const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2197
- const firstParagraph = buildParagraphFromRuns(
2198
- paragraph,
2199
- sliceRuns(paragraph, 0, offset),
2200
- getStyleAtOffset(paragraph, offset)
2201
- );
2202
- const secondRuns = sliceRuns(
2203
- paragraph,
2204
- offset,
2205
- getParagraphLength(paragraph)
2206
- );
2207
- const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
2208
- paragraph,
2209
- secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
2210
- ) : (() => {
2211
- const emptyParagraph = createEditorParagraph("");
2212
- emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
2213
- emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
2214
- return emptyParagraph;
2215
- })();
2216
- const paragraphs = getParagraphs(collapsedState);
2217
- const nextParagraphs = [
2218
- ...cloneParagraphs(paragraphs.slice(0, index)),
2219
- firstParagraph,
2220
- nextParagraph,
2221
- ...cloneParagraphs(paragraphs.slice(index + 1))
2222
- ];
2223
- return cloneStateWithParagraphs(
2224
- collapsedState,
2225
- nextParagraphs,
2226
- withSelection(paragraphOffsetToPosition(nextParagraph, 0))
2227
- );
2017
+ function moveSelectionUp(state) {
2018
+ return moveVertical(state, -1);
2228
2019
  }
2229
- function insertPageBreakAtSelection(state) {
2230
- const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2231
- const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2232
- const firstParagraph = buildParagraphFromRuns(
2233
- paragraph,
2234
- sliceRuns(paragraph, 0, offset),
2235
- getStyleAtOffset(paragraph, offset)
2236
- );
2237
- const secondRuns = sliceRuns(
2238
- paragraph,
2239
- offset,
2240
- getParagraphLength(paragraph)
2241
- );
2242
- const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
2243
- paragraph,
2244
- secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
2245
- ) : (() => {
2246
- const emptyParagraph = createEditorParagraph("");
2247
- emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
2248
- emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
2249
- return emptyParagraph;
2250
- })();
2251
- nextParagraph.style = {
2252
- ...paragraph.style ?? {},
2253
- pageBreakBefore: true
2254
- };
2255
- const paragraphs = getParagraphs(collapsedState);
2256
- const nextParagraphs = [
2257
- ...cloneParagraphs(paragraphs.slice(0, index)),
2258
- firstParagraph,
2259
- nextParagraph,
2260
- ...cloneParagraphs(paragraphs.slice(index + 1))
2261
- ];
2262
- return cloneStateWithParagraphs(
2263
- collapsedState,
2264
- nextParagraphs,
2265
- withSelection(paragraphOffsetToPosition(nextParagraph, 0))
2266
- );
2020
+ function moveSelectionDown(state) {
2021
+ return moveVertical(state, 1);
2267
2022
  }
2268
- function insertSectionBreakAtSelection(state, breakType) {
2269
- const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2270
- const { paragraph, offset } = getFocusParagraph(collapsedState);
2271
- const sections = getDocumentSections(collapsedState.document);
2272
- const activeSectionIndex = getActiveSectionIndex(collapsedState);
2273
- const zone = getActiveZone(collapsedState);
2274
- if (zone !== "main") {
2275
- return state;
2276
- }
2277
- const section = sections[activeSectionIndex];
2278
- if (!section) {
2279
- return state;
2023
+ function extendSelectionLeft(state) {
2024
+ return moveFocusHorizontally(state, -1);
2025
+ }
2026
+ function extendSelectionRight(state) {
2027
+ return moveFocusHorizontally(state, 1);
2028
+ }
2029
+ function extendSelectionUp(state) {
2030
+ return moveFocusVertical(state, -1);
2031
+ }
2032
+ function extendSelectionDown(state) {
2033
+ return moveFocusVertical(state, 1);
2034
+ }
2035
+ function ensureFootnotes(footnotes) {
2036
+ if (footnotes) return footnotes;
2037
+ return { items: {} };
2038
+ }
2039
+ function nextAutoMarker(document2) {
2040
+ var _a, _b;
2041
+ const footnotes = document2.footnotes;
2042
+ const format = ((_a = footnotes == null ? void 0 : footnotes.settings) == null ? void 0 : _a.numberFormat) ?? "decimal";
2043
+ const startAt = ((_b = footnotes == null ? void 0 : footnotes.settings) == null ? void 0 : _b.startAt) ?? 1;
2044
+ let autoCount = startAt - 1;
2045
+ const seen = /* @__PURE__ */ new Set();
2046
+ for (const { run } of iterateFootnoteReferenceRuns(document2)) {
2047
+ const ref = run.footnoteReference;
2048
+ if (!ref || ref.customMark) continue;
2049
+ if (seen.has(ref.footnoteId)) continue;
2050
+ seen.add(ref.footnoteId);
2051
+ autoCount += 1;
2280
2052
  }
2281
- const blockIndex = section.blocks.findIndex((block) => {
2282
- if (block.type === "paragraph") {
2283
- return block.id === paragraph.id;
2284
- }
2285
- return false;
2286
- });
2287
- if (blockIndex === -1) {
2053
+ return getFootnoteDisplayMarker(autoCount + 1, format);
2054
+ }
2055
+ function insertFootnote(state) {
2056
+ const zone = state.activeZone ?? "main";
2057
+ if (zone !== "main") {
2288
2058
  return state;
2289
2059
  }
2290
- const beforeBlocks = section.blocks.slice(0, blockIndex);
2291
- const afterBlocks = section.blocks.slice(blockIndex + 1);
2292
- const firstParagraph = buildParagraphFromRuns(
2293
- paragraph,
2294
- sliceRuns(paragraph, 0, offset),
2295
- getStyleAtOffset(paragraph, offset)
2060
+ const baseState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2061
+ const { paragraph, index, offset } = getFocusParagraph(baseState);
2062
+ const footnote = createEditorFootnote();
2063
+ const marker = nextAutoMarker(baseState.document);
2064
+ const referenceRun = createFootnoteReferenceRun(footnote.id, marker);
2065
+ const updatedParagraph = insertRunsAtOffset(paragraph, offset, [
2066
+ referenceRun
2067
+ ]);
2068
+ const paragraphs = getParagraphs(baseState);
2069
+ const nextParagraphs = paragraphs.map(
2070
+ (candidate, candidateIndex) => candidateIndex === index ? updatedParagraph : candidate
2296
2071
  );
2297
- const secondRuns = sliceRuns(
2298
- paragraph,
2299
- offset,
2300
- getParagraphLength(paragraph)
2072
+ const caretAfterMarker = paragraphOffsetToPosition(
2073
+ updatedParagraph,
2074
+ offset + marker.length
2301
2075
  );
2302
- const secondParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
2303
- paragraph,
2304
- secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
2305
- ) : (() => {
2306
- const emptyParagraph = createEditorParagraph("");
2307
- emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
2308
- emptyParagraph.list = paragraph.list ? { ...paragraph.list } : void 0;
2309
- return emptyParagraph;
2310
- })();
2311
- const newSectionId = `section:${Math.random().toString(36).slice(2, 9)}`;
2312
- const newSection = {
2313
- id: newSectionId,
2314
- blocks: [secondParagraph, ...afterBlocks],
2315
- pageSettings: { ...section.pageSettings },
2316
- header: section.header ? cloneBlocks(section.header) : void 0,
2317
- footer: section.footer ? cloneBlocks(section.footer) : void 0,
2318
- breakType
2319
- };
2320
- const updatedSection = {
2321
- ...section,
2322
- blocks: [...beforeBlocks, firstParagraph]
2076
+ const stateAfterInsert = cloneStateWithParagraphs(
2077
+ baseState,
2078
+ nextParagraphs,
2079
+ createCollapsedSelection(caretAfterMarker)
2080
+ );
2081
+ const footnotes = ensureFootnotes(stateAfterInsert.document.footnotes);
2082
+ const documentWithFootnote = {
2083
+ ...stateAfterInsert.document,
2084
+ footnotes: {
2085
+ ...footnotes,
2086
+ items: {
2087
+ ...footnotes.items,
2088
+ [footnote.id]: footnote
2089
+ }
2090
+ }
2323
2091
  };
2324
- const nextSections = [
2325
- ...sections.slice(0, activeSectionIndex),
2326
- updatedSection,
2327
- newSection,
2328
- ...sections.slice(activeSectionIndex + 1)
2329
- ];
2092
+ const documentWithRenumber = renumberFootnotes(documentWithFootnote);
2093
+ const bodyFirstParagraph = footnote.blocks.flatMap(getBlockParagraphs).find(Boolean);
2094
+ if (!bodyFirstParagraph) {
2095
+ return {
2096
+ ...stateAfterInsert,
2097
+ document: documentWithRenumber
2098
+ };
2099
+ }
2330
2100
  return {
2331
- ...collapsedState,
2332
- document: {
2333
- ...collapsedState.document,
2334
- sections: nextSections
2335
- },
2336
- activeSectionIndex: activeSectionIndex + 1,
2337
- selection: withSelection(paragraphOffsetToPosition(secondParagraph, 0))
2101
+ ...stateAfterInsert,
2102
+ document: documentWithRenumber,
2103
+ selection: createCollapsedSelection(
2104
+ paragraphOffsetToPosition(bodyFirstParagraph, 0)
2105
+ ),
2106
+ activeZone: "footnote",
2107
+ activeFootnoteId: footnote.id
2338
2108
  };
2339
2109
  }
2340
- function updateSectionSettings(state, sectionIndex, settings) {
2341
- var _a;
2342
- const sections = getDocumentSections(state.document);
2343
- if (sectionIndex < 0 || sectionIndex >= sections.length) {
2344
- return state;
2345
- }
2346
- const nextSections = [...sections];
2347
- nextSections[sectionIndex] = {
2348
- ...nextSections[sectionIndex],
2349
- ...settings,
2350
- pageSettings: {
2351
- ...nextSections[sectionIndex].pageSettings,
2352
- ...settings.pageSettings ?? {},
2353
- margins: {
2354
- ...nextSections[sectionIndex].pageSettings.margins,
2355
- ...((_a = settings.pageSettings) == null ? void 0 : _a.margins) ?? {}
2356
- }
2357
- }
2358
- };
2110
+ function toggleTrackChanges(state) {
2359
2111
  return {
2360
2112
  ...state,
2361
- document: {
2362
- ...state.document,
2363
- sections: nextSections
2364
- }
2113
+ trackChangesEnabled: !state.trackChangesEnabled
2365
2114
  };
2366
2115
  }
2367
- function setParagraphNamedStyle(state, styleId) {
2368
- return setParagraphStyle(state, "styleId", styleId);
2369
- }
2370
- function setParagraphStyle(state, key, value) {
2371
- const normalized = normalizeSelection(state);
2116
+ function acceptRevision(state, revisionId) {
2372
2117
  const paragraphs = getParagraphs(state);
2373
- const startIndex = normalized.startIndex;
2374
- const endIndex = normalized.endIndex;
2375
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2376
- if (paragraphIndex < startIndex || paragraphIndex > endIndex) {
2377
- return cloneParagraph(paragraph);
2118
+ const nextParagraphs = paragraphs.map((paragraph) => {
2119
+ const nextRuns = paragraph.runs.filter(
2120
+ (run) => {
2121
+ var _a;
2122
+ return !(((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "delete");
2123
+ }
2124
+ ).map((run) => {
2125
+ var _a;
2126
+ if (((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "insert") {
2127
+ const nextRun = { ...run };
2128
+ delete nextRun.revision;
2129
+ return nextRun;
2130
+ }
2131
+ return run;
2132
+ });
2133
+ if (nextRuns.length === paragraph.runs.length && nextRuns.every((run, i) => run === paragraph.runs[i])) {
2134
+ return paragraph;
2378
2135
  }
2379
- return {
2380
- ...cloneParagraph(paragraph),
2381
- style: setParagraphStyleValue(paragraph.style, key, value)
2382
- };
2136
+ return buildParagraphFromRuns(paragraph, nextRuns);
2383
2137
  });
2384
2138
  return cloneStateWithParagraphs(
2385
2139
  state,
2386
2140
  nextParagraphs,
2387
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2388
- );
2389
- }
2390
- function splitListItemAtSelection(state) {
2391
- const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2392
- const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2393
- const firstParagraph = buildParagraphFromRuns(
2394
- paragraph,
2395
- sliceRuns(paragraph, 0, offset),
2396
- getStyleAtOffset(paragraph, offset)
2397
- );
2398
- const secondRuns = sliceRuns(
2399
- paragraph,
2400
- offset,
2401
- getParagraphLength(paragraph)
2402
- );
2403
- const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
2404
- paragraph,
2405
- secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
2406
- ) : (() => {
2407
- const emptyParagraph = createEditorParagraph("");
2408
- emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
2409
- emptyParagraph.list = cloneParagraphList(paragraph.list);
2410
- return emptyParagraph;
2411
- })();
2412
- const paragraphs = getParagraphs(collapsedState);
2413
- const nextParagraphs = [
2414
- ...cloneParagraphs(paragraphs.slice(0, index)),
2415
- firstParagraph,
2416
- nextParagraph,
2417
- ...cloneParagraphs(paragraphs.slice(index + 1))
2418
- ];
2419
- return cloneStateWithParagraphs(
2420
- collapsedState,
2421
- nextParagraphs,
2422
- withSelection(paragraphOffsetToPosition(nextParagraph, 0))
2141
+ preserveSelectionByParagraphOffsets(
2142
+ nextParagraphs,
2143
+ normalizeSelection(state)
2144
+ )
2423
2145
  );
2424
2146
  }
2425
- function clearParagraphListAtSelection(state) {
2426
- const normalized = normalizeSelection(state);
2147
+ function rejectRevision(state, revisionId) {
2427
2148
  const paragraphs = getParagraphs(state);
2428
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2429
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2430
- return cloneParagraph(paragraph);
2149
+ const nextParagraphs = paragraphs.map((paragraph) => {
2150
+ const nextRuns = paragraph.runs.filter(
2151
+ (run) => {
2152
+ var _a;
2153
+ return !(((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "insert");
2154
+ }
2155
+ ).map((run) => {
2156
+ var _a;
2157
+ if (((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "delete") {
2158
+ const nextRun = { ...run };
2159
+ delete nextRun.revision;
2160
+ return nextRun;
2161
+ }
2162
+ return run;
2163
+ });
2164
+ if (nextRuns.length === paragraph.runs.length && nextRuns.every((run, i) => run === paragraph.runs[i])) {
2165
+ return paragraph;
2431
2166
  }
2432
- return clearParagraphList(paragraph);
2167
+ return buildParagraphFromRuns(paragraph, nextRuns);
2433
2168
  });
2434
2169
  return cloneStateWithParagraphs(
2435
2170
  state,
2436
2171
  nextParagraphs,
2437
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2172
+ preserveSelectionByParagraphOffsets(
2173
+ nextParagraphs,
2174
+ normalizeSelection(state)
2175
+ )
2438
2176
  );
2439
2177
  }
2440
- function indentParagraphList(state) {
2178
+ function acceptRevisionsInSelection(state) {
2179
+ var _a;
2441
2180
  const normalized = normalizeSelection(state);
2442
2181
  const paragraphs = getParagraphs(state);
2443
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2444
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2445
- return cloneParagraph(paragraph);
2446
- }
2447
- if (!paragraph.list) {
2448
- return cloneParagraph(paragraph);
2182
+ const revisionIds = /* @__PURE__ */ new Set();
2183
+ for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
2184
+ const paragraph = paragraphs[i];
2185
+ const startOffset = i === normalized.startIndex ? normalized.startParagraphOffset : 0;
2186
+ const endOffset = i === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2187
+ const runs = sliceRuns(paragraph, startOffset, endOffset);
2188
+ for (const run of runs) {
2189
+ if ((_a = run.revision) == null ? void 0 : _a.id) {
2190
+ revisionIds.add(run.revision.id);
2191
+ }
2449
2192
  }
2450
- return cloneParagraphWithListLevel(
2451
- paragraph,
2452
- (paragraph.list.level ?? 0) + 1
2453
- );
2454
- });
2455
- return cloneStateWithParagraphs(
2456
- state,
2457
- nextParagraphs,
2458
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2459
- );
2193
+ }
2194
+ let nextState = state;
2195
+ for (const revisionId of revisionIds) {
2196
+ nextState = acceptRevision(nextState, revisionId);
2197
+ }
2198
+ return nextState;
2460
2199
  }
2461
- function outdentParagraphList(state) {
2200
+ function rejectRevisionsInSelection(state) {
2201
+ var _a;
2462
2202
  const normalized = normalizeSelection(state);
2463
2203
  const paragraphs = getParagraphs(state);
2464
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2465
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2466
- return cloneParagraph(paragraph);
2467
- }
2468
- if (!paragraph.list) {
2469
- return cloneParagraph(paragraph);
2470
- }
2471
- const currentLevel = paragraph.list.level ?? 0;
2472
- if (currentLevel <= 0) {
2473
- return clearParagraphList(paragraph);
2204
+ const revisionIds = /* @__PURE__ */ new Set();
2205
+ for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
2206
+ const paragraph = paragraphs[i];
2207
+ const startOffset = i === normalized.startIndex ? normalized.startParagraphOffset : 0;
2208
+ const endOffset = i === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2209
+ const runs = sliceRuns(paragraph, startOffset, endOffset);
2210
+ for (const run of runs) {
2211
+ if ((_a = run.revision) == null ? void 0 : _a.id) {
2212
+ revisionIds.add(run.revision.id);
2213
+ }
2474
2214
  }
2475
- return cloneParagraphWithListLevel(paragraph, currentLevel - 1);
2476
- });
2477
- return cloneStateWithParagraphs(
2478
- state,
2479
- nextParagraphs,
2480
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2481
- );
2215
+ }
2216
+ let nextState = state;
2217
+ for (const revisionId of revisionIds) {
2218
+ nextState = rejectRevision(nextState, revisionId);
2219
+ }
2220
+ return nextState;
2482
2221
  }
2483
- function toggleParagraphList(state, kind) {
2484
- const normalized = normalizeSelection(state);
2485
- const paragraphs = getParagraphs(state);
2486
- const startIndex = normalized.startIndex;
2487
- const endIndex = normalized.endIndex;
2488
- const targetedParagraphs = paragraphs.slice(startIndex, endIndex + 1);
2489
- const shouldClear = targetedParagraphs.length > 0 && targetedParagraphs.every((paragraph) => {
2490
- var _a;
2491
- return ((_a = paragraph.list) == null ? void 0 : _a.kind) === kind;
2492
- });
2493
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2494
- var _a, _b, _c;
2495
- if (paragraphIndex < startIndex || paragraphIndex > endIndex) {
2496
- return cloneParagraph(paragraph);
2497
- }
2498
- const nextParagraph = cloneParagraph(paragraph);
2499
- if (shouldClear) {
2500
- delete nextParagraph.list;
2501
- return nextParagraph;
2502
- }
2503
- nextParagraph.list = {
2504
- kind,
2505
- level: ((_a = paragraph.list) == null ? void 0 : _a.level) ?? 0,
2506
- format: (_b = paragraph.list) == null ? void 0 : _b.format,
2507
- startAt: (_c = paragraph.list) == null ? void 0 : _c.startAt
2508
- };
2509
- return nextParagraph;
2510
- });
2511
- return cloneStateWithParagraphs(
2512
- state,
2513
- nextParagraphs,
2514
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2515
- );
2222
+ function cloneFragmentRuns(runs) {
2223
+ return runs.map(cloneRun);
2516
2224
  }
2517
- function setParagraphListFormat(state, format) {
2518
- const normalized = normalizeSelection(state);
2519
- const paragraphs = getParagraphs(state);
2520
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2521
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2522
- return cloneParagraph(paragraph);
2523
- }
2524
- if (!paragraph.list) {
2525
- return cloneParagraph(paragraph);
2526
- }
2527
- return {
2528
- ...cloneParagraph(paragraph),
2529
- list: {
2530
- ...paragraph.list,
2531
- format: format || void 0
2532
- }
2533
- };
2534
- });
2535
- return cloneStateWithParagraphs(
2536
- state,
2537
- nextParagraphs,
2538
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2539
- );
2225
+ function getRunsLength(runs) {
2226
+ return runs.reduce((total, run) => total + run.text.length, 0);
2540
2227
  }
2541
- function setParagraphListStartAt(state, startAt) {
2228
+ function collectSelectionFragments(state) {
2542
2229
  const normalized = normalizeSelection(state);
2230
+ if (normalized.isCollapsed) {
2231
+ return [];
2232
+ }
2543
2233
  const paragraphs = getParagraphs(state);
2544
- const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2545
- if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2546
- return cloneParagraph(paragraph);
2547
- }
2548
- if (!paragraph.list) {
2549
- return cloneParagraph(paragraph);
2550
- }
2551
- return {
2552
- ...cloneParagraph(paragraph),
2553
- list: {
2554
- ...paragraph.list,
2555
- startAt: startAt !== null ? startAt : void 0
2556
- }
2557
- };
2558
- });
2559
- return cloneStateWithParagraphs(
2560
- state,
2561
- nextParagraphs,
2562
- preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
2563
- );
2564
- }
2565
- function patchStyleValue(style2, key, value) {
2566
- const nextStyle = { ...style2 ?? {} };
2567
- if (value === null) {
2568
- delete nextStyle[key];
2569
- } else {
2570
- nextStyle[key] = value;
2234
+ const fragments = [];
2235
+ for (let index = normalized.startIndex; index <= normalized.endIndex; index += 1) {
2236
+ const paragraph = paragraphs[index];
2237
+ const startOffset = index === normalized.startIndex ? normalized.startParagraphOffset : 0;
2238
+ const endOffset = index === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2239
+ const runs = sliceRuns(paragraph, startOffset, endOffset);
2240
+ fragments.push({
2241
+ paragraphTemplate: cloneParagraph(paragraph),
2242
+ runs
2243
+ });
2571
2244
  }
2572
- return Object.keys(nextStyle).length > 0 ? nextStyle : void 0;
2573
- }
2574
- function updateStateSections(state, updateBlocks) {
2575
- const sections = getDocumentSections(state.document);
2576
- const nextSections = sections.map((section) => ({
2577
- ...section,
2578
- blocks: updateBlocks(section.blocks),
2579
- header: section.header ? updateBlocks(section.header) : void 0,
2580
- footer: section.footer ? updateBlocks(section.footer) : void 0
2581
- }));
2582
- return {
2583
- ...state,
2584
- document: {
2585
- ...state.document,
2586
- sections: nextSections
2587
- }
2588
- };
2589
- }
2590
- function updateTablesInBlocks(blocks, updateTable) {
2591
- return blocks.map((block) => {
2592
- if (block.type === "table") {
2593
- return updateTable(block);
2594
- }
2595
- return block;
2596
- });
2597
- }
2598
- function updateNestedTablesInBlocks(blocks, updateTable) {
2599
- return blocks.map((block) => {
2600
- if (block.type === "paragraph") return block;
2601
- return {
2602
- ...updateTable(block),
2603
- rows: block.rows.map((row) => ({
2604
- ...row,
2605
- cells: row.cells.map((cell) => ({
2606
- ...cell,
2607
- blocks: updateNestedTablesInBlocks(
2608
- cell.blocks,
2609
- updateTable
2610
- )
2611
- }))
2612
- }))
2613
- };
2614
- });
2615
- }
2616
- function getBlocksForZone(document2, sectionIndex, zone) {
2617
- const section = getDocumentSections(document2)[sectionIndex];
2618
- if (!section) return void 0;
2619
- if (zone === "header") return section.header;
2620
- if (zone === "footer") return section.footer;
2621
- return section.blocks;
2622
- }
2623
- function resolveActiveTableLocation(state) {
2624
- const activeSectionIndex = getActiveSectionIndex(state);
2625
- const loc = findParagraphTableLocation(
2626
- state.document,
2627
- state.selection.focus.paragraphId,
2628
- activeSectionIndex
2629
- );
2630
- return loc ? { activeSectionIndex, loc } : null;
2631
- }
2632
- function updateActiveTableBlocks(state, updateTable) {
2633
- const target = resolveActiveTableLocation(state);
2634
- if (!target) return state;
2635
- const { activeSectionIndex, loc } = target;
2636
- const activeZone = getActiveZone(state);
2637
- const updateBlocks = (blocks, zone) => blocks.map((block, blockIndex) => {
2638
- if (block.type === "table" && blockIndex === loc.blockIndex && zone === loc.zone) {
2639
- return updateTable(block);
2640
- }
2641
- return block;
2642
- });
2643
- const nextSections = getDocumentSections(state.document).map(
2644
- (section, sectionIndex) => {
2645
- if (sectionIndex !== activeSectionIndex) return section;
2646
- return {
2647
- ...section,
2648
- blocks: activeZone === "main" ? updateBlocks(section.blocks, "main") : section.blocks,
2649
- header: activeZone === "header" && section.header ? updateBlocks(section.header, "header") : section.header,
2650
- footer: activeZone === "footer" && section.footer ? updateBlocks(section.footer, "footer") : section.footer
2651
- };
2652
- }
2653
- );
2654
- return {
2655
- ...state,
2656
- document: {
2657
- ...state.document,
2658
- sections: nextSections
2659
- }
2660
- };
2245
+ return fragments;
2661
2246
  }
2662
- function collectTableSelectedParagraphIds(state) {
2663
- const selectedParagraphIds = /* @__PURE__ */ new Set();
2664
- const activeSectionIndex = getActiveSectionIndex(state);
2665
- const anchorLoc = findParagraphTableLocation(
2666
- state.document,
2667
- state.selection.anchor.paragraphId,
2668
- activeSectionIndex
2669
- );
2670
- const focusLoc = findParagraphTableLocation(
2671
- state.document,
2672
- state.selection.focus.paragraphId,
2673
- activeSectionIndex
2247
+ function insertFragmentsAtPosition(state, targetPosition, fragments) {
2248
+ if (fragments.length === 0) {
2249
+ return state;
2250
+ }
2251
+ const paragraphs = getParagraphs(state);
2252
+ const targetIndex = paragraphs.findIndex(
2253
+ (paragraph) => paragraph.id === targetPosition.paragraphId
2674
2254
  );
2675
- if (!anchorLoc || !focusLoc || anchorLoc.blockIndex !== focusLoc.blockIndex || anchorLoc.zone !== focusLoc.zone) {
2676
- return selectedParagraphIds;
2255
+ if (targetIndex === -1) {
2256
+ return state;
2677
2257
  }
2678
- const blocks = getBlocksForZone(
2679
- state.document,
2680
- activeSectionIndex,
2681
- anchorLoc.zone
2258
+ const targetParagraph = paragraphs[targetIndex];
2259
+ const targetOffset = positionToParagraphOffset(
2260
+ targetParagraph,
2261
+ targetPosition
2682
2262
  );
2683
- const tableBlock = blocks == null ? void 0 : blocks[anchorLoc.blockIndex];
2684
- if (!tableBlock || tableBlock.type !== "table") {
2685
- return selectedParagraphIds;
2263
+ const firstRuns = cloneFragmentRuns(fragments[0].runs);
2264
+ if (fragments.length === 1) {
2265
+ const nextTarget = insertRunsAtOffset(
2266
+ targetParagraph,
2267
+ targetOffset,
2268
+ firstRuns
2269
+ );
2270
+ const nextParagraphs2 = paragraphs.map(
2271
+ (candidate, index) => index === targetIndex ? nextTarget : candidate
2272
+ );
2273
+ const insertedLength = getRunsLength(firstRuns);
2274
+ const anchor2 = paragraphOffsetToPosition(nextTarget, targetOffset);
2275
+ const focus2 = paragraphOffsetToPosition(
2276
+ nextTarget,
2277
+ targetOffset + insertedLength
2278
+ );
2279
+ return cloneStateWithParagraphs(state, nextParagraphs2, {
2280
+ anchor: anchor2,
2281
+ focus: focus2
2282
+ });
2686
2283
  }
2687
- const tableLayout = buildTableCellLayout(tableBlock);
2688
- const anchorCell = tableLayout.find(
2689
- (entry) => entry.rowIndex === anchorLoc.rowIndex && entry.cellIndex === anchorLoc.cellIndex
2284
+ const beforeRuns = sliceRuns(targetParagraph, 0, targetOffset);
2285
+ const afterRuns = sliceRuns(
2286
+ targetParagraph,
2287
+ targetOffset,
2288
+ getParagraphLength(targetParagraph)
2690
2289
  );
2691
- const focusCell = tableLayout.find(
2692
- (entry) => entry.rowIndex === focusLoc.rowIndex && entry.cellIndex === focusLoc.cellIndex
2290
+ const lastFragment = fragments[fragments.length - 1];
2291
+ const middleFragments = fragments.slice(1, -1);
2292
+ const firstInserted = buildParagraphFromRuns(
2293
+ cloneParagraph(fragments[0].paragraphTemplate),
2294
+ [...beforeRuns, ...firstRuns],
2295
+ getStyleAtOffset(targetParagraph, targetOffset)
2693
2296
  );
2694
- if (!anchorCell || !focusCell) {
2695
- return selectedParagraphIds;
2696
- }
2697
- const startRow = Math.min(
2698
- anchorCell.visualRowIndex,
2699
- focusCell.visualRowIndex
2297
+ const insertedMiddle = middleFragments.map(
2298
+ (fragment) => buildParagraphFromRuns(
2299
+ cloneParagraph(fragment.paragraphTemplate),
2300
+ cloneFragmentRuns(fragment.runs)
2301
+ )
2700
2302
  );
2701
- const endRow = Math.max(
2702
- anchorCell.visualRowIndex + anchorCell.rowSpan - 1,
2703
- focusCell.visualRowIndex + focusCell.rowSpan - 1
2303
+ const lastInserted = buildParagraphFromRuns(
2304
+ cloneParagraph(lastFragment.paragraphTemplate),
2305
+ [...cloneFragmentRuns(lastFragment.runs), ...afterRuns],
2306
+ getStyleAtOffset(targetParagraph, targetOffset)
2704
2307
  );
2705
- const startCol = Math.min(
2706
- anchorCell.visualColumnIndex,
2707
- focusCell.visualColumnIndex
2308
+ const nextParagraphs = [
2309
+ ...paragraphs.slice(0, targetIndex),
2310
+ firstInserted,
2311
+ ...insertedMiddle,
2312
+ lastInserted,
2313
+ ...paragraphs.slice(targetIndex + 1)
2314
+ ];
2315
+ const anchor = paragraphOffsetToPosition(
2316
+ firstInserted,
2317
+ getRunsLength(beforeRuns)
2708
2318
  );
2709
- const endCol = Math.max(
2710
- anchorCell.visualColumnIndex + anchorCell.colSpan - 1,
2711
- focusCell.visualColumnIndex + focusCell.colSpan - 1
2319
+ const focus = paragraphOffsetToPosition(
2320
+ lastInserted,
2321
+ getRunsLength(lastFragment.runs)
2712
2322
  );
2713
- const cells = tableLayout.filter(
2714
- (entry) => entry.visualRowIndex <= endRow && entry.visualRowIndex + entry.rowSpan - 1 >= startRow && entry.visualColumnIndex <= endCol && entry.visualColumnIndex + entry.colSpan - 1 >= startCol
2323
+ return cloneStateWithParagraphs(state, nextParagraphs, { anchor, focus });
2324
+ }
2325
+ function isTargetInsideSelection(state, targetPosition) {
2326
+ const normalized = normalizeSelection(state);
2327
+ if (normalized.isCollapsed) {
2328
+ return false;
2329
+ }
2330
+ const paragraphs = getParagraphs(state);
2331
+ const targetIndex = paragraphs.findIndex(
2332
+ (paragraph2) => paragraph2.id === targetPosition.paragraphId
2715
2333
  );
2716
- for (const entry of cells) {
2717
- for (const paragraph of entry.cell.blocks) {
2718
- selectedParagraphIds.add(paragraph.id);
2719
- }
2334
+ if (targetIndex === -1) {
2335
+ return false;
2720
2336
  }
2721
- return selectedParagraphIds;
2337
+ if (targetIndex < normalized.startIndex || targetIndex > normalized.endIndex) {
2338
+ return false;
2339
+ }
2340
+ const paragraph = paragraphs[targetIndex];
2341
+ const targetOffset = positionToParagraphOffset(paragraph, targetPosition);
2342
+ if (targetIndex === normalized.startIndex && targetOffset < normalized.startParagraphOffset) {
2343
+ return false;
2344
+ }
2345
+ if (targetIndex === normalized.endIndex && targetOffset > normalized.endParagraphOffset) {
2346
+ return false;
2347
+ }
2348
+ return true;
2722
2349
  }
2723
- function collectLinearSelectedParagraphIds$1(state) {
2724
- const selectedParagraphIds = /* @__PURE__ */ new Set();
2350
+ function mapTargetAfterDelete(state, targetPosition) {
2725
2351
  const normalized = normalizeSelection(state);
2726
2352
  const paragraphs = getParagraphs(state);
2727
- for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
2728
- selectedParagraphIds.add(paragraphs[i].id);
2353
+ const targetIndex = paragraphs.findIndex(
2354
+ (paragraph) => paragraph.id === targetPosition.paragraphId
2355
+ );
2356
+ if (targetIndex === -1) {
2357
+ return targetPosition;
2729
2358
  }
2730
- return selectedParagraphIds;
2731
- }
2732
- function setTableCellStyleValue(state, key, value) {
2733
- const selectedParagraphIds = collectTableSelectedParagraphIds(state);
2734
- if (selectedParagraphIds.size === 0) {
2735
- for (const id of collectLinearSelectedParagraphIds$1(state)) {
2736
- selectedParagraphIds.add(id);
2359
+ const targetParagraph = paragraphs[targetIndex];
2360
+ const targetOffset = positionToParagraphOffset(
2361
+ targetParagraph,
2362
+ targetPosition
2363
+ );
2364
+ if (normalized.startIndex === normalized.endIndex) {
2365
+ if (targetIndex !== normalized.startIndex || targetOffset <= normalized.endParagraphOffset) {
2366
+ return targetPosition;
2737
2367
  }
2368
+ const startParagraph = paragraphs[normalized.startIndex];
2369
+ return paragraphOffsetToPosition(
2370
+ startParagraph,
2371
+ targetOffset - (normalized.endParagraphOffset - normalized.startParagraphOffset)
2372
+ );
2738
2373
  }
2739
- const updateCell = (cell) => ({
2740
- ...cell,
2741
- style: patchStyleValue(cell.style, key, value)
2742
- });
2743
- const nextSections = getDocumentSections(state.document).map((section) => ({
2744
- ...section,
2745
- blocks: updateTableCellsInBlocks(
2746
- section.blocks,
2747
- selectedParagraphIds,
2748
- updateCell
2749
- ),
2750
- header: section.header ? updateTableCellsInBlocks(
2751
- section.header,
2752
- selectedParagraphIds,
2753
- updateCell
2754
- ) : void 0,
2755
- footer: section.footer ? updateTableCellsInBlocks(
2756
- section.footer,
2757
- selectedParagraphIds,
2758
- updateCell
2759
- ) : void 0
2760
- }));
2761
- return {
2762
- ...state,
2763
- document: {
2764
- ...state.document,
2765
- sections: nextSections
2766
- }
2767
- };
2768
- }
2769
- function setTableCellWidth(state, width) {
2770
- return setTableCellStyleValue(state, "width", width);
2771
- }
2772
- function setTableCellBorders(state, border) {
2773
- let nextState = setTableCellStyleValue(state, "borderTop", border);
2774
- nextState = setTableCellStyleValue(nextState, "borderRight", border);
2775
- nextState = setTableCellStyleValue(nextState, "borderBottom", border);
2776
- nextState = setTableCellStyleValue(nextState, "borderLeft", border);
2777
- return nextState;
2374
+ return targetPosition;
2778
2375
  }
2779
- function collectLinearSelectedParagraphIds(state) {
2376
+ function moveOrCopySelectionToPosition(state, targetPosition, options = {}) {
2780
2377
  const normalized = normalizeSelection(state);
2781
- const paragraphs = getParagraphs(state);
2782
- const selectedParagraphIds = /* @__PURE__ */ new Set();
2783
- for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
2784
- selectedParagraphIds.add(paragraphs[i].id);
2378
+ if (normalized.isCollapsed) {
2379
+ return state;
2785
2380
  }
2786
- return selectedParagraphIds;
2381
+ if (isTargetInsideSelection(state, targetPosition)) {
2382
+ return state;
2383
+ }
2384
+ const fragments = collectSelectionFragments(state);
2385
+ if (fragments.length === 0) {
2386
+ return state;
2387
+ }
2388
+ if (options.copy) {
2389
+ return insertFragmentsAtPosition(state, targetPosition, fragments);
2390
+ }
2391
+ const mappedTarget = mapTargetAfterDelete(state, targetPosition);
2392
+ const deleted = deleteSelectionRange(state);
2393
+ return insertFragmentsAtPosition(deleted, mappedTarget, fragments);
2787
2394
  }
2788
- function setTableStyleValue(state, key, value) {
2789
- const selectedParagraphIds = collectLinearSelectedParagraphIds(state);
2790
- const updateTable = (table) => ({
2791
- ...table,
2792
- style: patchStyleValue(table.style, key, value)
2793
- });
2794
- const updateBlocks = (blocks) => {
2795
- return blocks.map((block) => {
2796
- if (block.type === "paragraph") return block;
2797
- const paragraphsInTable = getBlockParagraphs(block);
2798
- const isSelected = paragraphsInTable.some(
2799
- (paragraph) => selectedParagraphIds.has(paragraph.id)
2800
- );
2801
- const updatedRows = block.rows.map((row) => ({
2802
- ...row,
2803
- cells: row.cells.map((cell) => ({
2804
- ...cell,
2805
- blocks: updateBlocks(cell.blocks)
2806
- }))
2807
- }));
2808
- const nextTable = { ...block, rows: updatedRows };
2809
- return isSelected ? updateTable(nextTable) : nextTable;
2810
- });
2395
+ function insertTextAtSelection(state, text, styleOverride) {
2396
+ if (text.length === 0) {
2397
+ return state;
2398
+ }
2399
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2400
+ const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2401
+ const styles = styleOverride ? { ...styleOverride } : getStyleAtOffset(paragraph, offset);
2402
+ const insertedRun = {
2403
+ id: `run:${Math.random().toString(36).slice(2, 9)}`,
2404
+ text,
2405
+ styles
2811
2406
  };
2812
- return updateStateSections(state, updateBlocks);
2813
- }
2814
- function setActiveTableStyleValue(state, tableId, key, value) {
2815
- const updateTable = (table) => {
2816
- if (table.id !== tableId) return table;
2817
- return {
2818
- ...table,
2819
- style: patchStyleValue(table.style, key, value)
2407
+ if (collapsedState.trackChangesEnabled) {
2408
+ insertedRun.revision = {
2409
+ id: `rev:${Math.random().toString(36).slice(2, 9)}`,
2410
+ type: "insert",
2411
+ author: "User",
2412
+ date: Date.now()
2820
2413
  };
2821
- };
2822
- return updateStateSections(
2823
- state,
2824
- (blocks) => updateNestedTablesInBlocks(blocks, updateTable)
2414
+ }
2415
+ const nextParagraph = insertRunsAtOffset(paragraph, offset, [insertedRun]);
2416
+ const paragraphs = getParagraphs(collapsedState);
2417
+ const nextParagraphs = paragraphs.map(
2418
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : candidate
2419
+ );
2420
+ return cloneStateWithParagraphs(
2421
+ collapsedState,
2422
+ nextParagraphs,
2423
+ withSelection(
2424
+ paragraphOffsetToPosition(nextParagraph, offset + text.length)
2425
+ )
2825
2426
  );
2826
2427
  }
2827
- function setSelectedTableRowStyleValue(state, key, value) {
2828
- const target = resolveActiveTableLocation(state);
2829
- if (!target) return state;
2830
- const updateTable = (table) => {
2831
- const nextRows = table.rows.map(
2832
- (row, rowIndex) => rowIndex === target.loc.rowIndex ? { ...row, style: patchStyleValue(row.style, key, value) } : row
2833
- );
2834
- return { ...table, rows: nextRows };
2835
- };
2836
- return updateActiveTableBlocks(state, updateTable);
2837
- }
2838
- function setSelectedTableRowHeader(state, value) {
2839
- const target = resolveActiveTableLocation(state);
2840
- if (!target) return state;
2841
- const updateTable = (table) => ({
2842
- ...table,
2843
- rows: table.rows.map(
2844
- (row, rowIndex) => rowIndex === target.loc.rowIndex ? { ...row, isHeader: value === null ? void 0 : value } : row
2845
- )
2846
- });
2847
- return updateActiveTableBlocks(state, updateTable);
2848
- }
2849
- function setTableRowHeight(state, tableId, rowIndex, height) {
2850
- const updateTable = (table) => {
2851
- if (table.id !== tableId) return table;
2852
- const nextRows = [...table.rows];
2853
- const row = nextRows[rowIndex];
2854
- if (row) {
2855
- nextRows[rowIndex] = {
2856
- ...row,
2857
- style: patchStyleValue(row.style, "height", height)
2858
- };
2859
- }
2860
- return { ...table, rows: nextRows };
2861
- };
2862
- return updateStateSections(
2863
- state,
2864
- (blocks) => updateTablesInBlocks(blocks, updateTable)
2865
- );
2866
- }
2867
- function parseWidthToPt(value) {
2868
- if (typeof value === "number" && Number.isFinite(value)) {
2869
- return value;
2870
- }
2871
- if (typeof value !== "string") {
2872
- return null;
2873
- }
2874
- const trimmed = value.trim().toLowerCase();
2875
- if (!trimmed || trimmed.includes("%")) {
2876
- return null;
2877
- }
2878
- if (trimmed.endsWith("pt")) {
2879
- const parsed2 = Number.parseFloat(trimmed.slice(0, -2));
2880
- return Number.isFinite(parsed2) ? parsed2 : null;
2881
- }
2882
- if (trimmed.endsWith("px")) {
2883
- const parsed2 = Number.parseFloat(trimmed.slice(0, -2));
2884
- return Number.isFinite(parsed2) ? parsed2 * PT_PER_PX : null;
2428
+ function insertPlainTextAtSelection(state, text, styleOverride) {
2429
+ if (text.length === 0) {
2430
+ return state;
2885
2431
  }
2886
- if (!/^[+-]?\d+(\.\d+)?$/.test(trimmed)) {
2887
- return null;
2432
+ const normalizedText = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2433
+ if (!normalizedText.includes("\n")) {
2434
+ return insertTextAtSelection(state, normalizedText, styleOverride);
2888
2435
  }
2889
- const parsed = Number.parseFloat(trimmed);
2890
- return Number.isFinite(parsed) ? parsed : null;
2891
- }
2892
- function setTableColumnWidths(state, tableId, columnWidths, tableWidth, tableIndentLeft) {
2893
- const updateTable = (table) => {
2894
- var _a;
2895
- if (table.id !== tableId) return table;
2896
- const tableLayout = buildTableCellLayout(table);
2897
- const visualColumnCount = Math.max(
2898
- 1,
2899
- ...tableLayout.map(
2900
- (entry) => entry.visualColumnIndex + Math.max(1, entry.colSpan)
2901
- )
2902
- );
2903
- const nextGridCols = Array(visualColumnCount);
2904
- let hasGridOverride = false;
2905
- let canResolveGrid = true;
2906
- for (let columnIndex = 0; columnIndex < visualColumnCount; columnIndex += 1) {
2907
- const override = parseWidthToPt(columnWidths[columnIndex]);
2908
- if (override !== null) {
2909
- nextGridCols[columnIndex] = Math.max(1, override);
2910
- hasGridOverride = true;
2911
- continue;
2912
- }
2913
- const existing = (_a = table.gridCols) == null ? void 0 : _a[columnIndex];
2914
- if (typeof existing === "number" && Number.isFinite(existing) && existing > 0) {
2915
- nextGridCols[columnIndex] = existing;
2916
- continue;
2917
- }
2918
- canResolveGrid = false;
2919
- break;
2920
- }
2921
- const nextRows = table.rows.map((row, rowIndex) => {
2922
- const nextCells = row.cells.map((cell, cellIndex) => {
2923
- const entry = tableLayout.find(
2924
- (item) => item.rowIndex === rowIndex && item.cellIndex === cellIndex
2925
- );
2926
- if (!entry) return cell;
2927
- const rightVisualColumnIndex = entry.visualColumnIndex + entry.colSpan - 1;
2928
- const newWidth = columnWidths[rightVisualColumnIndex];
2929
- if (newWidth !== void 0 && entry.colSpan === 1) {
2930
- return {
2931
- ...cell,
2932
- style: {
2933
- ...cell.style ?? {},
2934
- width: typeof newWidth === "number" ? newWidth : newWidth
2935
- }
2936
- };
2937
- }
2938
- return cell;
2939
- });
2940
- return { ...row, cells: nextCells };
2941
- });
2942
- const nextStyle = { ...table.style ?? {} };
2943
- if (tableWidth !== void 0) {
2944
- nextStyle.width = tableWidth;
2945
- }
2946
- if (tableIndentLeft !== void 0) {
2947
- nextStyle.indentLeft = typeof tableIndentLeft === "number" ? tableIndentLeft : Number(tableIndentLeft);
2948
- }
2949
- return {
2950
- ...table,
2951
- rows: nextRows,
2952
- gridCols: hasGridOverride && canResolveGrid ? nextGridCols : table.gridCols,
2953
- style: Object.keys(nextStyle).length > 0 ? nextStyle : void 0
2954
- };
2955
- };
2956
- return updateStateSections(
2957
- state,
2958
- (blocks) => updateTablesInBlocks(blocks, updateTable)
2436
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
2437
+ const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2438
+ const lines = normalizedText.split("\n");
2439
+ const insertionStyles = getStyleAtOffset(paragraph, offset);
2440
+ const beforeRuns = sliceRuns(paragraph, 0, offset);
2441
+ const firstParagraph = buildParagraphFromRuns(
2442
+ paragraph,
2443
+ [...beforeRuns, createEditorStyledRun(lines[0], insertionStyles)],
2444
+ insertionStyles
2959
2445
  );
2960
- }
2961
- function insertTableAtSelection(state, rows, cols) {
2962
- const initialCellWidth = `${100 / Math.max(1, cols)}%`;
2963
- const tableRows = [];
2964
- for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
2965
- const cells = [];
2966
- for (let columnIndex = 0; columnIndex < cols; columnIndex += 1) {
2967
- cells.push({
2968
- ...createEditorTableCell([createEditorParagraph("")]),
2969
- style: {
2970
- width: initialCellWidth
2971
- }
2972
- });
2973
- }
2974
- tableRows.push(createEditorTableRow(cells));
2975
- }
2976
- const table = {
2977
- ...createEditorTable(tableRows),
2978
- style: {
2979
- width: "100%"
2980
- }
2981
- };
2982
- const focus = clampPosition(state, state.selection.focus);
2983
- const sections = getDocumentSections(state.document);
2984
- const activeSectionIndex = getActiveSectionIndex(state);
2985
- const zone = getActiveZone(state);
2986
- const insertIntoBlocks = (blocks) => {
2987
- const blockIndex = blocks.findIndex((block) => {
2988
- if (block.id === focus.paragraphId) return true;
2989
- if (block.type === "paragraph") return false;
2990
- return getBlockParagraphs(block).some(
2991
- (paragraph) => paragraph.id === focus.paragraphId
2992
- );
2993
- });
2994
- if (blockIndex === -1) {
2995
- return { nextBlocks: blocks, found: false };
2996
- }
2997
- return {
2998
- nextBlocks: [
2999
- ...blocks.slice(0, blockIndex + 1),
3000
- table,
3001
- ...blocks.slice(blockIndex + 1)
3002
- ],
3003
- found: true
3004
- };
3005
- };
3006
- const section = sections[activeSectionIndex];
3007
- if (!section) return state;
3008
- const nextSection = { ...section };
3009
- let found = false;
3010
- if (zone === "header") {
3011
- const result = insertIntoBlocks(section.header ?? []);
3012
- nextSection.header = result.nextBlocks;
3013
- found = result.found;
3014
- } else if (zone === "footer") {
3015
- const result = insertIntoBlocks(section.footer ?? []);
3016
- nextSection.footer = result.nextBlocks;
3017
- found = result.found;
3018
- } else {
3019
- const result = insertIntoBlocks(section.blocks);
3020
- nextSection.blocks = result.nextBlocks;
3021
- found = result.found;
3022
- }
3023
- if (!found) return state;
3024
- const nextSections = [...sections];
3025
- nextSections[activeSectionIndex] = nextSection;
3026
- return {
3027
- ...state,
3028
- document: {
3029
- ...state.document,
3030
- sections: nextSections
3031
- },
3032
- selection: withSelection(
3033
- paragraphOffsetToPosition(table.rows[0].cells[0].blocks[0], 0)
3034
- )
3035
- };
3036
- }
3037
- function setStateSelection(state, selection) {
3038
- return {
3039
- document: state.document,
3040
- selection
3041
- };
3042
- }
3043
- function moveVertical(state, delta) {
3044
- if (!isSelectionCollapsed(state.selection)) {
3045
- return collapseToBoundary(state, delta < 0 ? "start" : "end");
3046
- }
3047
- const { index, offset } = getFocusParagraph(state);
3048
- const paragraphs = getParagraphs(state);
3049
- const nextIndex = index + delta;
3050
- if (nextIndex < 0 || nextIndex >= paragraphs.length) {
3051
- return state;
3052
- }
3053
- const nextParagraph = paragraphs[nextIndex];
3054
- return setStateSelection(
3055
- state,
3056
- withSelection(
3057
- paragraphOffsetToPosition(
3058
- nextParagraph,
3059
- Math.min(offset, getParagraphLength(nextParagraph))
3060
- )
3061
- )
2446
+ const tailRuns = sliceRuns(paragraph, offset, getParagraphLength(paragraph));
2447
+ const middleParagraphs = lines.slice(1, -1).map(
2448
+ (line) => createParagraphFromRuns([{ text: line, styles: insertionStyles }])
3062
2449
  );
3063
- }
3064
- function moveFocusHorizontally(state, delta) {
3065
- const focus = clampPosition(state, state.selection.focus);
3066
- const paragraphs = getParagraphs(state);
3067
- const index = findParagraphIndex(paragraphs, focus.paragraphId);
3068
- const paragraph = paragraphs[index];
3069
- const paragraphOffset = positionToParagraphOffset(paragraph, focus);
3070
- const paragraphLength = getParagraphLength(paragraph);
3071
- if (delta < 0 && paragraphOffset > 0) {
3072
- return setStateSelection(state, {
3073
- anchor: state.selection.anchor,
3074
- focus: paragraphOffsetToPosition(paragraph, paragraphOffset - 1)
3075
- });
3076
- }
3077
- if (delta > 0 && paragraphOffset < paragraphLength) {
3078
- return setStateSelection(state, {
3079
- anchor: state.selection.anchor,
3080
- focus: paragraphOffsetToPosition(paragraph, paragraphOffset + 1)
3081
- });
3082
- }
3083
- if (delta < 0 && index > 0) {
3084
- const previousParagraph = paragraphs[index - 1];
3085
- return setStateSelection(state, {
3086
- anchor: state.selection.anchor,
3087
- focus: paragraphOffsetToPosition(
3088
- previousParagraph,
3089
- getParagraphLength(previousParagraph)
3090
- )
3091
- });
3092
- }
3093
- if (delta > 0 && index < paragraphs.length - 1) {
3094
- const nextParagraph = paragraphs[index + 1];
3095
- return setStateSelection(state, {
3096
- anchor: state.selection.anchor,
3097
- focus: paragraphOffsetToPosition(nextParagraph, 0)
3098
- });
3099
- }
3100
- return state;
3101
- }
3102
- function moveFocusVertical(state, delta) {
3103
- const focus = clampPosition(state, state.selection.focus);
3104
- const paragraphs = getParagraphs(state);
3105
- const index = findParagraphIndex(paragraphs, focus.paragraphId);
3106
- const paragraph = paragraphs[index];
3107
- const paragraphOffset = positionToParagraphOffset(paragraph, focus);
3108
- const nextIndex = index + delta;
3109
- if (nextIndex < 0 || nextIndex >= paragraphs.length) {
3110
- return state;
3111
- }
3112
- const nextParagraph = paragraphs[nextIndex];
3113
- return setStateSelection(state, {
3114
- anchor: state.selection.anchor,
3115
- focus: paragraphOffsetToPosition(
3116
- nextParagraph,
3117
- Math.min(paragraphOffset, getParagraphLength(nextParagraph))
2450
+ const lastParagraph = createParagraphFromRuns([
2451
+ { text: lines[lines.length - 1], styles: insertionStyles },
2452
+ ...tailRuns.map((run) => ({ text: run.text, styles: run.styles }))
2453
+ ]);
2454
+ const paragraphs = getParagraphs(collapsedState);
2455
+ const nextParagraphs = [
2456
+ ...paragraphs.slice(0, index),
2457
+ firstParagraph,
2458
+ ...middleParagraphs,
2459
+ lastParagraph,
2460
+ ...paragraphs.slice(index + 1)
2461
+ ];
2462
+ return cloneStateWithParagraphs(
2463
+ collapsedState,
2464
+ nextParagraphs,
2465
+ withSelection(
2466
+ paragraphOffsetToPosition(lastParagraph, lines[lines.length - 1].length)
3118
2467
  )
3119
- });
3120
- }
3121
- function getSelectedText(state) {
3122
- const normalized = normalizeSelection(state);
3123
- if (normalized.isCollapsed) {
3124
- return "";
3125
- }
3126
- const paragraphs = getParagraphs(state);
3127
- if (normalized.startIndex === normalized.endIndex) {
3128
- const paragraph = paragraphs[normalized.startIndex];
3129
- const text = getParagraphText(paragraph);
3130
- return text.slice(
3131
- normalized.startParagraphOffset,
3132
- normalized.endParagraphOffset
3133
- );
3134
- }
3135
- const parts = [];
3136
- const startParagraph = paragraphs[normalized.startIndex];
3137
- const endParagraph = paragraphs[normalized.endIndex];
3138
- parts.push(
3139
- getParagraphText(startParagraph).slice(normalized.startParagraphOffset)
3140
- );
3141
- for (let index = normalized.startIndex + 1; index < normalized.endIndex; index += 1) {
3142
- parts.push(getParagraphText(paragraphs[index]));
3143
- }
3144
- parts.push(
3145
- getParagraphText(endParagraph).slice(0, normalized.endParagraphOffset)
3146
2468
  );
3147
- return parts.join("\n");
3148
- }
3149
- function setSelection(state, selection) {
3150
- return {
3151
- ...state,
3152
- selection: {
3153
- anchor: clampPosition(state, selection.anchor),
3154
- focus: clampPosition(state, selection.focus)
3155
- }
3156
- };
3157
2469
  }
3158
- function moveSelectionLeft(state) {
2470
+ function deleteBackward(state) {
2471
+ var _a;
3159
2472
  if (!isSelectionCollapsed(state.selection)) {
3160
- return collapseToBoundary(state, "start");
2473
+ return deleteSelectionRange(state);
3161
2474
  }
3162
2475
  const { paragraph, index, offset } = getFocusParagraph(state);
3163
2476
  const paragraphs = getParagraphs(state);
3164
2477
  if (offset > 0) {
3165
- return {
3166
- document: state.document,
3167
- selection: withSelection(
3168
- paragraphOffsetToPosition(paragraph, offset - 1)
3169
- )
3170
- };
2478
+ if (state.trackChangesEnabled) {
2479
+ const runs = paragraph.runs;
2480
+ let consumed = 0;
2481
+ let targetRunIndex = -1;
2482
+ let runOffset = -1;
2483
+ for (let i = 0; i < runs.length; i += 1) {
2484
+ const nextConsumed = consumed + runs[i].text.length;
2485
+ if (offset <= nextConsumed) {
2486
+ targetRunIndex = i;
2487
+ runOffset = offset - consumed;
2488
+ break;
2489
+ }
2490
+ consumed = nextConsumed;
2491
+ }
2492
+ if (targetRunIndex !== -1) {
2493
+ const targetRun = runs[targetRunIndex];
2494
+ if (((_a = targetRun.revision) == null ? void 0 : _a.type) === "insert") {
2495
+ const nextRuns2 = [
2496
+ ...sliceRuns(paragraph, 0, offset - 1),
2497
+ ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
2498
+ ];
2499
+ const nextParagraph3 = buildParagraphFromRuns(paragraph, nextRuns2);
2500
+ const nextParagraphs4 = paragraphs.map(
2501
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph3 : candidate
2502
+ );
2503
+ return cloneStateWithParagraphs(
2504
+ state,
2505
+ nextParagraphs4,
2506
+ withSelection(paragraphOffsetToPosition(nextParagraph3, offset - 1))
2507
+ );
2508
+ }
2509
+ const charToDelete = targetRun.text[runOffset - 1];
2510
+ const deletionRun = {
2511
+ id: `run:${Math.random().toString(36).slice(2, 9)}`,
2512
+ text: charToDelete,
2513
+ styles: { ...targetRun.styles },
2514
+ revision: {
2515
+ id: `rev:${Math.random().toString(36).slice(2, 9)}`,
2516
+ type: "delete",
2517
+ author: "User",
2518
+ date: Date.now()
2519
+ }
2520
+ };
2521
+ const nextRuns = [
2522
+ ...sliceRuns(paragraph, 0, offset - 1),
2523
+ deletionRun,
2524
+ ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
2525
+ ];
2526
+ const nextParagraph2 = buildParagraphFromRuns(paragraph, nextRuns);
2527
+ const nextParagraphs3 = paragraphs.map(
2528
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph2 : candidate
2529
+ );
2530
+ return cloneStateWithParagraphs(
2531
+ state,
2532
+ nextParagraphs3,
2533
+ withSelection(paragraphOffsetToPosition(nextParagraph2, offset - 1))
2534
+ );
2535
+ }
2536
+ }
2537
+ const nextParagraph = buildParagraphFromRuns(
2538
+ paragraph,
2539
+ [
2540
+ ...sliceRuns(paragraph, 0, offset - 1),
2541
+ ...sliceRuns(paragraph, offset, getParagraphLength(paragraph))
2542
+ ],
2543
+ getStyleAtOffset(paragraph, offset - 1)
2544
+ );
2545
+ const nextParagraphs2 = paragraphs.map(
2546
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : candidate
2547
+ );
2548
+ return cloneStateWithParagraphs(
2549
+ state,
2550
+ nextParagraphs2,
2551
+ withSelection(paragraphOffsetToPosition(nextParagraph, offset - 1))
2552
+ );
3171
2553
  }
3172
2554
  if (index === 0) {
3173
2555
  return state;
3174
2556
  }
3175
2557
  const previousParagraph = paragraphs[index - 1];
3176
- return {
3177
- document: state.document,
3178
- selection: withSelection(
2558
+ const mergedParagraph = buildParagraphFromRuns(previousParagraph, [
2559
+ ...previousParagraph.runs.map(cloneRun),
2560
+ ...paragraph.runs.map(cloneRun)
2561
+ ]);
2562
+ const nextParagraphs = [
2563
+ ...paragraphs.slice(0, index - 1),
2564
+ mergedParagraph,
2565
+ ...paragraphs.slice(index + 1)
2566
+ ];
2567
+ return cloneStateWithParagraphs(
2568
+ state,
2569
+ nextParagraphs,
2570
+ withSelection(
3179
2571
  paragraphOffsetToPosition(
3180
- previousParagraph,
2572
+ mergedParagraph,
3181
2573
  getParagraphLength(previousParagraph)
3182
2574
  )
3183
2575
  )
3184
- };
2576
+ );
3185
2577
  }
3186
- function moveSelectionRight(state) {
2578
+ function deleteForward(state) {
2579
+ var _a;
3187
2580
  if (!isSelectionCollapsed(state.selection)) {
3188
- return collapseToBoundary(state, "end");
2581
+ return deleteSelectionRange(state);
3189
2582
  }
3190
2583
  const { paragraph, index, offset } = getFocusParagraph(state);
3191
2584
  const paragraphs = getParagraphs(state);
3192
- const paragraphLength = getParagraphLength(paragraph);
3193
- if (offset < paragraphLength) {
3194
- return {
3195
- document: state.document,
3196
- selection: withSelection(
3197
- paragraphOffsetToPosition(paragraph, offset + 1)
3198
- )
3199
- };
2585
+ if (offset < getParagraphLength(paragraph)) {
2586
+ if (state.trackChangesEnabled) {
2587
+ const runs = paragraph.runs;
2588
+ let consumed = 0;
2589
+ let targetRunIndex = -1;
2590
+ let runOffset = -1;
2591
+ for (let i = 0; i < runs.length; i += 1) {
2592
+ const nextConsumed = consumed + runs[i].text.length;
2593
+ if (offset < nextConsumed) {
2594
+ targetRunIndex = i;
2595
+ runOffset = offset - consumed;
2596
+ break;
2597
+ }
2598
+ consumed = nextConsumed;
2599
+ }
2600
+ if (targetRunIndex !== -1) {
2601
+ const targetRun = runs[targetRunIndex];
2602
+ if (((_a = targetRun.revision) == null ? void 0 : _a.type) === "insert") {
2603
+ const nextRuns2 = [
2604
+ ...sliceRuns(paragraph, 0, offset),
2605
+ ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
2606
+ ];
2607
+ const nextParagraph4 = buildParagraphFromRuns(paragraph, nextRuns2);
2608
+ const nextParagraphs4 = paragraphs.map(
2609
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph4 : candidate
2610
+ );
2611
+ return cloneStateWithParagraphs(
2612
+ state,
2613
+ nextParagraphs4,
2614
+ withSelection(paragraphOffsetToPosition(nextParagraph4, offset))
2615
+ );
2616
+ }
2617
+ const charToDelete = targetRun.text[runOffset];
2618
+ const deletionRun = {
2619
+ id: `run:${Math.random().toString(36).slice(2, 9)}`,
2620
+ text: charToDelete,
2621
+ styles: { ...targetRun.styles },
2622
+ revision: {
2623
+ id: `rev:${Math.random().toString(36).slice(2, 9)}`,
2624
+ type: "delete",
2625
+ author: "User",
2626
+ date: Date.now()
2627
+ }
2628
+ };
2629
+ const nextRuns = [
2630
+ ...sliceRuns(paragraph, 0, offset),
2631
+ deletionRun,
2632
+ ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
2633
+ ];
2634
+ const nextParagraph3 = buildParagraphFromRuns(paragraph, nextRuns);
2635
+ const nextParagraphs3 = paragraphs.map(
2636
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph3 : candidate
2637
+ );
2638
+ return cloneStateWithParagraphs(
2639
+ state,
2640
+ nextParagraphs3,
2641
+ withSelection(paragraphOffsetToPosition(nextParagraph3, offset))
2642
+ );
2643
+ }
2644
+ }
2645
+ const nextParagraph2 = buildParagraphFromRuns(
2646
+ paragraph,
2647
+ [
2648
+ ...sliceRuns(paragraph, 0, offset),
2649
+ ...sliceRuns(paragraph, offset + 1, getParagraphLength(paragraph))
2650
+ ],
2651
+ getStyleAtOffset(paragraph, offset)
2652
+ );
2653
+ const nextParagraphs2 = paragraphs.map(
2654
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph2 : candidate
2655
+ );
2656
+ return cloneStateWithParagraphs(
2657
+ state,
2658
+ nextParagraphs2,
2659
+ withSelection(paragraphOffsetToPosition(nextParagraph2, offset))
2660
+ );
3200
2661
  }
3201
2662
  if (index >= paragraphs.length - 1) {
3202
2663
  return state;
3203
2664
  }
3204
2665
  const nextParagraph = paragraphs[index + 1];
3205
- return {
3206
- document: state.document,
3207
- selection: withSelection(paragraphOffsetToPosition(nextParagraph, 0))
3208
- };
3209
- }
3210
- function moveSelectionUp(state) {
3211
- return moveVertical(state, -1);
3212
- }
3213
- function moveSelectionDown(state) {
3214
- return moveVertical(state, 1);
3215
- }
3216
- function extendSelectionLeft(state) {
3217
- return moveFocusHorizontally(state, -1);
3218
- }
3219
- function extendSelectionRight(state) {
3220
- return moveFocusHorizontally(state, 1);
3221
- }
3222
- function extendSelectionUp(state) {
3223
- return moveFocusVertical(state, -1);
3224
- }
3225
- function extendSelectionDown(state) {
3226
- return moveFocusVertical(state, 1);
2666
+ const mergedParagraph = buildParagraphFromRuns(paragraph, [
2667
+ ...paragraph.runs.map(cloneRun),
2668
+ ...nextParagraph.runs.map(cloneRun)
2669
+ ]);
2670
+ const nextParagraphs = [
2671
+ ...paragraphs.slice(0, index),
2672
+ mergedParagraph,
2673
+ ...paragraphs.slice(index + 2)
2674
+ ];
2675
+ return cloneStateWithParagraphs(
2676
+ state,
2677
+ nextParagraphs,
2678
+ withSelection(paragraphOffsetToPosition(mergedParagraph, offset))
2679
+ );
3227
2680
  }
3228
- function getLinkAtSelection(state) {
3229
- var _a, _b, _c;
2681
+ function toggleTextStyle(state, key) {
3230
2682
  const normalized = normalizeSelection(state);
3231
- const paragraphs = getParagraphs(state);
3232
2683
  if (normalized.isCollapsed) {
3233
- const paragraph = paragraphs[normalized.startIndex];
3234
- if (!paragraph) {
3235
- return null;
3236
- }
3237
- return ((_a = expandLinkRangeInParagraph(paragraph, normalized.startParagraphOffset)) == null ? void 0 : _a.href) ?? null;
2684
+ return state;
3238
2685
  }
3239
- const touchedRuns = paragraphs.slice(normalized.startIndex, normalized.endIndex + 1).flatMap((paragraph, relativeIndex) => {
2686
+ const paragraphs = getParagraphs(state);
2687
+ const touchedParagraphs = paragraphs.slice(
2688
+ normalized.startIndex,
2689
+ normalized.endIndex + 1
2690
+ );
2691
+ const touchedRuns = touchedParagraphs.flatMap((paragraph, relativeIndex) => {
3240
2692
  const paragraphIndex = normalized.startIndex + relativeIndex;
3241
2693
  const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
3242
2694
  const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
3243
2695
  return sliceRuns(paragraph, startOffset, endOffset);
3244
- }).filter((run) => run.text.length > 0 && !run.image);
2696
+ }).filter((run) => run.text.length > 0);
3245
2697
  if (touchedRuns.length === 0) {
3246
- return null;
3247
- }
3248
- const href = (_c = (_b = touchedRuns[0]) == null ? void 0 : _b.styles) == null ? void 0 : _c.link;
3249
- if (!href) {
3250
- return null;
3251
- }
3252
- return touchedRuns.every((run) => {
3253
- var _a2;
3254
- return ((_a2 = run.styles) == null ? void 0 : _a2.link) === href;
3255
- }) ? href : null;
3256
- }
3257
- function setLinkAtSelection(state, href) {
3258
- const normalized = normalizeSelection(state);
3259
- if (!normalized.isCollapsed) {
3260
- return setTextStyleValue(state, "link", href);
3261
- }
3262
- const paragraphs = getParagraphs(state);
3263
- const paragraph = paragraphs[normalized.startIndex];
3264
- if (!paragraph) {
3265
2698
  return state;
3266
2699
  }
3267
- const linkRange = expandLinkRangeInParagraph(
3268
- paragraph,
3269
- normalized.startParagraphOffset
2700
+ const shouldEnable = !touchedRuns.every((run) => {
2701
+ var _a;
2702
+ return Boolean((_a = run.styles) == null ? void 0 : _a[key]);
2703
+ });
2704
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2705
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2706
+ return paragraph;
2707
+ }
2708
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2709
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2710
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => ({
2711
+ ...run,
2712
+ styles: setBooleanStyle(run.styles, key, shouldEnable)
2713
+ }));
2714
+ });
2715
+ return cloneStateWithParagraphs(
2716
+ state,
2717
+ nextParagraphs,
2718
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3270
2719
  );
3271
- if (!linkRange) {
3272
- return state;
2720
+ }
2721
+ function isLetter(char) {
2722
+ return new RegExp("\\p{L}", "u").test(char);
2723
+ }
2724
+ function toSentenceCase(text) {
2725
+ let result = "";
2726
+ let capitalizeNext = true;
2727
+ for (const char of text.toLowerCase()) {
2728
+ if (capitalizeNext && isLetter(char)) {
2729
+ result += char.toUpperCase();
2730
+ capitalizeNext = false;
2731
+ } else {
2732
+ result += char;
2733
+ if (char === "." || char === "!" || char === "?") {
2734
+ capitalizeNext = true;
2735
+ }
2736
+ }
3273
2737
  }
3274
- const expandedSelection = {
3275
- anchor: paragraphOffsetToPosition(paragraph, linkRange.startOffset),
3276
- focus: paragraphOffsetToPosition(paragraph, linkRange.endOffset)
3277
- };
3278
- const expandedState = setSelection(state, expandedSelection);
3279
- const next = setTextStyleValue(expandedState, "link", href);
3280
- const nextParagraph = getParagraphs(next)[normalized.startIndex];
3281
- if (!nextParagraph) {
3282
- return next;
2738
+ return result;
2739
+ }
2740
+ function toCapitalizedWords(text) {
2741
+ let result = "";
2742
+ let prevIsLetter = false;
2743
+ for (const char of text) {
2744
+ const letter = isLetter(char);
2745
+ result += letter && !prevIsLetter ? char.toUpperCase() : char;
2746
+ prevIsLetter = letter;
3283
2747
  }
3284
- return {
3285
- ...next,
3286
- selection: {
3287
- anchor: paragraphOffsetToPosition(nextParagraph, linkRange.startOffset),
3288
- focus: paragraphOffsetToPosition(nextParagraph, linkRange.endOffset)
2748
+ return result;
2749
+ }
2750
+ function toToggledCase(text) {
2751
+ let result = "";
2752
+ for (const char of text) {
2753
+ const upper = char.toUpperCase();
2754
+ const lower = char.toLowerCase();
2755
+ if (char === lower && char !== upper) {
2756
+ result += upper;
2757
+ } else if (char === upper && char !== lower) {
2758
+ result += lower;
2759
+ } else {
2760
+ result += char;
3289
2761
  }
3290
- };
2762
+ }
2763
+ return result;
3291
2764
  }
3292
- function toggleTrackChanges(state) {
3293
- return {
3294
- ...state,
3295
- trackChangesEnabled: !state.trackChangesEnabled
3296
- };
2765
+ function applyCaseTransform(text, mode) {
2766
+ switch (mode) {
2767
+ case "lower":
2768
+ return text.toLowerCase();
2769
+ case "upper":
2770
+ return text.toUpperCase();
2771
+ case "capitalize":
2772
+ return toCapitalizedWords(text);
2773
+ case "toggle":
2774
+ return toToggledCase(text);
2775
+ case "sentence":
2776
+ default:
2777
+ return toSentenceCase(text);
2778
+ }
3297
2779
  }
3298
- function acceptRevision(state, revisionId) {
2780
+ function transformSelectedText(state, transform) {
2781
+ const normalized = normalizeSelection(state);
2782
+ if (normalized.isCollapsed) {
2783
+ return state;
2784
+ }
3299
2785
  const paragraphs = getParagraphs(state);
3300
- const nextParagraphs = paragraphs.map((paragraph) => {
3301
- const nextRuns = paragraph.runs.filter(
3302
- (run) => {
3303
- var _a;
3304
- return !(((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "delete");
3305
- }
3306
- ).map((run) => {
3307
- var _a;
3308
- if (((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "insert") {
3309
- const nextRun = { ...run };
3310
- delete nextRun.revision;
3311
- return nextRun;
3312
- }
3313
- return run;
3314
- });
3315
- if (nextRuns.length === paragraph.runs.length && nextRuns.every((run, i) => run === paragraph.runs[i])) {
2786
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2787
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
3316
2788
  return paragraph;
3317
2789
  }
3318
- return buildParagraphFromRuns(paragraph, nextRuns);
2790
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2791
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2792
+ const selectedText = sliceRuns(paragraph, startOffset, endOffset).map((run) => run.text).join("");
2793
+ const transformed = transform(selectedText);
2794
+ let cursor = 0;
2795
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
2796
+ const length = run.text.length;
2797
+ const nextText = transformed.slice(cursor, cursor + length);
2798
+ cursor += length;
2799
+ return { ...run, text: nextText };
2800
+ });
3319
2801
  });
3320
2802
  return cloneStateWithParagraphs(
3321
2803
  state,
3322
2804
  nextParagraphs,
3323
- preserveSelectionByParagraphOffsets(
3324
- nextParagraphs,
3325
- normalizeSelection(state)
3326
- )
2805
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3327
2806
  );
3328
2807
  }
3329
- function rejectRevision(state, revisionId) {
2808
+ function changeSelectedTextCase(state, mode) {
2809
+ return transformSelectedText(state, (text) => applyCaseTransform(text, mode));
2810
+ }
2811
+ function clearSelectedTextFormatting(state) {
2812
+ const normalized = normalizeSelection(state);
2813
+ if (normalized.isCollapsed) {
2814
+ return state;
2815
+ }
3330
2816
  const paragraphs = getParagraphs(state);
3331
- const nextParagraphs = paragraphs.map((paragraph) => {
3332
- const nextRuns = paragraph.runs.filter(
3333
- (run) => {
3334
- var _a;
3335
- return !(((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "insert");
3336
- }
3337
- ).map((run) => {
3338
- var _a;
3339
- if (((_a = run.revision) == null ? void 0 : _a.id) === revisionId && run.revision.type === "delete") {
3340
- const nextRun = { ...run };
3341
- delete nextRun.revision;
3342
- return nextRun;
3343
- }
3344
- return run;
3345
- });
3346
- if (nextRuns.length === paragraph.runs.length && nextRuns.every((run, i) => run === paragraph.runs[i])) {
2817
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2818
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
3347
2819
  return paragraph;
3348
2820
  }
3349
- return buildParagraphFromRuns(paragraph, nextRuns);
2821
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2822
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2823
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => {
2824
+ var _a;
2825
+ const link = (_a = run.styles) == null ? void 0 : _a.link;
2826
+ const styles = link != null && link !== "" ? { link } : {};
2827
+ return { ...run, styles };
2828
+ });
3350
2829
  });
3351
2830
  return cloneStateWithParagraphs(
3352
2831
  state,
3353
2832
  nextParagraphs,
3354
- preserveSelectionByParagraphOffsets(
3355
- nextParagraphs,
3356
- normalizeSelection(state)
3357
- )
2833
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3358
2834
  );
3359
2835
  }
3360
- function acceptRevisionsInSelection(state) {
3361
- var _a;
2836
+ function setTextStyleValue(state, key, value) {
3362
2837
  const normalized = normalizeSelection(state);
3363
- const paragraphs = getParagraphs(state);
3364
- const revisionIds = /* @__PURE__ */ new Set();
3365
- for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
3366
- const paragraph = paragraphs[i];
3367
- const startOffset = i === normalized.startIndex ? normalized.startParagraphOffset : 0;
3368
- const endOffset = i === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
3369
- const runs = sliceRuns(paragraph, startOffset, endOffset);
3370
- for (const run of runs) {
3371
- if ((_a = run.revision) == null ? void 0 : _a.id) {
3372
- revisionIds.add(run.revision.id);
3373
- }
3374
- }
3375
- }
3376
- let nextState = state;
3377
- for (const revisionId of revisionIds) {
3378
- nextState = acceptRevision(nextState, revisionId);
2838
+ if (normalized.isCollapsed) {
2839
+ return state;
3379
2840
  }
3380
- return nextState;
3381
- }
3382
- function rejectRevisionsInSelection(state) {
3383
- var _a;
3384
- const normalized = normalizeSelection(state);
3385
2841
  const paragraphs = getParagraphs(state);
3386
- const revisionIds = /* @__PURE__ */ new Set();
3387
- for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
3388
- const paragraph = paragraphs[i];
3389
- const startOffset = i === normalized.startIndex ? normalized.startParagraphOffset : 0;
3390
- const endOffset = i === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
3391
- const runs = sliceRuns(paragraph, startOffset, endOffset);
3392
- for (const run of runs) {
3393
- if ((_a = run.revision) == null ? void 0 : _a.id) {
3394
- revisionIds.add(run.revision.id);
3395
- }
2842
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2843
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2844
+ return paragraph;
3396
2845
  }
3397
- }
3398
- let nextState = state;
3399
- for (const revisionId of revisionIds) {
3400
- nextState = rejectRevision(nextState, revisionId);
3401
- }
3402
- return nextState;
3403
- }
3404
- function textRunStylesToCss(style2) {
3405
- if (!style2) {
3406
- return "";
3407
- }
3408
- const parts = [];
3409
- if (style2.fontFamily) {
3410
- parts.push(`font-family:${style2.fontFamily}`);
3411
- }
3412
- if (style2.fontSize !== void 0 && style2.fontSize !== null) {
3413
- parts.push(`font-size:${style2.fontSize}px`);
3414
- }
3415
- if (style2.color) {
3416
- parts.push(`color:${style2.color}`);
3417
- }
3418
- if (style2.highlight) {
3419
- parts.push(`background-color:${style2.highlight}`);
3420
- } else if (style2.shading) {
3421
- parts.push(`background-color:${style2.shading}`);
3422
- }
3423
- if (style2.superscript) {
3424
- parts.push("vertical-align:super");
3425
- parts.push("font-size:0.75em");
3426
- } else if (style2.subscript) {
3427
- parts.push("vertical-align:sub");
3428
- parts.push("font-size:0.75em");
3429
- }
3430
- if (style2.bold) {
3431
- parts.push("font-weight:700");
3432
- }
3433
- if (style2.italic) {
3434
- parts.push("font-style:italic");
3435
- }
3436
- if (style2.hidden) {
3437
- parts.push("display:none");
3438
- }
3439
- if (style2.allCaps) {
3440
- parts.push("text-transform:uppercase");
3441
- }
3442
- if (style2.smallCaps) {
3443
- parts.push("font-variant:small-caps");
3444
- }
3445
- if (style2.characterScale !== void 0 && style2.characterScale !== null) {
3446
- parts.push(`font-stretch:${style2.characterScale}%`);
3447
- }
3448
- if (style2.characterSpacing !== void 0 && style2.characterSpacing !== null) {
3449
- parts.push(`letter-spacing:${style2.characterSpacing}pt`);
3450
- }
3451
- if (getPrimaryTextLanguage(style2.language)) {
3452
- parts.push("hyphens:auto");
3453
- }
3454
- if (style2.baselineShift !== void 0 && style2.baselineShift !== null) {
3455
- parts.push(`vertical-align:${style2.baselineShift}pt`);
3456
- }
3457
- const ligatures = ligaturesToCss$1(style2.ligatures);
3458
- if (ligatures) {
3459
- parts.push(`font-variant-ligatures:${ligatures}`);
3460
- }
3461
- const numeric = numericToCss$1(style2.numberSpacing, style2.numberForm);
3462
- if (numeric) {
3463
- parts.push(`font-variant-numeric:${numeric}`);
3464
- }
3465
- const featureSettings = fontFeatureSettingsToCss(
3466
- style2.stylisticSet,
3467
- style2.contextualAlternates
2846
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2847
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2848
+ return mapRunsInRange(paragraph, startOffset, endOffset, (run) => ({
2849
+ ...run,
2850
+ styles: setValueStyle(run.styles, key, value)
2851
+ }));
2852
+ });
2853
+ return cloneStateWithParagraphs(
2854
+ state,
2855
+ nextParagraphs,
2856
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3468
2857
  );
3469
- if (featureSettings) {
3470
- parts.push(`font-feature-settings:${featureSettings}`);
3471
- }
3472
- const decorations = [];
3473
- if (style2.underline || style2.link) {
3474
- decorations.push("underline");
3475
- }
3476
- if (style2.strike) {
3477
- decorations.push("line-through");
3478
- }
3479
- if (style2.doubleStrike) {
3480
- decorations.push("line-through");
3481
- }
3482
- if (decorations.length > 0) {
3483
- parts.push(`text-decoration:${decorations.join(" ")}`);
3484
- if (style2.underline || style2.link) {
3485
- const cssDecorationStyle = underlineStyleToCssDecorationStyle(
3486
- style2.underlineStyle
3487
- );
3488
- if (cssDecorationStyle) {
3489
- parts.push(`text-decoration-style:${cssDecorationStyle}`);
3490
- }
3491
- if (style2.underlineColor) {
3492
- parts.push(`text-decoration-color:${style2.underlineColor}`);
3493
- }
3494
- }
3495
- }
3496
- return parts.join(";");
3497
- }
3498
- function getPrimaryTextLanguage(language) {
3499
- return (language == null ? void 0 : language.value) ?? (language == null ? void 0 : language.bidi) ?? (language == null ? void 0 : language.eastAsia) ?? null;
3500
2858
  }
3501
- function ligaturesToCss$1(ligatures) {
3502
- switch (ligatures) {
3503
- case "none":
3504
- return "none";
3505
- case "standard":
3506
- return "common-ligatures";
3507
- case "contextual":
3508
- return "contextual";
3509
- case "historical":
3510
- return "historical-ligatures";
3511
- case "standardContextual":
3512
- return "common-ligatures contextual";
3513
- default:
2859
+ function getLinkAtSelection(state) {
2860
+ var _a, _b, _c;
2861
+ const normalized = normalizeSelection(state);
2862
+ const paragraphs = getParagraphs(state);
2863
+ if (normalized.isCollapsed) {
2864
+ const paragraph = paragraphs[normalized.startIndex];
2865
+ if (!paragraph) {
3514
2866
  return null;
2867
+ }
2868
+ return ((_a = expandLinkRangeInParagraph(paragraph, normalized.startParagraphOffset)) == null ? void 0 : _a.href) ?? null;
3515
2869
  }
3516
- }
3517
- function numericToCss$1(numberSpacing, numberForm) {
3518
- const parts = [];
3519
- if (numberSpacing === "proportional") parts.push("proportional-nums");
3520
- if (numberSpacing === "tabular") parts.push("tabular-nums");
3521
- if (numberForm === "lining") parts.push("lining-nums");
3522
- if (numberForm === "oldStyle") parts.push("oldstyle-nums");
3523
- return parts.join(" ") || null;
3524
- }
3525
- function fontFeatureSettingsToCss(stylisticSet, contextualAlternates) {
3526
- const parts = [];
3527
- if (typeof stylisticSet === "number" && stylisticSet >= 1 && stylisticSet <= 20) {
3528
- parts.push(`"ss${String(stylisticSet).padStart(2, "0")}" 1`);
3529
- }
3530
- if (contextualAlternates) {
3531
- parts.push('"calt" 1');
3532
- }
3533
- return parts.join(", ") || null;
3534
- }
3535
- function paragraphStyleToCssText(style2) {
3536
- if (!style2) {
3537
- return "";
3538
- }
3539
- const parts = [];
3540
- if (style2.align) {
3541
- parts.push(`text-align:${style2.align}`);
3542
- }
3543
- if (style2.lineHeight !== void 0 && style2.lineHeight !== null) {
3544
- const isAbsoluteRule = style2.lineRule === "exact" || style2.lineRule === "atLeast";
3545
- parts.push(`line-height:${style2.lineHeight}${isAbsoluteRule ? "px" : ""}`);
3546
- }
3547
- if (style2.spacingBefore !== void 0 && style2.spacingBefore !== null) {
3548
- parts.push(`padding-top:${style2.spacingBefore}px`);
3549
- }
3550
- if (style2.spacingAfter !== void 0 && style2.spacingAfter !== null) {
3551
- parts.push(`padding-bottom:${style2.spacingAfter}px`);
3552
- }
3553
- if (style2.indentLeft !== void 0 && style2.indentLeft !== null) {
3554
- parts.push(`padding-left:${style2.indentLeft}px`);
3555
- }
3556
- if (style2.indentRight !== void 0 && style2.indentRight !== null) {
3557
- parts.push(`padding-right:${style2.indentRight}px`);
3558
- }
3559
- if (style2.indentFirstLine !== void 0 && style2.indentFirstLine !== null) {
3560
- parts.push(`text-indent:${style2.indentFirstLine}px`);
3561
- }
3562
- return parts.join(";");
3563
- }
3564
- function escapeHtml(text) {
3565
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
3566
- }
3567
- function textLanguageToHtmlAttributes(language) {
3568
- if (!language) {
3569
- return "";
3570
- }
3571
- const attrs = [];
3572
- const primary = getPrimaryTextLanguage(language);
3573
- if (primary) {
3574
- attrs.push(`lang="${escapeHtml(primary)}"`);
3575
- }
3576
- if (language.value) {
3577
- attrs.push(`data-oasis-lang-value="${escapeHtml(language.value)}"`);
3578
- }
3579
- if (language.eastAsia) {
3580
- attrs.push(`data-oasis-lang-east-asia="${escapeHtml(language.eastAsia)}"`);
3581
- }
3582
- if (language.bidi) {
3583
- attrs.push(`data-oasis-lang-bidi="${escapeHtml(language.bidi)}"`);
3584
- }
3585
- return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
3586
- }
3587
- function serializeImageRunToHtml(run, document2) {
3588
- var _a;
3589
- if (!run.image) {
3590
- return "";
3591
- }
3592
- const resolvedSrc = resolveImageSrc(document2, run.image.src);
3593
- const altAttr = run.image.alt !== void 0 ? ` alt="${escapeHtml(run.image.alt)}"` : "";
3594
- const img = `<img src="${escapeHtml(resolvedSrc)}" width="${Math.max(1, Math.round(run.image.width))}" height="${Math.max(1, Math.round(run.image.height))}"${altAttr}>`;
3595
- if ((_a = run.styles) == null ? void 0 : _a.link) {
3596
- return `<a href="${escapeHtml(run.styles.link)}">${img}</a>`;
3597
- }
3598
- return img;
3599
- }
3600
- function serializeTextRunToHtml(run, document2) {
3601
- if (run.image) {
3602
- return serializeImageRunToHtml(run, document2);
3603
- }
3604
- const text = escapeHtml(run.text).replace(/\n/g, "<br>");
3605
- let html = text;
3606
- const style2 = run.styles ?? void 0;
3607
- if (style2 == null ? void 0 : style2.strike) {
3608
- html = `<s>${html}</s>`;
3609
- }
3610
- if (style2 == null ? void 0 : style2.underline) {
3611
- html = `<u>${html}</u>`;
3612
- }
3613
- if (style2 == null ? void 0 : style2.italic) {
3614
- html = `<em>${html}</em>`;
3615
- }
3616
- if (style2 == null ? void 0 : style2.bold) {
3617
- html = `<strong>${html}</strong>`;
3618
- }
3619
- if (style2 == null ? void 0 : style2.superscript) {
3620
- html = `<sup>${html}</sup>`;
3621
- } else if (style2 == null ? void 0 : style2.subscript) {
3622
- html = `<sub>${html}</sub>`;
3623
- }
3624
- const css = textRunStylesToCss(style2);
3625
- const languageAttrs = textLanguageToHtmlAttributes(style2 == null ? void 0 : style2.language);
3626
- if (css.length > 0 || languageAttrs.length > 0) {
3627
- const styleAttr = css.length > 0 ? ` style="${css}"` : "";
3628
- html = `<span${styleAttr}${languageAttrs}>${html}</span>`;
2870
+ const touchedRuns = paragraphs.slice(normalized.startIndex, normalized.endIndex + 1).flatMap((paragraph, relativeIndex) => {
2871
+ const paragraphIndex = normalized.startIndex + relativeIndex;
2872
+ const startOffset = paragraphIndex === normalized.startIndex ? normalized.startParagraphOffset : 0;
2873
+ const endOffset = paragraphIndex === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
2874
+ return sliceRuns(paragraph, startOffset, endOffset);
2875
+ }).filter((run) => run.text.length > 0 && !run.image);
2876
+ if (touchedRuns.length === 0) {
2877
+ return null;
3629
2878
  }
3630
- if (style2 == null ? void 0 : style2.link) {
3631
- html = `<a href="${escapeHtml(style2.link)}">${html}</a>`;
2879
+ const href = (_c = (_b = touchedRuns[0]) == null ? void 0 : _b.styles) == null ? void 0 : _c.link;
2880
+ if (!href) {
2881
+ return null;
3632
2882
  }
3633
- return html;
3634
- }
3635
- function serializeParagraphRunsToHtml(runs, document2) {
3636
- return runs.map((run) => serializeTextRunToHtml(run, document2)).join("") || "<br>";
2883
+ return touchedRuns.every((run) => {
2884
+ var _a2;
2885
+ return ((_a2 = run.styles) == null ? void 0 : _a2.link) === href;
2886
+ }) ? href : null;
3637
2887
  }
3638
- function serializeEditorSelectionToHtml(state) {
3639
- var _a;
2888
+ function setLinkAtSelection(state, href) {
3640
2889
  const normalized = normalizeSelection(state);
3641
- if (normalized.isCollapsed) {
3642
- return "";
2890
+ if (!normalized.isCollapsed) {
2891
+ return setTextStyleValue(state, "link", href);
3643
2892
  }
3644
2893
  const paragraphs = getParagraphs(state);
3645
- const htmlParts = [];
3646
- let activeListKind = null;
3647
- const closeList = () => {
3648
- if (activeListKind) {
3649
- htmlParts.push(activeListKind === "bullet" ? "</ul>" : "</ol>");
3650
- activeListKind = null;
3651
- }
3652
- };
3653
- for (let index = normalized.startIndex; index <= normalized.endIndex; index += 1) {
3654
- const paragraph = paragraphs[index];
3655
- if (!paragraph) {
3656
- continue;
3657
- }
3658
- const startOffset = index === normalized.startIndex ? normalized.startParagraphOffset : 0;
3659
- const endOffset = index === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
3660
- const runs = sliceRuns(paragraph, startOffset, endOffset);
3661
- const css = paragraphStyleToCssText(paragraph.style);
3662
- const attrs = css.length > 0 ? ` style="${css}"` : "";
3663
- const paragraphHtml = serializeParagraphRunsToHtml(runs, state.document);
3664
- if ((_a = paragraph.list) == null ? void 0 : _a.kind) {
3665
- const wrapperTag = paragraph.list.kind === "bullet" ? "ul" : "ol";
3666
- if (activeListKind !== paragraph.list.kind) {
3667
- closeList();
3668
- htmlParts.push(`<${wrapperTag}>`);
3669
- activeListKind = paragraph.list.kind;
3670
- }
3671
- htmlParts.push(`<li${attrs}>${paragraphHtml}</li>`);
3672
- continue;
3673
- }
3674
- closeList();
3675
- htmlParts.push(`<p${attrs}>${paragraphHtml}</p>`);
2894
+ const paragraph = paragraphs[normalized.startIndex];
2895
+ if (!paragraph) {
2896
+ return state;
3676
2897
  }
3677
- closeList();
3678
- return htmlParts.join("");
3679
- }
3680
- function insertClipboardParagraphsAtSelection(state, paragraphsSpec) {
3681
- if (paragraphsSpec.length === 0) {
2898
+ const linkRange = expandLinkRangeInParagraph(
2899
+ paragraph,
2900
+ normalized.startParagraphOffset
2901
+ );
2902
+ if (!linkRange) {
3682
2903
  return state;
3683
2904
  }
2905
+ const expandedSelection = {
2906
+ anchor: paragraphOffsetToPosition(paragraph, linkRange.startOffset),
2907
+ focus: paragraphOffsetToPosition(paragraph, linkRange.endOffset)
2908
+ };
2909
+ const expandedState = setSelection(state, expandedSelection);
2910
+ const next = setTextStyleValue(expandedState, "link", href);
2911
+ const nextParagraph = getParagraphs(next)[normalized.startIndex];
2912
+ if (!nextParagraph) {
2913
+ return next;
2914
+ }
2915
+ return {
2916
+ ...next,
2917
+ selection: {
2918
+ anchor: paragraphOffsetToPosition(nextParagraph, linkRange.startOffset),
2919
+ focus: paragraphOffsetToPosition(nextParagraph, linkRange.endOffset)
2920
+ }
2921
+ };
2922
+ }
2923
+ function splitListItemAtSelection(state) {
3684
2924
  const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
3685
2925
  const { paragraph, index, offset } = getFocusParagraph(collapsedState);
2926
+ const firstParagraph = buildParagraphFromRuns(
2927
+ paragraph,
2928
+ sliceRuns(paragraph, 0, offset),
2929
+ getStyleAtOffset(paragraph, offset)
2930
+ );
2931
+ const secondRuns = sliceRuns(
2932
+ paragraph,
2933
+ offset,
2934
+ getParagraphLength(paragraph)
2935
+ );
2936
+ const nextParagraph = secondRuns.length > 0 ? createParagraphFromRunsLike(
2937
+ paragraph,
2938
+ secondRuns.map((run) => ({ text: run.text, styles: run.styles }))
2939
+ ) : (() => {
2940
+ const emptyParagraph = createEditorParagraph("");
2941
+ emptyParagraph.style = paragraph.style ? { ...paragraph.style } : void 0;
2942
+ emptyParagraph.list = cloneParagraphList(paragraph.list);
2943
+ return emptyParagraph;
2944
+ })();
3686
2945
  const paragraphs = getParagraphs(collapsedState);
3687
- const beforeRuns = sliceRuns(paragraph, 0, offset);
3688
- const afterRuns = sliceRuns(paragraph, offset, getParagraphLength(paragraph));
3689
- const pastedParagraphs = paragraphsSpec.map((spec) => {
3690
- const nextParagraph = createEditorParagraphFromRuns(
3691
- spec.runs.map((run) => ({
3692
- text: run.text,
3693
- styles: cloneStyle(run.styles),
3694
- image: run.image ? { ...run.image } : void 0
3695
- }))
3696
- );
3697
- nextParagraph.style = spec.style ? { ...spec.style } : void 0;
3698
- nextParagraph.list = spec.list ? { ...spec.list } : void 0;
3699
- return nextParagraph;
2946
+ const nextParagraphs = [
2947
+ ...cloneParagraphs(paragraphs.slice(0, index)),
2948
+ firstParagraph,
2949
+ nextParagraph,
2950
+ ...cloneParagraphs(paragraphs.slice(index + 1))
2951
+ ];
2952
+ return cloneStateWithParagraphs(
2953
+ collapsedState,
2954
+ nextParagraphs,
2955
+ withSelection(paragraphOffsetToPosition(nextParagraph, 0))
2956
+ );
2957
+ }
2958
+ function clearParagraphListAtSelection(state) {
2959
+ const normalized = normalizeSelection(state);
2960
+ const paragraphs = getParagraphs(state);
2961
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2962
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2963
+ return cloneParagraph(paragraph);
2964
+ }
2965
+ return clearParagraphList(paragraph);
3700
2966
  });
3701
- let nextParagraphs;
3702
- let nextSelection = withSelection(
3703
- paragraphOffsetToPosition(paragraph, offset)
2967
+ return cloneStateWithParagraphs(
2968
+ state,
2969
+ nextParagraphs,
2970
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3704
2971
  );
3705
- if (pastedParagraphs.length === 1) {
3706
- const source = pastedParagraphs[0];
3707
- const sourceLength = source.runs.reduce(
3708
- (total, run) => total + run.text.length,
3709
- 0
3710
- );
3711
- const mergedParagraph = buildParagraphFromRuns(
3712
- paragraph,
3713
- [...beforeRuns, ...source.runs.map(cloneRun), ...afterRuns],
3714
- getStyleAtOffset(paragraph, offset)
3715
- );
3716
- mergedParagraph.style = paragraph.style ? { ...paragraph.style } : source.style ? { ...source.style } : void 0;
3717
- mergedParagraph.list = paragraph.list ? { ...paragraph.list } : source.list ? { ...source.list } : void 0;
3718
- nextParagraphs = [
3719
- ...cloneParagraphs(paragraphs.slice(0, index)),
3720
- mergedParagraph,
3721
- ...cloneParagraphs(paragraphs.slice(index + 1))
3722
- ];
3723
- nextSelection = withSelection(
3724
- paragraphOffsetToPosition(
3725
- mergedParagraph,
3726
- beforeRuns.reduce((total, run) => total + run.text.length, 0) + sourceLength
3727
- )
3728
- );
3729
- } else {
3730
- const firstSource = pastedParagraphs[0];
3731
- const lastSource = pastedParagraphs[pastedParagraphs.length - 1];
3732
- const lastSourceLength = lastSource.runs.reduce(
3733
- (total, run) => total + run.text.length,
3734
- 0
3735
- );
3736
- const firstParagraph = buildParagraphFromRuns(
2972
+ }
2973
+ function indentParagraphList(state) {
2974
+ const normalized = normalizeSelection(state);
2975
+ const paragraphs = getParagraphs(state);
2976
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2977
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2978
+ return cloneParagraph(paragraph);
2979
+ }
2980
+ if (!paragraph.list) {
2981
+ return cloneParagraph(paragraph);
2982
+ }
2983
+ return cloneParagraphWithListLevel(
3737
2984
  paragraph,
3738
- [...beforeRuns, ...firstSource.runs.map(cloneRun)],
3739
- getStyleAtOffset(paragraph, offset)
3740
- );
3741
- firstParagraph.style = paragraph.style ? { ...paragraph.style } : firstSource.style ? { ...firstSource.style } : void 0;
3742
- firstParagraph.list = paragraph.list ? { ...paragraph.list } : firstSource.list ? { ...firstSource.list } : void 0;
3743
- const middleParagraphs = pastedParagraphs.slice(1, -1).map(cloneParagraph);
3744
- const lastParagraph = buildParagraphFromRuns(
3745
- lastSource,
3746
- [...lastSource.runs.map(cloneRun), ...afterRuns],
3747
- void 0
3748
- );
3749
- lastParagraph.list = lastSource.list ? { ...lastSource.list } : void 0;
3750
- nextParagraphs = [
3751
- ...cloneParagraphs(paragraphs.slice(0, index)),
3752
- firstParagraph,
3753
- ...middleParagraphs,
3754
- lastParagraph,
3755
- ...cloneParagraphs(paragraphs.slice(index + 1))
3756
- ];
3757
- nextSelection = withSelection(
3758
- paragraphOffsetToPosition(lastParagraph, lastSourceLength)
2985
+ (paragraph.list.level ?? 0) + 1
3759
2986
  );
3760
- }
2987
+ });
3761
2988
  return cloneStateWithParagraphs(
3762
- collapsedState,
2989
+ state,
3763
2990
  nextParagraphs,
3764
- nextSelection
2991
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3765
2992
  );
3766
2993
  }
3767
- function ensureFootnotes(footnotes) {
3768
- if (footnotes) return footnotes;
3769
- return { items: {} };
3770
- }
3771
- function nextAutoMarker(document2) {
3772
- var _a, _b;
3773
- const footnotes = document2.footnotes;
3774
- const format = ((_a = footnotes == null ? void 0 : footnotes.settings) == null ? void 0 : _a.numberFormat) ?? "decimal";
3775
- const startAt = ((_b = footnotes == null ? void 0 : footnotes.settings) == null ? void 0 : _b.startAt) ?? 1;
3776
- let autoCount = startAt - 1;
3777
- const seen = /* @__PURE__ */ new Set();
3778
- for (const { run } of iterateFootnoteReferenceRuns(document2)) {
3779
- const ref = run.footnoteReference;
3780
- if (!ref || ref.customMark) continue;
3781
- if (seen.has(ref.footnoteId)) continue;
3782
- seen.add(ref.footnoteId);
3783
- autoCount += 1;
3784
- }
3785
- return getFootnoteDisplayMarker(autoCount + 1, format);
3786
- }
3787
- function insertFootnote(state) {
3788
- const zone = state.activeZone ?? "main";
3789
- if (zone !== "main") {
3790
- return state;
3791
- }
3792
- const baseState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
3793
- const { paragraph, index, offset } = getFocusParagraph(baseState);
3794
- const footnote = createEditorFootnote();
3795
- const marker = nextAutoMarker(baseState.document);
3796
- const referenceRun = createFootnoteReferenceRun(footnote.id, marker);
3797
- const updatedParagraph = insertRunsAtOffset(paragraph, offset, [
3798
- referenceRun
3799
- ]);
3800
- const paragraphs = getParagraphs(baseState);
3801
- const nextParagraphs = paragraphs.map(
3802
- (candidate, candidateIndex) => candidateIndex === index ? updatedParagraph : candidate
3803
- );
3804
- const caretAfterMarker = paragraphOffsetToPosition(
3805
- updatedParagraph,
3806
- offset + marker.length
2994
+ function outdentParagraphList(state) {
2995
+ const normalized = normalizeSelection(state);
2996
+ const paragraphs = getParagraphs(state);
2997
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
2998
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
2999
+ return cloneParagraph(paragraph);
3000
+ }
3001
+ if (!paragraph.list) {
3002
+ return cloneParagraph(paragraph);
3003
+ }
3004
+ const currentLevel = paragraph.list.level ?? 0;
3005
+ if (currentLevel <= 0) {
3006
+ return clearParagraphList(paragraph);
3007
+ }
3008
+ return cloneParagraphWithListLevel(paragraph, currentLevel - 1);
3009
+ });
3010
+ return cloneStateWithParagraphs(
3011
+ state,
3012
+ nextParagraphs,
3013
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3807
3014
  );
3808
- const stateAfterInsert = cloneStateWithParagraphs(
3809
- baseState,
3015
+ }
3016
+ function toggleParagraphList(state, kind) {
3017
+ const normalized = normalizeSelection(state);
3018
+ const paragraphs = getParagraphs(state);
3019
+ const startIndex = normalized.startIndex;
3020
+ const endIndex = normalized.endIndex;
3021
+ const targetedParagraphs = paragraphs.slice(startIndex, endIndex + 1);
3022
+ const shouldClear = targetedParagraphs.length > 0 && targetedParagraphs.every((paragraph) => {
3023
+ var _a;
3024
+ return ((_a = paragraph.list) == null ? void 0 : _a.kind) === kind;
3025
+ });
3026
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
3027
+ var _a, _b, _c;
3028
+ if (paragraphIndex < startIndex || paragraphIndex > endIndex) {
3029
+ return cloneParagraph(paragraph);
3030
+ }
3031
+ const nextParagraph = cloneParagraph(paragraph);
3032
+ if (shouldClear) {
3033
+ delete nextParagraph.list;
3034
+ return nextParagraph;
3035
+ }
3036
+ nextParagraph.list = {
3037
+ kind,
3038
+ level: ((_a = paragraph.list) == null ? void 0 : _a.level) ?? 0,
3039
+ format: (_b = paragraph.list) == null ? void 0 : _b.format,
3040
+ startAt: (_c = paragraph.list) == null ? void 0 : _c.startAt
3041
+ };
3042
+ return nextParagraph;
3043
+ });
3044
+ return cloneStateWithParagraphs(
3045
+ state,
3810
3046
  nextParagraphs,
3811
- createCollapsedSelection(caretAfterMarker)
3047
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3812
3048
  );
3813
- const footnotes = ensureFootnotes(stateAfterInsert.document.footnotes);
3814
- const documentWithFootnote = {
3815
- ...stateAfterInsert.document,
3816
- footnotes: {
3817
- ...footnotes,
3818
- items: {
3819
- ...footnotes.items,
3820
- [footnote.id]: footnote
3821
- }
3049
+ }
3050
+ function setParagraphListFormat(state, format) {
3051
+ const normalized = normalizeSelection(state);
3052
+ const paragraphs = getParagraphs(state);
3053
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
3054
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
3055
+ return cloneParagraph(paragraph);
3056
+ }
3057
+ if (!paragraph.list) {
3058
+ return cloneParagraph(paragraph);
3822
3059
  }
3823
- };
3824
- const documentWithRenumber = renumberFootnotes(documentWithFootnote);
3825
- const bodyFirstParagraph = footnote.blocks.flatMap(getBlockParagraphs).find(Boolean);
3826
- if (!bodyFirstParagraph) {
3827
3060
  return {
3828
- ...stateAfterInsert,
3829
- document: documentWithRenumber
3061
+ ...cloneParagraph(paragraph),
3062
+ list: {
3063
+ ...paragraph.list,
3064
+ format: format || void 0
3065
+ }
3830
3066
  };
3831
- }
3832
- return {
3833
- ...stateAfterInsert,
3834
- document: documentWithRenumber,
3835
- selection: createCollapsedSelection(
3836
- paragraphOffsetToPosition(bodyFirstParagraph, 0)
3837
- ),
3838
- activeZone: "footnote",
3839
- activeFootnoteId: footnote.id
3840
- };
3841
- }
3842
- function cloneBlock(block) {
3843
- return block.type === "paragraph" ? {
3844
- ...block,
3845
- runs: block.runs.map((run) => ({
3846
- ...run,
3847
- styles: run.styles ? { ...run.styles } : void 0,
3848
- image: run.image ? { ...run.image } : void 0,
3849
- field: run.field ? { ...run.field } : void 0,
3850
- revision: run.revision ? { ...run.revision } : void 0,
3851
- footnoteReference: run.footnoteReference ? { ...run.footnoteReference } : void 0,
3852
- endnoteReference: run.endnoteReference ? { ...run.endnoteReference } : void 0
3853
- })),
3854
- style: block.style ? { ...block.style } : void 0,
3855
- list: block.list ? { ...block.list } : void 0
3856
- } : {
3857
- ...block,
3858
- style: block.style ? {
3859
- ...block.style,
3860
- defaultCellMargins: block.style.defaultCellMargins ? { ...block.style.defaultCellMargins } : void 0,
3861
- floating: block.style.floating ? { ...block.style.floating } : void 0,
3862
- revisionXml: block.style.revisionXml ? [...block.style.revisionXml] : void 0
3863
- } : void 0,
3864
- tblGridChangeXml: block.tblGridChangeXml,
3865
- rows: block.rows.map((row) => ({
3866
- ...row,
3867
- style: row.style ? {
3868
- ...row.style,
3869
- revisionXml: row.style.revisionXml ? [...row.style.revisionXml] : void 0
3870
- } : void 0,
3871
- cells: row.cells.map((cell) => ({
3872
- ...cell,
3873
- colSpan: cell.colSpan ?? void 0,
3874
- rowSpan: cell.rowSpan ?? void 0,
3875
- vMerge: cell.vMerge ?? void 0,
3876
- style: cell.style ? {
3877
- ...cell.style,
3878
- revisionXml: cell.style.revisionXml ? [...cell.style.revisionXml] : void 0
3879
- } : void 0,
3880
- blocks: cell.blocks.map((paragraph) => ({
3881
- ...paragraph,
3882
- runs: paragraph.runs.map((run) => ({
3883
- ...run,
3884
- styles: run.styles ? { ...run.styles } : void 0,
3885
- image: run.image ? { ...run.image } : void 0,
3886
- field: run.field ? { ...run.field } : void 0,
3887
- revision: run.revision ? { ...run.revision } : void 0,
3888
- footnoteReference: run.footnoteReference ? { ...run.footnoteReference } : void 0,
3889
- endnoteReference: run.endnoteReference ? { ...run.endnoteReference } : void 0
3890
- })),
3891
- style: paragraph.style ? { ...paragraph.style } : void 0,
3892
- list: paragraph.list ? { ...paragraph.list } : void 0
3893
- }))
3894
- }))
3895
- }))
3896
- };
3897
- }
3898
- function cloneSection(section) {
3899
- var _a, _b, _c, _d, _e, _f;
3900
- return {
3901
- ...section,
3902
- blocks: section.blocks.map(cloneBlock),
3903
- header: (_a = section.header) == null ? void 0 : _a.map(cloneBlock),
3904
- firstPageHeader: (_b = section.firstPageHeader) == null ? void 0 : _b.map(cloneBlock),
3905
- evenPageHeader: (_c = section.evenPageHeader) == null ? void 0 : _c.map(cloneBlock),
3906
- footer: (_d = section.footer) == null ? void 0 : _d.map(cloneBlock),
3907
- firstPageFooter: (_e = section.firstPageFooter) == null ? void 0 : _e.map(cloneBlock),
3908
- evenPageFooter: (_f = section.evenPageFooter) == null ? void 0 : _f.map(cloneBlock)
3909
- };
3910
- }
3911
- function cloneFootnote(footnote) {
3912
- return {
3913
- ...footnote,
3914
- blocks: footnote.blocks.map(cloneBlock)
3915
- };
3916
- }
3917
- function cloneFootnotes(footnotes) {
3918
- var _a, _b;
3919
- if (!footnotes) return void 0;
3920
- const nextItems = {};
3921
- for (const [id, footnote] of Object.entries(footnotes.items)) {
3922
- nextItems[id] = cloneFootnote(footnote);
3923
- }
3924
- return {
3925
- items: nextItems,
3926
- settings: footnotes.settings ? { ...footnotes.settings } : void 0,
3927
- separator: (_a = footnotes.separator) == null ? void 0 : _a.map(cloneBlock),
3928
- continuationSeparator: (_b = footnotes.continuationSeparator) == null ? void 0 : _b.map(cloneBlock)
3929
- };
3930
- }
3931
- function cloneEndnote(endnote) {
3932
- return {
3933
- ...endnote,
3934
- blocks: endnote.blocks.map(cloneBlock)
3935
- };
3936
- }
3937
- function cloneEndnotes(endnotes) {
3938
- var _a, _b;
3939
- if (!endnotes) return void 0;
3940
- const nextItems = {};
3941
- for (const [id, endnote] of Object.entries(endnotes.items)) {
3942
- nextItems[id] = cloneEndnote(endnote);
3943
- }
3944
- return {
3945
- items: nextItems,
3946
- settings: endnotes.settings ? { ...endnotes.settings } : void 0,
3947
- separator: (_a = endnotes.separator) == null ? void 0 : _a.map(cloneBlock),
3948
- continuationSeparator: (_b = endnotes.continuationSeparator) == null ? void 0 : _b.map(cloneBlock)
3949
- };
3067
+ });
3068
+ return cloneStateWithParagraphs(
3069
+ state,
3070
+ nextParagraphs,
3071
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3072
+ );
3950
3073
  }
3951
- function cloneEditorState(source) {
3952
- var _a;
3953
- return {
3954
- ...source,
3955
- document: {
3956
- ...source.document,
3957
- sections: (_a = source.document.sections) == null ? void 0 : _a.map(cloneSection),
3958
- footnotes: cloneFootnotes(source.document.footnotes),
3959
- endnotes: cloneEndnotes(source.document.endnotes)
3960
- },
3961
- selection: {
3962
- anchor: { ...source.selection.anchor },
3963
- focus: { ...source.selection.focus }
3964
- },
3965
- activeSectionIndex: source.activeSectionIndex ?? 0,
3966
- activeZone: source.activeZone ?? "main",
3967
- activeFootnoteId: source.activeFootnoteId
3968
- };
3074
+ function setParagraphListStartAt(state, startAt) {
3075
+ const normalized = normalizeSelection(state);
3076
+ const paragraphs = getParagraphs(state);
3077
+ const nextParagraphs = paragraphs.map((paragraph, paragraphIndex) => {
3078
+ if (paragraphIndex < normalized.startIndex || paragraphIndex > normalized.endIndex) {
3079
+ return cloneParagraph(paragraph);
3080
+ }
3081
+ if (!paragraph.list) {
3082
+ return cloneParagraph(paragraph);
3083
+ }
3084
+ return {
3085
+ ...cloneParagraph(paragraph),
3086
+ list: {
3087
+ ...paragraph.list,
3088
+ startAt: startAt !== null ? startAt : void 0
3089
+ }
3090
+ };
3091
+ });
3092
+ return cloneStateWithParagraphs(
3093
+ state,
3094
+ nextParagraphs,
3095
+ preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
3096
+ );
3969
3097
  }
3970
3098
  function createEditorCommandsController(deps) {
3971
3099
  const {
@@ -5759,6 +4887,478 @@ function useEditorFindReplace(deps) {
5759
4887
  setIsOpen
5760
4888
  };
5761
4889
  }
4890
+ function patchStyleValue(style2, key, value) {
4891
+ const nextStyle = { ...style2 ?? {} };
4892
+ if (value === null) {
4893
+ delete nextStyle[key];
4894
+ } else {
4895
+ nextStyle[key] = value;
4896
+ }
4897
+ return Object.keys(nextStyle).length > 0 ? nextStyle : void 0;
4898
+ }
4899
+ function updateStateSections(state, updateBlocks) {
4900
+ const sections = getDocumentSections(state.document);
4901
+ const nextSections = sections.map((section) => ({
4902
+ ...section,
4903
+ blocks: updateBlocks(section.blocks),
4904
+ header: section.header ? updateBlocks(section.header) : void 0,
4905
+ footer: section.footer ? updateBlocks(section.footer) : void 0
4906
+ }));
4907
+ return {
4908
+ ...state,
4909
+ document: {
4910
+ ...state.document,
4911
+ sections: nextSections
4912
+ }
4913
+ };
4914
+ }
4915
+ function updateTablesInBlocks(blocks, updateTable) {
4916
+ return blocks.map((block) => {
4917
+ if (block.type === "table") {
4918
+ return updateTable(block);
4919
+ }
4920
+ return block;
4921
+ });
4922
+ }
4923
+ function updateNestedTablesInBlocks(blocks, updateTable) {
4924
+ return blocks.map((block) => {
4925
+ if (block.type === "paragraph") return block;
4926
+ return {
4927
+ ...updateTable(block),
4928
+ rows: block.rows.map((row) => ({
4929
+ ...row,
4930
+ cells: row.cells.map((cell) => ({
4931
+ ...cell,
4932
+ blocks: updateNestedTablesInBlocks(
4933
+ cell.blocks,
4934
+ updateTable
4935
+ )
4936
+ }))
4937
+ }))
4938
+ };
4939
+ });
4940
+ }
4941
+ function getBlocksForZone(document2, sectionIndex, zone) {
4942
+ const section = getDocumentSections(document2)[sectionIndex];
4943
+ if (!section) return void 0;
4944
+ if (zone === "header") return section.header;
4945
+ if (zone === "footer") return section.footer;
4946
+ return section.blocks;
4947
+ }
4948
+ function resolveActiveTableLocation(state) {
4949
+ const activeSectionIndex = getActiveSectionIndex(state);
4950
+ const loc = findParagraphTableLocation(
4951
+ state.document,
4952
+ state.selection.focus.paragraphId,
4953
+ activeSectionIndex
4954
+ );
4955
+ return loc ? { activeSectionIndex, loc } : null;
4956
+ }
4957
+ function updateActiveTableBlocks(state, updateTable) {
4958
+ const target = resolveActiveTableLocation(state);
4959
+ if (!target) return state;
4960
+ const { activeSectionIndex, loc } = target;
4961
+ const activeZone = getActiveZone(state);
4962
+ const updateBlocks = (blocks, zone) => blocks.map((block, blockIndex) => {
4963
+ if (block.type === "table" && blockIndex === loc.blockIndex && zone === loc.zone) {
4964
+ return updateTable(block);
4965
+ }
4966
+ return block;
4967
+ });
4968
+ const nextSections = getDocumentSections(state.document).map(
4969
+ (section, sectionIndex) => {
4970
+ if (sectionIndex !== activeSectionIndex) return section;
4971
+ return {
4972
+ ...section,
4973
+ blocks: activeZone === "main" ? updateBlocks(section.blocks, "main") : section.blocks,
4974
+ header: activeZone === "header" && section.header ? updateBlocks(section.header, "header") : section.header,
4975
+ footer: activeZone === "footer" && section.footer ? updateBlocks(section.footer, "footer") : section.footer
4976
+ };
4977
+ }
4978
+ );
4979
+ return {
4980
+ ...state,
4981
+ document: {
4982
+ ...state.document,
4983
+ sections: nextSections
4984
+ }
4985
+ };
4986
+ }
4987
+ function collectTableSelectedParagraphIds(state) {
4988
+ const selectedParagraphIds = /* @__PURE__ */ new Set();
4989
+ const activeSectionIndex = getActiveSectionIndex(state);
4990
+ const anchorLoc = findParagraphTableLocation(
4991
+ state.document,
4992
+ state.selection.anchor.paragraphId,
4993
+ activeSectionIndex
4994
+ );
4995
+ const focusLoc = findParagraphTableLocation(
4996
+ state.document,
4997
+ state.selection.focus.paragraphId,
4998
+ activeSectionIndex
4999
+ );
5000
+ if (!anchorLoc || !focusLoc || anchorLoc.blockIndex !== focusLoc.blockIndex || anchorLoc.zone !== focusLoc.zone) {
5001
+ return selectedParagraphIds;
5002
+ }
5003
+ const blocks = getBlocksForZone(
5004
+ state.document,
5005
+ activeSectionIndex,
5006
+ anchorLoc.zone
5007
+ );
5008
+ const tableBlock = blocks == null ? void 0 : blocks[anchorLoc.blockIndex];
5009
+ if (!tableBlock || tableBlock.type !== "table") {
5010
+ return selectedParagraphIds;
5011
+ }
5012
+ const tableLayout = buildTableCellLayout(tableBlock);
5013
+ const anchorCell = tableLayout.find(
5014
+ (entry) => entry.rowIndex === anchorLoc.rowIndex && entry.cellIndex === anchorLoc.cellIndex
5015
+ );
5016
+ const focusCell = tableLayout.find(
5017
+ (entry) => entry.rowIndex === focusLoc.rowIndex && entry.cellIndex === focusLoc.cellIndex
5018
+ );
5019
+ if (!anchorCell || !focusCell) {
5020
+ return selectedParagraphIds;
5021
+ }
5022
+ const startRow = Math.min(
5023
+ anchorCell.visualRowIndex,
5024
+ focusCell.visualRowIndex
5025
+ );
5026
+ const endRow = Math.max(
5027
+ anchorCell.visualRowIndex + anchorCell.rowSpan - 1,
5028
+ focusCell.visualRowIndex + focusCell.rowSpan - 1
5029
+ );
5030
+ const startCol = Math.min(
5031
+ anchorCell.visualColumnIndex,
5032
+ focusCell.visualColumnIndex
5033
+ );
5034
+ const endCol = Math.max(
5035
+ anchorCell.visualColumnIndex + anchorCell.colSpan - 1,
5036
+ focusCell.visualColumnIndex + focusCell.colSpan - 1
5037
+ );
5038
+ const cells = tableLayout.filter(
5039
+ (entry) => entry.visualRowIndex <= endRow && entry.visualRowIndex + entry.rowSpan - 1 >= startRow && entry.visualColumnIndex <= endCol && entry.visualColumnIndex + entry.colSpan - 1 >= startCol
5040
+ );
5041
+ for (const entry of cells) {
5042
+ for (const paragraph of entry.cell.blocks) {
5043
+ selectedParagraphIds.add(paragraph.id);
5044
+ }
5045
+ }
5046
+ return selectedParagraphIds;
5047
+ }
5048
+ function collectLinearSelectedParagraphIds$1(state) {
5049
+ const selectedParagraphIds = /* @__PURE__ */ new Set();
5050
+ const normalized = normalizeSelection(state);
5051
+ const paragraphs = getParagraphs(state);
5052
+ for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
5053
+ selectedParagraphIds.add(paragraphs[i].id);
5054
+ }
5055
+ return selectedParagraphIds;
5056
+ }
5057
+ function setTableCellStyleValue(state, key, value) {
5058
+ const selectedParagraphIds = collectTableSelectedParagraphIds(state);
5059
+ if (selectedParagraphIds.size === 0) {
5060
+ for (const id of collectLinearSelectedParagraphIds$1(state)) {
5061
+ selectedParagraphIds.add(id);
5062
+ }
5063
+ }
5064
+ const updateCell = (cell) => ({
5065
+ ...cell,
5066
+ style: patchStyleValue(cell.style, key, value)
5067
+ });
5068
+ const nextSections = getDocumentSections(state.document).map((section) => ({
5069
+ ...section,
5070
+ blocks: updateTableCellsInBlocks(
5071
+ section.blocks,
5072
+ selectedParagraphIds,
5073
+ updateCell
5074
+ ),
5075
+ header: section.header ? updateTableCellsInBlocks(
5076
+ section.header,
5077
+ selectedParagraphIds,
5078
+ updateCell
5079
+ ) : void 0,
5080
+ footer: section.footer ? updateTableCellsInBlocks(
5081
+ section.footer,
5082
+ selectedParagraphIds,
5083
+ updateCell
5084
+ ) : void 0
5085
+ }));
5086
+ return {
5087
+ ...state,
5088
+ document: {
5089
+ ...state.document,
5090
+ sections: nextSections
5091
+ }
5092
+ };
5093
+ }
5094
+ function setTableCellWidth(state, width) {
5095
+ return setTableCellStyleValue(state, "width", width);
5096
+ }
5097
+ function setTableCellBorders(state, border) {
5098
+ let nextState = setTableCellStyleValue(state, "borderTop", border);
5099
+ nextState = setTableCellStyleValue(nextState, "borderRight", border);
5100
+ nextState = setTableCellStyleValue(nextState, "borderBottom", border);
5101
+ nextState = setTableCellStyleValue(nextState, "borderLeft", border);
5102
+ return nextState;
5103
+ }
5104
+ function collectLinearSelectedParagraphIds(state) {
5105
+ const normalized = normalizeSelection(state);
5106
+ const paragraphs = getParagraphs(state);
5107
+ const selectedParagraphIds = /* @__PURE__ */ new Set();
5108
+ for (let i = normalized.startIndex; i <= normalized.endIndex; i += 1) {
5109
+ selectedParagraphIds.add(paragraphs[i].id);
5110
+ }
5111
+ return selectedParagraphIds;
5112
+ }
5113
+ function setTableStyleValue(state, key, value) {
5114
+ const selectedParagraphIds = collectLinearSelectedParagraphIds(state);
5115
+ const updateTable = (table) => ({
5116
+ ...table,
5117
+ style: patchStyleValue(table.style, key, value)
5118
+ });
5119
+ const updateBlocks = (blocks) => {
5120
+ return blocks.map((block) => {
5121
+ if (block.type === "paragraph") return block;
5122
+ const paragraphsInTable = getBlockParagraphs(block);
5123
+ const isSelected = paragraphsInTable.some(
5124
+ (paragraph) => selectedParagraphIds.has(paragraph.id)
5125
+ );
5126
+ const updatedRows = block.rows.map((row) => ({
5127
+ ...row,
5128
+ cells: row.cells.map((cell) => ({
5129
+ ...cell,
5130
+ blocks: updateBlocks(cell.blocks)
5131
+ }))
5132
+ }));
5133
+ const nextTable = { ...block, rows: updatedRows };
5134
+ return isSelected ? updateTable(nextTable) : nextTable;
5135
+ });
5136
+ };
5137
+ return updateStateSections(state, updateBlocks);
5138
+ }
5139
+ function setActiveTableStyleValue(state, tableId, key, value) {
5140
+ const updateTable = (table) => {
5141
+ if (table.id !== tableId) return table;
5142
+ return {
5143
+ ...table,
5144
+ style: patchStyleValue(table.style, key, value)
5145
+ };
5146
+ };
5147
+ return updateStateSections(
5148
+ state,
5149
+ (blocks) => updateNestedTablesInBlocks(blocks, updateTable)
5150
+ );
5151
+ }
5152
+ function setSelectedTableRowStyleValue(state, key, value) {
5153
+ const target = resolveActiveTableLocation(state);
5154
+ if (!target) return state;
5155
+ const updateTable = (table) => {
5156
+ const nextRows = table.rows.map(
5157
+ (row, rowIndex) => rowIndex === target.loc.rowIndex ? { ...row, style: patchStyleValue(row.style, key, value) } : row
5158
+ );
5159
+ return { ...table, rows: nextRows };
5160
+ };
5161
+ return updateActiveTableBlocks(state, updateTable);
5162
+ }
5163
+ function setSelectedTableRowHeader(state, value) {
5164
+ const target = resolveActiveTableLocation(state);
5165
+ if (!target) return state;
5166
+ const updateTable = (table) => ({
5167
+ ...table,
5168
+ rows: table.rows.map(
5169
+ (row, rowIndex) => rowIndex === target.loc.rowIndex ? { ...row, isHeader: value === null ? void 0 : value } : row
5170
+ )
5171
+ });
5172
+ return updateActiveTableBlocks(state, updateTable);
5173
+ }
5174
+ function setTableRowHeight(state, tableId, rowIndex, height) {
5175
+ const updateTable = (table) => {
5176
+ if (table.id !== tableId) return table;
5177
+ const nextRows = [...table.rows];
5178
+ const row = nextRows[rowIndex];
5179
+ if (row) {
5180
+ nextRows[rowIndex] = {
5181
+ ...row,
5182
+ style: patchStyleValue(row.style, "height", height)
5183
+ };
5184
+ }
5185
+ return { ...table, rows: nextRows };
5186
+ };
5187
+ return updateStateSections(
5188
+ state,
5189
+ (blocks) => updateTablesInBlocks(blocks, updateTable)
5190
+ );
5191
+ }
5192
+ function parseWidthToPt(value) {
5193
+ if (typeof value === "number" && Number.isFinite(value)) {
5194
+ return value;
5195
+ }
5196
+ if (typeof value !== "string") {
5197
+ return null;
5198
+ }
5199
+ const trimmed = value.trim().toLowerCase();
5200
+ if (!trimmed || trimmed.includes("%")) {
5201
+ return null;
5202
+ }
5203
+ if (trimmed.endsWith("pt")) {
5204
+ const parsed2 = Number.parseFloat(trimmed.slice(0, -2));
5205
+ return Number.isFinite(parsed2) ? parsed2 : null;
5206
+ }
5207
+ if (trimmed.endsWith("px")) {
5208
+ const parsed2 = Number.parseFloat(trimmed.slice(0, -2));
5209
+ return Number.isFinite(parsed2) ? parsed2 * PT_PER_PX : null;
5210
+ }
5211
+ if (!/^[+-]?\d+(\.\d+)?$/.test(trimmed)) {
5212
+ return null;
5213
+ }
5214
+ const parsed = Number.parseFloat(trimmed);
5215
+ return Number.isFinite(parsed) ? parsed : null;
5216
+ }
5217
+ function setTableColumnWidths(state, tableId, columnWidths, tableWidth, tableIndentLeft) {
5218
+ const updateTable = (table) => {
5219
+ var _a;
5220
+ if (table.id !== tableId) return table;
5221
+ const tableLayout = buildTableCellLayout(table);
5222
+ const visualColumnCount = Math.max(
5223
+ 1,
5224
+ ...tableLayout.map(
5225
+ (entry) => entry.visualColumnIndex + Math.max(1, entry.colSpan)
5226
+ )
5227
+ );
5228
+ const nextGridCols = Array(visualColumnCount);
5229
+ let hasGridOverride = false;
5230
+ let canResolveGrid = true;
5231
+ for (let columnIndex = 0; columnIndex < visualColumnCount; columnIndex += 1) {
5232
+ const override = parseWidthToPt(columnWidths[columnIndex]);
5233
+ if (override !== null) {
5234
+ nextGridCols[columnIndex] = Math.max(1, override);
5235
+ hasGridOverride = true;
5236
+ continue;
5237
+ }
5238
+ const existing = (_a = table.gridCols) == null ? void 0 : _a[columnIndex];
5239
+ if (typeof existing === "number" && Number.isFinite(existing) && existing > 0) {
5240
+ nextGridCols[columnIndex] = existing;
5241
+ continue;
5242
+ }
5243
+ canResolveGrid = false;
5244
+ break;
5245
+ }
5246
+ const nextRows = table.rows.map((row, rowIndex) => {
5247
+ const nextCells = row.cells.map((cell, cellIndex) => {
5248
+ const entry = tableLayout.find(
5249
+ (item) => item.rowIndex === rowIndex && item.cellIndex === cellIndex
5250
+ );
5251
+ if (!entry) return cell;
5252
+ const rightVisualColumnIndex = entry.visualColumnIndex + entry.colSpan - 1;
5253
+ const newWidth = columnWidths[rightVisualColumnIndex];
5254
+ if (newWidth !== void 0 && entry.colSpan === 1) {
5255
+ return {
5256
+ ...cell,
5257
+ style: {
5258
+ ...cell.style ?? {},
5259
+ width: typeof newWidth === "number" ? newWidth : newWidth
5260
+ }
5261
+ };
5262
+ }
5263
+ return cell;
5264
+ });
5265
+ return { ...row, cells: nextCells };
5266
+ });
5267
+ const nextStyle = { ...table.style ?? {} };
5268
+ if (tableWidth !== void 0) {
5269
+ nextStyle.width = tableWidth;
5270
+ }
5271
+ if (tableIndentLeft !== void 0) {
5272
+ nextStyle.indentLeft = typeof tableIndentLeft === "number" ? tableIndentLeft : Number(tableIndentLeft);
5273
+ }
5274
+ return {
5275
+ ...table,
5276
+ rows: nextRows,
5277
+ gridCols: hasGridOverride && canResolveGrid ? nextGridCols : table.gridCols,
5278
+ style: Object.keys(nextStyle).length > 0 ? nextStyle : void 0
5279
+ };
5280
+ };
5281
+ return updateStateSections(
5282
+ state,
5283
+ (blocks) => updateTablesInBlocks(blocks, updateTable)
5284
+ );
5285
+ }
5286
+ function insertTableAtSelection(state, rows, cols) {
5287
+ const initialCellWidth = `${100 / Math.max(1, cols)}%`;
5288
+ const tableRows = [];
5289
+ for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
5290
+ const cells = [];
5291
+ for (let columnIndex = 0; columnIndex < cols; columnIndex += 1) {
5292
+ cells.push({
5293
+ ...createEditorTableCell([createEditorParagraph("")]),
5294
+ style: {
5295
+ width: initialCellWidth
5296
+ }
5297
+ });
5298
+ }
5299
+ tableRows.push(createEditorTableRow(cells));
5300
+ }
5301
+ const table = {
5302
+ ...createEditorTable(tableRows),
5303
+ style: {
5304
+ width: "100%"
5305
+ }
5306
+ };
5307
+ const focus = clampPosition(state, state.selection.focus);
5308
+ const sections = getDocumentSections(state.document);
5309
+ const activeSectionIndex = getActiveSectionIndex(state);
5310
+ const zone = getActiveZone(state);
5311
+ const insertIntoBlocks = (blocks) => {
5312
+ const blockIndex = blocks.findIndex((block) => {
5313
+ if (block.id === focus.paragraphId) return true;
5314
+ if (block.type === "paragraph") return false;
5315
+ return getBlockParagraphs(block).some(
5316
+ (paragraph) => paragraph.id === focus.paragraphId
5317
+ );
5318
+ });
5319
+ if (blockIndex === -1) {
5320
+ return { nextBlocks: blocks, found: false };
5321
+ }
5322
+ return {
5323
+ nextBlocks: [
5324
+ ...blocks.slice(0, blockIndex + 1),
5325
+ table,
5326
+ ...blocks.slice(blockIndex + 1)
5327
+ ],
5328
+ found: true
5329
+ };
5330
+ };
5331
+ const section = sections[activeSectionIndex];
5332
+ if (!section) return state;
5333
+ const nextSection = { ...section };
5334
+ let found = false;
5335
+ if (zone === "header") {
5336
+ const result = insertIntoBlocks(section.header ?? []);
5337
+ nextSection.header = result.nextBlocks;
5338
+ found = result.found;
5339
+ } else if (zone === "footer") {
5340
+ const result = insertIntoBlocks(section.footer ?? []);
5341
+ nextSection.footer = result.nextBlocks;
5342
+ found = result.found;
5343
+ } else {
5344
+ const result = insertIntoBlocks(section.blocks);
5345
+ nextSection.blocks = result.nextBlocks;
5346
+ found = result.found;
5347
+ }
5348
+ if (!found) return state;
5349
+ const nextSections = [...sections];
5350
+ nextSections[activeSectionIndex] = nextSection;
5351
+ return {
5352
+ ...state,
5353
+ document: {
5354
+ ...state.document,
5355
+ sections: nextSections
5356
+ },
5357
+ selection: withSelection(
5358
+ paragraphOffsetToPosition(table.rows[0].cells[0].blocks[0], 0)
5359
+ )
5360
+ };
5361
+ }
5762
5362
  const getRowVisualWidth = (row) => row.cells.reduce((sum, cell) => sum + Math.max(1, cell.colSpan ?? 1), 0);
5763
5363
  const getTableVisualWidth = (table) => table.rows.reduce((max, row) => Math.max(max, getRowVisualWidth(row)), 0);
5764
5364
  const findCellAtVisualColumn = (row, visualColumn) => {
@@ -8804,12 +8404,19 @@ function serializeInstrTextRun(instruction, rPrXml) {
8804
8404
  instruction
8805
8405
  )}</w:instrText></w:r>`;
8806
8406
  }
8807
- function serializeFootnoteRefMarker() {
8808
- return `<w:r><w:rPr><w:rStyle w:val="FootnoteReference"/><w:vertAlign w:val="superscript"/></w:rPr><w:footnoteRef/></w:r>`;
8407
+ const REFERENCE_STYLE = {
8408
+ footnote: "FootnoteReference",
8409
+ endnote: "EndnoteReference"
8410
+ };
8411
+ function serializeNoteRefMarker(kind) {
8412
+ return `<w:r><w:rPr><w:rStyle w:val="${REFERENCE_STYLE[kind]}"/><w:vertAlign w:val="superscript"/></w:rPr><w:${kind}Ref/></w:r>`;
8809
8413
  }
8810
- function serializeFootnoteReference(run, materializedRunStyle, context) {
8811
- var _a;
8812
- const docxId = (_a = context.footnoteIdMap) == null ? void 0 : _a.get(run.footnoteReference.footnoteId);
8414
+ function serializeNoteReference(kind, reference, materializedRunStyle, context) {
8415
+ if (!reference) {
8416
+ return null;
8417
+ }
8418
+ const idMap = kind === "footnote" ? context.footnoteIdMap : context.endnoteIdMap;
8419
+ const docxId = idMap == null ? void 0 : idMap.get(reference.noteId);
8813
8420
  if (docxId === void 0) {
8814
8421
  return null;
8815
8422
  }
@@ -8817,26 +8424,33 @@ function serializeFootnoteReference(run, materializedRunStyle, context) {
8817
8424
  ...materializedRunStyle ?? {},
8818
8425
  superscript: true
8819
8426
  };
8820
- const customMarkAttr = run.footnoteReference.customMark ? ' w:customMarkFollows="1"' : "";
8821
- const customMarkText = run.footnoteReference.customMark ? `<w:t xml:space="preserve">${escapeXml(run.footnoteReference.customMark)}</w:t>` : "";
8822
- return `<w:r>${serializeRunProperties(referenceStyle)}<w:footnoteReference${customMarkAttr} w:id="${docxId}"/>${customMarkText}</w:r>`;
8427
+ const customMarkAttr = reference.customMark ? ' w:customMarkFollows="1"' : "";
8428
+ const customMarkText = reference.customMark ? `<w:t xml:space="preserve">${escapeXml(reference.customMark)}</w:t>` : "";
8429
+ return `<w:r>${serializeRunProperties(referenceStyle)}<w:${kind}Reference${customMarkAttr} w:id="${docxId}"/>${customMarkText}</w:r>`;
8430
+ }
8431
+ function serializeFootnoteRefMarker() {
8432
+ return serializeNoteRefMarker("footnote");
8433
+ }
8434
+ function serializeFootnoteReference(run, materializedRunStyle, context) {
8435
+ const ref = run.footnoteReference;
8436
+ return serializeNoteReference(
8437
+ "footnote",
8438
+ ref ? { noteId: ref.footnoteId, customMark: ref.customMark } : void 0,
8439
+ materializedRunStyle,
8440
+ context
8441
+ );
8823
8442
  }
8824
8443
  function serializeEndnoteRefMarker() {
8825
- return `<w:r><w:rPr><w:rStyle w:val="EndnoteReference"/><w:vertAlign w:val="superscript"/></w:rPr><w:endnoteRef/></w:r>`;
8444
+ return serializeNoteRefMarker("endnote");
8826
8445
  }
8827
8446
  function serializeEndnoteReference(run, materializedRunStyle, context) {
8828
- var _a;
8829
- const docxId = (_a = context.endnoteIdMap) == null ? void 0 : _a.get(run.endnoteReference.endnoteId);
8830
- if (docxId === void 0) {
8831
- return null;
8832
- }
8833
- const referenceStyle = {
8834
- ...materializedRunStyle ?? {},
8835
- superscript: true
8836
- };
8837
- const customMarkAttr = run.endnoteReference.customMark ? ' w:customMarkFollows="1"' : "";
8838
- const customMarkText = run.endnoteReference.customMark ? `<w:t xml:space="preserve">${escapeXml(run.endnoteReference.customMark)}</w:t>` : "";
8839
- return `<w:r>${serializeRunProperties(referenceStyle)}<w:endnoteReference${customMarkAttr} w:id="${docxId}"/>${customMarkText}</w:r>`;
8447
+ const ref = run.endnoteReference;
8448
+ return serializeNoteReference(
8449
+ "endnote",
8450
+ ref ? { noteId: ref.endnoteId, customMark: ref.customMark } : void 0,
8451
+ materializedRunStyle,
8452
+ context
8453
+ );
8840
8454
  }
8841
8455
  function wrapRunWithHyperlink(runXml, link, context) {
8842
8456
  if (link.startsWith("#")) {
@@ -40327,11 +39941,9 @@ function createTablePropertiesDialogBridge(deps) {
40327
39941
  );
40328
39942
  next = setSelectedTableRowStyleValue(next, "hidden", values.hiddenRow);
40329
39943
  if (values.columnWidth !== null) {
40330
- next = setTableColumnWidths(
40331
- next,
40332
- currentCtx.tableId,
40333
- { [currentCtx.visualColumnIndex]: values.columnWidth }
40334
- );
39944
+ next = setTableColumnWidths(next, currentCtx.tableId, {
39945
+ [currentCtx.visualColumnIndex]: values.columnWidth
39946
+ });
40335
39947
  }
40336
39948
  next = setCellStyle(next, "width", values.cellWidth);
40337
39949
  next = setCellStyle(next, "verticalAlign", values.cellVerticalAlign);
@@ -40360,6 +39972,369 @@ function createTablePropertiesDialogBridge(deps) {
40360
39972
  applyTablePropertiesDialogValues
40361
39973
  };
40362
39974
  }
39975
+ function textRunStylesToCss(style2) {
39976
+ if (!style2) {
39977
+ return "";
39978
+ }
39979
+ const parts = [];
39980
+ if (style2.fontFamily) {
39981
+ parts.push(`font-family:${style2.fontFamily}`);
39982
+ }
39983
+ if (style2.fontSize !== void 0 && style2.fontSize !== null) {
39984
+ parts.push(`font-size:${style2.fontSize}px`);
39985
+ }
39986
+ if (style2.color) {
39987
+ parts.push(`color:${style2.color}`);
39988
+ }
39989
+ if (style2.highlight) {
39990
+ parts.push(`background-color:${style2.highlight}`);
39991
+ } else if (style2.shading) {
39992
+ parts.push(`background-color:${style2.shading}`);
39993
+ }
39994
+ if (style2.superscript) {
39995
+ parts.push("vertical-align:super");
39996
+ parts.push("font-size:0.75em");
39997
+ } else if (style2.subscript) {
39998
+ parts.push("vertical-align:sub");
39999
+ parts.push("font-size:0.75em");
40000
+ }
40001
+ if (style2.bold) {
40002
+ parts.push("font-weight:700");
40003
+ }
40004
+ if (style2.italic) {
40005
+ parts.push("font-style:italic");
40006
+ }
40007
+ if (style2.hidden) {
40008
+ parts.push("display:none");
40009
+ }
40010
+ if (style2.allCaps) {
40011
+ parts.push("text-transform:uppercase");
40012
+ }
40013
+ if (style2.smallCaps) {
40014
+ parts.push("font-variant:small-caps");
40015
+ }
40016
+ if (style2.characterScale !== void 0 && style2.characterScale !== null) {
40017
+ parts.push(`font-stretch:${style2.characterScale}%`);
40018
+ }
40019
+ if (style2.characterSpacing !== void 0 && style2.characterSpacing !== null) {
40020
+ parts.push(`letter-spacing:${style2.characterSpacing}pt`);
40021
+ }
40022
+ if (getPrimaryTextLanguage(style2.language)) {
40023
+ parts.push("hyphens:auto");
40024
+ }
40025
+ if (style2.baselineShift !== void 0 && style2.baselineShift !== null) {
40026
+ parts.push(`vertical-align:${style2.baselineShift}pt`);
40027
+ }
40028
+ const ligatures = ligaturesToCss$1(style2.ligatures);
40029
+ if (ligatures) {
40030
+ parts.push(`font-variant-ligatures:${ligatures}`);
40031
+ }
40032
+ const numeric = numericToCss$1(style2.numberSpacing, style2.numberForm);
40033
+ if (numeric) {
40034
+ parts.push(`font-variant-numeric:${numeric}`);
40035
+ }
40036
+ const featureSettings = fontFeatureSettingsToCss(
40037
+ style2.stylisticSet,
40038
+ style2.contextualAlternates
40039
+ );
40040
+ if (featureSettings) {
40041
+ parts.push(`font-feature-settings:${featureSettings}`);
40042
+ }
40043
+ const decorations = [];
40044
+ if (style2.underline || style2.link) {
40045
+ decorations.push("underline");
40046
+ }
40047
+ if (style2.strike) {
40048
+ decorations.push("line-through");
40049
+ }
40050
+ if (style2.doubleStrike) {
40051
+ decorations.push("line-through");
40052
+ }
40053
+ if (decorations.length > 0) {
40054
+ parts.push(`text-decoration:${decorations.join(" ")}`);
40055
+ if (style2.underline || style2.link) {
40056
+ const cssDecorationStyle = underlineStyleToCssDecorationStyle(
40057
+ style2.underlineStyle
40058
+ );
40059
+ if (cssDecorationStyle) {
40060
+ parts.push(`text-decoration-style:${cssDecorationStyle}`);
40061
+ }
40062
+ if (style2.underlineColor) {
40063
+ parts.push(`text-decoration-color:${style2.underlineColor}`);
40064
+ }
40065
+ }
40066
+ }
40067
+ return parts.join(";");
40068
+ }
40069
+ function getPrimaryTextLanguage(language) {
40070
+ return (language == null ? void 0 : language.value) ?? (language == null ? void 0 : language.bidi) ?? (language == null ? void 0 : language.eastAsia) ?? null;
40071
+ }
40072
+ function ligaturesToCss$1(ligatures) {
40073
+ switch (ligatures) {
40074
+ case "none":
40075
+ return "none";
40076
+ case "standard":
40077
+ return "common-ligatures";
40078
+ case "contextual":
40079
+ return "contextual";
40080
+ case "historical":
40081
+ return "historical-ligatures";
40082
+ case "standardContextual":
40083
+ return "common-ligatures contextual";
40084
+ default:
40085
+ return null;
40086
+ }
40087
+ }
40088
+ function numericToCss$1(numberSpacing, numberForm) {
40089
+ const parts = [];
40090
+ if (numberSpacing === "proportional") parts.push("proportional-nums");
40091
+ if (numberSpacing === "tabular") parts.push("tabular-nums");
40092
+ if (numberForm === "lining") parts.push("lining-nums");
40093
+ if (numberForm === "oldStyle") parts.push("oldstyle-nums");
40094
+ return parts.join(" ") || null;
40095
+ }
40096
+ function fontFeatureSettingsToCss(stylisticSet, contextualAlternates) {
40097
+ const parts = [];
40098
+ if (typeof stylisticSet === "number" && stylisticSet >= 1 && stylisticSet <= 20) {
40099
+ parts.push(`"ss${String(stylisticSet).padStart(2, "0")}" 1`);
40100
+ }
40101
+ if (contextualAlternates) {
40102
+ parts.push('"calt" 1');
40103
+ }
40104
+ return parts.join(", ") || null;
40105
+ }
40106
+ function paragraphStyleToCssText(style2) {
40107
+ if (!style2) {
40108
+ return "";
40109
+ }
40110
+ const parts = [];
40111
+ if (style2.align) {
40112
+ parts.push(`text-align:${style2.align}`);
40113
+ }
40114
+ if (style2.lineHeight !== void 0 && style2.lineHeight !== null) {
40115
+ const isAbsoluteRule = style2.lineRule === "exact" || style2.lineRule === "atLeast";
40116
+ parts.push(`line-height:${style2.lineHeight}${isAbsoluteRule ? "px" : ""}`);
40117
+ }
40118
+ if (style2.spacingBefore !== void 0 && style2.spacingBefore !== null) {
40119
+ parts.push(`padding-top:${style2.spacingBefore}px`);
40120
+ }
40121
+ if (style2.spacingAfter !== void 0 && style2.spacingAfter !== null) {
40122
+ parts.push(`padding-bottom:${style2.spacingAfter}px`);
40123
+ }
40124
+ if (style2.indentLeft !== void 0 && style2.indentLeft !== null) {
40125
+ parts.push(`padding-left:${style2.indentLeft}px`);
40126
+ }
40127
+ if (style2.indentRight !== void 0 && style2.indentRight !== null) {
40128
+ parts.push(`padding-right:${style2.indentRight}px`);
40129
+ }
40130
+ if (style2.indentFirstLine !== void 0 && style2.indentFirstLine !== null) {
40131
+ parts.push(`text-indent:${style2.indentFirstLine}px`);
40132
+ }
40133
+ return parts.join(";");
40134
+ }
40135
+ function escapeHtml(text) {
40136
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
40137
+ }
40138
+ function textLanguageToHtmlAttributes(language) {
40139
+ if (!language) {
40140
+ return "";
40141
+ }
40142
+ const attrs = [];
40143
+ const primary = getPrimaryTextLanguage(language);
40144
+ if (primary) {
40145
+ attrs.push(`lang="${escapeHtml(primary)}"`);
40146
+ }
40147
+ if (language.value) {
40148
+ attrs.push(`data-oasis-lang-value="${escapeHtml(language.value)}"`);
40149
+ }
40150
+ if (language.eastAsia) {
40151
+ attrs.push(`data-oasis-lang-east-asia="${escapeHtml(language.eastAsia)}"`);
40152
+ }
40153
+ if (language.bidi) {
40154
+ attrs.push(`data-oasis-lang-bidi="${escapeHtml(language.bidi)}"`);
40155
+ }
40156
+ return attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
40157
+ }
40158
+ function serializeImageRunToHtml(run, document2) {
40159
+ var _a;
40160
+ if (!run.image) {
40161
+ return "";
40162
+ }
40163
+ const resolvedSrc = resolveImageSrc(document2, run.image.src);
40164
+ const altAttr = run.image.alt !== void 0 ? ` alt="${escapeHtml(run.image.alt)}"` : "";
40165
+ const img = `<img src="${escapeHtml(resolvedSrc)}" width="${Math.max(1, Math.round(run.image.width))}" height="${Math.max(1, Math.round(run.image.height))}"${altAttr}>`;
40166
+ if ((_a = run.styles) == null ? void 0 : _a.link) {
40167
+ return `<a href="${escapeHtml(run.styles.link)}">${img}</a>`;
40168
+ }
40169
+ return img;
40170
+ }
40171
+ function serializeTextRunToHtml(run, document2) {
40172
+ if (run.image) {
40173
+ return serializeImageRunToHtml(run, document2);
40174
+ }
40175
+ const text = escapeHtml(run.text).replace(/\n/g, "<br>");
40176
+ let html = text;
40177
+ const style2 = run.styles ?? void 0;
40178
+ if (style2 == null ? void 0 : style2.strike) {
40179
+ html = `<s>${html}</s>`;
40180
+ }
40181
+ if (style2 == null ? void 0 : style2.underline) {
40182
+ html = `<u>${html}</u>`;
40183
+ }
40184
+ if (style2 == null ? void 0 : style2.italic) {
40185
+ html = `<em>${html}</em>`;
40186
+ }
40187
+ if (style2 == null ? void 0 : style2.bold) {
40188
+ html = `<strong>${html}</strong>`;
40189
+ }
40190
+ if (style2 == null ? void 0 : style2.superscript) {
40191
+ html = `<sup>${html}</sup>`;
40192
+ } else if (style2 == null ? void 0 : style2.subscript) {
40193
+ html = `<sub>${html}</sub>`;
40194
+ }
40195
+ const css = textRunStylesToCss(style2);
40196
+ const languageAttrs = textLanguageToHtmlAttributes(style2 == null ? void 0 : style2.language);
40197
+ if (css.length > 0 || languageAttrs.length > 0) {
40198
+ const styleAttr = css.length > 0 ? ` style="${css}"` : "";
40199
+ html = `<span${styleAttr}${languageAttrs}>${html}</span>`;
40200
+ }
40201
+ if (style2 == null ? void 0 : style2.link) {
40202
+ html = `<a href="${escapeHtml(style2.link)}">${html}</a>`;
40203
+ }
40204
+ return html;
40205
+ }
40206
+ function serializeParagraphRunsToHtml(runs, document2) {
40207
+ return runs.map((run) => serializeTextRunToHtml(run, document2)).join("") || "<br>";
40208
+ }
40209
+ function serializeEditorSelectionToHtml(state) {
40210
+ var _a;
40211
+ const normalized = normalizeSelection(state);
40212
+ if (normalized.isCollapsed) {
40213
+ return "";
40214
+ }
40215
+ const paragraphs = getParagraphs(state);
40216
+ const htmlParts = [];
40217
+ let activeListKind = null;
40218
+ const closeList = () => {
40219
+ if (activeListKind) {
40220
+ htmlParts.push(activeListKind === "bullet" ? "</ul>" : "</ol>");
40221
+ activeListKind = null;
40222
+ }
40223
+ };
40224
+ for (let index = normalized.startIndex; index <= normalized.endIndex; index += 1) {
40225
+ const paragraph = paragraphs[index];
40226
+ if (!paragraph) {
40227
+ continue;
40228
+ }
40229
+ const startOffset = index === normalized.startIndex ? normalized.startParagraphOffset : 0;
40230
+ const endOffset = index === normalized.endIndex ? normalized.endParagraphOffset : getParagraphLength(paragraph);
40231
+ const runs = sliceRuns(paragraph, startOffset, endOffset);
40232
+ const css = paragraphStyleToCssText(paragraph.style);
40233
+ const attrs = css.length > 0 ? ` style="${css}"` : "";
40234
+ const paragraphHtml = serializeParagraphRunsToHtml(runs, state.document);
40235
+ if ((_a = paragraph.list) == null ? void 0 : _a.kind) {
40236
+ const wrapperTag = paragraph.list.kind === "bullet" ? "ul" : "ol";
40237
+ if (activeListKind !== paragraph.list.kind) {
40238
+ closeList();
40239
+ htmlParts.push(`<${wrapperTag}>`);
40240
+ activeListKind = paragraph.list.kind;
40241
+ }
40242
+ htmlParts.push(`<li${attrs}>${paragraphHtml}</li>`);
40243
+ continue;
40244
+ }
40245
+ closeList();
40246
+ htmlParts.push(`<p${attrs}>${paragraphHtml}</p>`);
40247
+ }
40248
+ closeList();
40249
+ return htmlParts.join("");
40250
+ }
40251
+ function insertClipboardParagraphsAtSelection(state, paragraphsSpec) {
40252
+ if (paragraphsSpec.length === 0) {
40253
+ return state;
40254
+ }
40255
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
40256
+ const { paragraph, index, offset } = getFocusParagraph(collapsedState);
40257
+ const paragraphs = getParagraphs(collapsedState);
40258
+ const beforeRuns = sliceRuns(paragraph, 0, offset);
40259
+ const afterRuns = sliceRuns(paragraph, offset, getParagraphLength(paragraph));
40260
+ const pastedParagraphs = paragraphsSpec.map((spec) => {
40261
+ const nextParagraph = createEditorParagraphFromRuns(
40262
+ spec.runs.map((run) => ({
40263
+ text: run.text,
40264
+ styles: cloneStyle(run.styles),
40265
+ image: run.image ? { ...run.image } : void 0
40266
+ }))
40267
+ );
40268
+ nextParagraph.style = spec.style ? { ...spec.style } : void 0;
40269
+ nextParagraph.list = spec.list ? { ...spec.list } : void 0;
40270
+ return nextParagraph;
40271
+ });
40272
+ let nextParagraphs;
40273
+ let nextSelection = withSelection(
40274
+ paragraphOffsetToPosition(paragraph, offset)
40275
+ );
40276
+ if (pastedParagraphs.length === 1) {
40277
+ const source = pastedParagraphs[0];
40278
+ const sourceLength = source.runs.reduce(
40279
+ (total, run) => total + run.text.length,
40280
+ 0
40281
+ );
40282
+ const mergedParagraph = buildParagraphFromRuns(
40283
+ paragraph,
40284
+ [...beforeRuns, ...source.runs.map(cloneRun), ...afterRuns],
40285
+ getStyleAtOffset(paragraph, offset)
40286
+ );
40287
+ mergedParagraph.style = paragraph.style ? { ...paragraph.style } : source.style ? { ...source.style } : void 0;
40288
+ mergedParagraph.list = paragraph.list ? { ...paragraph.list } : source.list ? { ...source.list } : void 0;
40289
+ nextParagraphs = [
40290
+ ...cloneParagraphs(paragraphs.slice(0, index)),
40291
+ mergedParagraph,
40292
+ ...cloneParagraphs(paragraphs.slice(index + 1))
40293
+ ];
40294
+ nextSelection = withSelection(
40295
+ paragraphOffsetToPosition(
40296
+ mergedParagraph,
40297
+ beforeRuns.reduce((total, run) => total + run.text.length, 0) + sourceLength
40298
+ )
40299
+ );
40300
+ } else {
40301
+ const firstSource = pastedParagraphs[0];
40302
+ const lastSource = pastedParagraphs[pastedParagraphs.length - 1];
40303
+ const lastSourceLength = lastSource.runs.reduce(
40304
+ (total, run) => total + run.text.length,
40305
+ 0
40306
+ );
40307
+ const firstParagraph = buildParagraphFromRuns(
40308
+ paragraph,
40309
+ [...beforeRuns, ...firstSource.runs.map(cloneRun)],
40310
+ getStyleAtOffset(paragraph, offset)
40311
+ );
40312
+ firstParagraph.style = paragraph.style ? { ...paragraph.style } : firstSource.style ? { ...firstSource.style } : void 0;
40313
+ firstParagraph.list = paragraph.list ? { ...paragraph.list } : firstSource.list ? { ...firstSource.list } : void 0;
40314
+ const middleParagraphs = pastedParagraphs.slice(1, -1).map(cloneParagraph);
40315
+ const lastParagraph = buildParagraphFromRuns(
40316
+ lastSource,
40317
+ [...lastSource.runs.map(cloneRun), ...afterRuns],
40318
+ void 0
40319
+ );
40320
+ lastParagraph.list = lastSource.list ? { ...lastSource.list } : void 0;
40321
+ nextParagraphs = [
40322
+ ...cloneParagraphs(paragraphs.slice(0, index)),
40323
+ firstParagraph,
40324
+ ...middleParagraphs,
40325
+ lastParagraph,
40326
+ ...cloneParagraphs(paragraphs.slice(index + 1))
40327
+ ];
40328
+ nextSelection = withSelection(
40329
+ paragraphOffsetToPosition(lastParagraph, lastSourceLength)
40330
+ );
40331
+ }
40332
+ return cloneStateWithParagraphs(
40333
+ collapsedState,
40334
+ nextParagraphs,
40335
+ nextSelection
40336
+ );
40337
+ }
40363
40338
  function parseEditorClipboardHtmlWithDom(html) {
40364
40339
  if (typeof document === "undefined" || html.trim().length === 0) {
40365
40340
  return [];
@@ -40911,7 +40886,12 @@ function traceImageAlphaContour(img) {
40911
40886
  return polygon.map((point) => ({ ...point }));
40912
40887
  }
40913
40888
  function createEditorLayoutOptionsController(deps) {
40914
- const { state, resetTransactionGrouping, applyTransactionalState, focusInput } = deps;
40889
+ const {
40890
+ state,
40891
+ resetTransactionGrouping,
40892
+ applyTransactionalState,
40893
+ focusInput
40894
+ } = deps;
40915
40895
  const layoutOptionsTarget = () => {
40916
40896
  if (getSelectedImageRun(state())) return "image";
40917
40897
  if (getSelectedTextBoxRun(state())) return "textBox";
@@ -40973,6 +40953,43 @@ function createEditorLayoutOptionsController(deps) {
40973
40953
  )
40974
40954
  };
40975
40955
  }
40956
+ const SHAPE_DEFAULT_WIDTH = 150;
40957
+ const SHAPE_DEFAULT_HEIGHT = 100;
40958
+ const SHAPE_DEFAULT_FILL = "#4472C4";
40959
+ const SHAPE_DEFAULT_BORDER_COLOR = "#2F528F";
40960
+ const SHAPE_DEFAULT_BORDER_WIDTH_PT = 1;
40961
+ function insertShapeAtSelection(state, preset) {
40962
+ const collapsedState = isSelectionCollapsed(state.selection) ? state : deleteSelectionRange(state);
40963
+ const { paragraph, index, offset } = getFocusParagraph(collapsedState);
40964
+ const textBox = {
40965
+ width: SHAPE_DEFAULT_WIDTH,
40966
+ height: SHAPE_DEFAULT_HEIGHT,
40967
+ blocks: [createEditorParagraph("")],
40968
+ shape: {
40969
+ preset,
40970
+ fill: SHAPE_DEFAULT_FILL,
40971
+ borderColor: SHAPE_DEFAULT_BORDER_COLOR,
40972
+ borderWidthPt: SHAPE_DEFAULT_BORDER_WIDTH_PT
40973
+ },
40974
+ floating: wrapPresetToFloating(void 0, "front")
40975
+ };
40976
+ const insertedRun = createEditorStyledRun(
40977
+ "",
40978
+ getStyleAtOffset(paragraph, offset),
40979
+ void 0,
40980
+ textBox
40981
+ );
40982
+ const nextParagraph = insertRunsAtOffset(paragraph, offset, [insertedRun]);
40983
+ const paragraphs = getParagraphs(collapsedState);
40984
+ const nextParagraphs = paragraphs.map(
40985
+ (candidate, candidateIndex) => candidateIndex === index ? nextParagraph : cloneParagraph(candidate)
40986
+ );
40987
+ return cloneStateWithParagraphs(
40988
+ collapsedState,
40989
+ nextParagraphs,
40990
+ withSelection(paragraphOffsetToPosition(nextParagraph, offset + 1))
40991
+ );
40992
+ }
40976
40993
  const DEFAULT_TOC_MAX_LEVEL = 3;
40977
40994
  const TOC_INSTRUCTION = ' TOC \\o "1-3" \\h \\z \\u ';
40978
40995
  const twipsToPx = (twips) => Math.round(twips / TWIPS_PER_INCH * PX_PER_INCH);