oasis-editor 0.0.133 → 0.0.135

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{OasisEditorApp-DmXn9H33.js → OasisEditorApp-207_qEC4.js} +602 -30
  2. package/dist/app/controllers/EditorCommandsController.d.ts +5 -0
  3. package/dist/app/controllers/createCropSession.d.ts +26 -0
  4. package/dist/app/controllers/useEditorImageOperations.d.ts +7 -0
  5. package/dist/assets/{importDocxWorker-CCwhxVSR.js → importDocxWorker-B0cSSI12.js} +1 -1
  6. package/dist/core/commands/builtinCommands.d.ts +1 -1
  7. package/dist/core/commands/image.d.ts +51 -1
  8. package/dist/core/commands/publicCommandTypes.d.ts +5 -0
  9. package/dist/core/lineDash.d.ts +16 -0
  10. package/dist/core/model/index.d.ts +1 -1
  11. package/dist/core/model/types/primitives.d.ts +19 -0
  12. package/dist/core/pluginUiTypes.d.ts +1 -1
  13. package/dist/core/transactionMergeKeys.d.ts +2 -0
  14. package/dist/export/docx/docxTypes.d.ts +2 -1
  15. package/dist/export/docx/text/drawingContainerXml.d.ts +7 -1
  16. package/dist/export/pdf/draw/drawImageObject.d.ts +14 -0
  17. package/dist/export/pdf/writer/PdfContentStream.d.ts +8 -0
  18. package/dist/export/pdf/writer/pdfTypes.d.ts +12 -0
  19. package/dist/i18n/locales/en.d.ts +28 -0
  20. package/dist/i18n/locales/pt-BR.d.ts +28 -0
  21. package/dist/{index-BOj4-NlJ.js → index-CaKZARyM.js} +1217 -468
  22. package/dist/oasis-editor.css +1 -1
  23. package/dist/oasis-editor.js +49 -49
  24. package/dist/oasis-editor.umd.cjs +4 -4
  25. package/dist/plugins/internal/essentialsCapabilities.d.ts +21 -1
  26. package/dist/ui/OasisEditorEditorProps.d.ts +5 -0
  27. package/dist/ui/app/buildEditorViewProps.d.ts +2 -0
  28. package/dist/ui/app/createAppCommandsController.d.ts +8 -0
  29. package/dist/ui/app/createEditorCommandRuntime.d.ts +4 -0
  30. package/dist/ui/app/createEditorInteractionRuntime.d.ts +7 -0
  31. package/dist/ui/app/essentials/types.d.ts +5 -0
  32. package/dist/ui/canvas/paragraph/canvasInlineImage.d.ts +1 -1
  33. package/dist/ui/components/Toolbar/controls/ImageSizeControls.d.ts +16 -0
  34. package/dist/ui/components/Toolbar/pictureBorderPresets.d.ts +19 -0
  35. package/dist/ui/components/Toolbar/primitives/ColorGrids.d.ts +20 -0
  36. package/dist/ui/components/Toolbar/primitives/PictureBorderPicker.d.ts +37 -0
  37. package/dist/ui/components/Toolbar/primitives/WideMenuButton.d.ts +27 -0
  38. package/dist/ui/components/Toolbar/schema/items.d.ts +15 -1
  39. package/dist/ui/cropGeometry.d.ts +23 -0
  40. package/package.json +1 -1
@@ -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 { E as EMPTY_PROJECTION_CONTEXT, d as domTextMeasurer, g as getProjectedParagraphBlockHeight, e as estimateTableBlockHeight, p as projectParagraphLayout, a as getPageBodyBottom, b as getPageBodyTop, c as getPageContentWidth, F as FOOTNOTE_MARKER_GUTTER_PX, f as getParagraphText, h as getBlockParagraphs, i as getRunFootnoteReference, l as listReferencedEndnotes, j as getFootnoteDisplayMarker, k as createProjectionContext, m as getDocumentSections, n as getRunField, o as projectBlocksLayout, v as visitRun, q as assertNever, r as createSignal, s as createEditorStateFromDocument, t as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, u as fontSizePxToPt, w as probeLocalFontFamilies, x as createEditorParagraphFromRuns, y as isInlineObjectRun, z as createEditorStyledRun, A as getParagraphLength, B as getActiveZone, C as getActiveSectionIndex, D as getParagraphs, G as normalizeSelection, H as positionToParagraphOffset, I as paragraphOffsetToPosition, J as clampPosition, K as findParagraphIndex, L as createCollapsedSelection, M as isSelectionCollapsed, N as parseFontSizePtToPx, O as formatFontSizePt, P as createEditorParagraph, Q as resolveDefaultParagraphStyleId, R as findParagraphTableLocation, T as buildTableCellLayout, U as PT_PER_PX, V as createEditorTableCell, W as createEditorTableRow, X as createEditorTable, Y as PX_PER_POINT, Z as underlineStyleToCssDecorationStyle, _ as resolveImageSrc, $ as listKindForTag, a0 as isParagraphTag, a1 as collectInlineRuns, a2 as parseParagraphStyle, a3 as getRunImage, a4 as InlineShell, a5 as BalloonShell, a6 as DocumentShell, a7 as createMemo, a8 as getCaretRectFromSnapshot, a9 as getParagraphRectFromSnapshot, aa as createComponent, ab as CaretOverlay, ac as Show, ad as createRenderEffect, ae as style, af as setStyleProperty, ag as setAttribute, ah as memo, ai as template, aj as Button, ak as useI18n, al as createEffect, am as TextField, an as Dialog, ao as insert, ap as className, aq as Grid, ar as SelectField, as as StatusText, at as ColorField, au as UNDERLINE_STYLE_OPTIONS, av as Stack, aw as For, ax as ToggleChip, ay as FormField, az as Checkbox, aA as FieldGroup, aB as Tabs, aC as NumberField, aD as parseNumber, aE as createStore, aF as reconcile, aG as RadioGroup, aH as Radio$1, aI as TextAreaField, aJ as Text, aK as SurfaceButton, aL as delegateEvents, aM as onMount, aN as onCleanup, aO as CheckIcon, aP as use, aQ as PluginUiHost, aR as OasisEditorEditor, aS as OasisBrandMark, aT as setPreciseFontPreference, aU as setWelcomeSeen, aV as enablePreciseFontMode, aW as TWIPS_PER_POINT, aX as PX_PER_INCH, aY as TWIPS_PER_INCH, aZ as normalizeHex6, a_ as TABLE_CONDITIONAL_FLAG_ATTRIBUTES, a$ as TABLE_BORDER_EDGE_KEYS, b0 as resolveEffectiveParagraphStyle, b1 as resolveEffectiveTextStyleForParagraph, b2 as EMU_PER_PT, b3 as OOXML_ROTATION_UNITS, b4 as OOXML_PERCENT_DENOMINATOR, b5 as parseHexColorToRgb255, b6 as EMU_PER_PX, b7 as getRunEndnoteReference, b8 as iterateFootnoteReferenceRuns, b9 as iterateEndnoteReferenceRuns, ba as imageContentTypeDefaults, bb as getRunFieldChar, bc as getRunFieldInstruction, bd as createEditorRun, be as JSZip, bf as imageExtensionFromMime, bg as pxToPt$1, bh as resolveFloatingObjectRect, bi as getTextBoxFloatingGeometry, bj as getPresetPathSegments, bk as buildListLabels, bl as DEFAULT_FONT_SIZE_PX, bm as resolveGradientAxis, bn as isDoubleUnderlineStyle, bo as isWavyUnderlineStyle, bp as underlineStyleLineWidthPx, bq as WAVY_UNDERLINE_WAVELENGTH_PX, br as WAVY_UNDERLINE_AMPLITUDE_PX, bs as DOUBLE_UNDERLINE_OFFSET_PX, bt as underlineStyleDashArray, bu as EMPHASIS_GLYPH, bv as rgb255ToHex, bw as getImageFloatingGeometry, bx as textStyleToFontSizePt, by as resolveTextAlignmentBaselineOffset, bz as TEXT_BASELINE_RATIO, bA as resolveOpenTypeFeatureTags, bB as resolveDecorationLineY, bC as DOUBLE_STRIKE_OFFSET_PX, bD as resolveListLabel, bE as getListLabelInset, bF as getAlignedListLabelInset, bG as getParagraphBorderInsets, bH as buildSegmentTable, bI as buildCanvasTableLayout, bJ as resolveCanvasTableWidth, bK as resolveFloatingTableRect, bL as paragraphBetweenBorderMatches, bM as normalizeFamily, bN as ROBOTO_FONT_FILES, bO as loadFontAsset, bP as OFFICE_COMPAT_FONT_FAMILIES, bQ as BinaryReader, bR as buildSfnt, bS as defaultFontDecoderRegistry, bT as SfntFontProgram, bU as collectPdfFontFamilies, bV as outlineFrom, bW as getPageHeaderZoneTop, bX as getPageColumnRects, bY as findFootnoteReference, bZ as resolveImporterForFile, b_ as roundTo, b$ as getDocumentSectionsCanonical, c0 as getDocumentParagraphsCanonical, c1 as getDocumentParagraphs, c2 as getDocumentPageSettings, c3 as getTableCellContentWidthForParagraph, c4 as layoutMetricsEpoch, c5 as bumpLayoutMetricsEpoch, c6 as createCanvasLayoutSnapshotProvider, c7 as on, c8 as debounce, c9 as unwrap, ca as perfTimer, cb as getRunTextBox, cc as createEditorDocument, cd as resolveResizedDimensions, ce as resolveTextBoxRenderHeight, cf as getToolbarStyleState, cg as VERTICAL_HIT_WEIGHT, ch as getCachedCanvasImage, ci as measureParagraphMinContentWidthPx, cj as getEditableBlocksForZone, ck as findParagraphLocation, cl as createSectionBoundaryParagraph, cm as normalizePageSettings, cn as DEFAULT_EDITOR_PAGE_SETTINGS, co as markStart, cp as markEnd, cq as getParagraphEntries, cr as getParagraphById, cs as createEditorFootnote, ct as createFootnoteReferenceRun, cu as renumberFootnotes, cv as preciseFontModeVersion, cw as isPreciseFontModeEnabled, cx as getHeadingLevel, cy as togglePreciseFontMode, cz as nextFontSizePt, cA as previousFontSizePt, cB as fontSizePtToPx, cC as resolveNamedTextStyle, cD as createDefaultToolbarPreset, cE as MenuRegistry, cF as createToolbarRegistry, cG as Editor, cH as resolveCommandRef, cI as commandRefName, cJ as createOasisEditorClient, cK as createEditorZoom, cL as startLongTaskObserver, cM as installGlobalReport, cN as applyStoredPreciseFontPreference, cO as getWelcomeSeen, cP as isLocalFontAccessSupported, cQ as EDITOR_SCROLL_PADDING_PX, cR as Toolbar, cS as OasisEditorLoading, cT as I18nProvider, cU as createTranslator, cV as registerDomStatsSurface, cW as createEditorLogger } from "./index-BOj4-NlJ.js";
4
+ import { E as EMPTY_PROJECTION_CONTEXT, d as domTextMeasurer, g as getProjectedParagraphBlockHeight, e as estimateTableBlockHeight, p as projectParagraphLayout, a as getPageBodyBottom, b as getPageBodyTop, c as getPageContentWidth, F as FOOTNOTE_MARKER_GUTTER_PX, f as getParagraphText, h as getBlockParagraphs, i as getRunFootnoteReference, l as listReferencedEndnotes, j as getFootnoteDisplayMarker, k as createProjectionContext, m as getDocumentSections, n as getRunField, o as projectBlocksLayout, v as visitRun, q as assertNever, r as createSignal, s as createEditorStateFromDocument, t as createInitialEditorState, S as STANDARD_FONT_SIZES_PT, u as fontSizePxToPt, w as probeLocalFontFamilies, x as createEditorParagraphFromRuns, y as isInlineObjectRun, z as createEditorStyledRun, A as getParagraphLength, B as getActiveZone, C as getActiveSectionIndex, D as getParagraphs, G as normalizeSelection, H as positionToParagraphOffset, I as paragraphOffsetToPosition, J as clampPosition, K as findParagraphIndex, L as createCollapsedSelection, M as isSelectionCollapsed, N as parseFontSizePtToPx, O as formatFontSizePt, P as createEditorParagraph, Q as resolveDefaultParagraphStyleId, R as findParagraphTableLocation, T as buildTableCellLayout, U as PT_PER_PX, V as createEditorTableCell, W as createEditorTableRow, X as createEditorTable, Y as PX_PER_POINT, Z as underlineStyleToCssDecorationStyle, _ as resolveImageSrc, $ as listKindForTag, a0 as isParagraphTag, a1 as collectInlineRuns, a2 as parseParagraphStyle, a3 as getRunImage, a4 as InlineShell, a5 as BalloonShell, a6 as DocumentShell, a7 as createMemo, a8 as getCaretRectFromSnapshot, a9 as getParagraphRectFromSnapshot, aa as createComponent, ab as CaretOverlay, ac as Show, ad as createRenderEffect, ae as style, af as setStyleProperty, ag as setAttribute, ah as memo, ai as template, aj as Button, ak as useI18n, al as createEffect, am as TextField, an as Dialog, ao as insert, ap as className, aq as Grid, ar as SelectField, as as StatusText, at as ColorField, au as UNDERLINE_STYLE_OPTIONS, av as Stack, aw as For, ax as ToggleChip, ay as FormField, az as Checkbox, aA as FieldGroup, aB as Tabs, aC as NumberField, aD as parseNumber, aE as createStore, aF as reconcile, aG as RadioGroup, aH as Radio$1, aI as TextAreaField, aJ as Text, aK as SurfaceButton, aL as delegateEvents, aM as onMount, aN as onCleanup, aO as CheckIcon, aP as use, aQ as PluginUiHost, aR as OasisEditorEditor, aS as OasisBrandMark, aT as setPreciseFontPreference, aU as setWelcomeSeen, aV as enablePreciseFontMode, aW as TWIPS_PER_POINT, aX as PX_PER_INCH, aY as TWIPS_PER_INCH, aZ as normalizeHex6, a_ as TABLE_CONDITIONAL_FLAG_ATTRIBUTES, a$ as TABLE_BORDER_EDGE_KEYS, b0 as resolveEffectiveParagraphStyle, b1 as resolveEffectiveTextStyleForParagraph, b2 as EMU_PER_PT, b3 as OOXML_ROTATION_UNITS, b4 as OOXML_PERCENT_DENOMINATOR, b5 as parseHexColorToRgb255, b6 as EMU_PER_PX, b7 as getRunEndnoteReference, b8 as iterateFootnoteReferenceRuns, b9 as iterateEndnoteReferenceRuns, ba as imageContentTypeDefaults, bb as getRunFieldChar, bc as getRunFieldInstruction, bd as createEditorRun, be as JSZip, bf as imageExtensionFromMime, bg as pxToPt$1, bh as resolveFloatingObjectRect, bi as getTextBoxFloatingGeometry, bj as getPresetPathSegments, bk as buildListLabels, bl as lineDashPatternPt, bm as DEFAULT_FONT_SIZE_PX, bn as resolveGradientAxis, bo as isDoubleUnderlineStyle, bp as isWavyUnderlineStyle, bq as underlineStyleLineWidthPx, br as WAVY_UNDERLINE_WAVELENGTH_PX, bs as WAVY_UNDERLINE_AMPLITUDE_PX, bt as DOUBLE_UNDERLINE_OFFSET_PX, bu as underlineStyleDashArray, bv as EMPHASIS_GLYPH, bw as rgb255ToHex, bx as getImageFloatingGeometry, by as textStyleToFontSizePt, bz as resolveTextAlignmentBaselineOffset, bA as TEXT_BASELINE_RATIO, bB as resolveOpenTypeFeatureTags, bC as resolveDecorationLineY, bD as DOUBLE_STRIKE_OFFSET_PX, bE as resolveListLabel, bF as getListLabelInset, bG as getAlignedListLabelInset, bH as getParagraphBorderInsets, bI as buildSegmentTable, bJ as buildCanvasTableLayout, bK as resolveCanvasTableWidth, bL as resolveFloatingTableRect, bM as paragraphBetweenBorderMatches, bN as normalizeFamily, bO as ROBOTO_FONT_FILES, bP as loadFontAsset, bQ as OFFICE_COMPAT_FONT_FAMILIES, bR as BinaryReader, bS as buildSfnt, bT as defaultFontDecoderRegistry, bU as SfntFontProgram, bV as collectPdfFontFamilies, bW as outlineFrom, bX as getPageHeaderZoneTop, bY as getPageColumnRects, bZ as findFootnoteReference, b_ as resolveImporterForFile, b$ as roundTo, c0 as getDocumentSectionsCanonical, c1 as getDocumentParagraphsCanonical, c2 as getDocumentParagraphs, c3 as PX_PER_CM, c4 as getDocumentPageSettings, c5 as getTableCellContentWidthForParagraph, c6 as layoutMetricsEpoch, c7 as bumpLayoutMetricsEpoch, c8 as createCanvasLayoutSnapshotProvider, c9 as on, ca as debounce, cb as unwrap, cc as perfTimer, cd as getRunTextBox, ce as createEditorDocument, cf as resolveResizedDimensions, cg as axisSignForDirection, ch as clamp$1, ci as MIN_RESIZE_SIZE_PX, cj as resolveTextBoxRenderHeight, ck as getToolbarStyleState, cl as VERTICAL_HIT_WEIGHT, cm as getCachedCanvasImage, cn as measureParagraphMinContentWidthPx, co as getEditableBlocksForZone, cp as findParagraphLocation, cq as createSectionBoundaryParagraph, cr as normalizePageSettings, cs as DEFAULT_EDITOR_PAGE_SETTINGS, ct as markStart, cu as markEnd, cv as getParagraphEntries, cw as getParagraphById, cx as createEditorFootnote, cy as createFootnoteReferenceRun, cz as renumberFootnotes, cA as preciseFontModeVersion, cB as isPreciseFontModeEnabled, cC as getHeadingLevel, cD as togglePreciseFontMode, cE as nextFontSizePt, cF as previousFontSizePt, cG as fontSizePtToPx, cH as resolveNamedTextStyle, cI as createDefaultToolbarPreset, cJ as MenuRegistry, cK as createToolbarRegistry, cL as Editor, cM as resolveCommandRef, cN as commandRefName, cO as createOasisEditorClient, cP as createEditorZoom, cQ as startLongTaskObserver, cR as installGlobalReport, cS as applyStoredPreciseFontPreference, cT as getWelcomeSeen, cU as isLocalFontAccessSupported, cV as EDITOR_SCROLL_PADDING_PX, cW as Toolbar, cX as OasisEditorLoading, cY as I18nProvider, cZ as createTranslator, c_ as registerDomStatsSurface, c$ as createEditorLogger } from "./index-CaKZARyM.js";
5
5
  function projectHeaderFooterBlocksWithDependencies(blocks, deps, context = {}) {
6
6
  const {
7
7
  pageIndex,
@@ -27476,6 +27476,7 @@ const MERGE_KEYS = {
27476
27476
  link: "link",
27477
27477
  imageAlt: "imageAlt",
27478
27478
  imageCaption: "imageCaption",
27479
+ imageResize: "imageResize",
27479
27480
  layoutWrapPolygon: "layoutWrapPolygon",
27480
27481
  specialIndent: "specialIndent",
27481
27482
  paraBorders: "paraBorders",
@@ -35938,7 +35939,8 @@ function buildEditorViewProps(ctx) {
35938
35939
  hoveredRevision: overlayInput.hoveredRevision,
35939
35940
  focused: overlayInput.focused,
35940
35941
  showCaret: overlayInput.showCaret,
35941
- importProgress: overlayInput.importProgress
35942
+ importProgress: overlayInput.importProgress,
35943
+ imageCropMode: overlayInput.imageCropMode
35942
35944
  };
35943
35945
  const refs = {
35944
35946
  onViewportRef: (element) => {
@@ -35980,6 +35982,7 @@ function buildEditorViewProps(ctx) {
35980
35982
  onImageResizeHandleMouseDown: surface.handleImageResizeHandleMouseDown,
35981
35983
  onTextBoxResizeHandleMouseDown: surface.handleTextBoxResizeHandleMouseDown,
35982
35984
  onImageRotateHandleMouseDown: surface.handleImageRotateHandleMouseDown,
35985
+ onImageCropHandleMouseDown: surface.handleImageCropHandleMouseDown,
35983
35986
  onTextBoxRotateHandleMouseDown: surface.handleTextBoxRotateHandleMouseDown,
35984
35987
  onTableDragHandleMouseDown: surface.tableDrag.handleMouseDown,
35985
35988
  onTableCornerResizeHandleMouseDown: surface.tableCornerResize.handleMouseDown,
@@ -37601,6 +37604,15 @@ function buildSrcRect(crop) {
37601
37604
  }
37602
37605
  return `<a:srcRect l="${l}" t="${t}" r="${r}" b="${b}"/>`;
37603
37606
  }
37607
+ function buildImageLnXml(border) {
37608
+ if (!border) {
37609
+ return "";
37610
+ }
37611
+ const widthAttr = border.widthPt !== void 0 ? ` w="${Math.round(border.widthPt * EMU_PER_PT)}"` : "";
37612
+ const fill = `<a:solidFill><a:srgbClr val="${escapeXml(border.color.replace(/^#/, ""))}"/></a:solidFill>`;
37613
+ const dash = border.dash ? `<a:prstDash val="${border.dash}"/>` : "";
37614
+ return `<a:ln${widthAttr}>${fill}${dash}</a:ln>`;
37615
+ }
37604
37616
  function buildAnchorBool(value, fallback) {
37605
37617
  return value ?? fallback ? "1" : "0";
37606
37618
  }
@@ -37693,9 +37705,10 @@ function serializeImageRun(runId, rId, context, rPrXml) {
37693
37705
  const altAttr = img.alt !== void 0 ? ` descr="${escapeXml(img.alt)}" title="${escapeXml(img.alt)}"` : "";
37694
37706
  const xfrmAttrs = buildXfrmAttrs(img);
37695
37707
  const srcRect = buildSrcRect(img.crop);
37708
+ const lnXml = buildImageLnXml(img.border);
37696
37709
  const fill = img.fillMode === "tile" ? "<a:tile/>" : "<a:stretch><a:fillRect/></a:stretch>";
37697
37710
  const blipRelAttr = img.kind === "linked" ? `r:link="${rId}"` : `r:embed="${rId}"`;
37698
- const picXml = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="Picture"${altAttr}/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip ${blipRelAttr} xmlns:r="${OFFICE_REL_NS}"/>${srcRect}${fill}</pic:blipFill><pic:spPr><a:xfrm${xfrmAttrs}><a:off x="0" y="0"/><a:ext cx="${img.cx}" cy="${img.cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic>`;
37711
+ const picXml = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="Picture"${altAttr}/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip ${blipRelAttr} xmlns:r="${OFFICE_REL_NS}"/>${srcRect}${fill}</pic:blipFill><pic:spPr><a:xfrm${xfrmAttrs}><a:off x="0" y="0"/><a:ext cx="${img.cx}" cy="${img.cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom>${lnXml}</pic:spPr></pic:pic></a:graphicData></a:graphic>`;
37699
37712
  const drawing = buildDrawingXml(img, docPrId, altAttr, picXml);
37700
37713
  return `<w:r>${rPrXml}${drawing}</w:r>`;
37701
37714
  }
@@ -38936,6 +38949,7 @@ function buildPartContext(blocks, numberingContext, state, document2) {
38936
38949
  alt: run.image.alt,
38937
38950
  crop: run.image.crop,
38938
38951
  fillMode: run.image.fillMode,
38952
+ border: run.image.border,
38939
38953
  rotation: run.image.rotation,
38940
38954
  flipH: run.image.flipH,
38941
38955
  flipV: run.image.flipV,
@@ -39559,6 +39573,43 @@ async function registerPdfImageRun(writer, document2, image) {
39559
39573
  perWriter.set(resolvedSrc, preparedPromise);
39560
39574
  return preparedPromise;
39561
39575
  }
39576
+ async function drawImageObject(writer, pageIndex, document2, image, x, y, width, height) {
39577
+ const resourceName = await registerPdfImageRun(writer, document2, image);
39578
+ if (!resourceName) {
39579
+ return;
39580
+ }
39581
+ writer.drawImage(pageIndex, {
39582
+ resourceName,
39583
+ x,
39584
+ y,
39585
+ width,
39586
+ height,
39587
+ rotation: image.rotation,
39588
+ crop: image.crop
39589
+ });
39590
+ const border = image.border;
39591
+ if (!border) {
39592
+ return;
39593
+ }
39594
+ const rotation = image.rotation;
39595
+ if (rotation) {
39596
+ writer.saveGraphicsState(pageIndex);
39597
+ writer.rotateAbout(pageIndex, x + width / 2, y + height / 2, rotation);
39598
+ }
39599
+ const dashArray = lineDashPatternPt(border.dash);
39600
+ writer.drawRect(pageIndex, {
39601
+ x,
39602
+ y,
39603
+ width,
39604
+ height,
39605
+ stroke: border.color,
39606
+ lineWidth: border.widthPt ?? 1,
39607
+ ...dashArray.length > 0 ? { dashArray } : {}
39608
+ });
39609
+ if (rotation) {
39610
+ writer.restoreGraphicsState(pageIndex);
39611
+ }
39612
+ }
39562
39613
  function resolveFragmentSlots(line, fragment) {
39563
39614
  const slotByOffset = new Map(
39564
39615
  line.slots.map(
@@ -39915,20 +39966,16 @@ async function drawFloatingImagesForParagraph(options) {
39915
39966
  lineTop: options.paragraphTop + line.top,
39916
39967
  anchorLeft: options.contentLeft + ((slot == null ? void 0 : slot.left) ?? 0)
39917
39968
  });
39918
- const resourceName = await registerPdfImageRun(
39969
+ await drawImageObject(
39919
39970
  options.writer,
39971
+ options.pageIndex,
39920
39972
  options.document,
39921
- image
39973
+ image,
39974
+ pxToPt$1(rect.x),
39975
+ pxToPt$1(rect.y),
39976
+ pxToPt$1(rect.width),
39977
+ pxToPt$1(rect.height)
39922
39978
  );
39923
- if (!resourceName) continue;
39924
- options.writer.drawImage(options.pageIndex, {
39925
- resourceName,
39926
- x: pxToPt$1(rect.x),
39927
- y: pxToPt$1(rect.y),
39928
- width: pxToPt$1(rect.width),
39929
- height: pxToPt$1(rect.height),
39930
- rotation: image.rotation
39931
- });
39932
39979
  }
39933
39980
  }
39934
39981
  }
@@ -40018,20 +40065,16 @@ async function drawFragmentText(writer, pageIndex, paragraph, line, fragment, do
40018
40065
  if (fragment.image.floating) return;
40019
40066
  const slot = line.slots.find((c) => c.offset === fragment.startOffset) ?? line.slots.find((c) => c.offset >= fragment.startOffset);
40020
40067
  if (!slot) return;
40021
- const resourceName = await registerPdfImageRun(
40068
+ await drawImageObject(
40022
40069
  writer,
40070
+ pageIndex,
40023
40071
  document2,
40024
- fragment.image
40025
- );
40026
- if (!resourceName) return;
40027
- writer.drawImage(pageIndex, {
40028
- resourceName,
40029
- x: pxToPt$1(originX + slot.left),
40030
- y: pxToPt$1(originY + line.top + line.height - fragment.image.height),
40031
- width: pxToPt$1(fragment.image.width),
40032
- height: pxToPt$1(fragment.image.height),
40033
- rotation: fragment.image.rotation
40034
- });
40072
+ fragment.image,
40073
+ pxToPt$1(originX + slot.left),
40074
+ pxToPt$1(originY + line.top + line.height - fragment.image.height),
40075
+ pxToPt$1(fragment.image.width),
40076
+ pxToPt$1(fragment.image.height)
40077
+ );
40035
40078
  return;
40036
40079
  }
40037
40080
  if (fragment.textBox) {
@@ -41024,6 +41067,12 @@ function textMarkerComment(value) {
41024
41067
  );
41025
41068
  return `% OasisText ${encodePdfUtf16Hex(codePoints)}`;
41026
41069
  }
41070
+ function buildDashCommand(dashArray) {
41071
+ if (!dashArray || dashArray.length === 0) {
41072
+ return null;
41073
+ }
41074
+ return `[${dashArray.map((value) => formatNumber(value)).join(" ")}] 0 d`;
41075
+ }
41027
41076
  class PdfContentStream {
41028
41077
  constructor(page, fonts, images, shadings) {
41029
41078
  this.page = page;
@@ -41059,6 +41108,10 @@ class PdfContentStream {
41059
41108
  if (options.stroke) {
41060
41109
  commands.push(colorCommand(options.stroke, "RG", [0, 0, 0]));
41061
41110
  commands.push(`${formatNumber(options.lineWidth ?? 1)} w`);
41111
+ const dashCommand = buildDashCommand(options.dashArray);
41112
+ if (dashCommand) {
41113
+ commands.push(dashCommand);
41114
+ }
41062
41115
  }
41063
41116
  commands.push(
41064
41117
  [
@@ -41081,7 +41134,7 @@ class PdfContentStream {
41081
41134
  }
41082
41135
  drawLine(options) {
41083
41136
  const page = this.page;
41084
- const dashCommand = options.dashArray && options.dashArray.length > 0 ? `[${options.dashArray.map((value) => formatNumber(value)).join(" ")}] 0 d` : null;
41137
+ const dashCommand = buildDashCommand(options.dashArray);
41085
41138
  const commands = [
41086
41139
  "q",
41087
41140
  colorCommand(options.stroke, "RG", [0, 0, 0])
@@ -41278,6 +41331,20 @@ class PdfContentStream {
41278
41331
  page.imageResourceNames.add(options.resourceName);
41279
41332
  const bottom = page.height - options.y - options.height;
41280
41333
  const rotation = Number.isFinite(options.rotation) ? options.rotation ?? 0 : 0;
41334
+ const crop = options.crop;
41335
+ const cl = (crop == null ? void 0 : crop.left) ?? 0;
41336
+ const ct = (crop == null ? void 0 : crop.top) ?? 0;
41337
+ const cr = (crop == null ? void 0 : crop.right) ?? 0;
41338
+ const cb = (crop == null ? void 0 : crop.bottom) ?? 0;
41339
+ if (crop && (cl > 0 || ct > 0 || cr > 0 || cb > 0)) {
41340
+ this.drawCroppedImage(options, bottom, rotation, {
41341
+ left: cl,
41342
+ top: ct,
41343
+ right: cr,
41344
+ bottom: cb
41345
+ });
41346
+ return;
41347
+ }
41281
41348
  if (rotation === 0) {
41282
41349
  page.commands.push(
41283
41350
  [
@@ -41323,6 +41390,63 @@ class PdfContentStream {
41323
41390
  ].join("\n")
41324
41391
  );
41325
41392
  }
41393
+ /**
41394
+ * Draws a cropped image by clipping to the displayed box and scaling the full
41395
+ * image so only the cropped sub-region fills it — mirroring the canvas/DOCX
41396
+ * `a:srcRect` semantics. Works with rotation by mapping box-local space to the
41397
+ * page (rotation about the box centre), clipping in that space, then drawing
41398
+ * the enlarged image behind the clip.
41399
+ */
41400
+ drawCroppedImage(options, bottom, rotation, crop) {
41401
+ const page = this.page;
41402
+ const { width, height } = options;
41403
+ const fw = Math.max(1e-4, 1 - crop.left - crop.right);
41404
+ const fh = Math.max(1e-4, 1 - crop.top - crop.bottom);
41405
+ const fullWidth = width / fw;
41406
+ const fullHeight = height / fh;
41407
+ const originX = -crop.left * fullWidth;
41408
+ const originY = -crop.bottom * fullHeight;
41409
+ const radians = -rotation * Math.PI / 180;
41410
+ const cos = Math.cos(radians);
41411
+ const sin = Math.sin(radians);
41412
+ const cxl = width / 2;
41413
+ const cyl = height / 2;
41414
+ const cxPage = options.x + width / 2;
41415
+ const cyPage = bottom + height / 2;
41416
+ const ra = cos;
41417
+ const rb = sin;
41418
+ const rc = -sin;
41419
+ const rd = cos;
41420
+ const re = cxPage - (ra * cxl + rc * cyl);
41421
+ const rf = cyPage - (rb * cxl + rd * cyl);
41422
+ page.commands.push(
41423
+ [
41424
+ "q",
41425
+ [
41426
+ formatNumber(ra),
41427
+ formatNumber(rb),
41428
+ formatNumber(rc),
41429
+ formatNumber(rd),
41430
+ formatNumber(re),
41431
+ formatNumber(rf),
41432
+ "cm"
41433
+ ].join(" "),
41434
+ // Clip to the displayed box (box-local coordinates).
41435
+ `0 0 ${formatNumber(width)} ${formatNumber(height)} re W n`,
41436
+ [
41437
+ formatNumber(fullWidth),
41438
+ "0",
41439
+ "0",
41440
+ formatNumber(fullHeight),
41441
+ formatNumber(originX),
41442
+ formatNumber(originY),
41443
+ "cm"
41444
+ ].join(" "),
41445
+ `/${options.resourceName} Do`,
41446
+ "Q"
41447
+ ].join("\n")
41448
+ );
41449
+ }
41326
41450
  }
41327
41451
  function parseExtensionLookup(reader, offset, parseSubtable2) {
41328
41452
  reader.seek(offset);
@@ -44233,6 +44357,145 @@ function resizeSelectedImage(state, width, height) {
44233
44357
  height: Math.max(24, Math.round(height))
44234
44358
  }));
44235
44359
  }
44360
+ const MIN_IMAGE_PX = 24;
44361
+ function getSelectedImageSizeCm(state) {
44362
+ const selectedImage = getSelectedImageRun(state);
44363
+ const image = selectedImage && getRunImage(selectedImage.run);
44364
+ if (!image) {
44365
+ return null;
44366
+ }
44367
+ return {
44368
+ width: image.width / PX_PER_CM,
44369
+ height: image.height / PX_PER_CM
44370
+ };
44371
+ }
44372
+ function setSelectedImageWidthCm(state, cm) {
44373
+ const selectedImage = getSelectedImageRun(state);
44374
+ const image = selectedImage && getRunImage(selectedImage.run);
44375
+ if (!image || !Number.isFinite(cm) || cm <= 0) {
44376
+ return state;
44377
+ }
44378
+ const nextWidth = Math.max(MIN_IMAGE_PX, Math.round(cm * PX_PER_CM));
44379
+ const ratio = image.height / image.width;
44380
+ return resizeSelectedImage(state, nextWidth, nextWidth * ratio);
44381
+ }
44382
+ function setSelectedImageHeightCm(state, cm) {
44383
+ const selectedImage = getSelectedImageRun(state);
44384
+ const image = selectedImage && getRunImage(selectedImage.run);
44385
+ if (!image || !Number.isFinite(cm) || cm <= 0) {
44386
+ return state;
44387
+ }
44388
+ const nextHeight = Math.max(MIN_IMAGE_PX, Math.round(cm * PX_PER_CM));
44389
+ const ratio = image.width / image.height;
44390
+ return resizeSelectedImage(state, nextHeight * ratio, nextHeight);
44391
+ }
44392
+ function clampCropSide(value) {
44393
+ if (!value || !Number.isFinite(value) || value < 0) {
44394
+ return 0;
44395
+ }
44396
+ return Math.min(value, 0.99);
44397
+ }
44398
+ function normalizeCrop(crop) {
44399
+ if (!crop) {
44400
+ return void 0;
44401
+ }
44402
+ const left = clampCropSide(crop.left);
44403
+ const top = clampCropSide(crop.top);
44404
+ const right = clampCropSide(crop.right);
44405
+ const bottom = clampCropSide(crop.bottom);
44406
+ const safeRight = Math.min(right, Math.max(0, 0.99 - left));
44407
+ const safeBottom = Math.min(bottom, Math.max(0, 0.99 - top));
44408
+ if (left === 0 && top === 0 && safeRight === 0 && safeBottom === 0) {
44409
+ return void 0;
44410
+ }
44411
+ return { left, top, right: safeRight, bottom: safeBottom };
44412
+ }
44413
+ function setSelectedImageCrop(state, update) {
44414
+ return patchSelectedImage(state, (image) => {
44415
+ const next = { ...image };
44416
+ const crop = normalizeCrop(update.crop);
44417
+ if (crop) {
44418
+ next.crop = crop;
44419
+ } else {
44420
+ delete next.crop;
44421
+ }
44422
+ if (update.width !== void 0) {
44423
+ next.width = Math.max(MIN_IMAGE_PX, Math.round(update.width));
44424
+ }
44425
+ if (update.height !== void 0) {
44426
+ next.height = Math.max(MIN_IMAGE_PX, Math.round(update.height));
44427
+ }
44428
+ return next;
44429
+ });
44430
+ }
44431
+ function computeImageAspectCrop(image, mode) {
44432
+ if (mode === "reset") {
44433
+ return { crop: null };
44434
+ }
44435
+ const target = mode;
44436
+ const { width: W, height: H } = image;
44437
+ if (!Number.isFinite(target) || target <= 0 || W <= 0 || H <= 0) {
44438
+ return { crop: image.crop ?? null };
44439
+ }
44440
+ const c = image.crop ?? {};
44441
+ const l0 = clampCropSide(c.left);
44442
+ const t0 = clampCropSide(c.top);
44443
+ const r0 = clampCropSide(c.right);
44444
+ const b0 = clampCropSide(c.bottom);
44445
+ const currentRatio = W / H;
44446
+ if (currentRatio > target) {
44447
+ const newWidth = H * target;
44448
+ const addFrac = (W - newWidth) / W * Math.max(0, 1 - l0 - r0);
44449
+ return {
44450
+ crop: { ...c, left: l0 + addFrac / 2, right: r0 + addFrac / 2 },
44451
+ width: newWidth
44452
+ };
44453
+ }
44454
+ if (currentRatio < target) {
44455
+ const newHeight = W / target;
44456
+ const addFrac = (H - newHeight) / H * Math.max(0, 1 - t0 - b0);
44457
+ return {
44458
+ crop: { ...c, top: t0 + addFrac / 2, bottom: b0 + addFrac / 2 },
44459
+ height: newHeight
44460
+ };
44461
+ }
44462
+ return { crop: image.crop ?? null };
44463
+ }
44464
+ function applySelectedImageCropAspect(state, mode) {
44465
+ const selectedImage = getSelectedImageRun(state);
44466
+ const image = selectedImage && getRunImage(selectedImage.run);
44467
+ if (!image) {
44468
+ return state;
44469
+ }
44470
+ return setSelectedImageCrop(state, computeImageAspectCrop(image, mode));
44471
+ }
44472
+ function getSelectedImageBorder(state) {
44473
+ const selectedImage = getSelectedImageRun(state);
44474
+ const image = selectedImage && getRunImage(selectedImage.run);
44475
+ return (image == null ? void 0 : image.border) ?? null;
44476
+ }
44477
+ const DEFAULT_IMAGE_BORDER_COLOR = "#000000";
44478
+ function setSelectedImageBorder(state, patch) {
44479
+ return patchSelectedImage(state, (image) => {
44480
+ if (patch.color === null) {
44481
+ const { border: _removed, ...rest } = image;
44482
+ return rest;
44483
+ }
44484
+ const border = {
44485
+ ...image.border ?? { color: DEFAULT_IMAGE_BORDER_COLOR }
44486
+ };
44487
+ if (patch.color !== void 0) {
44488
+ border.color = patch.color;
44489
+ }
44490
+ if (patch.widthPt !== void 0) {
44491
+ border.widthPt = patch.widthPt;
44492
+ }
44493
+ if (patch.dash !== void 0) {
44494
+ border.dash = patch.dash;
44495
+ }
44496
+ return { ...image, border };
44497
+ });
44498
+ }
44236
44499
  function normalizeRotation$1(rotation) {
44237
44500
  if (!Number.isFinite(rotation)) {
44238
44501
  return void 0;
@@ -47710,12 +47973,168 @@ function createRotateSession(adapter, deps) {
47710
47973
  };
47711
47974
  return { start, stop };
47712
47975
  }
47976
+ function visibleFraction(near, far) {
47977
+ return Math.max(1e-4, 1 - near - far);
47978
+ }
47979
+ function resolveCroppedImage(geometry, deltaX, deltaY) {
47980
+ const { startWidth: W, startHeight: H } = geometry;
47981
+ const l0 = geometry.startCrop.left ?? 0;
47982
+ const t0 = geometry.startCrop.top ?? 0;
47983
+ const r0 = geometry.startCrop.right ?? 0;
47984
+ const b0 = geometry.startCrop.bottom ?? 0;
47985
+ const kx = visibleFraction(l0, r0) / W;
47986
+ const ky = visibleFraction(t0, b0) / H;
47987
+ const xs = axisSignForDirection(geometry.handleDirection, "x");
47988
+ const ys = axisSignForDirection(geometry.handleDirection, "y");
47989
+ let left = l0;
47990
+ let right = r0;
47991
+ let width = W;
47992
+ if (xs !== 0) {
47993
+ const maxGrow = (xs > 0 ? r0 : l0) / kx;
47994
+ width = clamp$1(W + deltaX * xs, MIN_RESIZE_SIZE_PX, W + maxGrow);
47995
+ const widthDelta = width - W;
47996
+ if (xs > 0) {
47997
+ right = Math.max(0, r0 - widthDelta * kx);
47998
+ } else {
47999
+ left = Math.max(0, l0 - widthDelta * kx);
48000
+ }
48001
+ }
48002
+ let top = t0;
48003
+ let bottom = b0;
48004
+ let height = H;
48005
+ if (ys !== 0) {
48006
+ const maxGrow = (ys > 0 ? b0 : t0) / ky;
48007
+ height = clamp$1(H + deltaY * ys, MIN_RESIZE_SIZE_PX, H + maxGrow);
48008
+ const heightDelta = height - H;
48009
+ if (ys > 0) {
48010
+ bottom = Math.max(0, b0 - heightDelta * ky);
48011
+ } else {
48012
+ top = Math.max(0, t0 - heightDelta * ky);
48013
+ }
48014
+ }
48015
+ return {
48016
+ crop: { left, top, right, bottom },
48017
+ width: Math.round(width),
48018
+ height: Math.round(height)
48019
+ };
48020
+ }
48021
+ function createCropSession(deps) {
48022
+ let active = null;
48023
+ const selectionForObject = (state, paragraphId, paragraphOffset) => {
48024
+ const paragraph = getParagraphs(state).find(
48025
+ (p) => p.id === paragraphId
48026
+ );
48027
+ if (!paragraph) {
48028
+ return null;
48029
+ }
48030
+ return {
48031
+ anchor: paragraphOffsetToPosition(paragraph, paragraphOffset),
48032
+ focus: paragraphOffsetToPosition(paragraph, paragraphOffset + 1)
48033
+ };
48034
+ };
48035
+ const withSelection2 = (state, selection) => ({
48036
+ ...state,
48037
+ selection: {
48038
+ anchor: { ...selection.anchor },
48039
+ focus: { ...selection.focus }
48040
+ }
48041
+ });
48042
+ const handleMouseMove = (event) => {
48043
+ var _a2;
48044
+ const crop = active;
48045
+ if (!crop) {
48046
+ return;
48047
+ }
48048
+ const z = ((_a2 = deps.zoomFactor) == null ? void 0 : _a2.call(deps)) ?? 1;
48049
+ const deltaX = (event.clientX - crop.startClientX) / z;
48050
+ const deltaY = (event.clientY - crop.startClientY) / z;
48051
+ const result = resolveCroppedImage(crop, deltaX, deltaY);
48052
+ const selection = selectionForObject(
48053
+ deps.state,
48054
+ crop.paragraphId,
48055
+ crop.paragraphOffset
48056
+ );
48057
+ if (!selection) {
48058
+ deps.logger.warn("image crop:missing paragraph", crop);
48059
+ return;
48060
+ }
48061
+ deps.applyState(
48062
+ setSelectedImageCrop(withSelection2(deps.state, selection), {
48063
+ crop: result.crop,
48064
+ width: result.width,
48065
+ height: result.height
48066
+ })
48067
+ );
48068
+ };
48069
+ const handleMouseUp = () => {
48070
+ const crop = active;
48071
+ if (crop) {
48072
+ deps.updateHistoryState((current) => ({
48073
+ ...current,
48074
+ undoStack: [...current.undoStack, deps.cloneState(crop.initialState)],
48075
+ redoStack: []
48076
+ }));
48077
+ }
48078
+ stop();
48079
+ deps.focusInput();
48080
+ };
48081
+ const stop = () => {
48082
+ active = null;
48083
+ window.removeEventListener("mousemove", handleMouseMove);
48084
+ window.removeEventListener("mouseup", handleMouseUp);
48085
+ };
48086
+ const start = (paragraphId, paragraphOffset, handleDirection, event, initialState) => {
48087
+ const selection = selectionForObject(
48088
+ initialState,
48089
+ paragraphId,
48090
+ paragraphOffset
48091
+ );
48092
+ if (!selection) {
48093
+ return;
48094
+ }
48095
+ const selected = getSelectedImageRun(
48096
+ withSelection2(initialState, selection)
48097
+ );
48098
+ const image = selected && getRunImage(selected.run);
48099
+ if (!image) {
48100
+ return;
48101
+ }
48102
+ const startCrop = { ...image.crop ?? {} };
48103
+ active = {
48104
+ paragraphId,
48105
+ paragraphOffset,
48106
+ handleDirection,
48107
+ startClientX: event.clientX,
48108
+ startClientY: event.clientY,
48109
+ startWidth: image.width,
48110
+ startHeight: image.height,
48111
+ startCrop,
48112
+ initialState: deps.cloneState(initialState)
48113
+ };
48114
+ window.addEventListener("mousemove", handleMouseMove);
48115
+ window.addEventListener("mouseup", handleMouseUp);
48116
+ };
48117
+ return { start, stop };
48118
+ }
47713
48119
  function createEditorImageOperations(deps) {
47714
48120
  return createEditorImageOperationsImpl(deps);
47715
48121
  }
47716
48122
  function createEditorImageOperationsImpl(deps) {
47717
48123
  const [dragging, setDragging] = createSignal(false);
48124
+ const [cropMode, setCropMode] = createSignal(false);
47718
48125
  const [draggedImageInfo, setDraggedImageInfo] = createSignal(null);
48126
+ createEffect(() => {
48127
+ if (cropMode() && !getSelectedImageInfo(deps.state)) {
48128
+ setCropMode(false);
48129
+ }
48130
+ });
48131
+ const toggleCropMode = () => {
48132
+ if (!getSelectedImageInfo(deps.state)) {
48133
+ setCropMode(false);
48134
+ return;
48135
+ }
48136
+ setCropMode((value) => !value);
48137
+ };
47719
48138
  const [mousePos, setMousePos] = createSignal({ x: 0, y: 0 });
47720
48139
  const [dropTargetPos, setDropTargetPos] = createSignal(
47721
48140
  null
@@ -47817,6 +48236,15 @@ function createEditorImageOperationsImpl(deps) {
47817
48236
  logger: deps.logger
47818
48237
  }
47819
48238
  );
48239
+ const imageCropSession = createCropSession({
48240
+ state: deps.state,
48241
+ applyState: deps.applyState,
48242
+ updateHistoryState: deps.updateHistoryState,
48243
+ cloneState: deps.cloneState,
48244
+ focusInput: deps.focusInput,
48245
+ logger: deps.logger,
48246
+ zoomFactor: deps.zoomFactor
48247
+ });
47820
48248
  const handleImageDragMouseMove = (event) => {
47821
48249
  let dragState = activeImageDrag;
47822
48250
  if (!dragState) {
@@ -47945,8 +48373,22 @@ function createEditorImageOperationsImpl(deps) {
47945
48373
  event.stopPropagation();
47946
48374
  imageRotateSession.start(paragraphId, paragraphOffset, event, deps.state);
47947
48375
  };
48376
+ const handleImageCropHandleMouseDown = (paragraphId, paragraphOffset, direction, event) => {
48377
+ event.preventDefault();
48378
+ event.stopPropagation();
48379
+ imageCropSession.start(
48380
+ paragraphId,
48381
+ paragraphOffset,
48382
+ direction,
48383
+ event,
48384
+ deps.state
48385
+ );
48386
+ };
47948
48387
  return {
47949
48388
  dragging,
48389
+ cropMode,
48390
+ setCropMode,
48391
+ toggleCropMode,
47950
48392
  draggedImageInfo,
47951
48393
  mousePos,
47952
48394
  dropTargetPos,
@@ -47955,9 +48397,11 @@ function createEditorImageOperationsImpl(deps) {
47955
48397
  stopImageDrag,
47956
48398
  stopImageResize: imageResizeSession.stop,
47957
48399
  stopImageRotate: imageRotateSession.stop,
48400
+ stopImageCrop: imageCropSession.stop,
47958
48401
  handleImageMouseDown,
47959
48402
  handleImageResizeHandleMouseDown,
47960
- handleImageRotateHandleMouseDown
48403
+ handleImageRotateHandleMouseDown,
48404
+ handleImageCropHandleMouseDown
47961
48405
  };
47962
48406
  }
47963
48407
  function createEditorTextBoxOperations(deps) {
@@ -51992,6 +52436,22 @@ function setParagraphListStartAt(state, startAt) {
51992
52436
  preserveSelectionByParagraphOffsets(nextParagraphs, normalized)
51993
52437
  );
51994
52438
  }
52439
+ function parseCropAspectPreset(preset) {
52440
+ const value = preset.trim().toLowerCase();
52441
+ if (value === "reset" || value === "fit" || value === "fill") {
52442
+ return "reset";
52443
+ }
52444
+ const parts = value.split(/[:/]/);
52445
+ if (parts.length !== 2) {
52446
+ return null;
52447
+ }
52448
+ const a = Number(parts[0]);
52449
+ const b = Number(parts[1]);
52450
+ if (!Number.isFinite(a) || !Number.isFinite(b) || a <= 0 || b <= 0) {
52451
+ return null;
52452
+ }
52453
+ return a / b;
52454
+ }
51995
52455
  function createEditorCommandsController(deps) {
51996
52456
  return createEditorCommandsControllerImpl(deps);
51997
52457
  }
@@ -52286,6 +52746,44 @@ function createEditorCommandsControllerImpl(deps) {
52286
52746
  }
52287
52747
  deps.openImageCaptionDialog(getSelectedImageCaption(state) ?? "");
52288
52748
  };
52749
+ const applyImageWidthCmCommand = (cm) => {
52750
+ if (!selectedImageRun() || !Number.isFinite(cm) || cm <= 0) {
52751
+ return;
52752
+ }
52753
+ execTransactional(
52754
+ (current) => setSelectedImageWidthCm(current, cm),
52755
+ { mergeKey: MERGE_KEYS.imageResize }
52756
+ );
52757
+ };
52758
+ const applyImageHeightCmCommand = (cm) => {
52759
+ if (!selectedImageRun() || !Number.isFinite(cm) || cm <= 0) {
52760
+ return;
52761
+ }
52762
+ execTransactional(
52763
+ (current) => setSelectedImageHeightCm(current, cm),
52764
+ { mergeKey: MERGE_KEYS.imageResize }
52765
+ );
52766
+ };
52767
+ const applyImageCropAspectCommand = (preset) => {
52768
+ if (!selectedImageRun()) {
52769
+ return;
52770
+ }
52771
+ const mode = parseCropAspectPreset(preset);
52772
+ if (mode === null) {
52773
+ return;
52774
+ }
52775
+ execTransactional(
52776
+ (current) => applySelectedImageCropAspect(current, mode)
52777
+ );
52778
+ };
52779
+ const applyImageBorderCommand = (patch) => {
52780
+ if (!selectedImageRun()) {
52781
+ return;
52782
+ }
52783
+ execTransactional(
52784
+ (current) => setSelectedImageBorder(current, patch)
52785
+ );
52786
+ };
52289
52787
  return {
52290
52788
  applyBooleanStyleCommand,
52291
52789
  applyValueStyleCommand,
@@ -52314,6 +52812,10 @@ function createEditorCommandsControllerImpl(deps) {
52314
52812
  promptForImageAlt,
52315
52813
  applyImageCaptionCommand,
52316
52814
  promptForImageCaption,
52815
+ applyImageWidthCmCommand,
52816
+ applyImageHeightCmCommand,
52817
+ applyImageCropAspectCommand,
52818
+ applyImageBorderCommand,
52317
52819
  handleListTab,
52318
52820
  handleListEnter,
52319
52821
  handleListBoundaryBackspace
@@ -53317,6 +53819,61 @@ function buildDocumentAndBrowserCommands({
53317
53819
  isEnabled: image.isSelected(),
53318
53820
  isActive: image.isSelected()
53319
53821
  })
53822
+ ),
53823
+ imageContext: actionCommand(
53824
+ "imageContext",
53825
+ () => {
53826
+ },
53827
+ () => ({
53828
+ isEnabled: image.isSelected(),
53829
+ isActive: image.isSelected(),
53830
+ value: null
53831
+ })
53832
+ ),
53833
+ imageWidthCm: actionCommand(
53834
+ "imageWidthCm",
53835
+ (p) => image.setWidthCm(Number(p)),
53836
+ () => {
53837
+ var _a2;
53838
+ return {
53839
+ isEnabled: image.isSelected(),
53840
+ value: ((_a2 = image.getSizeCm()) == null ? void 0 : _a2.width) ?? null
53841
+ };
53842
+ }
53843
+ ),
53844
+ imageHeightCm: actionCommand(
53845
+ "imageHeightCm",
53846
+ (p) => image.setHeightCm(Number(p)),
53847
+ () => {
53848
+ var _a2;
53849
+ return {
53850
+ isEnabled: image.isSelected(),
53851
+ value: ((_a2 = image.getSizeCm()) == null ? void 0 : _a2.height) ?? null
53852
+ };
53853
+ }
53854
+ ),
53855
+ imageCrop: actionCommand(
53856
+ "imageCrop",
53857
+ () => image.toggleCrop(),
53858
+ () => ({
53859
+ isEnabled: image.isSelected(),
53860
+ isActive: image.isCropActive()
53861
+ })
53862
+ ),
53863
+ imageCropAspect: actionCommand(
53864
+ "imageCropAspect",
53865
+ (p) => image.applyCropAspect(String(p)),
53866
+ () => ({
53867
+ isEnabled: image.isSelected()
53868
+ })
53869
+ ),
53870
+ imageBorder: actionCommand(
53871
+ "imageBorder",
53872
+ (p) => image.setBorder(p),
53873
+ () => ({
53874
+ isEnabled: image.isSelected(),
53875
+ value: image.getBorder()
53876
+ })
53320
53877
  )
53321
53878
  };
53322
53879
  }
@@ -54134,7 +54691,15 @@ function buildEssentialsImage(options) {
54134
54691
  return {
54135
54692
  promptAlt: () => options.commandsController.promptForImageAlt(),
54136
54693
  promptCaption: () => options.commandsController.promptForImageCaption(),
54137
- isSelected: () => Boolean(options.selectedImageRun())
54694
+ isSelected: () => Boolean(options.selectedImageRun()),
54695
+ getSizeCm: () => getSelectedImageSizeCm(options.state()),
54696
+ setWidthCm: (cm) => options.commandsController.applyImageWidthCmCommand(cm),
54697
+ setHeightCm: (cm) => options.commandsController.applyImageHeightCmCommand(cm),
54698
+ isCropActive: () => options.imageCropMode.isActive(),
54699
+ toggleCrop: () => options.imageCropMode.toggle(),
54700
+ applyCropAspect: (preset) => options.commandsController.applyImageCropAspectCommand(preset),
54701
+ getBorder: () => getSelectedImageBorder(options.state()),
54702
+ setBorder: (patch) => options.commandsController.applyImageBorderCommand(patch)
54138
54703
  };
54139
54704
  }
54140
54705
  function buildEssentialsBrowser() {
@@ -55083,6 +55648,10 @@ function createEditorCommandRuntimeImpl(deps) {
55083
55648
  importInputRef: deps.importInputRef,
55084
55649
  imageInputRef: deps.imageInputRef,
55085
55650
  selectedImageRun: interaction.selectedImageRun,
55651
+ imageCropMode: {
55652
+ isActive: interaction.imageOps.cropMode,
55653
+ toggle: interaction.imageOps.toggleCropMode
55654
+ },
55086
55655
  selectionBoxes: doc.selectionBoxes,
55087
55656
  focusInput: deps.focusInput,
55088
55657
  applyState: deps.applyState,
@@ -55409,7 +55978,8 @@ function OasisEditorApp(props = {}) {
55409
55978
  hoveredRevision: revisionController.hoveredRevision,
55410
55979
  focused,
55411
55980
  showCaret: shouldShowCaret,
55412
- importProgress: docIO.importProgress
55981
+ importProgress: docIO.importProgress,
55982
+ imageCropMode: imageOps.cropMode
55413
55983
  },
55414
55984
  refs: {
55415
55985
  focusController
@@ -55430,6 +56000,7 @@ function OasisEditorApp(props = {}) {
55430
56000
  handleImageResizeHandleMouseDown: imageOps.handleImageResizeHandleMouseDown,
55431
56001
  handleTextBoxResizeHandleMouseDown: textBoxOps.handleTextBoxResizeHandleMouseDown,
55432
56002
  handleImageRotateHandleMouseDown: imageOps.handleImageRotateHandleMouseDown,
56003
+ handleImageCropHandleMouseDown: imageOps.handleImageCropHandleMouseDown,
55433
56004
  handleTextBoxRotateHandleMouseDown: textBoxOps.handleTextBoxRotateHandleMouseDown,
55434
56005
  handleEditorContextMenu
55435
56006
  },
@@ -55458,6 +56029,7 @@ function OasisEditorApp(props = {}) {
55458
56029
  textDrag.stopDrag();
55459
56030
  imageOps.stopImageDrag();
55460
56031
  imageOps.stopImageResize();
56032
+ imageOps.stopImageCrop();
55461
56033
  textBoxOps.stopTextBoxResize();
55462
56034
  stopIconObserver();
55463
56035
  });