rapier-markdown-kit 1.2.33 → 1.2.40

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 (45) hide show
  1. package/README.md +15 -9
  2. package/dist/agent/vendor/pretext/NOTICE +2 -2
  3. package/dist/agent/vendor/pretext/SOURCE.json +62 -78
  4. package/dist/agent/vendor/pretext/analysis.js +24 -6
  5. package/dist/agent/vendor/pretext/gecko-line-breaks.js +1 -1
  6. package/dist/agent/vendor/pretext/generated/engine-break-data.js +1 -1
  7. package/dist/agent/vendor/pretext/generated/webkit-generic-families.js +1 -1
  8. package/dist/agent/vendor/pretext/graphemes.js +1 -1
  9. package/dist/agent/vendor/pretext/han-kerning.js +1 -1
  10. package/dist/agent/vendor/pretext/layout.js +14 -11
  11. package/dist/agent/vendor/pretext/line-break.js +170 -195
  12. package/dist/agent/vendor/pretext/line-breaks.js +1 -7
  13. package/dist/agent/vendor/pretext/line-text.js +2 -2
  14. package/dist/agent/vendor/pretext/measurement.js +454 -113
  15. package/dist/agent/vendor/pretext/prepare.js +164 -244
  16. package/dist/agent/vendor/pretext/rich-inline.js +57 -37
  17. package/dist/agent/will.mjs +73 -0
  18. package/dist/kit/ledger/data.mjs +2 -2
  19. package/dist/kit/ledger/format.mjs +86 -42
  20. package/dist/kit/ledger/hash.mjs +43 -2
  21. package/dist/kit/ledger/history.mjs +6 -0
  22. package/dist/kit/ledger/inverse-source.mjs +6 -2
  23. package/dist/kit/ledger/journal-records.mjs +4 -2
  24. package/dist/kit/ledger/merge.mjs +3 -17
  25. package/dist/kit/ledger/text-merge.mjs +28 -2
  26. package/dist/kit/rapier-ledger.mjs +2 -2
  27. package/dist/kit/render-markdown.mjs +133 -10
  28. package/dist/kit/render-print.mjs +3 -3
  29. package/dist/kit/render-sanitize.mjs +66 -23
  30. package/dist/kit/render.mjs +10 -10
  31. package/dist/kit/wiki.mjs +34 -0
  32. package/dist/kit/will.d.mts +3 -0
  33. package/dist/layout/hyphenation.mjs +6 -4
  34. package/dist/layout/line-plan.mjs +96 -0
  35. package/dist/layout/model.mjs +2 -1
  36. package/dist/layout/paragraph-fit.mjs +4 -4
  37. package/dist/layout/prepared-paragraph.mjs +19 -2
  38. package/dist/layout/typography.mjs +57 -63
  39. package/dist/spec/document-fonts.mjs +1 -0
  40. package/dist/spec/document-settings.mjs +1 -0
  41. package/dist/spec/html-blocks.mjs +10 -7
  42. package/dist/spec/md-assets.mjs +52 -12
  43. package/package.json +1 -1
  44. package/style.css +25 -23
  45. package/dist/agent/vendor/pretext/entry-geometry.js +0 -183
package/README.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # rapier-markdown-kit
2
2
 
3
- Read, render and write Self-contained Markdown in browsers and Node: one `.md` file with pictures, editable SVG
4
- drawings, layout and precise inline typography. Build portable documents for people and agents. Will/1 regions mark what an agent
3
+ Read, render and write Self-contained Markdown: one `.md` file with its pictures, drawings and layout.
4
+
5
+ <picture>
6
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jackskip22/rapier-plugins/main/assets/diagram-390-dark.png">
7
+ <img src="https://raw.githubusercontent.com/jackskip22/rapier-plugins/main/assets/diagram-390-light.png" alt="A Rapier document on a phone with an editable diagram of connected boxes" width="320">
8
+ </picture>
9
+
10
+ Try it: open a `.md` file at [rapier.website](https://rapier.website).
11
+ Install: `npm install rapier-markdown-kit`.
12
+
13
+ The kit works in browsers and Node: pictures, editable SVG drawings, layout and precise inline typography. Build portable documents for people and agents. Will/1 regions mark what an agent
5
14
  may edit, append to or preserve. MIT, no dependencies.
6
15
 
7
16
  - Typography uses ordinary inline HTML spans with validated size, color and family. Comments and references
@@ -9,16 +18,13 @@ may edit, append to or preserve. MIT, no dependencies.
9
18
  - One stylesheet renders the document as the editor and its exported page do.
10
19
  - The line planner flows text around a picture's real shape; a conformance suite of thirteen documents runs
11
20
  any implementation against it.
12
- - Will/1 markers say which regions an agent may edit, only add to, or must keep.
13
- - MIT, no dependencies, Node 22 or newer.
21
+ - Node 22 or newer.
14
22
 
15
23
  To show documents in your app without writing a renderer, frame the read-only reader with
16
24
  `npm install rapier-embed` (`build: 'reader'`). To hand a person the whole editor around their document as one
17
25
  offline file, run `npx rapier-html notes.md`.
18
26
 
19
- In the editor, an agent edits live beside the person or while they are away. Rapier shows its presence and changes;
20
- the person taps a change to see what was there before and undoes anything. `show {target:"comparison"}` lets the agent
21
- deliberately show a diff. The kit supplies the portable source and history those tools use.
27
+ The kit supplies the portable source and history Rapier's agent tools use.
22
28
 
23
29
  ```sh
24
30
  npm install rapier-markdown-kit
@@ -550,8 +556,8 @@ tolerance.
550
556
  ## License
551
557
 
552
558
  MIT, the full text in `LICENSE`; Rapier-owned modules and the stylesheet keep their MIT line. Pretext's complete license,
553
- notice and pinned source inventory are in `dist/agent/vendor/pretext/`. The selected upstream is unreleased main
554
- `bac1774c0f8b7a92e44b9da43b6d5443d55d0d9b`, despite its package version `0.0.9`. Its upstream license includes
559
+ notice and pinned source inventory are in `dist/agent/vendor/pretext/`. The selected upstream is main
560
+ `0d102a5cd933611e86a7e60bda7b4baa5995c6b0`: Pretext 1.0.0 plus the commits of main through pull request #525. Its upstream license includes
555
561
  Chromium/WebKit BSD, Unicode and ICU notices for derived code and generated data; those notices travel with the kit
556
562
  and the exported wrapping runtime. The history projection uses the MIT diff core;
557
563
  its full grant is in `dist/packages/rapier-diff/LICENSE`. The Rapier editor is AGPL-3.0-only and
@@ -1,5 +1,5 @@
1
- Pretext Unreleased at bac1774c0f8b7a92e44b9da43b6d5443d55d0d9b (2026-10-10T16:55:37-07:00)
2
- Package metadata version: 0.0.9; this snapshot is not the 0.0.9 release.
1
+ Pretext 1.0.0 plus main to #525 at 0d102a5cd933611e86a7e60bda7b4baa5995c6b0 (2026-10-15T10:02:17-07:00)
2
+ Package metadata version: 1.0.0; this snapshot is the 1.0.0 release (4a98f37b) plus the 16 commits of main through pull request #525.
3
3
  Copyright (c) 2026 Pretext contributors
4
4
  https://github.com/chenglou/pretext
5
5
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "package": "@chenglou/pretext",
3
- "version": "0.0.9",
4
- "release": "Unreleased",
3
+ "version": "1.0.0",
4
+ "release": "1.0.0 plus main to #525",
5
5
  "repository": "https://github.com/chenglou/pretext",
6
- "commit": "bac1774c0f8b7a92e44b9da43b6d5443d55d0d9b",
7
- "commitDate": "2026-10-10T16:55:37-07:00",
8
- "sourceTree": "85decd44b5dcef3d7c571c1f3be83cdd12cf71b3",
9
- "packageSha256": "a88235b35877319260005e8a01b06f575f73a3b4f9f0cbf26209f8ae10ca0c9c",
6
+ "commit": "0d102a5cd933611e86a7e60bda7b4baa5995c6b0",
7
+ "commitDate": "2026-10-15T10:02:17-07:00",
8
+ "sourceTree": "fc987521e1fab1b6c1bedcc7a2e1912ca06bb166",
9
+ "packageSha256": "adf65e4df509df3cb3acef2cc4dd6179591f72bc9a2c351012d9d62d15552d2a",
10
10
  "license": "MIT",
11
11
  "thirdPartyLicenses": [
12
12
  "BSD-3-Clause",
@@ -15,19 +15,19 @@
15
15
  "ICU"
16
16
  ],
17
17
  "licenseSha256": "b0bc6870efb4e667f911d5f6b52fc9b321d634a0469a17464e35da244c28f128",
18
- "noticeSha256": "fb31768b51f1ad699d0bf2fd9f72fd630ec9683e22f8f63aab34a4bde6569b3d",
18
+ "noticeSha256": "c0867f4217303fa447f1932581335903d1082a4e350bcb6d15fedbe6f796af76",
19
19
  "exports": {
20
20
  ".": "./layout.js",
21
21
  "./rich-inline": "./rich-inline.js"
22
22
  },
23
23
  "compiler": {
24
- "runtime": "v24.19.0",
25
- "amaro": "1.1.10",
24
+ "runtime": "v22.22.0",
25
+ "amaro": "1.1.4",
26
26
  "api": "node:module.stripTypeScriptTypes",
27
27
  "mode": "strip",
28
28
  "sourceMap": false,
29
29
  "importParser": "Acorn 8.19.0",
30
- "toolSha256": "9b974f2c80886088a0ff7e603d297298c9432090d864836ab09f9e6b90f64202"
30
+ "toolSha256": "53f6030b37a0a2a29e0957ffc93706cabbfc14de689f79b53ec056160d2082e8"
31
31
  },
32
32
  "changes": "Node TypeScript erasure and attribution header; rich-inline.js and prepare.js additionally carry rapier-paragraph-segments-v2 (direct legal source facts and explicit projected hyphen-minus). This local runtime extension is not byte-exact upstream. Source hashes, unchanged-upstream output hash and patched output hash are recorded. Default wrapping and the single measurement graph are preserved.",
33
33
  "generatedData": [
@@ -57,18 +57,18 @@
57
57
  "sourceBytes": 35140,
58
58
  "sourceSha256": "b8782c423a8d192f1d5c69c8ed2422bc8d55526c9aa18010e70348252285455e",
59
59
  "output": "generated/engine-break-data.js",
60
- "outputBytes": 35262,
61
- "outputSha256": "463e7f2edcbd315dffccf9e4c24d23c782f1cb2dfcee75342f1e1c8dc6aa5096",
60
+ "outputBytes": 35264,
61
+ "outputSha256": "71006713e3383564b5c7348c736c2dba6a59e04c05693a6a62e6367b45abbc7a",
62
62
  "imports": []
63
63
  },
64
64
  {
65
65
  "source": "src/line-breaks.ts",
66
- "sourceGitBlob": "fcdbe41fd6728d2930a000a2279a97208781ec5d",
67
- "sourceBytes": 38498,
68
- "sourceSha256": "027473f31fbbb0408d8381ae5fe02b72d93680e29a721bc36d9893ed9a49eca1",
66
+ "sourceGitBlob": "ec09b58611c8251d583bab2893f57dec78082a33",
67
+ "sourceBytes": 38127,
68
+ "sourceSha256": "4b3b654234a175e06ea672ff903c544e00ae7626698bfa8f83616c84fa0aaee4",
69
69
  "output": "line-breaks.js",
70
- "outputBytes": 38620,
71
- "outputSha256": "b817c1a9b1e022dd0427ee9628a81edbc0dd18b44e910c284070ff625fb0cce7",
70
+ "outputBytes": 38251,
71
+ "outputSha256": "cbc65ed7232d1bfc241787a3d99986e062c74bbb30d3fbf738cf7c59c2196ccf",
72
72
  "imports": [
73
73
  "./generated/engine-break-data.js"
74
74
  ]
@@ -79,8 +79,8 @@
79
79
  "sourceBytes": 4663,
80
80
  "sourceSha256": "2f99310f195889177675edd7e0fbd00ee1a59286f243a9a8b13085bcb12b89f3",
81
81
  "output": "graphemes.js",
82
- "outputBytes": 4785,
83
- "outputSha256": "efa38ca88b2cf8a5557cd7b0fea0778de10f0df833bcef79015026c64ab8d71f",
82
+ "outputBytes": 4787,
83
+ "outputSha256": "88bf8f7575ad7e888b4d7223130ab4cbe6c559cb83e35672cbe1ca94d3f86d01",
84
84
  "imports": [
85
85
  "./line-breaks.js"
86
86
  ]
@@ -91,8 +91,8 @@
91
91
  "sourceBytes": 33564,
92
92
  "sourceSha256": "cf67f7eecaf6c9849acfa9958575070597cb5e6f3a1a17bb2027cef828340248",
93
93
  "output": "gecko-line-breaks.js",
94
- "outputBytes": 33686,
95
- "outputSha256": "163a9aaafb492a83806b57a830b18d7d63051e9a15160c814c4518891835e9ff",
94
+ "outputBytes": 33688,
95
+ "outputSha256": "4551c550d9658572d00470099ab843c588a3a63b3ad3baf825ccebfc6983336e",
96
96
  "imports": [
97
97
  "./generated/engine-break-data.js",
98
98
  "./graphemes.js",
@@ -101,12 +101,12 @@
101
101
  },
102
102
  {
103
103
  "source": "src/analysis.ts",
104
- "sourceGitBlob": "921a5908672b0d8dbe4fee9f76c86e598a68e4a0",
105
- "sourceBytes": 39758,
106
- "sourceSha256": "7aadf2f9a979f6af7ec8e3e668036dcddf72800342ad76fe778c5c5fd2f16aeb",
104
+ "sourceGitBlob": "a994b67226c90e39fbd25e3b8fdfa63249b55527",
105
+ "sourceBytes": 41259,
106
+ "sourceSha256": "bf6fbab9ab2f32b92573ad982d8485ca7d2ee8de1886a8bdcc435b7bdca15241",
107
107
  "output": "analysis.js",
108
- "outputBytes": 39880,
109
- "outputSha256": "15ce0e71704851b6f278ef97dc165d57a3160063d2a99783e7bccb4e3bb66042",
108
+ "outputBytes": 41383,
109
+ "outputSha256": "c3595e80fc013ed6424f78e204e45a06b5a9d1c02d335b344782199edcfc369f",
110
110
  "imports": [
111
111
  "./gecko-line-breaks.js",
112
112
  "./graphemes.js",
@@ -119,59 +119,45 @@
119
119
  "sourceBytes": 5190,
120
120
  "sourceSha256": "16ffba2832197e189a5ddf7e745304a3c5faacc82858a51808c3744991b11614",
121
121
  "output": "generated/webkit-generic-families.js",
122
- "outputBytes": 5312,
123
- "outputSha256": "60255a17acf8cd9130ed048f9be1b409f439cd07939315f1c1ba6257c8b3fefd",
122
+ "outputBytes": 5314,
123
+ "outputSha256": "8df335194a5e28fe8b94da13b7c64f6eeafd2ee6e4ca82e47de97b50bef8c7e6",
124
124
  "imports": []
125
125
  },
126
126
  {
127
127
  "source": "src/measurement.ts",
128
- "sourceGitBlob": "1a0730fa4b706f37c2d18eb04a90487e1bae958b",
129
- "sourceBytes": 70366,
130
- "sourceSha256": "eb2469c67105a03e34fa2e066f51dcb552676d6ed29ce22a8f3ec5fef0801911",
128
+ "sourceGitBlob": "0ab3ebaa2802088fb2ac7b5dcc10d35a3440b36f",
129
+ "sourceBytes": 93605,
130
+ "sourceSha256": "245707d4090bcb74f0c796e074680e798d5eaf2c19e1ba66f06bcc2390132253",
131
131
  "output": "measurement.js",
132
- "outputBytes": 70488,
133
- "outputSha256": "5e3e5f011c8589a925b83691e2f6941e7b17b107be26784421fbf7b390593767",
132
+ "outputBytes": 93729,
133
+ "outputSha256": "bdb161e112ace0b15d3d072620d709e439a3c0d53d853922cc16ae6fcc00fbda",
134
134
  "imports": [
135
135
  "./generated/webkit-generic-families.js",
136
136
  "./graphemes.js",
137
137
  "./line-breaks.js"
138
138
  ]
139
139
  },
140
- {
141
- "source": "src/entry-geometry.ts",
142
- "sourceGitBlob": "c7f139c1f6234329fffa30678f5005c7b1468afb",
143
- "sourceBytes": 9321,
144
- "sourceSha256": "271d975afceb141c10406de5923decc61c9f45b9229dff421ff4355c46611899",
145
- "output": "entry-geometry.js",
146
- "outputBytes": 9443,
147
- "outputSha256": "d526d143bd6eb4432295f2e6551090088fa72f4de36c6c2d32af0f8f46979065",
148
- "imports": [
149
- "./graphemes.js",
150
- "./measurement.js"
151
- ]
152
- },
153
140
  {
154
141
  "source": "src/line-break.ts",
155
- "sourceGitBlob": "d6ef1b570aa99b86c72f52e4179d317d2effc73f",
156
- "sourceBytes": 67118,
157
- "sourceSha256": "968d4d8ff740bdba58b802b8c7bc44f9808c5257887602638c260a806118b913",
142
+ "sourceGitBlob": "4ddb69de1eca351f0d0023cad5eb7758bf98359d",
143
+ "sourceBytes": 68368,
144
+ "sourceSha256": "5f45ad068f266eff920cd1df6f0a9784e888d6c0e990631cd9ac6b3c8e77ee30",
158
145
  "output": "line-break.js",
159
- "outputBytes": 67240,
160
- "outputSha256": "c2e66ac93d0a61d86f9a34d6f3de6344b939f7f091c3acfa436714d189cb6253",
146
+ "outputBytes": 68492,
147
+ "outputSha256": "cc0c4c9f0cb76765ee78cda536e5df9dafa8fdc1a845acabee1fe4e4377c5a31",
161
148
  "imports": [
162
149
  "./analysis.js",
163
- "./entry-geometry.js",
164
150
  "./measurement.js"
165
151
  ]
166
152
  },
167
153
  {
168
154
  "source": "src/line-text.ts",
169
- "sourceGitBlob": "03952388b0c018b46585d121f8c82f30676200ee",
170
- "sourceBytes": 3735,
171
- "sourceSha256": "b77b5f59fcd17c048e11a36a9a9ecad2953ec5a69e75c3d9b3b28db989f4f6da",
155
+ "sourceGitBlob": "ece66351037a8c11e2504700dd1452ab3fcd873e",
156
+ "sourceBytes": 3759,
157
+ "sourceSha256": "d79e792a052baba6d50658e45dcd60d4c9c57720200682e41852f4e1f9186bd5",
172
158
  "output": "line-text.js",
173
- "outputBytes": 3857,
174
- "outputSha256": "7da3338966dc9772c845a32bb9f114a496885820de77ca1b9fe2ef86829494d1",
159
+ "outputBytes": 3883,
160
+ "outputSha256": "cf0d621bd2496a0376a985139356d7bf49f75e549743eaab06a74aaef06303af",
175
161
  "imports": [
176
162
  "./analysis.js",
177
163
  "./graphemes.js",
@@ -185,8 +171,8 @@
185
171
  "sourceBytes": 13202,
186
172
  "sourceSha256": "0fd39a11777abf2a8af12c7a8450903140d336ae6cdc58b4fb4bb033cc46ff3b",
187
173
  "output": "han-kerning.js",
188
- "outputBytes": 13324,
189
- "outputSha256": "860294fc69c4b549df112fa2898682deb0a4844f5f740e36adf1e9beae09c761",
174
+ "outputBytes": 13326,
175
+ "outputSha256": "7eabac3539df0ac2a753315cddd3a70a1e4e53100f955cb81304eece5dc43071",
190
176
  "imports": [
191
177
  "./analysis.js",
192
178
  "./line-breaks.js",
@@ -195,32 +181,31 @@
195
181
  },
196
182
  {
197
183
  "source": "src/prepare.ts",
198
- "sourceGitBlob": "569d74c217fac407e01c712c73b4d4ec1ce1b744",
199
- "sourceBytes": 47683,
200
- "sourceSha256": "cab52e730c67c1f43977ef1e5b149a87422cfaca703275fe35582c500f358b9c",
184
+ "sourceGitBlob": "c9185214686fbe9f4dd00c860f29cac8be790fb3",
185
+ "sourceBytes": 43095,
186
+ "sourceSha256": "4fc8ab0f7f61c9ba9bf7c451347936fbdf703c0096fecc3d9260180798e70909",
201
187
  "output": "prepare.js",
202
- "outputBytes": 47852,
203
- "outputSha256": "0ab0111a1bbb0857937ec7e08bb3aa567cc4f6d706e28986867b19d5efb68c0e",
188
+ "outputBytes": 43266,
189
+ "outputSha256": "0301c86ac74bc8395007d1b3d27e364de7da795f528501da98ed0adfb2230deb",
204
190
  "imports": [
205
191
  "./analysis.js",
206
- "./entry-geometry.js",
207
192
  "./generated/engine-break-data.js",
208
193
  "./graphemes.js",
209
194
  "./han-kerning.js",
210
195
  "./line-breaks.js",
211
196
  "./measurement.js"
212
197
  ],
213
- "upstreamOutputSha256": "6b309c760af7e0c75b9f089a7030974a61688e9877314479dcdf999a6521f490",
198
+ "upstreamOutputSha256": "a42bda210a756435b42c5cf9e853133ff2c27a93e9792b20f26e58aa2262cc9f",
214
199
  "localPatch": "rapier-paragraph-segments-v2"
215
200
  },
216
201
  {
217
202
  "source": "src/layout.ts",
218
- "sourceGitBlob": "c6a22ab8666bfffecb4b76d3bb282d5bb8ad7e52",
219
- "sourceBytes": 14212,
220
- "sourceSha256": "c0c6de52c793fce9f2395dd2ffd96c6229875f9ef5754184d166250f7e40800d",
203
+ "sourceGitBlob": "02fa8cb7b2b67c54a4e8a2c1f9694e6cc0c9e37d",
204
+ "sourceBytes": 14339,
205
+ "sourceSha256": "e2d88979f449c0416342377a2a8e7e98bd57f20539737ea5bcfab9d1b6ad2b22",
221
206
  "output": "layout.js",
222
- "outputBytes": 14334,
223
- "outputSha256": "f5ddbd649f9a89e193b82839075dbc3690b2f3a1a894c1cb1ab35e8c7c875347",
207
+ "outputBytes": 14463,
208
+ "outputSha256": "48922fbb39c1f0a9a62199ee7e51ea9baff421f5c03f0a8cca33ca57dee01a5b",
224
209
  "imports": [
225
210
  "./analysis.js",
226
211
  "./line-break.js",
@@ -232,21 +217,20 @@
232
217
  },
233
218
  {
234
219
  "source": "src/rich-inline.ts",
235
- "sourceGitBlob": "9e0178ec08b867e14d1a9d970ddb32974b714842",
236
- "sourceBytes": 73518,
237
- "sourceSha256": "0b327743200338746b473ff7e788798381fe05d372283ee29ec6eaf685701713",
220
+ "sourceGitBlob": "c39ef17092fcea7915d7a28de9328ecfc2ed2e7f",
221
+ "sourceBytes": 75016,
222
+ "sourceSha256": "f030adb3c32fd96742741970d9b75efe239b00317137d18560eaf369f53e5687",
238
223
  "output": "rich-inline.js",
239
- "outputBytes": 74268,
240
- "outputSha256": "f39d5d694c0a17262eda3d210e6ad7913c1db2d7167e2b600c8efbf1f3d2a571",
224
+ "outputBytes": 75768,
225
+ "outputSha256": "47e675a12f59c622a154e6f2009055679cfa03e3e4d0f623dcd85fb3d3576304",
241
226
  "imports": [
242
227
  "./analysis.js",
243
- "./entry-geometry.js",
244
228
  "./line-break.js",
245
229
  "./line-text.js",
246
230
  "./measurement.js",
247
231
  "./prepare.js"
248
232
  ],
249
- "upstreamOutputSha256": "22c0f38d56cb627243deb3bd8f7b8264e3a6969b4338c406b8e4d9357a9b1b5e",
233
+ "upstreamOutputSha256": "28e12e027b0448c27126f6c525936e94ce457712ee4447c67842115e313ca636",
250
234
  "localPatch": "rapier-paragraph-segments-v2"
251
235
  }
252
236
  ]
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  import { getGeckoLineBreaks, isDiscardable, isEastAsianSegmentBreak, isJapaneseOrChinese, isSpaceCombiningSequenceTail, isSpaceOrTabOrSegmentBreak } from './gecko-line-breaks.js'
3
3
  import { isBidiControl, } from './graphemes.js'
4
4
  import { BREAK, CLUSTER_START, FORCED_BREAK, ITEM_START, SOFT_HYPHEN_BREAK, getBlinkLineBreaks, getWebKitBreakBetweenItems, getWebKitLineBreaks } from './line-breaks.js'
@@ -49,6 +49,12 @@ export const RETURNABLE = 0x40
49
49
  // The engine's clusters don't split the segment, so no emergency break splits it
50
50
  // either. Measurement clears it.
51
51
  export const ONE_CLUSTER = 0x80
52
+ // In its place on a prepared handle: the zero-width break is a soft hyphen, which the Gecko scan
53
+ // makes one where its break draws no hyphen (classifySegmentUnit). Firefox's text run drops it,
54
+ // so it is a break with nothing there: it stays with the line that ends at it and no line starts
55
+ // with it, where a zero-width space is content (walkPreparedComplexLines in src/line-break.ts).
56
+ // Measurement sets it.
57
+ export const DROPPED = 0x80
52
58
 
53
59
 
54
60
  // Each kind's name by its code, as prepareWithSegments() gives them.
@@ -62,7 +68,8 @@ export const SEGMENT_KINDS = [
62
68
  // flags byte: its kind, UNBROKEN where the engine's scan gives no break before text, zero-width
63
69
  // glue or a control, other than at a line start, and where tabs don't hang before a tab or
64
70
  // the spaces after one, RETURNABLE at the other segments of text with such a boundary, which
65
- // `hasUnbroken` tells, and ONE_CLUSTER where the scan has clusters of its own.
71
+ // `hasUnbroken` tells, and ONE_CLUSTER where the scan has clusters of its own. A zero-width
72
+ // space right after another is UNBROKEN too, which `hasUnbroken` leaves out.
66
73
 
67
74
 
68
75
 
@@ -268,9 +275,9 @@ function mapSourceLineBreaks(source , normalizedLength , sourceBre
268
275
 
269
276
  // A FORCED_BREAK after U+2028 or U+2029 makes the separator a hard break in every white-space
270
277
  // mode, and a SOFT_HYPHEN_BREAK makes a soft hyphen a zero-width break: the line can end there
271
- // without a hyphen. One with only soft hyphens before it on its chunk stays a soft hyphen, since
272
- // a zero-width break there holds a line and Firefox, which drops soft hyphens from its text runs,
273
- // gives it none.
278
+ // without a hyphen, and Firefox, which drops soft hyphens from its text runs, has nothing there
279
+ // (DROPPED). One with only soft hyphens before it on its chunk stays a soft hyphen: no line ends
280
+ // at a chunk's start, and a line's start leaves either out.
274
281
  function classifySegmentUnit(normalized , breaks , i , code , whiteSpace , scan ) {
275
282
  if ((code === 0x2028 || code === 0x2029) && (breaks[i + 1] & FORCED_BREAK) !== 0) return HARD_BREAK
276
283
  if (code === 0x00AD && (breaks[i + 1] & SOFT_HYPHEN_BREAK) !== 0 && followsChunkContent(normalized, i)) return ZERO_WIDTH_BREAK
@@ -303,7 +310,8 @@ function isControlSegmentCode(code ) {
303
310
  // closing bracket, or under keep-all, is zero-width glue: it stays its own zero-width
304
311
  // segment, takes no letter spacing and doesn't end a line.
305
312
  // Combining marks right after it, or after a control, stay apart from the text after
306
- // them, since they shape on the grapheme before it (measureAnalysis). Where the Gecko
313
+ // them, a segment of their own that measurement measures alone, as it does any text
314
+ // (ENGINE_FOLLOWUPS.md, Canvas answers that differ from the page). Where the Gecko
307
315
  // scan marks cluster starts, a segment is ONE_CLUSTER unless one falls inside it.
308
316
  //
309
317
  // Firefox leaves soft hyphens and bidi controls out of the text run it breaks and maps a line end
@@ -394,6 +402,15 @@ function segmentAtLineBreaks(normalized , spaceSources
394
402
  // white space ends the line: Gecko breaks only after the whole run (nsLineBreaker.cpp:
395
403
  // 318-330). A soft hyphen before the tab keeps its break (GetHyphenationBreaks,
396
404
  // nsTextFrame.cpp:4409-4457).
405
+ //
406
+ // No break comes between two zero-width spaces either (UAX #14 LB7), so the second is
407
+ // marked too: a line that goes back to its last break, as Gecko's does from a tab that
408
+ // doesn't fit, goes back past both, where the second would hold a line of its own (`M`,
409
+ // two of them, a tab and `is` in pre-wrap at 24px are three lines in Firefox 157, the
410
+ // tab on the second). It isn't counted in `hasUnbroken`, which takes a text off the
411
+ // simple walkers: the second fits wherever the first does, so no line of theirs ends
412
+ // between the two, and none goes back to a break from it. A soft hyphen that is a
413
+ // zero-width break (classifySegmentUnit) is left as it was.
397
414
  let hasUnbroken = false
398
415
  const count = flags.length
399
416
  for (let j = count - 2; j >= 0; j--) {
@@ -405,6 +422,7 @@ function segmentAtLineBreaks(normalized , spaceSources
405
422
  } else if (next === TEXT || next === ZERO_WIDTH_GLUE || next === CONTROL) {
406
423
  if (kind === ZERO_WIDTH_BREAK || kind === SOFT_HYPHEN) flags[j] = flags[j] & ~KIND_BITS | ZERO_WIDTH_GLUE
407
424
  } else {
425
+ if (next === ZERO_WIDTH_BREAK && kind === ZERO_WIDTH_BREAK && normalized.charCodeAt(starts[j + 1] ) === 0x200B) flags[j + 1] = flags[j + 1] | UNBROKEN
408
426
  continue
409
427
  }
410
428
  flags[j + 1] = flags[j + 1] | UNBROKEN
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Break opportunities as Firefox finds them: a port of how Gecko transforms a text node's
3
3
  // white space, sets up its text run and breaks its words with nsLineBreaker over ICU4X's
4
4
  // line iterator, with Firefox's baked line data and the Unicode properties Gecko reads,
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Generated by scripts/generate-engine-break-data.ts from scripts/engine-data/.
3
3
  // Do not edit by hand. Regenerate with `bun run generate:engine-break-data`.
4
4
 
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Generated by scripts/generate-webkit-generic-families.ts from scripts/engine-data/safari-27.0/.
3
3
  // Do not edit by hand. Regenerate with `bun run generate:webkit-generic-families`.
4
4
 
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Grapheme clusters as each engine's Intl.Segmenter finds them: ICU's character rules
3
3
  // (char.brk) as Chrome and libicucore ship them, which scripts/generate-engine-break-data.ts
4
4
  // writes to src/generated/engine-break-data.ts. Firefox's ICU4X data gives the same clusters
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Blink's HanKerning under the default text-spacing-trim: normal (han_kerning.cc/.h,
3
3
  // han_kerning_char_type.h and shaping_line_breaker.cc at Chrome 153). Blink halts a fullwidth
4
4
  // opening mark after an opening, middle, closing or narrow opening mark, and a closing mark
@@ -1,4 +1,4 @@
1
- /*! Pretext Unreleased (bac1774c0) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
1
+ /*! Pretext 1.0.0 + main (0d102a5cd) | MIT; BSD/Unicode/ICU notices in LICENSE | Copyright (c) 2026 Pretext contributors */
2
2
  // Prepare text with engine segmentation rules and cached Canvas measurements, then
3
3
  // lay it out with arithmetic. Preparation touches the DOM in three places: the emoji
4
4
  // correction's span, read once per font where Canvas measures an emoji wider than its
@@ -131,15 +131,12 @@ function prepareInternal(
131
131
  // 2. Find break opportunities with the engine's own line-break scan
132
132
  // 3. Split the text into segments between them ("better." as one unit)
133
133
  // 4. Measure each segment via canvas measureText, cache by (segment, font).
134
- // A run of combining marks that glue or a control separates from its grapheme
135
- // measures after that grapheme, and WebKit measures a word with the space after it
134
+ // WebKit measures a word with the space after it
136
135
  // 5. Measure where each text segment of two or more graphemes can break under
137
136
  // overflow-wrap: break-word: by graphemes, pairs or prefixes, per engine
138
137
  // 6. Correct emoji canvas inflation (probed once per font)
139
138
  // 7. Record what changes at a line's edges: Blink's halts of CJK punctuation,
140
- // U+3000 hangs, how much narrower a soft hyphen's neighbors measure joined,
141
- // fresh-line widths inside segments with invisible characters, and the
142
- // characters WebKit keeps after an overflowing first one
139
+ // U+3000 hangs, and how much narrower a soft hyphen's neighbors measure joined
143
140
  export function prepare(text , font , options ) {
144
141
  return prepareInternal(text, font, false, options)
145
142
  }
@@ -279,13 +276,16 @@ export function measureNaturalWidth(prepared ) {
279
276
  return measureLineStats(prepared, Number.POSITIVE_INFINITY).maxLineWidth
280
277
  }
281
278
 
279
+ // Where a line stream starts without a `start`: the text's first line.
280
+ const TEXT_START_CURSOR = { segmentIndex: 0, graphemeIndex: 0 }
281
+
282
282
  // Steps one streamed line from `start` into the result's cursors: the
283
283
  // normalized line start and the line end. Returns the reported width, or null
284
284
  // after the last line.
285
285
  function stepNextLine(
286
286
  prepared ,
287
- start ,
288
287
  maxWidth ,
288
+ start ,
289
289
  lineStart ,
290
290
  lineEnd ,
291
291
  ) {
@@ -300,14 +300,17 @@ function stepNextLine(
300
300
  return width === null ? null : Math.max(0, width)
301
301
  }
302
302
 
303
+ // The line streams take the width before the cursor, as layoutNextRichInlineLineRange()
304
+ // does, and start at the text's first line without one: pass each line's `end` back
305
+ // for the next.
303
306
  export function layoutNextLine(
304
307
  prepared ,
305
- start ,
306
308
  maxWidth ,
309
+ start = TEXT_START_CURSOR,
307
310
  ) {
308
311
  const lineStart = { segmentIndex: 0, graphemeIndex: 0 }
309
312
  const end = { segmentIndex: 0, graphemeIndex: 0 }
310
- const width = stepNextLine(prepared, start, maxWidth, lineStart, end)
313
+ const width = stepNextLine(prepared, maxWidth, start, lineStart, end)
311
314
  if (width === null) return null
312
315
 
313
316
  const text = buildLineTextFromRange(
@@ -322,12 +325,12 @@ export function layoutNextLine(
322
325
 
323
326
  export function layoutNextLineRange(
324
327
  prepared ,
325
- start ,
326
328
  maxWidth ,
329
+ start = TEXT_START_CURSOR,
327
330
  ) {
328
331
  const lineStart = { segmentIndex: 0, graphemeIndex: 0 }
329
332
  const end = { segmentIndex: 0, graphemeIndex: 0 }
330
- const width = stepNextLine(prepared, start, maxWidth, lineStart, end)
333
+ const width = stepNextLine(prepared, maxWidth, start, lineStart, end)
331
334
  return width === null ? null : { width, start: lineStart, end }
332
335
  }
333
336