fetta 1.4.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -25
- package/dist/chunk-FP4I6OR2.js +43 -0
- package/dist/chunk-ORMEWXMH.js +33 -0
- package/dist/chunk-UPF3IYHC.js +1762 -0
- package/dist/helpers.d.ts +46 -0
- package/dist/helpers.js +121 -0
- package/dist/index-c1UKfWWK.d.ts +144 -0
- package/dist/index.d.ts +1 -137
- package/dist/index.js +2 -1
- package/dist/initialStyles-BGuPp5CS.d.ts +23 -0
- package/dist/motion.d.ts +185 -0
- package/dist/motion.js +2116 -0
- package/dist/react.d.ts +37 -76
- package/dist/react.js +136 -101
- package/package.json +26 -2
- package/dist/chunk-Y4GCLM4K.js +0 -1077
package/dist/chunk-Y4GCLM4K.js
DELETED
|
@@ -1,1077 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defProps = Object.defineProperties;
|
|
3
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
-
var __spreadValues = (a, b) => {
|
|
9
|
-
for (var prop in b || (b = {}))
|
|
10
|
-
if (__hasOwnProp.call(b, prop))
|
|
11
|
-
__defNormalProp(a, prop, b[prop]);
|
|
12
|
-
if (__getOwnPropSymbols)
|
|
13
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
-
if (__propIsEnum.call(b, prop))
|
|
15
|
-
__defNormalProp(a, prop, b[prop]);
|
|
16
|
-
}
|
|
17
|
-
return a;
|
|
18
|
-
};
|
|
19
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
-
|
|
21
|
-
// src/core/splitText.ts
|
|
22
|
-
var ARIA_LABEL_ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
23
|
-
"h1",
|
|
24
|
-
"h2",
|
|
25
|
-
"h3",
|
|
26
|
-
"h4",
|
|
27
|
-
"h5",
|
|
28
|
-
"h6",
|
|
29
|
-
"a",
|
|
30
|
-
"button",
|
|
31
|
-
"img",
|
|
32
|
-
"input",
|
|
33
|
-
"select",
|
|
34
|
-
"textarea",
|
|
35
|
-
"table",
|
|
36
|
-
"figure",
|
|
37
|
-
"form",
|
|
38
|
-
"fieldset",
|
|
39
|
-
"dialog",
|
|
40
|
-
"details",
|
|
41
|
-
"section",
|
|
42
|
-
"article",
|
|
43
|
-
"nav",
|
|
44
|
-
"aside",
|
|
45
|
-
"header",
|
|
46
|
-
"footer",
|
|
47
|
-
"main"
|
|
48
|
-
]);
|
|
49
|
-
var BREAK_CHARS = /* @__PURE__ */ new Set([
|
|
50
|
-
"\u2014",
|
|
51
|
-
// em-dash
|
|
52
|
-
"\u2013",
|
|
53
|
-
// en-dash
|
|
54
|
-
"-",
|
|
55
|
-
// hyphen
|
|
56
|
-
"/",
|
|
57
|
-
// slash
|
|
58
|
-
"\u2012",
|
|
59
|
-
// figure dash (U+2012)
|
|
60
|
-
"\u2015"
|
|
61
|
-
// horizontal bar (U+2015)
|
|
62
|
-
]);
|
|
63
|
-
var CONTEXTUAL_SCRIPT_REGEX = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF\u0590-\u05FF\uFB1D-\uFB4F\u0E00-\u0E7F\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F]/;
|
|
64
|
-
function hasContextualScript(chars) {
|
|
65
|
-
return chars.some((char) => CONTEXTUAL_SCRIPT_REGEX.test(char));
|
|
66
|
-
}
|
|
67
|
-
var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
|
|
68
|
-
"a",
|
|
69
|
-
"abbr",
|
|
70
|
-
"acronym",
|
|
71
|
-
"b",
|
|
72
|
-
"bdi",
|
|
73
|
-
"bdo",
|
|
74
|
-
"big",
|
|
75
|
-
"cite",
|
|
76
|
-
"code",
|
|
77
|
-
"data",
|
|
78
|
-
"del",
|
|
79
|
-
"dfn",
|
|
80
|
-
"em",
|
|
81
|
-
"i",
|
|
82
|
-
"ins",
|
|
83
|
-
"kbd",
|
|
84
|
-
"mark",
|
|
85
|
-
"q",
|
|
86
|
-
"s",
|
|
87
|
-
"samp",
|
|
88
|
-
"small",
|
|
89
|
-
"span",
|
|
90
|
-
"strong",
|
|
91
|
-
"sub",
|
|
92
|
-
"sup",
|
|
93
|
-
"time",
|
|
94
|
-
"u",
|
|
95
|
-
"var"
|
|
96
|
-
]);
|
|
97
|
-
var KERNING_STYLE_PROPS = [
|
|
98
|
-
"font",
|
|
99
|
-
"font-kerning",
|
|
100
|
-
"font-variant-ligatures",
|
|
101
|
-
"font-feature-settings",
|
|
102
|
-
"font-variation-settings",
|
|
103
|
-
"font-optical-sizing",
|
|
104
|
-
"font-size-adjust",
|
|
105
|
-
"font-stretch",
|
|
106
|
-
"font-variant-caps",
|
|
107
|
-
"font-variant-numeric",
|
|
108
|
-
"font-variant-east-asian",
|
|
109
|
-
"font-synthesis",
|
|
110
|
-
"font-synthesis-weight",
|
|
111
|
-
"font-synthesis-style",
|
|
112
|
-
"letter-spacing",
|
|
113
|
-
"word-spacing",
|
|
114
|
-
"text-rendering",
|
|
115
|
-
"text-transform",
|
|
116
|
-
"direction",
|
|
117
|
-
"unicode-bidi"
|
|
118
|
-
];
|
|
119
|
-
function copyKerningStyles(target, styles) {
|
|
120
|
-
KERNING_STYLE_PROPS.forEach((prop) => {
|
|
121
|
-
const value = styles.getPropertyValue(prop);
|
|
122
|
-
if (value) target.style.setProperty(prop, value);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
function buildKerningStyleKey(styles) {
|
|
126
|
-
return KERNING_STYLE_PROPS.map((prop) => styles.getPropertyValue(prop)).join("|");
|
|
127
|
-
}
|
|
128
|
-
var isSafariBrowser = null;
|
|
129
|
-
function isSafari() {
|
|
130
|
-
if (isSafariBrowser !== null) return isSafariBrowser;
|
|
131
|
-
if (typeof navigator === "undefined") return false;
|
|
132
|
-
isSafariBrowser = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
133
|
-
return isSafariBrowser;
|
|
134
|
-
}
|
|
135
|
-
function measureKerningDOM(container, styleSource, chars, styles) {
|
|
136
|
-
const kerningMap = /* @__PURE__ */ new Map();
|
|
137
|
-
if (chars.length < 2) return kerningMap;
|
|
138
|
-
const measurer = document.createElement("span");
|
|
139
|
-
measurer.style.cssText = `
|
|
140
|
-
position: absolute;
|
|
141
|
-
visibility: hidden;
|
|
142
|
-
white-space: pre;
|
|
143
|
-
`;
|
|
144
|
-
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
145
|
-
copyKerningStyles(measurer, computedStyles);
|
|
146
|
-
const webkitSmoothing = computedStyles.webkitFontSmoothing || computedStyles["-webkit-font-smoothing"];
|
|
147
|
-
const mozSmoothing = computedStyles.MozOsxFontSmoothing || computedStyles["-moz-osx-font-smoothing"];
|
|
148
|
-
if (webkitSmoothing) {
|
|
149
|
-
measurer.style.webkitFontSmoothing = webkitSmoothing;
|
|
150
|
-
}
|
|
151
|
-
if (mozSmoothing) {
|
|
152
|
-
measurer.style.MozOsxFontSmoothing = mozSmoothing;
|
|
153
|
-
}
|
|
154
|
-
container.appendChild(measurer);
|
|
155
|
-
const charWidths = /* @__PURE__ */ new Map();
|
|
156
|
-
for (const char of new Set(chars)) {
|
|
157
|
-
measurer.textContent = char;
|
|
158
|
-
charWidths.set(char, measurer.getBoundingClientRect().width);
|
|
159
|
-
}
|
|
160
|
-
for (let i = 0; i < chars.length - 1; i++) {
|
|
161
|
-
const char1 = chars[i];
|
|
162
|
-
const char2 = chars[i + 1];
|
|
163
|
-
measurer.textContent = char1 + char2;
|
|
164
|
-
const pairWidth = measurer.getBoundingClientRect().width;
|
|
165
|
-
const kerning = pairWidth - charWidths.get(char1) - charWidths.get(char2);
|
|
166
|
-
if (Math.abs(kerning) > 1e-3) {
|
|
167
|
-
kerningMap.set(i + 1, kerning);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
container.removeChild(measurer);
|
|
171
|
-
return kerningMap;
|
|
172
|
-
}
|
|
173
|
-
function measureKerningRange(container, styleSource, chars, styles) {
|
|
174
|
-
const kerningMap = /* @__PURE__ */ new Map();
|
|
175
|
-
if (chars.length < 2) return kerningMap;
|
|
176
|
-
const measurer = document.createElement("span");
|
|
177
|
-
measurer.style.cssText = "position:absolute;visibility:hidden;white-space:pre;";
|
|
178
|
-
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
179
|
-
copyKerningStyles(measurer, computedStyles);
|
|
180
|
-
container.appendChild(measurer);
|
|
181
|
-
const range = document.createRange();
|
|
182
|
-
const measureWidth = () => {
|
|
183
|
-
const textNode = measurer.firstChild;
|
|
184
|
-
if (!textNode) return 0;
|
|
185
|
-
range.selectNodeContents(textNode);
|
|
186
|
-
return range.getBoundingClientRect().width;
|
|
187
|
-
};
|
|
188
|
-
const charWidths = /* @__PURE__ */ new Map();
|
|
189
|
-
for (const char of new Set(chars)) {
|
|
190
|
-
measurer.textContent = char;
|
|
191
|
-
charWidths.set(char, measureWidth());
|
|
192
|
-
}
|
|
193
|
-
for (let i = 0; i < chars.length - 1; i++) {
|
|
194
|
-
const char1 = chars[i];
|
|
195
|
-
const char2 = chars[i + 1];
|
|
196
|
-
measurer.textContent = char1 + char2;
|
|
197
|
-
const kerning = measureWidth() - charWidths.get(char1) - charWidths.get(char2);
|
|
198
|
-
if (Math.abs(kerning) > 1e-3) {
|
|
199
|
-
kerningMap.set(i + 1, kerning);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
range.detach();
|
|
203
|
-
container.removeChild(measurer);
|
|
204
|
-
return kerningMap;
|
|
205
|
-
}
|
|
206
|
-
function measureKerning(container, styleSource, chars, styles) {
|
|
207
|
-
if (chars.length < 2) return /* @__PURE__ */ new Map();
|
|
208
|
-
if (!container.isConnected) {
|
|
209
|
-
console.warn("splitText: kerning measurement requires a connected DOM element. Skipping kerning.");
|
|
210
|
-
return /* @__PURE__ */ new Map();
|
|
211
|
-
}
|
|
212
|
-
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
213
|
-
return isSafari() ? measureKerningDOM(container, styleSource, chars, computedStyles) : measureKerningRange(container, styleSource, chars, computedStyles);
|
|
214
|
-
}
|
|
215
|
-
var srOnlyStylesInjected = false;
|
|
216
|
-
function injectSrOnlyStyles() {
|
|
217
|
-
if (srOnlyStylesInjected || typeof document === "undefined") return;
|
|
218
|
-
const style = document.createElement("style");
|
|
219
|
-
style.textContent = `
|
|
220
|
-
.fetta-sr-only {
|
|
221
|
-
position: absolute;
|
|
222
|
-
width: 1px;
|
|
223
|
-
height: 1px;
|
|
224
|
-
padding: 0;
|
|
225
|
-
margin: -1px;
|
|
226
|
-
overflow: hidden;
|
|
227
|
-
clip-path: inset(50%);
|
|
228
|
-
white-space: nowrap;
|
|
229
|
-
border-width: 0;
|
|
230
|
-
}`;
|
|
231
|
-
document.head.appendChild(style);
|
|
232
|
-
srOnlyStylesInjected = true;
|
|
233
|
-
}
|
|
234
|
-
function createScreenReaderCopy(originalHTML) {
|
|
235
|
-
const srCopy = document.createElement("span");
|
|
236
|
-
srCopy.className = "fetta-sr-only";
|
|
237
|
-
srCopy.innerHTML = originalHTML;
|
|
238
|
-
srCopy.dataset.fettaSrCopy = "true";
|
|
239
|
-
return srCopy;
|
|
240
|
-
}
|
|
241
|
-
function hasInlineDescendants(element) {
|
|
242
|
-
const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
|
|
243
|
-
let node;
|
|
244
|
-
while (node = walker.nextNode()) {
|
|
245
|
-
if (INLINE_ELEMENTS.has(node.tagName.toLowerCase())) {
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
function ancestorChainsEqual(a, b) {
|
|
252
|
-
if (a.length !== b.length) return false;
|
|
253
|
-
for (let i = 0; i < a.length; i++) {
|
|
254
|
-
if (a[i].instanceId !== b[i].instanceId) return false;
|
|
255
|
-
}
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
function groupCharsByAncestors(chars) {
|
|
259
|
-
if (chars.length === 0) return [];
|
|
260
|
-
const groups = [];
|
|
261
|
-
let currentGroup = [chars[0]];
|
|
262
|
-
let currentAncestors = chars[0].ancestors;
|
|
263
|
-
for (let i = 1; i < chars.length; i++) {
|
|
264
|
-
const char = chars[i];
|
|
265
|
-
if (ancestorChainsEqual(char.ancestors, currentAncestors)) {
|
|
266
|
-
currentGroup.push(char);
|
|
267
|
-
} else {
|
|
268
|
-
groups.push({ ancestors: currentAncestors, chars: currentGroup });
|
|
269
|
-
currentGroup = [char];
|
|
270
|
-
currentAncestors = char.ancestors;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
groups.push({ ancestors: currentAncestors, chars: currentGroup });
|
|
274
|
-
return groups;
|
|
275
|
-
}
|
|
276
|
-
function cloneAncestorAsWrapper(info) {
|
|
277
|
-
const el = document.createElement(info.tagName);
|
|
278
|
-
info.attributes.forEach((value, key) => {
|
|
279
|
-
el.setAttribute(key, value);
|
|
280
|
-
});
|
|
281
|
-
return el;
|
|
282
|
-
}
|
|
283
|
-
function wrapInAncestors(content, ancestors) {
|
|
284
|
-
if (ancestors.length === 0) return content;
|
|
285
|
-
let wrapped = content;
|
|
286
|
-
for (let i = 0; i < ancestors.length; i++) {
|
|
287
|
-
const wrapper = cloneAncestorAsWrapper(ancestors[i]);
|
|
288
|
-
wrapper.appendChild(wrapped);
|
|
289
|
-
wrapped = wrapper;
|
|
290
|
-
}
|
|
291
|
-
return wrapped;
|
|
292
|
-
}
|
|
293
|
-
function normalizeToPromise(value) {
|
|
294
|
-
if (!value) return null;
|
|
295
|
-
if (value instanceof Promise) return value;
|
|
296
|
-
if (typeof value === "object") {
|
|
297
|
-
if ("finished" in value) {
|
|
298
|
-
return value.finished;
|
|
299
|
-
}
|
|
300
|
-
if ("then" in value && typeof value.then === "function") {
|
|
301
|
-
return Promise.resolve(value);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
if (Array.isArray(value)) {
|
|
305
|
-
const promises = value.map(normalizeToPromise).filter((p) => p !== null);
|
|
306
|
-
return promises.length ? Promise.all(promises) : null;
|
|
307
|
-
}
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
var segmenterCache = null;
|
|
311
|
-
function segmentGraphemes(text) {
|
|
312
|
-
if (!segmenterCache) {
|
|
313
|
-
segmenterCache = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
314
|
-
}
|
|
315
|
-
return [...segmenterCache.segment(text)].map((s) => s.segment);
|
|
316
|
-
}
|
|
317
|
-
function buildAncestorChain(textNode, rootElement, ancestorCache) {
|
|
318
|
-
const ancestors = [];
|
|
319
|
-
let current = textNode.parentNode;
|
|
320
|
-
while (current && current !== rootElement && current instanceof Element) {
|
|
321
|
-
const tagName = current.tagName.toLowerCase();
|
|
322
|
-
if (INLINE_ELEMENTS.has(tagName)) {
|
|
323
|
-
let info = ancestorCache.get(current);
|
|
324
|
-
if (!info) {
|
|
325
|
-
const attributes = /* @__PURE__ */ new Map();
|
|
326
|
-
for (const attr of current.attributes) {
|
|
327
|
-
attributes.set(attr.name, attr.value);
|
|
328
|
-
}
|
|
329
|
-
info = {
|
|
330
|
-
tagName,
|
|
331
|
-
attributes,
|
|
332
|
-
instanceId: /* @__PURE__ */ Symbol()
|
|
333
|
-
};
|
|
334
|
-
ancestorCache.set(current, info);
|
|
335
|
-
}
|
|
336
|
-
ancestors.push(info);
|
|
337
|
-
}
|
|
338
|
-
current = current.parentNode;
|
|
339
|
-
}
|
|
340
|
-
return ancestors;
|
|
341
|
-
}
|
|
342
|
-
function collectTextStructure(element, trackAncestors) {
|
|
343
|
-
const words = [];
|
|
344
|
-
const ancestorCache = trackAncestors ? /* @__PURE__ */ new WeakMap() : null;
|
|
345
|
-
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
|
346
|
-
let node;
|
|
347
|
-
let currentWord = [];
|
|
348
|
-
let noSpaceBeforeNext = false;
|
|
349
|
-
const pushWord = () => {
|
|
350
|
-
if (currentWord.length > 0) {
|
|
351
|
-
words.push({
|
|
352
|
-
chars: currentWord,
|
|
353
|
-
noSpaceBefore: noSpaceBeforeNext
|
|
354
|
-
});
|
|
355
|
-
currentWord = [];
|
|
356
|
-
noSpaceBeforeNext = false;
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
const emptyAncestors = [];
|
|
360
|
-
while (node = walker.nextNode()) {
|
|
361
|
-
const text = node.textContent || "";
|
|
362
|
-
const ancestors = trackAncestors ? buildAncestorChain(node, element, ancestorCache) : emptyAncestors;
|
|
363
|
-
const graphemes = segmentGraphemes(text);
|
|
364
|
-
for (const grapheme of graphemes) {
|
|
365
|
-
if (grapheme === " " || grapheme === "\n" || grapheme === " ") {
|
|
366
|
-
pushWord();
|
|
367
|
-
noSpaceBeforeNext = false;
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
currentWord.push({ char: grapheme, ancestors });
|
|
371
|
-
if (BREAK_CHARS.has(grapheme)) {
|
|
372
|
-
pushWord();
|
|
373
|
-
noSpaceBeforeNext = true;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
pushWord();
|
|
378
|
-
return words;
|
|
379
|
-
}
|
|
380
|
-
function createSpan(className, index, display = "inline-block", options) {
|
|
381
|
-
const span = document.createElement("span");
|
|
382
|
-
if (className) {
|
|
383
|
-
span.className = className;
|
|
384
|
-
}
|
|
385
|
-
if (index !== void 0) {
|
|
386
|
-
span.dataset.index = index.toString();
|
|
387
|
-
if ((options == null ? void 0 : options.propIndex) && (options == null ? void 0 : options.propName)) {
|
|
388
|
-
span.style.setProperty(`--${options.propName}-index`, index.toString());
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
span.style.display = display;
|
|
392
|
-
span.style.position = "relative";
|
|
393
|
-
span.style.textDecoration = "inherit";
|
|
394
|
-
if (options == null ? void 0 : options.ariaHidden) {
|
|
395
|
-
span.setAttribute("aria-hidden", "true");
|
|
396
|
-
}
|
|
397
|
-
return span;
|
|
398
|
-
}
|
|
399
|
-
function createMaskWrapper(display = "inline-block") {
|
|
400
|
-
const wrapper = document.createElement("span");
|
|
401
|
-
wrapper.style.display = display;
|
|
402
|
-
wrapper.style.position = "relative";
|
|
403
|
-
wrapper.style.overflow = "clip";
|
|
404
|
-
return wrapper;
|
|
405
|
-
}
|
|
406
|
-
var PROTECTED_STYLES = /* @__PURE__ */ new Set([
|
|
407
|
-
"display",
|
|
408
|
-
"position",
|
|
409
|
-
"textDecoration",
|
|
410
|
-
"fontVariantLigatures"
|
|
411
|
-
]);
|
|
412
|
-
function applyInitialStyles(elements, style) {
|
|
413
|
-
if (!style || elements.length === 0) return;
|
|
414
|
-
const isFn = typeof style === "function";
|
|
415
|
-
for (let i = 0; i < elements.length; i++) {
|
|
416
|
-
const el = elements[i];
|
|
417
|
-
const styles = isFn ? style(el, i) : style;
|
|
418
|
-
for (const [key, value] of Object.entries(styles)) {
|
|
419
|
-
if (!PROTECTED_STYLES.has(key) && value !== void 0) {
|
|
420
|
-
el.style[key] = value;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
function applyInitialClasses(elements, className) {
|
|
426
|
-
if (!className || elements.length === 0) return;
|
|
427
|
-
const classes = className.split(/\s+/).filter(Boolean);
|
|
428
|
-
for (const el of elements) {
|
|
429
|
-
el.classList.add(...classes);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function groupIntoLines(elements, element) {
|
|
433
|
-
const fontSize = parseFloat(getComputedStyle(element).fontSize);
|
|
434
|
-
const tolerance = Math.max(5, fontSize * 0.3);
|
|
435
|
-
const lineGroups = [];
|
|
436
|
-
let currentLine = [];
|
|
437
|
-
let currentY = null;
|
|
438
|
-
elements.forEach((el) => {
|
|
439
|
-
const rect = el instanceof HTMLElement ? el.getBoundingClientRect() : el.parentElement.getBoundingClientRect();
|
|
440
|
-
const y = Math.round(rect.top);
|
|
441
|
-
if (currentY === null) {
|
|
442
|
-
currentY = y;
|
|
443
|
-
currentLine.push(el);
|
|
444
|
-
} else if (Math.abs(y - currentY) < tolerance) {
|
|
445
|
-
currentLine.push(el);
|
|
446
|
-
} else {
|
|
447
|
-
lineGroups.push(currentLine);
|
|
448
|
-
currentLine = [el];
|
|
449
|
-
currentY = y;
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
|
-
if (currentLine.length > 0) {
|
|
453
|
-
lineGroups.push(currentLine);
|
|
454
|
-
}
|
|
455
|
-
return lineGroups;
|
|
456
|
-
}
|
|
457
|
-
function performSplit(element, measuredWords, charClass, wordClass, lineClass, splitChars, splitWords, splitLines, options) {
|
|
458
|
-
var _a, _b;
|
|
459
|
-
element.textContent = "";
|
|
460
|
-
const allChars = [];
|
|
461
|
-
const allWords = [];
|
|
462
|
-
const needWordWrappers = splitChars || splitWords;
|
|
463
|
-
if (needWordWrappers) {
|
|
464
|
-
const noSpaceBeforeSet = /* @__PURE__ */ new Set();
|
|
465
|
-
const wordLevelAncestors = /* @__PURE__ */ new Map();
|
|
466
|
-
let globalCharIndex = 0;
|
|
467
|
-
measuredWords.forEach((measuredWord, wordIndex) => {
|
|
468
|
-
const wordSpan = createSpan(wordClass, wordIndex, "inline-block", {
|
|
469
|
-
propIndex: options == null ? void 0 : options.propIndex,
|
|
470
|
-
propName: "word",
|
|
471
|
-
ariaHidden: options == null ? void 0 : options.ariaHidden
|
|
472
|
-
});
|
|
473
|
-
if (measuredWord.noSpaceBefore) {
|
|
474
|
-
noSpaceBeforeSet.add(wordSpan);
|
|
475
|
-
}
|
|
476
|
-
if (splitChars) {
|
|
477
|
-
const hasAnyAncestors = measuredWord.chars.some((c) => c.ancestors.length > 0);
|
|
478
|
-
if (!hasAnyAncestors) {
|
|
479
|
-
measuredWord.chars.forEach((measuredChar, charIndexInWord) => {
|
|
480
|
-
const charSpan = createSpan(charClass, globalCharIndex, "inline-block", {
|
|
481
|
-
propIndex: options == null ? void 0 : options.propIndex,
|
|
482
|
-
propName: "char",
|
|
483
|
-
ariaHidden: options == null ? void 0 : options.ariaHidden
|
|
484
|
-
});
|
|
485
|
-
charSpan.textContent = measuredChar.char;
|
|
486
|
-
globalCharIndex++;
|
|
487
|
-
if ((options == null ? void 0 : options.mask) === "chars") {
|
|
488
|
-
const charWrapper = createMaskWrapper("inline-block");
|
|
489
|
-
charWrapper.appendChild(charSpan);
|
|
490
|
-
wordSpan.appendChild(charWrapper);
|
|
491
|
-
} else {
|
|
492
|
-
wordSpan.appendChild(charSpan);
|
|
493
|
-
}
|
|
494
|
-
allChars.push(charSpan);
|
|
495
|
-
});
|
|
496
|
-
} else {
|
|
497
|
-
const charGroups = groupCharsByAncestors(measuredWord.chars);
|
|
498
|
-
const hasWordLevelAncestors = charGroups.length === 1 && charGroups[0].ancestors.length > 0;
|
|
499
|
-
if (hasWordLevelAncestors) {
|
|
500
|
-
wordLevelAncestors.set(wordSpan, charGroups[0].ancestors);
|
|
501
|
-
}
|
|
502
|
-
charGroups.forEach((group) => {
|
|
503
|
-
group.chars.forEach((measuredChar) => {
|
|
504
|
-
const charSpan = createSpan(charClass, globalCharIndex, "inline-block", {
|
|
505
|
-
propIndex: options == null ? void 0 : options.propIndex,
|
|
506
|
-
propName: "char"
|
|
507
|
-
});
|
|
508
|
-
charSpan.textContent = measuredChar.char;
|
|
509
|
-
globalCharIndex++;
|
|
510
|
-
if ((options == null ? void 0 : options.mask) === "chars") {
|
|
511
|
-
const charWrapper = createMaskWrapper("inline-block");
|
|
512
|
-
charWrapper.appendChild(charSpan);
|
|
513
|
-
wordSpan.appendChild(charWrapper);
|
|
514
|
-
} else {
|
|
515
|
-
wordSpan.appendChild(charSpan);
|
|
516
|
-
}
|
|
517
|
-
allChars.push(charSpan);
|
|
518
|
-
});
|
|
519
|
-
if (!hasWordLevelAncestors && group.ancestors.length > 0) {
|
|
520
|
-
const charsToWrap = Array.from(wordSpan.childNodes);
|
|
521
|
-
const lastNChars = charsToWrap.slice(-group.chars.length);
|
|
522
|
-
lastNChars.forEach((node) => wordSpan.removeChild(node));
|
|
523
|
-
const fragment = document.createDocumentFragment();
|
|
524
|
-
lastNChars.forEach((node) => fragment.appendChild(node));
|
|
525
|
-
const wrapped = wrapInAncestors(fragment, group.ancestors);
|
|
526
|
-
wordSpan.appendChild(wrapped);
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
} else {
|
|
531
|
-
const hasAnyAncestors = measuredWord.chars.some((c) => c.ancestors.length > 0);
|
|
532
|
-
if (!hasAnyAncestors) {
|
|
533
|
-
wordSpan.textContent = measuredWord.chars.map((c) => c.char).join("");
|
|
534
|
-
} else {
|
|
535
|
-
const charGroups = groupCharsByAncestors(measuredWord.chars);
|
|
536
|
-
const hasWordLevelAncestors = charGroups.length === 1 && charGroups[0].ancestors.length > 0;
|
|
537
|
-
if (hasWordLevelAncestors) {
|
|
538
|
-
wordLevelAncestors.set(wordSpan, charGroups[0].ancestors);
|
|
539
|
-
wordSpan.textContent = measuredWord.chars.map((c) => c.char).join("");
|
|
540
|
-
} else {
|
|
541
|
-
charGroups.forEach((group) => {
|
|
542
|
-
const text = group.chars.map((c) => c.char).join("");
|
|
543
|
-
const textNode = document.createTextNode(text);
|
|
544
|
-
if (group.ancestors.length > 0) {
|
|
545
|
-
const wrapped = wrapInAncestors(textNode, group.ancestors);
|
|
546
|
-
wordSpan.appendChild(wrapped);
|
|
547
|
-
} else {
|
|
548
|
-
wordSpan.appendChild(textNode);
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
allWords.push(wordSpan);
|
|
555
|
-
});
|
|
556
|
-
let i = 0;
|
|
557
|
-
while (i < allWords.length) {
|
|
558
|
-
const wordSpan = allWords[i];
|
|
559
|
-
const ancestors = wordLevelAncestors.get(wordSpan);
|
|
560
|
-
if (ancestors && ancestors.length > 0) {
|
|
561
|
-
const wordGroup = [wordSpan];
|
|
562
|
-
let j = i + 1;
|
|
563
|
-
while (j < allWords.length) {
|
|
564
|
-
const nextWordSpan = allWords[j];
|
|
565
|
-
const nextAncestors = wordLevelAncestors.get(nextWordSpan);
|
|
566
|
-
if (nextAncestors && ancestorChainsEqual(ancestors, nextAncestors)) {
|
|
567
|
-
wordGroup.push(nextWordSpan);
|
|
568
|
-
j++;
|
|
569
|
-
} else {
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
const fragment = document.createDocumentFragment();
|
|
574
|
-
wordGroup.forEach((ws, idx) => {
|
|
575
|
-
if ((options == null ? void 0 : options.mask) === "words") {
|
|
576
|
-
const wordWrapper = createMaskWrapper("inline-block");
|
|
577
|
-
wordWrapper.appendChild(ws);
|
|
578
|
-
fragment.appendChild(wordWrapper);
|
|
579
|
-
} else {
|
|
580
|
-
fragment.appendChild(ws);
|
|
581
|
-
}
|
|
582
|
-
if (idx < wordGroup.length - 1 && !noSpaceBeforeSet.has(wordGroup[idx + 1])) {
|
|
583
|
-
fragment.appendChild(document.createTextNode(" "));
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
const wrapped = wrapInAncestors(fragment, ancestors);
|
|
587
|
-
element.appendChild(wrapped);
|
|
588
|
-
if (j < allWords.length && !noSpaceBeforeSet.has(allWords[j])) {
|
|
589
|
-
element.appendChild(document.createTextNode(" "));
|
|
590
|
-
}
|
|
591
|
-
i = j;
|
|
592
|
-
} else {
|
|
593
|
-
if ((options == null ? void 0 : options.mask) === "words") {
|
|
594
|
-
const wordWrapper = createMaskWrapper("inline-block");
|
|
595
|
-
wordWrapper.appendChild(wordSpan);
|
|
596
|
-
element.appendChild(wordWrapper);
|
|
597
|
-
} else {
|
|
598
|
-
element.appendChild(wordSpan);
|
|
599
|
-
}
|
|
600
|
-
if (i < allWords.length - 1 && !noSpaceBeforeSet.has(allWords[i + 1])) {
|
|
601
|
-
element.appendChild(document.createTextNode(" "));
|
|
602
|
-
}
|
|
603
|
-
i++;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
if (!(options == null ? void 0 : options.disableKerning) && splitChars && allWords.length > 0) {
|
|
607
|
-
for (const wordSpan of allWords) {
|
|
608
|
-
const wordChars = Array.from(wordSpan.querySelectorAll(`.${charClass}`));
|
|
609
|
-
if (wordChars.length < 2) continue;
|
|
610
|
-
const charStringsForCheck = wordChars.map((c) => c.textContent || "");
|
|
611
|
-
if (hasContextualScript(charStringsForCheck)) continue;
|
|
612
|
-
const styleGroups = [];
|
|
613
|
-
const firstCharStyles = getComputedStyle(wordChars[0]);
|
|
614
|
-
let currentKey = buildKerningStyleKey(firstCharStyles);
|
|
615
|
-
let currentGroup = {
|
|
616
|
-
chars: [wordChars[0]],
|
|
617
|
-
styleSource: wordChars[0],
|
|
618
|
-
styles: firstCharStyles
|
|
619
|
-
};
|
|
620
|
-
for (let i2 = 1; i2 < wordChars.length; i2++) {
|
|
621
|
-
const char = wordChars[i2];
|
|
622
|
-
const charStyles = getComputedStyle(char);
|
|
623
|
-
const key = buildKerningStyleKey(charStyles);
|
|
624
|
-
if (key === currentKey) {
|
|
625
|
-
currentGroup.chars.push(char);
|
|
626
|
-
} else {
|
|
627
|
-
styleGroups.push(currentGroup);
|
|
628
|
-
currentKey = key;
|
|
629
|
-
currentGroup = { chars: [char], styleSource: char, styles: charStyles };
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
styleGroups.push(currentGroup);
|
|
633
|
-
for (const group of styleGroups) {
|
|
634
|
-
if (group.chars.length < 2) continue;
|
|
635
|
-
const charStrings = group.chars.map((c) => c.textContent || "");
|
|
636
|
-
const kerningMap = measureKerning(element, group.styleSource, charStrings, group.styles);
|
|
637
|
-
for (const [charIndex, kerning] of kerningMap) {
|
|
638
|
-
const charSpan = group.chars[charIndex];
|
|
639
|
-
if (charSpan && Math.abs(kerning) < 20) {
|
|
640
|
-
const targetElement = (options == null ? void 0 : options.mask) === "chars" && charSpan.parentElement ? charSpan.parentElement : charSpan;
|
|
641
|
-
targetElement.style.marginLeft = `${kerning}px`;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
for (let wordIdx = 1; wordIdx < allWords.length; wordIdx++) {
|
|
647
|
-
if (noSpaceBeforeSet.has(allWords[wordIdx])) continue;
|
|
648
|
-
const prevWord = allWords[wordIdx - 1];
|
|
649
|
-
const currWord = allWords[wordIdx];
|
|
650
|
-
const prevChars = Array.from(prevWord.querySelectorAll(`.${charClass}`));
|
|
651
|
-
const currChars = Array.from(currWord.querySelectorAll(`.${charClass}`));
|
|
652
|
-
if (prevChars.length === 0 || currChars.length === 0) continue;
|
|
653
|
-
const lastCharSpan = prevChars[prevChars.length - 1];
|
|
654
|
-
const firstCharSpan = currChars[0];
|
|
655
|
-
const lastChar = lastCharSpan.textContent || "";
|
|
656
|
-
const firstChar = firstCharSpan.textContent || "";
|
|
657
|
-
if (!lastChar || !firstChar) continue;
|
|
658
|
-
if (hasContextualScript([lastChar, firstChar])) continue;
|
|
659
|
-
const styles = getComputedStyle(firstCharSpan);
|
|
660
|
-
const kerningMap = measureKerning(element, firstCharSpan, [lastChar, " ", firstChar], styles);
|
|
661
|
-
let totalKerning = 0;
|
|
662
|
-
if (kerningMap.has(1)) totalKerning += kerningMap.get(1);
|
|
663
|
-
if (kerningMap.has(2)) totalKerning += kerningMap.get(2);
|
|
664
|
-
if (Math.abs(totalKerning) > 1e-3 && Math.abs(totalKerning) < 20) {
|
|
665
|
-
const targetElement = (options == null ? void 0 : options.mask) === "chars" && firstCharSpan.parentElement ? firstCharSpan.parentElement : firstCharSpan;
|
|
666
|
-
targetElement.style.marginLeft = `${totalKerning}px`;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
} else if (!(options == null ? void 0 : options.disableKerning) && splitWords && allWords.length > 1) {
|
|
670
|
-
for (let wordIdx = 1; wordIdx < allWords.length; wordIdx++) {
|
|
671
|
-
if (noSpaceBeforeSet.has(allWords[wordIdx])) continue;
|
|
672
|
-
const prevWord = allWords[wordIdx - 1];
|
|
673
|
-
const currWord = allWords[wordIdx];
|
|
674
|
-
const prevText = prevWord.textContent || "";
|
|
675
|
-
const currText = currWord.textContent || "";
|
|
676
|
-
if (!prevText || !currText) continue;
|
|
677
|
-
const lastChar = prevText[prevText.length - 1];
|
|
678
|
-
const firstChar = currText[0];
|
|
679
|
-
if (hasContextualScript([lastChar, firstChar])) continue;
|
|
680
|
-
const styles = getComputedStyle(currWord);
|
|
681
|
-
const kerningMap = measureKerning(element, currWord, [lastChar, " ", firstChar], styles);
|
|
682
|
-
let totalKerning = 0;
|
|
683
|
-
if (kerningMap.has(1)) totalKerning += kerningMap.get(1);
|
|
684
|
-
if (kerningMap.has(2)) totalKerning += kerningMap.get(2);
|
|
685
|
-
if (Math.abs(totalKerning) > 1e-3 && Math.abs(totalKerning) < 20) {
|
|
686
|
-
const targetElement = (options == null ? void 0 : options.mask) === "words" && currWord.parentElement ? currWord.parentElement : currWord;
|
|
687
|
-
targetElement.style.marginLeft = `${totalKerning}px`;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
if (splitLines) {
|
|
692
|
-
const lineGroups = groupIntoLines(allWords, element);
|
|
693
|
-
element.textContent = "";
|
|
694
|
-
const allLines = [];
|
|
695
|
-
lineGroups.forEach((words, lineIndex) => {
|
|
696
|
-
const lineSpan = createSpan(lineClass, lineIndex, "block", {
|
|
697
|
-
propIndex: options == null ? void 0 : options.propIndex,
|
|
698
|
-
propName: "line",
|
|
699
|
-
ariaHidden: options == null ? void 0 : options.ariaHidden
|
|
700
|
-
});
|
|
701
|
-
allLines.push(lineSpan);
|
|
702
|
-
let wi = 0;
|
|
703
|
-
while (wi < words.length) {
|
|
704
|
-
const wordSpan = words[wi];
|
|
705
|
-
const ancestors = wordLevelAncestors.get(wordSpan);
|
|
706
|
-
if (ancestors && ancestors.length > 0) {
|
|
707
|
-
const wordGroup = [wordSpan];
|
|
708
|
-
let wj = wi + 1;
|
|
709
|
-
while (wj < words.length) {
|
|
710
|
-
const nextWordSpan = words[wj];
|
|
711
|
-
const nextAncestors = wordLevelAncestors.get(nextWordSpan);
|
|
712
|
-
if (nextAncestors && ancestorChainsEqual(ancestors, nextAncestors)) {
|
|
713
|
-
wordGroup.push(nextWordSpan);
|
|
714
|
-
wj++;
|
|
715
|
-
} else {
|
|
716
|
-
break;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
const fragment = document.createDocumentFragment();
|
|
720
|
-
wordGroup.forEach((ws, idx) => {
|
|
721
|
-
if ((options == null ? void 0 : options.mask) === "words") {
|
|
722
|
-
const wordWrapper = createMaskWrapper("inline-block");
|
|
723
|
-
wordWrapper.appendChild(ws);
|
|
724
|
-
fragment.appendChild(wordWrapper);
|
|
725
|
-
} else {
|
|
726
|
-
fragment.appendChild(ws);
|
|
727
|
-
}
|
|
728
|
-
if (idx < wordGroup.length - 1 && !noSpaceBeforeSet.has(wordGroup[idx + 1])) {
|
|
729
|
-
fragment.appendChild(document.createTextNode(" "));
|
|
730
|
-
}
|
|
731
|
-
});
|
|
732
|
-
const wrapped = wrapInAncestors(fragment, ancestors);
|
|
733
|
-
lineSpan.appendChild(wrapped);
|
|
734
|
-
if (wj < words.length && !noSpaceBeforeSet.has(words[wj])) {
|
|
735
|
-
lineSpan.appendChild(document.createTextNode(" "));
|
|
736
|
-
}
|
|
737
|
-
wi = wj;
|
|
738
|
-
} else {
|
|
739
|
-
if ((options == null ? void 0 : options.mask) === "words") {
|
|
740
|
-
const wordWrapper = createMaskWrapper("inline-block");
|
|
741
|
-
wordWrapper.appendChild(wordSpan);
|
|
742
|
-
lineSpan.appendChild(wordWrapper);
|
|
743
|
-
} else {
|
|
744
|
-
lineSpan.appendChild(wordSpan);
|
|
745
|
-
}
|
|
746
|
-
if (wi < words.length - 1 && !noSpaceBeforeSet.has(words[wi + 1])) {
|
|
747
|
-
lineSpan.appendChild(document.createTextNode(" "));
|
|
748
|
-
}
|
|
749
|
-
wi++;
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
if ((options == null ? void 0 : options.mask) === "lines") {
|
|
753
|
-
const lineWrapper = createMaskWrapper("block");
|
|
754
|
-
lineWrapper.appendChild(lineSpan);
|
|
755
|
-
element.appendChild(lineWrapper);
|
|
756
|
-
} else {
|
|
757
|
-
element.appendChild(lineSpan);
|
|
758
|
-
}
|
|
759
|
-
});
|
|
760
|
-
if (options == null ? void 0 : options.initialStyles) {
|
|
761
|
-
const { chars, words, lines } = options.initialStyles;
|
|
762
|
-
if (chars) applyInitialStyles(allChars, chars);
|
|
763
|
-
if (words) applyInitialStyles(allWords, words);
|
|
764
|
-
if (lines) applyInitialStyles(allLines, lines);
|
|
765
|
-
}
|
|
766
|
-
if (options == null ? void 0 : options.initialClasses) {
|
|
767
|
-
const { chars, words, lines } = options.initialClasses;
|
|
768
|
-
if (chars) applyInitialClasses(allChars, chars);
|
|
769
|
-
if (words) applyInitialClasses(allWords, words);
|
|
770
|
-
if (lines) applyInitialClasses(allLines, lines);
|
|
771
|
-
}
|
|
772
|
-
return {
|
|
773
|
-
chars: allChars,
|
|
774
|
-
words: splitWords ? allWords : [],
|
|
775
|
-
lines: allLines
|
|
776
|
-
};
|
|
777
|
-
}
|
|
778
|
-
if (options == null ? void 0 : options.initialStyles) {
|
|
779
|
-
const { chars, words } = options.initialStyles;
|
|
780
|
-
if (chars) applyInitialStyles(allChars, chars);
|
|
781
|
-
if (words) applyInitialStyles(allWords, words);
|
|
782
|
-
}
|
|
783
|
-
if (options == null ? void 0 : options.initialClasses) {
|
|
784
|
-
const { chars, words } = options.initialClasses;
|
|
785
|
-
if (chars) applyInitialClasses(allChars, chars);
|
|
786
|
-
if (words) applyInitialClasses(allWords, words);
|
|
787
|
-
}
|
|
788
|
-
return {
|
|
789
|
-
chars: allChars,
|
|
790
|
-
words: splitWords ? allWords : [],
|
|
791
|
-
lines: []
|
|
792
|
-
};
|
|
793
|
-
} else {
|
|
794
|
-
if (splitLines) {
|
|
795
|
-
const wordWrappers = [];
|
|
796
|
-
measuredWords.forEach((measuredWord, idx) => {
|
|
797
|
-
const textNode = document.createTextNode(
|
|
798
|
-
measuredWord.chars.map((c) => c.char).join("")
|
|
799
|
-
);
|
|
800
|
-
const wrapper = document.createElement("span");
|
|
801
|
-
wrapper.style.display = "inline";
|
|
802
|
-
wrapper.appendChild(textNode);
|
|
803
|
-
element.appendChild(wrapper);
|
|
804
|
-
wordWrappers.push({ wrapper, wordIndex: idx });
|
|
805
|
-
if (idx < measuredWords.length - 1 && !measuredWords[idx + 1].noSpaceBefore) {
|
|
806
|
-
const spaceNode = document.createTextNode(" ");
|
|
807
|
-
element.appendChild(spaceNode);
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
const lineGroups = groupIntoLines(wordWrappers.map((w) => w.wrapper), element);
|
|
811
|
-
element.textContent = "";
|
|
812
|
-
const allLines = [];
|
|
813
|
-
lineGroups.forEach((wrappers, lineIndex) => {
|
|
814
|
-
const lineSpan = createSpan(lineClass, lineIndex, "block", {
|
|
815
|
-
propIndex: options == null ? void 0 : options.propIndex,
|
|
816
|
-
propName: "line"
|
|
817
|
-
});
|
|
818
|
-
allLines.push(lineSpan);
|
|
819
|
-
wrappers.forEach((wrapper, wrapperIdx) => {
|
|
820
|
-
while (wrapper.firstChild) {
|
|
821
|
-
lineSpan.appendChild(wrapper.firstChild);
|
|
822
|
-
}
|
|
823
|
-
if (wrapperIdx < wrappers.length - 1) {
|
|
824
|
-
const nextWrapper = wrappers[wrapperIdx + 1];
|
|
825
|
-
const nextWordInfo = wordWrappers.find((w) => w.wrapper === nextWrapper);
|
|
826
|
-
if (nextWordInfo && !measuredWords[nextWordInfo.wordIndex].noSpaceBefore) {
|
|
827
|
-
lineSpan.appendChild(document.createTextNode(" "));
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
});
|
|
831
|
-
if ((options == null ? void 0 : options.mask) === "lines") {
|
|
832
|
-
const lineWrapper = createMaskWrapper("block");
|
|
833
|
-
lineWrapper.appendChild(lineSpan);
|
|
834
|
-
element.appendChild(lineWrapper);
|
|
835
|
-
} else {
|
|
836
|
-
element.appendChild(lineSpan);
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
if ((_a = options == null ? void 0 : options.initialStyles) == null ? void 0 : _a.lines) {
|
|
840
|
-
applyInitialStyles(allLines, options.initialStyles.lines);
|
|
841
|
-
}
|
|
842
|
-
if ((_b = options == null ? void 0 : options.initialClasses) == null ? void 0 : _b.lines) {
|
|
843
|
-
applyInitialClasses(allLines, options.initialClasses.lines);
|
|
844
|
-
}
|
|
845
|
-
return { chars: [], words: [], lines: allLines };
|
|
846
|
-
} else {
|
|
847
|
-
const fullText = measuredWords.map((w) => w.chars.map((c) => c.char).join("")).join(" ");
|
|
848
|
-
element.textContent = fullText;
|
|
849
|
-
return { chars: [], words: [], lines: [] };
|
|
850
|
-
}
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
function splitText(element, {
|
|
854
|
-
type = "chars,words,lines",
|
|
855
|
-
charClass = "split-char",
|
|
856
|
-
wordClass = "split-word",
|
|
857
|
-
lineClass = "split-line",
|
|
858
|
-
mask,
|
|
859
|
-
autoSplit = false,
|
|
860
|
-
onResize,
|
|
861
|
-
onSplit,
|
|
862
|
-
revertOnComplete = false,
|
|
863
|
-
propIndex = false,
|
|
864
|
-
disableKerning = false,
|
|
865
|
-
initialStyles,
|
|
866
|
-
initialClasses
|
|
867
|
-
} = {}) {
|
|
868
|
-
var _a;
|
|
869
|
-
if (!(element instanceof HTMLElement)) {
|
|
870
|
-
throw new Error("splitText: element must be an HTMLElement");
|
|
871
|
-
}
|
|
872
|
-
const text = (_a = element.textContent) == null ? void 0 : _a.trim();
|
|
873
|
-
if (!text) {
|
|
874
|
-
console.warn("splitText: element has no text content");
|
|
875
|
-
return {
|
|
876
|
-
chars: [],
|
|
877
|
-
words: [],
|
|
878
|
-
lines: [],
|
|
879
|
-
revert: () => {
|
|
880
|
-
}
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
if (autoSplit && !element.parentElement) {
|
|
884
|
-
console.warn(
|
|
885
|
-
"splitText: autoSplit requires a parent element. AutoSplit will not work."
|
|
886
|
-
);
|
|
887
|
-
}
|
|
888
|
-
const originalHTML = element.innerHTML;
|
|
889
|
-
let splitChars = type.includes("chars");
|
|
890
|
-
let splitWords = type.includes("words");
|
|
891
|
-
let splitLines = type.includes("lines");
|
|
892
|
-
if (!splitChars && !splitWords && !splitLines) {
|
|
893
|
-
console.warn('splitText: type must include at least one of: chars, words, lines. Defaulting to "chars,words,lines".');
|
|
894
|
-
splitChars = splitWords = splitLines = true;
|
|
895
|
-
}
|
|
896
|
-
let isActive = true;
|
|
897
|
-
let resizeObserver = null;
|
|
898
|
-
let debounceTimer = null;
|
|
899
|
-
let lastWidth = null;
|
|
900
|
-
let currentChars = [];
|
|
901
|
-
let currentWords = [];
|
|
902
|
-
let currentLines = [];
|
|
903
|
-
let originalAriaLabel = null;
|
|
904
|
-
if (splitChars) {
|
|
905
|
-
element.style.fontVariantLigatures = "none";
|
|
906
|
-
}
|
|
907
|
-
const trackAncestors = hasInlineDescendants(element);
|
|
908
|
-
const measuredWords = collectTextStructure(element, trackAncestors);
|
|
909
|
-
const useAriaLabel = !trackAncestors && ARIA_LABEL_ALLOWED_TAGS.has(element.tagName.toLowerCase());
|
|
910
|
-
const { chars, words, lines } = performSplit(
|
|
911
|
-
element,
|
|
912
|
-
measuredWords,
|
|
913
|
-
charClass,
|
|
914
|
-
wordClass,
|
|
915
|
-
lineClass,
|
|
916
|
-
splitChars,
|
|
917
|
-
splitWords,
|
|
918
|
-
splitLines,
|
|
919
|
-
{ propIndex, mask, ariaHidden: useAriaLabel, disableKerning, initialStyles, initialClasses }
|
|
920
|
-
);
|
|
921
|
-
currentChars = chars;
|
|
922
|
-
currentWords = words;
|
|
923
|
-
currentLines = lines;
|
|
924
|
-
if (trackAncestors) {
|
|
925
|
-
injectSrOnlyStyles();
|
|
926
|
-
const visualWrapper = document.createElement("span");
|
|
927
|
-
visualWrapper.setAttribute("aria-hidden", "true");
|
|
928
|
-
visualWrapper.dataset.fettaVisual = "true";
|
|
929
|
-
while (element.firstChild) {
|
|
930
|
-
visualWrapper.appendChild(element.firstChild);
|
|
931
|
-
}
|
|
932
|
-
element.appendChild(visualWrapper);
|
|
933
|
-
element.appendChild(createScreenReaderCopy(originalHTML));
|
|
934
|
-
} else if (useAriaLabel) {
|
|
935
|
-
originalAriaLabel = element.getAttribute("aria-label");
|
|
936
|
-
if (originalAriaLabel === null) {
|
|
937
|
-
element.setAttribute("aria-label", text);
|
|
938
|
-
}
|
|
939
|
-
} else {
|
|
940
|
-
injectSrOnlyStyles();
|
|
941
|
-
const visualWrapper = document.createElement("span");
|
|
942
|
-
visualWrapper.setAttribute("aria-hidden", "true");
|
|
943
|
-
visualWrapper.dataset.fettaVisual = "true";
|
|
944
|
-
while (element.firstChild) {
|
|
945
|
-
visualWrapper.appendChild(element.firstChild);
|
|
946
|
-
}
|
|
947
|
-
element.appendChild(visualWrapper);
|
|
948
|
-
element.appendChild(createScreenReaderCopy(originalHTML));
|
|
949
|
-
}
|
|
950
|
-
const dispose = () => {
|
|
951
|
-
if (!isActive) return;
|
|
952
|
-
if (resizeObserver) {
|
|
953
|
-
resizeObserver.disconnect();
|
|
954
|
-
resizeObserver = null;
|
|
955
|
-
}
|
|
956
|
-
if (debounceTimer) {
|
|
957
|
-
clearTimeout(debounceTimer);
|
|
958
|
-
debounceTimer = null;
|
|
959
|
-
}
|
|
960
|
-
isActive = false;
|
|
961
|
-
};
|
|
962
|
-
const revert = () => {
|
|
963
|
-
if (!isActive) return;
|
|
964
|
-
element.innerHTML = originalHTML;
|
|
965
|
-
if (useAriaLabel) {
|
|
966
|
-
if (originalAriaLabel !== null) {
|
|
967
|
-
element.setAttribute("aria-label", originalAriaLabel);
|
|
968
|
-
} else {
|
|
969
|
-
element.removeAttribute("aria-label");
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
if (splitChars) {
|
|
973
|
-
element.style.fontVariantLigatures = "none";
|
|
974
|
-
}
|
|
975
|
-
dispose();
|
|
976
|
-
};
|
|
977
|
-
if (autoSplit) {
|
|
978
|
-
const target = element.parentElement;
|
|
979
|
-
if (!target) {
|
|
980
|
-
console.warn(
|
|
981
|
-
"SplitText: autoSplit enabled but no parent element found. AutoSplit will not work."
|
|
982
|
-
);
|
|
983
|
-
} else {
|
|
984
|
-
let skipFirst = true;
|
|
985
|
-
const getLineFingerprint = (lines2) => {
|
|
986
|
-
return lines2.map((line) => line.textContent || "").join("\n");
|
|
987
|
-
};
|
|
988
|
-
const handleResize = () => {
|
|
989
|
-
if (!isActive) return;
|
|
990
|
-
if (!element.isConnected) {
|
|
991
|
-
dispose();
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
const currentWidth = target.offsetWidth;
|
|
995
|
-
if (currentWidth === lastWidth) return;
|
|
996
|
-
lastWidth = currentWidth;
|
|
997
|
-
const previousFingerprint = getLineFingerprint(currentLines);
|
|
998
|
-
element.innerHTML = originalHTML;
|
|
999
|
-
requestAnimationFrame(() => {
|
|
1000
|
-
if (!isActive) return;
|
|
1001
|
-
const newMeasuredWords = collectTextStructure(element, trackAncestors);
|
|
1002
|
-
const result = performSplit(
|
|
1003
|
-
element,
|
|
1004
|
-
newMeasuredWords,
|
|
1005
|
-
charClass,
|
|
1006
|
-
wordClass,
|
|
1007
|
-
lineClass,
|
|
1008
|
-
splitChars,
|
|
1009
|
-
splitWords,
|
|
1010
|
-
splitLines,
|
|
1011
|
-
{ propIndex, mask, ariaHidden: useAriaLabel, disableKerning, initialStyles, initialClasses }
|
|
1012
|
-
);
|
|
1013
|
-
currentChars = result.chars;
|
|
1014
|
-
currentWords = result.words;
|
|
1015
|
-
currentLines = result.lines;
|
|
1016
|
-
if (trackAncestors || !useAriaLabel) {
|
|
1017
|
-
const visualWrapper = document.createElement("span");
|
|
1018
|
-
visualWrapper.setAttribute("aria-hidden", "true");
|
|
1019
|
-
visualWrapper.dataset.fettaVisual = "true";
|
|
1020
|
-
while (element.firstChild) {
|
|
1021
|
-
visualWrapper.appendChild(element.firstChild);
|
|
1022
|
-
}
|
|
1023
|
-
element.appendChild(visualWrapper);
|
|
1024
|
-
element.appendChild(createScreenReaderCopy(originalHTML));
|
|
1025
|
-
}
|
|
1026
|
-
const newFingerprint = getLineFingerprint(result.lines);
|
|
1027
|
-
if (onResize && newFingerprint !== previousFingerprint) {
|
|
1028
|
-
onResize({
|
|
1029
|
-
chars: result.chars,
|
|
1030
|
-
words: result.words,
|
|
1031
|
-
lines: result.lines
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
});
|
|
1035
|
-
};
|
|
1036
|
-
resizeObserver = new ResizeObserver(() => {
|
|
1037
|
-
if (skipFirst) {
|
|
1038
|
-
skipFirst = false;
|
|
1039
|
-
return;
|
|
1040
|
-
}
|
|
1041
|
-
if (debounceTimer) {
|
|
1042
|
-
clearTimeout(debounceTimer);
|
|
1043
|
-
}
|
|
1044
|
-
debounceTimer = setTimeout(handleResize, 200);
|
|
1045
|
-
});
|
|
1046
|
-
resizeObserver.observe(target);
|
|
1047
|
-
lastWidth = target.offsetWidth;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
if (onSplit) {
|
|
1051
|
-
const animationResult = onSplit({
|
|
1052
|
-
chars: currentChars,
|
|
1053
|
-
words: currentWords,
|
|
1054
|
-
lines: currentLines
|
|
1055
|
-
});
|
|
1056
|
-
if (revertOnComplete) {
|
|
1057
|
-
const promise = normalizeToPromise(animationResult);
|
|
1058
|
-
if (promise) {
|
|
1059
|
-
promise.then(() => {
|
|
1060
|
-
if (isActive) {
|
|
1061
|
-
revert();
|
|
1062
|
-
}
|
|
1063
|
-
}).catch(() => {
|
|
1064
|
-
console.warn("[fetta] Animation rejected, text not reverted");
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
return {
|
|
1070
|
-
chars: currentChars,
|
|
1071
|
-
words: currentWords,
|
|
1072
|
-
lines: currentLines,
|
|
1073
|
-
revert
|
|
1074
|
-
};
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
export { __spreadProps, __spreadValues, normalizeToPromise, splitText };
|