fetta 1.4.4 → 1.5.1

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.
@@ -0,0 +1,46 @@
1
+ import { S as SplitTextResult } from './index-c1UKfWWK.js';
2
+
3
+ type SplitUnit = "chars" | "words" | "lines";
4
+ type StyleInput = Partial<CSSStyleDeclaration> | ((ctx: {
5
+ index: number;
6
+ unit: SplitUnit;
7
+ original: HTMLSpanElement;
8
+ }) => Partial<CSSStyleDeclaration>);
9
+ type ClassInput = string | ((ctx: {
10
+ index: number;
11
+ unit: SplitUnit;
12
+ original: HTMLSpanElement;
13
+ }) => string | undefined);
14
+ interface CreateSplitClonesOptions {
15
+ unit: SplitUnit;
16
+ wrap?: boolean;
17
+ display?: "auto" | "inline-block" | "block";
18
+ cloneOffset?: {
19
+ axis?: "x" | "y";
20
+ direction?: "start" | "end";
21
+ distance?: string;
22
+ };
23
+ trackClassName?: ClassInput;
24
+ cloneClassName?: ClassInput;
25
+ trackStyle?: StyleInput;
26
+ cloneStyle?: StyleInput;
27
+ }
28
+ interface SplitCloneItem {
29
+ index: number;
30
+ original: HTMLSpanElement;
31
+ clone: HTMLSpanElement;
32
+ track: HTMLSpanElement | null;
33
+ }
34
+ interface CreateSplitClonesResult {
35
+ unit: SplitUnit;
36
+ originals: HTMLSpanElement[];
37
+ clones: HTMLSpanElement[];
38
+ tracks: HTMLSpanElement[];
39
+ items: SplitCloneItem[];
40
+ cleanup: (options?: {
41
+ revertSplit?: boolean;
42
+ }) => void;
43
+ }
44
+ declare function createSplitClones(split: SplitTextResult, options: CreateSplitClonesOptions): CreateSplitClonesResult;
45
+
46
+ export { type ClassInput, type CreateSplitClonesOptions, type CreateSplitClonesResult, type SplitCloneItem, type SplitUnit, type StyleInput, createSplitClones };
@@ -0,0 +1,121 @@
1
+ import './chunk-ORMEWXMH.js';
2
+
3
+ // src/helpers/createSplitClones.ts
4
+ function resolveDisplay(display, unit) {
5
+ if (display && display !== "auto") return display;
6
+ return unit === "lines" ? "block" : "inline-block";
7
+ }
8
+ function applyClass(element, classInput, ctx) {
9
+ if (!classInput) return;
10
+ const className = typeof classInput === "function" ? classInput(ctx) : classInput;
11
+ if (!className) return;
12
+ const classes = className.split(/\s+/).filter(Boolean);
13
+ if (classes.length > 0) {
14
+ element.classList.add(...classes);
15
+ }
16
+ }
17
+ function applyStyle(element, styleInput, ctx) {
18
+ if (!styleInput) return;
19
+ const styles = typeof styleInput === "function" ? styleInput(ctx) : styleInput;
20
+ for (const [key, value] of Object.entries(styles)) {
21
+ if (value !== void 0 && value !== null) {
22
+ element.style[key] = value;
23
+ }
24
+ }
25
+ }
26
+ function normalizeOffset(direction, distance) {
27
+ const trimmed = distance.trim();
28
+ if (direction === "start") {
29
+ return trimmed.startsWith("-") ? trimmed : `-${trimmed}`;
30
+ }
31
+ return trimmed.startsWith("-") ? trimmed.slice(1) : trimmed;
32
+ }
33
+ function applyCloneOffset(clone, cloneOffset) {
34
+ var _a, _b, _c;
35
+ const axis = (_a = cloneOffset == null ? void 0 : cloneOffset.axis) != null ? _a : "y";
36
+ const direction = (_b = cloneOffset == null ? void 0 : cloneOffset.direction) != null ? _b : "start";
37
+ const distance = (_c = cloneOffset == null ? void 0 : cloneOffset.distance) != null ? _c : "100%";
38
+ const offset = normalizeOffset(direction, distance);
39
+ clone.style.position = "absolute";
40
+ if (axis === "y") {
41
+ clone.style.left = "0";
42
+ clone.style.top = offset;
43
+ } else {
44
+ clone.style.top = "0";
45
+ clone.style.left = offset;
46
+ }
47
+ }
48
+ function resolveOriginals(split, unit) {
49
+ if (unit === "chars") return split.chars;
50
+ if (unit === "words") return split.words;
51
+ if (unit === "lines") return split.lines;
52
+ throw new Error(`createSplitClones: unsupported unit "${unit}"`);
53
+ }
54
+ function createSplitClones(split, options) {
55
+ var _a;
56
+ const unit = options.unit;
57
+ const wrap = (_a = options.wrap) != null ? _a : false;
58
+ const originals = resolveOriginals(split, unit);
59
+ const clones = [];
60
+ const tracks = [];
61
+ const items = [];
62
+ let didCleanup = false;
63
+ originals.forEach((original, index) => {
64
+ const parent = original.parentElement;
65
+ if (!parent) return;
66
+ const ctx = { index, unit, original };
67
+ let track = null;
68
+ if (wrap) {
69
+ track = document.createElement("span");
70
+ track.style.position = "relative";
71
+ track.style.display = resolveDisplay(options.display, unit);
72
+ applyClass(track, options.trackClassName, ctx);
73
+ applyStyle(track, options.trackStyle, ctx);
74
+ parent.insertBefore(track, original);
75
+ track.appendChild(original);
76
+ tracks.push(track);
77
+ }
78
+ const clone = original.cloneNode(true);
79
+ applyCloneOffset(clone, options.cloneOffset);
80
+ applyClass(clone, options.cloneClassName, ctx);
81
+ applyStyle(clone, options.cloneStyle, ctx);
82
+ const host = original.parentElement;
83
+ if (!host) return;
84
+ host.appendChild(clone);
85
+ clones.push(clone);
86
+ items.push({
87
+ index,
88
+ original,
89
+ clone,
90
+ track
91
+ });
92
+ });
93
+ const cleanup = (cleanupOptions) => {
94
+ if (didCleanup) return;
95
+ didCleanup = true;
96
+ for (const item of items) {
97
+ item.clone.remove();
98
+ }
99
+ for (const item of items) {
100
+ if (!item.track) continue;
101
+ const trackParent = item.track.parentNode;
102
+ if (trackParent) {
103
+ trackParent.insertBefore(item.original, item.track);
104
+ }
105
+ item.track.remove();
106
+ }
107
+ if (cleanupOptions == null ? void 0 : cleanupOptions.revertSplit) {
108
+ split.revert();
109
+ }
110
+ };
111
+ return {
112
+ unit,
113
+ originals,
114
+ clones,
115
+ tracks,
116
+ items,
117
+ cleanup
118
+ };
119
+ }
120
+
121
+ export { createSplitClones };
@@ -0,0 +1,144 @@
1
+ /** Animation object shape used by Motion's `animate` return value. */
2
+ type FinishedAnimation = {
3
+ finished: Promise<unknown>;
4
+ };
5
+ /** Generic thenable animation object (e.g. GSAP Tween/Timeline). */
6
+ type ThenableAnimation = {
7
+ then: (onFulfilled?: ((result: unknown) => unknown) | undefined) => unknown;
8
+ };
9
+ type AnimationCallbackValue = FinishedAnimation | ThenableAnimation | Promise<unknown>;
10
+ /** Callback return type accepted by revertOnComplete normalization. */
11
+ type AnimationCallbackReturn = void | AnimationCallbackValue | AnimationCallbackReturn[];
12
+ /**
13
+ * Configuration options for the splitText function.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const options: SplitTextOptions = {
18
+ * type: "chars,words,lines",
19
+ * charClass: "char",
20
+ * mask: "lines",
21
+ * autoSplit: true,
22
+ * };
23
+ * ```
24
+ */
25
+ interface SplitTextOptions {
26
+ /** Split type: chars, words, lines, or combinations like "chars,words" */
27
+ type?: "chars" | "words" | "lines" | "chars,words" | "words,lines" | "chars,lines" | "chars,words,lines";
28
+ charClass?: string;
29
+ wordClass?: string;
30
+ lineClass?: string;
31
+ /** Apply overflow mask wrapper to elements for reveal animations */
32
+ mask?: "lines" | "words" | "chars";
33
+ /** Auto-split on resize (observes parent element) */
34
+ autoSplit?: boolean;
35
+ /** Callback when autoSplit/full-resplit replaces split output elements */
36
+ onResplit?: (result: Omit<SplitTextResult, "revert" | "dispose">) => void;
37
+ /** Callback fired after text is split, receives split elements. Return animation for revertOnComplete. */
38
+ onSplit?: (result: {
39
+ chars: HTMLSpanElement[];
40
+ words: HTMLSpanElement[];
41
+ lines: HTMLSpanElement[];
42
+ }) => AnimationCallbackReturn;
43
+ /** Auto-revert when onSplit animation completes */
44
+ revertOnComplete?: boolean;
45
+ /** Add CSS custom properties (--char-index, --word-index, --line-index) */
46
+ propIndex?: boolean;
47
+ /** Skip kerning compensation (no margin adjustments applied).
48
+ * Kerning is naturally lost when splitting into inline-block spans.
49
+ * Use this if you prefer no compensation over imperfect Safari compensation. */
50
+ disableKerning?: boolean;
51
+ /** Apply initial inline styles to elements after split (and after kerning compensation).
52
+ * Can be a static style object or a function that receives (element, index). */
53
+ initialStyles?: {
54
+ chars?: InitialStyle;
55
+ words?: InitialStyle;
56
+ lines?: InitialStyle;
57
+ };
58
+ /** Apply initial classes to elements after split (and after kerning compensation).
59
+ * Classes are added via classList.add() and support space-separated class names. */
60
+ initialClasses?: {
61
+ chars?: string;
62
+ words?: string;
63
+ lines?: string;
64
+ };
65
+ }
66
+ type CSSVariableStyles = {
67
+ [K in `--${string}`]?: string | number;
68
+ };
69
+ /** Style value for initialStyles - CSS-like properties with numeric value support */
70
+ type InitialStyleValue = {
71
+ [property: string]: string | number | undefined;
72
+ } & CSSVariableStyles;
73
+ /** Function that returns styles based on element and index */
74
+ type InitialStyleFn = (element: HTMLElement, index: number) => InitialStyleValue;
75
+ /** Initial style can be a static object or a function */
76
+ type InitialStyle = InitialStyleValue | InitialStyleFn;
77
+ /**
78
+ * Result returned by splitText containing arrays of split elements and a revert function.
79
+ *
80
+ * Each array contains the created span elements. Empty arrays are returned for
81
+ * split types not requested (e.g., if `type: "words"`, chars and lines will be empty).
82
+ */
83
+ interface SplitTextResult {
84
+ /** Array of character span elements (empty if chars not in type) */
85
+ chars: HTMLSpanElement[];
86
+ /** Array of word span elements (empty if words not in type) */
87
+ words: HTMLSpanElement[];
88
+ /** Array of line span elements (empty if lines not in type) */
89
+ lines: HTMLSpanElement[];
90
+ /** Revert the element to its original HTML and cleanup all observers/timers */
91
+ revert: () => void;
92
+ }
93
+ /**
94
+ * Split text into characters, words, and lines with kerning compensation.
95
+ *
96
+ * Fetta measures character positions before splitting, then applies margin adjustments
97
+ * after splitting to preserve the original kerning (letter spacing). This prevents
98
+ * the visual "jumping" that occurs with naive text splitting.
99
+ *
100
+ * @param element - The HTML element containing text to split. Must have text content.
101
+ * @param options - Configuration options for splitting behavior
102
+ * @returns Object containing arrays of split elements and a revert function
103
+ *
104
+ * @throws {Error} If element is not an HTMLElement
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * import { splitText } from "fetta";
109
+ * import { animate, stagger } from "motion";
110
+ *
111
+ * // Basic usage
112
+ * const { chars, words, lines, revert } = splitText(element);
113
+ *
114
+ * // Animate words
115
+ * animate(words, { opacity: [0, 1], y: [20, 0] }, { delay: stagger(0.05) });
116
+ *
117
+ * // Revert to original HTML when done
118
+ * revert();
119
+ * ```
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Auto-revert after animation completes
124
+ * splitText(element, {
125
+ * onSplit: ({ words }) => animate(words, { opacity: [0, 1] }),
126
+ * revertOnComplete: true,
127
+ * });
128
+ * ```
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // Responsive re-splitting
133
+ * splitText(element, {
134
+ * autoSplit: true,
135
+ * onResplit: ({ lines }) => {
136
+ * // Re-animate after resize
137
+ * animate(lines, { opacity: [0, 1] });
138
+ * },
139
+ * });
140
+ * ```
141
+ */
142
+ declare function splitText(element: HTMLElement, rawOptions?: SplitTextOptions): SplitTextResult;
143
+
144
+ export { type AnimationCallbackReturn as A, type SplitTextResult as S, type SplitTextOptions as a, splitText as s };
package/dist/index.d.ts CHANGED
@@ -1,137 +1 @@
1
- /**
2
- * Custom splitText implementation with built-in kerning compensation.
3
- * Measures kerning between character pairs, splits text into spans,
4
- * applies margin compensation, and detects lines based on rendered positions.
5
- */
6
- /**
7
- * Configuration options for the splitText function.
8
- *
9
- * @example
10
- * ```typescript
11
- * const options: SplitTextOptions = {
12
- * type: "chars,words,lines",
13
- * charClass: "char",
14
- * mask: "lines",
15
- * autoSplit: true,
16
- * };
17
- * ```
18
- */
19
- interface SplitTextOptions {
20
- /** Split type: chars, words, lines, or combinations like "chars,words" */
21
- type?: "chars" | "words" | "lines" | "chars,words" | "words,lines" | "chars,lines" | "chars,words,lines";
22
- charClass?: string;
23
- wordClass?: string;
24
- lineClass?: string;
25
- /** Apply overflow mask wrapper to elements for reveal animations */
26
- mask?: "lines" | "words" | "chars";
27
- /** Auto-split on resize (observes parent element) */
28
- autoSplit?: boolean;
29
- /** Callback when resize triggers re-split (does not re-trigger initial animations) */
30
- onResize?: (result: Omit<SplitTextResult, "revert" | "dispose">) => void;
31
- /** Callback fired after text is split, receives split elements. Return animation for revertOnComplete. */
32
- onSplit?: (result: {
33
- chars: HTMLSpanElement[];
34
- words: HTMLSpanElement[];
35
- lines: HTMLSpanElement[];
36
- }) => void | {
37
- finished: Promise<unknown>;
38
- } | Array<{
39
- finished: Promise<unknown>;
40
- }> | Promise<unknown>;
41
- /** Auto-revert when onSplit animation completes */
42
- revertOnComplete?: boolean;
43
- /** Add CSS custom properties (--char-index, --word-index, --line-index) */
44
- propIndex?: boolean;
45
- /** Skip kerning compensation (no margin adjustments applied).
46
- * Kerning is naturally lost when splitting into inline-block spans.
47
- * Use this if you prefer no compensation over imperfect Safari compensation. */
48
- disableKerning?: boolean;
49
- /** Apply initial inline styles to elements after split (and after kerning compensation).
50
- * Can be a static style object or a function that receives (element, index). */
51
- initialStyles?: {
52
- chars?: InitialStyle;
53
- words?: InitialStyle;
54
- lines?: InitialStyle;
55
- };
56
- /** Apply initial classes to elements after split (and after kerning compensation).
57
- * Classes are added via classList.add() and support space-separated class names. */
58
- initialClasses?: {
59
- chars?: string;
60
- words?: string;
61
- lines?: string;
62
- };
63
- }
64
- /** Style value for initialStyles - a partial CSSStyleDeclaration object */
65
- type InitialStyleValue = Partial<CSSStyleDeclaration>;
66
- /** Function that returns styles based on element and index */
67
- type InitialStyleFn = (element: HTMLElement, index: number) => InitialStyleValue;
68
- /** Initial style can be a static object or a function */
69
- type InitialStyle = InitialStyleValue | InitialStyleFn;
70
- /**
71
- * Result returned by splitText containing arrays of split elements and a revert function.
72
- *
73
- * Each array contains the created span elements. Empty arrays are returned for
74
- * split types not requested (e.g., if `type: "words"`, chars and lines will be empty).
75
- */
76
- interface SplitTextResult {
77
- /** Array of character span elements (empty if chars not in type) */
78
- chars: HTMLSpanElement[];
79
- /** Array of word span elements (empty if words not in type) */
80
- words: HTMLSpanElement[];
81
- /** Array of line span elements (empty if lines not in type) */
82
- lines: HTMLSpanElement[];
83
- /** Revert the element to its original HTML and cleanup all observers/timers */
84
- revert: () => void;
85
- }
86
- /**
87
- * Split text into characters, words, and lines with kerning compensation.
88
- *
89
- * Fetta measures character positions before splitting, then applies margin adjustments
90
- * after splitting to preserve the original kerning (letter spacing). This prevents
91
- * the visual "jumping" that occurs with naive text splitting.
92
- *
93
- * @param element - The HTML element containing text to split. Must have text content.
94
- * @param options - Configuration options for splitting behavior
95
- * @returns Object containing arrays of split elements and a revert function
96
- *
97
- * @throws {Error} If element is not an HTMLElement
98
- *
99
- * @example
100
- * ```typescript
101
- * import { splitText } from "fetta";
102
- * import { animate, stagger } from "motion";
103
- *
104
- * // Basic usage
105
- * const { chars, words, lines, revert } = splitText(element);
106
- *
107
- * // Animate words
108
- * animate(words, { opacity: [0, 1], y: [20, 0] }, { delay: stagger(0.05) });
109
- *
110
- * // Revert to original HTML when done
111
- * revert();
112
- * ```
113
- *
114
- * @example
115
- * ```typescript
116
- * // Auto-revert after animation completes
117
- * splitText(element, {
118
- * onSplit: ({ words }) => animate(words, { opacity: [0, 1] }),
119
- * revertOnComplete: true,
120
- * });
121
- * ```
122
- *
123
- * @example
124
- * ```typescript
125
- * // Responsive re-splitting
126
- * splitText(element, {
127
- * autoSplit: true,
128
- * onResize: ({ lines }) => {
129
- * // Re-animate after resize
130
- * animate(lines, { opacity: [0, 1] });
131
- * },
132
- * });
133
- * ```
134
- */
135
- declare function splitText(element: HTMLElement, { type, charClass, wordClass, lineClass, mask, autoSplit, onResize, onSplit, revertOnComplete, propIndex, disableKerning, initialStyles, initialClasses, }?: SplitTextOptions): SplitTextResult;
136
-
137
- export { type SplitTextOptions, type SplitTextResult, splitText };
1
+ export { a as SplitTextOptions, S as SplitTextResult, s as splitText } from './index-c1UKfWWK.js';
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- export { splitText } from './chunk-Y4GCLM4K.js';
1
+ export { splitText } from './chunk-UPF3IYHC.js';
2
+ import './chunk-ORMEWXMH.js';
@@ -0,0 +1,23 @@
1
+ type CSSVariableStyles = {
2
+ [K in `--${string}`]?: string | number;
3
+ };
4
+ /** Style value for initialStyles - CSS properties with numeric + CSS variable support */
5
+ type InitialStyleValue = Partial<Record<keyof CSSStyleDeclaration, string | number>> & CSSVariableStyles;
6
+ /** Function that returns styles based on element and index */
7
+ type InitialStyleFn = (element: HTMLElement, index: number) => InitialStyleValue;
8
+ /** Initial style can be a static object or a function */
9
+ type InitialStyle = InitialStyleValue | InitialStyleFn;
10
+ /** Initial styles configuration for chars, words, and/or lines */
11
+ interface InitialStyles {
12
+ chars?: InitialStyle;
13
+ words?: InitialStyle;
14
+ lines?: InitialStyle;
15
+ }
16
+ /** Initial classes configuration for chars, words, and/or lines */
17
+ interface InitialClasses {
18
+ chars?: string;
19
+ words?: string;
20
+ lines?: string;
21
+ }
22
+
23
+ export type { InitialStyles as I, InitialClasses as a };
@@ -0,0 +1,185 @@
1
+ import { I as InitialStyles, a as InitialClasses } from './initialStyles-BGuPp5CS.js';
2
+ import { DOMKeyframesDefinition, AnimationOptions, scroll } from 'motion';
3
+ import { HTMLMotionProps } from 'motion/react';
4
+ import { ReactElement, RefAttributes } from 'react';
5
+ import { A as AnimationCallbackReturn } from './index-c1UKfWWK.js';
6
+ export { a as CoreSplitTextOptions, S as SplitTextResult } from './index-c1UKfWWK.js';
7
+
8
+ interface SplitTextOptions {
9
+ type?: "chars" | "words" | "lines" | "chars,words" | "words,lines" | "chars,lines" | "chars,words,lines";
10
+ charClass?: string;
11
+ wordClass?: string;
12
+ lineClass?: string;
13
+ /** Apply overflow mask wrapper to elements for reveal animations */
14
+ mask?: "lines" | "words" | "chars";
15
+ propIndex?: boolean;
16
+ /** Skip kerning compensation (no margin adjustments applied).
17
+ * Kerning is naturally lost when splitting into inline-block spans.
18
+ * Use this if you prefer no compensation over imperfect Safari compensation. */
19
+ disableKerning?: boolean;
20
+ }
21
+ interface ScrollPropOptions {
22
+ /** Scroll offsets. Default: Motion's default ["start end", "end start"] */
23
+ offset?: MotionScrollOffset;
24
+ /** Scroll axis. Default: "y" */
25
+ axis?: "x" | "y";
26
+ /** Custom scroll container ref. Default: nearest scrollable ancestor / window */
27
+ container?: React.RefObject<Element | null>;
28
+ }
29
+ /** Matches Motion's viewport prop */
30
+ interface ViewportOptions {
31
+ /** Only trigger once. Default: false */
32
+ once?: boolean;
33
+ /** How much of the element must be visible. Motion supports "some" | "all" | number. Default: 0 */
34
+ amount?: number | "some" | "all";
35
+ /** How much visibility is required to consider the element out of view. Default: 0 (fully out) */
36
+ leave?: number | "some" | "all";
37
+ /** Root margin for IntersectionObserver. Default: "0px" */
38
+ margin?: string;
39
+ /** Root element for IntersectionObserver */
40
+ root?: React.RefObject<Element>;
41
+ }
42
+ /**
43
+ * Result passed to SplitText callbacks (onSplit, onViewportEnter, onViewportLeave, onResplit).
44
+ *
45
+ * Contains arrays of split elements and a revert function for manual control.
46
+ * Empty arrays are returned for split types not requested in options.
47
+ */
48
+ interface SplitTextElements {
49
+ /** Array of character span elements */
50
+ chars: HTMLSpanElement[];
51
+ /** Array of word span elements */
52
+ words: HTMLSpanElement[];
53
+ /** Array of line span elements */
54
+ lines: HTMLSpanElement[];
55
+ /** Revert to original HTML and cleanup observers */
56
+ revert: () => void;
57
+ }
58
+ /** Motion-compatible animation target (passed directly to motion variants) */
59
+ type VariantTarget = DOMKeyframesDefinition & {
60
+ transition?: AnimationOptions;
61
+ };
62
+ /** Info passed to function variant callbacks */
63
+ interface VariantInfo<TCustom = unknown> {
64
+ /** Relative index within nearest split parent (line > word > global) */
65
+ index: number;
66
+ /** Total elements in that parent group */
67
+ count: number;
68
+ /** Absolute index across all elements of this type */
69
+ globalIndex: number;
70
+ /** Total elements of this type across the entire split */
71
+ globalCount: number;
72
+ /** Parent line index (0 if lines not split) */
73
+ lineIndex: number;
74
+ /** Parent word index (0 if words not split) */
75
+ wordIndex: number;
76
+ /** User custom data passed to SplitText */
77
+ custom: TCustom | undefined;
78
+ /** AnimatePresence presence state */
79
+ isPresent: boolean;
80
+ }
81
+ type VariantResolver<TCustom = unknown> = (info: VariantInfo<TCustom>) => VariantTarget;
82
+ type WrapperVariantResolver<TCustom = unknown> = (args: {
83
+ custom?: TCustom;
84
+ }) => VariantTarget;
85
+ type PerTypeVariant<TCustom = unknown> = VariantTarget | VariantResolver<TCustom>;
86
+ type WrapperVariant<TCustom = unknown> = VariantTarget | WrapperVariantResolver<TCustom>;
87
+ /** A variant: flat target, flat function, per-type targets (static or function), with optional transition */
88
+ type VariantDefinition<TCustom = unknown> = VariantTarget | VariantResolver<TCustom> | {
89
+ chars?: PerTypeVariant<TCustom>;
90
+ words?: PerTypeVariant<TCustom>;
91
+ lines?: PerTypeVariant<TCustom>;
92
+ wrapper?: WrapperVariant<TCustom>;
93
+ transition?: AnimationOptions;
94
+ };
95
+ type DelayScope = "global" | "local";
96
+ type MotionScrollOptions = NonNullable<Parameters<typeof scroll>[1]>;
97
+ type MotionScrollOffset = MotionScrollOptions["offset"];
98
+ type ControlledWrapperMotionKeys = "children" | "className" | "style" | "ref" | "variants" | "initial" | "animate" | "exit" | "whileInView" | "whileHover" | "whileTap" | "whileFocus" | "transition" | "custom" | "onViewportEnter" | "onViewportLeave" | "onRevert" | "onHoverStart" | "onHoverEnd";
99
+ type WrapperMotionProps = Omit<HTMLMotionProps<"div">, ControlledWrapperMotionKeys>;
100
+ interface SplitTextProps<TCustom = unknown> extends WrapperMotionProps {
101
+ children: ReactElement;
102
+ /** The wrapper element type. Default: "div" */
103
+ as?: keyof HTMLElementTagNameMap;
104
+ /** Class name for the wrapper element */
105
+ className?: string;
106
+ /** Additional styles for the wrapper element (merged with internal styles) */
107
+ style?: React.CSSProperties;
108
+ /**
109
+ * Called after text is split.
110
+ * Return an animation or promise to enable revert (requires revertOnComplete).
111
+ * Still fires in variant mode for side effects.
112
+ */
113
+ onSplit?: (result: SplitTextElements) => AnimationCallbackReturn;
114
+ /** Called when autoSplit/full-resplit replaces split output elements */
115
+ onResplit?: (result: SplitTextElements) => void;
116
+ options?: SplitTextOptions;
117
+ autoSplit?: boolean;
118
+ /** When true, autoSplit/full-resplit updates replay initial->animate. */
119
+ animateOnResplit?: boolean;
120
+ /** When true, reverts to original HTML after animation promise resolves */
121
+ revertOnComplete?: boolean;
122
+ /** Viewport observer options (replaces `inView`). Configures IntersectionObserver. */
123
+ viewport?: ViewportOptions;
124
+ /** Called when element enters viewport (replaces `onInView`). Return animation for revertOnComplete support */
125
+ onViewportEnter?: (result: SplitTextElements) => AnimationCallbackReturn;
126
+ /** Called when element leaves viewport (replaces `onLeaveView`) */
127
+ onViewportLeave?: (result: SplitTextElements) => AnimationCallbackReturn;
128
+ /** Called when split text is reverted (manual or automatic) */
129
+ onRevert?: () => void;
130
+ /** Apply initial inline styles to elements after split (and after kerning compensation).
131
+ * Can be a static style object or a function that receives (element, index). */
132
+ initialStyles?: InitialStyles;
133
+ /** Apply initial classes to elements after split (and after kerning compensation).
134
+ * Classes are added via classList.add() and support space-separated class names. */
135
+ initialClasses?: InitialClasses;
136
+ /** Re-apply initialStyles/initialClasses (callback mode) or initial variant (variant mode) when element leaves viewport.
137
+ * Useful for scroll-triggered animations that should reset when scrolling away. */
138
+ resetOnViewportLeave?: boolean;
139
+ /** Wait for `document.fonts.ready` before splitting. Disable for immediate split. */
140
+ waitForFonts?: boolean;
141
+ /** Named variant definitions. Keys are variant names, values are animation targets. */
142
+ variants?: Record<string, VariantDefinition<TCustom>>;
143
+ /** Initial variant applied instantly after split (ignores transitions on mount). Set to false to skip. */
144
+ initial?: string | VariantDefinition<TCustom> | false;
145
+ /** Variant to animate to immediately after split */
146
+ animate?: string | VariantDefinition<TCustom>;
147
+ /** Variant to animate to when entering viewport */
148
+ whileInView?: string | VariantDefinition<TCustom>;
149
+ /** Variant to animate to when leaving viewport */
150
+ whileOutOfView?: string | VariantDefinition<TCustom>;
151
+ /** Variant to animate to on exit when used inside AnimatePresence.
152
+ * Accepts a variant name or a full variant definition. */
153
+ exit?: string | VariantDefinition<TCustom> | false;
154
+ /** Variant to scroll-animate to. Animation progress is driven by scroll position.
155
+ * Takes priority over `animate` and `whileInView`. */
156
+ whileScroll?: string | VariantDefinition<TCustom>;
157
+ /** Scroll options for whileScroll. Configures target tracking and scroll range. */
158
+ scroll?: ScrollPropOptions;
159
+ /** Variant to animate to on hover */
160
+ whileHover?: string | VariantDefinition<TCustom>;
161
+ /** Variant to animate to on tap */
162
+ whileTap?: string | VariantDefinition<TCustom>;
163
+ /** Variant to animate to on focus */
164
+ whileFocus?: string | VariantDefinition<TCustom>;
165
+ /** Reduced motion handling (matches MotionConfig reducedMotion) */
166
+ reducedMotion?: "user" | "always" | "never";
167
+ /** Custom data forwarded to function variants and AnimatePresence */
168
+ custom?: TCustom;
169
+ /** Called when hover starts */
170
+ onHoverStart?: () => void;
171
+ /** Called when hover ends */
172
+ onHoverEnd?: () => void;
173
+ /** Global transition options for variant animations.
174
+ * Precedence: per-element fn return > per-variant transition > this global transition. */
175
+ transition?: AnimationOptions;
176
+ /** Controls how delay functions are resolved. "global" uses globalIndex/globalCount, "local" uses index/count. */
177
+ delayScope?: DelayScope;
178
+ }
179
+ /**
180
+ * Motion-enabled SplitText component.
181
+ */
182
+ type SplitTextComponent = <TCustom = unknown>(props: SplitTextProps<TCustom> & RefAttributes<HTMLElement>) => ReactElement | null;
183
+ declare const SplitText: SplitTextComponent;
184
+
185
+ export { SplitText, type SplitTextElements, type SplitTextOptions, type VariantInfo };