@nasser-sw/fabric 7.0.1-beta16 → 7.0.1-beta17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -0
- package/dist/index.js +1982 -649
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +1982 -649
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +1982 -649
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +1982 -649
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/shapes/IText/IText.d.ts +31 -6
- package/dist/src/shapes/IText/IText.d.ts.map +1 -1
- package/dist/src/shapes/IText/IText.min.mjs +1 -1
- package/dist/src/shapes/IText/IText.min.mjs.map +1 -1
- package/dist/src/shapes/IText/IText.mjs +495 -126
- package/dist/src/shapes/IText/IText.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextBehavior.d.ts +12 -0
- package/dist/src/shapes/IText/ITextBehavior.d.ts.map +1 -1
- package/dist/src/shapes/IText/ITextBehavior.min.mjs +1 -1
- package/dist/src/shapes/IText/ITextBehavior.min.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextBehavior.mjs +127 -36
- package/dist/src/shapes/IText/ITextBehavior.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextClickBehavior.d.ts.map +1 -1
- package/dist/src/shapes/IText/ITextClickBehavior.min.mjs +1 -1
- package/dist/src/shapes/IText/ITextClickBehavior.min.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextClickBehavior.mjs +21 -4
- package/dist/src/shapes/IText/ITextClickBehavior.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextKeyBehavior.min.mjs +1 -1
- package/dist/src/shapes/IText/ITextKeyBehavior.min.mjs.map +1 -1
- package/dist/src/shapes/IText/ITextKeyBehavior.mjs +17 -21
- package/dist/src/shapes/IText/ITextKeyBehavior.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.d.ts +69 -1
- package/dist/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist/src/shapes/Text/Text.min.mjs +1 -1
- package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.mjs +374 -60
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Text/constants.d.ts.map +1 -1
- package/dist/src/shapes/Text/constants.min.mjs +1 -1
- package/dist/src/shapes/Text/constants.min.mjs.map +1 -1
- package/dist/src/shapes/Text/constants.mjs +2 -1
- package/dist/src/shapes/Text/constants.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts +8 -1
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs +406 -63
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/text/hitTest.min.mjs +1 -1
- package/dist/src/text/hitTest.min.mjs.map +1 -1
- package/dist/src/text/hitTest.mjs +1 -198
- package/dist/src/text/hitTest.mjs.map +1 -1
- package/dist/src/text/layout.min.mjs +1 -1
- package/dist/src/text/layout.min.mjs.map +1 -1
- package/dist/src/text/layout.mjs +122 -5
- package/dist/src/text/layout.mjs.map +1 -1
- package/dist/src/text/overlayEditor.min.mjs +1 -1
- package/dist/src/text/overlayEditor.min.mjs.map +1 -1
- package/dist/src/text/overlayEditor.mjs +132 -142
- package/dist/src/text/overlayEditor.mjs.map +1 -1
- package/dist/src/text/unicode.d.ts +28 -0
- package/dist/src/text/unicode.d.ts.map +1 -1
- package/dist/src/text/unicode.min.mjs +1 -1
- package/dist/src/text/unicode.min.mjs.map +1 -1
- package/dist/src/text/unicode.mjs +294 -1
- package/dist/src/text/unicode.mjs.map +1 -1
- package/dist-extensions/src/shapes/IText/IText.d.ts +31 -6
- package/dist-extensions/src/shapes/IText/IText.d.ts.map +1 -1
- package/dist-extensions/src/shapes/IText/ITextBehavior.d.ts +12 -0
- package/dist-extensions/src/shapes/IText/ITextBehavior.d.ts.map +1 -1
- package/dist-extensions/src/shapes/IText/ITextClickBehavior.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts +69 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/constants.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts +8 -1
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/text/unicode.d.ts +28 -0
- package/dist-extensions/src/text/unicode.d.ts.map +1 -1
- package/package.json +164 -164
- package/rtl-debug.html +358 -200
- package/src/shapes/IText/IText.ts +524 -110
- package/src/shapes/IText/ITextBehavior.ts +174 -80
- package/src/shapes/IText/ITextClickBehavior.ts +20 -6
- package/src/shapes/IText/ITextKeyBehavior.ts +15 -15
- package/src/shapes/Text/Text.ts +488 -107
- package/src/shapes/Text/constants.ts +4 -2
- package/src/shapes/Textbox.ts +414 -65
- package/src/text/layout.ts +150 -23
- package/src/text/overlayEditor.ts +148 -148
- package/src/text/unicode.ts +177 -2
|
@@ -7,6 +7,14 @@ import { graphemeSplit } from '../util/lang_string.mjs';
|
|
|
7
7
|
* and grapheme cluster boundary detection.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
// Unicode character categories for text processing
|
|
11
|
+
const UNICODE_CATEGORIES = {
|
|
12
|
+
// Bidirectional types
|
|
13
|
+
L: /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6]/,
|
|
14
|
+
R: /[\u05BE\u05C0\u05C3\u05C6\u05D0-\u05EA\u05F0-\u05F4\u0608\u060B\u060D]/,
|
|
15
|
+
AL: /[\u0627\u0629-\u063A\u0641-\u064A\u066D-\u066F\u0671-\u06D3\u06D5]/,
|
|
16
|
+
EN: /[\u0030-\u0039\u00B2\u00B3\u00B9\u06F0-\u06F9]/,
|
|
17
|
+
AN: /[\u0660-\u0669\u066B\u066C]/};
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
20
|
* Enhanced grapheme segmentation using Intl.Segmenter when available
|
|
@@ -30,5 +38,290 @@ function segmentGraphemes(text) {
|
|
|
30
38
|
return graphemeSplit(text);
|
|
31
39
|
}
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Analyze text for bidirectional runs using Unicode BiDi algorithm (simplified)
|
|
43
|
+
*/
|
|
44
|
+
function analyzeBiDi(text) {
|
|
45
|
+
let baseDirection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'ltr';
|
|
46
|
+
if (!text) return [];
|
|
47
|
+
const runs = [];
|
|
48
|
+
const chars = Array.from(text);
|
|
49
|
+
let currentRun = null;
|
|
50
|
+
for (let i = 0; i < chars.length; i++) {
|
|
51
|
+
const char = chars[i];
|
|
52
|
+
const charDirection = getBidiDirection(char, baseDirection);
|
|
53
|
+
|
|
54
|
+
// Start new run if direction changes
|
|
55
|
+
if (!currentRun || currentRun.direction !== charDirection) {
|
|
56
|
+
if (currentRun) {
|
|
57
|
+
runs.push(currentRun);
|
|
58
|
+
}
|
|
59
|
+
currentRun = {
|
|
60
|
+
text: char,
|
|
61
|
+
direction: charDirection,
|
|
62
|
+
level: charDirection === 'rtl' ? 1 : 0,
|
|
63
|
+
start: i,
|
|
64
|
+
end: i + 1
|
|
65
|
+
};
|
|
66
|
+
} else {
|
|
67
|
+
// Continue current run
|
|
68
|
+
currentRun.text += char;
|
|
69
|
+
currentRun.end = i + 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Add final run
|
|
74
|
+
if (currentRun) {
|
|
75
|
+
runs.push(currentRun);
|
|
76
|
+
}
|
|
77
|
+
return runs.length > 0 ? runs : [{
|
|
78
|
+
text,
|
|
79
|
+
direction: baseDirection,
|
|
80
|
+
level: baseDirection === 'rtl' ? 1 : 0,
|
|
81
|
+
start: 0,
|
|
82
|
+
end: text.length
|
|
83
|
+
}];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Character classification functions
|
|
88
|
+
*/
|
|
89
|
+
function isWhitespace(grapheme) {
|
|
90
|
+
return /\s/.test(grapheme);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get bidirectional character type
|
|
95
|
+
*/
|
|
96
|
+
function getBidiDirection(char, baseDirection) {
|
|
97
|
+
// Strong RTL characters
|
|
98
|
+
if (UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char)) {
|
|
99
|
+
return 'rtl';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Strong LTR characters
|
|
103
|
+
if (UNICODE_CATEGORIES.L.test(char)) {
|
|
104
|
+
return 'ltr';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Numbers follow base direction in simplified algorithm
|
|
108
|
+
if (UNICODE_CATEGORIES.EN.test(char) || UNICODE_CATEGORIES.AN.test(char)) {
|
|
109
|
+
return baseDirection;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Neutral characters follow context
|
|
113
|
+
return baseDirection;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Arabic Kashida (Tatweel) Support
|
|
118
|
+
// ============================================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Arabic Tatweel (kashida) character used for justification
|
|
122
|
+
*/
|
|
123
|
+
const ARABIC_TATWEEL = '\u0640';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Arabic letters that do NOT connect to the following letter (non-connecting on left).
|
|
127
|
+
* These letters cannot have kashida inserted after them.
|
|
128
|
+
* ا (Alef), د (Dal), ذ (Thal), ر (Ra), ز (Zay), و (Waw), ة (Teh Marbuta), ء (Hamza)
|
|
129
|
+
*/
|
|
130
|
+
const ARABIC_NON_CONNECTING = new Set(['\u0627',
|
|
131
|
+
// Alef
|
|
132
|
+
'\u062F',
|
|
133
|
+
// Dal
|
|
134
|
+
'\u0630',
|
|
135
|
+
// Thal
|
|
136
|
+
'\u0631',
|
|
137
|
+
// Ra
|
|
138
|
+
'\u0632',
|
|
139
|
+
// Zay
|
|
140
|
+
'\u0648',
|
|
141
|
+
// Waw
|
|
142
|
+
'\u0629',
|
|
143
|
+
// Teh Marbuta
|
|
144
|
+
'\u0621',
|
|
145
|
+
// Hamza
|
|
146
|
+
'\u0622',
|
|
147
|
+
// Alef with Madda
|
|
148
|
+
'\u0623',
|
|
149
|
+
// Alef with Hamza Above
|
|
150
|
+
'\u0625',
|
|
151
|
+
// Alef with Hamza Below
|
|
152
|
+
'\u0672',
|
|
153
|
+
// Alef with Wavy Hamza Above
|
|
154
|
+
'\u0673',
|
|
155
|
+
// Alef with Wavy Hamza Below
|
|
156
|
+
'\u0675',
|
|
157
|
+
// High Hamza Alef
|
|
158
|
+
'\u0688',
|
|
159
|
+
// Dal with Small Tah
|
|
160
|
+
'\u0689',
|
|
161
|
+
// Dal with Ring
|
|
162
|
+
'\u068A',
|
|
163
|
+
// Dal with Dot Below
|
|
164
|
+
'\u068B',
|
|
165
|
+
// Dal with Dot Below and Small Tah
|
|
166
|
+
'\u068C',
|
|
167
|
+
// Dahal
|
|
168
|
+
'\u068D',
|
|
169
|
+
// Ddahal
|
|
170
|
+
'\u068E',
|
|
171
|
+
// Dul
|
|
172
|
+
'\u068F',
|
|
173
|
+
// Dal with Three Dots Above Downwards
|
|
174
|
+
'\u0690',
|
|
175
|
+
// Dal with Four Dots Above
|
|
176
|
+
'\u0691',
|
|
177
|
+
// Rreh
|
|
178
|
+
'\u0692',
|
|
179
|
+
// Reh with Small V
|
|
180
|
+
'\u0693',
|
|
181
|
+
// Reh with Ring
|
|
182
|
+
'\u0694',
|
|
183
|
+
// Reh with Dot Below
|
|
184
|
+
'\u0695',
|
|
185
|
+
// Reh with Small V Below
|
|
186
|
+
'\u0696',
|
|
187
|
+
// Reh with Dot Below and Dot Above
|
|
188
|
+
'\u0697',
|
|
189
|
+
// Reh with Two Dots Above
|
|
190
|
+
'\u0698',
|
|
191
|
+
// Jeh
|
|
192
|
+
'\u0699',
|
|
193
|
+
// Reh with Four Dots Above
|
|
194
|
+
'\u06C4',
|
|
195
|
+
// Waw with Ring
|
|
196
|
+
'\u06C5',
|
|
197
|
+
// Kirghiz Oe
|
|
198
|
+
'\u06C6',
|
|
199
|
+
// Oe
|
|
200
|
+
'\u06C7',
|
|
201
|
+
// U
|
|
202
|
+
'\u06C8',
|
|
203
|
+
// Yu
|
|
204
|
+
'\u06C9',
|
|
205
|
+
// Kirghiz Yu
|
|
206
|
+
'\u06CA',
|
|
207
|
+
// Waw with Two Dots Above
|
|
208
|
+
'\u06CB',
|
|
209
|
+
// Ve
|
|
210
|
+
'\u06CD',
|
|
211
|
+
// Yeh with Tail
|
|
212
|
+
'\u06CF' // Waw with Dot Above
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Check if a character is an Arabic letter (main Arabic block + extended)
|
|
217
|
+
*/
|
|
218
|
+
function isArabicLetter(char) {
|
|
219
|
+
if (!char) return false;
|
|
220
|
+
const code = char.charCodeAt(0);
|
|
221
|
+
// Arabic: U+0600-U+06FF (main block)
|
|
222
|
+
// Arabic Supplement: U+0750-U+077F
|
|
223
|
+
// Arabic Extended-A: U+08A0-U+08FF
|
|
224
|
+
return code >= 0x0620 && code <= 0x064A ||
|
|
225
|
+
// Main letters
|
|
226
|
+
code >= 0x066E && code <= 0x06D3 ||
|
|
227
|
+
// Extended letters
|
|
228
|
+
code >= 0x0750 && code <= 0x077F ||
|
|
229
|
+
// Arabic Supplement
|
|
230
|
+
code >= 0x08A0 && code <= 0x08FF // Arabic Extended-A
|
|
231
|
+
;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if kashida can be inserted between two characters.
|
|
236
|
+
* Kashida can only be inserted:
|
|
237
|
+
* - Between two Arabic letters
|
|
238
|
+
* - After a letter that connects to the next (not in ARABIC_NON_CONNECTING)
|
|
239
|
+
* - Not at word boundaries (no whitespace before/after)
|
|
240
|
+
*/
|
|
241
|
+
// Alef variants that form ligatures with lam
|
|
242
|
+
const ARABIC_ALEF_VARIANTS = new Set(['\u0627',
|
|
243
|
+
// ا ALEF
|
|
244
|
+
'\u0623',
|
|
245
|
+
// أ ALEF WITH HAMZA ABOVE
|
|
246
|
+
'\u0625',
|
|
247
|
+
// إ ALEF WITH HAMZA BELOW
|
|
248
|
+
'\u0622',
|
|
249
|
+
// آ ALEF WITH MADDA ABOVE
|
|
250
|
+
'\u0671' // ٱ ALEF WASLA
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
// Lam character
|
|
254
|
+
const ARABIC_LAM = '\u0644'; // ل
|
|
255
|
+
|
|
256
|
+
function canInsertKashida(prevChar, nextChar) {
|
|
257
|
+
if (!prevChar || !nextChar) return false;
|
|
258
|
+
|
|
259
|
+
// Can't insert at whitespace boundaries
|
|
260
|
+
if (/\s/.test(prevChar) || /\s/.test(nextChar)) return false;
|
|
261
|
+
|
|
262
|
+
// Both must be Arabic letters
|
|
263
|
+
if (!isArabicLetter(prevChar) || !isArabicLetter(nextChar)) return false;
|
|
264
|
+
|
|
265
|
+
// Previous char must connect to the next (not be non-connecting)
|
|
266
|
+
if (ARABIC_NON_CONNECTING.has(prevChar)) return false;
|
|
267
|
+
|
|
268
|
+
// NEVER insert kashida between lam and alef - they form a ligature (لا)
|
|
269
|
+
if (prevChar === ARABIC_LAM && ARABIC_ALEF_VARIANTS.has(nextChar)) return false;
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Represents a valid kashida insertion point
|
|
275
|
+
*/
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Find all valid kashida insertion points in a line of text.
|
|
279
|
+
* Returns points sorted by priority (highest first).
|
|
280
|
+
*
|
|
281
|
+
* Priority rules (similar to Adobe Illustrator):
|
|
282
|
+
* 1. Between connected letters (ب + ب = highest)
|
|
283
|
+
* 2. Prefer middle of words over edges
|
|
284
|
+
* 3. Avoid inserting right before/after spaces
|
|
285
|
+
*/
|
|
286
|
+
function findKashidaPoints(graphemes) {
|
|
287
|
+
const points = [];
|
|
288
|
+
for (let i = 0; i < graphemes.length - 1; i++) {
|
|
289
|
+
const prev = graphemes[i];
|
|
290
|
+
const next = graphemes[i + 1];
|
|
291
|
+
if (canInsertKashida(prev, next)) {
|
|
292
|
+
// Calculate priority based on position in word
|
|
293
|
+
let priority = 1;
|
|
294
|
+
|
|
295
|
+
// Find word boundaries
|
|
296
|
+
let wordStart = i;
|
|
297
|
+
let wordEnd = i + 1;
|
|
298
|
+
while (wordStart > 0 && !isWhitespace(graphemes[wordStart - 1])) {
|
|
299
|
+
wordStart--;
|
|
300
|
+
}
|
|
301
|
+
while (wordEnd < graphemes.length && !isWhitespace(graphemes[wordEnd])) {
|
|
302
|
+
wordEnd++;
|
|
303
|
+
}
|
|
304
|
+
const wordLength = wordEnd - wordStart;
|
|
305
|
+
const posInWord = i - wordStart;
|
|
306
|
+
|
|
307
|
+
// Higher priority for middle positions
|
|
308
|
+
const distFromEdge = Math.min(posInWord, wordLength - 1 - posInWord);
|
|
309
|
+
priority = distFromEdge + 1;
|
|
310
|
+
|
|
311
|
+
// Boost priority for longer words
|
|
312
|
+
if (wordLength > 4) priority += 1;
|
|
313
|
+
if (wordLength > 6) priority += 1;
|
|
314
|
+
points.push({
|
|
315
|
+
charIndex: i,
|
|
316
|
+
priority
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Sort by priority descending
|
|
322
|
+
points.sort((a, b) => b.priority - a.priority);
|
|
323
|
+
return points;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export { ARABIC_TATWEEL, analyzeBiDi, canInsertKashida, findKashidaPoints, isArabicLetter, isWhitespace, segmentGraphemes };
|
|
34
327
|
//# sourceMappingURL=unicode.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unicode.mjs","sources":["../../../src/text/unicode.ts"],"sourcesContent":["/**\r\n * Unicode and Internationalization Support\r\n * \r\n * Enhanced Unicode handling for complex scripts, RTL/LTR text,\r\n * and grapheme cluster boundary detection.\r\n */\r\n\r\nimport { graphemeSplit } from '../util/lang_string';\r\n\r\nexport interface BiDiRun {\r\n text: string;\r\n direction: 'ltr' | 'rtl';\r\n level: number;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nexport interface ScriptInfo {\r\n script: string;\r\n direction: 'ltr' | 'rtl';\r\n needsShaping: boolean;\r\n complexLayout: boolean;\r\n}\r\n\r\n// Unicode character categories for text processing\r\nconst UNICODE_CATEGORIES = {\r\n // Bidirectional types\r\n L: /[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6]/,\r\n R: /[\\u05BE\\u05C0\\u05C3\\u05C6\\u05D0-\\u05EA\\u05F0-\\u05F4\\u0608\\u060B\\u060D]/,\r\n AL: /[\\u0627\\u0629-\\u063A\\u0641-\\u064A\\u066D-\\u066F\\u0671-\\u06D3\\u06D5]/,\r\n EN: /[\\u0030-\\u0039\\u00B2\\u00B3\\u00B9\\u06F0-\\u06F9]/,\r\n ES: /[\\u002B\\u002D]/,\r\n ET: /[\\u0023\\u0024\\u0025\\u00A2\\u00A3\\u00A4\\u00A5]/,\r\n AN: /[\\u0660-\\u0669\\u066B\\u066C]/,\r\n CS: /[\\u002C\\u002E\\u002F\\u003A\\u00A0]/,\r\n NSM: /[\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2]/,\r\n BN: /[\\u0000-\\u0008\\u000E-\\u001B\\u007F-\\u0084\\u0086-\\u009F]/,\r\n B: /[\\u000A\\u000D\\u001C-\\u001E\\u0085\\u2029]/,\r\n S: /[\\u0009\\u000B\\u001F]/,\r\n WS: /[\\u000C\\u0020\\u1680\\u2000-\\u200A\\u2028\\u205F\\u3000]/,\r\n ON: /[\\u0021\\u0022\\u0026-\\u002A\\u003B-\\u0040\\u005B-\\u0060\\u007B-\\u007E]/,\r\n};\r\n\r\n// Script detection patterns\r\nconst SCRIPT_PATTERNS = {\r\n latin: /[\\u0041-\\u005A\\u0061-\\u007A\\u00C0-\\u024F]/,\r\n arabic: /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF]/,\r\n hebrew: /[\\u0590-\\u05FF]/,\r\n cyrillic: /[\\u0400-\\u04FF\\u0500-\\u052F]/,\r\n greek: /[\\u0370-\\u03FF\\u1F00-\\u1FFF]/,\r\n cjk: /[\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uF900-\\uFAFF]/,\r\n hiragana: /[\\u3040-\\u309F]/,\r\n katakana: /[\\u30A0-\\u30FF]/,\r\n hangul: /[\\uAC00-\\uD7AF\\u1100-\\u11FF\\u3130-\\u318F]/,\r\n thai: /[\\u0E00-\\u0E7F]/,\r\n devanagari: /[\\u0900-\\u097F]/,\r\n bengali: /[\\u0980-\\u09FF]/,\r\n emoji: /[\\u1F600-\\u1F64F\\u1F300-\\u1F5FF\\u1F680-\\u1F6FF\\u1F700-\\u1F77F]/,\r\n};\r\n\r\n/**\r\n * Enhanced grapheme segmentation using Intl.Segmenter when available\r\n * with fallback to existing graphemeSplit implementation\r\n */\r\nexport function segmentGraphemes(text: string): string[] {\r\n // Use native Intl.Segmenter if available\r\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\r\n try {\r\n const segmenter = new Intl.Segmenter(undefined, {\r\n granularity: 'grapheme',\r\n });\r\n \r\n const segments = segmenter.segment(text);\r\n return Array.from(segments, segment => segment.segment);\r\n } catch (e) {\r\n // Fallback if Intl.Segmenter fails\r\n }\r\n }\r\n \r\n // Use existing Fabric.js implementation as fallback\r\n return graphemeSplit(text);\r\n}\r\n\r\n/**\r\n * Analyze text for bidirectional runs using Unicode BiDi algorithm (simplified)\r\n */\r\nexport function analyzeBiDi(text: string, baseDirection: 'ltr' | 'rtl' = 'ltr'): BiDiRun[] {\r\n if (!text) return [];\r\n\r\n const runs: BiDiRun[] = [];\r\n const chars = Array.from(text);\r\n let currentRun: BiDiRun | null = null;\r\n\r\n for (let i = 0; i < chars.length; i++) {\r\n const char = chars[i];\r\n const charDirection = getBidiDirection(char, baseDirection);\r\n \r\n // Start new run if direction changes\r\n if (!currentRun || currentRun.direction !== charDirection) {\r\n if (currentRun) {\r\n runs.push(currentRun);\r\n }\r\n \r\n currentRun = {\r\n text: char,\r\n direction: charDirection,\r\n level: charDirection === 'rtl' ? 1 : 0,\r\n start: i,\r\n end: i + 1,\r\n };\r\n } else {\r\n // Continue current run\r\n currentRun.text += char;\r\n currentRun.end = i + 1;\r\n }\r\n }\r\n\r\n // Add final run\r\n if (currentRun) {\r\n runs.push(currentRun);\r\n }\r\n\r\n return runs.length > 0 ? runs : [{\r\n text,\r\n direction: baseDirection,\r\n level: baseDirection === 'rtl' ? 1 : 0,\r\n start: 0,\r\n end: text.length,\r\n }];\r\n}\r\n\r\n/**\r\n * Detect the primary script of text for font fallback and shaping\r\n */\r\nexport function detectScript(text: string): string {\r\n const charCounts: Record<string, number> = {};\r\n const chars = Array.from(text);\r\n\r\n // Count characters by script\r\n for (const char of chars) {\r\n for (const [script, pattern] of Object.entries(SCRIPT_PATTERNS)) {\r\n if (pattern.test(char)) {\r\n charCounts[script] = (charCounts[script] || 0) + 1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Find dominant script\r\n let maxCount = 0;\r\n let dominantScript = 'latin';\r\n\r\n for (const [script, count] of Object.entries(charCounts)) {\r\n if (count > maxCount) {\r\n maxCount = count;\r\n dominantScript = script;\r\n }\r\n }\r\n\r\n return dominantScript;\r\n}\r\n\r\n/**\r\n * Get script information for layout decisions\r\n */\r\nexport function getScriptInfo(script: string): ScriptInfo {\r\n const scriptMap: Record<string, ScriptInfo> = {\r\n latin: {\r\n script: 'latin',\r\n direction: 'ltr',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n arabic: {\r\n script: 'arabic',\r\n direction: 'rtl',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n hebrew: {\r\n script: 'hebrew',\r\n direction: 'rtl',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n thai: {\r\n script: 'thai',\r\n direction: 'ltr',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n devanagari: {\r\n script: 'devanagari',\r\n direction: 'ltr',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n cjk: {\r\n script: 'cjk',\r\n direction: 'ltr',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n };\r\n\r\n return scriptMap[script] || scriptMap.latin;\r\n}\r\n\r\n/**\r\n * Break words according to language-specific rules\r\n */\r\nexport function breakWords(text: string, locale?: string): string[] {\r\n // Use native word segmentation if available\r\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\r\n try {\r\n const segmenter = new Intl.Segmenter(locale, {\r\n granularity: 'word',\r\n });\r\n \r\n const segments = segmenter.segment(text);\r\n return Array.from(segments)\r\n .filter(segment => segment.isWordLike)\r\n .map(segment => segment.segment);\r\n } catch (e) {\r\n // Fallback if Intl.Segmenter fails\r\n }\r\n }\r\n\r\n // Simple fallback word breaking\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n}\r\n\r\n/**\r\n * Character classification functions\r\n */\r\nexport function isWhitespace(grapheme: string): boolean {\r\n return /\\s/.test(grapheme);\r\n}\r\n\r\nexport function isLineBreak(grapheme: string): boolean {\r\n return grapheme === '\\n' || grapheme === '\\r' || grapheme === '\\r\\n';\r\n}\r\n\r\nexport function isWordSeparator(grapheme: string): boolean {\r\n return /[\\s\\-\\u2010-\\u2015]/.test(grapheme);\r\n}\r\n\r\nexport function isPunctuation(grapheme: string): boolean {\r\n return /[\\p{P}]/u.test(grapheme);\r\n}\r\n\r\nexport function isEmoji(grapheme: string): boolean {\r\n return /[\\p{Emoji}]/u.test(grapheme);\r\n}\r\n\r\nexport function isRTLCharacter(char: string): boolean {\r\n return UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char);\r\n}\r\n\r\n/**\r\n * Advanced grapheme cluster handling for complex scripts\r\n */\r\nexport function findGraphemeClusterBoundaries(text: string): number[] {\r\n const boundaries: number[] = [0];\r\n const graphemes = segmentGraphemes(text);\r\n let position = 0;\r\n\r\n for (const grapheme of graphemes) {\r\n position += grapheme.length;\r\n boundaries.push(position);\r\n }\r\n\r\n return boundaries;\r\n}\r\n\r\n/**\r\n * Check if a position is at a grapheme cluster boundary\r\n */\r\nexport function isGraphemeClusterBoundary(text: string, position: number): boolean {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n return boundaries.includes(position);\r\n}\r\n\r\n/**\r\n * Find the next grapheme cluster boundary from a given position\r\n */\r\nexport function findNextGraphemeClusterBoundary(text: string, position: number): number {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n return boundaries.find(boundary => boundary > position) || text.length;\r\n}\r\n\r\n/**\r\n * Find the previous grapheme cluster boundary from a given position \r\n */\r\nexport function findPreviousGraphemeClusterBoundary(text: string, position: number): number {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n const reversedBoundaries = [...boundaries].reverse();\r\n return reversedBoundaries.find(boundary => boundary < position) || 0;\r\n}\r\n\r\n/**\r\n * Normalize text for consistent processing\r\n */\r\nexport function normalizeText(text: string, form: 'NFC' | 'NFD' | 'NFKC' | 'NFKD' = 'NFC'): string {\r\n if (typeof text.normalize === 'function') {\r\n return text.normalize(form);\r\n }\r\n return text;\r\n}\r\n\r\n/**\r\n * Detect if text contains complex script characters that need special handling\r\n */\r\nexport function needsComplexLayout(text: string): boolean {\r\n const complexScripts = ['arabic', 'hebrew', 'thai', 'devanagari', 'bengali'];\r\n const detectedScript = detectScript(text);\r\n return complexScripts.includes(detectedScript);\r\n}\r\n\r\n/**\r\n * Get text direction based on content analysis\r\n */\r\nexport function getTextDirection(text: string, fallback: 'ltr' | 'rtl' = 'ltr'): 'ltr' | 'rtl' {\r\n let rtlChars = 0;\r\n let ltrChars = 0;\r\n\r\n for (const char of text) {\r\n if (UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char)) {\r\n rtlChars++;\r\n } else if (UNICODE_CATEGORIES.L.test(char)) {\r\n ltrChars++;\r\n }\r\n }\r\n\r\n if (rtlChars > ltrChars) return 'rtl';\r\n if (ltrChars > rtlChars) return 'ltr';\r\n return fallback;\r\n}\r\n\r\n/**\r\n * Split text into lines respecting complex script rules\r\n */\r\nexport function splitTextLines(text: string): string[] {\r\n // Handle different line break types\r\n return text.split(/\\r\\n|\\r|\\n/);\r\n}\r\n\r\n/**\r\n * Check if combining marks or modifiers should be kept with base character\r\n */\r\nexport function isCombiningMark(char: string): boolean {\r\n return UNICODE_CATEGORIES.NSM.test(char);\r\n}\r\n\r\n/**\r\n * Get bidirectional character type\r\n */\r\nfunction getBidiDirection(char: string, baseDirection: 'ltr' | 'rtl'): 'ltr' | 'rtl' {\r\n // Strong RTL characters\r\n if (UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char)) {\r\n return 'rtl';\r\n }\r\n \r\n // Strong LTR characters \r\n if (UNICODE_CATEGORIES.L.test(char)) {\r\n return 'ltr';\r\n }\r\n \r\n // Numbers follow base direction in simplified algorithm\r\n if (UNICODE_CATEGORIES.EN.test(char) || UNICODE_CATEGORIES.AN.test(char)) {\r\n return baseDirection;\r\n }\r\n \r\n // Neutral characters follow context\r\n return baseDirection;\r\n}\r\n\r\n/**\r\n * Advanced word breaking for different scripts\r\n */\r\nexport function breakWordsAdvanced(text: string): string[] {\r\n const script = detectScript(text);\r\n \r\n switch (script) {\r\n case 'cjk':\r\n // CJK can break at most characters\r\n return Array.from(text);\r\n \r\n case 'thai':\r\n // Thai doesn't use spaces - would need dictionary-based breaking\r\n // For now, fall back to character-based breaking\r\n return Array.from(text);\r\n \r\n case 'arabic':\r\n case 'hebrew':\r\n // Handle RTL scripts\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n \r\n default:\r\n // Standard space-based word breaking\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n }\r\n}\r\n\r\n/**\r\n * Check if text needs right-to-left processing\r\n */\r\nexport function needsRTLProcessing(text: string): boolean {\r\n for (const char of text) {\r\n if (isRTLCharacter(char)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Reverse text for RTL display (simplified - real RTL is more complex)\r\n */\r\nexport function reverseForRTL(text: string): string {\r\n // This is a simplified implementation\r\n // Real RTL processing requires full BiDi algorithm\r\n const graphemes = segmentGraphemes(text);\r\n return graphemes.reverse().join('');\r\n}\r\n\r\n/**\r\n * Get appropriate line breaking class for character\r\n */\r\nexport function getLineBreakClass(char: string): string {\r\n // Simplified line breaking classes\r\n if (/\\s/.test(char)) return 'SP';\r\n if (/[!-\\/:-@\\[-`{-~]/.test(char)) return 'BA'; // Break after\r\n if (/[(\\[{]/.test(char)) return 'OP'; // Open punctuation\r\n if (/[)\\]}]/.test(char)) return 'CL'; // Close punctuation\r\n if (/\\d/.test(char)) return 'NU'; // Numeric\r\n if (/[A-Za-z]/.test(char)) return 'AL'; // Alphabetic\r\n \r\n return 'AL'; // Default to alphabetic\r\n}\r\n\r\n/**\r\n * Check if line break is allowed between two characters\r\n */\r\nexport function isLineBreakAllowed(before: string, after: string): boolean {\r\n const beforeClass = getLineBreakClass(before);\r\n const afterClass = getLineBreakClass(after);\r\n \r\n // Simplified line breaking rules\r\n if (beforeClass === 'OP') return false; // Don't break after opening\r\n if (afterClass === 'CL') return false; // Don't break before closing\r\n if (beforeClass === 'SP') return true; // Always allow break after space\r\n \r\n return true; // Default allow\r\n}"],"names":["segmentGraphemes","text","Intl","segmenter","Segmenter","undefined","granularity","segments","segment","Array","from","e","graphemeSplit"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;;;AAuDA;AACA;AACA;AACA;AACO,SAASA,gBAAgBA,CAACC,IAAY,EAAY;AACvD;EACA,IAAI,OAAOC,IAAI,KAAK,WAAW,IAAI,WAAW,IAAIA,IAAI,EAAE;IACtD,IAAI;MACF,MAAMC,SAAS,GAAG,IAAID,IAAI,CAACE,SAAS,CAACC,SAAS,EAAE;AAC9CC,QAAAA,WAAW,EAAE;AACf,OAAC,CAAC;AAEF,MAAA,MAAMC,QAAQ,GAAGJ,SAAS,CAACK,OAAO,CAACP,IAAI,CAAC;MACxC,OAAOQ,KAAK,CAACC,IAAI,CAACH,QAAQ,EAAEC,OAAO,IAAIA,OAAO,CAACA,OAAO,CAAC;IACzD,CAAC,CAAC,OAAOG,CAAC,EAAE;AACV;AAAA,IAAA;AAEJ,EAAA;;AAEA;EACA,OAAOC,aAAa,CAACX,IAAI,CAAC;AAC5B;;;;"}
|
|
1
|
+
{"version":3,"file":"unicode.mjs","sources":["../../../src/text/unicode.ts"],"sourcesContent":["/**\r\n * Unicode and Internationalization Support\r\n * \r\n * Enhanced Unicode handling for complex scripts, RTL/LTR text,\r\n * and grapheme cluster boundary detection.\r\n */\r\n\r\nimport { graphemeSplit } from '../util/lang_string';\r\n\r\nexport interface BiDiRun {\r\n text: string;\r\n direction: 'ltr' | 'rtl';\r\n level: number;\r\n start: number;\r\n end: number;\r\n}\r\n\r\nexport interface ScriptInfo {\r\n script: string;\r\n direction: 'ltr' | 'rtl';\r\n needsShaping: boolean;\r\n complexLayout: boolean;\r\n}\r\n\r\n// Unicode character categories for text processing\r\nconst UNICODE_CATEGORIES = {\r\n // Bidirectional types\r\n L: /[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6]/,\r\n R: /[\\u05BE\\u05C0\\u05C3\\u05C6\\u05D0-\\u05EA\\u05F0-\\u05F4\\u0608\\u060B\\u060D]/,\r\n AL: /[\\u0627\\u0629-\\u063A\\u0641-\\u064A\\u066D-\\u066F\\u0671-\\u06D3\\u06D5]/,\r\n EN: /[\\u0030-\\u0039\\u00B2\\u00B3\\u00B9\\u06F0-\\u06F9]/,\r\n ES: /[\\u002B\\u002D]/,\r\n ET: /[\\u0023\\u0024\\u0025\\u00A2\\u00A3\\u00A4\\u00A5]/,\r\n AN: /[\\u0660-\\u0669\\u066B\\u066C]/,\r\n CS: /[\\u002C\\u002E\\u002F\\u003A\\u00A0]/,\r\n NSM: /[\\u0300-\\u036F\\u0483-\\u0489\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2]/,\r\n BN: /[\\u0000-\\u0008\\u000E-\\u001B\\u007F-\\u0084\\u0086-\\u009F]/,\r\n B: /[\\u000A\\u000D\\u001C-\\u001E\\u0085\\u2029]/,\r\n S: /[\\u0009\\u000B\\u001F]/,\r\n WS: /[\\u000C\\u0020\\u1680\\u2000-\\u200A\\u2028\\u205F\\u3000]/,\r\n ON: /[\\u0021\\u0022\\u0026-\\u002A\\u003B-\\u0040\\u005B-\\u0060\\u007B-\\u007E]/,\r\n};\r\n\r\n// Script detection patterns\r\nconst SCRIPT_PATTERNS = {\r\n latin: /[\\u0041-\\u005A\\u0061-\\u007A\\u00C0-\\u024F]/,\r\n arabic: /[\\u0600-\\u06FF\\u0750-\\u077F\\u08A0-\\u08FF]/,\r\n hebrew: /[\\u0590-\\u05FF]/,\r\n cyrillic: /[\\u0400-\\u04FF\\u0500-\\u052F]/,\r\n greek: /[\\u0370-\\u03FF\\u1F00-\\u1FFF]/,\r\n cjk: /[\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uF900-\\uFAFF]/,\r\n hiragana: /[\\u3040-\\u309F]/,\r\n katakana: /[\\u30A0-\\u30FF]/,\r\n hangul: /[\\uAC00-\\uD7AF\\u1100-\\u11FF\\u3130-\\u318F]/,\r\n thai: /[\\u0E00-\\u0E7F]/,\r\n devanagari: /[\\u0900-\\u097F]/,\r\n bengali: /[\\u0980-\\u09FF]/,\r\n emoji: /[\\u1F600-\\u1F64F\\u1F300-\\u1F5FF\\u1F680-\\u1F6FF\\u1F700-\\u1F77F]/,\r\n};\r\n\r\n/**\r\n * Enhanced grapheme segmentation using Intl.Segmenter when available\r\n * with fallback to existing graphemeSplit implementation\r\n */\r\nexport function segmentGraphemes(text: string): string[] {\r\n // Use native Intl.Segmenter if available\r\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\r\n try {\r\n const segmenter = new Intl.Segmenter(undefined, {\r\n granularity: 'grapheme',\r\n });\r\n \r\n const segments = segmenter.segment(text);\r\n return Array.from(segments, segment => segment.segment);\r\n } catch (e) {\r\n // Fallback if Intl.Segmenter fails\r\n }\r\n }\r\n \r\n // Use existing Fabric.js implementation as fallback\r\n return graphemeSplit(text);\r\n}\r\n\r\n/**\r\n * Analyze text for bidirectional runs using Unicode BiDi algorithm (simplified)\r\n */\r\nexport function analyzeBiDi(text: string, baseDirection: 'ltr' | 'rtl' = 'ltr'): BiDiRun[] {\r\n if (!text) return [];\r\n\r\n const runs: BiDiRun[] = [];\r\n const chars = Array.from(text);\r\n let currentRun: BiDiRun | null = null;\r\n\r\n for (let i = 0; i < chars.length; i++) {\r\n const char = chars[i];\r\n const charDirection = getBidiDirection(char, baseDirection);\r\n \r\n // Start new run if direction changes\r\n if (!currentRun || currentRun.direction !== charDirection) {\r\n if (currentRun) {\r\n runs.push(currentRun);\r\n }\r\n \r\n currentRun = {\r\n text: char,\r\n direction: charDirection,\r\n level: charDirection === 'rtl' ? 1 : 0,\r\n start: i,\r\n end: i + 1,\r\n };\r\n } else {\r\n // Continue current run\r\n currentRun.text += char;\r\n currentRun.end = i + 1;\r\n }\r\n }\r\n\r\n // Add final run\r\n if (currentRun) {\r\n runs.push(currentRun);\r\n }\r\n\r\n return runs.length > 0 ? runs : [{\r\n text,\r\n direction: baseDirection,\r\n level: baseDirection === 'rtl' ? 1 : 0,\r\n start: 0,\r\n end: text.length,\r\n }];\r\n}\r\n\r\n/**\r\n * Detect the primary script of text for font fallback and shaping\r\n */\r\nexport function detectScript(text: string): string {\r\n const charCounts: Record<string, number> = {};\r\n const chars = Array.from(text);\r\n\r\n // Count characters by script\r\n for (const char of chars) {\r\n for (const [script, pattern] of Object.entries(SCRIPT_PATTERNS)) {\r\n if (pattern.test(char)) {\r\n charCounts[script] = (charCounts[script] || 0) + 1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Find dominant script\r\n let maxCount = 0;\r\n let dominantScript = 'latin';\r\n\r\n for (const [script, count] of Object.entries(charCounts)) {\r\n if (count > maxCount) {\r\n maxCount = count;\r\n dominantScript = script;\r\n }\r\n }\r\n\r\n return dominantScript;\r\n}\r\n\r\n/**\r\n * Get script information for layout decisions\r\n */\r\nexport function getScriptInfo(script: string): ScriptInfo {\r\n const scriptMap: Record<string, ScriptInfo> = {\r\n latin: {\r\n script: 'latin',\r\n direction: 'ltr',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n arabic: {\r\n script: 'arabic',\r\n direction: 'rtl',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n hebrew: {\r\n script: 'hebrew',\r\n direction: 'rtl',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n thai: {\r\n script: 'thai',\r\n direction: 'ltr',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n devanagari: {\r\n script: 'devanagari',\r\n direction: 'ltr',\r\n needsShaping: true,\r\n complexLayout: true,\r\n },\r\n cjk: {\r\n script: 'cjk',\r\n direction: 'ltr',\r\n needsShaping: false,\r\n complexLayout: false,\r\n },\r\n };\r\n\r\n return scriptMap[script] || scriptMap.latin;\r\n}\r\n\r\n/**\r\n * Break words according to language-specific rules\r\n */\r\nexport function breakWords(text: string, locale?: string): string[] {\r\n // Use native word segmentation if available\r\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\r\n try {\r\n const segmenter = new Intl.Segmenter(locale, {\r\n granularity: 'word',\r\n });\r\n \r\n const segments = segmenter.segment(text);\r\n return Array.from(segments)\r\n .filter(segment => segment.isWordLike)\r\n .map(segment => segment.segment);\r\n } catch (e) {\r\n // Fallback if Intl.Segmenter fails\r\n }\r\n }\r\n\r\n // Simple fallback word breaking\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n}\r\n\r\n/**\r\n * Character classification functions\r\n */\r\nexport function isWhitespace(grapheme: string): boolean {\r\n return /\\s/.test(grapheme);\r\n}\r\n\r\nexport function isLineBreak(grapheme: string): boolean {\r\n return grapheme === '\\n' || grapheme === '\\r' || grapheme === '\\r\\n';\r\n}\r\n\r\nexport function isWordSeparator(grapheme: string): boolean {\r\n return /[\\s\\-\\u2010-\\u2015]/.test(grapheme);\r\n}\r\n\r\nexport function isPunctuation(grapheme: string): boolean {\r\n return /[\\p{P}]/u.test(grapheme);\r\n}\r\n\r\nexport function isEmoji(grapheme: string): boolean {\r\n return /[\\p{Emoji}]/u.test(grapheme);\r\n}\r\n\r\nexport function isRTLCharacter(char: string): boolean {\r\n return UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char);\r\n}\r\n\r\n/**\r\n * Advanced grapheme cluster handling for complex scripts\r\n */\r\nexport function findGraphemeClusterBoundaries(text: string): number[] {\r\n const boundaries: number[] = [0];\r\n const graphemes = segmentGraphemes(text);\r\n let position = 0;\r\n\r\n for (const grapheme of graphemes) {\r\n position += grapheme.length;\r\n boundaries.push(position);\r\n }\r\n\r\n return boundaries;\r\n}\r\n\r\n/**\r\n * Check if a position is at a grapheme cluster boundary\r\n */\r\nexport function isGraphemeClusterBoundary(text: string, position: number): boolean {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n return boundaries.includes(position);\r\n}\r\n\r\n/**\r\n * Find the next grapheme cluster boundary from a given position\r\n */\r\nexport function findNextGraphemeClusterBoundary(text: string, position: number): number {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n return boundaries.find(boundary => boundary > position) || text.length;\r\n}\r\n\r\n/**\r\n * Find the previous grapheme cluster boundary from a given position \r\n */\r\nexport function findPreviousGraphemeClusterBoundary(text: string, position: number): number {\r\n const boundaries = findGraphemeClusterBoundaries(text);\r\n const reversedBoundaries = [...boundaries].reverse();\r\n return reversedBoundaries.find(boundary => boundary < position) || 0;\r\n}\r\n\r\n/**\r\n * Normalize text for consistent processing\r\n */\r\nexport function normalizeText(text: string, form: 'NFC' | 'NFD' | 'NFKC' | 'NFKD' = 'NFC'): string {\r\n if (typeof text.normalize === 'function') {\r\n return text.normalize(form);\r\n }\r\n return text;\r\n}\r\n\r\n/**\r\n * Detect if text contains complex script characters that need special handling\r\n */\r\nexport function needsComplexLayout(text: string): boolean {\r\n const complexScripts = ['arabic', 'hebrew', 'thai', 'devanagari', 'bengali'];\r\n const detectedScript = detectScript(text);\r\n return complexScripts.includes(detectedScript);\r\n}\r\n\r\n/**\r\n * Get text direction based on content analysis\r\n */\r\nexport function getTextDirection(text: string, fallback: 'ltr' | 'rtl' = 'ltr'): 'ltr' | 'rtl' {\r\n let rtlChars = 0;\r\n let ltrChars = 0;\r\n\r\n for (const char of text) {\r\n if (UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char)) {\r\n rtlChars++;\r\n } else if (UNICODE_CATEGORIES.L.test(char)) {\r\n ltrChars++;\r\n }\r\n }\r\n\r\n if (rtlChars > ltrChars) return 'rtl';\r\n if (ltrChars > rtlChars) return 'ltr';\r\n return fallback;\r\n}\r\n\r\n/**\r\n * Split text into lines respecting complex script rules\r\n */\r\nexport function splitTextLines(text: string): string[] {\r\n // Handle different line break types\r\n return text.split(/\\r\\n|\\r|\\n/);\r\n}\r\n\r\n/**\r\n * Check if combining marks or modifiers should be kept with base character\r\n */\r\nexport function isCombiningMark(char: string): boolean {\r\n return UNICODE_CATEGORIES.NSM.test(char);\r\n}\r\n\r\n/**\r\n * Get bidirectional character type\r\n */\r\nfunction getBidiDirection(char: string, baseDirection: 'ltr' | 'rtl'): 'ltr' | 'rtl' {\r\n // Strong RTL characters\r\n if (UNICODE_CATEGORIES.R.test(char) || UNICODE_CATEGORIES.AL.test(char)) {\r\n return 'rtl';\r\n }\r\n \r\n // Strong LTR characters \r\n if (UNICODE_CATEGORIES.L.test(char)) {\r\n return 'ltr';\r\n }\r\n \r\n // Numbers follow base direction in simplified algorithm\r\n if (UNICODE_CATEGORIES.EN.test(char) || UNICODE_CATEGORIES.AN.test(char)) {\r\n return baseDirection;\r\n }\r\n \r\n // Neutral characters follow context\r\n return baseDirection;\r\n}\r\n\r\n/**\r\n * Advanced word breaking for different scripts\r\n */\r\nexport function breakWordsAdvanced(text: string): string[] {\r\n const script = detectScript(text);\r\n \r\n switch (script) {\r\n case 'cjk':\r\n // CJK can break at most characters\r\n return Array.from(text);\r\n \r\n case 'thai':\r\n // Thai doesn't use spaces - would need dictionary-based breaking\r\n // For now, fall back to character-based breaking\r\n return Array.from(text);\r\n \r\n case 'arabic':\r\n case 'hebrew':\r\n // Handle RTL scripts\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n \r\n default:\r\n // Standard space-based word breaking\r\n return text.split(/\\s+/).filter(word => word.length > 0);\r\n }\r\n}\r\n\r\n/**\r\n * Check if text needs right-to-left processing\r\n */\r\nexport function needsRTLProcessing(text: string): boolean {\r\n for (const char of text) {\r\n if (isRTLCharacter(char)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Reverse text for RTL display (simplified - real RTL is more complex)\r\n */\r\nexport function reverseForRTL(text: string): string {\r\n // This is a simplified implementation\r\n // Real RTL processing requires full BiDi algorithm\r\n const graphemes = segmentGraphemes(text);\r\n return graphemes.reverse().join('');\r\n}\r\n\r\n/**\r\n * Get appropriate line breaking class for character\r\n */\r\nexport function getLineBreakClass(char: string): string {\r\n // Simplified line breaking classes\r\n if (/\\s/.test(char)) return 'SP';\r\n if (/[!-\\/:-@\\[-`{-~]/.test(char)) return 'BA'; // Break after\r\n if (/[(\\[{]/.test(char)) return 'OP'; // Open punctuation\r\n if (/[)\\]}]/.test(char)) return 'CL'; // Close punctuation\r\n if (/\\d/.test(char)) return 'NU'; // Numeric\r\n if (/[A-Za-z]/.test(char)) return 'AL'; // Alphabetic\r\n \r\n return 'AL'; // Default to alphabetic\r\n}\r\n\r\n/**\r\n * Check if line break is allowed between two characters\r\n */\r\nexport function isLineBreakAllowed(before: string, after: string): boolean {\r\n const beforeClass = getLineBreakClass(before);\r\n const afterClass = getLineBreakClass(after);\r\n\r\n // Simplified line breaking rules\r\n if (beforeClass === 'OP') return false; // Don't break after opening\r\n if (afterClass === 'CL') return false; // Don't break before closing\r\n if (beforeClass === 'SP') return true; // Always allow break after space\r\n\r\n return true; // Default allow\r\n}\r\n\r\n// ============================================================================\r\n// Arabic Kashida (Tatweel) Support\r\n// ============================================================================\r\n\r\n/**\r\n * Arabic Tatweel (kashida) character used for justification\r\n */\r\nexport const ARABIC_TATWEEL = '\\u0640';\r\n\r\n/**\r\n * Arabic letters that do NOT connect to the following letter (non-connecting on left).\r\n * These letters cannot have kashida inserted after them.\r\n * ا (Alef), د (Dal), ذ (Thal), ر (Ra), ز (Zay), و (Waw), ة (Teh Marbuta), ء (Hamza)\r\n */\r\nconst ARABIC_NON_CONNECTING = new Set([\r\n '\\u0627', // Alef\r\n '\\u062F', // Dal\r\n '\\u0630', // Thal\r\n '\\u0631', // Ra\r\n '\\u0632', // Zay\r\n '\\u0648', // Waw\r\n '\\u0629', // Teh Marbuta\r\n '\\u0621', // Hamza\r\n '\\u0622', // Alef with Madda\r\n '\\u0623', // Alef with Hamza Above\r\n '\\u0625', // Alef with Hamza Below\r\n '\\u0672', // Alef with Wavy Hamza Above\r\n '\\u0673', // Alef with Wavy Hamza Below\r\n '\\u0675', // High Hamza Alef\r\n '\\u0688', // Dal with Small Tah\r\n '\\u0689', // Dal with Ring\r\n '\\u068A', // Dal with Dot Below\r\n '\\u068B', // Dal with Dot Below and Small Tah\r\n '\\u068C', // Dahal\r\n '\\u068D', // Ddahal\r\n '\\u068E', // Dul\r\n '\\u068F', // Dal with Three Dots Above Downwards\r\n '\\u0690', // Dal with Four Dots Above\r\n '\\u0691', // Rreh\r\n '\\u0692', // Reh with Small V\r\n '\\u0693', // Reh with Ring\r\n '\\u0694', // Reh with Dot Below\r\n '\\u0695', // Reh with Small V Below\r\n '\\u0696', // Reh with Dot Below and Dot Above\r\n '\\u0697', // Reh with Two Dots Above\r\n '\\u0698', // Jeh\r\n '\\u0699', // Reh with Four Dots Above\r\n '\\u06C4', // Waw with Ring\r\n '\\u06C5', // Kirghiz Oe\r\n '\\u06C6', // Oe\r\n '\\u06C7', // U\r\n '\\u06C8', // Yu\r\n '\\u06C9', // Kirghiz Yu\r\n '\\u06CA', // Waw with Two Dots Above\r\n '\\u06CB', // Ve\r\n '\\u06CD', // Yeh with Tail\r\n '\\u06CF', // Waw with Dot Above\r\n]);\r\n\r\n/**\r\n * Check if a character is an Arabic letter (main Arabic block + extended)\r\n */\r\nexport function isArabicLetter(char: string): boolean {\r\n if (!char) return false;\r\n const code = char.charCodeAt(0);\r\n // Arabic: U+0600-U+06FF (main block)\r\n // Arabic Supplement: U+0750-U+077F\r\n // Arabic Extended-A: U+08A0-U+08FF\r\n return (\r\n (code >= 0x0620 && code <= 0x064A) || // Main letters\r\n (code >= 0x066E && code <= 0x06D3) || // Extended letters\r\n (code >= 0x0750 && code <= 0x077F) || // Arabic Supplement\r\n (code >= 0x08A0 && code <= 0x08FF) // Arabic Extended-A\r\n );\r\n}\r\n\r\n/**\r\n * Check if kashida can be inserted between two characters.\r\n * Kashida can only be inserted:\r\n * - Between two Arabic letters\r\n * - After a letter that connects to the next (not in ARABIC_NON_CONNECTING)\r\n * - Not at word boundaries (no whitespace before/after)\r\n */\r\n// Alef variants that form ligatures with lam\r\nconst ARABIC_ALEF_VARIANTS = new Set([\r\n '\\u0627', // ا ALEF\r\n '\\u0623', // أ ALEF WITH HAMZA ABOVE\r\n '\\u0625', // إ ALEF WITH HAMZA BELOW\r\n '\\u0622', // آ ALEF WITH MADDA ABOVE\r\n '\\u0671', // ٱ ALEF WASLA\r\n]);\r\n\r\n// Lam character\r\nconst ARABIC_LAM = '\\u0644'; // ل\r\n\r\nexport function canInsertKashida(prevChar: string, nextChar: string): boolean {\r\n if (!prevChar || !nextChar) return false;\r\n\r\n // Can't insert at whitespace boundaries\r\n if (/\\s/.test(prevChar) || /\\s/.test(nextChar)) return false;\r\n\r\n // Both must be Arabic letters\r\n if (!isArabicLetter(prevChar) || !isArabicLetter(nextChar)) return false;\r\n\r\n // Previous char must connect to the next (not be non-connecting)\r\n if (ARABIC_NON_CONNECTING.has(prevChar)) return false;\r\n\r\n // NEVER insert kashida between lam and alef - they form a ligature (لا)\r\n if (prevChar === ARABIC_LAM && ARABIC_ALEF_VARIANTS.has(nextChar)) return false;\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Represents a valid kashida insertion point\r\n */\r\nexport interface KashidaPoint {\r\n /** Index in the grapheme array where kashida can be inserted after */\r\n charIndex: number;\r\n /** Priority for kashida insertion (higher = insert here first) */\r\n priority: number;\r\n}\r\n\r\n/**\r\n * Find all valid kashida insertion points in a line of text.\r\n * Returns points sorted by priority (highest first).\r\n *\r\n * Priority rules (similar to Adobe Illustrator):\r\n * 1. Between connected letters (ب + ب = highest)\r\n * 2. Prefer middle of words over edges\r\n * 3. Avoid inserting right before/after spaces\r\n */\r\nexport function findKashidaPoints(graphemes: string[]): KashidaPoint[] {\r\n const points: KashidaPoint[] = [];\r\n\r\n for (let i = 0; i < graphemes.length - 1; i++) {\r\n const prev = graphemes[i];\r\n const next = graphemes[i + 1];\r\n\r\n if (canInsertKashida(prev, next)) {\r\n // Calculate priority based on position in word\r\n let priority = 1;\r\n\r\n // Find word boundaries\r\n let wordStart = i;\r\n let wordEnd = i + 1;\r\n\r\n while (wordStart > 0 && !isWhitespace(graphemes[wordStart - 1])) {\r\n wordStart--;\r\n }\r\n while (wordEnd < graphemes.length && !isWhitespace(graphemes[wordEnd])) {\r\n wordEnd++;\r\n }\r\n\r\n const wordLength = wordEnd - wordStart;\r\n const posInWord = i - wordStart;\r\n\r\n // Higher priority for middle positions\r\n const distFromEdge = Math.min(posInWord, wordLength - 1 - posInWord);\r\n priority = distFromEdge + 1;\r\n\r\n // Boost priority for longer words\r\n if (wordLength > 4) priority += 1;\r\n if (wordLength > 6) priority += 1;\r\n\r\n points.push({ charIndex: i, priority });\r\n }\r\n }\r\n\r\n // Sort by priority descending\r\n points.sort((a, b) => b.priority - a.priority);\r\n\r\n return points;\r\n}"],"names":["UNICODE_CATEGORIES","L","R","AL","EN","ES","AN","segmentGraphemes","text","Intl","segmenter","Segmenter","undefined","granularity","segments","segment","Array","from","e","graphemeSplit","analyzeBiDi","baseDirection","arguments","length","runs","chars","currentRun","i","char","charDirection","getBidiDirection","direction","push","level","start","end","isWhitespace","grapheme","test","ARABIC_TATWEEL","ARABIC_NON_CONNECTING","Set","isArabicLetter","code","charCodeAt","ARABIC_ALEF_VARIANTS","ARABIC_LAM","canInsertKashida","prevChar","nextChar","has","findKashidaPoints","graphemes","points","prev","next","priority","wordStart","wordEnd","wordLength","posInWord","distFromEdge","Math","min","charIndex","sort","a","b"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;;AAmBA;AACA,MAAMA,kBAAkB,GAAG;AACzB;AACAC,EAAAA,CAAC,EAAE,0EAA0E;AAC7EC,EAAAA,CAAC,EAAE,wEAAwE;AAC3EC,EAAAA,EAAE,EAAE,oEAAoE;AACxEC,EAAAA,EAAE,EAAE,gDAAgD;AACpDC,EAEAC,EAAE,EAAE,6BAQN,CAAC;;AAmBD;AACA;AACA;AACA;AACO,SAASC,gBAAgBA,CAACC,IAAY,EAAY;AACvD;EACA,IAAI,OAAOC,IAAI,KAAK,WAAW,IAAI,WAAW,IAAIA,IAAI,EAAE;IACtD,IAAI;MACF,MAAMC,SAAS,GAAG,IAAID,IAAI,CAACE,SAAS,CAACC,SAAS,EAAE;AAC9CC,QAAAA,WAAW,EAAE;AACf,OAAC,CAAC;AAEF,MAAA,MAAMC,QAAQ,GAAGJ,SAAS,CAACK,OAAO,CAACP,IAAI,CAAC;MACxC,OAAOQ,KAAK,CAACC,IAAI,CAACH,QAAQ,EAAEC,OAAO,IAAIA,OAAO,CAACA,OAAO,CAAC;IACzD,CAAC,CAAC,OAAOG,CAAC,EAAE;AACV;AAAA,IAAA;AAEJ,EAAA;;AAEA;EACA,OAAOC,aAAa,CAACX,IAAI,CAAC;AAC5B;;AAEA;AACA;AACA;AACO,SAASY,WAAWA,CAACZ,IAAY,EAAmD;AAAA,EAAA,IAAjDa,aAA4B,GAAAC,SAAA,CAAAC,MAAA,GAAA,CAAA,IAAAD,SAAA,CAAA,CAAA,CAAA,KAAAV,SAAA,GAAAU,SAAA,CAAA,CAAA,CAAA,GAAG,KAAK;AAC5E,EAAA,IAAI,CAACd,IAAI,EAAE,OAAO,EAAE;EAEpB,MAAMgB,IAAe,GAAG,EAAE;AAC1B,EAAA,MAAMC,KAAK,GAAGT,KAAK,CAACC,IAAI,CAACT,IAAI,CAAC;EAC9B,IAAIkB,UAA0B,GAAG,IAAI;AAErC,EAAA,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,KAAK,CAACF,MAAM,EAAEI,CAAC,EAAE,EAAE;AACrC,IAAA,MAAMC,IAAI,GAAGH,KAAK,CAACE,CAAC,CAAC;AACrB,IAAA,MAAME,aAAa,GAAGC,gBAAgB,CAACF,IAAI,EAAEP,aAAa,CAAC;;AAE3D;IACA,IAAI,CAACK,UAAU,IAAIA,UAAU,CAACK,SAAS,KAAKF,aAAa,EAAE;AACzD,MAAA,IAAIH,UAAU,EAAE;AACdF,QAAAA,IAAI,CAACQ,IAAI,CAACN,UAAU,CAAC;AACvB,MAAA;AAEAA,MAAAA,UAAU,GAAG;AACXlB,QAAAA,IAAI,EAAEoB,IAAI;AACVG,QAAAA,SAAS,EAAEF,aAAa;AACxBI,QAAAA,KAAK,EAAEJ,aAAa,KAAK,KAAK,GAAG,CAAC,GAAG,CAAC;AACtCK,QAAAA,KAAK,EAAEP,CAAC;QACRQ,GAAG,EAAER,CAAC,GAAG;OACV;AACH,IAAA,CAAC,MAAM;AACL;MACAD,UAAU,CAAClB,IAAI,IAAIoB,IAAI;AACvBF,MAAAA,UAAU,CAACS,GAAG,GAAGR,CAAC,GAAG,CAAC;AACxB,IAAA;AACF,EAAA;;AAEA;AACA,EAAA,IAAID,UAAU,EAAE;AACdF,IAAAA,IAAI,CAACQ,IAAI,CAACN,UAAU,CAAC;AACvB,EAAA;EAEA,OAAOF,IAAI,CAACD,MAAM,GAAG,CAAC,GAAGC,IAAI,GAAG,CAAC;IAC/BhB,IAAI;AACJuB,IAAAA,SAAS,EAAEV,aAAa;AACxBY,IAAAA,KAAK,EAAEZ,aAAa,KAAK,KAAK,GAAG,CAAC,GAAG,CAAC;AACtCa,IAAAA,KAAK,EAAE,CAAC;IACRC,GAAG,EAAE3B,IAAI,CAACe;AACZ,GAAC,CAAC;AACJ;;AAuGA;AACA;AACA;AACO,SAASa,YAAYA,CAACC,QAAgB,EAAW;AACtD,EAAA,OAAO,IAAI,CAACC,IAAI,CAACD,QAAQ,CAAC;AAC5B;;AAqHA;AACA;AACA;AACA,SAASP,gBAAgBA,CAACF,IAAY,EAAEP,aAA4B,EAAiB;AACnF;AACA,EAAA,IAAIrB,kBAAkB,CAACE,CAAC,CAACoC,IAAI,CAACV,IAAI,CAAC,IAAI5B,kBAAkB,CAACG,EAAE,CAACmC,IAAI,CAACV,IAAI,CAAC,EAAE;AACvE,IAAA,OAAO,KAAK;AACd,EAAA;;AAEA;EACA,IAAI5B,kBAAkB,CAACC,CAAC,CAACqC,IAAI,CAACV,IAAI,CAAC,EAAE;AACnC,IAAA,OAAO,KAAK;AACd,EAAA;;AAEA;AACA,EAAA,IAAI5B,kBAAkB,CAACI,EAAE,CAACkC,IAAI,CAACV,IAAI,CAAC,IAAI5B,kBAAkB,CAACM,EAAE,CAACgC,IAAI,CAACV,IAAI,CAAC,EAAE;AACxE,IAAA,OAAOP,aAAa;AACtB,EAAA;;AAEA;AACA,EAAA,OAAOA,aAAa;AACtB;;AAiFA;AACA;AACA;;AAEA;AACA;AACA;AACO,MAAMkB,cAAc,GAAG;;AAE9B;AACA;AACA;AACA;AACA;AACA,MAAMC,qBAAqB,GAAG,IAAIC,GAAG,CAAC,CACpC,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE,CACX,CAAC;;AAEF;AACA;AACA;AACO,SAASC,cAAcA,CAACd,IAAY,EAAW;AACpD,EAAA,IAAI,CAACA,IAAI,EAAE,OAAO,KAAK;AACvB,EAAA,MAAMe,IAAI,GAAGf,IAAI,CAACgB,UAAU,CAAC,CAAC,CAAC;AAC/B;AACA;AACA;AACA,EAAA,OACGD,IAAI,IAAI,MAAM,IAAIA,IAAI,IAAI,MAAM;AAAK;AACrCA,EAAAA,IAAI,IAAI,MAAM,IAAIA,IAAI,IAAI,MAAO;AAAI;AACrCA,EAAAA,IAAI,IAAI,MAAM,IAAIA,IAAI,IAAI,MAAO;AAAI;AACrCA,EAAAA,IAAI,IAAI,MAAM,IAAIA,IAAI,IAAI,MAAO;AAAI;AAE1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAME,oBAAoB,GAAG,IAAIJ,GAAG,CAAC,CACnC,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE;AACV,QAAQ;AAAE,CACX,CAAC;;AAEF;AACA,MAAMK,UAAU,GAAG,QAAQ,CAAC;;AAErB,SAASC,gBAAgBA,CAACC,QAAgB,EAAEC,QAAgB,EAAW;AAC5E,EAAA,IAAI,CAACD,QAAQ,IAAI,CAACC,QAAQ,EAAE,OAAO,KAAK;;AAExC;AACA,EAAA,IAAI,IAAI,CAACX,IAAI,CAACU,QAAQ,CAAC,IAAI,IAAI,CAACV,IAAI,CAACW,QAAQ,CAAC,EAAE,OAAO,KAAK;;AAE5D;AACA,EAAA,IAAI,CAACP,cAAc,CAACM,QAAQ,CAAC,IAAI,CAACN,cAAc,CAACO,QAAQ,CAAC,EAAE,OAAO,KAAK;;AAExE;EACA,IAAIT,qBAAqB,CAACU,GAAG,CAACF,QAAQ,CAAC,EAAE,OAAO,KAAK;;AAErD;AACA,EAAA,IAAIA,QAAQ,KAAKF,UAAU,IAAID,oBAAoB,CAACK,GAAG,CAACD,QAAQ,CAAC,EAAE,OAAO,KAAK;AAE/E,EAAA,OAAO,IAAI;AACb;;AAEA;AACA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,iBAAiBA,CAACC,SAAmB,EAAkB;EACrE,MAAMC,MAAsB,GAAG,EAAE;AAEjC,EAAA,KAAK,IAAI1B,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGyB,SAAS,CAAC7B,MAAM,GAAG,CAAC,EAAEI,CAAC,EAAE,EAAE;AAC7C,IAAA,MAAM2B,IAAI,GAAGF,SAAS,CAACzB,CAAC,CAAC;AACzB,IAAA,MAAM4B,IAAI,GAAGH,SAAS,CAACzB,CAAC,GAAG,CAAC,CAAC;AAE7B,IAAA,IAAIoB,gBAAgB,CAACO,IAAI,EAAEC,IAAI,CAAC,EAAE;AAChC;MACA,IAAIC,QAAQ,GAAG,CAAC;;AAEhB;MACA,IAAIC,SAAS,GAAG9B,CAAC;AACjB,MAAA,IAAI+B,OAAO,GAAG/B,CAAC,GAAG,CAAC;AAEnB,MAAA,OAAO8B,SAAS,GAAG,CAAC,IAAI,CAACrB,YAAY,CAACgB,SAAS,CAACK,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE;AAC/DA,QAAAA,SAAS,EAAE;AACb,MAAA;AACA,MAAA,OAAOC,OAAO,GAAGN,SAAS,CAAC7B,MAAM,IAAI,CAACa,YAAY,CAACgB,SAAS,CAACM,OAAO,CAAC,CAAC,EAAE;AACtEA,QAAAA,OAAO,EAAE;AACX,MAAA;AAEA,MAAA,MAAMC,UAAU,GAAGD,OAAO,GAAGD,SAAS;AACtC,MAAA,MAAMG,SAAS,GAAGjC,CAAC,GAAG8B,SAAS;;AAE/B;AACA,MAAA,MAAMI,YAAY,GAAGC,IAAI,CAACC,GAAG,CAACH,SAAS,EAAED,UAAU,GAAG,CAAC,GAAGC,SAAS,CAAC;MACpEJ,QAAQ,GAAGK,YAAY,GAAG,CAAC;;AAE3B;AACA,MAAA,IAAIF,UAAU,GAAG,CAAC,EAAEH,QAAQ,IAAI,CAAC;AACjC,MAAA,IAAIG,UAAU,GAAG,CAAC,EAAEH,QAAQ,IAAI,CAAC;MAEjCH,MAAM,CAACrB,IAAI,CAAC;AAAEgC,QAAAA,SAAS,EAAErC,CAAC;AAAE6B,QAAAA;AAAS,OAAC,CAAC;AACzC,IAAA;AACF,EAAA;;AAEA;AACAH,EAAAA,MAAM,CAACY,IAAI,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKA,CAAC,CAACX,QAAQ,GAAGU,CAAC,CAACV,QAAQ,CAAC;AAE9C,EAAA,OAAOH,MAAM;AACf;;;;"}
|
|
@@ -82,6 +82,12 @@ export declare class IText<Props extends TOptions<ITextProps> = Partial<ITextPro
|
|
|
82
82
|
* @type Number
|
|
83
83
|
*/
|
|
84
84
|
selectionEnd: number;
|
|
85
|
+
/**
|
|
86
|
+
* Cache for visual positions per line to ensure consistency
|
|
87
|
+
* during selection operations
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
private _visualPositionsCache;
|
|
85
91
|
compositionStart: number;
|
|
86
92
|
compositionEnd: number;
|
|
87
93
|
/**
|
|
@@ -252,19 +258,37 @@ export declare class IText<Props extends TOptions<ITextProps> = Partial<ITextPro
|
|
|
252
258
|
*/
|
|
253
259
|
_getCursorBoundariesAdvanced(index: number): CursorBoundaries;
|
|
254
260
|
/**
|
|
255
|
-
*
|
|
256
|
-
*
|
|
261
|
+
* Override selection to use measureText-based visual positions
|
|
262
|
+
* This ensures hit testing matches actual browser BiDi rendering
|
|
257
263
|
*/
|
|
258
264
|
getSelectionStartFromPointer(e: TPointerEvent): number;
|
|
265
|
+
/**
|
|
266
|
+
* Clear the visual positions cache
|
|
267
|
+
* Should be called when text content or dimensions change
|
|
268
|
+
*/
|
|
269
|
+
_clearVisualPositionsCache(): void;
|
|
270
|
+
/**
|
|
271
|
+
* Measure visual character positions for hit testing using BiDi analysis
|
|
272
|
+
* This properly handles mixed RTL/LTR text by analyzing BiDi runs
|
|
273
|
+
* Results are cached per line for consistency during selection operations
|
|
274
|
+
*/
|
|
275
|
+
_measureVisualPositions(lineIndex: number, lineText: string): Array<{
|
|
276
|
+
logicalIndex: number;
|
|
277
|
+
visualX: number;
|
|
278
|
+
width: number;
|
|
279
|
+
isRtl: boolean;
|
|
280
|
+
}>;
|
|
259
281
|
/**
|
|
260
282
|
* Original cursor boundaries implementation
|
|
261
283
|
* @private
|
|
262
284
|
*/
|
|
263
285
|
_getCursorBoundariesOriginal(index: number, skipCaching?: boolean): CursorBoundaries;
|
|
264
286
|
/**
|
|
265
|
-
* Calculates cursor left/top offset relative to
|
|
287
|
+
* Calculates cursor left/top offset relative to _getLeftOffset()
|
|
288
|
+
* Uses visual positions for BiDi text support
|
|
289
|
+
* Handles kashida by converting original indices to display indices
|
|
266
290
|
* @private
|
|
267
|
-
* @param {number} index index from start
|
|
291
|
+
* @param {number} index index from start (in original text space, without tatweels)
|
|
268
292
|
*/
|
|
269
293
|
__getCursorBoundariesOffsets(index: number): {
|
|
270
294
|
top: number;
|
|
@@ -306,9 +330,10 @@ export declare class IText<Props extends TOptions<ITextProps> = Partial<ITextPro
|
|
|
306
330
|
renderDragSourceEffect(): void;
|
|
307
331
|
renderDropTargetEffect(e: DragEvent): void;
|
|
308
332
|
/**
|
|
309
|
-
* Renders text selection
|
|
333
|
+
* Renders text selection using visual positions for BiDi support
|
|
334
|
+
* Handles kashida by converting original indices to display indices
|
|
310
335
|
* @private
|
|
311
|
-
* @param {{ selectionStart: number, selectionEnd: number }} selection
|
|
336
|
+
* @param {{ selectionStart: number, selectionEnd: number }} selection (in original text space)
|
|
312
337
|
* @param {Object} boundaries Object with left/top/leftOffset/topOffset
|
|
313
338
|
* @param {CanvasRenderingContext2D} ctx transformed context to draw on
|
|
314
339
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IText.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/IText.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAS1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAQnE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"IText.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/IText.ts"],"names":[],"mappings":"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"}
|
|
@@ -146,11 +146,23 @@ export declare abstract class ITextBehavior<Props extends TOptions<TextProps> =
|
|
|
146
146
|
findLineBoundaryRight(startFrom: number): number;
|
|
147
147
|
/**
|
|
148
148
|
* Finds index corresponding to beginning or end of a word
|
|
149
|
+
* Uses Intl.Segmenter for proper Unicode word segmentation when available,
|
|
150
|
+
* falls back to regex-based detection for older browsers.
|
|
149
151
|
* @param {Number} selectionStart Index of a character
|
|
150
152
|
* @param {Number} direction 1 or -1
|
|
151
153
|
* @return {Number} Index of the beginning or end of a word
|
|
152
154
|
*/
|
|
153
155
|
searchWordBoundary(selectionStart: number, direction: 1 | -1): number;
|
|
156
|
+
/**
|
|
157
|
+
* Word boundary search using Intl.Segmenter (proper Unicode support)
|
|
158
|
+
* Works on original text (this.text) since selectionStart is in original text space
|
|
159
|
+
*/
|
|
160
|
+
private _searchWordBoundaryWithSegmenter;
|
|
161
|
+
/**
|
|
162
|
+
* Word boundary search using regex (fallback for older browsers)
|
|
163
|
+
* Works on original text (this.text) since selectionStart is in original text space
|
|
164
|
+
*/
|
|
165
|
+
private _searchWordBoundaryWithRegex;
|
|
154
166
|
/**
|
|
155
167
|
* Selects the word that contains the char at index selectionStart
|
|
156
168
|
* @param {Number} selectionStart Index of a character
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITextBehavior.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/ITextBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"ITextBehavior.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/ITextBehavior.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ITextClickBehavior.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/ITextClickBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAOnE,8BAAsB,kBAAkB,CACtC,KAAK,SAAS,QAAQ,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,EACtD,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,SAAS,SAAS,WAAW,GAAG,WAAW,CAC3C,SAAQ,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;IAClD,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAEvD,YAAY;IAcZ;;;;;;OAMG;IACH,mBAAmB;IAInB;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,SAAS;IAIxB;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,SAAS;IAIpB;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,iBAAiB;IAe7C;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,iBAAiB;IAQ7C;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,mBAAmB,CAAC,WAAW,CAAC;IA+B1E;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,CAAC,SAAS,CAAC;IAmC/D;;;OAGG;IACH,gBAAgB,CAAC,CAAC,EAAE,aAAa;IAgBjC;;;;OAIG;IACH,4BAA4B,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"ITextClickBehavior.d.ts","sourceRoot":"","sources":["../../../../src/shapes/IText/ITextClickBehavior.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EAClB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAOnE,8BAAsB,kBAAkB,CACtC,KAAK,SAAS,QAAQ,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,EACtD,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,SAAS,SAAS,WAAW,GAAG,WAAW,CAC3C,SAAQ,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;IAClD,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAEvD,YAAY;IAcZ;;;;;;OAMG;IACH,mBAAmB;IAInB;;;;;OAKG;IACH,WAAW,CAAC,CAAC,EAAE,SAAS;IAIxB;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,SAAS;IAIpB;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,iBAAiB;IAe7C;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,iBAAiB;IAQ7C;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,mBAAmB,CAAC,WAAW,CAAC;IA+B1E;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,mBAAmB,CAAC,SAAS,CAAC;IAmC/D;;;OAGG;IACH,gBAAgB,CAAC,CAAC,EAAE,aAAa;IAgBjC;;;;OAIG;IACH,4BAA4B,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM;CAoEvD"}
|