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/dist/react.d.ts CHANGED
@@ -1,25 +1,9 @@
1
1
  import * as react from 'react';
2
2
  import { ReactElement } from 'react';
3
- export { SplitTextOptions, SplitTextResult } from './index.js';
3
+ import { A as AnimationCallbackReturn } from './index-c1UKfWWK.js';
4
+ export { a as CoreSplitTextOptions, S as SplitTextResult } from './index-c1UKfWWK.js';
5
+ import { I as InitialStyles, a as InitialClasses } from './initialStyles-BGuPp5CS.js';
4
6
 
5
- /** Style value for initialStyles - a partial CSSStyleDeclaration object */
6
- type InitialStyleValue = Partial<CSSStyleDeclaration>;
7
- /** Function that returns styles based on element and index */
8
- type InitialStyleFn = (element: HTMLElement, index: number) => InitialStyleValue;
9
- /** Initial style can be a static object or a function */
10
- type InitialStyle = InitialStyleValue | InitialStyleFn;
11
- /** Initial styles configuration for chars, words, and/or lines */
12
- interface InitialStyles {
13
- chars?: InitialStyle;
14
- words?: InitialStyle;
15
- lines?: InitialStyle;
16
- }
17
- /** Initial classes configuration for chars, words, and/or lines */
18
- interface InitialClasses {
19
- chars?: string;
20
- words?: string;
21
- lines?: string;
22
- }
23
7
  interface SplitTextOptions {
24
8
  type?: "chars" | "words" | "lines" | "chars,words" | "words,lines" | "chars,lines" | "chars,words,lines";
25
9
  charClass?: string;
@@ -33,16 +17,21 @@ interface SplitTextOptions {
33
17
  * Use this if you prefer no compensation over imperfect Safari compensation. */
34
18
  disableKerning?: boolean;
35
19
  }
36
- interface InViewOptions {
37
- /** How much of the element must be visible (0-1). Default: 0 */
38
- amount?: number;
39
- /** Root margin for IntersectionObserver. Default: "0px" */
40
- margin?: string;
20
+ /** Matches Motion's viewport prop */
21
+ interface ViewportOptions {
41
22
  /** Only trigger once. Default: false */
42
23
  once?: boolean;
24
+ /** How much of the element must be visible. Motion supports "some" | "all" | number. Default: 0 */
25
+ amount?: number | "some" | "all";
26
+ /** How much visibility is required to consider the element out of view. Default: 0 (fully out) */
27
+ leave?: number | "some" | "all";
28
+ /** Root margin for IntersectionObserver. Default: "0px" */
29
+ margin?: string;
30
+ /** Root element for IntersectionObserver */
31
+ root?: React.RefObject<Element>;
43
32
  }
44
33
  /**
45
- * Result passed to SplitText callbacks (onSplit, onInView, onLeaveView, onResize).
34
+ * Result passed to SplitText callbacks (onSplit, onViewportEnter, onViewportLeave, onResplit).
46
35
  *
47
36
  * Contains arrays of split elements and a revert function for manual control.
48
37
  * Empty arrays are returned for split types not requested in options.
@@ -57,16 +46,12 @@ interface SplitTextElements {
57
46
  /** Revert to original HTML and cleanup observers */
58
47
  revert: () => void;
59
48
  }
60
- /** Return type for callbacks - void, single animation, array of animations, or promise */
61
- type CallbackReturn = void | {
62
- finished: Promise<unknown>;
63
- } | Array<{
64
- finished: Promise<unknown>;
65
- }> | Promise<unknown>;
66
- interface SplitTextProps {
49
+ type ControlledWrapperHTMLKeys = "children" | "className" | "style" | "ref" | "as" | "onSplit" | "onResplit" | "options" | "autoSplit" | "revertOnComplete" | "viewport" | "onViewportEnter" | "onViewportLeave" | "onRevert" | "initialStyles" | "initialClasses" | "resetOnViewportLeave" | "waitForFonts";
50
+ type WrapperHTMLProps = Omit<React.HTMLAttributes<HTMLElement>, ControlledWrapperHTMLKeys>;
51
+ interface SplitTextProps extends WrapperHTMLProps {
67
52
  children: ReactElement;
68
53
  /** The wrapper element type. Default: "div" */
69
- as?: keyof React.JSX.IntrinsicElements;
54
+ as?: keyof HTMLElementTagNameMap;
70
55
  /** Class name for the wrapper element */
71
56
  className?: string;
72
57
  /** Additional styles for the wrapper element (merged with internal styles) */
@@ -74,30 +59,33 @@ interface SplitTextProps {
74
59
  /**
75
60
  * Called after text is split.
76
61
  * Return an animation or promise to enable revert (requires revertOnComplete).
77
- * If inView is enabled, this is called immediately but animation typically runs in onInView.
78
62
  */
79
- onSplit?: (result: SplitTextElements) => CallbackReturn;
80
- /** Called when autoSplit triggers a re-split on resize */
81
- onResize?: (result: SplitTextElements) => void;
63
+ onSplit?: (result: SplitTextElements) => AnimationCallbackReturn;
64
+ /** Called when autoSplit/full-resplit replaces split output elements */
65
+ onResplit?: (result: SplitTextElements) => void;
82
66
  options?: SplitTextOptions;
83
67
  autoSplit?: boolean;
84
68
  /** When true, reverts to original HTML after animation promise resolves */
85
69
  revertOnComplete?: boolean;
86
- /** Enable viewport detection. Pass true for defaults or InViewOptions for customization */
87
- inView?: boolean | InViewOptions;
88
- /** Called when element enters viewport. Return animation for revertOnComplete support */
89
- onInView?: (result: SplitTextElements) => CallbackReturn;
90
- /** Called when element leaves viewport */
91
- onLeaveView?: (result: SplitTextElements) => CallbackReturn;
70
+ /** Viewport observer options (replaces `inView`). Configures IntersectionObserver. */
71
+ viewport?: ViewportOptions;
72
+ /** Called when element enters viewport (replaces `onInView`). Return animation for revertOnComplete support */
73
+ onViewportEnter?: (result: SplitTextElements) => AnimationCallbackReturn;
74
+ /** Called when element leaves viewport (replaces `onLeaveView`) */
75
+ onViewportLeave?: (result: SplitTextElements) => AnimationCallbackReturn;
76
+ /** Called when split text is reverted (manual or automatic) */
77
+ onRevert?: () => void;
92
78
  /** Apply initial inline styles to elements after split (and after kerning compensation).
93
79
  * Can be a static style object or a function that receives (element, index). */
94
80
  initialStyles?: InitialStyles;
95
81
  /** Apply initial classes to elements after split (and after kerning compensation).
96
82
  * Classes are added via classList.add() and support space-separated class names. */
97
83
  initialClasses?: InitialClasses;
98
- /** Re-apply initialStyles and initialClasses when element leaves viewport.
84
+ /** Re-apply initialStyles/initialClasses when element leaves viewport.
99
85
  * Useful for scroll-triggered animations that should reset when scrolling away. */
100
- resetOnLeave?: boolean;
86
+ resetOnViewportLeave?: boolean;
87
+ /** Wait for `document.fonts.ready` before splitting. Disable for immediate split. */
88
+ waitForFonts?: boolean;
101
89
  }
102
90
  /**
103
91
  * React component wrapper for text splitting with kerning compensation.
@@ -105,6 +93,8 @@ interface SplitTextProps {
105
93
  * Wraps a single child element and splits its text content into characters,
106
94
  * words, and/or lines. Handles lifecycle cleanup automatically on unmount.
107
95
  *
96
+ * Supports callback mode via `onSplit`, `onViewportEnter`, `onViewportLeave`.
97
+ *
108
98
  * @param props - Component props including callbacks and options
109
99
  * @returns The child element wrapped in a container div
110
100
  *
@@ -113,7 +103,7 @@ interface SplitTextProps {
113
103
  * import { SplitText } from "fetta/react";
114
104
  * import { animate, stagger } from "motion";
115
105
  *
116
- * // Basic animation
106
+ * // Imperative animation
117
107
  * <SplitText
118
108
  * onSplit={({ words }) => {
119
109
  * animate(words, { opacity: [0, 1], y: [20, 0] }, { delay: stagger(0.05) });
@@ -122,36 +112,7 @@ interface SplitTextProps {
122
112
  * <h1>Animated Text</h1>
123
113
  * </SplitText>
124
114
  * ```
125
- *
126
- * @example
127
- * ```tsx
128
- * // Scroll-triggered with auto-revert
129
- * <SplitText
130
- * onSplit={({ chars }) => {
131
- * chars.forEach(c => c.style.opacity = "0");
132
- * }}
133
- * inView={{ amount: 0.5, once: true }}
134
- * onInView={({ chars }) =>
135
- * animate(chars, { opacity: 1 }, { delay: stagger(0.02) })
136
- * }
137
- * revertOnComplete
138
- * >
139
- * <p>Reveals on scroll, reverts after animation</p>
140
- * </SplitText>
141
- * ```
142
- *
143
- * @example
144
- * ```tsx
145
- * // Responsive re-splitting
146
- * <SplitText
147
- * autoSplit
148
- * onSplit={({ lines }) => animate(lines, { opacity: [0, 1] })}
149
- * onResize={({ lines }) => animate(lines, { opacity: [0, 1] })}
150
- * >
151
- * <p>Re-animates when container resizes</p>
152
- * </SplitText>
153
- * ```
154
115
  */
155
116
  declare const SplitText: react.ForwardRefExoticComponent<SplitTextProps & react.RefAttributes<HTMLElement>>;
156
117
 
157
- export { SplitText, type SplitTextElements };
118
+ export { SplitText, type SplitTextElements, type SplitTextOptions };
package/dist/react.js CHANGED
@@ -1,45 +1,47 @@
1
- import { splitText, __spreadProps, __spreadValues, normalizeToPromise } from './chunk-Y4GCLM4K.js';
2
- import { forwardRef, useRef, useCallback, useState, useLayoutEffect, useEffect, isValidElement, cloneElement } from 'react';
3
- import { jsx } from 'react/jsx-runtime';
1
+ import { waitForFontsReady, reapplyInitialStyles, reapplyInitialClasses } from './chunk-FP4I6OR2.js';
2
+ import { splitText, normalizeToPromise } from './chunk-UPF3IYHC.js';
3
+ import { __objRest, __spreadProps, __spreadValues } from './chunk-ORMEWXMH.js';
4
+ import { forwardRef, useRef, useCallback, useState, useLayoutEffect, useEffect, isValidElement, createElement } from 'react';
4
5
 
5
- function reapplyInitialStyles(elements, style) {
6
- if (!style || elements.length === 0) return;
7
- const isFn = typeof style === "function";
8
- for (let i = 0; i < elements.length; i++) {
9
- const el = elements[i];
10
- const styles = isFn ? style(el, i) : style;
11
- for (const [key, value] of Object.entries(styles)) {
12
- if (value !== void 0) {
13
- el.style[key] = value;
14
- }
15
- }
16
- }
17
- }
18
- function reapplyInitialClasses(elements, className) {
19
- if (!className || elements.length === 0) return;
20
- const classes = className.split(/\s+/).filter(Boolean);
21
- for (const el of elements) {
22
- el.classList.add(...classes);
23
- }
24
- }
25
6
  var SplitText = forwardRef(
26
- function SplitText2({
27
- children,
28
- as: Component = "div",
29
- className,
30
- style: userStyle,
31
- onSplit,
32
- onResize,
33
- options,
34
- autoSplit = false,
35
- revertOnComplete = false,
36
- inView,
37
- onInView,
38
- onLeaveView,
39
- initialStyles,
40
- initialClasses,
41
- resetOnLeave = false
42
- }, forwardedRef) {
7
+ function SplitText2(_a, forwardedRef) {
8
+ var _b = _a, {
9
+ children,
10
+ as: Component = "div",
11
+ className,
12
+ style: userStyle,
13
+ onSplit,
14
+ onResplit,
15
+ options,
16
+ autoSplit = false,
17
+ revertOnComplete = false,
18
+ viewport,
19
+ onViewportEnter,
20
+ onViewportLeave,
21
+ onRevert,
22
+ initialStyles,
23
+ initialClasses,
24
+ resetOnViewportLeave = false,
25
+ waitForFonts = true
26
+ } = _b, wrapperProps = __objRest(_b, [
27
+ "children",
28
+ "as",
29
+ "className",
30
+ "style",
31
+ "onSplit",
32
+ "onResplit",
33
+ "options",
34
+ "autoSplit",
35
+ "revertOnComplete",
36
+ "viewport",
37
+ "onViewportEnter",
38
+ "onViewportLeave",
39
+ "onRevert",
40
+ "initialStyles",
41
+ "initialClasses",
42
+ "resetOnViewportLeave",
43
+ "waitForFonts"
44
+ ]);
43
45
  const containerRef = useRef(null);
44
46
  const mergedRef = useCallback(
45
47
  (node) => {
@@ -54,27 +56,30 @@ var SplitText = forwardRef(
54
56
  );
55
57
  const [childElement, setChildElement] = useState(null);
56
58
  const [isInView, setIsInView] = useState(false);
59
+ const needsViewport = !!(onViewportEnter || onViewportLeave || resetOnViewportLeave || viewport);
57
60
  const onSplitRef = useRef(onSplit);
58
- const onResizeRef = useRef(onResize);
61
+ const onResplitRef = useRef(onResplit);
59
62
  const optionsRef = useRef(options);
60
63
  const revertOnCompleteRef = useRef(revertOnComplete);
61
- const inViewRef = useRef(inView);
62
- const onInViewRef = useRef(onInView);
63
- const onLeaveViewRef = useRef(onLeaveView);
64
+ const viewportRef = useRef(viewport);
65
+ const onViewportEnterRef = useRef(onViewportEnter);
66
+ const onViewportLeaveRef = useRef(onViewportLeave);
67
+ const onRevertRef = useRef(onRevert);
64
68
  const initialStylesRef = useRef(initialStyles);
65
69
  const initialClassesRef = useRef(initialClasses);
66
- const resetOnLeaveRef = useRef(resetOnLeave);
70
+ const resetOnViewportLeaveRef = useRef(resetOnViewportLeave);
67
71
  useLayoutEffect(() => {
68
72
  onSplitRef.current = onSplit;
69
- onResizeRef.current = onResize;
73
+ onResplitRef.current = onResplit;
70
74
  optionsRef.current = options;
71
75
  revertOnCompleteRef.current = revertOnComplete;
72
- inViewRef.current = inView;
73
- onInViewRef.current = onInView;
74
- onLeaveViewRef.current = onLeaveView;
76
+ viewportRef.current = viewport;
77
+ onViewportEnterRef.current = onViewportEnter;
78
+ onViewportLeaveRef.current = onViewportLeave;
79
+ onRevertRef.current = onRevert;
75
80
  initialStylesRef.current = initialStyles;
76
81
  initialClassesRef.current = initialClasses;
77
- resetOnLeaveRef.current = resetOnLeave;
82
+ resetOnViewportLeaveRef.current = resetOnViewportLeave;
78
83
  });
79
84
  const hasSplitRef = useRef(false);
80
85
  const hasRevertedRef = useRef(false);
@@ -82,53 +87,65 @@ var SplitText = forwardRef(
82
87
  const splitResultRef = useRef(null);
83
88
  const observerRef = useRef(null);
84
89
  const hasTriggeredOnceRef = useRef(false);
85
- const childRefCallback = useCallback((node) => {
86
- setChildElement(node);
87
- }, []);
90
+ useLayoutEffect(() => {
91
+ var _a2;
92
+ const element = (_a2 = containerRef.current) == null ? void 0 : _a2.firstElementChild;
93
+ setChildElement(element instanceof HTMLElement ? element : null);
94
+ }, [children]);
88
95
  useEffect(() => {
89
96
  if (!childElement) return;
90
97
  if (hasSplitRef.current) return;
91
98
  let isMounted = true;
92
- document.fonts.ready.then(() => {
93
- var _a, _b;
99
+ waitForFontsReady(waitForFonts).then(() => {
94
100
  if (!isMounted || hasSplitRef.current) return;
95
101
  if (!containerRef.current) return;
102
+ let coreRevert = null;
103
+ const revert = () => {
104
+ var _a2;
105
+ if (hasRevertedRef.current) return;
106
+ hasRevertedRef.current = true;
107
+ try {
108
+ (_a2 = onRevertRef.current) == null ? void 0 : _a2.call(onRevertRef);
109
+ } finally {
110
+ coreRevert == null ? void 0 : coreRevert();
111
+ }
112
+ };
96
113
  const result = splitText(childElement, __spreadProps(__spreadValues({}, optionsRef.current), {
97
114
  autoSplit,
98
115
  revertOnComplete: revertOnCompleteRef.current,
99
116
  initialStyles: initialStylesRef.current,
100
117
  initialClasses: initialClassesRef.current,
101
- onResize: (resizeResult) => {
118
+ onResplit: (resizeResult) => {
102
119
  var _a2;
103
120
  const newSplitTextElements = {
104
121
  chars: resizeResult.chars,
105
122
  words: resizeResult.words,
106
123
  lines: resizeResult.lines,
107
- revert: result.revert
124
+ revert
108
125
  };
109
126
  splitResultRef.current = newSplitTextElements;
110
- (_a2 = onResizeRef.current) == null ? void 0 : _a2.call(onResizeRef, newSplitTextElements);
127
+ (_a2 = onResplitRef.current) == null ? void 0 : _a2.call(onResplitRef, newSplitTextElements);
111
128
  }
112
129
  }));
113
- revertFnRef.current = result.revert;
130
+ coreRevert = result.revert;
131
+ revertFnRef.current = revert;
114
132
  hasSplitRef.current = true;
115
133
  const splitElements = {
116
134
  chars: result.chars,
117
135
  words: result.words,
118
136
  lines: result.lines,
119
- revert: result.revert
137
+ revert
120
138
  };
121
139
  splitResultRef.current = splitElements;
122
140
  containerRef.current.style.visibility = "visible";
123
141
  if (onSplitRef.current) {
124
142
  const callbackResult = onSplitRef.current(splitElements);
125
- if (!inViewRef.current && revertOnCompleteRef.current) {
143
+ if (!needsViewport && revertOnCompleteRef.current) {
126
144
  const promise = normalizeToPromise(callbackResult);
127
145
  if (promise) {
128
146
  promise.then(() => {
129
147
  if (!isMounted || hasRevertedRef.current) return;
130
- result.revert();
131
- hasRevertedRef.current = true;
148
+ splitElements.revert();
132
149
  }).catch(() => {
133
150
  console.warn("[fetta] Animation rejected, text not reverted");
134
151
  });
@@ -139,29 +156,44 @@ var SplitText = forwardRef(
139
156
  }
140
157
  }
141
158
  }
142
- if (inViewRef.current && containerRef.current) {
143
- const inViewOptions = typeof inViewRef.current === "object" ? inViewRef.current : {};
144
- const threshold = (_a = inViewOptions.amount) != null ? _a : 0;
145
- const rootMargin = (_b = inViewOptions.margin) != null ? _b : "0px";
146
- const thresholds = threshold > 0 ? [0, threshold] : 0;
147
- observerRef.current = new IntersectionObserver(
148
- (entries) => {
149
- const entry = entries[0];
150
- if (!entry) return;
151
- const isOnce = typeof inViewRef.current === "object" && inViewRef.current.once;
152
- if (entry.isIntersecting && entry.intersectionRatio >= threshold) {
153
- if (isOnce && hasTriggeredOnceRef.current) return;
154
- hasTriggeredOnceRef.current = true;
155
- setIsInView(true);
156
- } else if (!entry.isIntersecting && !isOnce) {
157
- setIsInView(false);
158
- }
159
- },
160
- { threshold: thresholds, rootMargin }
161
- );
162
- observerRef.current.observe(containerRef.current);
159
+ if (needsViewport && containerRef.current) {
160
+ setupViewportObserver(containerRef.current);
163
161
  }
164
162
  });
163
+ function setupViewportObserver(container) {
164
+ var _a2, _b2, _c, _d, _e;
165
+ const vpOptions = viewportRef.current || {};
166
+ const amount = (_a2 = vpOptions.amount) != null ? _a2 : 0;
167
+ const leave = (_b2 = vpOptions.leave) != null ? _b2 : 0;
168
+ const threshold = amount === "some" ? 0 : amount === "all" ? 1 : amount;
169
+ const leaveThreshold = leave === "some" ? 0 : leave === "all" ? 1 : leave;
170
+ const rootMargin = (_c = vpOptions.margin) != null ? _c : "0px";
171
+ const root = (_e = (_d = vpOptions.root) == null ? void 0 : _d.current) != null ? _e : void 0;
172
+ const thresholdValues = Array.from(
173
+ /* @__PURE__ */ new Set([0, threshold, leaveThreshold])
174
+ ).sort((a, b) => a - b);
175
+ const thresholds = thresholdValues.length === 1 ? thresholdValues[0] : thresholdValues;
176
+ observerRef.current = new IntersectionObserver(
177
+ (entries) => {
178
+ const entry = entries[0];
179
+ if (!entry) return;
180
+ const isOnce = vpOptions.once;
181
+ if (entry.isIntersecting && entry.intersectionRatio >= threshold) {
182
+ if (isOnce && hasTriggeredOnceRef.current) return;
183
+ hasTriggeredOnceRef.current = true;
184
+ setIsInView(true);
185
+ return;
186
+ }
187
+ if (isOnce) return;
188
+ const shouldLeave = leaveThreshold === 0 ? !entry.isIntersecting : entry.intersectionRatio <= leaveThreshold;
189
+ if (shouldLeave) {
190
+ setIsInView(false);
191
+ }
192
+ },
193
+ { threshold: thresholds, rootMargin, root }
194
+ );
195
+ observerRef.current.observe(container);
196
+ }
165
197
  return () => {
166
198
  isMounted = false;
167
199
  if (observerRef.current) {
@@ -173,25 +205,26 @@ var SplitText = forwardRef(
173
205
  }
174
206
  hasSplitRef.current = false;
175
207
  };
176
- }, [childElement, autoSplit]);
208
+ }, [childElement, autoSplit, needsViewport, waitForFonts]);
177
209
  useEffect(() => {
178
210
  if (!splitResultRef.current) return;
179
211
  if (hasRevertedRef.current) return;
180
- if (isInView && onInViewRef.current) {
181
- const callbackResult = onInViewRef.current(splitResultRef.current);
212
+ if (isInView && onViewportEnterRef.current) {
213
+ const callbackResult = onViewportEnterRef.current(
214
+ splitResultRef.current
215
+ );
182
216
  const promise = normalizeToPromise(callbackResult);
183
217
  if (revertOnCompleteRef.current && promise) {
184
218
  promise.then(() => {
185
- var _a;
219
+ var _a2;
186
220
  if (hasRevertedRef.current) return;
187
- (_a = splitResultRef.current) == null ? void 0 : _a.revert();
188
- hasRevertedRef.current = true;
221
+ (_a2 = splitResultRef.current) == null ? void 0 : _a2.revert();
189
222
  }).catch(() => {
190
223
  console.warn("[fetta] Animation rejected, text not reverted");
191
224
  });
192
225
  }
193
226
  } else if (!isInView && splitResultRef.current) {
194
- if (resetOnLeaveRef.current) {
227
+ if (resetOnViewportLeaveRef.current) {
195
228
  const { chars, words, lines } = splitResultRef.current;
196
229
  const styles = initialStylesRef.current;
197
230
  const classes = initialClassesRef.current;
@@ -206,8 +239,8 @@ var SplitText = forwardRef(
206
239
  reapplyInitialClasses(lines, classes.lines);
207
240
  }
208
241
  }
209
- if (onLeaveViewRef.current) {
210
- onLeaveViewRef.current(splitResultRef.current);
242
+ if (onViewportLeaveRef.current) {
243
+ onViewportLeaveRef.current(splitResultRef.current);
211
244
  }
212
245
  }
213
246
  }, [isInView]);
@@ -215,18 +248,20 @@ var SplitText = forwardRef(
215
248
  console.error("SplitText: children must be a single valid React element");
216
249
  return null;
217
250
  }
218
- const clonedChild = cloneElement(children, {
219
- ref: childRefCallback
220
- });
221
251
  const Wrapper = Component;
222
- return /* @__PURE__ */ jsx(
252
+ return createElement(
223
253
  Wrapper,
224
- {
254
+ __spreadProps(__spreadValues({
225
255
  ref: mergedRef,
256
+ "data-fetta-auto-split-wrapper": "true"
257
+ }, wrapperProps), {
226
258
  className,
227
- style: __spreadValues({ visibility: "hidden", position: "relative" }, userStyle),
228
- children: clonedChild
229
- }
259
+ style: __spreadValues({
260
+ visibility: waitForFonts ? "hidden" : "visible",
261
+ position: "relative"
262
+ }, userStyle)
263
+ }),
264
+ children
230
265
  );
231
266
  }
232
267
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fetta",
3
- "version": "1.4.4",
3
+ "version": "1.5.0",
4
4
  "description": "Text splitting library with kerning compensation for animations",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -13,9 +13,17 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "import": "./dist/index.js"
15
15
  },
16
+ "./helpers": {
17
+ "types": "./dist/helpers.d.ts",
18
+ "import": "./dist/helpers.js"
19
+ },
16
20
  "./react": {
17
21
  "types": "./dist/react.d.ts",
18
22
  "import": "./dist/react.js"
23
+ },
24
+ "./motion": {
25
+ "types": "./dist/motion.d.ts",
26
+ "import": "./dist/motion.js"
19
27
  }
20
28
  },
21
29
  "main": "./dist/index.js",
@@ -33,6 +41,7 @@
33
41
  "test": "vitest",
34
42
  "test:ui": "vitest --ui",
35
43
  "test:coverage": "vitest run --coverage",
44
+ "pretest:e2e": "pnpm run build",
36
45
  "test:e2e": "playwright test",
37
46
  "test:all": "vitest run --coverage && playwright test",
38
47
  "size": "size-limit",
@@ -49,14 +58,29 @@
49
58
  "path": "dist/react.js",
50
59
  "import": "*",
51
60
  "ignore": ["react"]
61
+ },
62
+ {
63
+ "name": "Motion",
64
+ "path": "dist/motion.js",
65
+ "import": "*",
66
+ "ignore": ["react", "motion", "motion/react"]
67
+ },
68
+ {
69
+ "name": "Helpers",
70
+ "path": "dist/helpers.js",
71
+ "import": "*"
52
72
  }
53
73
  ],
54
74
  "peerDependencies": {
55
- "react": ">=18.0.0"
75
+ "react": ">=18.0.0",
76
+ "motion": ">=11.0.0"
56
77
  },
57
78
  "peerDependenciesMeta": {
58
79
  "react": {
59
80
  "optional": true
81
+ },
82
+ "motion": {
83
+ "optional": true
60
84
  }
61
85
  },
62
86
  "devDependencies": {