@stll/folio-core 0.51.0 → 0.52.0

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.
@@ -3,7 +3,7 @@ import { expectHyperlinkMarkAttrs, expectRunPropertyChangeMarkAttrs, expectTable
3
3
  import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyles.js";
4
4
  import { applyMarksToRunFormattingRepresentation, expandRunFormattingCarrier, runFormattingCarrierReviewText } from "../prosemirror/runFormattingInlineCarriers.js";
5
5
  import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
6
- import { paragraphRunStyleContextAt } from "../prosemirror/runStyleFormatting.js";
6
+ import { nearestParagraphRunStyleContext } from "../prosemirror/runStyleFormatting.js";
7
7
  import { isTableCellRetainedInReviewView } from "../prosemirror/tableCellRevisionVisibility.js";
8
8
  import { canonicalJson } from "../utils/canonicalJson.js";
9
9
  //#region src/compare/inline-provenance.ts
@@ -19,10 +19,11 @@ const hyperlinkIdentity = (node) => {
19
19
  });
20
20
  };
21
21
  const isInserted = (node) => node.marks.some(({ type }) => type.name === "insertion");
22
- const carrierRepresentations = (carrier) => carrier.representations.map((representation) => ({
22
+ const carrierRepresentations = ({ carrier, paragraph }) => carrier.representations.map((representation) => ({
23
23
  ...representation,
24
24
  from: representation.position,
25
- to: representation.position + representation.node.nodeSize
25
+ to: representation.position + representation.node.nodeSize,
26
+ paragraph
26
27
  }));
27
28
  const targetBlockIdLookup = (anchors) => {
28
29
  const ordered = Object.values(anchors).toSorted((left, right) => left.from - right.from || left.to - right.to);
@@ -53,7 +54,13 @@ const collectCarriers = ({ doc, targetSnapshot }) => {
53
54
  const carriers = [];
54
55
  const targetBlockIdAt = targetSnapshot ? targetBlockIdLookup(targetSnapshot.anchors) : void 0;
55
56
  let unanchoredTargetCarrier = false;
57
+ const openParagraphs = [];
56
58
  doc.descendants((node, position) => {
59
+ while ((openParagraphs.at(-1)?.end ?? Number.POSITIVE_INFINITY) <= position) openParagraphs.pop();
60
+ if (node.type.name === "paragraph") openParagraphs.push({
61
+ node,
62
+ end: position + node.nodeSize
63
+ });
57
64
  if ((node.type.name === "tableCell" || node.type.name === "tableHeader") && !isTableCellRetainedInReviewView(expectTableCellAttrs(node).cellMarker?.kind, "final")) return false;
58
65
  if (!node.isInline) return true;
59
66
  const carrier = expandRunFormattingCarrier(node, position);
@@ -69,6 +76,7 @@ const collectCarriers = ({ doc, targetSnapshot }) => {
69
76
  }
70
77
  carriers.push({
71
78
  carrier,
79
+ paragraph: openParagraphs.at(-1)?.node ?? null,
72
80
  text: runFormattingCarrierReviewText(carrier),
73
81
  targetBlockId
74
82
  });
@@ -106,8 +114,8 @@ const matchCarrierStreams = ({ live, target }) => {
106
114
  const targetIsText = targetCarrier.carrier.disposition === "text-run";
107
115
  if (!liveIsText || !targetIsText) {
108
116
  if (liveOffset !== 0 || targetOffset !== 0 || !sameCarrierShape(liveCarrier, targetCarrier)) return null;
109
- const liveRepresentations = carrierRepresentations(liveCarrier.carrier);
110
- const targetRepresentations = carrierRepresentations(targetCarrier.carrier);
117
+ const liveRepresentations = carrierRepresentations(liveCarrier);
118
+ const targetRepresentations = carrierRepresentations(targetCarrier);
111
119
  for (const [index, liveRepresentation] of liveRepresentations.entries()) {
112
120
  const targetRepresentation = targetRepresentations.at(index);
113
121
  if (!targetRepresentation) return null;
@@ -123,8 +131,8 @@ const matchCarrierStreams = ({ live, target }) => {
123
131
  }
124
132
  const sharedLength = Math.min(liveText.length, targetText.length);
125
133
  if (sharedLength === 0 || liveText.slice(0, sharedLength) !== targetText.slice(0, sharedLength)) return null;
126
- const liveRepresentation = carrierRepresentations(liveCarrier.carrier).at(0);
127
- const targetRepresentation = carrierRepresentations(targetCarrier.carrier).at(0);
134
+ const liveRepresentation = carrierRepresentations(liveCarrier).at(0);
135
+ const targetRepresentation = carrierRepresentations(targetCarrier).at(0);
128
136
  if (!liveRepresentation || !targetRepresentation) return null;
129
137
  matched.push({
130
138
  live: {
@@ -152,12 +160,8 @@ const matchCarrierStreams = ({ live, target }) => {
152
160
  }
153
161
  return matched;
154
162
  };
155
- const authoredFormattingAt = ({ doc, representation, styleResolver }) => readAuthoredRunFormatting({
156
- context: paragraphRunStyleContextAt({
157
- doc,
158
- pos: representation.from,
159
- styleResolver
160
- }),
163
+ const authoredFormattingAt = ({ representation, styleResolver }) => readAuthoredRunFormatting({
164
+ context: nearestParagraphRunStyleContext(representation.paragraph, styleResolver),
161
165
  marks: representation.node.marks,
162
166
  styleResolver
163
167
  });
@@ -190,12 +194,10 @@ const matchInlineProvenance = ({ state, targetSnapshot, revisionStamp, originalR
190
194
  const planned = [];
191
195
  for (const segment of matched) {
192
196
  const liveFormatting = authoredFormattingAt({
193
- doc: state.doc,
194
197
  representation: segment.live,
195
198
  styleResolver: liveStyleResolver
196
199
  });
197
200
  const targetFormatting = authoredFormattingAt({
198
- doc: targetDocument,
199
201
  representation: segment.target,
200
202
  styleResolver: targetStyleResolver
201
203
  });
@@ -220,11 +222,7 @@ const matchInlineProvenance = ({ state, targetSnapshot, revisionStamp, originalR
220
222
  let nextRevisionId = revisionStamp.idSeed;
221
223
  const changedTargetBlockIds = /* @__PURE__ */ new Set();
222
224
  for (const change of planned.toReversed()) {
223
- const context = paragraphRunStyleContextAt({
224
- doc: state.doc,
225
- pos: change.live.from,
226
- styleResolver: liveStyleResolver
227
- });
225
+ const context = nearestParagraphRunStyleContext(change.live.paragraph, liveStyleResolver);
228
226
  const formattingMarks = reconcileRunFormattingMarks({
229
227
  authoredFormatting: change.formatting,
230
228
  context,
@@ -321,11 +319,9 @@ const sameAuthoredInlineProvenance = (baseSnapshot, targetSnapshot) => {
321
319
  const baseStyleResolver = styleResolverOf(baseSnapshot);
322
320
  const targetStyleResolver = styleResolverOf(targetSnapshot);
323
321
  return matched.every(({ live, target }) => hyperlinkIdentity(live.node) === hyperlinkIdentity(target.node) && canonicalJson(authoredFormattingAt({
324
- doc: baseDocument,
325
322
  representation: live,
326
323
  styleResolver: baseStyleResolver
327
324
  })) === canonicalJson(authoredFormattingAt({
328
- doc: targetDocument,
329
325
  representation: target,
330
326
  styleResolver: targetStyleResolver
331
327
  })));
@@ -108,9 +108,22 @@ const boundaryParagraphEntriesOf = (document) => {
108
108
  if (!children) return null;
109
109
  return children.flatMap((child) => child.type === "paragraph" ? [child.paragraph] : []);
110
110
  };
111
+ const hasSectionEndpoint = (document) => {
112
+ let found = false;
113
+ document.forEach((node) => {
114
+ if (node.type.name === "paragraph" && expectParagraphAttrs(node)._sectionProperties !== void 0) found = true;
115
+ });
116
+ return found;
117
+ };
111
118
  /** Stage section deltas after document operations, against the accepted projection. */
112
119
  const stageSectionBoundaryProperties = ({ state, target, originalRevisionIdSeed, revisionStamp, author, maxRanges, mapTargetProperties }) => {
113
120
  if (!Number.isSafeInteger(maxRanges) || maxRanges < 0) return { status: "budget-exceeded" };
121
+ if (!hasSectionEndpoint(target)) return {
122
+ status: "matched",
123
+ transaction: state.tr,
124
+ nextRevisionId: revisionStamp.idSeed,
125
+ rangeCount: 0
126
+ };
114
127
  const reviewedState = resolveAllChangesInHeadlessStateWithMapping(state, "accept");
115
128
  const reviewed = boundaryParagraphEntriesOf(reviewedState.state.doc);
116
129
  const targets = boundaryParagraphEntriesOf(target);
@@ -1,6 +1,32 @@
1
1
  // @ts-nocheck -- generated and verified by build-shaper-wasm.ts
2
2
  /* @ts-self-types="./text_shaper.d.ts" */
3
3
 
4
+ /**
5
+ * Resolve the bidirectional levels and visual order of one line.
6
+ *
7
+ * `right_to_left` is the paragraph direction, or `None` for rules P2 and P3.
8
+ * Returns `[paragraphLevel, charCount, level * charCount, visualIndex *
9
+ * charCount]`, counting characters as Unicode scalar values.
10
+ * @param {string} text
11
+ * @param {boolean | null} [right_to_left]
12
+ * @returns {Int32Array}
13
+ */
14
+ export function resolveBidi(text, right_to_left) {
15
+ try {
16
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
17
+ const ptr0 = passStringToWasm0(text, wasm.__wbindgen_export, wasm.__wbindgen_export2);
18
+ const len0 = WASM_VECTOR_LEN;
19
+ wasm.resolveBidi(retptr, ptr0, len0, isLikeNone(right_to_left) ? 0xFFFFFF : right_to_left ? 1 : 0);
20
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
21
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
22
+ var v2 = getArrayI32FromWasm0(r0, r1).slice();
23
+ wasm.__wbindgen_export3(r0, r1 * 4, 4);
24
+ return v2;
25
+ } finally {
26
+ wasm.__wbindgen_add_to_stack_pointer(16);
27
+ }
28
+ }
29
+
4
30
  /**
5
31
  * Shape one run of text with one face.
6
32
  *
Binary file
@@ -52,6 +52,12 @@ type ParagraphRunStyleContextAtOptions = {
52
52
  styleResolver?: RunStyleResolver | null;
53
53
  };
54
54
  declare const paragraphRunStyleContextAt: ({ doc, pos, styleResolver }: ParagraphRunStyleContextAtOptions) => ParagraphRunStyleContext;
55
+ /**
56
+ * {@link paragraphRunStyleContextAt} for a caller that already knows the
57
+ * nearest paragraph, or that there is none. A document walk knows it for free,
58
+ * where `doc.resolve` re-descends from the root once per run.
59
+ */
60
+ declare const nearestParagraphRunStyleContext: (paragraph: Node | null, styleResolver?: RunStyleResolver | null) => ParagraphRunStyleContext;
55
61
  type ResolveEffectiveRunStyleFormattingOptions = {
56
62
  marks: readonly Mark[];
57
63
  paragraphFormatting: document_d_exports.TextFormatting | undefined;
@@ -60,4 +66,4 @@ type ResolveEffectiveRunStyleFormattingOptions = {
60
66
  /** Resolve the non-direct run cascade from shared document styles and the current paragraph. */
61
67
  declare const resolveEffectiveRunStyleFormatting: ({ marks, paragraphFormatting, styleResolver }: ResolveEffectiveRunStyleFormattingOptions) => document_d_exports.TextFormatting | undefined;
62
68
  //#endregion
63
- export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
69
+ export { ParagraphRunStyleContext, RunStyleResolver, getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -153,12 +153,18 @@ const paragraphRunStyleContextAt = ({ doc, pos, styleResolver }) => {
153
153
  const ancestor = resolved.node(depth);
154
154
  if (ancestor.type.name === "paragraph") return paragraphRunStyleContext(ancestor, styleResolver);
155
155
  }
156
- return {
157
- baseParagraphFormatting: void 0,
158
- paragraphFormatting: void 0,
159
- paragraphMarkFormatting: void 0,
160
- paragraphMarkPrecedesStyle: false
161
- };
156
+ return nearestParagraphRunStyleContext(null, styleResolver);
157
+ };
158
+ /**
159
+ * {@link paragraphRunStyleContextAt} for a caller that already knows the
160
+ * nearest paragraph, or that there is none. A document walk knows it for free,
161
+ * where `doc.resolve` re-descends from the root once per run.
162
+ */
163
+ const nearestParagraphRunStyleContext = (paragraph, styleResolver) => paragraph ? paragraphRunStyleContext(paragraph, styleResolver) : {
164
+ baseParagraphFormatting: void 0,
165
+ paragraphFormatting: void 0,
166
+ paragraphMarkFormatting: void 0,
167
+ paragraphMarkPrecedesStyle: false
162
168
  };
163
169
  /** Resolve the non-direct run cascade from shared document styles and the current paragraph. */
164
170
  const resolveEffectiveRunStyleFormatting = ({ marks, paragraphFormatting, styleResolver }) => {
@@ -176,4 +182,4 @@ const resolveEffectiveRunStyleFormatting = ({ marks, paragraphFormatting, styleR
176
182
  });
177
183
  };
178
184
  //#endregion
179
- export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
185
+ export { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, nearestParagraphRunStyleContext, paragraphFormattingForRun, paragraphRunStyleContext, paragraphRunStyleContextAt, resolveEffectiveRunStyleFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting };
@@ -14,6 +14,9 @@
14
14
  * the Unicode data that engine needs, and a document in Latin, Cyrillic or
15
15
  * Greek needs none of it: `getShaper` is called only once a run in a shaping
16
16
  * script is about to be measured or painted, and never before.
17
+ *
18
+ * The same artifact resolves the bidirectional algorithm, because splitting a
19
+ * line into runs that each read one way is what shaping needs first.
17
20
  */
18
21
  /** Which way a run advances. Resolved by the producer, never guessed here. */
19
22
  declare const SHAPING_DIRECTION: {
@@ -57,22 +60,62 @@ type ShapedRun = {
57
60
  /** Design units per em, so a caller scales without re-reading the face. */
58
61
  readonly unitsPerEm: number;
59
62
  };
63
+ /** The paragraph direction of a line whose bidirectional levels are resolved. */
64
+ declare const BIDI_DIRECTION: {
65
+ readonly leftToRight: "ltr";
66
+ readonly rightToLeft: "rtl";
67
+ /** Rules P2 and P3: the first strong character outside an isolate decides. */
68
+ readonly auto: "auto";
69
+ };
70
+ type BidiDirection = (typeof BIDI_DIRECTION)[keyof typeof BIDI_DIRECTION];
71
+ type ResolveBidiRequest = {
72
+ /** One paragraph laid out as one line; a paragraph separator does not split it. */
73
+ readonly text: string;
74
+ readonly direction: BidiDirection;
75
+ };
76
+ /**
77
+ * One line after the Unicode Bidirectional Algorithm (UAX #9), rules P2
78
+ * through L2. Indices count code points, not UTF-16 units.
79
+ */
80
+ type BidiLine = {
81
+ /** 0 when the paragraph reads left to right, 1 when right to left. */
82
+ readonly paragraphLevel: number;
83
+ /**
84
+ * Embedding level per code point, after rule L1; odd levels read right to
85
+ * left. Characters rule X9 removes (explicit formatting characters such as
86
+ * isolates) carry a level but draw nothing.
87
+ */
88
+ readonly levels: readonly number[];
89
+ /** Code-point indices in visual order, left to right (rule L2). */
90
+ readonly visualOrder: readonly number[];
91
+ };
60
92
  type Shaper = {
61
93
  readonly shapeRun: (request: ShapeRunRequest) => ShapedRun;
94
+ readonly resolveBidi: (request: ResolveBidiRequest) => BidiLine;
62
95
  };
63
96
  declare const ShaperError_base: import("better-result").TaggedErrorClass<"ShaperError">;
64
97
  declare class ShaperError extends ShaperError_base<{
65
98
  message: string;
66
99
  cause?: unknown;
67
100
  }> {}
101
+ /**
102
+ * Where the artifact comes from when the caller already holds it: a runtime
103
+ * that cannot fetch its own package files (a single-file executable, an
104
+ * embedded asset) hands over the WebAssembly bytes instead.
105
+ */
106
+ type ShaperSource = {
107
+ readonly wasm: Uint8Array | ArrayBuffer;
108
+ };
68
109
  /**
69
110
  * Loads the shaper, once, and hands back the single implementation both the
70
111
  * measurer and the PDF backend use.
71
112
  *
72
- * Calling this is what fetches the artifact, so a caller asks for it only after
73
- * establishing that some run actually needs shaping.
113
+ * Calling this without a source is what fetches the artifact, so a caller asks
114
+ * for it only after establishing that some run actually needs shaping. With a
115
+ * source, the bytes given are instantiated and nothing is fetched. Either way
116
+ * the first successful load is the one every later call shares.
74
117
  */
75
- declare const getShaper: () => Promise<Shaper>;
118
+ declare const getShaper: (source?: ShaperSource) => Promise<Shaper>;
76
119
  /**
77
120
  * Whether the artifact has been loaded in this process.
78
121
  *
@@ -89,4 +132,4 @@ declare const shaperLoaded: () => boolean;
89
132
  */
90
133
  declare const resolvedShaper: () => Shaper | null;
91
134
  //#endregion
92
- export { SHAPING_DIRECTION, ShapeRunRequest, ShapedGlyph, ShapedRun, Shaper, ShaperError, ShapingDirection, getShaper, resolvedShaper, shaperLoaded };
135
+ export { BIDI_DIRECTION, BidiDirection, BidiLine, ResolveBidiRequest, SHAPING_DIRECTION, ShapeRunRequest, ShapedGlyph, ShapedRun, Shaper, ShaperError, ShaperSource, ShapingDirection, getShaper, resolvedShaper, shaperLoaded };
@@ -1,4 +1,4 @@
1
- import __wbg_init, { shapeRun } from "../generated/text_shaper.js";
1
+ import __wbg_init, { resolveBidi, shapeRun } from "../generated/text_shaper.js";
2
2
  import { TaggedError } from "better-result";
3
3
  //#region src/shaping/shaper.ts
4
4
  /**
@@ -16,12 +16,22 @@ import { TaggedError } from "better-result";
16
16
  * the Unicode data that engine needs, and a document in Latin, Cyrillic or
17
17
  * Greek needs none of it: `getShaper` is called only once a run in a shaping
18
18
  * script is about to be measured or painted, and never before.
19
+ *
20
+ * The same artifact resolves the bidirectional algorithm, because splitting a
21
+ * line into runs that each read one way is what shaping needs first.
19
22
  */
20
23
  /** Which way a run advances. Resolved by the producer, never guessed here. */
21
24
  const SHAPING_DIRECTION = {
22
25
  leftToRight: "ltr",
23
26
  rightToLeft: "rtl"
24
27
  };
28
+ /** The paragraph direction of a line whose bidirectional levels are resolved. */
29
+ const BIDI_DIRECTION = {
30
+ leftToRight: "ltr",
31
+ rightToLeft: "rtl",
32
+ /** Rules P2 and P3: the first strong character outside an isolate decides. */
33
+ auto: "auto"
34
+ };
25
35
  var ShaperError = class extends TaggedError("ShaperError") {};
26
36
  /**
27
37
  * The flat buffer the WebAssembly entry returns:
@@ -51,26 +61,47 @@ const decode = (buffer) => {
51
61
  unitsPerEm
52
62
  };
53
63
  };
54
- const shaper = { shapeRun: ({ font, faceIndex = 0, text, direction, script = "", language = "", featuresOn = [], featuresOff = [] }) => {
55
- try {
56
- return decode(shapeRun(font, faceIndex, text, direction === SHAPING_DIRECTION.rightToLeft, script, language, [...featuresOn], [...featuresOff]));
57
- } catch (cause) {
58
- throw new ShaperError({
59
- message: "Could not shape a run of text",
60
- cause
61
- });
64
+ /** `[paragraphLevel, count, level * count, visualIndex * count]`. */
65
+ const decodeBidi = (buffer) => {
66
+ const count = buffer[1] ?? 0;
67
+ const levelsAt = HEADER_FIELDS;
68
+ const orderAt = HEADER_FIELDS + count;
69
+ return {
70
+ paragraphLevel: buffer[0] ?? 0,
71
+ levels: Array.from(buffer.subarray(levelsAt, orderAt)),
72
+ visualOrder: Array.from(buffer.subarray(orderAt, orderAt + count))
73
+ };
74
+ };
75
+ const RIGHT_TO_LEFT_BY_BIDI_DIRECTION = {
76
+ ltr: false,
77
+ rtl: true,
78
+ auto: void 0
79
+ };
80
+ const shaper = {
81
+ resolveBidi: ({ text, direction }) => decodeBidi(resolveBidi(text, RIGHT_TO_LEFT_BY_BIDI_DIRECTION[direction])),
82
+ shapeRun: ({ font, faceIndex = 0, text, direction, script = "", language = "", featuresOn = [], featuresOff = [] }) => {
83
+ try {
84
+ return decode(shapeRun(font, faceIndex, text, direction === SHAPING_DIRECTION.rightToLeft, script, language, [...featuresOn], [...featuresOff]));
85
+ } catch (cause) {
86
+ throw new ShaperError({
87
+ message: "Could not shape a run of text",
88
+ cause
89
+ });
90
+ }
62
91
  }
63
- } };
92
+ };
64
93
  let loading;
65
94
  /**
66
95
  * Loads the shaper, once, and hands back the single implementation both the
67
96
  * measurer and the PDF backend use.
68
97
  *
69
- * Calling this is what fetches the artifact, so a caller asks for it only after
70
- * establishing that some run actually needs shaping.
98
+ * Calling this without a source is what fetches the artifact, so a caller asks
99
+ * for it only after establishing that some run actually needs shaping. With a
100
+ * source, the bytes given are instantiated and nothing is fetched. Either way
101
+ * the first successful load is the one every later call shares.
71
102
  */
72
- const getShaper = () => {
73
- loading ??= __wbg_init().then(() => {
103
+ const getShaper = (source) => {
104
+ loading ??= __wbg_init(source === void 0 ? void 0 : { module_or_path: source.wasm }).then(() => {
74
105
  resolved = shaper;
75
106
  return shaper;
76
107
  }).catch((cause) => {
@@ -99,4 +130,4 @@ let resolved = null;
99
130
  */
100
131
  const resolvedShaper = () => resolved;
101
132
  //#endregion
102
- export { SHAPING_DIRECTION, ShaperError, getShaper, resolvedShaper, shaperLoaded };
133
+ export { BIDI_DIRECTION, SHAPING_DIRECTION, ShaperError, getShaper, resolvedShaper, shaperLoaded };
@@ -0,0 +1,4 @@
1
+ import { BIDI_DIRECTION, BidiLine, ResolveBidiRequest, SHAPING_DIRECTION, ShapeRunRequest, ShapedRun, Shaper, ShaperSource, getShaper } from "./shaping/shaper.js";
2
+ import { SfntFont, parseSfnt } from "./fonts/sfnt/parse.js";
3
+ import { TrueTypeSubset, subsetTrueType } from "./fonts/sfnt/subset.js";
4
+ export { BIDI_DIRECTION, type BidiLine, type ResolveBidiRequest, SHAPING_DIRECTION, type SfntFont, type ShapeRunRequest, type ShapedRun, type Shaper, type ShaperSource, type TrueTypeSubset, getShaper, parseSfnt, subsetTrueType };
@@ -0,0 +1,4 @@
1
+ import { parseSfnt } from "./fonts/sfnt/parse.js";
2
+ import { subsetTrueType } from "./fonts/sfnt/subset.js";
3
+ import { BIDI_DIRECTION, SHAPING_DIRECTION, getShaper } from "./shaping/shaper.js";
4
+ export { BIDI_DIRECTION, SHAPING_DIRECTION, getShaper, parseSfnt, subsetTrueType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
5
5
  "keywords": [
6
6
  "document-model",
@@ -106,6 +106,11 @@
106
106
  "types": "./dist/docx/documentClone.d.ts",
107
107
  "import": "./dist/docx/documentClone.js"
108
108
  },
109
+ "./text-shaping": {
110
+ "types": "./dist/text-shaping.d.ts",
111
+ "import": "./dist/text-shaping.js"
112
+ },
113
+ "./text-shaping/wasm": "./dist/generated/text_shaper_bg.wasm",
109
114
  "./docx/paragraphPropertySource": null,
110
115
  "./internal/*": null,
111
116
  "./*": {