diff --git a/packages/calligraph/src/index.tsx b/packages/calligraph/src/index.tsx
index faba526..b32477d 100644
--- a/packages/calligraph/src/index.tsx
+++ b/packages/calligraph/src/index.tsx
@@ -105,7 +105,6 @@ export function Calligraph(props: CalligraphProps) {
initial: animateInitial = false,
onComplete,
autoSize = true,
- className,
style,
...rest
} = props;
@@ -115,24 +114,18 @@ export function Calligraph(props: CalligraphProps) {
const rendererProps = {
text: String(children ?? ""),
- Component,
transition,
stagger,
animateInitial,
onComplete,
- className,
- style,
- rest,
};
- let content: React.ReactNode;
-
- if (variant === "number") {
- content = ;
- } else if (variant === "slots") {
- content = ;
- } else {
- content = (
+ const content: React.ReactNode =
+ variant === "number" ? (
+
+ ) : variant === "slots" ? (
+
+ ) : (
);
- }
-
- if (autoSize) {
- return {content};
- }
- return content;
+ return (
+
+ {autoSize ? (
+ {content}
+ ) : (
+ content
+ )}
+
+ );
}
diff --git a/packages/calligraph/src/number.tsx b/packages/calligraph/src/number.tsx
index 4f69dd7..00e634b 100644
--- a/packages/calligraph/src/number.tsx
+++ b/packages/calligraph/src/number.tsx
@@ -1,53 +1,39 @@
import type { Transition } from "motion/react";
import { AnimatePresence, MotionConfig, motion } from "motion/react";
-import { useRef, useState } from "react";
+import { useState } from "react";
import { reconcileDigitKeys } from "./reconcile";
import { DIGIT_DISTANCE, isDigit, splitGraphemes } from "./shared";
export function NumberRenderer({
text,
- Component,
transition,
stagger,
animateInitial,
onComplete,
- className,
- style,
- rest,
}: {
text: string;
- Component: React.ElementType;
transition: Transition;
stagger: number;
animateInitial: boolean;
onComplete?: () => void;
- className?: string;
- style?: React.CSSProperties;
- rest: Record;
}) {
const chars = splitGraphemes(text);
- const nextIdRef = useRef(chars.length);
+ const [nextId, setNextId] = useState(chars.length);
const [prevText, setPrevText] = useState(text);
const [digitKeys, setDigitKeys] = useState(() =>
chars.map((_, i) => i),
);
- const dirRef = useRef(1);
+ const [direction, setDirection] = useState(1);
if (text !== prevText) {
- const result = reconcileDigitKeys(
- prevText,
- text,
- digitKeys,
- nextIdRef.current,
- );
- nextIdRef.current = result.nextId;
- dirRef.current = result.direction;
+ const result = reconcileDigitKeys(prevText, text, digitKeys, nextId);
+ setNextId(result.nextId);
+ setDirection(result.direction);
setDigitKeys(result.keys);
setPrevText(text);
}
- const dir = dirRef.current;
const prefixLen = (() => {
const idx = chars.findIndex((c) => isDigit(c));
return idx === -1 ? chars.length : idx;
@@ -55,88 +41,81 @@ export function NumberRenderer({
return (
-
-
- {chars.map((char, i) => {
- const isPrefix = i < prefixLen;
- const outerKey = isPrefix
- ? `pre-${i}`
- : `col-${chars.length - 1 - i}`;
- const delay = i * stagger;
- const isLast = i === chars.length - 1;
+
+ {chars.map((char, i) => {
+ const isPrefix = i < prefixLen;
+ const outerKey = isPrefix
+ ? `pre-${i}`
+ : `col-${chars.length - 1 - i}`;
+ const delay = i * stagger;
+ const isLast = i === chars.length - 1;
- return (
-
- {isPrefix ? (
-
- {char}
-
- ) : (
-
+ {isPrefix ? (
+
+ {char}
+
+ ) : (
+
+ 0
+ ? DIGIT_DISTANCE
+ : -DIGIT_DISTANCE
+ : 0,
+ filter: "blur(2px)",
+ scale: 0.5,
+ opacity: 0,
+ }}
+ animate={{
+ y: 0,
+ opacity: 1,
+ filter: "blur(0px)",
+ scale: 1,
+ transition: { delay },
+ }}
+ exit={{
+ y: isDigit(char)
+ ? direction > 0
+ ? -DIGIT_DISTANCE
+ : DIGIT_DISTANCE
+ : 0,
+ opacity: 0,
+ filter: "blur(2px)",
+ scale: 0.5,
+ transition: { delay },
+ }}
+ onAnimationComplete={
+ isLast && onComplete ? onComplete : undefined
+ }
+ style={{
+ display: "inline-block",
+ whiteSpace: "pre",
+ }}
>
- 0
- ? DIGIT_DISTANCE
- : -DIGIT_DISTANCE
- : 0,
- filter: "blur(2px)",
- scale: 0.5,
- opacity: 0,
- }}
- animate={{
- y: 0,
- opacity: 1,
- filter: "blur(0px)",
- scale: 1,
- transition: { delay },
- }}
- exit={{
- y: isDigit(char)
- ? dir > 0
- ? -DIGIT_DISTANCE
- : DIGIT_DISTANCE
- : 0,
- opacity: 0,
- filter: "blur(2px)",
- scale: 0.5,
- transition: { delay },
- }}
- onAnimationComplete={
- isLast && onComplete ? onComplete : undefined
- }
- style={{
- display: "inline-block",
- whiteSpace: "pre",
- }}
- >
- {char}
-
-
- )}
-
- );
- })}
-
-
+ {char}
+
+
+ )}
+
+ );
+ })}
+
);
}
diff --git a/packages/calligraph/src/slots.tsx b/packages/calligraph/src/slots.tsx
index f1809aa..45c0f11 100644
--- a/packages/calligraph/src/slots.tsx
+++ b/packages/calligraph/src/slots.tsx
@@ -132,52 +132,38 @@ function SlotColumn({
export function SlotsRenderer({
text,
- Component,
transition,
stagger,
animateInitial,
- className,
- style,
- rest,
}: {
text: string;
- Component: React.ElementType;
transition: Transition;
stagger: number;
animateInitial: boolean;
onComplete?: () => void;
- className?: string;
- style?: React.CSSProperties;
- rest: Record;
}) {
const chars = splitGraphemes(text);
- const nextIdRef = useRef(chars.length);
+ const [nextId, setNextId] = useState(chars.length);
const [prevText, setPrevText] = useState(text);
const [digitKeys, setDigitKeys] = useState(() =>
chars.map((_, i) => i),
);
- const dirRef = useRef(1);
- const mountedRef = useRef(false);
+ const [direction, setDirection] = useState(1);
+ const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
- mountedRef.current = true;
+ setIsMounted(true);
}, []);
if (text !== prevText) {
- const result = reconcileDigitKeys(
- prevText,
- text,
- digitKeys,
- nextIdRef.current,
- );
- nextIdRef.current = result.nextId;
- dirRef.current = result.direction;
+ const result = reconcileDigitKeys(prevText, text, digitKeys, nextId);
+ setNextId(result.nextId);
+ setDirection(result.direction);
setDigitKeys(result.keys);
setPrevText(text);
}
- const dir = dirRef.current;
const prefixLen = (() => {
const idx = chars.findIndex((c) => isDigit(c));
return idx === -1 ? chars.length : idx;
@@ -188,72 +174,61 @@ export function SlotsRenderer({
return (
-
-
-
- {chars.map((char, i) => {
- const isPrefix = i < prefixLen;
- const outerKey = isPrefix
- ? `pre-${i}`
- : `col-${chars.length - 1 - i}`;
-
- if (isPrefix || !isDigit(char)) {
- return (
-
- {char}
-
- );
- }
-
- const delay = (digitCount - 1 - digitIndex) * stagger;
- digitIndex++;
-
+
+ {chars.map((char, i) => {
+ const isPrefix = i < prefixLen;
+ const outerKey = isPrefix
+ ? `pre-${i}`
+ : `col-${chars.length - 1 - i}`;
+
+ if (isPrefix || !isDigit(char)) {
return (
-
+ {char}
);
- })}
-
-
-
+ }
+
+ const delay = (digitCount - 1 - digitIndex) * stagger;
+ digitIndex++;
+
+ return (
+
+
+
+ );
+ })}
+
+
);
}
diff --git a/packages/calligraph/src/text.tsx b/packages/calligraph/src/text.tsx
index 5c70cda..8d92588 100644
--- a/packages/calligraph/src/text.tsx
+++ b/packages/calligraph/src/text.tsx
@@ -1,24 +1,19 @@
import type { Transition } from "motion/react";
import { AnimatePresence, MotionConfig, motion } from "motion/react";
-import { useRef, useState } from "react";
+import { useState } from "react";
import { reconcileTextKeys } from "./reconcile";
import { splitGraphemes } from "./shared";
export function TextRenderer({
text,
- Component,
transition,
driftX,
driftY,
trend,
animateInitial,
onComplete,
- className,
- style,
- rest,
}: {
text: string;
- Component: React.ElementType;
transition: Transition;
driftX: number;
driftY: number;
@@ -26,12 +21,9 @@ export function TextRenderer({
stagger: number;
animateInitial: boolean;
onComplete?: () => void;
- className?: string;
- style?: React.CSSProperties;
- rest: Record;
}) {
const graphemes = splitGraphemes(text);
- const nextIdRef = useRef(graphemes.length);
+ const [nextId, setNextId] = useState(graphemes.length);
const [prevText, setPrevText] = useState(text);
const [charKeys, setCharKeys] = useState(() =>
graphemes.map((_, i) => `c${i}`),
@@ -39,13 +31,8 @@ export function TextRenderer({
const [changeRatio, setChangeRatio] = useState(0);
if (text !== prevText) {
- const result = reconcileTextKeys(
- prevText,
- text,
- charKeys,
- nextIdRef.current,
- );
- nextIdRef.current = result.nextId;
+ const result = reconcileTextKeys(prevText, text, charKeys, nextId);
+ setNextId(result.nextId);
setPrevText(text);
setCharKeys(result.keys);
setChangeRatio(result.changeRatio);
@@ -53,59 +40,52 @@ export function TextRenderer({
return (
-
-
- {graphemes.map((char, i) => {
- const key = charKeys[i];
- const progress =
- graphemes.length <= 1 ? 0 : i / (graphemes.length - 1);
- const offsetX = (progress - 0.5) * driftX * changeRatio;
- const offsetY = (progress - 0.5) * driftY * changeRatio;
- const trendY = trend * 8 * changeRatio;
- const isLast = i === graphemes.length - 1;
+
+ {graphemes.map((char, i) => {
+ const key = charKeys[i];
+ const progress =
+ graphemes.length <= 1 ? 0 : i / (graphemes.length - 1);
+ const offsetX = (progress - 0.5) * driftX * changeRatio;
+ const offsetY = (progress - 0.5) * driftY * changeRatio;
+ const trendY = trend * 8 * changeRatio;
+ const isLast = i === graphemes.length - 1;
- return (
-
- {char}
-
- );
- })}
-
-
+ return (
+
+ {char}
+
+ );
+ })}
+
);
}