@quartzds/core 1.0.0-beta.123 → 1.0.0-beta.125

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 (190) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/components/index.js +1 -1
  3. package/components/{p-BvRd7jA2.js → p-2tdMcXmA.js} +5 -5
  4. package/components/{p-BvRd7jA2.js.map → p-2tdMcXmA.js.map} +1 -1
  5. package/components/{p-CVuTVnQo.js → p-B6ToH-uM.js} +4 -4
  6. package/components/p-B6ToH-uM.js.map +1 -0
  7. package/components/{p-C93kOEAe.js → p-BRpaYGSM.js} +5 -5
  8. package/components/{p-C93kOEAe.js.map → p-BRpaYGSM.js.map} +1 -1
  9. package/components/{p-CbY4T0d2.js → p-B_CYrw-t.js} +3 -3
  10. package/components/{p-CbY4T0d2.js.map → p-B_CYrw-t.js.map} +1 -1
  11. package/components/{p-BoSYRCNp.js → p-BceRDckL.js} +4 -4
  12. package/components/{p-BoSYRCNp.js.map → p-BceRDckL.js.map} +1 -1
  13. package/components/{p-BZlKeCFb.js → p-BuCcV5P1.js} +9 -9
  14. package/components/p-BuCcV5P1.js.map +1 -0
  15. package/components/{p-B7s906mS.js → p-CG_jPYOl.js} +5 -5
  16. package/components/{p-B7s906mS.js.map → p-CG_jPYOl.js.map} +1 -1
  17. package/components/p-CaibVX_2.js +3539 -0
  18. package/components/p-CaibVX_2.js.map +1 -0
  19. package/components/{p-CowZ-pDD.js → p-CgQQYnEy.js} +75 -39
  20. package/components/p-CgQQYnEy.js.map +1 -0
  21. package/components/{p-yb0Kv4Y6.js → p-DTMrBXCl.js} +24 -9
  22. package/components/p-DTMrBXCl.js.map +1 -0
  23. package/components/{p-C9R8N06B.js → p-EjoVBa5a.js} +3 -3
  24. package/components/{p-C9R8N06B.js.map → p-EjoVBa5a.js.map} +1 -1
  25. package/components/{p-CKp062X8.js → p-ox2syNht.js} +6 -6
  26. package/components/{p-CKp062X8.js.map → p-ox2syNht.js.map} +1 -1
  27. package/components/qds-action-item.js +3 -3
  28. package/components/qds-avatar-media.js +1 -1
  29. package/components/qds-breadcrumb-item.js +11 -6
  30. package/components/qds-breadcrumb-item.js.map +1 -1
  31. package/components/qds-button.js +9 -9
  32. package/components/qds-button.js.map +1 -1
  33. package/components/qds-checkbox.js +1 -1
  34. package/components/qds-chip.js +5 -5
  35. package/components/qds-chip.js.map +1 -1
  36. package/components/qds-dialog.js +5 -5
  37. package/components/qds-dialog.js.map +1 -1
  38. package/components/qds-divider.js +1 -1
  39. package/components/qds-dropdown.js +1 -1
  40. package/components/qds-form-message.js +23 -17
  41. package/components/qds-form-message.js.map +1 -1
  42. package/components/qds-icon-button.js +1 -1
  43. package/components/qds-icon-tab.js +4 -4
  44. package/components/qds-icon.js +1 -1
  45. package/components/qds-inline-link.js +5 -5
  46. package/components/qds-inline-link.js.map +1 -1
  47. package/components/qds-input.js +3 -3
  48. package/components/qds-label.js +2 -2
  49. package/components/qds-list-item.js +16 -13
  50. package/components/qds-list-item.js.map +1 -1
  51. package/components/qds-loader.js +1 -1
  52. package/components/qds-menu-item.js +38 -12
  53. package/components/qds-menu-item.js.map +1 -1
  54. package/components/qds-mini-button.js +1 -1
  55. package/components/qds-progress-bar.js +1 -1
  56. package/components/qds-radio.js +1 -1
  57. package/components/qds-select.js +3 -3
  58. package/components/qds-standalone-link.js +4 -4
  59. package/components/qds-switch.js +6 -6
  60. package/components/qds-switch.js.map +1 -1
  61. package/components/qds-tab.js +7 -7
  62. package/components/qds-tabbar.js +59 -38
  63. package/components/qds-tabbar.js.map +1 -1
  64. package/components/qds-table-cell.js +2 -2
  65. package/components/qds-table-head-cell.js +2 -2
  66. package/components/qds-table-row.js +1 -1
  67. package/components/qds-table.js +1 -1
  68. package/components/qds-tag.js +1 -1
  69. package/components/qds-textarea.js +3 -3
  70. package/components/qds-title.js +1 -1
  71. package/components/qds-tooltip.js +1 -1
  72. package/dist/cjs/helpers-DjUgyTKn.js +3559 -0
  73. package/dist/cjs/helpers-DjUgyTKn.js.map +1 -0
  74. package/dist/cjs/loader.cjs.js +1 -1
  75. package/dist/cjs/qds-action-item.cjs.entry.js +1 -1
  76. package/dist/cjs/qds-avatar-media.qds-checkbox.qds-radio.entry.cjs.js.map +1 -1
  77. package/dist/cjs/qds-avatar-media_3.cjs.entry.js +72 -36
  78. package/dist/cjs/qds-breadcrumb-item.cjs.entry.js +9 -4
  79. package/dist/cjs/qds-breadcrumb-item.entry.cjs.js.map +1 -1
  80. package/dist/cjs/qds-button.cjs.entry.js +7 -7
  81. package/dist/cjs/qds-button.entry.cjs.js.map +1 -1
  82. package/dist/cjs/qds-chip.cjs.entry.js +2 -2
  83. package/dist/cjs/qds-chip.entry.cjs.js.map +1 -1
  84. package/dist/cjs/qds-dialog.cjs.entry.js +2 -2
  85. package/dist/cjs/qds-dialog.entry.cjs.js.map +1 -1
  86. package/dist/cjs/qds-divider.qds-icon-button.entry.cjs.js.map +1 -1
  87. package/dist/cjs/qds-divider_2.cjs.entry.js +3 -3
  88. package/dist/cjs/qds-dropdown.cjs.entry.js +20 -6
  89. package/dist/cjs/qds-dropdown.entry.cjs.js.map +1 -1
  90. package/dist/cjs/qds-form-message.cjs.entry.js +26 -16
  91. package/dist/cjs/qds-form-message.entry.cjs.js.map +1 -1
  92. package/dist/cjs/qds-icon-tab.cjs.entry.js +1 -1
  93. package/dist/cjs/qds-icon.cjs.entry.js +1 -1
  94. package/dist/cjs/qds-inline-link.cjs.entry.js +4 -4
  95. package/dist/cjs/qds-inline-link.entry.cjs.js.map +1 -1
  96. package/dist/cjs/qds-input.cjs.entry.js +1 -1
  97. package/dist/cjs/qds-label.cjs.entry.js +1 -1
  98. package/dist/cjs/qds-list-item.cjs.entry.js +8 -5
  99. package/dist/cjs/qds-list-item.entry.cjs.js.map +1 -1
  100. package/dist/cjs/qds-menu-item.cjs.entry.js +34 -8
  101. package/dist/cjs/qds-menu-item.entry.cjs.js.map +1 -1
  102. package/dist/cjs/qds-mini-button.cjs.entry.js +2 -2
  103. package/dist/cjs/qds-progress-bar.cjs.entry.js +1 -1
  104. package/dist/cjs/qds-select.cjs.entry.js +2 -2
  105. package/dist/cjs/qds-standalone-link.cjs.entry.js +3 -3
  106. package/dist/cjs/qds-switch.cjs.entry.js +5 -5
  107. package/dist/cjs/qds-switch.entry.cjs.js.map +1 -1
  108. package/dist/cjs/qds-tab.cjs.entry.js +4 -4
  109. package/dist/cjs/qds-tabbar.cjs.entry.js +57 -33
  110. package/dist/cjs/qds-tabbar.entry.cjs.js.map +1 -1
  111. package/dist/cjs/qds-table-cell.cjs.entry.js +2 -2
  112. package/dist/cjs/qds-table-head-cell.cjs.entry.js +2 -2
  113. package/dist/cjs/qds-table-row.cjs.entry.js +1 -1
  114. package/dist/cjs/qds-table.cjs.entry.js +1 -1
  115. package/dist/cjs/qds-tag.cjs.entry.js +3 -3
  116. package/dist/cjs/qds-textarea.cjs.entry.js +3 -3
  117. package/dist/cjs/qds-title.cjs.entry.js +2 -2
  118. package/dist/cjs/qds-tooltip.cjs.entry.js +1 -1
  119. package/dist/cjs/qds.cjs.js +1 -1
  120. package/dist/custom-elements.json +224 -70
  121. package/dist/docs.json +48 -6
  122. package/dist/esm/helpers-mPQzhx-O.js +3539 -0
  123. package/dist/esm/helpers-mPQzhx-O.js.map +1 -0
  124. package/dist/esm/loader.js +1 -1
  125. package/dist/esm/qds-action-item.entry.js +1 -1
  126. package/dist/esm/qds-avatar-media.qds-checkbox.qds-radio.entry.js.map +1 -1
  127. package/dist/esm/qds-avatar-media_3.entry.js +72 -36
  128. package/dist/esm/qds-breadcrumb-item.entry.js +9 -4
  129. package/dist/esm/qds-breadcrumb-item.entry.js.map +1 -1
  130. package/dist/esm/qds-button.entry.js +7 -7
  131. package/dist/esm/qds-button.entry.js.map +1 -1
  132. package/dist/esm/qds-chip.entry.js +2 -2
  133. package/dist/esm/qds-chip.entry.js.map +1 -1
  134. package/dist/esm/qds-dialog.entry.js +2 -2
  135. package/dist/esm/qds-dialog.entry.js.map +1 -1
  136. package/dist/esm/qds-divider.qds-icon-button.entry.js.map +1 -1
  137. package/dist/esm/qds-divider_2.entry.js +3 -3
  138. package/dist/esm/qds-dropdown.entry.js +20 -6
  139. package/dist/esm/qds-dropdown.entry.js.map +1 -1
  140. package/dist/esm/qds-form-message.entry.js +26 -16
  141. package/dist/esm/qds-form-message.entry.js.map +1 -1
  142. package/dist/esm/qds-icon-tab.entry.js +1 -1
  143. package/dist/esm/qds-icon.entry.js +1 -1
  144. package/dist/esm/qds-inline-link.entry.js +4 -4
  145. package/dist/esm/qds-inline-link.entry.js.map +1 -1
  146. package/dist/esm/qds-input.entry.js +1 -1
  147. package/dist/esm/qds-label.entry.js +1 -1
  148. package/dist/esm/qds-list-item.entry.js +8 -5
  149. package/dist/esm/qds-list-item.entry.js.map +1 -1
  150. package/dist/esm/qds-menu-item.entry.js +34 -8
  151. package/dist/esm/qds-menu-item.entry.js.map +1 -1
  152. package/dist/esm/qds-mini-button.entry.js +2 -2
  153. package/dist/esm/qds-progress-bar.entry.js +1 -1
  154. package/dist/esm/qds-select.entry.js +2 -2
  155. package/dist/esm/qds-standalone-link.entry.js +3 -3
  156. package/dist/esm/qds-switch.entry.js +5 -5
  157. package/dist/esm/qds-switch.entry.js.map +1 -1
  158. package/dist/esm/qds-tab.entry.js +4 -4
  159. package/dist/esm/qds-tabbar.entry.js +57 -33
  160. package/dist/esm/qds-tabbar.entry.js.map +1 -1
  161. package/dist/esm/qds-table-cell.entry.js +2 -2
  162. package/dist/esm/qds-table-head-cell.entry.js +2 -2
  163. package/dist/esm/qds-table-row.entry.js +1 -1
  164. package/dist/esm/qds-table.entry.js +1 -1
  165. package/dist/esm/qds-tag.entry.js +3 -3
  166. package/dist/esm/qds-textarea.entry.js +3 -3
  167. package/dist/esm/qds-title.entry.js +2 -2
  168. package/dist/esm/qds-tooltip.entry.js +1 -1
  169. package/dist/esm/qds.js +1 -1
  170. package/dist/types/components/checkbox/checkbox.d.ts +9 -9
  171. package/dist/types/components/dropdown/dropdown.d.ts +1 -0
  172. package/dist/types/components/form-message/form-message.d.ts +2 -0
  173. package/dist/types/components/menu-item/menu-item.d.ts +1 -0
  174. package/dist/types/components/tabbar/tabbar.d.ts +2 -0
  175. package/dist/types/components.d.ts +3 -2
  176. package/dist/types/helpers.d.ts +6 -1
  177. package/dist/vscode.html-custom-data.json +1 -1
  178. package/hydrate/index.js +3560 -193
  179. package/hydrate/index.mjs +3560 -193
  180. package/package.json +2 -1
  181. package/components/p-BZlKeCFb.js.map +0 -1
  182. package/components/p-BalM52S_.js +0 -291
  183. package/components/p-BalM52S_.js.map +0 -1
  184. package/components/p-CVuTVnQo.js.map +0 -1
  185. package/components/p-CowZ-pDD.js.map +0 -1
  186. package/components/p-yb0Kv4Y6.js.map +0 -1
  187. package/dist/cjs/helpers-Qs3cpKiI.js +0 -308
  188. package/dist/cjs/helpers-Qs3cpKiI.js.map +0 -1
  189. package/dist/esm/helpers-Fe2AA6uo.js +0 -291
  190. package/dist/esm/helpers-Fe2AA6uo.js.map +0 -1
@@ -0,0 +1,3539 @@
1
+ /*!
2
+ * SPDX-FileCopyrightText: © 2026 Schneider Electric
3
+ *
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ // Generated by scripts/generate-bidi-data.ts from scripts/unicode/DerivedBidiClass-17.0.0.txt.
7
+ // Do not edit by hand. Regenerate with `bun run generate:bidi-data`.
8
+ // Formatting and isolate controls are projected onto `BN` because the rich
9
+ // bidi helper consumes a simplified class set and does not model UBA isolates.
10
+ const latin1BidiTypes = [
11
+ 'BN',
12
+ 'BN',
13
+ 'BN',
14
+ 'BN',
15
+ 'BN',
16
+ 'BN',
17
+ 'BN',
18
+ 'BN',
19
+ 'BN',
20
+ 'S',
21
+ 'B',
22
+ 'S',
23
+ 'WS',
24
+ 'B',
25
+ 'BN',
26
+ 'BN',
27
+ 'BN',
28
+ 'BN',
29
+ 'BN',
30
+ 'BN',
31
+ 'BN',
32
+ 'BN',
33
+ 'BN',
34
+ 'BN',
35
+ 'BN',
36
+ 'BN',
37
+ 'BN',
38
+ 'BN',
39
+ 'B',
40
+ 'B',
41
+ 'B',
42
+ 'S',
43
+ 'WS',
44
+ 'ON',
45
+ 'ON',
46
+ 'ET',
47
+ 'ET',
48
+ 'ET',
49
+ 'ON',
50
+ 'ON',
51
+ 'ON',
52
+ 'ON',
53
+ 'ON',
54
+ 'ES',
55
+ 'CS',
56
+ 'ES',
57
+ 'CS',
58
+ 'CS',
59
+ 'EN',
60
+ 'EN',
61
+ 'EN',
62
+ 'EN',
63
+ 'EN',
64
+ 'EN',
65
+ 'EN',
66
+ 'EN',
67
+ 'EN',
68
+ 'EN',
69
+ 'CS',
70
+ 'ON',
71
+ 'ON',
72
+ 'ON',
73
+ 'ON',
74
+ 'ON',
75
+ 'ON',
76
+ 'L',
77
+ 'L',
78
+ 'L',
79
+ 'L',
80
+ 'L',
81
+ 'L',
82
+ 'L',
83
+ 'L',
84
+ 'L',
85
+ 'L',
86
+ 'L',
87
+ 'L',
88
+ 'L',
89
+ 'L',
90
+ 'L',
91
+ 'L',
92
+ 'L',
93
+ 'L',
94
+ 'L',
95
+ 'L',
96
+ 'L',
97
+ 'L',
98
+ 'L',
99
+ 'L',
100
+ 'L',
101
+ 'L',
102
+ 'ON',
103
+ 'ON',
104
+ 'ON',
105
+ 'ON',
106
+ 'ON',
107
+ 'ON',
108
+ 'L',
109
+ 'L',
110
+ 'L',
111
+ 'L',
112
+ 'L',
113
+ 'L',
114
+ 'L',
115
+ 'L',
116
+ 'L',
117
+ 'L',
118
+ 'L',
119
+ 'L',
120
+ 'L',
121
+ 'L',
122
+ 'L',
123
+ 'L',
124
+ 'L',
125
+ 'L',
126
+ 'L',
127
+ 'L',
128
+ 'L',
129
+ 'L',
130
+ 'L',
131
+ 'L',
132
+ 'L',
133
+ 'L',
134
+ 'ON',
135
+ 'ON',
136
+ 'ON',
137
+ 'ON',
138
+ 'BN',
139
+ 'BN',
140
+ 'BN',
141
+ 'BN',
142
+ 'BN',
143
+ 'BN',
144
+ 'B',
145
+ 'BN',
146
+ 'BN',
147
+ 'BN',
148
+ 'BN',
149
+ 'BN',
150
+ 'BN',
151
+ 'BN',
152
+ 'BN',
153
+ 'BN',
154
+ 'BN',
155
+ 'BN',
156
+ 'BN',
157
+ 'BN',
158
+ 'BN',
159
+ 'BN',
160
+ 'BN',
161
+ 'BN',
162
+ 'BN',
163
+ 'BN',
164
+ 'BN',
165
+ 'BN',
166
+ 'BN',
167
+ 'BN',
168
+ 'BN',
169
+ 'BN',
170
+ 'BN',
171
+ 'CS',
172
+ 'ON',
173
+ 'ET',
174
+ 'ET',
175
+ 'ET',
176
+ 'ET',
177
+ 'ON',
178
+ 'ON',
179
+ 'ON',
180
+ 'ON',
181
+ 'L',
182
+ 'ON',
183
+ 'ON',
184
+ 'BN',
185
+ 'ON',
186
+ 'ON',
187
+ 'ET',
188
+ 'ET',
189
+ 'EN',
190
+ 'EN',
191
+ 'ON',
192
+ 'L',
193
+ 'ON',
194
+ 'ON',
195
+ 'ON',
196
+ 'EN',
197
+ 'L',
198
+ 'ON',
199
+ 'ON',
200
+ 'ON',
201
+ 'ON',
202
+ 'ON',
203
+ 'L',
204
+ 'L',
205
+ 'L',
206
+ 'L',
207
+ 'L',
208
+ 'L',
209
+ 'L',
210
+ 'L',
211
+ 'L',
212
+ 'L',
213
+ 'L',
214
+ 'L',
215
+ 'L',
216
+ 'L',
217
+ 'L',
218
+ 'L',
219
+ 'L',
220
+ 'L',
221
+ 'L',
222
+ 'L',
223
+ 'L',
224
+ 'L',
225
+ 'L',
226
+ 'ON',
227
+ 'L',
228
+ 'L',
229
+ 'L',
230
+ 'L',
231
+ 'L',
232
+ 'L',
233
+ 'L',
234
+ 'L',
235
+ 'L',
236
+ 'L',
237
+ 'L',
238
+ 'L',
239
+ 'L',
240
+ 'L',
241
+ 'L',
242
+ 'L',
243
+ 'L',
244
+ 'L',
245
+ 'L',
246
+ 'L',
247
+ 'L',
248
+ 'L',
249
+ 'L',
250
+ 'L',
251
+ 'L',
252
+ 'L',
253
+ 'L',
254
+ 'L',
255
+ 'L',
256
+ 'L',
257
+ 'L',
258
+ 'ON',
259
+ 'L',
260
+ 'L',
261
+ 'L',
262
+ 'L',
263
+ 'L',
264
+ 'L',
265
+ 'L',
266
+ 'L',
267
+ ];
268
+ const nonLatin1BidiRanges = [
269
+ [0x2B9, 0x2BA, 'ON'],
270
+ [0x2C2, 0x2CF, 'ON'],
271
+ [0x2D2, 0x2DF, 'ON'],
272
+ [0x2E5, 0x2ED, 'ON'],
273
+ [0x2EF, 0x2FF, 'ON'],
274
+ [0x300, 0x36F, 'NSM'],
275
+ [0x374, 0x375, 'ON'],
276
+ [0x37E, 0x37E, 'ON'],
277
+ [0x384, 0x385, 'ON'],
278
+ [0x387, 0x387, 'ON'],
279
+ [0x3F6, 0x3F6, 'ON'],
280
+ [0x483, 0x489, 'NSM'],
281
+ [0x58A, 0x58A, 'ON'],
282
+ [0x58D, 0x58E, 'ON'],
283
+ [0x58F, 0x58F, 'ET'],
284
+ [0x590, 0x590, 'R'],
285
+ [0x591, 0x5BD, 'NSM'],
286
+ [0x5BE, 0x5BE, 'R'],
287
+ [0x5BF, 0x5BF, 'NSM'],
288
+ [0x5C0, 0x5C0, 'R'],
289
+ [0x5C1, 0x5C2, 'NSM'],
290
+ [0x5C3, 0x5C3, 'R'],
291
+ [0x5C4, 0x5C5, 'NSM'],
292
+ [0x5C6, 0x5C6, 'R'],
293
+ [0x5C7, 0x5C7, 'NSM'],
294
+ [0x5C8, 0x5FF, 'R'],
295
+ [0x600, 0x605, 'AN'],
296
+ [0x606, 0x607, 'ON'],
297
+ [0x608, 0x608, 'AL'],
298
+ [0x609, 0x60A, 'ET'],
299
+ [0x60B, 0x60B, 'AL'],
300
+ [0x60C, 0x60C, 'CS'],
301
+ [0x60D, 0x60D, 'AL'],
302
+ [0x60E, 0x60F, 'ON'],
303
+ [0x610, 0x61A, 'NSM'],
304
+ [0x61B, 0x64A, 'AL'],
305
+ [0x64B, 0x65F, 'NSM'],
306
+ [0x660, 0x669, 'AN'],
307
+ [0x66A, 0x66A, 'ET'],
308
+ [0x66B, 0x66C, 'AN'],
309
+ [0x66D, 0x66F, 'AL'],
310
+ [0x670, 0x670, 'NSM'],
311
+ [0x671, 0x6D5, 'AL'],
312
+ [0x6D6, 0x6DC, 'NSM'],
313
+ [0x6DD, 0x6DD, 'AN'],
314
+ [0x6DE, 0x6DE, 'ON'],
315
+ [0x6DF, 0x6E4, 'NSM'],
316
+ [0x6E5, 0x6E6, 'AL'],
317
+ [0x6E7, 0x6E8, 'NSM'],
318
+ [0x6E9, 0x6E9, 'ON'],
319
+ [0x6EA, 0x6ED, 'NSM'],
320
+ [0x6EE, 0x6EF, 'AL'],
321
+ [0x6F0, 0x6F9, 'EN'],
322
+ [0x6FA, 0x710, 'AL'],
323
+ [0x711, 0x711, 'NSM'],
324
+ [0x712, 0x72F, 'AL'],
325
+ [0x730, 0x74A, 'NSM'],
326
+ [0x74B, 0x7A5, 'AL'],
327
+ [0x7A6, 0x7B0, 'NSM'],
328
+ [0x7B1, 0x7BF, 'AL'],
329
+ [0x7C0, 0x7EA, 'R'],
330
+ [0x7EB, 0x7F3, 'NSM'],
331
+ [0x7F4, 0x7F5, 'R'],
332
+ [0x7F6, 0x7F9, 'ON'],
333
+ [0x7FA, 0x7FC, 'R'],
334
+ [0x7FD, 0x7FD, 'NSM'],
335
+ [0x7FE, 0x815, 'R'],
336
+ [0x816, 0x819, 'NSM'],
337
+ [0x81A, 0x81A, 'R'],
338
+ [0x81B, 0x823, 'NSM'],
339
+ [0x824, 0x824, 'R'],
340
+ [0x825, 0x827, 'NSM'],
341
+ [0x828, 0x828, 'R'],
342
+ [0x829, 0x82D, 'NSM'],
343
+ [0x82E, 0x858, 'R'],
344
+ [0x859, 0x85B, 'NSM'],
345
+ [0x85C, 0x85F, 'R'],
346
+ [0x860, 0x88F, 'AL'],
347
+ [0x890, 0x891, 'AN'],
348
+ [0x892, 0x896, 'AL'],
349
+ [0x897, 0x89F, 'NSM'],
350
+ [0x8A0, 0x8C9, 'AL'],
351
+ [0x8CA, 0x8E1, 'NSM'],
352
+ [0x8E2, 0x8E2, 'AN'],
353
+ [0x8E3, 0x902, 'NSM'],
354
+ [0x93A, 0x93A, 'NSM'],
355
+ [0x93C, 0x93C, 'NSM'],
356
+ [0x941, 0x948, 'NSM'],
357
+ [0x94D, 0x94D, 'NSM'],
358
+ [0x951, 0x957, 'NSM'],
359
+ [0x962, 0x963, 'NSM'],
360
+ [0x981, 0x981, 'NSM'],
361
+ [0x9BC, 0x9BC, 'NSM'],
362
+ [0x9C1, 0x9C4, 'NSM'],
363
+ [0x9CD, 0x9CD, 'NSM'],
364
+ [0x9E2, 0x9E3, 'NSM'],
365
+ [0x9F2, 0x9F3, 'ET'],
366
+ [0x9FB, 0x9FB, 'ET'],
367
+ [0x9FE, 0x9FE, 'NSM'],
368
+ [0xA01, 0xA02, 'NSM'],
369
+ [0xA3C, 0xA3C, 'NSM'],
370
+ [0xA41, 0xA42, 'NSM'],
371
+ [0xA47, 0xA48, 'NSM'],
372
+ [0xA4B, 0xA4D, 'NSM'],
373
+ [0xA51, 0xA51, 'NSM'],
374
+ [0xA70, 0xA71, 'NSM'],
375
+ [0xA75, 0xA75, 'NSM'],
376
+ [0xA81, 0xA82, 'NSM'],
377
+ [0xABC, 0xABC, 'NSM'],
378
+ [0xAC1, 0xAC5, 'NSM'],
379
+ [0xAC7, 0xAC8, 'NSM'],
380
+ [0xACD, 0xACD, 'NSM'],
381
+ [0xAE2, 0xAE3, 'NSM'],
382
+ [0xAF1, 0xAF1, 'ET'],
383
+ [0xAFA, 0xAFF, 'NSM'],
384
+ [0xB01, 0xB01, 'NSM'],
385
+ [0xB3C, 0xB3C, 'NSM'],
386
+ [0xB3F, 0xB3F, 'NSM'],
387
+ [0xB41, 0xB44, 'NSM'],
388
+ [0xB4D, 0xB4D, 'NSM'],
389
+ [0xB55, 0xB56, 'NSM'],
390
+ [0xB62, 0xB63, 'NSM'],
391
+ [0xB82, 0xB82, 'NSM'],
392
+ [0xBC0, 0xBC0, 'NSM'],
393
+ [0xBCD, 0xBCD, 'NSM'],
394
+ [0xBF3, 0xBF8, 'ON'],
395
+ [0xBF9, 0xBF9, 'ET'],
396
+ [0xBFA, 0xBFA, 'ON'],
397
+ [0xC00, 0xC00, 'NSM'],
398
+ [0xC04, 0xC04, 'NSM'],
399
+ [0xC3C, 0xC3C, 'NSM'],
400
+ [0xC3E, 0xC40, 'NSM'],
401
+ [0xC46, 0xC48, 'NSM'],
402
+ [0xC4A, 0xC4D, 'NSM'],
403
+ [0xC55, 0xC56, 'NSM'],
404
+ [0xC62, 0xC63, 'NSM'],
405
+ [0xC78, 0xC7E, 'ON'],
406
+ [0xC81, 0xC81, 'NSM'],
407
+ [0xCBC, 0xCBC, 'NSM'],
408
+ [0xCCC, 0xCCD, 'NSM'],
409
+ [0xCE2, 0xCE3, 'NSM'],
410
+ [0xD00, 0xD01, 'NSM'],
411
+ [0xD3B, 0xD3C, 'NSM'],
412
+ [0xD41, 0xD44, 'NSM'],
413
+ [0xD4D, 0xD4D, 'NSM'],
414
+ [0xD62, 0xD63, 'NSM'],
415
+ [0xD81, 0xD81, 'NSM'],
416
+ [0xDCA, 0xDCA, 'NSM'],
417
+ [0xDD2, 0xDD4, 'NSM'],
418
+ [0xDD6, 0xDD6, 'NSM'],
419
+ [0xE31, 0xE31, 'NSM'],
420
+ [0xE34, 0xE3A, 'NSM'],
421
+ [0xE3F, 0xE3F, 'ET'],
422
+ [0xE47, 0xE4E, 'NSM'],
423
+ [0xEB1, 0xEB1, 'NSM'],
424
+ [0xEB4, 0xEBC, 'NSM'],
425
+ [0xEC8, 0xECE, 'NSM'],
426
+ [0xF18, 0xF19, 'NSM'],
427
+ [0xF35, 0xF35, 'NSM'],
428
+ [0xF37, 0xF37, 'NSM'],
429
+ [0xF39, 0xF39, 'NSM'],
430
+ [0xF3A, 0xF3D, 'ON'],
431
+ [0xF71, 0xF7E, 'NSM'],
432
+ [0xF80, 0xF84, 'NSM'],
433
+ [0xF86, 0xF87, 'NSM'],
434
+ [0xF8D, 0xF97, 'NSM'],
435
+ [0xF99, 0xFBC, 'NSM'],
436
+ [0xFC6, 0xFC6, 'NSM'],
437
+ [0x102D, 0x1030, 'NSM'],
438
+ [0x1032, 0x1037, 'NSM'],
439
+ [0x1039, 0x103A, 'NSM'],
440
+ [0x103D, 0x103E, 'NSM'],
441
+ [0x1058, 0x1059, 'NSM'],
442
+ [0x105E, 0x1060, 'NSM'],
443
+ [0x1071, 0x1074, 'NSM'],
444
+ [0x1082, 0x1082, 'NSM'],
445
+ [0x1085, 0x1086, 'NSM'],
446
+ [0x108D, 0x108D, 'NSM'],
447
+ [0x109D, 0x109D, 'NSM'],
448
+ [0x135D, 0x135F, 'NSM'],
449
+ [0x1390, 0x1399, 'ON'],
450
+ [0x1400, 0x1400, 'ON'],
451
+ [0x1680, 0x1680, 'WS'],
452
+ [0x169B, 0x169C, 'ON'],
453
+ [0x1712, 0x1714, 'NSM'],
454
+ [0x1732, 0x1733, 'NSM'],
455
+ [0x1752, 0x1753, 'NSM'],
456
+ [0x1772, 0x1773, 'NSM'],
457
+ [0x17B4, 0x17B5, 'NSM'],
458
+ [0x17B7, 0x17BD, 'NSM'],
459
+ [0x17C6, 0x17C6, 'NSM'],
460
+ [0x17C9, 0x17D3, 'NSM'],
461
+ [0x17DB, 0x17DB, 'ET'],
462
+ [0x17DD, 0x17DD, 'NSM'],
463
+ [0x17F0, 0x17F9, 'ON'],
464
+ [0x1800, 0x180A, 'ON'],
465
+ [0x180B, 0x180D, 'NSM'],
466
+ [0x180E, 0x180E, 'BN'],
467
+ [0x180F, 0x180F, 'NSM'],
468
+ [0x1885, 0x1886, 'NSM'],
469
+ [0x18A9, 0x18A9, 'NSM'],
470
+ [0x1920, 0x1922, 'NSM'],
471
+ [0x1927, 0x1928, 'NSM'],
472
+ [0x1932, 0x1932, 'NSM'],
473
+ [0x1939, 0x193B, 'NSM'],
474
+ [0x1940, 0x1940, 'ON'],
475
+ [0x1944, 0x1945, 'ON'],
476
+ [0x19DE, 0x19FF, 'ON'],
477
+ [0x1A17, 0x1A18, 'NSM'],
478
+ [0x1A1B, 0x1A1B, 'NSM'],
479
+ [0x1A56, 0x1A56, 'NSM'],
480
+ [0x1A58, 0x1A5E, 'NSM'],
481
+ [0x1A60, 0x1A60, 'NSM'],
482
+ [0x1A62, 0x1A62, 'NSM'],
483
+ [0x1A65, 0x1A6C, 'NSM'],
484
+ [0x1A73, 0x1A7C, 'NSM'],
485
+ [0x1A7F, 0x1A7F, 'NSM'],
486
+ [0x1AB0, 0x1ADD, 'NSM'],
487
+ [0x1AE0, 0x1AEB, 'NSM'],
488
+ [0x1B00, 0x1B03, 'NSM'],
489
+ [0x1B34, 0x1B34, 'NSM'],
490
+ [0x1B36, 0x1B3A, 'NSM'],
491
+ [0x1B3C, 0x1B3C, 'NSM'],
492
+ [0x1B42, 0x1B42, 'NSM'],
493
+ [0x1B6B, 0x1B73, 'NSM'],
494
+ [0x1B80, 0x1B81, 'NSM'],
495
+ [0x1BA2, 0x1BA5, 'NSM'],
496
+ [0x1BA8, 0x1BA9, 'NSM'],
497
+ [0x1BAB, 0x1BAD, 'NSM'],
498
+ [0x1BE6, 0x1BE6, 'NSM'],
499
+ [0x1BE8, 0x1BE9, 'NSM'],
500
+ [0x1BED, 0x1BED, 'NSM'],
501
+ [0x1BEF, 0x1BF1, 'NSM'],
502
+ [0x1C2C, 0x1C33, 'NSM'],
503
+ [0x1C36, 0x1C37, 'NSM'],
504
+ [0x1CD0, 0x1CD2, 'NSM'],
505
+ [0x1CD4, 0x1CE0, 'NSM'],
506
+ [0x1CE2, 0x1CE8, 'NSM'],
507
+ [0x1CED, 0x1CED, 'NSM'],
508
+ [0x1CF4, 0x1CF4, 'NSM'],
509
+ [0x1CF8, 0x1CF9, 'NSM'],
510
+ [0x1DC0, 0x1DFF, 'NSM'],
511
+ [0x1FBD, 0x1FBD, 'ON'],
512
+ [0x1FBF, 0x1FC1, 'ON'],
513
+ [0x1FCD, 0x1FCF, 'ON'],
514
+ [0x1FDD, 0x1FDF, 'ON'],
515
+ [0x1FED, 0x1FEF, 'ON'],
516
+ [0x1FFD, 0x1FFE, 'ON'],
517
+ [0x2000, 0x200A, 'WS'],
518
+ [0x200B, 0x200D, 'BN'],
519
+ [0x200F, 0x200F, 'R'],
520
+ [0x2010, 0x2027, 'ON'],
521
+ [0x2028, 0x2028, 'WS'],
522
+ [0x2029, 0x2029, 'B'],
523
+ [0x202A, 0x202E, 'BN'],
524
+ [0x202F, 0x202F, 'CS'],
525
+ [0x2030, 0x2034, 'ET'],
526
+ [0x2035, 0x2043, 'ON'],
527
+ [0x2044, 0x2044, 'CS'],
528
+ [0x2045, 0x205E, 'ON'],
529
+ [0x205F, 0x205F, 'WS'],
530
+ [0x2060, 0x206F, 'BN'],
531
+ [0x2070, 0x2070, 'EN'],
532
+ [0x2074, 0x2079, 'EN'],
533
+ [0x207A, 0x207B, 'ES'],
534
+ [0x207C, 0x207E, 'ON'],
535
+ [0x2080, 0x2089, 'EN'],
536
+ [0x208A, 0x208B, 'ES'],
537
+ [0x208C, 0x208E, 'ON'],
538
+ [0x20A0, 0x20CF, 'ET'],
539
+ [0x20D0, 0x20F0, 'NSM'],
540
+ [0x2100, 0x2101, 'ON'],
541
+ [0x2103, 0x2106, 'ON'],
542
+ [0x2108, 0x2109, 'ON'],
543
+ [0x2114, 0x2114, 'ON'],
544
+ [0x2116, 0x2118, 'ON'],
545
+ [0x211E, 0x2123, 'ON'],
546
+ [0x2125, 0x2125, 'ON'],
547
+ [0x2127, 0x2127, 'ON'],
548
+ [0x2129, 0x2129, 'ON'],
549
+ [0x212E, 0x212E, 'ET'],
550
+ [0x213A, 0x213B, 'ON'],
551
+ [0x2140, 0x2144, 'ON'],
552
+ [0x214A, 0x214D, 'ON'],
553
+ [0x2150, 0x215F, 'ON'],
554
+ [0x2189, 0x218B, 'ON'],
555
+ [0x2190, 0x2211, 'ON'],
556
+ [0x2212, 0x2212, 'ES'],
557
+ [0x2213, 0x2213, 'ET'],
558
+ [0x2214, 0x2335, 'ON'],
559
+ [0x237B, 0x2394, 'ON'],
560
+ [0x2396, 0x2429, 'ON'],
561
+ [0x2440, 0x244A, 'ON'],
562
+ [0x2460, 0x2487, 'ON'],
563
+ [0x2488, 0x249B, 'EN'],
564
+ [0x24EA, 0x26AB, 'ON'],
565
+ [0x26AD, 0x27FF, 'ON'],
566
+ [0x2900, 0x2B73, 'ON'],
567
+ [0x2B76, 0x2BFF, 'ON'],
568
+ [0x2CE5, 0x2CEA, 'ON'],
569
+ [0x2CEF, 0x2CF1, 'NSM'],
570
+ [0x2CF9, 0x2CFF, 'ON'],
571
+ [0x2D7F, 0x2D7F, 'NSM'],
572
+ [0x2DE0, 0x2DFF, 'NSM'],
573
+ [0x2E00, 0x2E5D, 'ON'],
574
+ [0x2E80, 0x2E99, 'ON'],
575
+ [0x2E9B, 0x2EF3, 'ON'],
576
+ [0x2F00, 0x2FD5, 'ON'],
577
+ [0x2FF0, 0x2FFF, 'ON'],
578
+ [0x3000, 0x3000, 'WS'],
579
+ [0x3001, 0x3004, 'ON'],
580
+ [0x3008, 0x3020, 'ON'],
581
+ [0x302A, 0x302D, 'NSM'],
582
+ [0x3030, 0x3030, 'ON'],
583
+ [0x3036, 0x3037, 'ON'],
584
+ [0x303D, 0x303F, 'ON'],
585
+ [0x3099, 0x309A, 'NSM'],
586
+ [0x309B, 0x309C, 'ON'],
587
+ [0x30A0, 0x30A0, 'ON'],
588
+ [0x30FB, 0x30FB, 'ON'],
589
+ [0x31C0, 0x31E5, 'ON'],
590
+ [0x31EF, 0x31EF, 'ON'],
591
+ [0x321D, 0x321E, 'ON'],
592
+ [0x3250, 0x325F, 'ON'],
593
+ [0x327C, 0x327E, 'ON'],
594
+ [0x32B1, 0x32BF, 'ON'],
595
+ [0x32CC, 0x32CF, 'ON'],
596
+ [0x3377, 0x337A, 'ON'],
597
+ [0x33DE, 0x33DF, 'ON'],
598
+ [0x33FF, 0x33FF, 'ON'],
599
+ [0x4DC0, 0x4DFF, 'ON'],
600
+ [0xA490, 0xA4C6, 'ON'],
601
+ [0xA60D, 0xA60F, 'ON'],
602
+ [0xA66F, 0xA672, 'NSM'],
603
+ [0xA673, 0xA673, 'ON'],
604
+ [0xA674, 0xA67D, 'NSM'],
605
+ [0xA67E, 0xA67F, 'ON'],
606
+ [0xA69E, 0xA69F, 'NSM'],
607
+ [0xA6F0, 0xA6F1, 'NSM'],
608
+ [0xA700, 0xA721, 'ON'],
609
+ [0xA788, 0xA788, 'ON'],
610
+ [0xA802, 0xA802, 'NSM'],
611
+ [0xA806, 0xA806, 'NSM'],
612
+ [0xA80B, 0xA80B, 'NSM'],
613
+ [0xA825, 0xA826, 'NSM'],
614
+ [0xA828, 0xA82B, 'ON'],
615
+ [0xA82C, 0xA82C, 'NSM'],
616
+ [0xA838, 0xA839, 'ET'],
617
+ [0xA874, 0xA877, 'ON'],
618
+ [0xA8C4, 0xA8C5, 'NSM'],
619
+ [0xA8E0, 0xA8F1, 'NSM'],
620
+ [0xA8FF, 0xA8FF, 'NSM'],
621
+ [0xA926, 0xA92D, 'NSM'],
622
+ [0xA947, 0xA951, 'NSM'],
623
+ [0xA980, 0xA982, 'NSM'],
624
+ [0xA9B3, 0xA9B3, 'NSM'],
625
+ [0xA9B6, 0xA9B9, 'NSM'],
626
+ [0xA9BC, 0xA9BD, 'NSM'],
627
+ [0xA9E5, 0xA9E5, 'NSM'],
628
+ [0xAA29, 0xAA2E, 'NSM'],
629
+ [0xAA31, 0xAA32, 'NSM'],
630
+ [0xAA35, 0xAA36, 'NSM'],
631
+ [0xAA43, 0xAA43, 'NSM'],
632
+ [0xAA4C, 0xAA4C, 'NSM'],
633
+ [0xAA7C, 0xAA7C, 'NSM'],
634
+ [0xAAB0, 0xAAB0, 'NSM'],
635
+ [0xAAB2, 0xAAB4, 'NSM'],
636
+ [0xAAB7, 0xAAB8, 'NSM'],
637
+ [0xAABE, 0xAABF, 'NSM'],
638
+ [0xAAC1, 0xAAC1, 'NSM'],
639
+ [0xAAEC, 0xAAED, 'NSM'],
640
+ [0xAAF6, 0xAAF6, 'NSM'],
641
+ [0xAB6A, 0xAB6B, 'ON'],
642
+ [0xABE5, 0xABE5, 'NSM'],
643
+ [0xABE8, 0xABE8, 'NSM'],
644
+ [0xABED, 0xABED, 'NSM'],
645
+ [0xFB1D, 0xFB1D, 'R'],
646
+ [0xFB1E, 0xFB1E, 'NSM'],
647
+ [0xFB1F, 0xFB28, 'R'],
648
+ [0xFB29, 0xFB29, 'ES'],
649
+ [0xFB2A, 0xFB4F, 'R'],
650
+ [0xFB50, 0xFBC2, 'AL'],
651
+ [0xFBC3, 0xFBD2, 'ON'],
652
+ [0xFBD3, 0xFD3D, 'AL'],
653
+ [0xFD3E, 0xFD4F, 'ON'],
654
+ [0xFD50, 0xFD8F, 'AL'],
655
+ [0xFD90, 0xFD91, 'ON'],
656
+ [0xFD92, 0xFDC7, 'AL'],
657
+ [0xFDC8, 0xFDCF, 'ON'],
658
+ [0xFDD0, 0xFDEF, 'BN'],
659
+ [0xFDF0, 0xFDFC, 'AL'],
660
+ [0xFDFD, 0xFDFF, 'ON'],
661
+ [0xFE00, 0xFE0F, 'NSM'],
662
+ [0xFE10, 0xFE19, 'ON'],
663
+ [0xFE20, 0xFE2F, 'NSM'],
664
+ [0xFE30, 0xFE4F, 'ON'],
665
+ [0xFE50, 0xFE50, 'CS'],
666
+ [0xFE51, 0xFE51, 'ON'],
667
+ [0xFE52, 0xFE52, 'CS'],
668
+ [0xFE54, 0xFE54, 'ON'],
669
+ [0xFE55, 0xFE55, 'CS'],
670
+ [0xFE56, 0xFE5E, 'ON'],
671
+ [0xFE5F, 0xFE5F, 'ET'],
672
+ [0xFE60, 0xFE61, 'ON'],
673
+ [0xFE62, 0xFE63, 'ES'],
674
+ [0xFE64, 0xFE66, 'ON'],
675
+ [0xFE68, 0xFE68, 'ON'],
676
+ [0xFE69, 0xFE6A, 'ET'],
677
+ [0xFE6B, 0xFE6B, 'ON'],
678
+ [0xFE70, 0xFEFE, 'AL'],
679
+ [0xFEFF, 0xFEFF, 'BN'],
680
+ [0xFF01, 0xFF02, 'ON'],
681
+ [0xFF03, 0xFF05, 'ET'],
682
+ [0xFF06, 0xFF0A, 'ON'],
683
+ [0xFF0B, 0xFF0B, 'ES'],
684
+ [0xFF0C, 0xFF0C, 'CS'],
685
+ [0xFF0D, 0xFF0D, 'ES'],
686
+ [0xFF0E, 0xFF0F, 'CS'],
687
+ [0xFF10, 0xFF19, 'EN'],
688
+ [0xFF1A, 0xFF1A, 'CS'],
689
+ [0xFF1B, 0xFF20, 'ON'],
690
+ [0xFF3B, 0xFF40, 'ON'],
691
+ [0xFF5B, 0xFF65, 'ON'],
692
+ [0xFFE0, 0xFFE1, 'ET'],
693
+ [0xFFE2, 0xFFE4, 'ON'],
694
+ [0xFFE5, 0xFFE6, 'ET'],
695
+ [0xFFE8, 0xFFEE, 'ON'],
696
+ [0xFFF0, 0xFFF8, 'BN'],
697
+ [0xFFF9, 0xFFFD, 'ON'],
698
+ [0xFFFE, 0xFFFF, 'BN'],
699
+ [0x10101, 0x10101, 'ON'],
700
+ [0x10140, 0x1018C, 'ON'],
701
+ [0x10190, 0x1019C, 'ON'],
702
+ [0x101A0, 0x101A0, 'ON'],
703
+ [0x101FD, 0x101FD, 'NSM'],
704
+ [0x102E0, 0x102E0, 'NSM'],
705
+ [0x102E1, 0x102FB, 'EN'],
706
+ [0x10376, 0x1037A, 'NSM'],
707
+ [0x10800, 0x1091E, 'R'],
708
+ [0x1091F, 0x1091F, 'ON'],
709
+ [0x10920, 0x10A00, 'R'],
710
+ [0x10A01, 0x10A03, 'NSM'],
711
+ [0x10A04, 0x10A04, 'R'],
712
+ [0x10A05, 0x10A06, 'NSM'],
713
+ [0x10A07, 0x10A0B, 'R'],
714
+ [0x10A0C, 0x10A0F, 'NSM'],
715
+ [0x10A10, 0x10A37, 'R'],
716
+ [0x10A38, 0x10A3A, 'NSM'],
717
+ [0x10A3B, 0x10A3E, 'R'],
718
+ [0x10A3F, 0x10A3F, 'NSM'],
719
+ [0x10A40, 0x10AE4, 'R'],
720
+ [0x10AE5, 0x10AE6, 'NSM'],
721
+ [0x10AE7, 0x10B38, 'R'],
722
+ [0x10B39, 0x10B3F, 'ON'],
723
+ [0x10B40, 0x10CFF, 'R'],
724
+ [0x10D00, 0x10D23, 'AL'],
725
+ [0x10D24, 0x10D27, 'NSM'],
726
+ [0x10D28, 0x10D2F, 'AL'],
727
+ [0x10D30, 0x10D39, 'AN'],
728
+ [0x10D3A, 0x10D3F, 'AL'],
729
+ [0x10D40, 0x10D49, 'AN'],
730
+ [0x10D4A, 0x10D68, 'R'],
731
+ [0x10D69, 0x10D6D, 'NSM'],
732
+ [0x10D6E, 0x10D6E, 'ON'],
733
+ [0x10D6F, 0x10E5F, 'R'],
734
+ [0x10E60, 0x10E7E, 'AN'],
735
+ [0x10E7F, 0x10EAA, 'R'],
736
+ [0x10EAB, 0x10EAC, 'NSM'],
737
+ [0x10EAD, 0x10EBF, 'R'],
738
+ [0x10EC0, 0x10ECF, 'AL'],
739
+ [0x10ED0, 0x10ED8, 'ON'],
740
+ [0x10ED9, 0x10EF9, 'AL'],
741
+ [0x10EFA, 0x10EFF, 'NSM'],
742
+ [0x10F00, 0x10F2F, 'R'],
743
+ [0x10F30, 0x10F45, 'AL'],
744
+ [0x10F46, 0x10F50, 'NSM'],
745
+ [0x10F51, 0x10F6F, 'AL'],
746
+ [0x10F70, 0x10F81, 'R'],
747
+ [0x10F82, 0x10F85, 'NSM'],
748
+ [0x10F86, 0x10FFF, 'R'],
749
+ [0x11001, 0x11001, 'NSM'],
750
+ [0x11038, 0x11046, 'NSM'],
751
+ [0x11052, 0x11065, 'ON'],
752
+ [0x11070, 0x11070, 'NSM'],
753
+ [0x11073, 0x11074, 'NSM'],
754
+ [0x1107F, 0x11081, 'NSM'],
755
+ [0x110B3, 0x110B6, 'NSM'],
756
+ [0x110B9, 0x110BA, 'NSM'],
757
+ [0x110C2, 0x110C2, 'NSM'],
758
+ [0x11100, 0x11102, 'NSM'],
759
+ [0x11127, 0x1112B, 'NSM'],
760
+ [0x1112D, 0x11134, 'NSM'],
761
+ [0x11173, 0x11173, 'NSM'],
762
+ [0x11180, 0x11181, 'NSM'],
763
+ [0x111B6, 0x111BE, 'NSM'],
764
+ [0x111C9, 0x111CC, 'NSM'],
765
+ [0x111CF, 0x111CF, 'NSM'],
766
+ [0x1122F, 0x11231, 'NSM'],
767
+ [0x11234, 0x11234, 'NSM'],
768
+ [0x11236, 0x11237, 'NSM'],
769
+ [0x1123E, 0x1123E, 'NSM'],
770
+ [0x11241, 0x11241, 'NSM'],
771
+ [0x112DF, 0x112DF, 'NSM'],
772
+ [0x112E3, 0x112EA, 'NSM'],
773
+ [0x11300, 0x11301, 'NSM'],
774
+ [0x1133B, 0x1133C, 'NSM'],
775
+ [0x11340, 0x11340, 'NSM'],
776
+ [0x11366, 0x1136C, 'NSM'],
777
+ [0x11370, 0x11374, 'NSM'],
778
+ [0x113BB, 0x113C0, 'NSM'],
779
+ [0x113CE, 0x113CE, 'NSM'],
780
+ [0x113D0, 0x113D0, 'NSM'],
781
+ [0x113D2, 0x113D2, 'NSM'],
782
+ [0x113E1, 0x113E2, 'NSM'],
783
+ [0x11438, 0x1143F, 'NSM'],
784
+ [0x11442, 0x11444, 'NSM'],
785
+ [0x11446, 0x11446, 'NSM'],
786
+ [0x1145E, 0x1145E, 'NSM'],
787
+ [0x114B3, 0x114B8, 'NSM'],
788
+ [0x114BA, 0x114BA, 'NSM'],
789
+ [0x114BF, 0x114C0, 'NSM'],
790
+ [0x114C2, 0x114C3, 'NSM'],
791
+ [0x115B2, 0x115B5, 'NSM'],
792
+ [0x115BC, 0x115BD, 'NSM'],
793
+ [0x115BF, 0x115C0, 'NSM'],
794
+ [0x115DC, 0x115DD, 'NSM'],
795
+ [0x11633, 0x1163A, 'NSM'],
796
+ [0x1163D, 0x1163D, 'NSM'],
797
+ [0x1163F, 0x11640, 'NSM'],
798
+ [0x11660, 0x1166C, 'ON'],
799
+ [0x116AB, 0x116AB, 'NSM'],
800
+ [0x116AD, 0x116AD, 'NSM'],
801
+ [0x116B0, 0x116B5, 'NSM'],
802
+ [0x116B7, 0x116B7, 'NSM'],
803
+ [0x1171D, 0x1171D, 'NSM'],
804
+ [0x1171F, 0x1171F, 'NSM'],
805
+ [0x11722, 0x11725, 'NSM'],
806
+ [0x11727, 0x1172B, 'NSM'],
807
+ [0x1182F, 0x11837, 'NSM'],
808
+ [0x11839, 0x1183A, 'NSM'],
809
+ [0x1193B, 0x1193C, 'NSM'],
810
+ [0x1193E, 0x1193E, 'NSM'],
811
+ [0x11943, 0x11943, 'NSM'],
812
+ [0x119D4, 0x119D7, 'NSM'],
813
+ [0x119DA, 0x119DB, 'NSM'],
814
+ [0x119E0, 0x119E0, 'NSM'],
815
+ [0x11A01, 0x11A06, 'NSM'],
816
+ [0x11A09, 0x11A0A, 'NSM'],
817
+ [0x11A33, 0x11A38, 'NSM'],
818
+ [0x11A3B, 0x11A3E, 'NSM'],
819
+ [0x11A47, 0x11A47, 'NSM'],
820
+ [0x11A51, 0x11A56, 'NSM'],
821
+ [0x11A59, 0x11A5B, 'NSM'],
822
+ [0x11A8A, 0x11A96, 'NSM'],
823
+ [0x11A98, 0x11A99, 'NSM'],
824
+ [0x11B60, 0x11B60, 'NSM'],
825
+ [0x11B62, 0x11B64, 'NSM'],
826
+ [0x11B66, 0x11B66, 'NSM'],
827
+ [0x11C30, 0x11C36, 'NSM'],
828
+ [0x11C38, 0x11C3D, 'NSM'],
829
+ [0x11C92, 0x11CA7, 'NSM'],
830
+ [0x11CAA, 0x11CB0, 'NSM'],
831
+ [0x11CB2, 0x11CB3, 'NSM'],
832
+ [0x11CB5, 0x11CB6, 'NSM'],
833
+ [0x11D31, 0x11D36, 'NSM'],
834
+ [0x11D3A, 0x11D3A, 'NSM'],
835
+ [0x11D3C, 0x11D3D, 'NSM'],
836
+ [0x11D3F, 0x11D45, 'NSM'],
837
+ [0x11D47, 0x11D47, 'NSM'],
838
+ [0x11D90, 0x11D91, 'NSM'],
839
+ [0x11D95, 0x11D95, 'NSM'],
840
+ [0x11D97, 0x11D97, 'NSM'],
841
+ [0x11EF3, 0x11EF4, 'NSM'],
842
+ [0x11F00, 0x11F01, 'NSM'],
843
+ [0x11F36, 0x11F3A, 'NSM'],
844
+ [0x11F40, 0x11F40, 'NSM'],
845
+ [0x11F42, 0x11F42, 'NSM'],
846
+ [0x11F5A, 0x11F5A, 'NSM'],
847
+ [0x11FD5, 0x11FDC, 'ON'],
848
+ [0x11FDD, 0x11FE0, 'ET'],
849
+ [0x11FE1, 0x11FF1, 'ON'],
850
+ [0x13440, 0x13440, 'NSM'],
851
+ [0x13447, 0x13455, 'NSM'],
852
+ [0x1611E, 0x16129, 'NSM'],
853
+ [0x1612D, 0x1612F, 'NSM'],
854
+ [0x16AF0, 0x16AF4, 'NSM'],
855
+ [0x16B30, 0x16B36, 'NSM'],
856
+ [0x16F4F, 0x16F4F, 'NSM'],
857
+ [0x16F8F, 0x16F92, 'NSM'],
858
+ [0x16FE2, 0x16FE2, 'ON'],
859
+ [0x16FE4, 0x16FE4, 'NSM'],
860
+ [0x1BC9D, 0x1BC9E, 'NSM'],
861
+ [0x1BCA0, 0x1BCA3, 'BN'],
862
+ [0x1CC00, 0x1CCD5, 'ON'],
863
+ [0x1CCF0, 0x1CCF9, 'EN'],
864
+ [0x1CCFA, 0x1CCFC, 'ON'],
865
+ [0x1CD00, 0x1CEB3, 'ON'],
866
+ [0x1CEBA, 0x1CED0, 'ON'],
867
+ [0x1CEE0, 0x1CEF0, 'ON'],
868
+ [0x1CF00, 0x1CF2D, 'NSM'],
869
+ [0x1CF30, 0x1CF46, 'NSM'],
870
+ [0x1D167, 0x1D169, 'NSM'],
871
+ [0x1D173, 0x1D17A, 'BN'],
872
+ [0x1D17B, 0x1D182, 'NSM'],
873
+ [0x1D185, 0x1D18B, 'NSM'],
874
+ [0x1D1AA, 0x1D1AD, 'NSM'],
875
+ [0x1D1E9, 0x1D1EA, 'ON'],
876
+ [0x1D200, 0x1D241, 'ON'],
877
+ [0x1D242, 0x1D244, 'NSM'],
878
+ [0x1D245, 0x1D245, 'ON'],
879
+ [0x1D300, 0x1D356, 'ON'],
880
+ [0x1D6C1, 0x1D6C1, 'ON'],
881
+ [0x1D6DB, 0x1D6DB, 'ON'],
882
+ [0x1D6FB, 0x1D6FB, 'ON'],
883
+ [0x1D715, 0x1D715, 'ON'],
884
+ [0x1D735, 0x1D735, 'ON'],
885
+ [0x1D74F, 0x1D74F, 'ON'],
886
+ [0x1D76F, 0x1D76F, 'ON'],
887
+ [0x1D789, 0x1D789, 'ON'],
888
+ [0x1D7A9, 0x1D7A9, 'ON'],
889
+ [0x1D7C3, 0x1D7C3, 'ON'],
890
+ [0x1D7CE, 0x1D7FF, 'EN'],
891
+ [0x1DA00, 0x1DA36, 'NSM'],
892
+ [0x1DA3B, 0x1DA6C, 'NSM'],
893
+ [0x1DA75, 0x1DA75, 'NSM'],
894
+ [0x1DA84, 0x1DA84, 'NSM'],
895
+ [0x1DA9B, 0x1DA9F, 'NSM'],
896
+ [0x1DAA1, 0x1DAAF, 'NSM'],
897
+ [0x1E000, 0x1E006, 'NSM'],
898
+ [0x1E008, 0x1E018, 'NSM'],
899
+ [0x1E01B, 0x1E021, 'NSM'],
900
+ [0x1E023, 0x1E024, 'NSM'],
901
+ [0x1E026, 0x1E02A, 'NSM'],
902
+ [0x1E08F, 0x1E08F, 'NSM'],
903
+ [0x1E130, 0x1E136, 'NSM'],
904
+ [0x1E2AE, 0x1E2AE, 'NSM'],
905
+ [0x1E2EC, 0x1E2EF, 'NSM'],
906
+ [0x1E2FF, 0x1E2FF, 'ET'],
907
+ [0x1E4EC, 0x1E4EF, 'NSM'],
908
+ [0x1E5EE, 0x1E5EF, 'NSM'],
909
+ [0x1E6E3, 0x1E6E3, 'NSM'],
910
+ [0x1E6E6, 0x1E6E6, 'NSM'],
911
+ [0x1E6EE, 0x1E6EF, 'NSM'],
912
+ [0x1E6F5, 0x1E6F5, 'NSM'],
913
+ [0x1E800, 0x1E8CF, 'R'],
914
+ [0x1E8D0, 0x1E8D6, 'NSM'],
915
+ [0x1E8D7, 0x1E943, 'R'],
916
+ [0x1E944, 0x1E94A, 'NSM'],
917
+ [0x1E94B, 0x1EC6F, 'R'],
918
+ [0x1EC70, 0x1ECBF, 'AL'],
919
+ [0x1ECC0, 0x1ECFF, 'R'],
920
+ [0x1ED00, 0x1ED4F, 'AL'],
921
+ [0x1ED50, 0x1EDFF, 'R'],
922
+ [0x1EE00, 0x1EEEF, 'AL'],
923
+ [0x1EEF0, 0x1EEF1, 'ON'],
924
+ [0x1EEF2, 0x1EEFF, 'AL'],
925
+ [0x1EF00, 0x1EFFF, 'R'],
926
+ [0x1F000, 0x1F02B, 'ON'],
927
+ [0x1F030, 0x1F093, 'ON'],
928
+ [0x1F0A0, 0x1F0AE, 'ON'],
929
+ [0x1F0B1, 0x1F0BF, 'ON'],
930
+ [0x1F0C1, 0x1F0CF, 'ON'],
931
+ [0x1F0D1, 0x1F0F5, 'ON'],
932
+ [0x1F100, 0x1F10A, 'EN'],
933
+ [0x1F10B, 0x1F10F, 'ON'],
934
+ [0x1F12F, 0x1F12F, 'ON'],
935
+ [0x1F16A, 0x1F16F, 'ON'],
936
+ [0x1F1AD, 0x1F1AD, 'ON'],
937
+ [0x1F260, 0x1F265, 'ON'],
938
+ [0x1F300, 0x1F6D8, 'ON'],
939
+ [0x1F6DC, 0x1F6EC, 'ON'],
940
+ [0x1F6F0, 0x1F6FC, 'ON'],
941
+ [0x1F700, 0x1F7D9, 'ON'],
942
+ [0x1F7E0, 0x1F7EB, 'ON'],
943
+ [0x1F7F0, 0x1F7F0, 'ON'],
944
+ [0x1F800, 0x1F80B, 'ON'],
945
+ [0x1F810, 0x1F847, 'ON'],
946
+ [0x1F850, 0x1F859, 'ON'],
947
+ [0x1F860, 0x1F887, 'ON'],
948
+ [0x1F890, 0x1F8AD, 'ON'],
949
+ [0x1F8B0, 0x1F8BB, 'ON'],
950
+ [0x1F8C0, 0x1F8C1, 'ON'],
951
+ [0x1F8D0, 0x1F8D8, 'ON'],
952
+ [0x1F900, 0x1FA57, 'ON'],
953
+ [0x1FA60, 0x1FA6D, 'ON'],
954
+ [0x1FA70, 0x1FA7C, 'ON'],
955
+ [0x1FA80, 0x1FA8A, 'ON'],
956
+ [0x1FA8E, 0x1FAC6, 'ON'],
957
+ [0x1FAC8, 0x1FAC8, 'ON'],
958
+ [0x1FACD, 0x1FADC, 'ON'],
959
+ [0x1FADF, 0x1FAEA, 'ON'],
960
+ [0x1FAEF, 0x1FAF8, 'ON'],
961
+ [0x1FB00, 0x1FB92, 'ON'],
962
+ [0x1FB94, 0x1FBEF, 'ON'],
963
+ [0x1FBF0, 0x1FBF9, 'EN'],
964
+ [0x1FBFA, 0x1FBFA, 'ON'],
965
+ [0x1FFFE, 0x1FFFF, 'BN'],
966
+ [0x2FFFE, 0x2FFFF, 'BN'],
967
+ [0x3FFFE, 0x3FFFF, 'BN'],
968
+ [0x4FFFE, 0x4FFFF, 'BN'],
969
+ [0x5FFFE, 0x5FFFF, 'BN'],
970
+ [0x6FFFE, 0x6FFFF, 'BN'],
971
+ [0x7FFFE, 0x7FFFF, 'BN'],
972
+ [0x8FFFE, 0x8FFFF, 'BN'],
973
+ [0x9FFFE, 0x9FFFF, 'BN'],
974
+ [0xAFFFE, 0xAFFFF, 'BN'],
975
+ [0xBFFFE, 0xBFFFF, 'BN'],
976
+ [0xCFFFE, 0xCFFFF, 'BN'],
977
+ [0xDFFFE, 0xE00FF, 'BN'],
978
+ [0xE0100, 0xE01EF, 'NSM'],
979
+ [0xE01F0, 0xE0FFF, 'BN'],
980
+ [0xEFFFE, 0xEFFFF, 'BN'],
981
+ [0xFFFFE, 0xFFFFF, 'BN'],
982
+ [0x10FFFE, 0x10FFFF, 'BN'],
983
+ ];
984
+
985
+ // Simplified bidi metadata helper for the rich prepareWithSegments() path,
986
+ // forked from pdf.js via Sebastian's text-layout. It classifies characters
987
+ // into bidi types, computes embedding levels, and maps them onto prepared
988
+ // segments for custom rendering. The line-breaking engine does not consume
989
+ // these levels.
990
+ function classifyCodePoint(codePoint) {
991
+ if (codePoint <= 0x00FF)
992
+ return latin1BidiTypes[codePoint];
993
+ let lo = 0;
994
+ let hi = nonLatin1BidiRanges.length - 1;
995
+ while (lo <= hi) {
996
+ const mid = (lo + hi) >> 1;
997
+ const range = nonLatin1BidiRanges[mid];
998
+ if (codePoint < range[0]) {
999
+ hi = mid - 1;
1000
+ continue;
1001
+ }
1002
+ if (codePoint > range[1]) {
1003
+ lo = mid + 1;
1004
+ continue;
1005
+ }
1006
+ return range[2];
1007
+ }
1008
+ return 'L';
1009
+ }
1010
+ function computeBidiLevels(str) {
1011
+ const len = str.length;
1012
+ if (len === 0)
1013
+ return null;
1014
+ // eslint-disable-next-line unicorn/no-new-array
1015
+ const types = new Array(len);
1016
+ let sawBidi = false;
1017
+ // Keep the resolved bidi classes aligned to UTF-16 code-unit offsets,
1018
+ // because the rich prepared segments index back into the normalized string
1019
+ // with JavaScript string offsets.
1020
+ for (let i = 0; i < len;) {
1021
+ const first = str.charCodeAt(i);
1022
+ let codePoint = first;
1023
+ let codeUnitLength = 1;
1024
+ if (first >= 0xD800 && first <= 0xDBFF && i + 1 < len) {
1025
+ const second = str.charCodeAt(i + 1);
1026
+ if (second >= 0xDC00 && second <= 0xDFFF) {
1027
+ codePoint = ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
1028
+ codeUnitLength = 2;
1029
+ }
1030
+ }
1031
+ const t = classifyCodePoint(codePoint);
1032
+ if (t === 'R' || t === 'AL' || t === 'AN')
1033
+ sawBidi = true;
1034
+ for (let j = 0; j < codeUnitLength; j++) {
1035
+ types[i + j] = t;
1036
+ }
1037
+ i += codeUnitLength;
1038
+ }
1039
+ if (!sawBidi)
1040
+ return null;
1041
+ // Use the first strong character to pick the paragraph base direction.
1042
+ // Rich-path bidi metadata is only an approximation, but this keeps mixed
1043
+ // LTR/RTL text aligned with the common UBA paragraph rule.
1044
+ let startLevel = 0;
1045
+ for (let i = 0; i < len; i++) {
1046
+ const t = types[i];
1047
+ if (t === 'L') {
1048
+ startLevel = 0;
1049
+ break;
1050
+ }
1051
+ if (t === 'R' || t === 'AL') {
1052
+ startLevel = 1;
1053
+ break;
1054
+ }
1055
+ }
1056
+ const levels = new Int8Array(len);
1057
+ for (let i = 0; i < len; i++)
1058
+ levels[i] = startLevel;
1059
+ const e = (startLevel & 1) ? 'R' : 'L';
1060
+ const sor = e;
1061
+ // W1-W7
1062
+ let lastType = sor;
1063
+ for (let i = 0; i < len; i++) {
1064
+ if (types[i] === 'NSM')
1065
+ types[i] = lastType;
1066
+ else
1067
+ lastType = types[i];
1068
+ }
1069
+ lastType = sor;
1070
+ for (let i = 0; i < len; i++) {
1071
+ const t = types[i];
1072
+ if (t === 'EN')
1073
+ types[i] = lastType === 'AL' ? 'AN' : 'EN';
1074
+ else if (t === 'R' || t === 'L' || t === 'AL')
1075
+ lastType = t;
1076
+ }
1077
+ for (let i = 0; i < len; i++) {
1078
+ if (types[i] === 'AL')
1079
+ types[i] = 'R';
1080
+ }
1081
+ for (let i = 1; i < len - 1; i++) {
1082
+ if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
1083
+ types[i] = 'EN';
1084
+ }
1085
+ if (types[i] === 'CS' &&
1086
+ (types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
1087
+ types[i + 1] === types[i - 1]) {
1088
+ types[i] = types[i - 1];
1089
+ }
1090
+ }
1091
+ for (let i = 0; i < len; i++) {
1092
+ if (types[i] !== 'EN')
1093
+ continue;
1094
+ let j;
1095
+ for (j = i - 1; j >= 0 && types[j] === 'ET'; j--)
1096
+ types[j] = 'EN';
1097
+ for (j = i + 1; j < len && types[j] === 'ET'; j++)
1098
+ types[j] = 'EN';
1099
+ }
1100
+ for (let i = 0; i < len; i++) {
1101
+ const t = types[i];
1102
+ if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS')
1103
+ types[i] = 'ON';
1104
+ }
1105
+ lastType = sor;
1106
+ for (let i = 0; i < len; i++) {
1107
+ const t = types[i];
1108
+ if (t === 'EN')
1109
+ types[i] = lastType === 'L' ? 'L' : 'EN';
1110
+ else if (t === 'R' || t === 'L')
1111
+ lastType = t;
1112
+ }
1113
+ // N1-N2
1114
+ for (let i = 0; i < len; i++) {
1115
+ if (types[i] !== 'ON')
1116
+ continue;
1117
+ let end = i + 1;
1118
+ while (end < len && types[end] === 'ON')
1119
+ end++;
1120
+ const before = i > 0 ? types[i - 1] : sor;
1121
+ const after = end < len ? types[end] : sor;
1122
+ const bDir = before !== 'L' ? 'R' : 'L';
1123
+ const aDir = after !== 'L' ? 'R' : 'L';
1124
+ if (bDir === aDir) {
1125
+ for (let j = i; j < end; j++)
1126
+ types[j] = bDir;
1127
+ }
1128
+ i = end - 1;
1129
+ }
1130
+ for (let i = 0; i < len; i++) {
1131
+ if (types[i] === 'ON')
1132
+ types[i] = e;
1133
+ }
1134
+ // I1-I2
1135
+ for (let i = 0; i < len; i++) {
1136
+ const t = types[i];
1137
+ if ((levels[i] & 1) === 0) {
1138
+ if (t === 'R')
1139
+ levels[i]++;
1140
+ else if (t === 'AN' || t === 'EN')
1141
+ levels[i] += 2;
1142
+ }
1143
+ else if (t === 'L' || t === 'AN' || t === 'EN') {
1144
+ levels[i]++;
1145
+ }
1146
+ }
1147
+ return levels;
1148
+ }
1149
+ function computeSegmentLevels(normalized, segStarts) {
1150
+ const bidiLevels = computeBidiLevels(normalized);
1151
+ if (bidiLevels === null)
1152
+ return null;
1153
+ const segLevels = new Int8Array(segStarts.length);
1154
+ for (let i = 0; i < segStarts.length; i++) {
1155
+ segLevels[i] = bidiLevels[segStarts[i]];
1156
+ }
1157
+ return segLevels;
1158
+ }
1159
+
1160
+ const collapsibleWhitespaceRunRe = /[ \t\n\r\f]+/g;
1161
+ const needsWhitespaceNormalizationRe = /[\t\n\r\f]| {2,}|^ | $/;
1162
+ function getWhiteSpaceProfile(whiteSpace) {
1163
+ const mode = whiteSpace ?? 'normal';
1164
+ return mode === 'pre-wrap'
1165
+ ? { mode, preserveOrdinarySpaces: true, preserveHardBreaks: true }
1166
+ : { mode, preserveOrdinarySpaces: false, preserveHardBreaks: false };
1167
+ }
1168
+ function normalizeWhitespaceNormal(text) {
1169
+ if (!needsWhitespaceNormalizationRe.test(text))
1170
+ return text;
1171
+ let normalized = text.replace(collapsibleWhitespaceRunRe, ' ');
1172
+ if (normalized.charCodeAt(0) === 0x20) {
1173
+ normalized = normalized.slice(1);
1174
+ }
1175
+ if (normalized.length > 0 && normalized.charCodeAt(normalized.length - 1) === 0x20) {
1176
+ normalized = normalized.slice(0, -1);
1177
+ }
1178
+ return normalized;
1179
+ }
1180
+ function normalizeWhitespacePreWrap(text) {
1181
+ if (!/[\r\f]/.test(text))
1182
+ return text;
1183
+ return text
1184
+ .replace(/\r\n/g, '\n')
1185
+ .replace(/[\r\f]/g, '\n');
1186
+ }
1187
+ let sharedWordSegmenter = null;
1188
+ let segmenterLocale;
1189
+ function getSharedWordSegmenter() {
1190
+ if (sharedWordSegmenter === null) {
1191
+ sharedWordSegmenter = new Intl.Segmenter(segmenterLocale, { granularity: 'word' });
1192
+ }
1193
+ return sharedWordSegmenter;
1194
+ }
1195
+ const arabicScriptRe = /\p{Script=Arabic}/u;
1196
+ const combiningMarkRe = /\p{M}/u;
1197
+ const decimalDigitRe = /\p{Nd}/u;
1198
+ function containsArabicScript(text) {
1199
+ return arabicScriptRe.test(text);
1200
+ }
1201
+ function isCJKCodePoint(codePoint) {
1202
+ return ((codePoint >= 0x4E00 && codePoint <= 0x9FFF) ||
1203
+ (codePoint >= 0x3400 && codePoint <= 0x4DBF) ||
1204
+ (codePoint >= 0x20000 && codePoint <= 0x2A6DF) ||
1205
+ (codePoint >= 0x2A700 && codePoint <= 0x2B73F) ||
1206
+ (codePoint >= 0x2B740 && codePoint <= 0x2B81F) ||
1207
+ (codePoint >= 0x2B820 && codePoint <= 0x2CEAF) ||
1208
+ (codePoint >= 0x2CEB0 && codePoint <= 0x2EBEF) ||
1209
+ (codePoint >= 0x2EBF0 && codePoint <= 0x2EE5D) ||
1210
+ (codePoint >= 0x2F800 && codePoint <= 0x2FA1F) ||
1211
+ (codePoint >= 0x30000 && codePoint <= 0x3134F) ||
1212
+ (codePoint >= 0x31350 && codePoint <= 0x323AF) ||
1213
+ (codePoint >= 0x323B0 && codePoint <= 0x33479) ||
1214
+ (codePoint >= 0xF900 && codePoint <= 0xFAFF) ||
1215
+ (codePoint >= 0x3000 && codePoint <= 0x303F) ||
1216
+ (codePoint >= 0x3040 && codePoint <= 0x309F) ||
1217
+ (codePoint >= 0x30A0 && codePoint <= 0x30FF) ||
1218
+ (codePoint >= 0x3130 && codePoint <= 0x318F) ||
1219
+ (codePoint >= 0xAC00 && codePoint <= 0xD7AF) ||
1220
+ (codePoint >= 0xFF00 && codePoint <= 0xFFEF));
1221
+ }
1222
+ function isCJK(s) {
1223
+ for (let i = 0; i < s.length; i++) {
1224
+ const first = s.charCodeAt(i);
1225
+ if (first < 0x3000)
1226
+ continue;
1227
+ if (first >= 0xD800 && first <= 0xDBFF && i + 1 < s.length) {
1228
+ const second = s.charCodeAt(i + 1);
1229
+ if (second >= 0xDC00 && second <= 0xDFFF) {
1230
+ const codePoint = ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
1231
+ if (isCJKCodePoint(codePoint))
1232
+ return true;
1233
+ i++;
1234
+ continue;
1235
+ }
1236
+ }
1237
+ if (isCJKCodePoint(first))
1238
+ return true;
1239
+ }
1240
+ return false;
1241
+ }
1242
+ function endsWithLineStartProhibitedText(text) {
1243
+ const last = getLastCodePoint(text);
1244
+ return last !== null && (kinsokuStart.has(last) || leftStickyPunctuation.has(last));
1245
+ }
1246
+ const keepAllGlueChars = new Set([
1247
+ '\u00A0',
1248
+ '\u202F',
1249
+ '\u2060',
1250
+ '\uFEFF',
1251
+ ]);
1252
+ function containsCJKText(text) {
1253
+ return isCJK(text);
1254
+ }
1255
+ function endsWithKeepAllGlueText(text) {
1256
+ const last = getLastCodePoint(text);
1257
+ return last !== null && keepAllGlueChars.has(last);
1258
+ }
1259
+ function canContinueKeepAllTextRun(previousText) {
1260
+ return (!endsWithLineStartProhibitedText(previousText) &&
1261
+ !endsWithKeepAllGlueText(previousText));
1262
+ }
1263
+ const kinsokuStart = new Set([
1264
+ '\uFF0C',
1265
+ '\uFF0E',
1266
+ '\uFF01',
1267
+ '\uFF1A',
1268
+ '\uFF1B',
1269
+ '\uFF1F',
1270
+ '\u3001',
1271
+ '\u3002',
1272
+ '\u30FB',
1273
+ '\uFF09',
1274
+ '\u3015',
1275
+ '\u3009',
1276
+ '\u300B',
1277
+ '\u300D',
1278
+ '\u300F',
1279
+ '\u3011',
1280
+ '\u3017',
1281
+ '\u3019',
1282
+ '\u301B',
1283
+ '\u30FC',
1284
+ '\u3005',
1285
+ '\u303B',
1286
+ '\u309D',
1287
+ '\u309E',
1288
+ '\u30FD',
1289
+ '\u30FE',
1290
+ ]);
1291
+ const kinsokuEnd = new Set([
1292
+ '"',
1293
+ '(', '[', '{',
1294
+ '“', '‘', '«', '‹',
1295
+ '\uFF08',
1296
+ '\u3014',
1297
+ '\u3008',
1298
+ '\u300A',
1299
+ '\u300C',
1300
+ '\u300E',
1301
+ '\u3010',
1302
+ '\u3016',
1303
+ '\u3018',
1304
+ '\u301A',
1305
+ ]);
1306
+ const forwardStickyGlue = new Set([
1307
+ "'", '’',
1308
+ ]);
1309
+ const leftStickyPunctuation = new Set([
1310
+ '.', ',', '!', '?', ':', ';',
1311
+ '\u060C',
1312
+ '\u061B',
1313
+ '\u061F',
1314
+ '\u0964',
1315
+ '\u0965',
1316
+ '\u104A',
1317
+ '\u104B',
1318
+ '\u104C',
1319
+ '\u104D',
1320
+ '\u104F',
1321
+ ')', ']', '}',
1322
+ '%',
1323
+ '"',
1324
+ '”', '’', '»', '›',
1325
+ '…',
1326
+ ]);
1327
+ const arabicNoSpaceTrailingPunctuation = new Set([
1328
+ ':',
1329
+ '.',
1330
+ '\u060C',
1331
+ '\u061B',
1332
+ ]);
1333
+ const myanmarMedialGlue = new Set([
1334
+ '\u104F',
1335
+ ]);
1336
+ const closingQuoteChars = new Set([
1337
+ '”', '’', '»', '›',
1338
+ '\u300D',
1339
+ '\u300F',
1340
+ '\u3011',
1341
+ '\u300B',
1342
+ '\u3009',
1343
+ '\u3015',
1344
+ '\uFF09',
1345
+ ]);
1346
+ function isLeftStickyPunctuationSegment(segment) {
1347
+ if (isEscapedQuoteClusterSegment(segment))
1348
+ return true;
1349
+ let sawPunctuation = false;
1350
+ for (const ch of segment) {
1351
+ if (leftStickyPunctuation.has(ch)) {
1352
+ sawPunctuation = true;
1353
+ continue;
1354
+ }
1355
+ if (sawPunctuation && combiningMarkRe.test(ch))
1356
+ continue;
1357
+ return false;
1358
+ }
1359
+ return sawPunctuation;
1360
+ }
1361
+ function isCJKLineStartProhibitedSegment(segment) {
1362
+ for (const ch of segment) {
1363
+ if (!kinsokuStart.has(ch) && !leftStickyPunctuation.has(ch))
1364
+ return false;
1365
+ }
1366
+ return segment.length > 0;
1367
+ }
1368
+ function isForwardStickyClusterSegment(segment) {
1369
+ if (isEscapedQuoteClusterSegment(segment))
1370
+ return true;
1371
+ for (const ch of segment) {
1372
+ if (!kinsokuEnd.has(ch) && !forwardStickyGlue.has(ch) && !combiningMarkRe.test(ch))
1373
+ return false;
1374
+ }
1375
+ return segment.length > 0;
1376
+ }
1377
+ function isEscapedQuoteClusterSegment(segment) {
1378
+ let sawQuote = false;
1379
+ for (const ch of segment) {
1380
+ if (ch === '\\' || combiningMarkRe.test(ch))
1381
+ continue;
1382
+ if (kinsokuEnd.has(ch) || leftStickyPunctuation.has(ch) || forwardStickyGlue.has(ch)) {
1383
+ sawQuote = true;
1384
+ continue;
1385
+ }
1386
+ return false;
1387
+ }
1388
+ return sawQuote;
1389
+ }
1390
+ function previousCodePointStart(text, end) {
1391
+ const last = end - 1;
1392
+ if (last <= 0)
1393
+ return Math.max(last, 0);
1394
+ const lastCodeUnit = text.charCodeAt(last);
1395
+ if (lastCodeUnit < 0xDC00 || lastCodeUnit > 0xDFFF)
1396
+ return last;
1397
+ const maybeHigh = last - 1;
1398
+ if (maybeHigh < 0)
1399
+ return last;
1400
+ const highCodeUnit = text.charCodeAt(maybeHigh);
1401
+ return highCodeUnit >= 0xD800 && highCodeUnit <= 0xDBFF ? maybeHigh : last;
1402
+ }
1403
+ function getLastCodePoint(text) {
1404
+ if (text.length === 0)
1405
+ return null;
1406
+ const start = previousCodePointStart(text, text.length);
1407
+ return text.slice(start);
1408
+ }
1409
+ function splitTrailingForwardStickyCluster(text) {
1410
+ const chars = Array.from(text);
1411
+ let splitIndex = chars.length;
1412
+ while (splitIndex > 0) {
1413
+ const ch = chars[splitIndex - 1];
1414
+ if (combiningMarkRe.test(ch)) {
1415
+ splitIndex--;
1416
+ continue;
1417
+ }
1418
+ if (kinsokuEnd.has(ch) || forwardStickyGlue.has(ch)) {
1419
+ splitIndex--;
1420
+ continue;
1421
+ }
1422
+ break;
1423
+ }
1424
+ if (splitIndex <= 0 || splitIndex === chars.length)
1425
+ return null;
1426
+ return {
1427
+ head: chars.slice(0, splitIndex).join(''),
1428
+ tail: chars.slice(splitIndex).join(''),
1429
+ };
1430
+ }
1431
+ function getRepeatableSingleCharRunChar(text, isWordLike, kind) {
1432
+ return kind === 'text' && !isWordLike && text.length === 1 && text !== '-' && text !== '—'
1433
+ ? text
1434
+ : null;
1435
+ }
1436
+ function materializeDeferredSingleCharRun(texts, chars, lengths, index) {
1437
+ const ch = chars[index];
1438
+ const text = texts[index];
1439
+ if (ch == null)
1440
+ return text;
1441
+ const length = lengths[index];
1442
+ if (text.length === length)
1443
+ return text;
1444
+ const materialized = ch.repeat(length);
1445
+ texts[index] = materialized;
1446
+ return materialized;
1447
+ }
1448
+ function hasArabicNoSpacePunctuation(containsArabic, lastCodePoint) {
1449
+ return containsArabic && lastCodePoint !== null && arabicNoSpaceTrailingPunctuation.has(lastCodePoint);
1450
+ }
1451
+ function endsWithMyanmarMedialGlue(segment) {
1452
+ const lastCodePoint = getLastCodePoint(segment);
1453
+ return lastCodePoint !== null && myanmarMedialGlue.has(lastCodePoint);
1454
+ }
1455
+ function splitLeadingSpaceAndMarks(segment) {
1456
+ if (segment.length < 2 || segment[0] !== ' ')
1457
+ return null;
1458
+ const marks = segment.slice(1);
1459
+ if (/^\p{M}+$/u.test(marks)) {
1460
+ return { space: ' ', marks };
1461
+ }
1462
+ return null;
1463
+ }
1464
+ function endsWithClosingQuote(text) {
1465
+ let end = text.length;
1466
+ while (end > 0) {
1467
+ const start = previousCodePointStart(text, end);
1468
+ const ch = text.slice(start, end);
1469
+ if (closingQuoteChars.has(ch))
1470
+ return true;
1471
+ if (!leftStickyPunctuation.has(ch))
1472
+ return false;
1473
+ end = start;
1474
+ }
1475
+ return false;
1476
+ }
1477
+ function classifySegmentBreakChar(ch, whiteSpaceProfile) {
1478
+ if (whiteSpaceProfile.preserveOrdinarySpaces || whiteSpaceProfile.preserveHardBreaks) {
1479
+ if (ch === ' ')
1480
+ return 'preserved-space';
1481
+ if (ch === '\t')
1482
+ return 'tab';
1483
+ if (whiteSpaceProfile.preserveHardBreaks && ch === '\n')
1484
+ return 'hard-break';
1485
+ }
1486
+ if (ch === ' ')
1487
+ return 'space';
1488
+ if (ch === '\u00A0' || ch === '\u202F' || ch === '\u2060' || ch === '\uFEFF') {
1489
+ return 'glue';
1490
+ }
1491
+ if (ch === '\u200B')
1492
+ return 'zero-width-break';
1493
+ if (ch === '\u00AD')
1494
+ return 'soft-hyphen';
1495
+ return 'text';
1496
+ }
1497
+ // All characters that classifySegmentBreakChar maps to a non-'text' kind.
1498
+ const breakCharRe = /[\x20\t\n\xA0\xAD\u200B\u202F\u2060\uFEFF]/;
1499
+ function joinTextParts(parts) {
1500
+ return parts.length === 1 ? parts[0] : parts.join('');
1501
+ }
1502
+ function joinReversedPrefixParts(prefixParts, tail) {
1503
+ const parts = [];
1504
+ for (let i = prefixParts.length - 1; i >= 0; i--) {
1505
+ parts.push(prefixParts[i]);
1506
+ }
1507
+ parts.push(tail);
1508
+ return joinTextParts(parts);
1509
+ }
1510
+ function splitSegmentByBreakKind(segment, isWordLike, start, whiteSpaceProfile) {
1511
+ if (!breakCharRe.test(segment)) {
1512
+ return [{ text: segment, isWordLike, kind: 'text', start }];
1513
+ }
1514
+ const pieces = [];
1515
+ let currentKind = null;
1516
+ let currentTextParts = [];
1517
+ let currentStart = start;
1518
+ let currentWordLike = false;
1519
+ let offset = 0;
1520
+ for (const ch of segment) {
1521
+ const kind = classifySegmentBreakChar(ch, whiteSpaceProfile);
1522
+ const wordLike = kind === 'text' && isWordLike;
1523
+ if (currentKind !== null && kind === currentKind && wordLike === currentWordLike) {
1524
+ currentTextParts.push(ch);
1525
+ offset += ch.length;
1526
+ continue;
1527
+ }
1528
+ if (currentKind !== null) {
1529
+ pieces.push({
1530
+ text: joinTextParts(currentTextParts),
1531
+ isWordLike: currentWordLike,
1532
+ kind: currentKind,
1533
+ start: currentStart,
1534
+ });
1535
+ }
1536
+ currentKind = kind;
1537
+ currentTextParts = [ch];
1538
+ currentStart = start + offset;
1539
+ currentWordLike = wordLike;
1540
+ offset += ch.length;
1541
+ }
1542
+ if (currentKind !== null) {
1543
+ pieces.push({
1544
+ text: joinTextParts(currentTextParts),
1545
+ isWordLike: currentWordLike,
1546
+ kind: currentKind,
1547
+ start: currentStart,
1548
+ });
1549
+ }
1550
+ return pieces;
1551
+ }
1552
+ function isTextRunBoundary(kind) {
1553
+ return (kind === 'space' ||
1554
+ kind === 'preserved-space' ||
1555
+ kind === 'zero-width-break' ||
1556
+ kind === 'hard-break');
1557
+ }
1558
+ const urlSchemeSegmentRe = /^[A-Za-z][A-Za-z0-9+.-]*:$/;
1559
+ function isUrlLikeRunStart(segmentation, index) {
1560
+ const text = segmentation.texts[index];
1561
+ if (text.startsWith('www.'))
1562
+ return true;
1563
+ return (urlSchemeSegmentRe.test(text) &&
1564
+ index + 1 < segmentation.len &&
1565
+ segmentation.kinds[index + 1] === 'text' &&
1566
+ segmentation.texts[index + 1] === '//');
1567
+ }
1568
+ function isUrlQueryBoundarySegment(text) {
1569
+ return text.includes('?') && (text.includes('://') || text.startsWith('www.'));
1570
+ }
1571
+ function mergeUrlLikeRuns(segmentation) {
1572
+ const texts = segmentation.texts.slice();
1573
+ const isWordLike = segmentation.isWordLike.slice();
1574
+ const kinds = segmentation.kinds.slice();
1575
+ const starts = segmentation.starts.slice();
1576
+ for (let i = 0; i < segmentation.len; i++) {
1577
+ if (kinds[i] !== 'text' || !isUrlLikeRunStart(segmentation, i))
1578
+ continue;
1579
+ const mergedParts = [texts[i]];
1580
+ let j = i + 1;
1581
+ while (j < segmentation.len && !isTextRunBoundary(kinds[j])) {
1582
+ mergedParts.push(texts[j]);
1583
+ isWordLike[i] = true;
1584
+ const endsQueryPrefix = texts[j].includes('?');
1585
+ kinds[j] = 'text';
1586
+ texts[j] = '';
1587
+ j++;
1588
+ if (endsQueryPrefix)
1589
+ break;
1590
+ }
1591
+ texts[i] = joinTextParts(mergedParts);
1592
+ }
1593
+ let compactLen = 0;
1594
+ for (let read = 0; read < texts.length; read++) {
1595
+ const text = texts[read];
1596
+ if (text.length === 0)
1597
+ continue;
1598
+ if (compactLen !== read) {
1599
+ texts[compactLen] = text;
1600
+ isWordLike[compactLen] = isWordLike[read];
1601
+ kinds[compactLen] = kinds[read];
1602
+ starts[compactLen] = starts[read];
1603
+ }
1604
+ compactLen++;
1605
+ }
1606
+ texts.length = compactLen;
1607
+ isWordLike.length = compactLen;
1608
+ kinds.length = compactLen;
1609
+ starts.length = compactLen;
1610
+ return {
1611
+ len: compactLen,
1612
+ texts,
1613
+ isWordLike,
1614
+ kinds,
1615
+ starts,
1616
+ };
1617
+ }
1618
+ function mergeUrlQueryRuns(segmentation) {
1619
+ const texts = [];
1620
+ const isWordLike = [];
1621
+ const kinds = [];
1622
+ const starts = [];
1623
+ for (let i = 0; i < segmentation.len; i++) {
1624
+ const text = segmentation.texts[i];
1625
+ texts.push(text);
1626
+ isWordLike.push(segmentation.isWordLike[i]);
1627
+ kinds.push(segmentation.kinds[i]);
1628
+ starts.push(segmentation.starts[i]);
1629
+ if (!isUrlQueryBoundarySegment(text))
1630
+ continue;
1631
+ const nextIndex = i + 1;
1632
+ if (nextIndex >= segmentation.len ||
1633
+ isTextRunBoundary(segmentation.kinds[nextIndex])) {
1634
+ continue;
1635
+ }
1636
+ const queryParts = [];
1637
+ const queryStart = segmentation.starts[nextIndex];
1638
+ let j = nextIndex;
1639
+ while (j < segmentation.len && !isTextRunBoundary(segmentation.kinds[j])) {
1640
+ queryParts.push(segmentation.texts[j]);
1641
+ j++;
1642
+ }
1643
+ if (queryParts.length > 0) {
1644
+ texts.push(joinTextParts(queryParts));
1645
+ isWordLike.push(true);
1646
+ kinds.push('text');
1647
+ starts.push(queryStart);
1648
+ i = j - 1;
1649
+ }
1650
+ }
1651
+ return {
1652
+ len: texts.length,
1653
+ texts,
1654
+ isWordLike,
1655
+ kinds,
1656
+ starts,
1657
+ };
1658
+ }
1659
+ const numericJoinerChars = new Set([
1660
+ ':', '-', '/', '×', ',', '.', '+',
1661
+ '\u2013',
1662
+ '\u2014',
1663
+ ]);
1664
+ const asciiPunctuationChainSegmentRe = /^[A-Za-z0-9_]+[,:;]*$/;
1665
+ const asciiPunctuationChainTrailingJoinersRe = /[,:;]+$/;
1666
+ function segmentContainsDecimalDigit(text) {
1667
+ for (const ch of text) {
1668
+ if (decimalDigitRe.test(ch))
1669
+ return true;
1670
+ }
1671
+ return false;
1672
+ }
1673
+ function isNumericRunSegment(text) {
1674
+ if (text.length === 0)
1675
+ return false;
1676
+ for (const ch of text) {
1677
+ if (decimalDigitRe.test(ch) || numericJoinerChars.has(ch))
1678
+ continue;
1679
+ return false;
1680
+ }
1681
+ return true;
1682
+ }
1683
+ function mergeNumericRuns(segmentation) {
1684
+ const texts = [];
1685
+ const isWordLike = [];
1686
+ const kinds = [];
1687
+ const starts = [];
1688
+ for (let i = 0; i < segmentation.len; i++) {
1689
+ const text = segmentation.texts[i];
1690
+ const kind = segmentation.kinds[i];
1691
+ if (kind === 'text' && isNumericRunSegment(text) && segmentContainsDecimalDigit(text)) {
1692
+ const mergedParts = [text];
1693
+ let j = i + 1;
1694
+ while (j < segmentation.len &&
1695
+ segmentation.kinds[j] === 'text' &&
1696
+ isNumericRunSegment(segmentation.texts[j])) {
1697
+ mergedParts.push(segmentation.texts[j]);
1698
+ j++;
1699
+ }
1700
+ texts.push(joinTextParts(mergedParts));
1701
+ isWordLike.push(true);
1702
+ kinds.push('text');
1703
+ starts.push(segmentation.starts[i]);
1704
+ i = j - 1;
1705
+ continue;
1706
+ }
1707
+ texts.push(text);
1708
+ isWordLike.push(segmentation.isWordLike[i]);
1709
+ kinds.push(kind);
1710
+ starts.push(segmentation.starts[i]);
1711
+ }
1712
+ return {
1713
+ len: texts.length,
1714
+ texts,
1715
+ isWordLike,
1716
+ kinds,
1717
+ starts,
1718
+ };
1719
+ }
1720
+ function mergeAsciiPunctuationChains(segmentation) {
1721
+ const texts = [];
1722
+ const isWordLike = [];
1723
+ const kinds = [];
1724
+ const starts = [];
1725
+ for (let i = 0; i < segmentation.len; i++) {
1726
+ const text = segmentation.texts[i];
1727
+ const kind = segmentation.kinds[i];
1728
+ const wordLike = segmentation.isWordLike[i];
1729
+ if (kind === 'text' && wordLike && asciiPunctuationChainSegmentRe.test(text)) {
1730
+ const mergedParts = [text];
1731
+ let endsWithJoiners = asciiPunctuationChainTrailingJoinersRe.test(text);
1732
+ let j = i + 1;
1733
+ while (endsWithJoiners &&
1734
+ j < segmentation.len &&
1735
+ segmentation.kinds[j] === 'text' &&
1736
+ segmentation.isWordLike[j] &&
1737
+ asciiPunctuationChainSegmentRe.test(segmentation.texts[j])) {
1738
+ const nextText = segmentation.texts[j];
1739
+ mergedParts.push(nextText);
1740
+ endsWithJoiners = asciiPunctuationChainTrailingJoinersRe.test(nextText);
1741
+ j++;
1742
+ }
1743
+ texts.push(joinTextParts(mergedParts));
1744
+ isWordLike.push(true);
1745
+ kinds.push('text');
1746
+ starts.push(segmentation.starts[i]);
1747
+ i = j - 1;
1748
+ continue;
1749
+ }
1750
+ texts.push(text);
1751
+ isWordLike.push(wordLike);
1752
+ kinds.push(kind);
1753
+ starts.push(segmentation.starts[i]);
1754
+ }
1755
+ return {
1756
+ len: texts.length,
1757
+ texts,
1758
+ isWordLike,
1759
+ kinds,
1760
+ starts,
1761
+ };
1762
+ }
1763
+ function splitHyphenatedNumericRuns(segmentation) {
1764
+ const texts = [];
1765
+ const isWordLike = [];
1766
+ const kinds = [];
1767
+ const starts = [];
1768
+ for (let i = 0; i < segmentation.len; i++) {
1769
+ const text = segmentation.texts[i];
1770
+ if (segmentation.kinds[i] === 'text' && text.includes('-')) {
1771
+ const parts = text.split('-');
1772
+ let shouldSplit = parts.length > 1;
1773
+ for (let j = 0; j < parts.length; j++) {
1774
+ const part = parts[j];
1775
+ if (!shouldSplit)
1776
+ break;
1777
+ if (part.length === 0 ||
1778
+ !segmentContainsDecimalDigit(part) ||
1779
+ !isNumericRunSegment(part)) {
1780
+ shouldSplit = false;
1781
+ }
1782
+ }
1783
+ if (shouldSplit) {
1784
+ let offset = 0;
1785
+ for (let j = 0; j < parts.length; j++) {
1786
+ const part = parts[j];
1787
+ const splitText = j < parts.length - 1 ? `${part}-` : part;
1788
+ texts.push(splitText);
1789
+ isWordLike.push(true);
1790
+ kinds.push('text');
1791
+ starts.push(segmentation.starts[i] + offset);
1792
+ offset += splitText.length;
1793
+ }
1794
+ continue;
1795
+ }
1796
+ }
1797
+ texts.push(text);
1798
+ isWordLike.push(segmentation.isWordLike[i]);
1799
+ kinds.push(segmentation.kinds[i]);
1800
+ starts.push(segmentation.starts[i]);
1801
+ }
1802
+ return {
1803
+ len: texts.length,
1804
+ texts,
1805
+ isWordLike,
1806
+ kinds,
1807
+ starts,
1808
+ };
1809
+ }
1810
+ function mergeGlueConnectedTextRuns(segmentation) {
1811
+ const texts = [];
1812
+ const isWordLike = [];
1813
+ const kinds = [];
1814
+ const starts = [];
1815
+ let read = 0;
1816
+ while (read < segmentation.len) {
1817
+ const textParts = [segmentation.texts[read]];
1818
+ let wordLike = segmentation.isWordLike[read];
1819
+ let kind = segmentation.kinds[read];
1820
+ let start = segmentation.starts[read];
1821
+ if (kind === 'glue') {
1822
+ const glueParts = [textParts[0]];
1823
+ const glueStart = start;
1824
+ read++;
1825
+ while (read < segmentation.len && segmentation.kinds[read] === 'glue') {
1826
+ glueParts.push(segmentation.texts[read]);
1827
+ read++;
1828
+ }
1829
+ const glueText = joinTextParts(glueParts);
1830
+ if (read < segmentation.len && segmentation.kinds[read] === 'text') {
1831
+ textParts[0] = glueText;
1832
+ textParts.push(segmentation.texts[read]);
1833
+ wordLike = segmentation.isWordLike[read];
1834
+ kind = 'text';
1835
+ start = glueStart;
1836
+ read++;
1837
+ }
1838
+ else {
1839
+ texts.push(glueText);
1840
+ isWordLike.push(false);
1841
+ kinds.push('glue');
1842
+ starts.push(glueStart);
1843
+ continue;
1844
+ }
1845
+ }
1846
+ else {
1847
+ read++;
1848
+ }
1849
+ if (kind === 'text') {
1850
+ while (read < segmentation.len && segmentation.kinds[read] === 'glue') {
1851
+ const glueParts = [];
1852
+ while (read < segmentation.len && segmentation.kinds[read] === 'glue') {
1853
+ glueParts.push(segmentation.texts[read]);
1854
+ read++;
1855
+ }
1856
+ const glueText = joinTextParts(glueParts);
1857
+ if (read < segmentation.len && segmentation.kinds[read] === 'text') {
1858
+ textParts.push(glueText, segmentation.texts[read]);
1859
+ wordLike = wordLike || segmentation.isWordLike[read];
1860
+ read++;
1861
+ continue;
1862
+ }
1863
+ textParts.push(glueText);
1864
+ }
1865
+ }
1866
+ texts.push(joinTextParts(textParts));
1867
+ isWordLike.push(wordLike);
1868
+ kinds.push(kind);
1869
+ starts.push(start);
1870
+ }
1871
+ return {
1872
+ len: texts.length,
1873
+ texts,
1874
+ isWordLike,
1875
+ kinds,
1876
+ starts,
1877
+ };
1878
+ }
1879
+ function carryTrailingForwardStickyAcrossCJKBoundary(segmentation) {
1880
+ const texts = segmentation.texts.slice();
1881
+ const isWordLike = segmentation.isWordLike.slice();
1882
+ const kinds = segmentation.kinds.slice();
1883
+ const starts = segmentation.starts.slice();
1884
+ for (let i = 0; i < texts.length - 1; i++) {
1885
+ if (kinds[i] !== 'text' || kinds[i + 1] !== 'text')
1886
+ continue;
1887
+ if (!isCJK(texts[i]) || !isCJK(texts[i + 1]))
1888
+ continue;
1889
+ const split = splitTrailingForwardStickyCluster(texts[i]);
1890
+ if (split === null)
1891
+ continue;
1892
+ texts[i] = split.head;
1893
+ texts[i + 1] = split.tail + texts[i + 1];
1894
+ starts[i + 1] = starts[i] + split.head.length;
1895
+ }
1896
+ return {
1897
+ len: texts.length,
1898
+ texts,
1899
+ isWordLike,
1900
+ kinds,
1901
+ starts,
1902
+ };
1903
+ }
1904
+ function buildMergedSegmentation(normalized, profile, whiteSpaceProfile) {
1905
+ const wordSegmenter = getSharedWordSegmenter();
1906
+ let mergedLen = 0;
1907
+ const mergedTexts = [];
1908
+ const mergedTextParts = [];
1909
+ const mergedWordLike = [];
1910
+ const mergedKinds = [];
1911
+ const mergedStarts = [];
1912
+ // Track repeatable single-char punctuation runs structurally so identical
1913
+ // merges stay O(1) instead of re-scanning the accumulated segment each time.
1914
+ const mergedSingleCharRunChars = [];
1915
+ const mergedSingleCharRunLengths = [];
1916
+ const mergedContainsCJK = [];
1917
+ const mergedContainsArabicScript = [];
1918
+ const mergedEndsWithClosingQuote = [];
1919
+ const mergedEndsWithMyanmarMedialGlue = [];
1920
+ const mergedHasArabicNoSpacePunctuation = [];
1921
+ for (const s of wordSegmenter.segment(normalized)) {
1922
+ for (const piece of splitSegmentByBreakKind(s.segment, s.isWordLike ?? false, s.index, whiteSpaceProfile)) {
1923
+ const isText = piece.kind === 'text';
1924
+ const repeatableSingleCharRunChar = getRepeatableSingleCharRunChar(piece.text, piece.isWordLike, piece.kind);
1925
+ const pieceContainsCJK = isCJK(piece.text);
1926
+ const pieceContainsArabicScript = containsArabicScript(piece.text);
1927
+ const pieceLastCodePoint = getLastCodePoint(piece.text);
1928
+ const pieceEndsWithClosingQuote = endsWithClosingQuote(piece.text);
1929
+ const pieceEndsWithMyanmarMedialGlue = endsWithMyanmarMedialGlue(piece.text);
1930
+ const prevIndex = mergedLen - 1;
1931
+ function appendPieceToPrevious() {
1932
+ if (mergedSingleCharRunChars[prevIndex] !== null) {
1933
+ mergedTextParts[prevIndex] = [
1934
+ materializeDeferredSingleCharRun(mergedTexts, mergedSingleCharRunChars, mergedSingleCharRunLengths, prevIndex),
1935
+ ];
1936
+ mergedSingleCharRunChars[prevIndex] = null;
1937
+ }
1938
+ mergedTextParts[prevIndex].push(piece.text);
1939
+ mergedWordLike[prevIndex] = mergedWordLike[prevIndex] || piece.isWordLike;
1940
+ mergedContainsCJK[prevIndex] = mergedContainsCJK[prevIndex] || pieceContainsCJK;
1941
+ mergedContainsArabicScript[prevIndex] =
1942
+ mergedContainsArabicScript[prevIndex] || pieceContainsArabicScript;
1943
+ mergedEndsWithClosingQuote[prevIndex] = pieceEndsWithClosingQuote;
1944
+ mergedEndsWithMyanmarMedialGlue[prevIndex] = pieceEndsWithMyanmarMedialGlue;
1945
+ mergedHasArabicNoSpacePunctuation[prevIndex] = hasArabicNoSpacePunctuation(mergedContainsArabicScript[prevIndex], pieceLastCodePoint);
1946
+ }
1947
+ // First-pass keeps: no-space script-specific joins and punctuation glue
1948
+ // that depend on the immediately preceding text run.
1949
+ if (profile.carryCJKAfterClosingQuote &&
1950
+ isText &&
1951
+ mergedLen > 0 &&
1952
+ mergedKinds[prevIndex] === 'text' &&
1953
+ pieceContainsCJK &&
1954
+ mergedContainsCJK[prevIndex] &&
1955
+ mergedEndsWithClosingQuote[prevIndex]) {
1956
+ appendPieceToPrevious();
1957
+ }
1958
+ else if (isText &&
1959
+ mergedLen > 0 &&
1960
+ mergedKinds[prevIndex] === 'text' &&
1961
+ isCJKLineStartProhibitedSegment(piece.text) &&
1962
+ mergedContainsCJK[prevIndex]) {
1963
+ appendPieceToPrevious();
1964
+ }
1965
+ else if (isText &&
1966
+ mergedLen > 0 &&
1967
+ mergedKinds[prevIndex] === 'text' &&
1968
+ mergedEndsWithMyanmarMedialGlue[prevIndex]) {
1969
+ appendPieceToPrevious();
1970
+ }
1971
+ else if (isText &&
1972
+ mergedLen > 0 &&
1973
+ mergedKinds[prevIndex] === 'text' &&
1974
+ piece.isWordLike &&
1975
+ pieceContainsArabicScript &&
1976
+ mergedHasArabicNoSpacePunctuation[prevIndex]) {
1977
+ appendPieceToPrevious();
1978
+ mergedWordLike[prevIndex] = true;
1979
+ }
1980
+ else if (repeatableSingleCharRunChar !== null &&
1981
+ mergedLen > 0 &&
1982
+ mergedKinds[prevIndex] === 'text' &&
1983
+ mergedSingleCharRunChars[prevIndex] === repeatableSingleCharRunChar) {
1984
+ mergedSingleCharRunLengths[prevIndex] = (mergedSingleCharRunLengths[prevIndex] ?? 1) + 1;
1985
+ }
1986
+ else if (isText &&
1987
+ !piece.isWordLike &&
1988
+ mergedLen > 0 &&
1989
+ mergedKinds[prevIndex] === 'text' &&
1990
+ !mergedContainsCJK[prevIndex] &&
1991
+ (isLeftStickyPunctuationSegment(piece.text) ||
1992
+ (piece.text === '-' && mergedWordLike[prevIndex]))) {
1993
+ appendPieceToPrevious();
1994
+ }
1995
+ else {
1996
+ mergedTexts[mergedLen] = piece.text;
1997
+ mergedTextParts[mergedLen] = [piece.text];
1998
+ mergedWordLike[mergedLen] = piece.isWordLike;
1999
+ mergedKinds[mergedLen] = piece.kind;
2000
+ mergedStarts[mergedLen] = piece.start;
2001
+ mergedSingleCharRunChars[mergedLen] = repeatableSingleCharRunChar;
2002
+ mergedSingleCharRunLengths[mergedLen] = repeatableSingleCharRunChar === null ? 0 : 1;
2003
+ mergedContainsCJK[mergedLen] = pieceContainsCJK;
2004
+ mergedContainsArabicScript[mergedLen] = pieceContainsArabicScript;
2005
+ mergedEndsWithClosingQuote[mergedLen] = pieceEndsWithClosingQuote;
2006
+ mergedEndsWithMyanmarMedialGlue[mergedLen] = pieceEndsWithMyanmarMedialGlue;
2007
+ mergedHasArabicNoSpacePunctuation[mergedLen] = hasArabicNoSpacePunctuation(pieceContainsArabicScript, pieceLastCodePoint);
2008
+ mergedLen++;
2009
+ }
2010
+ }
2011
+ }
2012
+ for (let i = 0; i < mergedLen; i++) {
2013
+ if (mergedSingleCharRunChars[i] !== null) {
2014
+ mergedTexts[i] = materializeDeferredSingleCharRun(mergedTexts, mergedSingleCharRunChars, mergedSingleCharRunLengths, i);
2015
+ continue;
2016
+ }
2017
+ mergedTexts[i] = joinTextParts(mergedTextParts[i]);
2018
+ }
2019
+ // Later passes operate on the merged text stream itself: contextual escaped
2020
+ // quote glue, forward-sticky carry, compaction, then the broader URL/numeric
2021
+ // and Arabic-leading-mark fixes.
2022
+ for (let i = 1; i < mergedLen; i++) {
2023
+ if (mergedKinds[i] === 'text' &&
2024
+ !mergedWordLike[i] &&
2025
+ isEscapedQuoteClusterSegment(mergedTexts[i]) &&
2026
+ mergedKinds[i - 1] === 'text' &&
2027
+ !mergedContainsCJK[i - 1]) {
2028
+ mergedTexts[i - 1] += mergedTexts[i];
2029
+ mergedWordLike[i - 1] = mergedWordLike[i - 1] || mergedWordLike[i];
2030
+ mergedTexts[i] = '';
2031
+ }
2032
+ }
2033
+ const forwardStickyPrefixParts = Array.from({ length: mergedLen }, () => null);
2034
+ let nextLiveIndex = -1;
2035
+ for (let i = mergedLen - 1; i >= 0; i--) {
2036
+ const text = mergedTexts[i];
2037
+ if (text.length === 0)
2038
+ continue;
2039
+ if (mergedKinds[i] === 'text' &&
2040
+ !mergedWordLike[i] &&
2041
+ isForwardStickyClusterSegment(text) &&
2042
+ nextLiveIndex >= 0 &&
2043
+ mergedKinds[nextLiveIndex] === 'text') {
2044
+ const prefixParts = forwardStickyPrefixParts[nextLiveIndex] ?? [];
2045
+ prefixParts.push(text);
2046
+ forwardStickyPrefixParts[nextLiveIndex] = prefixParts;
2047
+ mergedStarts[nextLiveIndex] = mergedStarts[i];
2048
+ mergedTexts[i] = '';
2049
+ continue;
2050
+ }
2051
+ nextLiveIndex = i;
2052
+ }
2053
+ for (let i = 0; i < mergedLen; i++) {
2054
+ const prefixParts = forwardStickyPrefixParts[i];
2055
+ if (prefixParts == null)
2056
+ continue;
2057
+ mergedTexts[i] = joinReversedPrefixParts(prefixParts, mergedTexts[i]);
2058
+ }
2059
+ let compactLen = 0;
2060
+ for (let read = 0; read < mergedLen; read++) {
2061
+ const text = mergedTexts[read];
2062
+ if (text.length === 0)
2063
+ continue;
2064
+ if (compactLen !== read) {
2065
+ mergedTexts[compactLen] = text;
2066
+ mergedWordLike[compactLen] = mergedWordLike[read];
2067
+ mergedKinds[compactLen] = mergedKinds[read];
2068
+ mergedStarts[compactLen] = mergedStarts[read];
2069
+ }
2070
+ compactLen++;
2071
+ }
2072
+ mergedTexts.length = compactLen;
2073
+ mergedWordLike.length = compactLen;
2074
+ mergedKinds.length = compactLen;
2075
+ mergedStarts.length = compactLen;
2076
+ const compacted = mergeGlueConnectedTextRuns({
2077
+ len: compactLen,
2078
+ texts: mergedTexts,
2079
+ isWordLike: mergedWordLike,
2080
+ kinds: mergedKinds,
2081
+ starts: mergedStarts,
2082
+ });
2083
+ const withMergedUrls = carryTrailingForwardStickyAcrossCJKBoundary(mergeAsciiPunctuationChains(splitHyphenatedNumericRuns(mergeNumericRuns(mergeUrlQueryRuns(mergeUrlLikeRuns(compacted))))));
2084
+ for (let i = 0; i < withMergedUrls.len - 1; i++) {
2085
+ const split = splitLeadingSpaceAndMarks(withMergedUrls.texts[i]);
2086
+ if (split === null)
2087
+ continue;
2088
+ if ((withMergedUrls.kinds[i] !== 'space' && withMergedUrls.kinds[i] !== 'preserved-space') ||
2089
+ withMergedUrls.kinds[i + 1] !== 'text' ||
2090
+ !containsArabicScript(withMergedUrls.texts[i + 1])) {
2091
+ continue;
2092
+ }
2093
+ withMergedUrls.texts[i] = split.space;
2094
+ withMergedUrls.isWordLike[i] = false;
2095
+ withMergedUrls.kinds[i] = withMergedUrls.kinds[i] === 'preserved-space' ? 'preserved-space' : 'space';
2096
+ withMergedUrls.texts[i + 1] = split.marks + withMergedUrls.texts[i + 1];
2097
+ withMergedUrls.starts[i + 1] = withMergedUrls.starts[i] + split.space.length;
2098
+ }
2099
+ return withMergedUrls;
2100
+ }
2101
+ function compileAnalysisChunks(segmentation, whiteSpaceProfile) {
2102
+ if (segmentation.len === 0)
2103
+ return [];
2104
+ if (!whiteSpaceProfile.preserveHardBreaks) {
2105
+ return [{
2106
+ startSegmentIndex: 0,
2107
+ endSegmentIndex: segmentation.len,
2108
+ consumedEndSegmentIndex: segmentation.len,
2109
+ }];
2110
+ }
2111
+ const chunks = [];
2112
+ let startSegmentIndex = 0;
2113
+ for (let i = 0; i < segmentation.len; i++) {
2114
+ if (segmentation.kinds[i] !== 'hard-break')
2115
+ continue;
2116
+ chunks.push({
2117
+ startSegmentIndex,
2118
+ endSegmentIndex: i,
2119
+ consumedEndSegmentIndex: i + 1,
2120
+ });
2121
+ startSegmentIndex = i + 1;
2122
+ }
2123
+ if (startSegmentIndex < segmentation.len) {
2124
+ chunks.push({
2125
+ startSegmentIndex,
2126
+ endSegmentIndex: segmentation.len,
2127
+ consumedEndSegmentIndex: segmentation.len,
2128
+ });
2129
+ }
2130
+ return chunks;
2131
+ }
2132
+ function mergeKeepAllTextSegments(segmentation) {
2133
+ if (segmentation.len <= 1)
2134
+ return segmentation;
2135
+ const texts = [];
2136
+ const isWordLike = [];
2137
+ const kinds = [];
2138
+ const starts = [];
2139
+ let pendingTextParts = null;
2140
+ let pendingWordLike = false;
2141
+ let pendingStart = 0;
2142
+ let pendingContainsCJK = false;
2143
+ let pendingCanContinue = false;
2144
+ function flushPendingText() {
2145
+ if (pendingTextParts === null)
2146
+ return;
2147
+ texts.push(joinTextParts(pendingTextParts));
2148
+ isWordLike.push(pendingWordLike);
2149
+ kinds.push('text');
2150
+ starts.push(pendingStart);
2151
+ pendingTextParts = null;
2152
+ }
2153
+ for (let i = 0; i < segmentation.len; i++) {
2154
+ const text = segmentation.texts[i];
2155
+ const kind = segmentation.kinds[i];
2156
+ const wordLike = segmentation.isWordLike[i];
2157
+ const start = segmentation.starts[i];
2158
+ if (kind === 'text') {
2159
+ const textContainsCJK = containsCJKText(text);
2160
+ const textCanContinue = canContinueKeepAllTextRun(text);
2161
+ if (pendingTextParts !== null && pendingContainsCJK && pendingCanContinue) {
2162
+ pendingTextParts.push(text);
2163
+ pendingWordLike = pendingWordLike || wordLike;
2164
+ pendingContainsCJK = pendingContainsCJK || textContainsCJK;
2165
+ pendingCanContinue = textCanContinue;
2166
+ continue;
2167
+ }
2168
+ flushPendingText();
2169
+ pendingTextParts = [text];
2170
+ pendingWordLike = wordLike;
2171
+ pendingStart = start;
2172
+ pendingContainsCJK = textContainsCJK;
2173
+ pendingCanContinue = textCanContinue;
2174
+ continue;
2175
+ }
2176
+ flushPendingText();
2177
+ texts.push(text);
2178
+ isWordLike.push(wordLike);
2179
+ kinds.push(kind);
2180
+ starts.push(start);
2181
+ }
2182
+ flushPendingText();
2183
+ return {
2184
+ len: texts.length,
2185
+ texts,
2186
+ isWordLike,
2187
+ kinds,
2188
+ starts,
2189
+ };
2190
+ }
2191
+ function analyzeText(text, profile, whiteSpace = 'normal', wordBreak = 'normal') {
2192
+ const whiteSpaceProfile = getWhiteSpaceProfile(whiteSpace);
2193
+ const normalized = whiteSpaceProfile.mode === 'pre-wrap'
2194
+ ? normalizeWhitespacePreWrap(text)
2195
+ : normalizeWhitespaceNormal(text);
2196
+ if (normalized.length === 0) {
2197
+ return {
2198
+ normalized,
2199
+ chunks: [],
2200
+ len: 0,
2201
+ texts: [],
2202
+ isWordLike: [],
2203
+ kinds: [],
2204
+ starts: [],
2205
+ };
2206
+ }
2207
+ const segmentation = wordBreak === 'keep-all'
2208
+ ? mergeKeepAllTextSegments(buildMergedSegmentation(normalized, profile, whiteSpaceProfile))
2209
+ : buildMergedSegmentation(normalized, profile, whiteSpaceProfile);
2210
+ return {
2211
+ normalized,
2212
+ chunks: compileAnalysisChunks(segmentation, whiteSpaceProfile),
2213
+ ...segmentation,
2214
+ };
2215
+ }
2216
+
2217
+ let measureContext = null;
2218
+ const segmentMetricCaches = new Map();
2219
+ let cachedEngineProfile = null;
2220
+ // Safari's prefix-fit policy is useful for ordinary word-sized runs, but letting
2221
+ // it measure every growing prefix of a giant segment recreates a pathological
2222
+ // superlinear prepare-time path. Past this size, switch to the cheaper
2223
+ // pair-context model and keep the public behavior linear.
2224
+ const MAX_PREFIX_FIT_GRAPHEMES = 96;
2225
+ const emojiPresentationRe = /\p{Emoji_Presentation}/u;
2226
+ const maybeEmojiRe = /[\p{Emoji_Presentation}\p{Extended_Pictographic}\p{Regional_Indicator}\uFE0F\u20E3]/u;
2227
+ let sharedGraphemeSegmenter$1 = null;
2228
+ const emojiCorrectionCache = new Map();
2229
+ function getMeasureContext() {
2230
+ if (measureContext !== null)
2231
+ return measureContext;
2232
+ if (typeof OffscreenCanvas !== 'undefined') {
2233
+ measureContext = new OffscreenCanvas(1, 1).getContext('2d');
2234
+ return measureContext;
2235
+ }
2236
+ if (typeof document !== 'undefined') {
2237
+ measureContext = document.createElement('canvas').getContext('2d');
2238
+ return measureContext;
2239
+ }
2240
+ throw new Error('Text measurement requires OffscreenCanvas or a DOM canvas context.');
2241
+ }
2242
+ function getSegmentMetricCache(font) {
2243
+ let cache = segmentMetricCaches.get(font);
2244
+ if (!cache) {
2245
+ cache = new Map();
2246
+ segmentMetricCaches.set(font, cache);
2247
+ }
2248
+ return cache;
2249
+ }
2250
+ function getSegmentMetrics(seg, cache) {
2251
+ let metrics = cache.get(seg);
2252
+ if (metrics === undefined) {
2253
+ const ctx = getMeasureContext();
2254
+ metrics = {
2255
+ width: ctx.measureText(seg).width,
2256
+ containsCJK: isCJK(seg),
2257
+ };
2258
+ cache.set(seg, metrics);
2259
+ }
2260
+ return metrics;
2261
+ }
2262
+ function getEngineProfile() {
2263
+ if (cachedEngineProfile !== null)
2264
+ return cachedEngineProfile;
2265
+ if (typeof navigator === 'undefined') {
2266
+ cachedEngineProfile = {
2267
+ lineFitEpsilon: 0.005,
2268
+ carryCJKAfterClosingQuote: false,
2269
+ preferPrefixWidthsForBreakableRuns: false,
2270
+ preferEarlySoftHyphenBreak: false,
2271
+ };
2272
+ return cachedEngineProfile;
2273
+ }
2274
+ const ua = navigator.userAgent;
2275
+ const vendor = navigator.vendor;
2276
+ const isSafari = vendor === 'Apple Computer, Inc.' &&
2277
+ ua.includes('Safari/') &&
2278
+ !ua.includes('Chrome/') &&
2279
+ !ua.includes('Chromium/') &&
2280
+ !ua.includes('CriOS/') &&
2281
+ !ua.includes('FxiOS/') &&
2282
+ !ua.includes('EdgiOS/');
2283
+ const isChromium = ua.includes('Chrome/') ||
2284
+ ua.includes('Chromium/') ||
2285
+ ua.includes('CriOS/') ||
2286
+ ua.includes('Edg/');
2287
+ cachedEngineProfile = {
2288
+ lineFitEpsilon: isSafari ? 1 / 64 : 0.005,
2289
+ carryCJKAfterClosingQuote: isChromium,
2290
+ preferPrefixWidthsForBreakableRuns: isSafari,
2291
+ preferEarlySoftHyphenBreak: isSafari,
2292
+ };
2293
+ return cachedEngineProfile;
2294
+ }
2295
+ function parseFontSize(font) {
2296
+ const m = font.match(/(\d+(?:\.\d+)?)\s*px/);
2297
+ return m ? parseFloat(m[1]) : 16;
2298
+ }
2299
+ function getSharedGraphemeSegmenter$1() {
2300
+ if (sharedGraphemeSegmenter$1 === null) {
2301
+ sharedGraphemeSegmenter$1 = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
2302
+ }
2303
+ return sharedGraphemeSegmenter$1;
2304
+ }
2305
+ function isEmojiGrapheme(g) {
2306
+ return emojiPresentationRe.test(g) || g.includes('\uFE0F');
2307
+ }
2308
+ function textMayContainEmoji(text) {
2309
+ return maybeEmojiRe.test(text);
2310
+ }
2311
+ function getEmojiCorrection(font, fontSize) {
2312
+ let correction = emojiCorrectionCache.get(font);
2313
+ if (correction !== undefined)
2314
+ return correction;
2315
+ const ctx = getMeasureContext();
2316
+ ctx.font = font;
2317
+ const canvasW = ctx.measureText('\u{1F600}').width;
2318
+ correction = 0;
2319
+ if (canvasW > fontSize + 0.5 &&
2320
+ typeof document !== 'undefined' &&
2321
+ document.body !== null) {
2322
+ const span = document.createElement('span');
2323
+ span.style.font = font;
2324
+ span.style.display = 'inline-block';
2325
+ span.style.visibility = 'hidden';
2326
+ span.style.position = 'absolute';
2327
+ span.textContent = '\u{1F600}';
2328
+ document.body.appendChild(span);
2329
+ const domW = span.getBoundingClientRect().width;
2330
+ document.body.removeChild(span);
2331
+ if (canvasW - domW > 0.5) {
2332
+ correction = canvasW - domW;
2333
+ }
2334
+ }
2335
+ emojiCorrectionCache.set(font, correction);
2336
+ return correction;
2337
+ }
2338
+ function countEmojiGraphemes(text) {
2339
+ let count = 0;
2340
+ const graphemeSegmenter = getSharedGraphemeSegmenter$1();
2341
+ for (const g of graphemeSegmenter.segment(text)) {
2342
+ if (isEmojiGrapheme(g.segment))
2343
+ count++;
2344
+ }
2345
+ return count;
2346
+ }
2347
+ function getEmojiCount(seg, metrics) {
2348
+ if (metrics.emojiCount === undefined) {
2349
+ metrics.emojiCount = countEmojiGraphemes(seg);
2350
+ }
2351
+ return metrics.emojiCount;
2352
+ }
2353
+ function getCorrectedSegmentWidth(seg, metrics, emojiCorrection) {
2354
+ if (emojiCorrection === 0)
2355
+ return metrics.width;
2356
+ return metrics.width - getEmojiCount(seg, metrics) * emojiCorrection;
2357
+ }
2358
+ function getSegmentBreakableFitAdvances(seg, metrics, cache, emojiCorrection, mode) {
2359
+ if (metrics.breakableFitAdvances !== undefined && metrics.breakableFitMode === mode) {
2360
+ return metrics.breakableFitAdvances;
2361
+ }
2362
+ metrics.breakableFitMode = mode;
2363
+ const graphemeSegmenter = getSharedGraphemeSegmenter$1();
2364
+ const graphemes = [];
2365
+ for (const gs of graphemeSegmenter.segment(seg)) {
2366
+ graphemes.push(gs.segment);
2367
+ }
2368
+ if (graphemes.length <= 1) {
2369
+ metrics.breakableFitAdvances = null;
2370
+ return metrics.breakableFitAdvances;
2371
+ }
2372
+ if (mode === 'sum-graphemes') {
2373
+ const advances = [];
2374
+ for (const grapheme of graphemes) {
2375
+ const graphemeMetrics = getSegmentMetrics(grapheme, cache);
2376
+ advances.push(getCorrectedSegmentWidth(grapheme, graphemeMetrics, emojiCorrection));
2377
+ }
2378
+ metrics.breakableFitAdvances = advances;
2379
+ return metrics.breakableFitAdvances;
2380
+ }
2381
+ if (mode === 'pair-context' || graphemes.length > MAX_PREFIX_FIT_GRAPHEMES) {
2382
+ const advances = [];
2383
+ let previousGrapheme = null;
2384
+ let previousWidth = 0;
2385
+ for (const grapheme of graphemes) {
2386
+ const graphemeMetrics = getSegmentMetrics(grapheme, cache);
2387
+ const currentWidth = getCorrectedSegmentWidth(grapheme, graphemeMetrics, emojiCorrection);
2388
+ if (previousGrapheme === null) {
2389
+ advances.push(currentWidth);
2390
+ }
2391
+ else {
2392
+ const pair = previousGrapheme + grapheme;
2393
+ const pairMetrics = getSegmentMetrics(pair, cache);
2394
+ advances.push(getCorrectedSegmentWidth(pair, pairMetrics, emojiCorrection) - previousWidth);
2395
+ }
2396
+ previousGrapheme = grapheme;
2397
+ previousWidth = currentWidth;
2398
+ }
2399
+ metrics.breakableFitAdvances = advances;
2400
+ return metrics.breakableFitAdvances;
2401
+ }
2402
+ const advances = [];
2403
+ let prefix = '';
2404
+ let prefixWidth = 0;
2405
+ for (const grapheme of graphemes) {
2406
+ prefix += grapheme;
2407
+ const prefixMetrics = getSegmentMetrics(prefix, cache);
2408
+ const nextPrefixWidth = getCorrectedSegmentWidth(prefix, prefixMetrics, emojiCorrection);
2409
+ advances.push(nextPrefixWidth - prefixWidth);
2410
+ prefixWidth = nextPrefixWidth;
2411
+ }
2412
+ metrics.breakableFitAdvances = advances;
2413
+ return metrics.breakableFitAdvances;
2414
+ }
2415
+ function getFontMeasurementState(font, needsEmojiCorrection) {
2416
+ const ctx = getMeasureContext();
2417
+ ctx.font = font;
2418
+ const cache = getSegmentMetricCache(font);
2419
+ const fontSize = parseFontSize(font);
2420
+ const emojiCorrection = needsEmojiCorrection ? getEmojiCorrection(font, fontSize) : 0;
2421
+ return { cache, fontSize, emojiCorrection };
2422
+ }
2423
+
2424
+ function consumesAtLineStart(kind) {
2425
+ return kind === 'space' || kind === 'zero-width-break' || kind === 'soft-hyphen';
2426
+ }
2427
+ function breaksAfter(kind) {
2428
+ return (kind === 'space' ||
2429
+ kind === 'preserved-space' ||
2430
+ kind === 'tab' ||
2431
+ kind === 'zero-width-break' ||
2432
+ kind === 'soft-hyphen');
2433
+ }
2434
+ function normalizeLineStartSegmentIndex(prepared, segmentIndex, endSegmentIndex = prepared.widths.length) {
2435
+ while (segmentIndex < endSegmentIndex) {
2436
+ const kind = prepared.kinds[segmentIndex];
2437
+ if (!consumesAtLineStart(kind))
2438
+ break;
2439
+ segmentIndex++;
2440
+ }
2441
+ return segmentIndex;
2442
+ }
2443
+ function getTabAdvance(lineWidth, tabStopAdvance) {
2444
+ if (tabStopAdvance <= 0)
2445
+ return 0;
2446
+ const remainder = lineWidth % tabStopAdvance;
2447
+ if (Math.abs(remainder) <= 1e-6)
2448
+ return tabStopAdvance;
2449
+ return tabStopAdvance - remainder;
2450
+ }
2451
+ function getLeadingLetterSpacing(prepared, hasContent, segmentIndex) {
2452
+ return (prepared.letterSpacing !== 0 &&
2453
+ hasContent &&
2454
+ prepared.spacingGraphemeCounts[segmentIndex] > 0)
2455
+ ? prepared.letterSpacing
2456
+ : 0;
2457
+ }
2458
+ function getLineEndContribution(leadingSpacing, segmentContribution) {
2459
+ return segmentContribution === 0 ? 0 : leadingSpacing + segmentContribution;
2460
+ }
2461
+ function getTabTrailingLetterSpacing(prepared, segmentIndex) {
2462
+ return (prepared.letterSpacing !== 0 &&
2463
+ prepared.spacingGraphemeCounts[segmentIndex] > 0)
2464
+ ? prepared.letterSpacing
2465
+ : 0;
2466
+ }
2467
+ function getWholeSegmentFitContribution(prepared, kind, segmentIndex, leadingSpacing, segmentWidth) {
2468
+ const segmentContribution = kind === 'tab'
2469
+ ? segmentWidth + getTabTrailingLetterSpacing(prepared, segmentIndex)
2470
+ : prepared.lineEndFitAdvances[segmentIndex];
2471
+ return getLineEndContribution(leadingSpacing, segmentContribution);
2472
+ }
2473
+ function getBreakOpportunityFitContribution(prepared, kind, segmentIndex, leadingSpacing) {
2474
+ const segmentContribution = kind === 'tab' ? 0 : prepared.lineEndFitAdvances[segmentIndex];
2475
+ return getLineEndContribution(leadingSpacing, segmentContribution);
2476
+ }
2477
+ function getLineEndPaintContribution(prepared, kind, segmentIndex, leadingSpacing, segmentWidth) {
2478
+ const segmentContribution = kind === 'tab' ? segmentWidth : prepared.lineEndPaintAdvances[segmentIndex];
2479
+ return getLineEndContribution(leadingSpacing, segmentContribution);
2480
+ }
2481
+ function getBreakableGraphemeAdvance(prepared, hasContent, baseAdvance) {
2482
+ return prepared.letterSpacing !== 0 && hasContent
2483
+ ? baseAdvance + prepared.letterSpacing
2484
+ : baseAdvance;
2485
+ }
2486
+ function getBreakableCandidateFitWidth(prepared, candidatePaintWidth) {
2487
+ return prepared.letterSpacing === 0
2488
+ ? candidatePaintWidth
2489
+ : candidatePaintWidth + prepared.letterSpacing;
2490
+ }
2491
+ function fitSoftHyphenBreak(graphemeFitAdvances, initialWidth, maxWidth, lineFitEpsilon, discretionaryHyphenWidth, letterSpacing) {
2492
+ let fitCount = 0;
2493
+ let fittedWidth = initialWidth;
2494
+ while (fitCount < graphemeFitAdvances.length) {
2495
+ const nextWidth = fittedWidth + graphemeFitAdvances[fitCount] + letterSpacing;
2496
+ const nextLineWidth = fitCount + 1 < graphemeFitAdvances.length
2497
+ ? nextWidth + discretionaryHyphenWidth
2498
+ : nextWidth;
2499
+ if (nextLineWidth > maxWidth + lineFitEpsilon)
2500
+ break;
2501
+ fittedWidth = nextWidth;
2502
+ fitCount++;
2503
+ }
2504
+ return { fitCount, fittedWidth };
2505
+ }
2506
+ function countPreparedLines(prepared, maxWidth) {
2507
+ return walkPreparedLinesRaw(prepared, maxWidth);
2508
+ }
2509
+ function walkPreparedLinesSimple(prepared, maxWidth, onLine) {
2510
+ const { widths, kinds, breakableFitAdvances } = prepared;
2511
+ if (widths.length === 0)
2512
+ return 0;
2513
+ const engineProfile = getEngineProfile();
2514
+ const lineFitEpsilon = engineProfile.lineFitEpsilon;
2515
+ const fitLimit = maxWidth + lineFitEpsilon;
2516
+ let lineCount = 0;
2517
+ let lineW = 0;
2518
+ let hasContent = false;
2519
+ let lineEndSegmentIndex = 0;
2520
+ let lineEndGraphemeIndex = 0;
2521
+ let pendingBreakSegmentIndex = -1;
2522
+ let pendingBreakPaintWidth = 0;
2523
+ function clearPendingBreak() {
2524
+ pendingBreakSegmentIndex = -1;
2525
+ pendingBreakPaintWidth = 0;
2526
+ }
2527
+ function emitCurrentLine(endSegmentIndex = lineEndSegmentIndex, endGraphemeIndex = lineEndGraphemeIndex, width = lineW) {
2528
+ lineCount++;
2529
+ lineW = 0;
2530
+ hasContent = false;
2531
+ clearPendingBreak();
2532
+ }
2533
+ function startLineAtSegment(segmentIndex, width) {
2534
+ hasContent = true;
2535
+ lineEndSegmentIndex = segmentIndex + 1;
2536
+ lineEndGraphemeIndex = 0;
2537
+ lineW = width;
2538
+ }
2539
+ function startLineAtGrapheme(segmentIndex, graphemeIndex, width) {
2540
+ hasContent = true;
2541
+ lineEndSegmentIndex = segmentIndex;
2542
+ lineEndGraphemeIndex = graphemeIndex + 1;
2543
+ lineW = width;
2544
+ }
2545
+ function appendWholeSegment(segmentIndex, width) {
2546
+ if (!hasContent) {
2547
+ startLineAtSegment(segmentIndex, width);
2548
+ return;
2549
+ }
2550
+ lineW += width;
2551
+ lineEndSegmentIndex = segmentIndex + 1;
2552
+ lineEndGraphemeIndex = 0;
2553
+ }
2554
+ function appendBreakableSegmentFrom(segmentIndex, startGraphemeIndex) {
2555
+ const fitAdvances = breakableFitAdvances[segmentIndex];
2556
+ for (let g = startGraphemeIndex; g < fitAdvances.length; g++) {
2557
+ const gw = fitAdvances[g];
2558
+ if (!hasContent) {
2559
+ startLineAtGrapheme(segmentIndex, g, gw);
2560
+ }
2561
+ else if (lineW + gw > fitLimit) {
2562
+ emitCurrentLine();
2563
+ startLineAtGrapheme(segmentIndex, g, gw);
2564
+ }
2565
+ else {
2566
+ lineW += gw;
2567
+ lineEndSegmentIndex = segmentIndex;
2568
+ lineEndGraphemeIndex = g + 1;
2569
+ }
2570
+ }
2571
+ if (hasContent && lineEndSegmentIndex === segmentIndex && lineEndGraphemeIndex === fitAdvances.length) {
2572
+ lineEndSegmentIndex = segmentIndex + 1;
2573
+ lineEndGraphemeIndex = 0;
2574
+ }
2575
+ }
2576
+ let i = 0;
2577
+ while (i < widths.length) {
2578
+ if (!hasContent) {
2579
+ i = normalizeLineStartSegmentIndex(prepared, i);
2580
+ if (i >= widths.length)
2581
+ break;
2582
+ }
2583
+ const w = widths[i];
2584
+ const kind = kinds[i];
2585
+ const breakAfter = breaksAfter(kind);
2586
+ if (!hasContent) {
2587
+ if (w > fitLimit && breakableFitAdvances[i] !== null) {
2588
+ appendBreakableSegmentFrom(i, 0);
2589
+ }
2590
+ else {
2591
+ startLineAtSegment(i, w);
2592
+ }
2593
+ if (breakAfter) {
2594
+ pendingBreakSegmentIndex = i + 1;
2595
+ pendingBreakPaintWidth = lineW - w;
2596
+ }
2597
+ i++;
2598
+ continue;
2599
+ }
2600
+ const newW = lineW + w;
2601
+ if (newW > fitLimit) {
2602
+ if (breakAfter) {
2603
+ appendWholeSegment(i, w);
2604
+ emitCurrentLine(i + 1, 0, lineW - w);
2605
+ i++;
2606
+ continue;
2607
+ }
2608
+ if (pendingBreakSegmentIndex >= 0) {
2609
+ if (lineEndSegmentIndex > pendingBreakSegmentIndex ||
2610
+ (lineEndSegmentIndex === pendingBreakSegmentIndex && lineEndGraphemeIndex > 0)) {
2611
+ emitCurrentLine();
2612
+ continue;
2613
+ }
2614
+ emitCurrentLine(pendingBreakSegmentIndex, 0, pendingBreakPaintWidth);
2615
+ continue;
2616
+ }
2617
+ if (w > fitLimit && breakableFitAdvances[i] !== null) {
2618
+ emitCurrentLine();
2619
+ appendBreakableSegmentFrom(i, 0);
2620
+ i++;
2621
+ continue;
2622
+ }
2623
+ emitCurrentLine();
2624
+ continue;
2625
+ }
2626
+ appendWholeSegment(i, w);
2627
+ if (breakAfter) {
2628
+ pendingBreakSegmentIndex = i + 1;
2629
+ pendingBreakPaintWidth = lineW - w;
2630
+ }
2631
+ i++;
2632
+ }
2633
+ if (hasContent)
2634
+ emitCurrentLine();
2635
+ return lineCount;
2636
+ }
2637
+ function walkPreparedLinesRaw(prepared, maxWidth, onLine) {
2638
+ if (prepared.simpleLineWalkFastPath) {
2639
+ return walkPreparedLinesSimple(prepared, maxWidth);
2640
+ }
2641
+ const { widths, kinds, breakableFitAdvances, discretionaryHyphenWidth, chunks, } = prepared;
2642
+ if (widths.length === 0 || chunks.length === 0)
2643
+ return 0;
2644
+ const engineProfile = getEngineProfile();
2645
+ const lineFitEpsilon = engineProfile.lineFitEpsilon;
2646
+ const fitLimit = maxWidth + lineFitEpsilon;
2647
+ let lineCount = 0;
2648
+ let lineW = 0;
2649
+ let hasContent = false;
2650
+ let lineEndSegmentIndex = 0;
2651
+ let lineEndGraphemeIndex = 0;
2652
+ let pendingBreakSegmentIndex = -1;
2653
+ let pendingBreakFitWidth = 0;
2654
+ let pendingBreakPaintWidth = 0;
2655
+ let pendingBreakKind = null;
2656
+ function clearPendingBreak() {
2657
+ pendingBreakSegmentIndex = -1;
2658
+ pendingBreakFitWidth = 0;
2659
+ pendingBreakPaintWidth = 0;
2660
+ pendingBreakKind = null;
2661
+ }
2662
+ function emitCurrentLine(endSegmentIndex = lineEndSegmentIndex, endGraphemeIndex = lineEndGraphemeIndex, width = lineW) {
2663
+ lineCount++;
2664
+ lineW = 0;
2665
+ hasContent = false;
2666
+ clearPendingBreak();
2667
+ }
2668
+ function startLineAtSegment(segmentIndex, width) {
2669
+ hasContent = true;
2670
+ lineEndSegmentIndex = segmentIndex + 1;
2671
+ lineEndGraphemeIndex = 0;
2672
+ lineW = width;
2673
+ }
2674
+ function startLineAtGrapheme(segmentIndex, graphemeIndex, width) {
2675
+ hasContent = true;
2676
+ lineEndSegmentIndex = segmentIndex;
2677
+ lineEndGraphemeIndex = graphemeIndex + 1;
2678
+ lineW = width;
2679
+ }
2680
+ function appendWholeSegment(segmentIndex, advance) {
2681
+ if (!hasContent) {
2682
+ startLineAtSegment(segmentIndex, advance);
2683
+ return;
2684
+ }
2685
+ lineW += advance;
2686
+ lineEndSegmentIndex = segmentIndex + 1;
2687
+ lineEndGraphemeIndex = 0;
2688
+ }
2689
+ function updatePendingBreakForWholeSegment(kind, breakAfter, segmentIndex, segmentWidth, leadingSpacing, advance) {
2690
+ if (!breakAfter)
2691
+ return;
2692
+ const fitAdvance = getBreakOpportunityFitContribution(prepared, kind, segmentIndex, leadingSpacing);
2693
+ const paintAdvance = getLineEndPaintContribution(prepared, kind, segmentIndex, leadingSpacing, segmentWidth);
2694
+ pendingBreakSegmentIndex = segmentIndex + 1;
2695
+ pendingBreakFitWidth = lineW - advance + fitAdvance;
2696
+ pendingBreakPaintWidth = lineW - advance + paintAdvance;
2697
+ pendingBreakKind = kind;
2698
+ }
2699
+ function appendBreakableSegmentFrom(segmentIndex, startGraphemeIndex) {
2700
+ const fitAdvances = breakableFitAdvances[segmentIndex];
2701
+ for (let g = startGraphemeIndex; g < fitAdvances.length; g++) {
2702
+ const baseGw = fitAdvances[g];
2703
+ if (!hasContent) {
2704
+ startLineAtGrapheme(segmentIndex, g, baseGw);
2705
+ }
2706
+ else {
2707
+ const gw = getBreakableGraphemeAdvance(prepared, true, baseGw);
2708
+ const candidatePaintWidth = lineW + gw;
2709
+ if (getBreakableCandidateFitWidth(prepared, candidatePaintWidth) > fitLimit) {
2710
+ emitCurrentLine();
2711
+ startLineAtGrapheme(segmentIndex, g, baseGw);
2712
+ }
2713
+ else {
2714
+ lineW = candidatePaintWidth;
2715
+ lineEndSegmentIndex = segmentIndex;
2716
+ lineEndGraphemeIndex = g + 1;
2717
+ }
2718
+ }
2719
+ }
2720
+ if (hasContent && lineEndSegmentIndex === segmentIndex && lineEndGraphemeIndex === fitAdvances.length) {
2721
+ lineEndSegmentIndex = segmentIndex + 1;
2722
+ lineEndGraphemeIndex = 0;
2723
+ }
2724
+ }
2725
+ function continueSoftHyphenBreakableSegment(segmentIndex) {
2726
+ if (pendingBreakKind !== 'soft-hyphen')
2727
+ return false;
2728
+ const fitWidths = breakableFitAdvances[segmentIndex];
2729
+ if (fitWidths == null)
2730
+ return false;
2731
+ const { fitCount, fittedWidth } = fitSoftHyphenBreak(fitWidths, lineW, maxWidth, lineFitEpsilon, discretionaryHyphenWidth, prepared.letterSpacing);
2732
+ if (fitCount === 0)
2733
+ return false;
2734
+ lineW = fittedWidth;
2735
+ lineEndSegmentIndex = segmentIndex;
2736
+ lineEndGraphemeIndex = fitCount;
2737
+ clearPendingBreak();
2738
+ if (fitCount === fitWidths.length) {
2739
+ lineEndSegmentIndex = segmentIndex + 1;
2740
+ lineEndGraphemeIndex = 0;
2741
+ return true;
2742
+ }
2743
+ emitCurrentLine(segmentIndex, fitCount, fittedWidth + discretionaryHyphenWidth);
2744
+ appendBreakableSegmentFrom(segmentIndex, fitCount);
2745
+ return true;
2746
+ }
2747
+ function emitEmptyChunk(chunk) {
2748
+ lineCount++;
2749
+ clearPendingBreak();
2750
+ }
2751
+ for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
2752
+ const chunk = chunks[chunkIndex];
2753
+ if (chunk.startSegmentIndex === chunk.endSegmentIndex) {
2754
+ emitEmptyChunk();
2755
+ continue;
2756
+ }
2757
+ hasContent = false;
2758
+ lineW = 0;
2759
+ lineEndSegmentIndex = chunk.startSegmentIndex;
2760
+ lineEndGraphemeIndex = 0;
2761
+ clearPendingBreak();
2762
+ let i = chunk.startSegmentIndex;
2763
+ while (i < chunk.endSegmentIndex) {
2764
+ if (!hasContent) {
2765
+ i = normalizeLineStartSegmentIndex(prepared, i, chunk.endSegmentIndex);
2766
+ if (i >= chunk.endSegmentIndex)
2767
+ break;
2768
+ }
2769
+ const kind = kinds[i];
2770
+ const breakAfter = breaksAfter(kind);
2771
+ const leadingSpacing = getLeadingLetterSpacing(prepared, hasContent, i);
2772
+ const w = kind === 'tab'
2773
+ ? getTabAdvance(lineW + leadingSpacing, prepared.tabStopAdvance)
2774
+ : widths[i];
2775
+ const advance = leadingSpacing + w;
2776
+ const fitAdvance = getWholeSegmentFitContribution(prepared, kind, i, leadingSpacing, w);
2777
+ if (kind === 'soft-hyphen') {
2778
+ if (hasContent) {
2779
+ lineEndSegmentIndex = i + 1;
2780
+ lineEndGraphemeIndex = 0;
2781
+ pendingBreakSegmentIndex = i + 1;
2782
+ pendingBreakFitWidth = lineW + discretionaryHyphenWidth;
2783
+ pendingBreakPaintWidth = lineW + discretionaryHyphenWidth;
2784
+ pendingBreakKind = kind;
2785
+ }
2786
+ i++;
2787
+ continue;
2788
+ }
2789
+ if (!hasContent) {
2790
+ if (fitAdvance > fitLimit && breakableFitAdvances[i] !== null) {
2791
+ appendBreakableSegmentFrom(i, 0);
2792
+ }
2793
+ else {
2794
+ startLineAtSegment(i, w);
2795
+ }
2796
+ updatePendingBreakForWholeSegment(kind, breakAfter, i, w, leadingSpacing, advance);
2797
+ i++;
2798
+ continue;
2799
+ }
2800
+ const newFitW = lineW + fitAdvance;
2801
+ if (newFitW > fitLimit) {
2802
+ const currentBreakFitWidth = lineW + getBreakOpportunityFitContribution(prepared, kind, i, leadingSpacing);
2803
+ const currentBreakPaintWidth = lineW + getLineEndPaintContribution(prepared, kind, i, leadingSpacing, w);
2804
+ if (pendingBreakKind === 'soft-hyphen' &&
2805
+ engineProfile.preferEarlySoftHyphenBreak &&
2806
+ pendingBreakFitWidth <= fitLimit) {
2807
+ emitCurrentLine(pendingBreakSegmentIndex, 0, pendingBreakPaintWidth);
2808
+ continue;
2809
+ }
2810
+ if (pendingBreakKind === 'soft-hyphen' && continueSoftHyphenBreakableSegment(i)) {
2811
+ i++;
2812
+ continue;
2813
+ }
2814
+ if (breakAfter && currentBreakFitWidth <= fitLimit) {
2815
+ appendWholeSegment(i, advance);
2816
+ emitCurrentLine(i + 1, 0, currentBreakPaintWidth);
2817
+ i++;
2818
+ continue;
2819
+ }
2820
+ if (pendingBreakSegmentIndex >= 0 && pendingBreakFitWidth <= fitLimit) {
2821
+ if (lineEndSegmentIndex > pendingBreakSegmentIndex ||
2822
+ (lineEndSegmentIndex === pendingBreakSegmentIndex && lineEndGraphemeIndex > 0)) {
2823
+ emitCurrentLine();
2824
+ continue;
2825
+ }
2826
+ const nextSegmentIndex = pendingBreakSegmentIndex;
2827
+ emitCurrentLine(nextSegmentIndex, 0, pendingBreakPaintWidth);
2828
+ i = nextSegmentIndex;
2829
+ continue;
2830
+ }
2831
+ if (fitAdvance > fitLimit && breakableFitAdvances[i] !== null) {
2832
+ emitCurrentLine();
2833
+ appendBreakableSegmentFrom(i, 0);
2834
+ i++;
2835
+ continue;
2836
+ }
2837
+ emitCurrentLine();
2838
+ continue;
2839
+ }
2840
+ appendWholeSegment(i, advance);
2841
+ updatePendingBreakForWholeSegment(kind, breakAfter, i, w, leadingSpacing, advance);
2842
+ i++;
2843
+ }
2844
+ if (hasContent) {
2845
+ const finalPaintWidth = pendingBreakSegmentIndex === chunk.consumedEndSegmentIndex
2846
+ ? pendingBreakPaintWidth
2847
+ : lineW;
2848
+ emitCurrentLine(chunk.consumedEndSegmentIndex, 0, finalPaintWidth);
2849
+ }
2850
+ }
2851
+ return lineCount;
2852
+ }
2853
+
2854
+ // Text measurement for browser environments using canvas measureText.
2855
+ //
2856
+ // Problem: DOM-based text measurement (getBoundingClientRect, offsetHeight)
2857
+ // forces synchronous layout reflow. When components independently measure text,
2858
+ // each measurement triggers a reflow of the entire document. This creates
2859
+ // read/write interleaving that can cost 30ms+ per frame for 500 text blocks.
2860
+ //
2861
+ // Solution: two-phase measurement centered around canvas measureText.
2862
+ // prepare(text, font) — segments text via Intl.Segmenter, measures each word
2863
+ // via canvas, caches widths, and does one cached DOM calibration read per
2864
+ // font when emoji correction is needed. Call once when text first appears.
2865
+ // layout(prepared, maxWidth, lineHeight) — walks cached word widths with pure
2866
+ // arithmetic to count lines and compute height. Call on every resize.
2867
+ // ~0.0002ms per text.
2868
+ //
2869
+ // i18n: Intl.Segmenter handles CJK (per-character breaking), Thai, Arabic, etc.
2870
+ // Bidi: simplified rich-path metadata for mixed LTR/RTL custom rendering.
2871
+ // Punctuation merging: "better." measured as one unit (matches CSS behavior).
2872
+ // Trailing whitespace: hangs past line edge without triggering breaks (CSS behavior).
2873
+ // overflow-wrap: pre-measured grapheme widths enable character-level word breaking.
2874
+ //
2875
+ // Emoji correction: Chrome/Firefox canvas measures emoji wider than DOM at font
2876
+ // sizes <24px on macOS (Apple Color Emoji). The inflation is constant per emoji
2877
+ // grapheme at a given size, font-independent. Auto-detected by comparing canvas
2878
+ // vs actual DOM emoji width (one cached DOM read per font). Safari canvas and
2879
+ // DOM agree (both wider than fontSize), so correction = 0 there.
2880
+ //
2881
+ // Limitations:
2882
+ // - system-ui font: canvas resolves to different optical variants than DOM on macOS.
2883
+ // Use named fonts (Helvetica, Inter, etc.) for guaranteed accuracy.
2884
+ // See RESEARCH.md "Discovery: system-ui font resolution mismatch".
2885
+ //
2886
+ // Based on Sebastian Markbage's text-layout research (github.com/chenglou/text-layout).
2887
+ let sharedGraphemeSegmenter = null;
2888
+ function getSharedGraphemeSegmenter() {
2889
+ if (sharedGraphemeSegmenter === null) {
2890
+ sharedGraphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
2891
+ }
2892
+ return sharedGraphemeSegmenter;
2893
+ }
2894
+ // --- Public API ---
2895
+ function createEmptyPrepared(includeSegments) {
2896
+ return {
2897
+ widths: [],
2898
+ lineEndFitAdvances: [],
2899
+ lineEndPaintAdvances: [],
2900
+ kinds: [],
2901
+ simpleLineWalkFastPath: true,
2902
+ segLevels: null,
2903
+ breakableFitAdvances: [],
2904
+ letterSpacing: 0,
2905
+ spacingGraphemeCounts: [],
2906
+ discretionaryHyphenWidth: 0,
2907
+ tabStopAdvance: 0,
2908
+ chunks: [],
2909
+ };
2910
+ }
2911
+ function buildBaseCjkUnits(segText, engineProfile) {
2912
+ const units = [];
2913
+ let unitParts = [];
2914
+ let unitStart = 0;
2915
+ let unitContainsCJK = false;
2916
+ let unitEndsWithClosingQuote = false;
2917
+ let unitIsSingleKinsokuEnd = false;
2918
+ function pushUnit() {
2919
+ if (unitParts.length === 0)
2920
+ return;
2921
+ units.push({
2922
+ text: unitParts.length === 1 ? unitParts[0] : unitParts.join(''),
2923
+ start: unitStart,
2924
+ });
2925
+ unitParts = [];
2926
+ unitContainsCJK = false;
2927
+ unitEndsWithClosingQuote = false;
2928
+ unitIsSingleKinsokuEnd = false;
2929
+ }
2930
+ function startUnit(grapheme, start, graphemeContainsCJK) {
2931
+ unitParts = [grapheme];
2932
+ unitStart = start;
2933
+ unitContainsCJK = graphemeContainsCJK;
2934
+ unitEndsWithClosingQuote = endsWithClosingQuote(grapheme);
2935
+ unitIsSingleKinsokuEnd = kinsokuEnd.has(grapheme);
2936
+ }
2937
+ function appendToUnit(grapheme, graphemeContainsCJK) {
2938
+ unitParts.push(grapheme);
2939
+ unitContainsCJK = unitContainsCJK || graphemeContainsCJK;
2940
+ const graphemeEndsWithClosingQuote = endsWithClosingQuote(grapheme);
2941
+ if (grapheme.length === 1 && leftStickyPunctuation.has(grapheme)) {
2942
+ unitEndsWithClosingQuote = unitEndsWithClosingQuote || graphemeEndsWithClosingQuote;
2943
+ }
2944
+ else {
2945
+ unitEndsWithClosingQuote = graphemeEndsWithClosingQuote;
2946
+ }
2947
+ unitIsSingleKinsokuEnd = false;
2948
+ }
2949
+ for (const gs of getSharedGraphemeSegmenter().segment(segText)) {
2950
+ const grapheme = gs.segment;
2951
+ const graphemeContainsCJK = isCJK(grapheme);
2952
+ if (unitParts.length === 0) {
2953
+ startUnit(grapheme, gs.index, graphemeContainsCJK);
2954
+ continue;
2955
+ }
2956
+ if (unitIsSingleKinsokuEnd ||
2957
+ kinsokuStart.has(grapheme) ||
2958
+ leftStickyPunctuation.has(grapheme) ||
2959
+ (engineProfile.carryCJKAfterClosingQuote &&
2960
+ graphemeContainsCJK &&
2961
+ unitEndsWithClosingQuote)) {
2962
+ appendToUnit(grapheme, graphemeContainsCJK);
2963
+ continue;
2964
+ }
2965
+ if (!unitContainsCJK && !graphemeContainsCJK) {
2966
+ appendToUnit(grapheme, graphemeContainsCJK);
2967
+ continue;
2968
+ }
2969
+ pushUnit();
2970
+ startUnit(grapheme, gs.index, graphemeContainsCJK);
2971
+ }
2972
+ pushUnit();
2973
+ return units;
2974
+ }
2975
+ function mergeKeepAllTextUnits(units) {
2976
+ if (units.length <= 1)
2977
+ return units;
2978
+ const merged = [];
2979
+ let currentTextParts = [units[0].text];
2980
+ let currentStart = units[0].start;
2981
+ let currentContainsCJK = isCJK(units[0].text);
2982
+ let currentCanContinue = canContinueKeepAllTextRun(units[0].text);
2983
+ function flushCurrent() {
2984
+ merged.push({
2985
+ text: currentTextParts.length === 1 ? currentTextParts[0] : currentTextParts.join(''),
2986
+ start: currentStart,
2987
+ });
2988
+ }
2989
+ for (let i = 1; i < units.length; i++) {
2990
+ const next = units[i];
2991
+ const nextContainsCJK = isCJK(next.text);
2992
+ const nextCanContinue = canContinueKeepAllTextRun(next.text);
2993
+ if (currentContainsCJK && currentCanContinue) {
2994
+ currentTextParts.push(next.text);
2995
+ currentContainsCJK = currentContainsCJK || nextContainsCJK;
2996
+ currentCanContinue = nextCanContinue;
2997
+ continue;
2998
+ }
2999
+ flushCurrent();
3000
+ currentTextParts = [next.text];
3001
+ currentStart = next.start;
3002
+ currentContainsCJK = nextContainsCJK;
3003
+ currentCanContinue = nextCanContinue;
3004
+ }
3005
+ flushCurrent();
3006
+ return merged;
3007
+ }
3008
+ function countRenderedSpacingGraphemes(text, kind) {
3009
+ if (kind === 'zero-width-break' ||
3010
+ kind === 'soft-hyphen' ||
3011
+ kind === 'hard-break') {
3012
+ return 0;
3013
+ }
3014
+ if (kind === 'tab')
3015
+ return 1;
3016
+ let count = 0;
3017
+ const graphemeSegmenter = getSharedGraphemeSegmenter();
3018
+ for (const _ of graphemeSegmenter.segment(text))
3019
+ count++;
3020
+ return count;
3021
+ }
3022
+ function addInternalLetterSpacing(width, graphemeCount, letterSpacing) {
3023
+ return graphemeCount > 1 ? width + (graphemeCount - 1) * letterSpacing : width;
3024
+ }
3025
+ function measureAnalysis(analysis, font, includeSegments, wordBreak, letterSpacing) {
3026
+ const engineProfile = getEngineProfile();
3027
+ const { cache, emojiCorrection } = getFontMeasurementState(font, textMayContainEmoji(analysis.normalized));
3028
+ const discretionaryHyphenWidth = getCorrectedSegmentWidth('-', getSegmentMetrics('-', cache), emojiCorrection) +
3029
+ (letterSpacing === 0 ? 0 : letterSpacing);
3030
+ const spaceWidth = getCorrectedSegmentWidth(' ', getSegmentMetrics(' ', cache), emojiCorrection);
3031
+ const tabStopAdvance = spaceWidth * 8;
3032
+ const hasLetterSpacing = letterSpacing !== 0;
3033
+ if (analysis.len === 0)
3034
+ return createEmptyPrepared();
3035
+ const widths = [];
3036
+ const lineEndFitAdvances = [];
3037
+ const lineEndPaintAdvances = [];
3038
+ const kinds = [];
3039
+ let simpleLineWalkFastPath = analysis.chunks.length <= 1 && !hasLetterSpacing;
3040
+ const segStarts = null;
3041
+ const breakableFitAdvances = [];
3042
+ const spacingGraphemeCounts = [];
3043
+ const segments = includeSegments ? [] : null;
3044
+ const preparedStartByAnalysisIndex = Array.from({ length: analysis.len });
3045
+ function pushMeasuredSegment(text, width, lineEndFitAdvance, lineEndPaintAdvance, kind, start, breakableFitAdvance, spacingGraphemeCount) {
3046
+ if (kind !== 'text' && kind !== 'space' && kind !== 'zero-width-break') {
3047
+ simpleLineWalkFastPath = false;
3048
+ }
3049
+ widths.push(width);
3050
+ lineEndFitAdvances.push(lineEndFitAdvance);
3051
+ lineEndPaintAdvances.push(lineEndPaintAdvance);
3052
+ kinds.push(kind);
3053
+ breakableFitAdvances.push(breakableFitAdvance);
3054
+ if (hasLetterSpacing)
3055
+ spacingGraphemeCounts.push(spacingGraphemeCount);
3056
+ if (segments !== null)
3057
+ segments.push(text);
3058
+ }
3059
+ function pushMeasuredTextSegment(text, kind, start, wordLike, allowOverflowBreaks) {
3060
+ const textMetrics = getSegmentMetrics(text, cache);
3061
+ const spacingGraphemeCount = hasLetterSpacing
3062
+ ? countRenderedSpacingGraphemes(text, kind)
3063
+ : 0;
3064
+ const width = addInternalLetterSpacing(getCorrectedSegmentWidth(text, textMetrics, emojiCorrection), spacingGraphemeCount, letterSpacing);
3065
+ const baseLineEndFitAdvance = kind === 'space' || kind === 'preserved-space' || kind === 'zero-width-break'
3066
+ ? 0
3067
+ : width;
3068
+ const lineEndFitAdvance = baseLineEndFitAdvance === 0
3069
+ ? 0
3070
+ : baseLineEndFitAdvance + (spacingGraphemeCount > 0 ? letterSpacing : 0);
3071
+ const lineEndPaintAdvance = kind === 'space' || kind === 'zero-width-break'
3072
+ ? 0
3073
+ : width;
3074
+ if (allowOverflowBreaks && wordLike && text.length > 1) {
3075
+ let fitMode = 'sum-graphemes';
3076
+ if (letterSpacing !== 0) {
3077
+ fitMode = 'segment-prefixes';
3078
+ }
3079
+ else if (isNumericRunSegment(text)) {
3080
+ fitMode = 'pair-context';
3081
+ }
3082
+ else if (engineProfile.preferPrefixWidthsForBreakableRuns) {
3083
+ fitMode = 'segment-prefixes';
3084
+ }
3085
+ const fitAdvances = getSegmentBreakableFitAdvances(text, textMetrics, cache, emojiCorrection, fitMode);
3086
+ pushMeasuredSegment(text, width, lineEndFitAdvance, lineEndPaintAdvance, kind, start, fitAdvances, spacingGraphemeCount);
3087
+ return;
3088
+ }
3089
+ pushMeasuredSegment(text, width, lineEndFitAdvance, lineEndPaintAdvance, kind, start, null, spacingGraphemeCount);
3090
+ }
3091
+ for (let mi = 0; mi < analysis.len; mi++) {
3092
+ preparedStartByAnalysisIndex[mi] = widths.length;
3093
+ const segText = analysis.texts[mi];
3094
+ const segWordLike = analysis.isWordLike[mi];
3095
+ const segKind = analysis.kinds[mi];
3096
+ const segStart = analysis.starts[mi];
3097
+ if (segKind === 'soft-hyphen') {
3098
+ pushMeasuredSegment(segText, 0, discretionaryHyphenWidth, discretionaryHyphenWidth, segKind, segStart, null, 0);
3099
+ continue;
3100
+ }
3101
+ if (segKind === 'hard-break') {
3102
+ pushMeasuredSegment(segText, 0, 0, 0, segKind, segStart, null, 0);
3103
+ continue;
3104
+ }
3105
+ if (segKind === 'tab') {
3106
+ pushMeasuredSegment(segText, 0, 0, 0, segKind, segStart, null, hasLetterSpacing ? countRenderedSpacingGraphemes(segText, segKind) : 0);
3107
+ continue;
3108
+ }
3109
+ const segMetrics = getSegmentMetrics(segText, cache);
3110
+ if (segKind === 'text' && segMetrics.containsCJK) {
3111
+ const baseUnits = buildBaseCjkUnits(segText, engineProfile);
3112
+ const measuredUnits = wordBreak === 'keep-all'
3113
+ ? mergeKeepAllTextUnits(baseUnits)
3114
+ : baseUnits;
3115
+ for (let i = 0; i < measuredUnits.length; i++) {
3116
+ const unit = measuredUnits[i];
3117
+ pushMeasuredTextSegment(unit.text, 'text', segStart + unit.start, segWordLike, wordBreak === 'keep-all' || !isCJK(unit.text));
3118
+ }
3119
+ continue;
3120
+ }
3121
+ pushMeasuredTextSegment(segText, segKind, segStart, segWordLike, true);
3122
+ }
3123
+ const chunks = mapAnalysisChunksToPreparedChunks(analysis.chunks, preparedStartByAnalysisIndex, widths.length);
3124
+ const segLevels = segStarts === null ? null : computeSegmentLevels(analysis.normalized, segStarts);
3125
+ if (segments !== null) {
3126
+ return {
3127
+ widths,
3128
+ lineEndFitAdvances,
3129
+ lineEndPaintAdvances,
3130
+ kinds,
3131
+ simpleLineWalkFastPath,
3132
+ segLevels,
3133
+ breakableFitAdvances,
3134
+ letterSpacing,
3135
+ spacingGraphemeCounts,
3136
+ discretionaryHyphenWidth,
3137
+ tabStopAdvance,
3138
+ chunks,
3139
+ segments,
3140
+ };
3141
+ }
3142
+ return {
3143
+ widths,
3144
+ lineEndFitAdvances,
3145
+ lineEndPaintAdvances,
3146
+ kinds,
3147
+ simpleLineWalkFastPath,
3148
+ segLevels,
3149
+ breakableFitAdvances,
3150
+ letterSpacing,
3151
+ spacingGraphemeCounts,
3152
+ discretionaryHyphenWidth,
3153
+ tabStopAdvance,
3154
+ chunks,
3155
+ };
3156
+ }
3157
+ function mapAnalysisChunksToPreparedChunks(chunks, preparedStartByAnalysisIndex, preparedEndSegmentIndex) {
3158
+ const preparedChunks = [];
3159
+ for (let i = 0; i < chunks.length; i++) {
3160
+ const chunk = chunks[i];
3161
+ const startSegmentIndex = chunk.startSegmentIndex < preparedStartByAnalysisIndex.length
3162
+ ? preparedStartByAnalysisIndex[chunk.startSegmentIndex]
3163
+ : preparedEndSegmentIndex;
3164
+ const endSegmentIndex = chunk.endSegmentIndex < preparedStartByAnalysisIndex.length
3165
+ ? preparedStartByAnalysisIndex[chunk.endSegmentIndex]
3166
+ : preparedEndSegmentIndex;
3167
+ const consumedEndSegmentIndex = chunk.consumedEndSegmentIndex < preparedStartByAnalysisIndex.length
3168
+ ? preparedStartByAnalysisIndex[chunk.consumedEndSegmentIndex]
3169
+ : preparedEndSegmentIndex;
3170
+ preparedChunks.push({
3171
+ startSegmentIndex,
3172
+ endSegmentIndex,
3173
+ consumedEndSegmentIndex,
3174
+ });
3175
+ }
3176
+ return preparedChunks;
3177
+ }
3178
+ function prepareInternal(text, font, includeSegments, options) {
3179
+ const wordBreak = options?.wordBreak ?? 'normal';
3180
+ const letterSpacing = options?.letterSpacing ?? 0;
3181
+ const analysis = analyzeText(text, getEngineProfile(), options?.whiteSpace, wordBreak);
3182
+ return measureAnalysis(analysis, font, includeSegments, wordBreak, letterSpacing);
3183
+ }
3184
+ // Prepare text for layout. Segments the text, measures each segment via canvas,
3185
+ // and stores the widths for fast relayout at any width. Call once per text block
3186
+ // (e.g. when a comment first appears). The result is width-independent — the
3187
+ // same PreparedText can be laid out at any maxWidth and lineHeight via layout().
3188
+ //
3189
+ // Steps:
3190
+ // 1. Normalize collapsible whitespace (CSS white-space: normal behavior)
3191
+ // 2. Segment via Intl.Segmenter (handles CJK, Thai, etc.)
3192
+ // 3. Merge punctuation into preceding word ("better." as one unit)
3193
+ // 4. Split CJK words into individual graphemes (per-character line breaks)
3194
+ // 5. Measure each segment via canvas measureText, cache by (segment, font)
3195
+ // 6. Pre-measure graphemes of long words (for overflow-wrap: break-word)
3196
+ // 7. Correct emoji canvas inflation (auto-detected per font size)
3197
+ // 8. Optionally compute rich-path bidi metadata for custom renderers
3198
+ function prepare(text, font, options) {
3199
+ return prepareInternal(text, font, false, options);
3200
+ }
3201
+ function getInternalPrepared(prepared) {
3202
+ return prepared;
3203
+ }
3204
+ // Layout prepared text at a given max width and caller-provided lineHeight.
3205
+ // Pure arithmetic on cached widths — no canvas calls, no DOM reads, no string
3206
+ // operations, no allocations.
3207
+ // ~0.0002ms per text block. Call on every resize.
3208
+ //
3209
+ // Line breaking rules (matching CSS white-space: normal + overflow-wrap: break-word):
3210
+ // - Break before any non-space segment that would overflow the line
3211
+ // - Trailing whitespace hangs past the line edge (doesn't trigger breaks)
3212
+ // - Segments wider than maxWidth are broken at grapheme boundaries
3213
+ function layout(prepared, maxWidth, lineHeight) {
3214
+ // Keep the resize hot path specialized. `layoutWithLines()` shares the same
3215
+ // break semantics but also tracks line ranges; the extra bookkeeping is too
3216
+ // expensive to pay on every hot-path `layout()` call.
3217
+ const lineCount = countPreparedLines(getInternalPrepared(prepared), maxWidth);
3218
+ return { lineCount, height: lineCount * lineHeight };
3219
+ }
3220
+
3221
+ // SPDX-FileCopyrightText: © 2024 Schneider Electric
3222
+ //
3223
+ // SPDX-License-Identifier: Apache-2.0
3224
+ const inheritAttributes = (element, attributes = []) => {
3225
+ const attributeObject = {};
3226
+ for (const attribute of attributes) {
3227
+ const value = element.getAttribute(attribute);
3228
+ if (value !== null) {
3229
+ attributeObject[attribute] = value;
3230
+ element.removeAttribute(attribute);
3231
+ }
3232
+ }
3233
+ return attributeObject;
3234
+ };
3235
+ const ariaAttributes = [
3236
+ 'aria-activedescendant',
3237
+ 'aria-atomic',
3238
+ 'aria-autocomplete',
3239
+ 'aria-braillelabel',
3240
+ 'aria-brailleroledescription',
3241
+ 'aria-busy',
3242
+ 'aria-checked',
3243
+ 'aria-colcount',
3244
+ 'aria-colindex',
3245
+ 'aria-colindextext',
3246
+ 'aria-colspan',
3247
+ 'aria-controls',
3248
+ 'aria-current',
3249
+ 'aria-describedby',
3250
+ 'aria-description',
3251
+ 'aria-details',
3252
+ 'aria-disabled',
3253
+ 'aria-errormessage',
3254
+ 'aria-expanded',
3255
+ 'aria-flowto',
3256
+ 'aria-haspopup',
3257
+ 'aria-hidden',
3258
+ 'aria-invalid',
3259
+ 'aria-keyshortcuts',
3260
+ 'aria-label',
3261
+ 'aria-labelledby',
3262
+ 'aria-level',
3263
+ 'aria-live',
3264
+ 'aria-multiline',
3265
+ 'aria-multiselectable',
3266
+ 'aria-orientation',
3267
+ 'aria-owns',
3268
+ 'aria-placeholder',
3269
+ 'aria-posinset',
3270
+ 'aria-pressed',
3271
+ 'aria-readonly',
3272
+ 'aria-relevant',
3273
+ 'aria-required',
3274
+ 'aria-roledescription',
3275
+ 'aria-rowcount',
3276
+ 'aria-rowindex',
3277
+ 'aria-rowindextext',
3278
+ 'aria-rowspan',
3279
+ 'aria-selected',
3280
+ 'aria-setsize',
3281
+ 'aria-sort',
3282
+ 'aria-valuemax',
3283
+ 'aria-valuemin',
3284
+ 'aria-valuenow',
3285
+ 'aria-valuetext',
3286
+ 'role',
3287
+ ];
3288
+ /**
3289
+ * Returns an array of aria attributes that should be copied from
3290
+ * the shadow host element to a target within the light DOM.
3291
+ *
3292
+ * @param element The element that the attributes should be copied from.
3293
+ */
3294
+ const inheritAriaAttributes = (element) => inheritAttributes(element, ariaAttributes);
3295
+ const prefix = 'Invariant failed';
3296
+ /**
3297
+ * Throws an error if the value is falsy.
3298
+ *
3299
+ * @param value Value to test.
3300
+ * @param message Optional message to display in development builds.
3301
+ */
3302
+ function invariant(value, message) {
3303
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
3304
+ if (value)
3305
+ return;
3306
+ throw new Error(prefix);
3307
+ }
3308
+ /**
3309
+ * From an object pick a set of keys.
3310
+ *
3311
+ * @param object Object to pick from.
3312
+ * @param keys They keys to pick.
3313
+ * @returns New object with only the picked keys.
3314
+ */
3315
+ const pick = (object, ...keys) => {
3316
+ const returnValue = {};
3317
+ for (const key of keys)
3318
+ returnValue[key] = object[key];
3319
+ return returnValue;
3320
+ };
3321
+ const pickFocusEventAttributes = (event) => pick(event, 'relatedTarget');
3322
+ const pickInputEventAttributes = (event) => pick(event, 'data', 'inputType', 'isComposing');
3323
+ const getConversionFactor = (element, unit) => {
3324
+ switch (unit) {
3325
+ case 'cm': {
3326
+ return 96 / 2.54;
3327
+ }
3328
+ case 'em': {
3329
+ return Number.parseFloat(globalThis.getComputedStyle(element.parentElement ?? document.documentElement).fontSize);
3330
+ }
3331
+ case 'in': {
3332
+ return 96;
3333
+ }
3334
+ case 'mm': {
3335
+ return 96 / 25.4;
3336
+ }
3337
+ case 'pc': {
3338
+ return 16;
3339
+ }
3340
+ case 'pt': {
3341
+ return 96 / 72;
3342
+ }
3343
+ case 'px': {
3344
+ return 1;
3345
+ }
3346
+ case 'rem': {
3347
+ return Number.parseFloat(globalThis.getComputedStyle(document.documentElement).fontSize);
3348
+ }
3349
+ default: {
3350
+ return undefined;
3351
+ }
3352
+ }
3353
+ };
3354
+ const propertyToPx = (element, property) => {
3355
+ const value = globalThis.getComputedStyle(element).getPropertyValue(property);
3356
+ const number = Number.parseFloat(value);
3357
+ if (Number.isNaN(number))
3358
+ return undefined;
3359
+ const unit = /\s*[\d+.-]*\s*(.*)/.exec(value)?.[1] ?? '';
3360
+ const conversionFactor = getConversionFactor(element, unit) ?? 1;
3361
+ return number * conversionFactor;
3362
+ };
3363
+ const ignorePromise = (promise) => {
3364
+ promise.catch(() => {
3365
+ invariant(false);
3366
+ });
3367
+ };
3368
+ const isTouchDevice = () => 'ontouchstart' in globalThis ||
3369
+ ('maxTouchPoints' in globalThis && globalThis.navigator.maxTouchPoints > 0);
3370
+ const toPretextWhiteSpace = (value) => value === 'pre-wrap' ? 'pre-wrap' : 'normal';
3371
+ const toPretextWordBreak = (value) => value === 'keep-all' ? 'keep-all' : 'normal';
3372
+ /**
3373
+ * Checks if an element's ellipsis is active.
3374
+ *
3375
+ * @param element The element to check.
3376
+ * @returns `true` if ellipsis is active, `false` otherwise.
3377
+ */
3378
+ const isEllipsisActive = (element) => {
3379
+ const computedStyle = globalThis.getComputedStyle(element);
3380
+ const { webkitLineClamp, lineHeight, font, fontStyle, fontWeight, fontSize, fontFamily, paddingLeft, paddingRight, borderLeftWidth, borderRightWidth, whiteSpace, wordBreak, } = computedStyle;
3381
+ // `font` shorthand returns "" in Chromium/Firefox for shadow DOM elements
3382
+ // whose font was set via CSS custom properties. Build it from the individual
3383
+ // sub-properties which are always reliably populated.
3384
+ const resolvedFont = font === ''
3385
+ ? `${fontStyle} ${fontWeight} ${fontSize} ${fontFamily}`.trim()
3386
+ : font;
3387
+ const parsedLineClamp = Number.parseInt(webkitLineClamp, 10);
3388
+ if (Number.isNaN(parsedLineClamp)) {
3389
+ return element.scrollWidth > element.clientWidth;
3390
+ }
3391
+ const parsedLineHeight = Number.parseFloat(lineHeight);
3392
+ if (Number.isNaN(parsedLineHeight)) {
3393
+ return element.scrollHeight > element.clientHeight;
3394
+ }
3395
+ const contentWidth = element.getBoundingClientRect().width -
3396
+ Number.parseFloat(paddingLeft) -
3397
+ Number.parseFloat(paddingRight) -
3398
+ Number.parseFloat(borderLeftWidth) -
3399
+ Number.parseFloat(borderRightWidth);
3400
+ if (contentWidth <= 0)
3401
+ return false;
3402
+ const text = element.textContent ?? '';
3403
+ if (text.trim() === '')
3404
+ return false;
3405
+ const parsedLetterSpacing = Number.parseFloat(computedStyle.letterSpacing);
3406
+ const letterSpacing = Number.isNaN(parsedLetterSpacing)
3407
+ ? undefined
3408
+ : parsedLetterSpacing;
3409
+ try {
3410
+ const prepared = prepare(text, resolvedFont, {
3411
+ letterSpacing,
3412
+ whiteSpace: toPretextWhiteSpace(whiteSpace),
3413
+ wordBreak: toPretextWordBreak(wordBreak),
3414
+ });
3415
+ const { lineCount } = layout(prepared, contentWidth, parsedLineHeight);
3416
+ return lineCount > parsedLineClamp;
3417
+ }
3418
+ catch {
3419
+ return element.scrollHeight > parsedLineClamp * parsedLineHeight;
3420
+ }
3421
+ };
3422
+ const determineLinkIcon = (target,
3423
+ // eslint-disable-next-line unicorn/prevent-abbreviations
3424
+ rel) => {
3425
+ if (!(rel?.split(' ') ?? []).includes('external'))
3426
+ return undefined;
3427
+ return target === '_blank' ? 'external-new-tab-link' : 'external-link';
3428
+ };
3429
+ const resolveTarget = (target) => {
3430
+ const resolvedTarget = typeof target === 'function' ? target() : target;
3431
+ if (typeof resolvedTarget !== 'string')
3432
+ return resolvedTarget;
3433
+ const element = document.querySelector(resolvedTarget);
3434
+ if (element === null)
3435
+ throw new Error('String must resolve to an Element.');
3436
+ return element;
3437
+ };
3438
+ /**
3439
+ * Patched version of requestAnimationFrame that avoids ngzone
3440
+ * Use only when you know ngzone should not run
3441
+ */
3442
+ const raf = (h) => {
3443
+ const win = window;
3444
+ // eslint-disable-next-line no-underscore-dangle
3445
+ if (typeof win.__zone_symbol__requestAnimationFrame === 'function') {
3446
+ // eslint-disable-next-line no-underscore-dangle
3447
+ return win.__zone_symbol__requestAnimationFrame(h);
3448
+ }
3449
+ if (typeof requestAnimationFrame === 'function') {
3450
+ return requestAnimationFrame(h);
3451
+ }
3452
+ return setTimeout(h);
3453
+ };
3454
+ /**
3455
+ * Waits for a component to be ready for
3456
+ * both custom element and non-custom element builds.
3457
+ * If non-custom element build, el.componentOnReady
3458
+ * will be used.
3459
+ * For custom element builds, we wait a frame
3460
+ * so that the inner contents of the component
3461
+ * have a chance to render.
3462
+ *
3463
+ * Use this utility rather than calling
3464
+ * el.componentOnReady yourself.
3465
+ *
3466
+ * Reference: https://stenciljs.com/docs/api#componentonready
3467
+ */
3468
+ const componentOnReady = (element, callback) => {
3469
+ if (element.componentOnReady === undefined) {
3470
+ raf(() => {
3471
+ callback(element);
3472
+ });
3473
+ }
3474
+ else {
3475
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
3476
+ element.componentOnReady().then((resolvedElement) => {
3477
+ callback(resolvedElement);
3478
+ });
3479
+ }
3480
+ };
3481
+ const resolvePanelFromValue = (value) => {
3482
+ if (value instanceof HTMLElement) {
3483
+ return value;
3484
+ }
3485
+ if (typeof value === 'string') {
3486
+ const element = document.querySelector(value);
3487
+ return element instanceof HTMLElement ? element : undefined;
3488
+ }
3489
+ return undefined;
3490
+ };
3491
+ const resolvePanelElement = (tab) => {
3492
+ const panelValue = typeof tab.panel === 'function' ? tab.panel() : tab.panel;
3493
+ return resolvePanelFromValue(panelValue);
3494
+ };
3495
+ const HORIZONTAL_MOVE_KEYS = new Set([
3496
+ 'ArrowLeft',
3497
+ 'ArrowRight',
3498
+ 'Home',
3499
+ 'End',
3500
+ ]);
3501
+ const VERTICAL_MOVE_KEYS = new Set([
3502
+ 'ArrowUp',
3503
+ 'ArrowDown',
3504
+ 'Home',
3505
+ 'End',
3506
+ ]);
3507
+ const closestElement = (selector, base) => {
3508
+ function closestFrom(element) {
3509
+ if (element === document || element === globalThis)
3510
+ return undefined;
3511
+ const { assignedSlot } = element;
3512
+ // eslint-disable-next-line no-param-reassign
3513
+ if (assignedSlot)
3514
+ element = assignedSlot;
3515
+ const found = element.closest(selector);
3516
+ return (found ??
3517
+ closestFrom(element.getRootNode().host));
3518
+ }
3519
+ return closestFrom(base);
3520
+ };
3521
+ const isRTL = (element) => getComputedStyle(element).direction === 'rtl';
3522
+ const getSubmenuOpenKey = (element) => isRTL(element) ? 'ArrowLeft' : 'ArrowRight';
3523
+ const getSubmenuCloseKey = (element) => isRTL(element) ? 'ArrowRight' : 'ArrowLeft';
3524
+ const isCurrentPage = (url) => {
3525
+ try {
3526
+ const currentUrl = new URL(window.location.href);
3527
+ const targetUrl = new URL(url);
3528
+ return (currentUrl.origin === targetUrl.origin &&
3529
+ currentUrl.pathname === targetUrl.pathname);
3530
+ }
3531
+ catch {
3532
+ return false;
3533
+ }
3534
+ };
3535
+
3536
+ export { HORIZONTAL_MOVE_KEYS as H, VERTICAL_MOVE_KEYS as V, isEllipsisActive as a, isCurrentPage as b, inheritAriaAttributes as c, determineLinkIcon as d, pickInputEventAttributes as e, ignorePromise as f, isRTL as g, getSubmenuOpenKey as h, invariant as i, closestElement as j, getSubmenuCloseKey as k, propertyToPx as l, resolvePanelElement as m, componentOnReady as n, isTouchDevice as o, pickFocusEventAttributes as p, resolveTarget as r };
3537
+ //# sourceMappingURL=p-CaibVX_2.js.map
3538
+
3539
+ //# sourceMappingURL=p-CaibVX_2.js.map