@portone/docx-editor 0.5.0 → 0.5.1

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 (42) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/CONTRIBUTING.md +2 -0
  3. package/dist/docx/formatting/styles.d.ts +0 -2
  4. package/dist/docx/formatting/styles.js +2 -15
  5. package/dist/docx/identities.js +17 -26
  6. package/dist/docx/importParagraph.d.ts +6 -5
  7. package/dist/docx/importParagraph.js +15 -62
  8. package/dist/docx/importPolicy.js +10 -5
  9. package/dist/docx/serializeParagraph.d.ts +5 -4
  10. package/dist/docx/serializeParagraph.js +22 -58
  11. package/dist/docx/tableTemplate.d.ts +25 -0
  12. package/dist/docx/tableTemplate.js +30 -16
  13. package/dist/docx/wrappers.d.ts +67 -0
  14. package/dist/docx/wrappers.js +117 -0
  15. package/dist/editor/clipboard/blockReaders.d.ts +74 -0
  16. package/dist/editor/clipboard/blockReaders.js +193 -0
  17. package/dist/editor/clipboard/htmlReader.d.ts +2 -6
  18. package/dist/editor/clipboard/htmlReader.js +98 -24
  19. package/dist/editor/clipboard/inlineFormatting.d.ts +0 -7
  20. package/dist/editor/clipboard/inlineFormatting.js +1 -7
  21. package/dist/editor/clipboard/plugin.js +7 -139
  22. package/dist/editor/clipboard/readContext.d.ts +10 -0
  23. package/dist/editor/clipboard/readContext.js +8 -2
  24. package/dist/editor/clipboard/source.d.ts +12 -0
  25. package/dist/editor/clipboard/source.js +21 -0
  26. package/dist/editor/commands/comments/editing.js +2 -1
  27. package/dist/editor/commands/linkCommands.js +20 -5
  28. package/dist/editor/commands/lockCommands.js +59 -16
  29. package/dist/editor/commands/paragraphCommands.js +2 -2
  30. package/dist/ooxml/props.d.ts +2 -0
  31. package/dist/ooxml/props.js +14 -0
  32. package/dist/schema/attrRoles.js +8 -3
  33. package/dist/schema/clipboard.d.ts +72 -0
  34. package/dist/schema/clipboard.js +288 -0
  35. package/dist/schema/docxSchema.js +27 -27
  36. package/dist/schema/locks.d.ts +3 -0
  37. package/dist/schema/locks.js +29 -12
  38. package/dist/schema/rendering.d.ts +14 -0
  39. package/dist/schema/rendering.js +24 -11
  40. package/dist/schema/wrappers.d.ts +58 -0
  41. package/dist/schema/wrappers.js +77 -0
  42. package/package.json +5 -4
@@ -35,6 +35,7 @@ import {
35
35
  tableStyle
36
36
  } from "../styles/inlineStyle.js";
37
37
  import { imageNodeSpec, runMarkSpec } from "./rendering.js";
38
+ import { WRAPPER_ATTRS, WRAPPER_GROUP } from "./wrappers.js";
38
39
  import { imageNodeSpec as imageNodeSpec2, runMarkSpec as runMarkSpec2 } from "./rendering.js";
39
40
  var NO_STORIES = Object.freeze({});
40
41
  function isRecord(value) {
@@ -572,7 +573,7 @@ var docxSchema = new Schema({
572
573
  hardBreak: {
573
574
  group: "inline",
574
575
  inline: true,
575
- marks: "run sdt link",
576
+ marks: "run wrapper",
576
577
  attrs: { brAttrs: { default: null } },
577
578
  toDOM(node) {
578
579
  return [
@@ -605,7 +606,7 @@ var docxSchema = new Schema({
605
606
  group: "inline",
606
607
  inline: true,
607
608
  draggable: true,
608
- marks: "run sdt link",
609
+ marks: "run wrapper",
609
610
  attrs: {
610
611
  /** The image bytes as a data URL */
611
612
  src: { default: null },
@@ -640,7 +641,7 @@ var docxSchema = new Schema({
640
641
  inline: true,
641
642
  atom: true,
642
643
  selectable: false,
643
- marks: "sdt link",
644
+ marks: "wrapper",
644
645
  attrs: {
645
646
  id: { default: null },
646
647
  xml: { default: null }
@@ -672,7 +673,7 @@ var docxSchema = new Schema({
672
673
  inline: true,
673
674
  atom: true,
674
675
  selectable: false,
675
- marks: "sdt link",
676
+ marks: "wrapper",
676
677
  attrs: {
677
678
  id: { default: null },
678
679
  xml: { default: null }
@@ -704,7 +705,7 @@ var docxSchema = new Schema({
704
705
  inline: true,
705
706
  atom: true,
706
707
  selectable: false,
707
- marks: "run sdt link",
708
+ marks: "run wrapper",
708
709
  attrs: {
709
710
  id: { default: null },
710
711
  referenceXml: { default: null },
@@ -780,7 +781,7 @@ var docxSchema = new Schema({
780
781
  inline: true,
781
782
  atom: true,
782
783
  selectable: false,
783
- marks: "run sdt link",
784
+ marks: "run wrapper",
784
785
  attrs: {
785
786
  kind: { default: "footnote" },
786
787
  id: { default: null },
@@ -836,7 +837,7 @@ var docxSchema = new Schema({
836
837
  group: "inline",
837
838
  inline: true,
838
839
  atom: true,
839
- marks: "run sdt link",
840
+ marks: "run wrapper",
840
841
  attrs: {
841
842
  xml: { default: null },
842
843
  /** The local name of the element, for example `fldChar` */
@@ -862,7 +863,7 @@ var docxSchema = new Schema({
862
863
  group: "inline",
863
864
  inline: true,
864
865
  atom: true,
865
- marks: "sdt link",
866
+ marks: "wrapper",
866
867
  attrs: {
867
868
  xml: { default: null },
868
869
  /** The local name of the element; `r` for a run with no content, kept whole */
@@ -889,20 +890,20 @@ var docxSchema = new Schema({
889
890
  *
890
891
  * It is declared ahead of the run mark on purpose: the mark declared first is drawn
891
892
  * outside on screen, so one control can hold the several runs it wrapped in the file.
893
+ * It is declared ahead of the other wrappers for the same reason, which is what settles
894
+ * the nesting of two wrappers written at one and the same depth (`./wrappers`).
892
895
  */
893
896
  sdt: {
897
+ group: WRAPPER_GROUP,
894
898
  // A character typed against either edge of the control belongs outside it
895
899
  inclusive: false,
900
+ // §17.5.2.17 has a control hold a control, so a second one does not replace the first:
901
+ // which stands inside which is what `depth` says (`./wrappers`)
902
+ excludes: "",
896
903
  attrs: {
897
904
  /** The opening XML of the `<w:sdt>`, the same string a wrapped cell carries */
898
905
  sdtPrefix: { default: null },
899
- /**
900
- * Which control this is, counted through the document as it was opened, and never
901
- * written back to the file. Two controls whose XML is identical would otherwise wear
902
- * the very same mark and their text would run into one. The first control gets 0, so
903
- * a control made during editing needs no number of its own.
904
- */
905
- sdtKey: { default: 0 },
906
+ ...WRAPPER_ATTRS,
906
907
  /**
907
908
  * The two clauses of the control's lock: whether its contents may not be edited, and
908
909
  * whether the control itself may not be deleted, not even whole. The `w:lock` inside
@@ -921,7 +922,8 @@ var docxSchema = new Schema({
921
922
  {
922
923
  class: locked ? `${editorClassNames.sdt} ${editorClassNames.sdtLocked}` : editorClassNames.sdt,
923
924
  "data-sdt-prefix": text(mark.attrs.sdtPrefix),
924
- "data-sdt-key": numberText(mark.attrs.sdtKey),
925
+ "data-key": numberText(mark.attrs.key),
926
+ "data-depth": numberText(mark.attrs.depth),
925
927
  "data-sdt-contents-locked": locked ? "1" : void 0,
926
928
  "data-sdt-deletion-locked": mark.attrs.deletionLocked === true ? "1" : void 0
927
929
  },
@@ -936,7 +938,8 @@ var docxSchema = new Schema({
936
938
  if (prefix === null || prefix === false) return false;
937
939
  return {
938
940
  sdtPrefix: prefix,
939
- sdtKey: parseInt10(dom.getAttribute("data-sdt-key"), 0),
941
+ key: parseInt10(dom.getAttribute("data-key"), 0),
942
+ depth: parseInt10(dom.getAttribute("data-depth"), 0),
940
943
  contentsLocked: dom.getAttribute("data-sdt-contents-locked") === "1",
941
944
  deletionLocked: dom.getAttribute("data-sdt-deletion-locked") === "1"
942
945
  };
@@ -952,10 +955,12 @@ var docxSchema = new Schema({
952
955
  * back out inside it (`docx/serializeParagraph`).
953
956
  */
954
957
  link: {
958
+ group: WRAPPER_GROUP,
955
959
  // A character typed against either edge of a link belongs outside it, and that is also what
956
960
  // decides whether a caret counts as standing in one (`editor/commands/linkCommands`)
957
961
  inclusive: false,
958
962
  attrs: {
963
+ ...WRAPPER_ATTRS,
959
964
  /**
960
965
  * The opening XML of the `<w:hyperlink>`, which carries everything about the link we never
961
966
  * read: `w:tooltip`, `w:history`, `w:docLocation`, `w:anchor`. null for a link made in the
@@ -967,14 +972,7 @@ var docxSchema = new Schema({
967
972
  * a bookmark alone, or one whose relationship leads nowhere we can follow: the wrapper still
968
973
  * travels, and no address is offered for it.
969
974
  */
970
- href: { default: null },
971
- /**
972
- * Which link this is, counted through the document as it was opened, and never written back
973
- * to the file. Two links written exactly alike would otherwise wear the very same mark and
974
- * the text they cover would run into one wrapper. The first link gets 0, so a link made
975
- * during editing needs no number of its own.
976
- */
977
- linkKey: { default: 0 }
975
+ href: { default: null }
978
976
  },
979
977
  toDOM(mark) {
980
978
  return [
@@ -986,7 +984,8 @@ var docxSchema = new Schema({
986
984
  // by the link panel instead
987
985
  "data-href": text(mark.attrs.href),
988
986
  "data-link-prefix": text(mark.attrs.linkPrefix),
989
- "data-link-key": numberText(mark.attrs.linkKey)
987
+ "data-key": numberText(mark.attrs.key),
988
+ "data-depth": numberText(mark.attrs.depth)
990
989
  },
991
990
  0
992
991
  ];
@@ -1002,7 +1001,8 @@ var docxSchema = new Schema({
1002
1001
  return {
1003
1002
  linkPrefix: prefix,
1004
1003
  href,
1005
- linkKey: parseInt10(dom.getAttribute("data-link-key"), 0)
1004
+ key: parseInt10(dom.getAttribute("data-key"), 0),
1005
+ depth: parseInt10(dom.getAttribute("data-depth"), 0)
1006
1006
  };
1007
1007
  }
1008
1008
  }
@@ -56,6 +56,9 @@ export interface ControlSpan extends StepRange {
56
56
  * A control that wrapped several runs comes in as several inlines wearing the very same mark, and
57
57
  * what a lock answers for is the control rather than the run: a stretch covering one run of a
58
58
  * control whole still covers only a part of the control.
59
+ *
60
+ * A control standing inside another gives a span of its own, the outer one first, and the two
61
+ * overlap: each locks on its own terms.
59
62
  */
60
63
  export declare function controlSpans(block: Textblock): ControlSpan[];
61
64
  /**
@@ -10,11 +10,12 @@ import {
10
10
  ReplaceStep
11
11
  } from "prosemirror-transform";
12
12
  import { docxSchema } from "./index.js";
13
+ import { wrappersOf } from "./wrappers.js";
13
14
  var unlockAllowed = new PluginKey("docxEditorUnlockAllowed");
14
15
  var historyReplay = new PluginKey("docxEditorHistoryReplay");
15
16
  var OPEN = { contents: false, deletion: false };
16
- function sdtMarkOf(node) {
17
- return node?.marks.find((mark) => mark.type === docxSchema.marks.sdt) ?? null;
17
+ function sdtMarksOf(node) {
18
+ return node ? wrappersOf(node, docxSchema.marks.sdt) : [];
18
19
  }
19
20
  function markLocks(mark) {
20
21
  return {
@@ -23,8 +24,7 @@ function markLocks(mark) {
23
24
  };
24
25
  }
25
26
  function lockedMarkOf(node) {
26
- const mark = sdtMarkOf(node);
27
- return mark !== null && markLocks(mark).contents ? mark : null;
27
+ return sdtMarksOf(node).find((mark) => markLocks(mark).contents) ?? null;
28
28
  }
29
29
  var CELL_CONTENTS_ATTR = "sdtContentsLocked";
30
30
  var CELL_DELETION_ATTR = "sdtDeletionLocked";
@@ -42,20 +42,37 @@ function isLockedCell(node) {
42
42
  return cellLocks(node).contents;
43
43
  }
44
44
  function carriesLock(node) {
45
- const mark = node.isInline ? sdtMarkOf(node) : null;
46
- const locks = mark === null ? cellLocks(node) : markLocks(mark);
47
- return locks.contents || locks.deletion;
45
+ const marks = node.isInline ? sdtMarksOf(node) : [];
46
+ if (marks.length === 0) {
47
+ const locks = cellLocks(node);
48
+ return locks.contents || locks.deletion;
49
+ }
50
+ return marks.some((mark) => {
51
+ const locks = markLocks(mark);
52
+ return locks.contents || locks.deletion;
53
+ });
48
54
  }
49
55
  function controlSpans(block) {
50
56
  const spans = [];
57
+ let reaching = [];
51
58
  block.node.forEach((child, offset) => {
52
- const mark = sdtMarkOf(child);
53
- if (!mark) return;
54
59
  const from = block.start + offset;
55
60
  const to = from + child.nodeSize;
56
- const last = spans.at(-1);
57
- if (last && last.to === from && last.mark.eq(mark)) last.to = to;
58
- else spans.push({ from, to, mark });
61
+ const standing = [];
62
+ for (const mark of sdtMarksOf(child)) {
63
+ const carried = reaching.find(
64
+ (span) => span.to === from && span.mark.eq(mark)
65
+ );
66
+ if (carried) {
67
+ carried.to = to;
68
+ standing.push(carried);
69
+ continue;
70
+ }
71
+ const started = { from, to, mark };
72
+ spans.push(started);
73
+ standing.push(started);
74
+ }
75
+ reaching = standing;
59
76
  });
60
77
  return spans;
61
78
  }
@@ -1,6 +1,20 @@
1
1
  import type { Attrs, DOMOutputSpec } from "prosemirror-model";
2
2
  import type { FontFallbacks } from "../styles/fontStack";
3
+ /**
4
+ * What a run says to anyone reading it, the page and a copy of it alike.
5
+ *
6
+ * The rest of the drawing is this editor talking to itself - the original XML, the worked-out
7
+ * formatting it was drawn from - and `schema/clipboard` publishes only what is here.
8
+ */
9
+ export declare function runAttrs(attrs: Attrs, fontFallbacks: FontFallbacks): Record<string, string | undefined>;
3
10
  /** The DOM representation shared by the schema and the editor's custom run mark view. */
4
11
  export declare function runMarkSpec(attrs: Attrs, fontFallbacks: FontFallbacks): DOMOutputSpec;
12
+ /**
13
+ * What an image says to anyone reading it, the page and a copy of it alike.
14
+ *
15
+ * The size is given in the pixels it is drawn at rather than as the document's own measure in EMU,
16
+ * which is what makes it the half another application can read.
17
+ */
18
+ export declare function imageAttrs(attrs: Attrs): Record<string, string | undefined>;
5
19
  /** The image element shared by the schema and the resizable image node view. */
6
20
  export declare function imageNodeSpec(attrs: Attrs): DOMOutputSpec;
@@ -9,15 +9,21 @@ function text(value) {
9
9
  function formatJson(format) {
10
10
  return format ? JSON.stringify(format) : void 0;
11
11
  }
12
+ function runAttrs(attrs, fontFallbacks) {
13
+ const format = toRunFormat(attrs.format);
14
+ return {
15
+ class: editorClassNames.run,
16
+ style: runStyle(format, fontFallbacks),
17
+ // Which shape of a Han character the browser draws is decided by this and nothing else
18
+ lang: format?.lang
19
+ };
20
+ }
12
21
  function runMarkSpec(attrs, fontFallbacks) {
13
22
  const format = toRunFormat(attrs.format);
14
23
  return [
15
24
  "span",
16
25
  {
17
- class: editorClassNames.run,
18
- style: runStyle(format, fontFallbacks),
19
- // Which shape of a Han character the browser draws is decided by this and nothing else
20
- lang: format?.lang,
26
+ ...runAttrs(attrs, fontFallbacks),
21
27
  "data-rattrs": text(attrs.rAttrs),
22
28
  "data-rpr": text(attrs.rPr),
23
29
  "data-fmt": formatJson(format),
@@ -27,22 +33,29 @@ function runMarkSpec(attrs, fontFallbacks) {
27
33
  0
28
34
  ];
29
35
  }
30
- function imageNodeSpec(attrs) {
36
+ function imageAttrs(attrs) {
31
37
  const extent = toImageExtent(attrs.extent);
38
+ return {
39
+ class: editorClassNames.image,
40
+ src: toImageSrc(attrs.src) ?? void 0,
41
+ alt: text(attrs.alt) ?? "",
42
+ width: extent ? `${Math.round(emuToPx(extent.cx))}` : void 0,
43
+ height: extent ? `${Math.round(emuToPx(extent.cy))}` : void 0
44
+ };
45
+ }
46
+ function imageNodeSpec(attrs) {
32
47
  return [
33
48
  "img",
34
49
  {
35
- class: editorClassNames.image,
36
- src: toImageSrc(attrs.src) ?? void 0,
37
- alt: text(attrs.alt) ?? "",
38
- width: extent ? `${Math.round(emuToPx(extent.cx))}` : void 0,
39
- height: extent ? `${Math.round(emuToPx(extent.cy))}` : void 0,
40
- "data-extent": formatJson(extent),
50
+ ...imageAttrs(attrs),
51
+ "data-extent": formatJson(toImageExtent(attrs.extent)),
41
52
  "data-xml": text(attrs.xml)
42
53
  }
43
54
  ];
44
55
  }
45
56
  export {
57
+ imageAttrs,
46
58
  imageNodeSpec,
59
+ runAttrs,
47
60
  runMarkSpec
48
61
  };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The inline wrappers a stretch of content stands inside, as the schema records them.
3
+ *
4
+ * A wrapper is an element that holds inline content and goes back out around the same content:
5
+ * a content control (`w:sdt`), a hyperlink (`w:hyperlink`). Each is a mark of its own, so each
6
+ * keeps the `inclusive` rule and the attrs its kind needs, and all of them share the `wrapper`
7
+ * group, so a node's `marks:` whitelist names the group rather than every kind in it and a new
8
+ * kind arrives as one mark spec.
9
+ *
10
+ * The nesting is recorded on the marks themselves: `depth` counts from the outermost wrapper the
11
+ * file wrote inwards. The order of a mark set cannot carry it - `Mark.addToSet` keeps insertion
12
+ * order only among marks of different types, `parseDOM` rebuilds a set from the page, and two
13
+ * wrappers of one kind may stand one inside the other - so `depth` is the source of truth and
14
+ * `wrapperMarks` is the one place that reads the order off it.
15
+ *
16
+ * What each kind reads out of the file and writes back into it is `docx/wrappers`.
17
+ */
18
+ import type { Mark, MarkType, Node as PMNode } from "prosemirror-model";
19
+ /** The mark group every inline wrapper belongs to */
20
+ export declare const WRAPPER_GROUP = "wrapper";
21
+ /** What every wrapper mark spec carries besides the attrs of its own kind */
22
+ export declare const WRAPPER_ATTRS: {
23
+ /** Outer-to-inner order as read from the file; equal depths fall back to declaration rank */
24
+ readonly depth: {
25
+ readonly default: 0;
26
+ };
27
+ /** Which occurrence this is in the opened document, so two wrappers written alike stay apart */
28
+ readonly key: {
29
+ readonly default: 0;
30
+ };
31
+ };
32
+ /** Whether marks of this type wrap the content they cover (`WRAPPER_GROUP`) */
33
+ export declare function isWrapperType(type: MarkType): boolean;
34
+ /**
35
+ * The wrappers this node stands inside, outermost first.
36
+ *
37
+ * Two wrappers written at the same depth - a control laid over a link during editing, say - fall
38
+ * back to the order the schema declares them in, which is the nesting the marks meant before
39
+ * `depth` existed.
40
+ */
41
+ export declare function wrapperMarks(node: PMNode): readonly Mark[];
42
+ /** Every wrapper of this kind the node stands inside, outermost first */
43
+ export declare function wrappersOf(node: PMNode, kind: MarkType): readonly Mark[];
44
+ /** The outermost wrapper of this kind the node stands inside. null where it stands in none */
45
+ export declare function wrapperOf(node: PMNode, kind: MarkType): Mark | null;
46
+ /**
47
+ * The depth of the innermost of these wrappers, and -1 where there is none, so that
48
+ * `innermostDepth(marks) + 1` is the depth a wrapper laid inside every one of them takes.
49
+ */
50
+ export declare function innermostDepth(marks: readonly Mark[]): number;
51
+ /**
52
+ * The wrappers all of these nodes stand inside alike, outermost first: the longest run of
53
+ * wrappers, from the outside in, that every one of them wears the very same one of.
54
+ *
55
+ * A wrapper laid across the whole stretch goes inside these and outside everything else, which is
56
+ * what keeps it one element in the file rather than one per stretch the nesting differs over.
57
+ */
58
+ export declare function sharedWrappers(nodes: readonly PMNode[]): readonly Mark[];
@@ -0,0 +1,77 @@
1
+ // src/schema/wrappers.ts
2
+ var WRAPPER_GROUP = "wrapper";
3
+ var WRAPPER_ATTRS = {
4
+ /** Outer-to-inner order as read from the file; equal depths fall back to declaration rank */
5
+ depth: { default: 0 },
6
+ /** Which occurrence this is in the opened document, so two wrappers written alike stay apart */
7
+ key: { default: 0 }
8
+ };
9
+ var FACTS = /* @__PURE__ */ new WeakMap();
10
+ var NO_WRAPPERS = [];
11
+ function factsOf(type) {
12
+ const known = FACTS.get(type);
13
+ if (known) return known;
14
+ const facts = {
15
+ wrapper: (type.spec.group ?? "").split(" ").includes(WRAPPER_GROUP),
16
+ rank: Object.keys(type.schema.marks).indexOf(type.name)
17
+ };
18
+ FACTS.set(type, facts);
19
+ return facts;
20
+ }
21
+ function isWrapperType(type) {
22
+ return factsOf(type).wrapper;
23
+ }
24
+ function depthOf(mark) {
25
+ const depth = mark.attrs.depth;
26
+ return typeof depth === "number" ? depth : 0;
27
+ }
28
+ function wrapperMarks(node) {
29
+ const marks = node.marks;
30
+ let found = 0;
31
+ for (const mark of marks) {
32
+ if (factsOf(mark.type).wrapper) found += 1;
33
+ }
34
+ if (found === 0) return NO_WRAPPERS;
35
+ const wrappers = found === marks.length ? [...marks] : marks.filter((mark) => factsOf(mark.type).wrapper);
36
+ if (found < 2) return wrappers;
37
+ return wrappers.sort(
38
+ (a, b) => depthOf(a) - depthOf(b) || factsOf(a.type).rank - factsOf(b.type).rank
39
+ );
40
+ }
41
+ function wrappersOf(node, kind) {
42
+ return wrapperMarks(node).filter((mark) => mark.type === kind);
43
+ }
44
+ function wrapperOf(node, kind) {
45
+ return wrapperMarks(node).find((mark) => mark.type === kind) ?? null;
46
+ }
47
+ function innermostDepth(marks) {
48
+ return marks.reduce(
49
+ (deepest, mark) => factsOf(mark.type).wrapper ? Math.max(deepest, depthOf(mark)) : deepest,
50
+ -1
51
+ );
52
+ }
53
+ function sharedWrappers(nodes) {
54
+ const first = nodes.at(0);
55
+ if (first === void 0) return [];
56
+ let shared = wrapperMarks(first);
57
+ for (const node of nodes.slice(1)) {
58
+ const marks = wrapperMarks(node);
59
+ const differs = shared.findIndex((mark, index) => {
60
+ const beside = marks[index];
61
+ return beside === void 0 || !mark.eq(beside);
62
+ });
63
+ if (differs !== -1) shared = shared.slice(0, differs);
64
+ if (shared.length === 0) break;
65
+ }
66
+ return shared;
67
+ }
68
+ export {
69
+ WRAPPER_ATTRS,
70
+ WRAPPER_GROUP,
71
+ innermostDepth,
72
+ isWrapperType,
73
+ sharedWrappers,
74
+ wrapperMarks,
75
+ wrapperOf,
76
+ wrappersOf
77
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portone/docx-editor",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "A simple DOCX editor for React, built directly on OOXML.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -107,7 +107,7 @@
107
107
  "build:demo": "vite build --config demo/vite.config.ts",
108
108
  "dev:site": "pnpm --filter @portone/docx-editor-site dev",
109
109
  "build:site": "pnpm --filter @portone/docx-editor-site build",
110
- "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm test:fixtures && pnpm test:site-release && pnpm check:demo-library",
110
+ "check": "pnpm lint && pnpm typecheck && pnpm test && pnpm test:fixtures && pnpm test:site-release && pnpm test:release && pnpm check:demo-library",
111
111
  "typecheck": "tsc --noEmit && tsc --noEmit -p e2e && tsc --noEmit -p demo && pnpm --filter @portone/docx-editor-site typecheck",
112
112
  "lint": "pnpm biome check . --diagnostic-level=error",
113
113
  "test": "vitest run",
@@ -119,9 +119,10 @@
119
119
  "api:update": "pnpm build && node scripts/api-report.mjs --local",
120
120
  "spec": "node scripts/index-ooxml-spec.mjs",
121
121
  "changeset": "changeset",
122
- "changeset:version": "changeset version",
122
+ "release:pr": "node scripts/release.mjs pr",
123
123
  "test:e2e": "playwright test",
124
- "test:site-release": "node --test scripts/site-release.test.mjs"
124
+ "test:site-release": "node --test scripts/site-release.test.mjs",
125
+ "test:release": "node --test scripts/release.test.mjs"
125
126
  },
126
127
  "types": "./dist/index.d.ts"
127
128
  }