rapier-markdown-kit 1.1.102 → 1.1.104
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 +2 -2
- package/README.md +213 -53
- package/dist/agent/vendor/hyphen-en-us/LICENSE +14 -0
- package/dist/agent/vendor/hyphen-en-us/SOURCE.json +33 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.hyp.txt +14 -0
- package/dist/agent/vendor/hyphen-en-us/hyph-en-us.pat.txt +4938 -0
- package/dist/agent/vendor/hyphen-en-us/patterns.js +25 -0
- package/dist/agent/vendor/pretext/LICENSE +208 -0
- package/dist/agent/vendor/pretext/NOTICE +26 -13
- package/dist/agent/vendor/pretext/SOURCE.json +213 -45
- package/dist/agent/vendor/pretext/analysis.js +675 -1224
- package/dist/agent/vendor/pretext/entry-geometry.js +183 -0
- package/dist/agent/vendor/pretext/gecko-line-breaks.js +688 -0
- package/dist/agent/vendor/pretext/generated/engine-break-data.js +57 -0
- package/dist/agent/vendor/pretext/generated/webkit-generic-families.js +80 -0
- package/dist/agent/vendor/pretext/graphemes.js +98 -0
- package/dist/agent/vendor/pretext/han-kerning.js +253 -0
- package/dist/agent/vendor/pretext/layout.js +352 -290
- package/dist/agent/vendor/pretext/line-break.js +1154 -588
- package/dist/agent/vendor/pretext/line-breaks.js +892 -0
- package/dist/agent/vendor/pretext/line-text.js +81 -39
- package/dist/agent/vendor/pretext/measurement.js +1105 -176
- package/dist/agent/vendor/pretext/prepare.js +807 -0
- package/dist/agent/vendor/pretext/rich-inline.js +1242 -273
- package/dist/agent/will.mjs +2 -0
- package/dist/kit/assets.mjs +5 -1
- package/dist/kit/conformance/run.mjs +4 -4
- package/dist/kit/export-fonts.mjs +26 -11
- package/dist/kit/index.mjs +1 -0
- package/dist/kit/ledger/carried.mjs +9 -7
- package/dist/kit/ledger/data.mjs +73 -13
- package/dist/kit/ledger/format.mjs +166 -53
- package/dist/kit/ledger/hash.mjs +75 -18
- package/dist/kit/ledger/history.mjs +143 -115
- package/dist/kit/ledger/inverse-source.mjs +158 -19
- package/dist/kit/ledger/journal-records.mjs +292 -67
- package/dist/kit/model.mjs +1 -1
- package/dist/kit/pdf-glyphs.mjs +4 -4
- package/dist/kit/render-markdown.mjs +259 -122
- package/dist/kit/render-sanitize.mjs +24 -4
- package/dist/kit/render-work.mjs +99 -20
- package/dist/kit/render.mjs +101 -65
- package/dist/kit/typography.mjs +2 -0
- package/dist/layout/hyphenation.mjs +127 -0
- package/dist/layout/line-plan.mjs +88 -96
- package/dist/layout/model.mjs +61 -80
- package/dist/layout/paragraph-fit.mjs +191 -0
- package/dist/layout/preparation.mjs +373 -0
- package/dist/layout/prepared-paragraph.mjs +223 -0
- package/dist/layout/typography.mjs +345 -111
- package/dist/packages/rapier-diff/index.mjs +288 -196
- package/dist/spec/document-fonts.mjs +13 -4
- package/dist/spec/md-assets.mjs +149 -30
- package/dist/spec/md-layout.mjs +5 -2
- package/dist/spec/md-marks.mjs +218 -3
- package/dist/spec/md-source.mjs +122 -0
- package/package.json +2 -1
- package/style.css +9 -0
- package/dist/agent/vendor/pretext/bidi.js +0 -151
- package/dist/agent/vendor/pretext/generated/bidi-data.js +0 -3831
package/LICENSE
CHANGED
|
@@ -21,8 +21,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
21
21
|
SOFTWARE.
|
|
22
22
|
|
|
23
23
|
Files under this licence carry `SPDX-License-Identifier: MIT` in their first lines: the standard's
|
|
24
|
-
grammar, marks and reference style (`spec/md-layout.mjs`, `spec/md-marks.mjs`, `spec/flowchart.mjs`, `spec/markdown-style.css`), the layout model and line planner
|
|
25
|
-
(`layout/model.mjs`, `layout/line-plan.mjs`, `layout/typography.mjs`),
|
|
24
|
+
grammar, marks and reference style (`spec/md-layout.mjs`, `spec/md-marks.mjs`, `spec/md-source.mjs`, `spec/flowchart.mjs`, `spec/markdown-style.css`), the layout model and line planner
|
|
25
|
+
(`layout/model.mjs`, `layout/line-plan.mjs`, `layout/typography.mjs`, `layout/preparation.mjs`),
|
|
26
26
|
the portable HTML and document metadata helpers (`spec/html-blocks.mjs`, `spec/frontmatter.mjs`,
|
|
27
27
|
`spec/document-settings.mjs`, `spec/document-fonts.mjs`), the Will grammar (`agent/will.mjs`), the picture appendix reader and writer
|
|
28
28
|
(`spec/md-assets.mjs`), the two shared-page reference readers (`tools/read-shared-page.mjs`,
|
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# rapier-markdown-kit
|
|
2
2
|
|
|
3
3
|
Read, render and write Self-contained Markdown in browsers and Node: one `.md` file with pictures, editable SVG
|
|
4
|
-
drawings, layout and
|
|
4
|
+
drawings, layout and precise inline typography. Build portable documents for people and agents. Will/1 regions mark what an agent
|
|
5
5
|
may edit, append to or preserve. MIT, no dependencies.
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
- Typography uses ordinary inline HTML spans with validated size, colour and family. Comments and references
|
|
8
|
+
carry other optional facts; each reader chooses its HTML, style, extension and resource support.
|
|
9
9
|
- One stylesheet renders the document as the editor and its exported page do.
|
|
10
10
|
- The line planner flows text around a picture's real shape; a conformance suite of thirteen documents runs
|
|
11
11
|
any implementation against it.
|
|
@@ -26,7 +26,7 @@ npm install rapier-markdown-kit
|
|
|
26
26
|
|
|
27
27
|
```js
|
|
28
28
|
import {parseLayout} from 'rapier-markdown-kit/layout'; // the md-layout comment a picture carries
|
|
29
|
-
import {
|
|
29
|
+
import {typography, formatPageBreak} from 'rapier-markdown-kit/marks'; // inline typography and page breaks
|
|
30
30
|
import {flowLines} from 'rapier-markdown-kit/model'; // the line planner: text around pictures
|
|
31
31
|
import {parseWill} from 'rapier-markdown-kit/will'; // Will/1 markers: keep, append, edit
|
|
32
32
|
import {parseAssets} from 'rapier-markdown-kit/assets'; // the picture appendix
|
|
@@ -119,17 +119,139 @@ family name share the host's font namespace. Print retains its existing factory
|
|
|
119
119
|
| Import | What it is |
|
|
120
120
|
| --- | --- |
|
|
121
121
|
| `rapier-markdown-kit/layout` | The `md-layout:v1` comment a picture carries: parse it, validate it, write it back. |
|
|
122
|
-
| `rapier-markdown-kit/marks` |
|
|
122
|
+
| `rapier-markdown-kit/marks` | Unified typography values, span writer and parser installer; preserved colour/font comments, ink and page breaks. |
|
|
123
123
|
| `rapier-markdown-kit/model` | Occupancy profiles and the line planner: the wrapping itself. |
|
|
124
|
+
| `rapier-markdown-kit/typography` | Source-preserving paragraph refinement through `createTypography()`. |
|
|
124
125
|
| `rapier-markdown-kit/will` | The Will/1 grammar (a separate, optional standard): the markers around an agent's intent regions. |
|
|
125
126
|
| `rapier-markdown-kit/assets` | The picture appendix: the reference definitions a document's pictures live in. It never decodes a picture. |
|
|
126
127
|
| `rapier-markdown-kit/style.css` | The reference style: type, lists, tables, tasks, pictures and the document's other markup, scoped to `.md-render`. |
|
|
127
128
|
| `rapier-markdown-kit/rapier-ledger` | The MIT edit-ledger format, replay, authorship projection and offline merge. |
|
|
128
129
|
| `rapier-markdown-kit/ledger/carried` | Checked optional parts for pages and saved Markdown. |
|
|
129
|
-
| `rapier-markdown-kit` | Named exports from the layout, marks, model, Will, assets and render modules, plus the `ledger` namespace. |
|
|
130
|
+
| `rapier-markdown-kit` | Named exports from the layout, marks, model, typography, Will, assets and render modules, plus the `ledger` namespace. |
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
The canonical inline form is ordinary HTML inside Markdown. CSS support varies; the host's font metrics still
|
|
133
|
+
determine line layout (below).
|
|
134
|
+
|
|
135
|
+
## Refined paragraphs
|
|
136
|
+
|
|
137
|
+
The existing comment expresses the paragraph's intent without storing font-dependent line breaks:
|
|
138
|
+
|
|
139
|
+
```md
|
|
140
|
+
Words stay in their original source. <!--md-layout:v1 align=justify hyphens=auto hanging=on-->
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`align=justify` alone keeps native justification. With `hyphens=auto`, the browser adapter chooses a paragraph-wide
|
|
144
|
+
plan using the same pinned Pretext analysis, shaping and actual-font authority as picture wrapping. It prefers
|
|
145
|
+
whole words, bounds ordinary spaces to 60–180% of their natural advance, permits at most two consecutive
|
|
146
|
+
discretionary endings, and starts the final line with a whole word. A short final line costs more; the final line
|
|
147
|
+
is never stretched. Authored compound hyphens are ordinary break opportunities, distinct from discretionary ones.
|
|
148
|
+
In very narrow measures, bounded spaces can leave some ragged edges. There is no paragraph-length switch.
|
|
149
|
+
|
|
150
|
+
Automatic cuts keep at least three graphemes on each side, with at most one automatic split per word. ASCII words
|
|
151
|
+
under `en` and `en-US` use the included Kuiken/Plain TeX pattern data and exceptions. Other English regions,
|
|
152
|
+
non-ASCII words and other admitted languages ask the browser's offline hyphenator for legal positions. That path
|
|
153
|
+
requires native `hyphenate-limit-chars` support; otherwise the paragraph stays native. Available dictionaries and
|
|
154
|
+
their divisions depend on the host. The included American patterns are a deliberate alternative to native data,
|
|
155
|
+
not a promise of identical opportunities in every browser. No language or font data is downloaded.
|
|
156
|
+
|
|
157
|
+
The projection displays a hyphen-minus from the affected text face, measured by Pretext as part of the whole
|
|
158
|
+
prefix. It never adds a source hyphen. Explicit authored `hyphenate-character` stays native. With `hanging=on`,
|
|
159
|
+
measured punctuation extends only into available unclipped margins, by at most half an em. Refinement adds no
|
|
160
|
+
letter tracking; authored supported letter spacing remains part of its shaping contract.
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
import {createTypography} from 'rapier-markdown-kit/typography';
|
|
164
|
+
|
|
165
|
+
const refinement = createTypography();
|
|
166
|
+
await document.fonts.ready;
|
|
167
|
+
function update() {
|
|
168
|
+
if (refinement.apply(root).pending) requestAnimationFrame(update);
|
|
169
|
+
}
|
|
170
|
+
update();
|
|
171
|
+
for (const event of ['copy', 'cut']) document.addEventListener(event, () => {
|
|
172
|
+
if (refinement.clearSelection(root)) requestAnimationFrame(update);
|
|
173
|
+
}, true);
|
|
174
|
+
// On a width change, call update() again. Source/style/font changes are revalidated.
|
|
175
|
+
// Before native editing or consuming this disposable DOM projection:
|
|
176
|
+
refinement.clear(root);
|
|
177
|
+
// When retiring the root:
|
|
178
|
+
refinement.retire(root);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`apply()` works on visible paragraphs and yields at completed preparation phases or word batches after an 8 ms
|
|
182
|
+
allowance. A single native shaping call can exceed that allowance; it is not a hard execution deadline. Pending
|
|
183
|
+
paragraphs remain native and readable. Each continuation revalidates source, style and font authority, and chooses
|
|
184
|
+
lines at the current width only after all required metrics finish. `{all:true}` performs the same complete work
|
|
185
|
+
synchronously for explicit capture or a print host with an established content width. Width changes reuse current measured geometry, and unchanged break
|
|
186
|
+
topology reuses projection nodes. Bind font loading, completion and failure to `invalidateFonts(document)` and
|
|
187
|
+
schedule `apply()`; a changed font generation removes stale projections before new preparation.
|
|
188
|
+
|
|
189
|
+
The adapter retains original text, semantic elements and listeners, backward selections, hard breaks, protected
|
|
190
|
+
code/nowrap atoms, NBSP, SHY and Unicode source coordinates. `clearSelection()` restores selected inline trees
|
|
191
|
+
before native clipboard capture; schedule refinement afterward as above. The editor and complete exported pages
|
|
192
|
+
bind this lifecycle themselves. Active editing/composition stays native. Unsupported
|
|
193
|
+
scripts, direction, shaping controls, initials and picture-flow paragraphs also stay native. The current adapter
|
|
194
|
+
admits horizontal LTR Latin, Greek, Cyrillic and common/inherited characters on Chrome/Chromium; native font
|
|
195
|
+
coverage and language support still apply. A font-family name is never a substitute for a loaded actual face.
|
|
196
|
+
|
|
197
|
+
Complete exported pages carry the same single module graph, CSP nonce, offline language data and font lifecycle.
|
|
198
|
+
Their readiness promise completes after the visible refinement queue; scrolling refines newly visible paragraphs.
|
|
199
|
+
Before print, an authored paper size supplies the fixed content width and all paragraphs finish synchronously.
|
|
200
|
+
Automatic-paper browser printing clears the projection and uses native CSS: `beforeprint` may still report the
|
|
201
|
+
screen viewport rather than the selected paper. Scoped fragments and `scripts:false` output also retain native CSS. The American data's separate permissive notice and exact provenance accompany the kit;
|
|
202
|
+
Pretext retains its own complete notices. These vendor notices are not replaced by the kit's MIT grant.
|
|
203
|
+
|
|
204
|
+
## One inline typography form
|
|
205
|
+
|
|
206
|
+
```md
|
|
207
|
+
Plain prose needs no typography markup.
|
|
208
|
+
|
|
209
|
+
A <span style="font-size:13.5pt;color:#175dc4">precise **phrase**</span>.
|
|
210
|
+
|
|
211
|
+
## <span style="font-size:9.25pt;font-family:serif">Still a semantic H2</span>
|
|
212
|
+
|
|
213
|
+
<span style="font-size:18px;color:#175dc4;font-family:"Coastal Text"">An offline custom run</span>
|
|
214
|
+
|
|
215
|
+
[font:Coastal Text]: data:font/woff2;base64,<font-bytes> '{"family":"Coastal Text","sourceId":"f0123456789abcdef01234567"}'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The font bytes and identity in that last example are placeholders; a host derives identity from admitted bytes.
|
|
219
|
+
A family name alone is not a portable font. Default prose needs no font reference. Custom faces keep the existing
|
|
220
|
+
font-data authority, including a name that collides with a factory face.
|
|
221
|
+
|
|
222
|
+
`typography.normalize({size, color, family})` validates a style. `typography.wrap(style, inlineMarkdown)` writes one
|
|
223
|
+
inline span; split block selections and keep their `#`, list markers and separators outside. `typography.parseStyle`
|
|
224
|
+
returns only admitted facts. `typography.install(md)` installs that interpretation on the caller's markdown-it
|
|
225
|
+
parser, and `typographySourceRanges(source, md)` reports original UTF-16 wrapper ranges through that parser.
|
|
226
|
+
These calls neither mutate the source nor load resources. The installer also reads already-authored colour and
|
|
227
|
+
font comments into the same facts; an ordinary open/save must preserve their bytes, not rewrite them as spans.
|
|
228
|
+
|
|
229
|
+
Sizes accept positive decimal `pt`/`px`, at most 12 fractional digits, up to 1638pt/2184px; 96px = 72pt. New values
|
|
230
|
+
use lowercase units and omit insignificant zeros. Colours become lowercase six-digit RGB hex; opaque integer
|
|
231
|
+
RGB CSSOM values are also read. Families are one validated name, an unquoted CSS generic, or an existing preset
|
|
232
|
+
stack. `sans`, `serif`, `mono`, `system`, `hand` are reserved choice aliases, not quoted custom identities. Styles
|
|
233
|
+
are bounded to 4096 characters, 32 declarations and 64 paired levels. Invalid declarations and unknown properties
|
|
234
|
+
are ignored; invalid/unclosed style strings admit no facts. Inner spans override individual properties. An editor
|
|
235
|
+
clearing a selection removes that property's overrides and preserves the surrounding words' styles.
|
|
236
|
+
|
|
237
|
+
Keep each opener with its first words and each closer with its last words. Soft/hard breaks may stay inside one paragraph; blank lines cannot. An opener alone on a line can become a raw HTML block.
|
|
238
|
+
The old leading colour comment has the same portability fault: it can suppress Markdown parsing or disappear
|
|
239
|
+
with its whole block in a non-HTML conversion. With inline HTML enabled, the new form preserves words, emphasis,
|
|
240
|
+
links and heading rank; GitHub strips the styles, and HTML-disabled readers may show the tags. Rapier's **Copy
|
|
241
|
+
markdown without typography** removes recognized wrappers while retaining semantic Markdown and literal code.
|
|
242
|
+
Its separate Pandoc/Quarto copy option writes bracketed spans deliberately; Pandoc HTML carries the CSS, but
|
|
243
|
+
ordinary LaTeX and native DOCX styling do not follow automatically.
|
|
244
|
+
|
|
245
|
+
Rapier's own Word adapter writes native run properties, rounding to the nearest half-point with positive ties up
|
|
246
|
+
and refusing results outside 1–3276 half-points. The unchanged DOCX source carrier keeps original decimals and units;
|
|
247
|
+
native import reports represented direct-run/character-style sizes without repeating document or paragraph defaults
|
|
248
|
+
as inline marks. It does not reproduce an arbitrary Word style sheet. HTML and print/PDF retain the same admitted facts at the default reference
|
|
249
|
+
unit, independent of editor zoom. No mapping claims identical glyphs or line breaks across applications.
|
|
250
|
+
|
|
251
|
+
See the original [typography guidance](https://github.com/jackskip22/rapier/blob/main/docs/markdown-standard.md#inline-typography),
|
|
252
|
+
[CommonMark raw HTML](https://spec.commonmark.org/0.31.2/#raw-html), [CSS absolute units](https://www.w3.org/TR/css-values-4/#absolute-lengths),
|
|
253
|
+
[Pandoc spans](https://pandoc.org/MANUAL.html#extension-bracketed_spans) and [Quarto spans](https://quarto.org/docs/authoring/markdown-basics.html#divs-and-spans).
|
|
254
|
+
Those specifications retain their own licences.
|
|
133
255
|
|
|
134
256
|
## Render with the reference style
|
|
135
257
|
|
|
@@ -142,19 +264,19 @@ are named font families with system fallbacks; no font or external asset is fetc
|
|
|
142
264
|
The example below renders trusted Markdown with `markdown-it` and the kit's readers: run
|
|
143
265
|
`npm install rapier-markdown-kit markdown-it@15`, save it as `render.mjs`, run `node render.mjs` and open
|
|
144
266
|
`styled.html`, which uses only `style.css`. It shows core Markdown, GFM tables, an aligned paragraph, a sized
|
|
145
|
-
picture, a
|
|
267
|
+
picture, a precise combined run, a semantic heading and a page break; tasks, footnotes and diagrams are the caller's plugins. The full markup
|
|
146
268
|
contract is [Reference style](https://github.com/jackskip22/rapier/blob/main/docs/markdown-standard.md#reference-style).
|
|
147
269
|
|
|
148
270
|
<!-- reference-style-example -->
|
|
149
271
|
```js
|
|
150
272
|
import MarkdownIt from 'markdown-it';
|
|
151
273
|
import {parseLayout, formatLayout, imageStyle} from 'rapier-markdown-kit/layout';
|
|
152
|
-
import {TEXT_COLOR_NAMES, formatColorRun, formatPageBreak,
|
|
274
|
+
import {TEXT_COLOR_NAMES, typography, formatColorRun, formatPageBreak, isPageBreakBlock} from 'rapier-markdown-kit/marks';
|
|
153
275
|
import {installMarkdownImages} from 'rapier-markdown-kit/assets';
|
|
154
276
|
import {readFile, writeFile} from 'node:fs/promises';
|
|
155
277
|
import {pathToFileURL} from 'node:url';
|
|
156
278
|
|
|
157
|
-
const md = installMarkdownImages(new MarkdownIt({html: true, linkify: true}));
|
|
279
|
+
const md = typography.install(installMarkdownImages(new MarkdownIt({html: true, linkify: true})));
|
|
158
280
|
md.renderer.rules.table_open = (tokens, index, options, env, renderer) =>
|
|
159
281
|
'<div class="table-scroll-wrap">\n' + renderer.renderToken(tokens, index, options);
|
|
160
282
|
md.renderer.rules.table_close = (tokens, index, options, env, renderer) =>
|
|
@@ -175,29 +297,6 @@ md.core.ruler.after('inline', 'reference-layout', state => {
|
|
|
175
297
|
}
|
|
176
298
|
}
|
|
177
299
|
});
|
|
178
|
-
md.core.ruler.after('inline', 'reference-colour', state => {
|
|
179
|
-
for (const inline of state.tokens) {
|
|
180
|
-
if (inline.type !== 'inline') continue;
|
|
181
|
-
let open = null, depth = 0;
|
|
182
|
-
for (const token of inline.children) {
|
|
183
|
-
if (token.type !== 'html_inline') {
|
|
184
|
-
depth += token.nesting;
|
|
185
|
-
if (open && depth < open.depth) open = null;
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
if (isColorClose(token.content) && open && depth === open.depth) {
|
|
189
|
-
Object.assign(open.token, {type: 'reference_colour_open', tag: 'span', nesting: 1, content: ''});
|
|
190
|
-
open.token.attrSet('data-md-color', open.hex);
|
|
191
|
-
open.token.attrSet('style', '--md-color:' + open.hex);
|
|
192
|
-
Object.assign(token, {type: 'reference_colour_close', tag: 'span', nesting: -1, content: ''});
|
|
193
|
-
open = null;
|
|
194
|
-
} else {
|
|
195
|
-
const hex = parseColorOpen(token.content);
|
|
196
|
-
if (hex && !open) open = {token, hex, depth};
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
300
|
const htmlBlock = md.renderer.rules.html_block;
|
|
202
301
|
md.renderer.rules.html_block = (tokens, index, options, env, renderer) =>
|
|
203
302
|
isPageBreakBlock(tokens[index].content)
|
|
@@ -213,7 +312,7 @@ export const exampleSource = [
|
|
|
213
312
|
'',
|
|
214
313
|
'One paragraph with **weight**, *emphasis*, `inline code` and a [link](https://example.com).',
|
|
215
314
|
'',
|
|
216
|
-
'## Lists and tables',
|
|
315
|
+
'## ' + typography.wrap({size: '21.5pt', family: 'serif'}, 'Lists and tables'),
|
|
217
316
|
'',
|
|
218
317
|
'1. First numbered item',
|
|
219
318
|
'2. Second numbered item',
|
|
@@ -234,7 +333,9 @@ export const exampleSource = [
|
|
|
234
333
|
'',
|
|
235
334
|
'A centred paragraph.' + formatLayout({align: 'center'}),
|
|
236
335
|
'',
|
|
237
|
-
'A ' + formatColorRun(TEXT_COLOR_NAMES.blue, 'blue phrase') + ' keeps its
|
|
336
|
+
'A ' + formatColorRun(TEXT_COLOR_NAMES.blue, 'blue phrase') + ' keeps its colour.',
|
|
337
|
+
'',
|
|
338
|
+
'And ' + typography.wrap({size: '13.5pt', color: '#175dc4', family: 'serif'}, '**precise words**') + ' keep their emphasis.',
|
|
238
339
|
'',
|
|
239
340
|
'' + formatLayout({width: 45, align: 'center'}),
|
|
240
341
|
'',
|
|
@@ -257,12 +358,12 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
|
|
257
358
|
|
|
258
359
|
## Example
|
|
259
360
|
|
|
260
|
-
Save this as `example.mjs` in the folder you installed into and run `node example.mjs`. It
|
|
261
|
-
|
|
361
|
+
Save this as `example.mjs` in the folder you installed into and run `node example.mjs`. It validates
|
|
362
|
+
the fragments' source custody and prints the resulting line count and height for its supplied measurements.
|
|
262
363
|
|
|
263
364
|
```js
|
|
264
365
|
import {parseLayout} from 'rapier-markdown-kit/layout';
|
|
265
|
-
import {parseProfile, pictureSlices,
|
|
366
|
+
import {parseProfile, pictureSlices, createPreparationScope, flowLines, mapFragment} from 'rapier-markdown-kit/model';
|
|
266
367
|
const {loadDocuments, installMeasurer} = await import(new URL(
|
|
267
368
|
'./dist/kit/conformance/measurer.mjs', import.meta.resolve('rapier-markdown-kit/package.json')));
|
|
268
369
|
|
|
@@ -281,27 +382,82 @@ const obstacles = pictureSlices(profile, /* x */ 0, /* y */ 0, /* width */ 120,
|
|
|
281
382
|
|
|
282
383
|
// 3. Plan the lines of a paragraph around those obstacles.
|
|
283
384
|
const text = 'This anchor paragraph carries enough ordinary prose', font = 'normal 400 17.6px Geist, system-ui, sans-serif';
|
|
284
|
-
const
|
|
285
|
-
const flow =
|
|
385
|
+
const preparation = createPreparationScope(), paragraph = {};
|
|
386
|
+
const flow = preparation.prepare(paragraph, [{text, font, letterSpacing: 0}], {language: 'en'});
|
|
387
|
+
if (!flow) throw new Error('The host could not prepare this paragraph');
|
|
286
388
|
const plan = flowLines(flow, /* column width */ 300, /* top */ 0, obstacles, /* line height */ 20, /* min slot */ 40);
|
|
287
389
|
// Each line carries its own x, y and width, and the text fragments laid into it.
|
|
288
|
-
|
|
390
|
+
if (!plan || !preparation.current(flow)) throw new Error('No current plan');
|
|
391
|
+
let end = 0;
|
|
392
|
+
for (const line of plan.lines) for (const fragment of line.fragments) {
|
|
393
|
+
const mapped = mapFragment(text, fragment);
|
|
394
|
+
if (!mapped || mapped.start < end || text.slice(end, mapped.start).trim()) throw new Error('Unmapped source');
|
|
395
|
+
end = mapped.end;
|
|
396
|
+
}
|
|
397
|
+
if (text.slice(end).trim()) throw new Error('Unmapped source tail');
|
|
398
|
+
console.log('lines:', plan.lines.length, 'height:', plan.height);
|
|
289
399
|
```
|
|
290
400
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
argument (`'start'` by default). A picture moves a block's words only where its outline meets them: when no line of the
|
|
401
|
+
The block's `text-align` is the ninth argument (`'start'` by default). Native balanced headings retain native
|
|
402
|
+
wrapping: the current rich line-range API does not identify every legal balancing candidate. A picture moves a
|
|
403
|
+
block's words only where its outline meets them: when no line of the
|
|
295
404
|
block, laid and aligned in the whole column as with no picture, meets an obstacle, the plan is that layout (`x` 0, the
|
|
296
405
|
column's width); otherwise every line flows around the obstacles.
|
|
297
406
|
|
|
298
407
|
## What the host supplies
|
|
299
408
|
|
|
300
|
-
|
|
409
|
+
Rich preparation measures text through one pinned Pretext graph. It needs a global
|
|
301
410
|
`OffscreenCanvas` (or a DOM `document`) whose `getContext('2d')` has a settable `font` and a
|
|
302
411
|
`measureText(text)` returning `{width}`. A browser has one already; in Node, put those two members
|
|
303
|
-
in front of
|
|
304
|
-
|
|
412
|
+
in front of the host's actual shaper and admit its fonts before preparation. The example replays historical
|
|
413
|
+
measurements instead; an unrecorded query falls back to summing single characters. That fallback demonstrates API
|
|
414
|
+
execution only and does not qualify kerning, ligatures, complex scripts or actual browser line selection.
|
|
415
|
+
|
|
416
|
+
Create one `createPreparationScope(document)` for a host document in the same measurement realm. Call
|
|
417
|
+
`scope.prepare(owner, items, {whiteSpace, wordBreak, language})` with a stable paragraph owner and original rich
|
|
418
|
+
items; omitted document support is available for declared Node measurement hosts. Text items accept
|
|
419
|
+
`{text, font, letterSpacing?, break?: 'normal' | 'never', extraWidth?}`; box items accept `{width}`. Paragraph
|
|
420
|
+
`whiteSpace` is `normal` or `pre-wrap`, and `wordBreak` is `normal` or `keep-all`. `language` is the content language,
|
|
421
|
+
not the interface locale. Mixed run languages require native fallback. The scope retains owners weakly and reuses
|
|
422
|
+
preparation across widths. Changes to exact text, item shaping settings or language require a new preparation.
|
|
423
|
+
|
|
424
|
+
The returned handle is opaque. Pass it to `flowLines`, or retain the original ranges from
|
|
425
|
+
`layoutNextRichInlineLineRange` for `materializeRichInlineLineRange`. Materialized fragments give `itemIndex`,
|
|
426
|
+
`sourceStart` and `sourceEnd` in UTF-16 offsets of that item's **original** text; `mapFragment(originalText, fragment)`
|
|
427
|
+
provides the shared display-to-source mapping. `gapItemIndex` names the source style for a collapsed gap. Never decode
|
|
428
|
+
range cursors as old segment/grapheme fields, resegment text to interpret them, JSON-serialize or deep-freeze the
|
|
429
|
+
handle. Storage segments and emergency overflow advances are not a list of legal breaks.
|
|
430
|
+
|
|
431
|
+
`scope.current(handle)` checks the shared actual-font authority before projection. Bind font loading, completion and
|
|
432
|
+
failure to `scope.invalidateFonts()` and schedule reflow. Actual face identity, descriptors and status detect
|
|
433
|
+
same-name replacement and invalidate the vendor's metric cache as well as prepared handles. Width changes do
|
|
434
|
+
neither. Call `scope.forget(owner)` when a block stops participating. One imported graph owns the realm's vendor
|
|
435
|
+
metrics; another bundle or copied vendor tree cannot share that authority. Call `scope.retire()` when replacing or
|
|
436
|
+
retiring a projection scope, so both its handles and the shared vendor metrics are retired. This retains the
|
|
437
|
+
document's known custom-family history, allowing a missing previously declared face to be refused instead of
|
|
438
|
+
silently measured through a fallback. Only the owner replacing the whole document calls
|
|
439
|
+
`scope.retire({documentChanged: true})`, which also resets that document's expected-family history.
|
|
440
|
+
|
|
441
|
+
The browser adapter calls `supportsRichStyle(style, language)` and refuses settings the pinned API cannot represent.
|
|
442
|
+
The API has no independent controls for kerning, OpenType features, variation settings, optical sizing, word spacing
|
|
443
|
+
or mixed item language; a matching font-family string alone is not proof of matching actual font data. Unsupported
|
|
444
|
+
settings, unavailable or failed faces, complex objects, authored `br`, preserved-whitespace DOM paragraphs and
|
|
445
|
+
balanced headings keep selectable native DOM. Direct prepared-text hosts can use `pre-wrap` with original CRLF and
|
|
446
|
+
hard breaks. The reference combines browser-derived break tables and Canvas metrics with JavaScript flow. The DOM
|
|
447
|
+
adapter admits Chrome/Chromium profiles; Firefox, WebKit and Chrome on iOS retain native DOM. It does not invoke live
|
|
448
|
+
DOM line selection or promise identical pixels in other engines.
|
|
449
|
+
Editor soft-break source tokens and generated-content shells stay native. The semantic export resolves verified
|
|
450
|
+
soft-break tokens to ordinary rendered spaces through its existing owner before wrapping; its source carrier keeps
|
|
451
|
+
the original Markdown unchanged.
|
|
452
|
+
Ordinary picture flow keeps its greedy policy instead of the reference sheet's generic `pretty` preference;
|
|
453
|
+
explicit authored inline `text-wrap:pretty` retains native wrapping. No native pretty optimization is claimed.
|
|
454
|
+
A lone Latin, Greek or Cyrillic word prefix, including an authored no-break-space group, may defer to a later
|
|
455
|
+
wider picture-side slot on the same row when the public engine output fits the entire group there. Decorated
|
|
456
|
+
atoms, mixed-item words, punctuation, discretionary breaks and next-row placement retain the engine policy.
|
|
457
|
+
|
|
458
|
+
`md-layout:v1` remains semantic and engine-independent. No plan or font-dependent pixel carrier is saved. Offline
|
|
459
|
+
complete pages load their admitted embedded faces before enhanced wrapping; fragments and `scripts:false` pages
|
|
460
|
+
retain native wrapping. Fonts and codecs remain explicit host capabilities as described above.
|
|
305
461
|
|
|
306
462
|
`alphaProfile(image)` samples a decoded `<img>` through a canvas, so it needs a browser. Without
|
|
307
463
|
one, read the saved descriptor with `parseProfile`, or sample the picture with your own image
|
|
@@ -317,15 +473,19 @@ node node_modules/rapier-markdown-kit/dist/kit/conformance/run.mjs
|
|
|
317
473
|
```
|
|
318
474
|
|
|
319
475
|
Thirteen small documents, each with the line boxes Rapier's own export produced for it. **Preservation**: every
|
|
320
|
-
layout comment round-trips exactly (12 of 12 that carry one). **Presentation
|
|
321
|
-
|
|
476
|
+
layout comment round-trips exactly (12 of 12 that carry one). **Presentation** compares the plan with historical
|
|
477
|
+
measurements and reports real-trace hits separately from character-sum misses (`dist/kit/conformance/README.md`).
|
|
478
|
+
Its historical line counts are not a current-engine or font-shaping acceptance gate.
|
|
322
479
|
`--impl path/to/module.mjs` runs another implementation against the same documents; `--tolerance 2` sets the pixel
|
|
323
480
|
tolerance.
|
|
324
481
|
|
|
325
482
|
## Licence
|
|
326
483
|
|
|
327
|
-
MIT, the full text in `LICENSE`; Rapier-owned modules and the stylesheet keep their MIT line. Pretext's licence,
|
|
328
|
-
pinned source inventory are in `dist/agent/vendor/pretext/`. The
|
|
484
|
+
MIT, the full text in `LICENSE`; Rapier-owned modules and the stylesheet keep their MIT line. Pretext's complete licence,
|
|
485
|
+
notice and pinned source inventory are in `dist/agent/vendor/pretext/`. The selected upstream is unreleased main
|
|
486
|
+
`bac1774c0f8b7a92e44b9da43b6d5443d55d0d9b`, despite its package version `0.0.9`. Its upstream licence includes
|
|
487
|
+
Chromium/WebKit BSD, Unicode and ICU notices for derived code and generated data; those notices travel with the kit
|
|
488
|
+
and the exported wrapping runtime. The history projection uses the MIT diff core;
|
|
329
489
|
its full grant is in `dist/packages/rapier-diff/LICENSE`. The Rapier editor is AGPL-3.0-only and
|
|
330
490
|
none of it is in this package. The kit carries Rapier's release number, written from the one
|
|
331
491
|
value the editor's release reads.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
American English hyphenation patterns (hyph-en-us)
|
|
2
|
+
Copyright (C) 1990, 2004, 2005 Gerard D.C. Kuiken
|
|
3
|
+
|
|
4
|
+
Copying and distribution of this file, with or without modification,
|
|
5
|
+
are permitted in any medium without royalty provided the copyright
|
|
6
|
+
notice and this notice are preserved.
|
|
7
|
+
|
|
8
|
+
Source: hyphenation/tex-hyphen, commit 5684c0f51c0b81133db2efbe60a408b4155a3ff5
|
|
9
|
+
hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-en-us.tex
|
|
10
|
+
The accompanying .pat.txt and .hyp.txt inputs are unchanged. patterns.js is a
|
|
11
|
+
mechanical numeric representation generated by tools/compile-hyphens.mjs.
|
|
12
|
+
These data include the original Plain TeX patterns and the additional patterns
|
|
13
|
+
and exceptions described in the upstream file. No hyphenation implementation
|
|
14
|
+
from that repository or Justice is included.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repository": "https://github.com/hyphenation/tex-hyphen",
|
|
3
|
+
"commit": "5684c0f51c0b81133db2efbe60a408b4155a3ff5",
|
|
4
|
+
"upstreamDirectory": "hyph-utf8/tex/generic/hyph-utf8/patterns/txt/",
|
|
5
|
+
"licenseSource": "hyph-utf8/tex/generic/hyph-utf8/patterns/tex/hyph-en-us.tex",
|
|
6
|
+
"licenseSourceGitBlob": "bd9b757d89074e3e11b590311ce13ba6667544aa",
|
|
7
|
+
"license": "LicenseRef-Kuiken",
|
|
8
|
+
"licenseSha256": "0cf036759a4fb63a3d0bdb919f0dacbe137e225cb6f8f268d2928e368a8c1731",
|
|
9
|
+
"inputs": [
|
|
10
|
+
{
|
|
11
|
+
"path": "hyph-en-us.pat.txt",
|
|
12
|
+
"sourceGitBlob": "f69e835d9dacea688fdc51956ea9243b9d042e51",
|
|
13
|
+
"bytes": 31489,
|
|
14
|
+
"sha256": "0f57318b878b132547ae92db39a6e1d1cf2a05d9008874955d6ecb910007a463"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "hyph-en-us.hyp.txt",
|
|
18
|
+
"sourceGitBlob": "b87163d4425b7b5b7e2d9f170e486131988706c4",
|
|
19
|
+
"bytes": 169,
|
|
20
|
+
"sha256": "5e785c27e151f878c312991d937b5582615b77737ab30bac413d5967d6aa21da"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"generator": "tools/compile-hyphens.mjs",
|
|
24
|
+
"generatorSha256": "b5758c3ceac76ac39a8ba0bf2f45bc88854e4779d4f443a9c0957694305571dd",
|
|
25
|
+
"policy": "Complete pinned data in a static prefix trie, with original MIT Rapier traversal and matcher; en and en-US ASCII words. Other regional English, non-ASCII words and other languages use the native offline hyphenator.",
|
|
26
|
+
"files": [
|
|
27
|
+
{
|
|
28
|
+
"output": "patterns.js",
|
|
29
|
+
"outputBytes": 46360,
|
|
30
|
+
"outputSha256": "e0360f1552704657d79a670f1e2e0b263f6eea42e209866b521cd8ec2aff387d"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|