@tarhnama/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +16 -0
- package/dist/code-tokens.d.ts +39 -0
- package/dist/code-tokens.d.ts.map +1 -0
- package/dist/code-tokens.js +189 -0
- package/dist/code-tokens.js.map +1 -0
- package/dist/context-menu.d.ts +59 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +69 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/features.d.ts +114 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/features.js +128 -0
- package/dist/features.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/nested.d.ts +66 -0
- package/dist/nested.d.ts.map +1 -0
- package/dist/nested.js +194 -0
- package/dist/nested.js.map +1 -0
- package/dist/ops.d.ts +120 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +333 -0
- package/dist/ops.js.map +1 -0
- package/dist/shortcuts.d.ts +90 -0
- package/dist/shortcuts.d.ts.map +1 -0
- package/dist/shortcuts.js +179 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/spine.d.ts +92 -0
- package/dist/spine.d.ts.map +1 -0
- package/dist/spine.js +213 -0
- package/dist/spine.js.map +1 -0
- package/dist/styles.d.ts +63 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +169 -0
- package/dist/styles.js.map +1 -0
- package/dist/tree.d.ts +70 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +190 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +239 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +47 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
- package/src/code-tokens.ts +236 -0
- package/src/context-menu.ts +139 -0
- package/src/features.ts +173 -0
- package/src/index.ts +58 -0
- package/src/nested.ts +271 -0
- package/src/ops.ts +341 -0
- package/src/shortcuts.ts +280 -0
- package/src/spine.ts +214 -0
- package/src/styles.ts +201 -0
- package/src/tree.ts +189 -0
- package/src/types.ts +275 -0
package/dist/tree.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { BODY } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the derived tree in a single O(n) pass.
|
|
4
|
+
*
|
|
5
|
+
* The rule that makes body text work: a level-0 block attaches to the nearest open
|
|
6
|
+
* heading but NEVER terminates a subtree. Only a heading whose level is <= an open
|
|
7
|
+
* heading's level closes it. This mirrors Word's outline semantics, where body text
|
|
8
|
+
* under "1.2" stays under "1.2" no matter how much of it there is.
|
|
9
|
+
*
|
|
10
|
+
* (The legacy `Document.getDirectChildren` had a bug here: it broke on `level <= own`
|
|
11
|
+
* without excluding body text, so a heading's direct children were truncated at the
|
|
12
|
+
* first paragraph of body text. That bug is not reproduced — see the regression test.)
|
|
13
|
+
*/
|
|
14
|
+
export function buildIndex(blocks) {
|
|
15
|
+
const n = blocks.length;
|
|
16
|
+
const parent = new Int32Array(n).fill(-1);
|
|
17
|
+
const subtreeEnd = new Int32Array(n);
|
|
18
|
+
const depth = new Int32Array(n);
|
|
19
|
+
// Stack of indices of currently-open headings, strictly increasing in level.
|
|
20
|
+
const open = [];
|
|
21
|
+
for (let i = 0; i < n; i++) {
|
|
22
|
+
const level = blocks[i].level;
|
|
23
|
+
if (level === BODY) {
|
|
24
|
+
// Body text: attaches to the enclosing heading, closes nothing.
|
|
25
|
+
const top = open.length > 0 ? open[open.length - 1] : -1;
|
|
26
|
+
parent[i] = top;
|
|
27
|
+
subtreeEnd[i] = i + 1;
|
|
28
|
+
depth[i] = top === -1 ? 0 : depth[top] + 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
// A heading closes every open heading at the same or deeper level.
|
|
32
|
+
while (open.length > 0 && blocks[open[open.length - 1]].level >= level) {
|
|
33
|
+
subtreeEnd[open.pop()] = i;
|
|
34
|
+
}
|
|
35
|
+
const top = open.length > 0 ? open[open.length - 1] : -1;
|
|
36
|
+
parent[i] = top;
|
|
37
|
+
depth[i] = top === -1 ? 0 : depth[top] + 1;
|
|
38
|
+
open.push(i);
|
|
39
|
+
}
|
|
40
|
+
// Headings still open at EOF extend to the end of the document.
|
|
41
|
+
while (open.length > 0)
|
|
42
|
+
subtreeEnd[open.pop()] = n;
|
|
43
|
+
return { parent, subtreeEnd, depth, length: n };
|
|
44
|
+
}
|
|
45
|
+
/** `[start, end)` covering `i` and everything beneath it. */
|
|
46
|
+
export function subtreeRange(index, i) {
|
|
47
|
+
return [i, index.subtreeEnd[i]];
|
|
48
|
+
}
|
|
49
|
+
/** Every descendant index of `i`, at any depth, in document order. */
|
|
50
|
+
export function deepChildren(index, i) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (let j = i + 1; j < index.subtreeEnd[i]; j++)
|
|
53
|
+
out.push(j);
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/** Heading children of `i` — one level down in the DERIVED tree, not by `level`. */
|
|
57
|
+
export function childHeadings(blocks, index, i) {
|
|
58
|
+
const out = [];
|
|
59
|
+
for (let j = i + 1; j < index.subtreeEnd[i]; j++) {
|
|
60
|
+
if (index.parent[j] === i && blocks[j].level !== BODY)
|
|
61
|
+
out.push(j);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
/** Body-text blocks belonging directly to `i`. */
|
|
66
|
+
export function bodyChildren(blocks, index, i) {
|
|
67
|
+
const out = [];
|
|
68
|
+
for (let j = i + 1; j < index.subtreeEnd[i]; j++) {
|
|
69
|
+
if (index.parent[j] === i && blocks[j].level === BODY)
|
|
70
|
+
out.push(j);
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
/** Chain of ancestors from nearest parent to root. */
|
|
75
|
+
export function ancestors(index, i) {
|
|
76
|
+
const out = [];
|
|
77
|
+
for (let p = index.parent[i]; p !== -1; p = index.parent[p])
|
|
78
|
+
out.push(p);
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether two block lists have the same STRUCTURE: the same blocks, at the same levels,
|
|
83
|
+
* folded and locked the same way. Text is not structure.
|
|
84
|
+
*
|
|
85
|
+
* Everything a view derives from the outline — the tree, the counts, the folds, the locks,
|
|
86
|
+
* the spine — depends on exactly these fields, and typing never changes one. A memo keyed
|
|
87
|
+
* on the LIST recomputes per character, because every edit makes a new list; keyed on this
|
|
88
|
+
* it recomputes when the outline actually moves. The `a === b` check is the fast path:
|
|
89
|
+
* structural ops share unchanged blocks by reference, and so does the editor's conversion,
|
|
90
|
+
* so for typing this is a pointer comparison per block.
|
|
91
|
+
*/
|
|
92
|
+
export function sameStructure(a, b) {
|
|
93
|
+
if (a === b)
|
|
94
|
+
return true;
|
|
95
|
+
if (a.length !== b.length)
|
|
96
|
+
return false;
|
|
97
|
+
for (let i = 0; i < a.length; i++) {
|
|
98
|
+
const x = a[i];
|
|
99
|
+
const y = b[i];
|
|
100
|
+
if (x === y)
|
|
101
|
+
continue;
|
|
102
|
+
if (x.id !== y.id || x.level !== y.level)
|
|
103
|
+
return false;
|
|
104
|
+
if ((x.collapsed === true) !== (y.collapsed === true))
|
|
105
|
+
return false;
|
|
106
|
+
if ((x.locked === true) !== (y.locked === true))
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
export function hasChildren(index, i) {
|
|
112
|
+
return index.subtreeEnd[i] > i + 1;
|
|
113
|
+
}
|
|
114
|
+
/** Index of the nearest preceding heading, or -1. Used by the indent rules. */
|
|
115
|
+
export function prevHeading(blocks, i) {
|
|
116
|
+
for (let j = i - 1; j >= 0; j--)
|
|
117
|
+
if (blocks[j].level !== BODY)
|
|
118
|
+
return j;
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Indices that should actually be rendered, honouring `collapsed`.
|
|
123
|
+
*
|
|
124
|
+
* This is the project's primary scale lever. ProseMirror puts the entire document
|
|
125
|
+
* in the DOM and cannot be virtualized, so the working set has to be small by
|
|
126
|
+
* construction — and an outline collapsed to level 2 renders hundreds of blocks
|
|
127
|
+
* rather than tens of thousands. A collapsed subtree must render as NOTHING, not
|
|
128
|
+
* as hidden DOM, or the lever does no work.
|
|
129
|
+
*/
|
|
130
|
+
export function visibleIndices(blocks, index) {
|
|
131
|
+
const out = [];
|
|
132
|
+
for (let i = 0; i < blocks.length;) {
|
|
133
|
+
out.push(i);
|
|
134
|
+
if (blocks[i].collapsed && index.subtreeEnd[i] > i + 1) {
|
|
135
|
+
i = index.subtreeEnd[i]; // skip the whole subtree
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
i++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
/** Convenience for callers that want blocks rather than indices. */
|
|
144
|
+
export function visibleBlocks(blocks, index) {
|
|
145
|
+
return visibleIndices(blocks, index).map((i) => blocks[i]);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Is `i` read-only — either locked itself, or inside a locked subtree?
|
|
149
|
+
*
|
|
150
|
+
* Walks ancestors rather than reading a stored flag, which is what keeps lock state
|
|
151
|
+
* correct for free when a block is moved, indented, or outdented: a block dragged out
|
|
152
|
+
* of a locked chapter stops being locked because its ancestry changed, with no
|
|
153
|
+
* bookkeeping pass to get wrong.
|
|
154
|
+
*/
|
|
155
|
+
export function isLocked(blocks, index, i) {
|
|
156
|
+
const block = blocks[i];
|
|
157
|
+
if (!block)
|
|
158
|
+
return false;
|
|
159
|
+
if (block.locked === true)
|
|
160
|
+
return true;
|
|
161
|
+
for (const ancestor of ancestors(index, i)) {
|
|
162
|
+
if (blocks[ancestor]?.locked === true)
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The nearest ancestor (or self) that carries the lock, or -1.
|
|
169
|
+
*
|
|
170
|
+
* The UI needs this to say WHAT is locked — "this chapter is read-only" is actionable,
|
|
171
|
+
* "this paragraph is read-only" leaves the reader hunting for the padlock.
|
|
172
|
+
*/
|
|
173
|
+
export function lockOwner(blocks, index, i) {
|
|
174
|
+
if (blocks[i]?.locked === true)
|
|
175
|
+
return i;
|
|
176
|
+
for (const ancestor of [...ancestors(index, i)].reverse()) {
|
|
177
|
+
if (blocks[ancestor]?.locked === true)
|
|
178
|
+
return ancestor;
|
|
179
|
+
}
|
|
180
|
+
return -1;
|
|
181
|
+
}
|
|
182
|
+
/** Indices of every read-only block, for bulk checks like a paste guard. */
|
|
183
|
+
export function lockedIndices(blocks, index) {
|
|
184
|
+
const out = [];
|
|
185
|
+
for (let i = 0; i < blocks.length; i++)
|
|
186
|
+
if (isLocked(blocks, index, i))
|
|
187
|
+
out.push(i);
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=tree.js.map
|
package/dist/tree.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical outline model: a FLAT list of blocks, each carrying an explicit
|
|
3
|
+
* outline level. The tree is DERIVED (see tree.ts), never stored.
|
|
4
|
+
*
|
|
5
|
+
* Why flat: Microsoft Word is flat (`w:outlineLvl` per paragraph) and Markdown is
|
|
6
|
+
* flat (`#`..`######`). Critically, real Word documents skip levels (an H1 followed
|
|
7
|
+
* by an H3) all the time — a nested schema cannot represent that and rejects the
|
|
8
|
+
* document on import. A flat model imports it and normalizes on demand.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* `0` is body text and is NOT a hierarchy level — body text belongs to the nearest
|
|
12
|
+
* preceding heading. `1`-`9` are outline levels.
|
|
13
|
+
*
|
|
14
|
+
* Note the off-by-one against OOXML: Word's `w:outlineLvl` is 0-indexed (0-8),
|
|
15
|
+
* so `outlineLvl + 1 === OutlineLevel` for headings. Getting this wrong silently
|
|
16
|
+
* corrupts every imported document, so the conversion lives in exactly one place
|
|
17
|
+
* (see @tarhnama/docx) and is tested.
|
|
18
|
+
*/
|
|
19
|
+
export type OutlineLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
|
20
|
+
/** Body text: belongs to the nearest preceding heading, terminates no subtree. */
|
|
21
|
+
export declare const BODY: 0;
|
|
22
|
+
/** The deepest addressable outline level, matching Word's Heading 1-9. */
|
|
23
|
+
export declare const MAX_LEVEL: 9;
|
|
24
|
+
/**
|
|
25
|
+
* Per-block text direction. Persian-first: `rtl` is the default. `auto` defers to
|
|
26
|
+
* first-strong-character detection.
|
|
27
|
+
*
|
|
28
|
+
* This is a per-block attribute rather than a CSS concern because Word stores
|
|
29
|
+
* direction per paragraph (`w:bidi`), so a per-block attribute round-trips 1:1.
|
|
30
|
+
*/
|
|
31
|
+
export type Direction = 'rtl' | 'ltr' | 'auto';
|
|
32
|
+
/**
|
|
33
|
+
* A single block. `content` is deliberately opaque: the core never interprets
|
|
34
|
+
* inline content, which keeps this package free of any editor dependency and
|
|
35
|
+
* lets the same tree algorithms serve the ProseMirror layer, the .docx importer,
|
|
36
|
+
* and any future engine.
|
|
37
|
+
*/
|
|
38
|
+
export interface Block<C = unknown> {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly level: OutlineLevel;
|
|
41
|
+
readonly type: string;
|
|
42
|
+
readonly dir: Direction;
|
|
43
|
+
readonly collapsed: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Read-only. A locked block's content cannot be edited and its position in the tree
|
|
46
|
+
* cannot change.
|
|
47
|
+
*
|
|
48
|
+
* Set only on the block the user actually locked — locking a heading locks its whole
|
|
49
|
+
* SUBTREE, but that is DERIVED (`isLocked`) rather than written onto every descendant.
|
|
50
|
+
* Storing it per-block would make lock state drift the moment a block moves, and would
|
|
51
|
+
* turn "lock this chapter" into an edit of every paragraph inside it.
|
|
52
|
+
*
|
|
53
|
+
* Collapse is deliberately still allowed on a locked subtree: collapsing is a view
|
|
54
|
+
* operation, not an edit, and a reader must be able to fold a section they cannot change.
|
|
55
|
+
*/
|
|
56
|
+
readonly locked?: boolean;
|
|
57
|
+
/** Paragraph-level formatting (alignment, spacing, indent). See `BlockFormat`. */
|
|
58
|
+
readonly format?: BlockFormat;
|
|
59
|
+
/**
|
|
60
|
+
* The named style this block references (`w:pStyle`).
|
|
61
|
+
*
|
|
62
|
+
* Direct formatting in `format` OVERRIDES the style, exactly as in Word. A block with
|
|
63
|
+
* neither is the document's default style.
|
|
64
|
+
*/
|
|
65
|
+
readonly styleId?: string;
|
|
66
|
+
readonly content?: C;
|
|
67
|
+
/**
|
|
68
|
+
* Per-type properties the core deliberately does NOT interpret: a code block's
|
|
69
|
+
* language, a list item's marker and depth, a blockquote's nesting. Word and Markdown
|
|
70
|
+
* both carry these, and without somewhere to put them an importer has to either drop
|
|
71
|
+
* them or smuggle them into `type`, which is worse.
|
|
72
|
+
*
|
|
73
|
+
* Opaque here for the same reason `content` is — core stays free of any format's
|
|
74
|
+
* vocabulary, and the tree algorithms never look at it.
|
|
75
|
+
*/
|
|
76
|
+
readonly attrs?: Readonly<Record<string, unknown>>;
|
|
77
|
+
}
|
|
78
|
+
/** A flat document. */
|
|
79
|
+
export type Blocks<C = unknown> = readonly Block<C>[];
|
|
80
|
+
/**
|
|
81
|
+
* The derived tree, computed in one O(n) pass over the flat list.
|
|
82
|
+
*
|
|
83
|
+
* Every array is indexed by block position. Recomputing this on each transaction
|
|
84
|
+
* is cheap and keeps the flat list the single source of truth — no tree state to
|
|
85
|
+
* fall out of sync.
|
|
86
|
+
*/
|
|
87
|
+
export interface TreeIndex {
|
|
88
|
+
/** Index of the governing heading, or -1 for a top-level block. */
|
|
89
|
+
readonly parent: Int32Array;
|
|
90
|
+
/** Exclusive end index of this block's subtree. For body text, always `i + 1`. */
|
|
91
|
+
readonly subtreeEnd: Int32Array;
|
|
92
|
+
/** Depth in the derived tree. Differs from `level` when levels skip. */
|
|
93
|
+
readonly depth: Int32Array;
|
|
94
|
+
/** Number of blocks the index was built from. */
|
|
95
|
+
readonly length: number;
|
|
96
|
+
}
|
|
97
|
+
export declare function isHeading(block: Block): boolean;
|
|
98
|
+
export declare function isBody(block: Block): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Paragraph-level formatting — what Word keeps in `w:pPr`.
|
|
101
|
+
*
|
|
102
|
+
* Separate from `attrs` because it is universal: every block can carry it, every exporter
|
|
103
|
+
* needs it, and giving it a type means a typo in one package is a compile error rather
|
|
104
|
+
* than a silently missing indent.
|
|
105
|
+
*
|
|
106
|
+
* **Units are twips (1/20 of a point), matching Word exactly.** The same reasoning as
|
|
107
|
+
* half-points for font size: Word stores `w:spacing`/`w:ind` in twips, so storing anything
|
|
108
|
+
* else means rounding on every round trip, and rounding accumulates. Helpers convert for
|
|
109
|
+
* display.
|
|
110
|
+
*/
|
|
111
|
+
export interface BlockFormat {
|
|
112
|
+
/**
|
|
113
|
+
* LOGICAL alignment, not physical.
|
|
114
|
+
*
|
|
115
|
+
* `start`/`end` rather than `left`/`right` for the same reason the CSS is written with
|
|
116
|
+
* logical properties: in a Persian document `start` is the right-hand edge, and a
|
|
117
|
+
* model that stored `left` would mirror wrongly the moment direction changed.
|
|
118
|
+
*/
|
|
119
|
+
readonly align?: 'start' | 'end' | 'center' | 'justify';
|
|
120
|
+
/** Line spacing as a multiple: 1 single, 1.5, 2 double. */
|
|
121
|
+
readonly lineHeight?: number;
|
|
122
|
+
readonly spaceBeforeTwips?: number;
|
|
123
|
+
readonly spaceAfterTwips?: number;
|
|
124
|
+
/** Indent from the start edge — the right in RTL. */
|
|
125
|
+
readonly indentStartTwips?: number;
|
|
126
|
+
readonly indentEndTwips?: number;
|
|
127
|
+
/** First-line indent. NEGATIVE means a hanging indent, as in Word. */
|
|
128
|
+
readonly firstLineTwips?: number;
|
|
129
|
+
/** Keep with the following paragraph when paginating. */
|
|
130
|
+
readonly keepNext?: boolean;
|
|
131
|
+
/** Do not split this paragraph across pages. */
|
|
132
|
+
readonly keepLines?: boolean;
|
|
133
|
+
readonly pageBreakBefore?: boolean;
|
|
134
|
+
/** Paragraph shading as `#RRGGBB`. */
|
|
135
|
+
readonly shading?: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* A named paragraph style.
|
|
139
|
+
*
|
|
140
|
+
* Word documents are built out of these: a paragraph carries a style reference plus
|
|
141
|
+
* whatever direct formatting overrides it. Resolving styles down to direct formatting on
|
|
142
|
+
* import — which is what this project did until now — renders correctly and then loses
|
|
143
|
+
* the whole structure on the way back out. Word shows the result as "Normal + formatting"
|
|
144
|
+
* on every paragraph, the styles pane is empty, and the author's ability to restyle the
|
|
145
|
+
* document in one action is gone. The style name is content, not presentation.
|
|
146
|
+
*
|
|
147
|
+
* Kept in `core` rather than `docx` because Markdown and the editor both need to round-trip
|
|
148
|
+
* the reference even though neither interprets it.
|
|
149
|
+
*/
|
|
150
|
+
export interface NamedStyle {
|
|
151
|
+
/** `w:styleId` — the stable key a paragraph references. */
|
|
152
|
+
readonly id: string;
|
|
153
|
+
/** `w:name` — what the user sees in Word's styles pane. */
|
|
154
|
+
readonly name: string;
|
|
155
|
+
/**
|
|
156
|
+
* `w:basedOn`. Resolution walks this chain, so a cycle must be broken by the resolver
|
|
157
|
+
* rather than trusted not to exist — real documents contain them.
|
|
158
|
+
*/
|
|
159
|
+
readonly basedOn?: string;
|
|
160
|
+
/** The outline level this style implies (`w:outlineLvl` + 1). */
|
|
161
|
+
readonly outlineLevel?: OutlineLevel;
|
|
162
|
+
readonly format?: BlockFormat;
|
|
163
|
+
/** Run-level defaults the style carries. Half-points, as Word stores them. */
|
|
164
|
+
readonly font?: string;
|
|
165
|
+
readonly sizeHalfPt?: number;
|
|
166
|
+
readonly bold?: boolean;
|
|
167
|
+
readonly italic?: boolean;
|
|
168
|
+
readonly color?: string;
|
|
169
|
+
/** True for Word's own styles (Normal, Heading 1–9), which must not be renamed. */
|
|
170
|
+
readonly builtIn?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Page setup — Word's `w:sectPr`.
|
|
174
|
+
*
|
|
175
|
+
* Margins are LOGICAL (`start`/`end`), not `left`/`right`, for the same reason the rest of
|
|
176
|
+
* the model is: in an RTL document the binding edge is the right one, and a model storing
|
|
177
|
+
* `left` mirrors wrongly the instant direction changes. The conversion to Word's physical
|
|
178
|
+
* `w:left`/`w:right` happens once, in the exporter, where the section's direction is known.
|
|
179
|
+
*/
|
|
180
|
+
export interface PageSetup {
|
|
181
|
+
readonly widthTwips?: number;
|
|
182
|
+
readonly heightTwips?: number;
|
|
183
|
+
readonly marginTopTwips?: number;
|
|
184
|
+
readonly marginBottomTwips?: number;
|
|
185
|
+
readonly marginStartTwips?: number;
|
|
186
|
+
readonly marginEndTwips?: number;
|
|
187
|
+
/** `w:gutter` — extra space on the binding edge. */
|
|
188
|
+
readonly gutterTwips?: number;
|
|
189
|
+
/** `w:mirrorMargins` — swap start/end on facing pages, for double-sided printing. */
|
|
190
|
+
readonly mirrorMargins?: boolean;
|
|
191
|
+
/** `w:bidi` on the section: columns and margins run right-to-left. */
|
|
192
|
+
readonly rtl?: boolean;
|
|
193
|
+
readonly landscape?: boolean;
|
|
194
|
+
}
|
|
195
|
+
/** A4 in twips. Word's default for most of the world, and the one Persian documents use. */
|
|
196
|
+
export declare const A4_WIDTH_TWIPS = 11906;
|
|
197
|
+
export declare const A4_HEIGHT_TWIPS = 16838;
|
|
198
|
+
/** Word's default margin: one inch. */
|
|
199
|
+
export declare const DEFAULT_MARGIN_TWIPS = 1440;
|
|
200
|
+
/** A4, RTL, one-inch margins — the sane default for a Persian document. */
|
|
201
|
+
export declare const PERSIAN_A4: PageSetup;
|
|
202
|
+
/** 1 point = 20 twips. Word's unit throughout `w:pPr`. */
|
|
203
|
+
export declare const TWIPS_PER_POINT = 20;
|
|
204
|
+
export declare function pointsToTwips(points: number): number;
|
|
205
|
+
export declare function twipsToPoints(twips: number): number;
|
|
206
|
+
/** Twips to a CSS length, for rendering. */
|
|
207
|
+
export declare function twipsToCss(twips: number): string;
|
|
208
|
+
/**
|
|
209
|
+
* A document: blocks plus the identity that links point at.
|
|
210
|
+
*
|
|
211
|
+
* First-class in the model rather than a concept each application reinvents. A link
|
|
212
|
+
* targets `docId`, the search index is keyed by it, and persistence stores it — so a
|
|
213
|
+
* "document" that only existed as an application's own interface meant every consumer
|
|
214
|
+
* had to agree on its shape by convention.
|
|
215
|
+
*/
|
|
216
|
+
export interface OutlineDocumentOf<C = unknown> {
|
|
217
|
+
readonly id: string;
|
|
218
|
+
readonly title: string;
|
|
219
|
+
readonly blocks: Blocks<C>;
|
|
220
|
+
/** Epoch millis of the last change, when the host tracks it. */
|
|
221
|
+
readonly updatedAt?: number;
|
|
222
|
+
/**
|
|
223
|
+
* Default direction for blocks that do not state one, and for empty blocks where
|
|
224
|
+
* first-strong detection has nothing to work with.
|
|
225
|
+
*/
|
|
226
|
+
readonly dir?: Direction;
|
|
227
|
+
/**
|
|
228
|
+
* The document's style table. Blocks reference entries by `styleId`.
|
|
229
|
+
*
|
|
230
|
+
* On the document rather than global because two documents in one workspace legitimately
|
|
231
|
+
* carry different style definitions — they came from different Word files.
|
|
232
|
+
*/
|
|
233
|
+
readonly styles?: readonly NamedStyle[];
|
|
234
|
+
/** Page geometry, for `.docx` export and print. */
|
|
235
|
+
readonly page?: PageSetup;
|
|
236
|
+
/** Host-defined metadata: tags, author, source path. Never interpreted here. */
|
|
237
|
+
readonly meta?: Readonly<Record<string, unknown>>;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical outline model: a FLAT list of blocks, each carrying an explicit
|
|
3
|
+
* outline level. The tree is DERIVED (see tree.ts), never stored.
|
|
4
|
+
*
|
|
5
|
+
* Why flat: Microsoft Word is flat (`w:outlineLvl` per paragraph) and Markdown is
|
|
6
|
+
* flat (`#`..`######`). Critically, real Word documents skip levels (an H1 followed
|
|
7
|
+
* by an H3) all the time — a nested schema cannot represent that and rejects the
|
|
8
|
+
* document on import. A flat model imports it and normalizes on demand.
|
|
9
|
+
*/
|
|
10
|
+
/** Body text: belongs to the nearest preceding heading, terminates no subtree. */
|
|
11
|
+
export const BODY = 0;
|
|
12
|
+
/** The deepest addressable outline level, matching Word's Heading 1-9. */
|
|
13
|
+
export const MAX_LEVEL = 9;
|
|
14
|
+
export function isHeading(block) {
|
|
15
|
+
return block.level >= 1;
|
|
16
|
+
}
|
|
17
|
+
export function isBody(block) {
|
|
18
|
+
return block.level === BODY;
|
|
19
|
+
}
|
|
20
|
+
/** A4 in twips. Word's default for most of the world, and the one Persian documents use. */
|
|
21
|
+
export const A4_WIDTH_TWIPS = 11906;
|
|
22
|
+
export const A4_HEIGHT_TWIPS = 16838;
|
|
23
|
+
/** Word's default margin: one inch. */
|
|
24
|
+
export const DEFAULT_MARGIN_TWIPS = 1440;
|
|
25
|
+
/** A4, RTL, one-inch margins — the sane default for a Persian document. */
|
|
26
|
+
export const PERSIAN_A4 = {
|
|
27
|
+
widthTwips: A4_WIDTH_TWIPS,
|
|
28
|
+
heightTwips: A4_HEIGHT_TWIPS,
|
|
29
|
+
marginTopTwips: DEFAULT_MARGIN_TWIPS,
|
|
30
|
+
marginBottomTwips: DEFAULT_MARGIN_TWIPS,
|
|
31
|
+
marginStartTwips: DEFAULT_MARGIN_TWIPS,
|
|
32
|
+
marginEndTwips: DEFAULT_MARGIN_TWIPS,
|
|
33
|
+
rtl: true,
|
|
34
|
+
};
|
|
35
|
+
/** 1 point = 20 twips. Word's unit throughout `w:pPr`. */
|
|
36
|
+
export const TWIPS_PER_POINT = 20;
|
|
37
|
+
export function pointsToTwips(points) {
|
|
38
|
+
return Math.round(points * TWIPS_PER_POINT);
|
|
39
|
+
}
|
|
40
|
+
export function twipsToPoints(twips) {
|
|
41
|
+
return twips / TWIPS_PER_POINT;
|
|
42
|
+
}
|
|
43
|
+
/** Twips to a CSS length, for rendering. */
|
|
44
|
+
export function twipsToCss(twips) {
|
|
45
|
+
return `${twipsToPoints(twips)}pt`;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,kFAAkF;AAClF,MAAM,CAAC,MAAM,IAAI,GAAG,CAAU,CAAC;AAE/B,0EAA0E;AAC1E,MAAM,CAAC,MAAM,SAAS,GAAG,CAAU,CAAC;AA+EpC,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,KAAY;IACjC,OAAO,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;AAC9B,CAAC;AAqGD,4FAA4F;AAC5F,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AACpC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,uCAAuC;AACvC,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAEzC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,UAAU,GAAc;IACnC,UAAU,EAAE,cAAc;IAC1B,WAAW,EAAE,eAAe;IAC5B,cAAc,EAAE,oBAAoB;IACpC,iBAAiB,EAAE,oBAAoB;IACvC,gBAAgB,EAAE,oBAAoB;IACtC,cAAc,EAAE,oBAAoB;IACpC,GAAG,EAAE,IAAI;CACV,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAElC,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,GAAG,eAAe,CAAC;AACjC,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;AACrC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tarhnama/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Framework-agnostic outline document model: flat blocks with outline levels, plus a derived tree index. No DOM, no editor dependency.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/mahdi/tarhnama.git",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/mahdi/tarhnama#readme",
|
|
12
|
+
"bugs": "https://github.com/mahdi/tarhnama/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"outline",
|
|
15
|
+
"editor",
|
|
16
|
+
"rtl",
|
|
17
|
+
"persian",
|
|
18
|
+
"prosemirror",
|
|
19
|
+
"docx",
|
|
20
|
+
"markdown"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"src",
|
|
36
|
+
"!src/**/*.test.ts",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=20"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.build.json",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:watch": "vitest",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|