=> {theme.textColors.colorText}
;
+const MockComponent = ({ theme }: { theme: ThemeShape }): React.ReactElement => (
+ {theme.textColors.colorText}
+);
const MockComponentWithTheme = withTheme(MockComponent);
describe("withTheme", () => {
diff --git a/packages/paste-website/package.json b/packages/paste-website/package.json
index cfe0a5b6ba..319f742de2 100644
--- a/packages/paste-website/package.json
+++ b/packages/paste-website/package.json
@@ -184,9 +184,9 @@
"react-github-button": "^0.1.11",
"react-hook-form": "^7.30.0",
"react-hotkeys-hook": "^4.4.1",
+ "react-intersection-observer": "^9.15.1",
"react-live": "^3.1.1",
"react-scrollspy": "^3.4.0",
- "react-visibility-sensor": "5.1.1",
"remark-gfm": "^3.0.1",
"rollbar": "^2.26.2",
"sharp": "^0.32.5",
@@ -201,7 +201,7 @@
"zustand": "^4.4.7"
},
"devDependencies": {
- "@next/eslint-plugin-next": "15.2.0",
+ "@next/eslint-plugin-next": "14.2.24",
"@storybook/react": "7.6.4",
"@tanstack/eslint-plugin-query": "^5.17.7",
"@testing-library/react": "^16.2.0",
diff --git a/packages/paste-website/src/assets/illustrations/DoodleArrow.tsx b/packages/paste-website/src/assets/illustrations/DoodleArrow.tsx
index df3930e2f1..9f8711ac60 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleArrow.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleArrow.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 250;
@@ -10,20 +11,27 @@ export const DoodleArrow = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
d="m344.148655 2159.0516-19.1052-24.0516 29.0358 1.512m-12.636 190.8252c69.120001-25.92 101.520001-132.3 0-184.14"
transform="matrix(-1 0 0 1 408.043 -2133)"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleBurst.tsx b/packages/paste-website/src/assets/illustrations/DoodleBurst.tsx
index 56b568adb7..0daf3b0d37 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleBurst.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleBurst.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 260;
@@ -10,20 +11,27 @@ export const DoodleBurst = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
height="57"
fill="none"
viewBox="0 0 62 57"
- xmlns="http://www.w3.org/2000/svg"
+ xmlns="http:www.w3.org/2000/svg"
>
{
strokeWidth="2"
d="M41.9 1.811L49.76 31.14M19.856 16.52l19.743 23.629M1.366 38.239L32.938 52.83"
/>
-
-
+
+ //{" "}
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleCloud.tsx b/packages/paste-website/src/assets/illustrations/DoodleCloud.tsx
index 84bd7d96a7..ef9ca315c1 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleCloud.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleCloud.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 160;
@@ -10,11 +11,16 @@ export const DoodleCloud = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
@@ -24,15 +30,17 @@ export const DoodleCloud = (): JSX.Element => {
},
});
+ const AnimatedPath = animated("path");
+
return (
-
+
-
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleCurve.tsx b/packages/paste-website/src/assets/illustrations/DoodleCurve.tsx
index e24f532719..39103a67e9 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleCurve.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleCurve.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 50;
@@ -10,20 +11,27 @@ export const DoodleCurve = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
d="m1335 1226c-.25169 1.35808-1.83458 9.29809-8.94915 13.52449-7.11458 4.22641-16.96983 3.00357-24.05085-3.38112"
transform="matrix(-.5 -.8660254 .8660254 -.5 -392.924817 1771.854751)"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopArrow.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopArrow.tsx
index 7cd0881a8e..46eb82bb8d 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopArrow.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopArrow.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
const dashArray = 250;
@@ -10,20 +11,27 @@ export const DoodleLoopArrow = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
strokeWidth="2"
d="M67.65 30.703l24.992 13.844L81.73 9.203"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopArrowLarge.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopArrowLarge.tsx
index d545cc51c0..da99b18976 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopArrowLarge.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopArrowLarge.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 350;
@@ -10,20 +11,27 @@ export const DoodleLoopArrowLarge = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
strokeWidth="2"
d="M171.344 1.59c-34.204 9.243-53.899 28.315-45.514 45.922 6.641 13.944 18.251 14.936 12.365.38-25.277-62.508-125.41 60.186-125.65 119.236"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopLarge.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopLarge.tsx
index 6a5861f8e0..b09f042d30 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopLarge.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopLarge.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
const dashArray = 350;
@@ -10,20 +11,26 @@ export const DoodleLoopLarge = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
return (
-
-
+ {
d="m1243 2198c64.87467-44.8 80.72191-116.48 51.50355-122.58462-12.47475-2.6043-18.93746 4.47508-6.43794 7.87693 53.66769 14.61169 23.27564-111.75385-15.35202-141.29231"
transform="translate(-1241 -1940)"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopMedium.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopMedium.tsx
index ea8bb09bd3..bb0f3a7405 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopMedium.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopMedium.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 350;
@@ -10,20 +11,27 @@ export const DoodleLoopMedium = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
strokeWidth="2"
d="M53.527 139.26a74.384 74.384 0 0021.888-30.826c8.939-23.983-2.428-68.705-23.83-69.065-12.107-.203-12.712 13.61 3.671 14.666C73.936 55.239 96.861 26.418 85.161 2"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopSmall.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopSmall.tsx
index f6721d7c71..c6992e9ab3 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopSmall.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopSmall.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
-import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import * as React from "react";
+import { useInView } from "react-intersection-observer";
const dashArray = 110;
@@ -10,20 +11,27 @@ export const DoodleLoopSmall = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
d="M364,1507.07693 C349.942623,1512.99997 333.47541,1504.31284 333.877049,1493.65136 C334.278689,1482.98987 345.52459,1484.17448 345.52459,1492.86162 C345.52459,1504.70771 325.040984,1512.99997 315,1505.10258"
transform="rotate(36 2469.219 271.304)"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleLoopTiny.tsx b/packages/paste-website/src/assets/illustrations/DoodleLoopTiny.tsx
index 657a905093..e934b72844 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleLoopTiny.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleLoopTiny.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
const dashArray = 110;
@@ -10,20 +11,26 @@ export const DoodleLoopTiny = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
return (
-
-
+ {
strokeWidth="2"
d="M2 47.603a38.008 38.008 0 0019.233 1.81c12.897-2.172 29.783-18.627 24.474-28.19-3.003-5.41-9.27-2.148-5.551 5.371 4.239 8.574 22.85 11.355 30.666-.06"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/assets/illustrations/DoodleZigzag.tsx b/packages/paste-website/src/assets/illustrations/DoodleZigzag.tsx
index 737e5ecf4b..7147c72168 100644
--- a/packages/paste-website/src/assets/illustrations/DoodleZigzag.tsx
+++ b/packages/paste-website/src/assets/illustrations/DoodleZigzag.tsx
@@ -1,8 +1,9 @@
import { animated, useSpring } from "@twilio-paste/animation-library";
+import { Box } from "@twilio-paste/box";
import { useTheme } from "@twilio-paste/theme";
import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
const dashArray = 260;
@@ -10,20 +11,27 @@ export const DoodleZigzag = (): JSX.Element => {
const [show, setShow] = React.useState(false);
const theme = useTheme();
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
- setShow(isVisible);
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
+ setShow(true);
}
- }
+ }, [inView, show]);
const styles = useSpring({
x: show ? 0 : -1 * dashArray,
config: { mass: 1, tension: 280, friction: 40 },
});
+ const AnimatedSVG = animated("svg");
+
return (
-
-
+ {
d="m464 1781.6-14.8-37.2-17.6 38.8-22-47.2-14 50.8-29.6-24.4 2.4 33.6"
transform="translate(-365 -1735)"
/>
-
-
+
+
);
};
diff --git a/packages/paste-website/src/components/color-swatch/ColorGradient.tsx b/packages/paste-website/src/components/color-swatch/ColorGradient.tsx
index d2064c7720..3f6bde4aa1 100644
--- a/packages/paste-website/src/components/color-swatch/ColorGradient.tsx
+++ b/packages/paste-website/src/components/color-swatch/ColorGradient.tsx
@@ -6,7 +6,7 @@ import { styled, themeGet } from "@twilio-paste/styling-library";
import { useUID } from "@twilio-paste/uid-library";
import * as React from "react";
import type { JSX } from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
import { useDarkModeContext } from "../../context/DarkModeContext";
import type { Themes } from "../../types";
@@ -52,11 +52,8 @@ const StyledGradientSwatch = styled.div<{ backgroundColor: string }>`
const StyledGradientSwatchTall = styled.div<{ backgroundColor: string; rounded: boolean }>((props) => {
return {
backgroundColor: props.backgroundColor,
- // @ts-expect-error this works fine
height: props.theme.space.space120,
- // @ts-expect-error this works fine
borderBottomLeftRadius: props.rounded ? props.theme.radii.borderRadius20 : 0,
- // @ts-expect-error this works fine
borderBottomRightRadius: props.rounded ? props.theme.radii.borderRadius20 : 0,
};
});
@@ -69,13 +66,18 @@ export const ColorGradient: React.FC<
const aliasValues = getAliasValuesFromPrefix(aliasPrefix, theme);
const count = aliasValues.length - 1;
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.3,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
setTimeout(() => {
- setShow(isVisible);
+ setShow(true);
}, index * 50);
}
- }
+ }, [inView, show, index]);
const styles = useSpring({
opacity: show ? 1 : 0.1,
@@ -86,13 +88,13 @@ export const ColorGradient: React.FC<
if (makeTall) {
return (
-
+
{aliasValues.map((aliasValue, _index) => (
))}
-
+
);
}
return (
diff --git a/packages/paste-website/src/components/customization-landing-page/ReadyToGetStarted.tsx b/packages/paste-website/src/components/customization-landing-page/ReadyToGetStarted.tsx
index de3b27b5ac..30bd6d4b71 100644
--- a/packages/paste-website/src/components/customization-landing-page/ReadyToGetStarted.tsx
+++ b/packages/paste-website/src/components/customization-landing-page/ReadyToGetStarted.tsx
@@ -15,6 +15,7 @@ export const ReadyToGetStarted = (): JSX.Element => {
diff --git a/packages/paste-website/src/components/customization-landing-page/image-slider/ImageSlider.tsx b/packages/paste-website/src/components/customization-landing-page/image-slider/ImageSlider.tsx
index 60c325c5b7..f72c42ebfa 100644
--- a/packages/paste-website/src/components/customization-landing-page/image-slider/ImageSlider.tsx
+++ b/packages/paste-website/src/components/customization-landing-page/image-slider/ImageSlider.tsx
@@ -2,7 +2,7 @@ import { Box } from "@twilio-paste/box";
import { useUIDSeed } from "@twilio-paste/uid-library";
import Image from "next/image";
import * as React from "react";
-import type { JSX, Ref, MutableRefObject } from "react";
+import type { JSX, Ref, RefObject } from "react";
import HeroBack from "../../../assets/images/customization/hero-back.png";
import HeroFront from "../../../assets/images/customization/hero-front.png";
@@ -94,7 +94,7 @@ export const ImageSlider = (): JSX.Element => {
maxWidth="size60"
position="absolute"
top="space150"
- ref={containerRef as MutableRefObject}
+ ref={containerRef as RefObject}
right="spaceNegative150"
width="60%"
zIndex="zIndex10"
diff --git a/packages/paste-website/src/components/homepage/HomeHeroIllustration.tsx b/packages/paste-website/src/components/homepage/HomeHeroIllustration.tsx
index 4fcf23c750..ad6eeee4b8 100644
--- a/packages/paste-website/src/components/homepage/HomeHeroIllustration.tsx
+++ b/packages/paste-website/src/components/homepage/HomeHeroIllustration.tsx
@@ -4,7 +4,7 @@ import type { ValueOf } from "@twilio-paste/types";
import lottie from "lottie-web";
import Image from "next/image";
import * as React from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
import HomeHeroIllu from "../../assets/illustrations/home_hero.svg";
import { inCypress } from "../../utils/inCypress";
@@ -44,11 +44,16 @@ const HomeHeroIllustration: React.FC> = () => {
const containerRef = React.useRef(null);
const [illustrationState, setIllustrationState] = React.useState(IllustrationStates.UNINITIALIZED);
- const handleVisibilityChange = (isVisible: boolean): void => {
- if (illustrationState === IllustrationStates.UNINITIALIZED && isVisible) {
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 0.1,
+ });
+
+ React.useEffect(() => {
+ if (illustrationState === IllustrationStates.UNINITIALIZED && inView) {
setIllustrationState(prefersReducedMotion ? IllustrationStates.STATIC : IllustrationStates.DYNAMIC);
}
- };
+ }, [inView, illustrationState, prefersReducedMotion]);
React.useEffect(() => {
if (!prefersReducedMotion && illustrationState === IllustrationStates.DYNAMIC) {
@@ -84,7 +89,7 @@ const HomeHeroIllustration: React.FC> = () => {
* Also to prevent height fouc when the animation loads
*/
return (
-
+
> = () => {
>
-
+
);
};
diff --git a/packages/paste-website/src/components/homepage/Themeable.tsx b/packages/paste-website/src/components/homepage/Themeable.tsx
index 596bf6dd06..678a5a342b 100644
--- a/packages/paste-website/src/components/homepage/Themeable.tsx
+++ b/packages/paste-website/src/components/homepage/Themeable.tsx
@@ -71,10 +71,12 @@ const Boop: React.FC = ({
};
}, [isBooped, timing]);
+ const AnimatedSpan = animated("span");
+
return (
-
+
{children}
-
+
);
};
diff --git a/packages/paste-website/src/components/homepage/WeDoTheThinking.tsx b/packages/paste-website/src/components/homepage/WeDoTheThinking.tsx
index 87c303cd36..98cc468fda 100644
--- a/packages/paste-website/src/components/homepage/WeDoTheThinking.tsx
+++ b/packages/paste-website/src/components/homepage/WeDoTheThinking.tsx
@@ -4,7 +4,7 @@ import { Heading } from "@twilio-paste/heading";
import { CheckboxCheckIcon } from "@twilio-paste/icons/esm/CheckboxCheckIcon";
import { Text } from "@twilio-paste/text";
import * as React from "react";
-import VisibilitySensor from "react-visibility-sensor";
+import { useInView } from "react-intersection-observer";
import { SectionContainer } from "./SectionContainer";
@@ -16,13 +16,19 @@ const ThinkingLine: React.FC<{ children: React.ReactNode; index: number }> = ({
}): React.ReactElement => {
const [show, setShow] = React.useState(false);
- function handleVisibilityChange(isVisible: boolean): void {
- if (!show) {
+ const { ref, inView } = useInView({
+ triggerOnce: true,
+ threshold: 1,
+ delay: 100,
+ });
+
+ React.useEffect(() => {
+ if (inView && !show) {
setTimeout(() => {
- setShow(isVisible);
+ setShow(true);
}, index * 50);
}
- }
+ }, [inView, show, index]);
const styles = useSpring({
opacity: show ? 1 : 0.1,
@@ -32,7 +38,7 @@ const ThinkingLine: React.FC<{ children: React.ReactNode; index: number }> = ({
});
return (
-
+
= ({
{children}
-
+
);
};
diff --git a/packages/paste-website/src/components/site-wrapper/site-footer/SiteFooterNav.tsx b/packages/paste-website/src/components/site-wrapper/site-footer/SiteFooterNav.tsx
index de302f125f..6e5b11cb3d 100644
--- a/packages/paste-website/src/components/site-wrapper/site-footer/SiteFooterNav.tsx
+++ b/packages/paste-website/src/components/site-wrapper/site-footer/SiteFooterNav.tsx
@@ -196,7 +196,7 @@ const SiteFooterNav = (): JSX.Element => {
diff --git a/yarn.lock b/yarn.lock
index 2148723423..beed64c788 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3776,26 +3776,7 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/babel-plugin@npm:^11.11.0":
- version: 11.13.5
- resolution: "@emotion/babel-plugin@npm:11.13.5"
- dependencies:
- "@babel/helper-module-imports": ^7.16.7
- "@babel/runtime": ^7.18.3
- "@emotion/hash": ^0.9.2
- "@emotion/memoize": ^0.9.0
- "@emotion/serialize": ^1.3.3
- babel-plugin-macros: ^3.1.0
- convert-source-map: ^1.5.0
- escape-string-regexp: ^4.0.0
- find-root: ^1.1.0
- source-map: ^0.5.7
- stylis: 4.2.0
- checksum: c41df7e6c19520e76d1939f884be878bf88b5ba00bd3de9d05c5b6c5baa5051686ab124d7317a0645de1b017b574d8139ae1d6390ec267fbe8e85a5252afb542
- languageName: node
- linkType: hard
-
-"@emotion/babel-plugin@npm:^11.2.0, @emotion/babel-plugin@npm:^11.7.1":
+"@emotion/babel-plugin@npm:^11.10.5, @emotion/babel-plugin@npm:^11.2.0, @emotion/babel-plugin@npm:^11.7.1":
version: 11.10.5
resolution: "@emotion/babel-plugin@npm:11.10.5"
dependencies:
@@ -3831,33 +3812,7 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/cache@npm:11.11.0":
- version: 11.11.0
- resolution: "@emotion/cache@npm:11.11.0"
- dependencies:
- "@emotion/memoize": ^0.8.1
- "@emotion/sheet": ^1.2.2
- "@emotion/utils": ^1.2.1
- "@emotion/weak-memoize": ^0.3.1
- stylis: 4.2.0
- checksum: 8eb1dc22beaa20c21a2e04c284d5a2630a018a9d51fb190e52de348c8d27f4e8ca4bbab003d68b4f6cd9cc1c569ca747a997797e0f76d6c734a660dc29decf08
- languageName: node
- linkType: hard
-
-"@emotion/cache@npm:^11.11.0":
- version: 11.14.0
- resolution: "@emotion/cache@npm:11.14.0"
- dependencies:
- "@emotion/memoize": ^0.9.0
- "@emotion/sheet": ^1.4.0
- "@emotion/utils": ^1.4.2
- "@emotion/weak-memoize": ^0.4.0
- stylis: 4.2.0
- checksum: 0a81591541ea43bc7851742e6444b7800d72e98006f94e775ae6ea0806662d14e0a86ff940f5f19d33b4bb2c427c882aa65d417e7322a6e0d5f20fe65ed920c9
- languageName: node
- linkType: hard
-
-"@emotion/cache@npm:^11.7.1":
+"@emotion/cache@npm:11.10.5, @emotion/cache@npm:^11.10.5, @emotion/cache@npm:^11.7.1":
version: 11.10.5
resolution: "@emotion/cache@npm:11.10.5"
dependencies:
@@ -3921,13 +3876,6 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/hash@npm:^0.9.2":
- version: 0.9.2
- resolution: "@emotion/hash@npm:0.9.2"
- checksum: 379bde2830ccb0328c2617ec009642321c0e009a46aa383dfbe75b679c6aea977ca698c832d225a893901f29d7b3eef0e38cf341f560f6b2b56f1ff23c172387
- languageName: node
- linkType: hard
-
"@emotion/is-prop-valid@npm:^0.8.1":
version: 0.8.8
resolution: "@emotion/is-prop-valid@npm:0.8.8"
@@ -3937,12 +3885,12 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/is-prop-valid@npm:^1.2.1":
- version: 1.3.1
- resolution: "@emotion/is-prop-valid@npm:1.3.1"
+"@emotion/is-prop-valid@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@emotion/is-prop-valid@npm:1.2.0"
dependencies:
- "@emotion/memoize": ^0.9.0
- checksum: fe6549d54f389e1a17cb02d832af7ee85fb6ea126fc18d02ca47216e8ff19332c1983f4a0ba68602cfcd3b325ffd4ebf0b2d0c6270f1e7e6fe3fca4ba7741e1a
+ "@emotion/memoize": ^0.8.0
+ checksum: cc7a19850a4c5b24f1514665289442c8c641709e6f7711067ad550e05df331da0692a16148e85eda6f47e31b3261b64d74c5e25194d053223be16231f969d633
languageName: node
linkType: hard
@@ -3988,38 +3936,27 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/memoize@npm:^0.8.1":
- version: 0.8.1
- resolution: "@emotion/memoize@npm:0.8.1"
- checksum: a19cc01a29fcc97514948eaab4dc34d8272e934466ed87c07f157887406bc318000c69ae6f813a9001c6a225364df04249842a50e692ef7a9873335fbcc141b0
- languageName: node
- linkType: hard
-
-"@emotion/memoize@npm:^0.9.0":
- version: 0.9.0
- resolution: "@emotion/memoize@npm:0.9.0"
- checksum: 038132359397348e378c593a773b1148cd0cf0a2285ffd067a0f63447b945f5278860d9de718f906a74c7c940ba1783ac2ca18f1c06a307b01cc0e3944e783b1
- languageName: node
- linkType: hard
-
-"@emotion/react@npm:11.11.0":
- version: 11.11.0
- resolution: "@emotion/react@npm:11.11.0"
+"@emotion/react@npm:11.10.5":
+ version: 11.10.5
+ resolution: "@emotion/react@npm:11.10.5"
dependencies:
"@babel/runtime": ^7.18.3
- "@emotion/babel-plugin": ^11.11.0
- "@emotion/cache": ^11.11.0
- "@emotion/serialize": ^1.1.2
- "@emotion/use-insertion-effect-with-fallbacks": ^1.0.1
- "@emotion/utils": ^1.2.1
- "@emotion/weak-memoize": ^0.3.1
+ "@emotion/babel-plugin": ^11.10.5
+ "@emotion/cache": ^11.10.5
+ "@emotion/serialize": ^1.1.1
+ "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0
+ "@emotion/utils": ^1.2.0
+ "@emotion/weak-memoize": ^0.3.0
hoist-non-react-statics: ^3.3.1
peerDependencies:
+ "@babel/core": ^7.0.0
react: ">=16.8.0"
peerDependenciesMeta:
+ "@babel/core":
+ optional: true
"@types/react":
optional: true
- checksum: 2653e7c3de7b6fd5b0e18dea15621a9886104cc7c8cd5522ca69e52bd547ef6f13644193f8e0a906eea1e29a4f1d8167cdfa4667572fb7fafe0c62ab30fbaab6
+ checksum: 32b67b28e9b6d6c53b970072680697f04c2521441050bdeb19a1a7f0164af549b4dad39ff375eda1b6a3cf1cc86ba2c6fa55460ec040e6ebbca3e9ec58353cf7
languageName: node
linkType: hard
@@ -4036,19 +3973,6 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/serialize@npm:^1.1.2, @emotion/serialize@npm:^1.3.3":
- version: 1.3.3
- resolution: "@emotion/serialize@npm:1.3.3"
- dependencies:
- "@emotion/hash": ^0.9.2
- "@emotion/memoize": ^0.9.0
- "@emotion/unitless": ^0.10.0
- "@emotion/utils": ^1.4.2
- csstype: ^3.0.2
- checksum: 510331233767ae4e09e925287ca2c7269b320fa1d737ea86db5b3c861a734483ea832394c0c1fe5b21468fe335624a75e72818831d303ba38125f54f44ba02e7
- languageName: node
- linkType: hard
-
"@emotion/sheet@npm:^1.0.3, @emotion/sheet@npm:^1.2.1":
version: 1.2.1
resolution: "@emotion/sheet@npm:1.2.1"
@@ -4056,37 +3980,26 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/sheet@npm:^1.2.2, @emotion/sheet@npm:^1.4.0":
- version: 1.4.0
- resolution: "@emotion/sheet@npm:1.4.0"
- checksum: eeb1212e3289db8e083e72e7e401cd6d1a84deece87e9ce184f7b96b9b5dbd6f070a89057255a6ff14d9865c3ce31f27c39248a053e4cdd875540359042586b4
- languageName: node
- linkType: hard
-
-"@emotion/styled@npm:11.11.0":
- version: 11.11.0
- resolution: "@emotion/styled@npm:11.11.0"
+"@emotion/styled@npm:11.10.5":
+ version: 11.10.5
+ resolution: "@emotion/styled@npm:11.10.5"
dependencies:
"@babel/runtime": ^7.18.3
- "@emotion/babel-plugin": ^11.11.0
- "@emotion/is-prop-valid": ^1.2.1
- "@emotion/serialize": ^1.1.2
- "@emotion/use-insertion-effect-with-fallbacks": ^1.0.1
- "@emotion/utils": ^1.2.1
+ "@emotion/babel-plugin": ^11.10.5
+ "@emotion/is-prop-valid": ^1.2.0
+ "@emotion/serialize": ^1.1.1
+ "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0
+ "@emotion/utils": ^1.2.0
peerDependencies:
+ "@babel/core": ^7.0.0
"@emotion/react": ^11.0.0-rc.0
react: ">=16.8.0"
peerDependenciesMeta:
+ "@babel/core":
+ optional: true
"@types/react":
optional: true
- checksum: 904f641aad3892c65d7d6c0808b036dae1e6d6dad4861c1c7dc0baa59977047c6cad220691206eba7b4059f1a1c6e6c1ef4ebb8c829089e280fa0f2164a01e6b
- languageName: node
- linkType: hard
-
-"@emotion/unitless@npm:^0.10.0":
- version: 0.10.0
- resolution: "@emotion/unitless@npm:0.10.0"
- checksum: d79346df31a933e6d33518e92636afeb603ce043f3857d0a39a2ac78a09ef0be8bedff40130930cb25df1beeee12d96ee38613963886fa377c681a89970b787c
+ checksum: 1cec5f6aeb227a7255141031e8594f38ad83902413472aae0a46c27e5f9769c01e23c1ad39adee408d8a2168a697464314d1a0c4f50b31a5d25ea506b2d7bbc8
languageName: node
linkType: hard
@@ -4106,15 +4019,6 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.1":
- version: 1.2.0
- resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0"
- peerDependencies:
- react: ">=16.8.0"
- checksum: 8ff6aec7f2924526ff8c8f8f93d4b8236376e2e12c435314a18c9a373016e24dfdf984e82bbc83712b8e90ff4783cd765eb39fc7050d1a43245e5728740ddd71
- languageName: node
- linkType: hard
-
"@emotion/utils@npm:^1.0.0, @emotion/utils@npm:^1.2.0":
version: 1.2.0
resolution: "@emotion/utils@npm:1.2.0"
@@ -4122,13 +4026,6 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/utils@npm:^1.2.1, @emotion/utils@npm:^1.4.2":
- version: 1.4.2
- resolution: "@emotion/utils@npm:1.4.2"
- checksum: 04cf76849c6401205c058b82689fd0ec5bf501aed6974880fe9681a1d61543efb97e848f4c38664ac4a9068c7ad2d1cb84f73bde6cf95f1208aa3c28e0190321
- languageName: node
- linkType: hard
-
"@emotion/weak-memoize@npm:^0.3.0":
version: 0.3.0
resolution: "@emotion/weak-memoize@npm:0.3.0"
@@ -4136,20 +4033,6 @@ __metadata:
languageName: node
linkType: hard
-"@emotion/weak-memoize@npm:^0.3.1":
- version: 0.3.1
- resolution: "@emotion/weak-memoize@npm:0.3.1"
- checksum: b2be47caa24a8122622ea18cd2d650dbb4f8ad37b636dc41ed420c2e082f7f1e564ecdea68122b546df7f305b159bf5ab9ffee872abd0f052e687428459af594
- languageName: node
- linkType: hard
-
-"@emotion/weak-memoize@npm:^0.4.0":
- version: 0.4.0
- resolution: "@emotion/weak-memoize@npm:0.4.0"
- checksum: db5da0e89bd752c78b6bd65a1e56231f0abebe2f71c0bd8fc47dff96408f7065b02e214080f99924f6a3bfe7ee15afc48dad999d76df86b39b16e513f7a94f52
- languageName: node
- linkType: hard
-
"@esbuild/android-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/android-arm64@npm:0.18.20"
@@ -5989,12 +5872,12 @@ __metadata:
languageName: node
linkType: hard
-"@next/eslint-plugin-next@npm:15.2.0":
- version: 15.2.0
- resolution: "@next/eslint-plugin-next@npm:15.2.0"
+"@next/eslint-plugin-next@npm:14.2.24":
+ version: 14.2.24
+ resolution: "@next/eslint-plugin-next@npm:14.2.24"
dependencies:
- fast-glob: 3.3.1
- checksum: 3ce7ddcf8d2d66bf44adc5ed224f4fe3b7d6eb9566ef2a95d9c700c5e5cf5dd274fd9152c1585448f423c4079b24d21e9fd42e783fc9c8aaa7c3a536f6b625a5
+ glob: 10.3.10
+ checksum: fbcfa0eaa592930d1da7be55a78caf3232783644bd62e2c545f865bc45633917d1b897e955f675e921108903b0db4e89660037efdda659016095ac68474284e4
languageName: node
linkType: hard
@@ -15559,9 +15442,9 @@ __metadata:
version: 0.0.0-use.local
resolution: "@twilio-paste/styling-library@workspace:packages/paste-libraries/styling"
dependencies:
- "@emotion/cache": 11.11.0
- "@emotion/react": 11.11.0
- "@emotion/styled": 11.11.0
+ "@emotion/cache": 11.10.5
+ "@emotion/react": 11.10.5
+ "@emotion/styled": 11.10.5
"@styled-system/css": 5.1.5
"@styled-system/should-forward-prop": 5.1.5
"@styled-system/theme-get": 5.1.2
@@ -16466,7 +16349,7 @@ __metadata:
"@mdx-js/mdx": ^1.6.22
"@mdx-js/react": ^1.6.22
"@next/bundle-analyzer": 15.2.0
- "@next/eslint-plugin-next": 15.2.0
+ "@next/eslint-plugin-next": 14.2.24
"@next/mdx": 15.2.0
"@octokit/core": ^5.0.1
"@octokit/plugin-paginate-graphql": ^4.0.0
@@ -16630,9 +16513,9 @@ __metadata:
react-github-button: ^0.1.11
react-hook-form: ^7.30.0
react-hotkeys-hook: ^4.4.1
+ react-intersection-observer: ^9.15.1
react-live: ^3.1.1
react-scrollspy: ^3.4.0
- react-visibility-sensor: 5.1.1
remark-gfm: ^3.0.1
rollbar: ^2.26.2
sharp: ^0.32.5
@@ -26461,19 +26344,6 @@ __metadata:
languageName: node
linkType: hard
-"fast-glob@npm:3.3.1":
- version: 3.3.1
- resolution: "fast-glob@npm:3.3.1"
- dependencies:
- "@nodelib/fs.stat": ^2.0.2
- "@nodelib/fs.walk": ^1.2.3
- glob-parent: ^5.1.2
- merge2: ^1.3.0
- micromatch: ^4.0.4
- checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5
- languageName: node
- linkType: hard
-
"fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9":
version: 3.2.12
resolution: "fast-glob@npm:3.2.12"
@@ -27936,6 +27806,21 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
+"glob@npm:10.3.10":
+ version: 10.3.10
+ resolution: "glob@npm:10.3.10"
+ dependencies:
+ foreground-child: ^3.1.0
+ jackspeak: ^2.3.5
+ minimatch: ^9.0.1
+ minipass: ^5.0.0 || ^6.0.2 || ^7.0.0
+ path-scurry: ^1.10.1
+ bin:
+ glob: dist/esm/bin.mjs
+ checksum: 4f2fe2511e157b5a3f525a54092169a5f92405f24d2aed3142f4411df328baca13059f4182f1db1bf933e2c69c0bd89e57ae87edd8950cba8c7ccbe84f721cf3
+ languageName: node
+ linkType: hard
+
"glob@npm:7.1.2":
version: 7.1.2
resolution: "glob@npm:7.1.2"
@@ -30845,6 +30730,19 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
+"jackspeak@npm:^2.3.5":
+ version: 2.3.6
+ resolution: "jackspeak@npm:2.3.6"
+ dependencies:
+ "@isaacs/cliui": ^8.0.2
+ "@pkgjs/parseargs": ^0.11.0
+ dependenciesMeta:
+ "@pkgjs/parseargs":
+ optional: true
+ checksum: 57d43ad11eadc98cdfe7496612f6bbb5255ea69fe51ea431162db302c2a11011642f50cfad57288bd0aea78384a0612b16e131944ad8ecd09d619041c8531b54
+ languageName: node
+ linkType: hard
+
"jackspeak@npm:^3.1.2":
version: 3.4.3
resolution: "jackspeak@npm:3.4.3"
@@ -39953,6 +39851,19 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
+"react-intersection-observer@npm:^9.15.1":
+ version: 9.15.1
+ resolution: "react-intersection-observer@npm:9.15.1"
+ peerDependencies:
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ checksum: 9769b06f065a246c2e477ad6a4ffeeb66c0c00098f094980f123df4ef1e09067b8d4b9f88d5f8e3a6de747c384b02452d0ac8cb91fff7093c15b8375ae097166
+ languageName: node
+ linkType: hard
+
"react-is@npm:18.0.0":
version: 18.0.0
resolution: "react-is@npm:18.0.0"
@@ -40328,18 +40239,6 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"react-visibility-sensor@npm:5.1.1":
- version: 5.1.1
- resolution: "react-visibility-sensor@npm:5.1.1"
- dependencies:
- prop-types: ^15.7.2
- peerDependencies:
- react: ">=16.0.0"
- react-dom: ">=16.0.0"
- checksum: ebce7bc743071930a2dd333a041c4a99aac24d5059c47a52eff25a8d81ab9307fadc87b8a6655ebb3154f5c1ceafcc309ae04ee07a7d5fad2949a6903d15acd5
- languageName: node
- linkType: hard
-
"react@npm:^19.0.0":
version: 19.0.0
resolution: "react@npm:19.0.0"
@@ -43580,13 +43479,6 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
-"stylis@npm:4.2.0":
- version: 4.2.0
- resolution: "stylis@npm:4.2.0"
- checksum: 0eb6cc1b866dc17a6037d0a82ac7fa877eba6a757443e79e7c4f35bacedbf6421fadcab4363b39667b43355cbaaa570a3cde850f776498e5450f32ed2f9b7584
- languageName: node
- linkType: hard
-
"success-symbol@npm:^0.1.0":
version: 0.1.0
resolution: "success-symbol@npm:0.1.0"