fetta 1.2.0 → 1.3.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/dist/{chunk-PRR25BMJ.js → chunk-Q2D5AQBW.js} +124 -31
- package/dist/index.js +1 -1
- package/dist/react.d.ts +7 -1
- package/dist/react.js +8 -3
- package/package.json +1 -1
|
@@ -63,6 +63,86 @@ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
|
|
|
63
63
|
"u",
|
|
64
64
|
"var"
|
|
65
65
|
]);
|
|
66
|
+
var KERNING_STYLE_PROPS = [
|
|
67
|
+
"font",
|
|
68
|
+
"font-kerning",
|
|
69
|
+
"font-variant-ligatures",
|
|
70
|
+
"font-feature-settings",
|
|
71
|
+
"font-variation-settings",
|
|
72
|
+
"font-optical-sizing",
|
|
73
|
+
"font-size-adjust",
|
|
74
|
+
"font-stretch",
|
|
75
|
+
"font-variant-caps",
|
|
76
|
+
"font-variant-numeric",
|
|
77
|
+
"font-variant-east-asian",
|
|
78
|
+
"font-synthesis",
|
|
79
|
+
"font-synthesis-weight",
|
|
80
|
+
"font-synthesis-style",
|
|
81
|
+
"letter-spacing",
|
|
82
|
+
"word-spacing",
|
|
83
|
+
"text-rendering",
|
|
84
|
+
"text-transform",
|
|
85
|
+
"direction",
|
|
86
|
+
"unicode-bidi"
|
|
87
|
+
];
|
|
88
|
+
function copyKerningStyles(target, styles) {
|
|
89
|
+
KERNING_STYLE_PROPS.forEach((prop) => {
|
|
90
|
+
const value = styles.getPropertyValue(prop);
|
|
91
|
+
if (value) target.style.setProperty(prop, value);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function buildCanvasFontString(styles) {
|
|
95
|
+
const fontStyle = styles.fontStyle || "normal";
|
|
96
|
+
const fontWeight = styles.fontWeight || "normal";
|
|
97
|
+
const fontSize = styles.fontSize || "16px";
|
|
98
|
+
const fontFamily = styles.fontFamily || "sans-serif";
|
|
99
|
+
return [fontStyle, fontWeight, fontSize, fontFamily].filter(Boolean).join(" ");
|
|
100
|
+
}
|
|
101
|
+
function applyKerningStylesToCanvas(ctx, styles) {
|
|
102
|
+
ctx.font = buildCanvasFontString(styles);
|
|
103
|
+
const ctxAny = ctx;
|
|
104
|
+
const setIfExists = (prop, value) => {
|
|
105
|
+
if (!value || value === "normal") return;
|
|
106
|
+
if (prop in ctxAny) ctxAny[prop] = value;
|
|
107
|
+
};
|
|
108
|
+
setIfExists("fontKerning", styles.getPropertyValue("font-kerning"));
|
|
109
|
+
setIfExists("fontVariantLigatures", styles.getPropertyValue("font-variant-ligatures"));
|
|
110
|
+
setIfExists("fontFeatureSettings", styles.getPropertyValue("font-feature-settings"));
|
|
111
|
+
setIfExists("fontVariationSettings", styles.getPropertyValue("font-variation-settings"));
|
|
112
|
+
setIfExists("fontOpticalSizing", styles.getPropertyValue("font-optical-sizing"));
|
|
113
|
+
setIfExists("fontSizeAdjust", styles.getPropertyValue("font-size-adjust"));
|
|
114
|
+
setIfExists("fontStretch", styles.getPropertyValue("font-stretch"));
|
|
115
|
+
setIfExists("fontVariantCaps", styles.getPropertyValue("font-variant-caps"));
|
|
116
|
+
setIfExists("fontVariantNumeric", styles.getPropertyValue("font-variant-numeric"));
|
|
117
|
+
setIfExists("fontVariantEastAsian", styles.getPropertyValue("font-variant-east-asian"));
|
|
118
|
+
setIfExists("fontSynthesis", styles.getPropertyValue("font-synthesis"));
|
|
119
|
+
setIfExists("fontSynthesisWeight", styles.getPropertyValue("font-synthesis-weight"));
|
|
120
|
+
setIfExists("fontSynthesisStyle", styles.getPropertyValue("font-synthesis-style"));
|
|
121
|
+
setIfExists("letterSpacing", styles.getPropertyValue("letter-spacing"));
|
|
122
|
+
setIfExists("wordSpacing", styles.getPropertyValue("word-spacing"));
|
|
123
|
+
setIfExists("textRendering", styles.getPropertyValue("text-rendering"));
|
|
124
|
+
setIfExists("direction", styles.getPropertyValue("direction"));
|
|
125
|
+
}
|
|
126
|
+
function buildKerningStyleKey(styles) {
|
|
127
|
+
return KERNING_STYLE_PROPS.map((prop) => styles.getPropertyValue(prop)).join("|");
|
|
128
|
+
}
|
|
129
|
+
function shouldUseDomKerning(styles) {
|
|
130
|
+
const textTransform = styles.getPropertyValue("text-transform");
|
|
131
|
+
if (textTransform && textTransform !== "none") return true;
|
|
132
|
+
const fontVariant = styles.getPropertyValue("font-variant");
|
|
133
|
+
if (fontVariant && fontVariant !== "normal") return true;
|
|
134
|
+
const fontStretch = styles.getPropertyValue("font-stretch");
|
|
135
|
+
if (fontStretch && fontStretch !== "normal" && fontStretch !== "100%") return true;
|
|
136
|
+
const fontFeatureSettings = styles.getPropertyValue("font-feature-settings");
|
|
137
|
+
if (fontFeatureSettings && fontFeatureSettings !== "normal") return true;
|
|
138
|
+
const fontVariationSettings = styles.getPropertyValue("font-variation-settings");
|
|
139
|
+
if (fontVariationSettings && fontVariationSettings !== "normal") return true;
|
|
140
|
+
const fontOpticalSizing = styles.getPropertyValue("font-optical-sizing");
|
|
141
|
+
if (fontOpticalSizing && fontOpticalSizing !== "auto") return true;
|
|
142
|
+
const fontSizeAdjust = styles.getPropertyValue("font-size-adjust");
|
|
143
|
+
if (fontSizeAdjust && fontSizeAdjust !== "none") return true;
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
66
146
|
var isSafariBrowser = null;
|
|
67
147
|
function isSafari() {
|
|
68
148
|
if (isSafariBrowser !== null) return isSafariBrowser;
|
|
@@ -70,21 +150,14 @@ function isSafari() {
|
|
|
70
150
|
isSafariBrowser = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
71
151
|
return isSafariBrowser;
|
|
72
152
|
}
|
|
73
|
-
function measureKerningCanvas(
|
|
153
|
+
function measureKerningCanvas(styleSource, chars, styles) {
|
|
74
154
|
const kerningMap = /* @__PURE__ */ new Map();
|
|
75
155
|
if (chars.length < 2) return kerningMap;
|
|
76
156
|
const canvas = document.createElement("canvas");
|
|
77
157
|
const ctx = canvas.getContext("2d");
|
|
78
158
|
if (!ctx) return kerningMap;
|
|
79
|
-
const
|
|
80
|
-
ctx
|
|
81
|
-
if (styles.letterSpacing && styles.letterSpacing !== "normal") {
|
|
82
|
-
ctx.letterSpacing = styles.letterSpacing;
|
|
83
|
-
}
|
|
84
|
-
if (styles.wordSpacing && styles.wordSpacing !== "normal") {
|
|
85
|
-
ctx.wordSpacing = styles.wordSpacing;
|
|
86
|
-
}
|
|
87
|
-
if ("fontVariantLigatures" in ctx) ctx.fontVariantLigatures = "none";
|
|
159
|
+
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
160
|
+
applyKerningStylesToCanvas(ctx, computedStyles);
|
|
88
161
|
const charWidths = /* @__PURE__ */ new Map();
|
|
89
162
|
for (const char of new Set(chars)) {
|
|
90
163
|
charWidths.set(char, ctx.measureText(char).width);
|
|
@@ -100,7 +173,7 @@ function measureKerningCanvas(element, chars) {
|
|
|
100
173
|
}
|
|
101
174
|
return kerningMap;
|
|
102
175
|
}
|
|
103
|
-
function measureKerningDOM(
|
|
176
|
+
function measureKerningDOM(container, styleSource, chars, styles) {
|
|
104
177
|
const kerningMap = /* @__PURE__ */ new Map();
|
|
105
178
|
if (chars.length < 2) return kerningMap;
|
|
106
179
|
const measurer = document.createElement("span");
|
|
@@ -109,21 +182,17 @@ function measureKerningDOM(element, chars) {
|
|
|
109
182
|
visibility: hidden;
|
|
110
183
|
white-space: pre;
|
|
111
184
|
`;
|
|
112
|
-
const
|
|
113
|
-
measurer
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
measurer.style.fontKerning = styles.fontKerning;
|
|
117
|
-
measurer.style.fontVariantLigatures = "none";
|
|
118
|
-
const webkitSmoothing = styles.webkitFontSmoothing || styles["-webkit-font-smoothing"];
|
|
119
|
-
const mozSmoothing = styles.MozOsxFontSmoothing || styles["-moz-osx-font-smoothing"];
|
|
185
|
+
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
186
|
+
copyKerningStyles(measurer, computedStyles);
|
|
187
|
+
const webkitSmoothing = computedStyles.webkitFontSmoothing || computedStyles["-webkit-font-smoothing"];
|
|
188
|
+
const mozSmoothing = computedStyles.MozOsxFontSmoothing || computedStyles["-moz-osx-font-smoothing"];
|
|
120
189
|
if (webkitSmoothing) {
|
|
121
190
|
measurer.style.webkitFontSmoothing = webkitSmoothing;
|
|
122
191
|
}
|
|
123
192
|
if (mozSmoothing) {
|
|
124
193
|
measurer.style.MozOsxFontSmoothing = mozSmoothing;
|
|
125
194
|
}
|
|
126
|
-
|
|
195
|
+
container.appendChild(measurer);
|
|
127
196
|
const charWidths = /* @__PURE__ */ new Map();
|
|
128
197
|
for (const char of new Set(chars)) {
|
|
129
198
|
measurer.textContent = char;
|
|
@@ -139,12 +208,13 @@ function measureKerningDOM(element, chars) {
|
|
|
139
208
|
kerningMap.set(i + 1, kerning);
|
|
140
209
|
}
|
|
141
210
|
}
|
|
142
|
-
|
|
211
|
+
container.removeChild(measurer);
|
|
143
212
|
return kerningMap;
|
|
144
213
|
}
|
|
145
|
-
function measureKerning(
|
|
214
|
+
function measureKerning(container, styleSource, chars, styles) {
|
|
146
215
|
if (chars.length < 2) return /* @__PURE__ */ new Map();
|
|
147
|
-
|
|
216
|
+
const computedStyles = styles != null ? styles : getComputedStyle(styleSource);
|
|
217
|
+
return isSafari() || shouldUseDomKerning(computedStyles) ? measureKerningDOM(container, styleSource, chars, computedStyles) : measureKerningCanvas(styleSource, chars, computedStyles);
|
|
148
218
|
}
|
|
149
219
|
var srOnlyStylesInjected = false;
|
|
150
220
|
function injectSrOnlyStyles() {
|
|
@@ -407,7 +477,6 @@ function performSplit(element, measuredWords, charClass, wordClass, lineClass, s
|
|
|
407
477
|
}
|
|
408
478
|
charGroups.forEach((group) => {
|
|
409
479
|
group.chars.forEach((measuredChar) => {
|
|
410
|
-
measuredWord.chars.indexOf(measuredChar);
|
|
411
480
|
const charSpan = createSpan(charClass, globalCharIndex, "inline-block", {
|
|
412
481
|
propIndex: options == null ? void 0 : options.propIndex,
|
|
413
482
|
propName: "char"
|
|
@@ -514,13 +583,37 @@ function performSplit(element, measuredWords, charClass, wordClass, lineClass, s
|
|
|
514
583
|
for (const wordSpan of allWords) {
|
|
515
584
|
const wordChars = Array.from(wordSpan.querySelectorAll(`.${charClass}`));
|
|
516
585
|
if (wordChars.length < 2) continue;
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
586
|
+
const styleGroups = [];
|
|
587
|
+
const firstCharStyles = getComputedStyle(wordChars[0]);
|
|
588
|
+
let currentKey = buildKerningStyleKey(firstCharStyles);
|
|
589
|
+
let currentGroup = {
|
|
590
|
+
chars: [wordChars[0]],
|
|
591
|
+
styleSource: wordChars[0],
|
|
592
|
+
styles: firstCharStyles
|
|
593
|
+
};
|
|
594
|
+
for (let i2 = 1; i2 < wordChars.length; i2++) {
|
|
595
|
+
const char = wordChars[i2];
|
|
596
|
+
const charStyles = getComputedStyle(char);
|
|
597
|
+
const key = buildKerningStyleKey(charStyles);
|
|
598
|
+
if (key === currentKey) {
|
|
599
|
+
currentGroup.chars.push(char);
|
|
600
|
+
} else {
|
|
601
|
+
styleGroups.push(currentGroup);
|
|
602
|
+
currentKey = key;
|
|
603
|
+
currentGroup = { chars: [char], styleSource: char, styles: charStyles };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
styleGroups.push(currentGroup);
|
|
607
|
+
for (const group of styleGroups) {
|
|
608
|
+
if (group.chars.length < 2) continue;
|
|
609
|
+
const charStrings = group.chars.map((c) => c.textContent || "");
|
|
610
|
+
const kerningMap = measureKerning(element, group.styleSource, charStrings, group.styles);
|
|
611
|
+
for (const [charIndex, kerning] of kerningMap) {
|
|
612
|
+
const charSpan = group.chars[charIndex];
|
|
613
|
+
if (charSpan && Math.abs(kerning) < 20) {
|
|
614
|
+
const targetElement = (options == null ? void 0 : options.mask) === "chars" && charSpan.parentElement ? charSpan.parentElement : charSpan;
|
|
615
|
+
targetElement.style.marginLeft = `${kerning}px`;
|
|
616
|
+
}
|
|
524
617
|
}
|
|
525
618
|
}
|
|
526
619
|
}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { splitText } from './chunk-
|
|
1
|
+
export { splitText } from './chunk-Q2D5AQBW.js';
|
package/dist/react.d.ts
CHANGED
|
@@ -43,6 +43,12 @@ type CallbackReturn = void | {
|
|
|
43
43
|
}> | Promise<unknown>;
|
|
44
44
|
interface SplitTextProps {
|
|
45
45
|
children: ReactElement;
|
|
46
|
+
/** The wrapper element type. Default: "div" */
|
|
47
|
+
as?: keyof React.JSX.IntrinsicElements;
|
|
48
|
+
/** Class name for the wrapper element */
|
|
49
|
+
className?: string;
|
|
50
|
+
/** Additional styles for the wrapper element (merged with internal styles) */
|
|
51
|
+
style?: React.CSSProperties;
|
|
46
52
|
/**
|
|
47
53
|
* Called after text is split.
|
|
48
54
|
* Return an animation or promise to enable revert (requires revertOnComplete).
|
|
@@ -115,6 +121,6 @@ interface SplitTextProps {
|
|
|
115
121
|
* </SplitText>
|
|
116
122
|
* ```
|
|
117
123
|
*/
|
|
118
|
-
declare const SplitText: react.ForwardRefExoticComponent<SplitTextProps & react.RefAttributes<
|
|
124
|
+
declare const SplitText: react.ForwardRefExoticComponent<SplitTextProps & react.RefAttributes<HTMLElement>>;
|
|
119
125
|
|
|
120
126
|
export { SplitText, type SplitTextElements };
|
package/dist/react.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { splitText, __spreadProps, __spreadValues, normalizeToPromise } from './chunk-
|
|
1
|
+
import { splitText, __spreadProps, __spreadValues, normalizeToPromise } from './chunk-Q2D5AQBW.js';
|
|
2
2
|
import { forwardRef, useRef, useCallback, useState, useLayoutEffect, useEffect, isValidElement, cloneElement } from 'react';
|
|
3
3
|
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
5
|
var SplitText = forwardRef(
|
|
6
6
|
function SplitText2({
|
|
7
7
|
children,
|
|
8
|
+
as: Component = "div",
|
|
9
|
+
className,
|
|
10
|
+
style: userStyle,
|
|
8
11
|
onSplit,
|
|
9
12
|
onResize,
|
|
10
13
|
options,
|
|
@@ -167,11 +170,13 @@ var SplitText = forwardRef(
|
|
|
167
170
|
const clonedChild = cloneElement(children, {
|
|
168
171
|
ref: childRefCallback
|
|
169
172
|
});
|
|
173
|
+
const Wrapper = Component;
|
|
170
174
|
return /* @__PURE__ */ jsx(
|
|
171
|
-
|
|
175
|
+
Wrapper,
|
|
172
176
|
{
|
|
173
177
|
ref: mergedRef,
|
|
174
|
-
|
|
178
|
+
className,
|
|
179
|
+
style: __spreadValues({ visibility: "hidden", position: "relative" }, userStyle),
|
|
175
180
|
children: clonedChild
|
|
176
181
|
}
|
|
177
182
|
);
|