@impulse-ui-native/toast 16.0.0 → 17.0.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/README.md
CHANGED
|
@@ -117,10 +117,7 @@ The duration timer starts when status reaches open.
|
|
|
117
117
|
|
|
118
118
|
## Theme motion and action typography
|
|
119
119
|
|
|
120
|
-
`
|
|
121
|
-
the transitions (180 ms, 150 ms, and 220 ms by default).
|
|
122
|
-
`actionFontWeight` defaults to the primitive theme semi-bold weight. The
|
|
123
|
-
`duration` prop still controls auto-dismiss independently of animation timing.
|
|
120
|
+
Toast uses critically damped springs for entry, exit, and stack movement. `enterDuration` / `exitDuration` / `stackDuration` are perceptual durations (260 / 220 / 220 ms). Stack scaling originates at the screen edge matching placement. The dismissal timer starts after entry settles. `duration` controls auto-dismiss independently of animation timing. `actionFontWeight` defaults to the primitive theme semi-bold weight.
|
|
124
121
|
|
|
125
122
|
## Repository palette consistency
|
|
126
123
|
|
|
@@ -5,7 +5,7 @@ import Animated, {
|
|
|
5
5
|
cancelAnimation,
|
|
6
6
|
useAnimatedStyle,
|
|
7
7
|
useSharedValue,
|
|
8
|
-
|
|
8
|
+
withSpring
|
|
9
9
|
} from "react-native-reanimated";
|
|
10
10
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
11
11
|
import { OverlayOrder, useOverlayLayer } from "@impulse-ui-native/overlay";
|
|
@@ -35,7 +35,7 @@ const ToastRoot = memo(function ToastRoot2(props) {
|
|
|
35
35
|
);
|
|
36
36
|
const animatedDepth = useSharedValue(stackDepth);
|
|
37
37
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
38
|
-
opacity: progress.value,
|
|
38
|
+
opacity: Math.max(0, Math.min(1, progress.value)),
|
|
39
39
|
transform: [
|
|
40
40
|
{
|
|
41
41
|
translateY: (1 - progress.value) * (placement === "top" ? -edgeOffset : edgeOffset) + animatedDepth.value * tokens.gap
|
|
@@ -58,7 +58,7 @@ const ToastRoot = memo(function ToastRoot2(props) {
|
|
|
58
58
|
left: insets.left + tokens.edgeOffset,
|
|
59
59
|
right: insets.right + tokens.edgeOffset,
|
|
60
60
|
[placement]: insets[placement] + (placement === "top" ? tokens.topOffset : tokens.edgeOffset),
|
|
61
|
-
transformOrigin: "center top",
|
|
61
|
+
transformOrigin: placement === "top" ? "center top" : "center bottom",
|
|
62
62
|
zIndex: tokens.zIndexBase + layer
|
|
63
63
|
},
|
|
64
64
|
animatedStyle
|
|
@@ -66,11 +66,12 @@ const ToastRoot = memo(function ToastRoot2(props) {
|
|
|
66
66
|
[styles.container, insets, tokens, placement, layer, animatedStyle]
|
|
67
67
|
);
|
|
68
68
|
useEffect(() => {
|
|
69
|
-
animatedDepth.value =
|
|
70
|
-
duration: tokens.stackDuration
|
|
69
|
+
animatedDepth.value = withSpring(stackDepth, {
|
|
70
|
+
duration: tokens.stackDuration,
|
|
71
|
+
dampingRatio: 1
|
|
71
72
|
});
|
|
72
|
-
return () => cancelAnimation(animatedDepth);
|
|
73
73
|
}, [animatedDepth, stackDepth, tokens.stackDuration]);
|
|
74
|
+
useEffect(() => () => cancelAnimation(animatedDepth), [animatedDepth]);
|
|
74
75
|
if (!lifecycle.mounted) {
|
|
75
76
|
return null;
|
|
76
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/toast-root.tsx"],"sourcesContent":["import { memo, useEffect, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport Animated, {\n cancelAnimation,\n useAnimatedStyle,\n useSharedValue,\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/toast-root.tsx"],"sourcesContent":["import { memo, useEffect, useMemo } from \"react\";\r\nimport { StyleSheet } from \"react-native\";\r\nimport Animated, {\r\n cancelAnimation,\r\n useAnimatedStyle,\r\n useSharedValue,\r\n withSpring,\r\n} from \"react-native-reanimated\";\r\nimport { useSafeAreaInsets } from \"react-native-safe-area-context\";\r\n\r\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\r\nimport { OverlayOrder, useOverlayLayer } from \"@impulse-ui-native/overlay\";\r\nimport { useComponentsTokens, useThemedStyles } from \"@impulse-ui-native/theme\";\r\n\r\nimport type { ToastRootProps } from \"../types\";\r\nimport { DefaultDuration } from \"../constants/toast.constants\";\r\nimport { ToastContext } from \"../contexts/toast.context\";\r\nimport { useToastLifecycle } from \"../hooks/use-toast-lifecycle.hook\";\r\n\r\nexport const ToastRoot = memo(function ToastRoot(props: ToastRootProps) {\r\n const {\r\n id,\r\n children,\r\n placement = \"bottom\",\r\n tone = \"success\",\r\n duration = DefaultDuration,\r\n layer = 0,\r\n } = props;\r\n\r\n const insets = useSafeAreaInsets();\r\n\r\n const tokens = useComponentsTokens().toast;\r\n\r\n const lifecycle = useToastLifecycle(props, duration);\r\n const toastLayer = useOverlayLayer(id, undefined, OverlayOrder.NewestFirst);\r\n const styles = useThemedStyles(themedStyles);\r\n const { progress } = lifecycle;\r\n const edgeOffset = tokens.edgeOffset;\r\n const stackDepth = Math.min(\r\n Math.max(0, toastLayer),\r\n Math.max(0, tokens.stackLimit - 1),\r\n );\r\n const animatedDepth = useSharedValue(stackDepth);\r\n const animatedStyle = useAnimatedStyle(() => ({\r\n opacity: Math.max(0, Math.min(1, progress.value)),\r\n transform: [\r\n {\r\n translateY:\r\n (1 - progress.value) *\r\n (placement === \"top\" ? -edgeOffset : edgeOffset) +\r\n animatedDepth.value * tokens.gap,\r\n },\r\n { scale: Math.max(0, 1 - animatedDepth.value * tokens.stackScaleStep) },\r\n ],\r\n }));\r\n\r\n const context = useMemo(\r\n () => ({\r\n tone,\r\n interactive: lifecycle.interactive,\r\n close: lifecycle.close,\r\n }),\r\n [tone, lifecycle.interactive, lifecycle.close],\r\n );\r\n const containerStyle = useMemo(\r\n () => [\r\n styles.container,\r\n {\r\n left: insets.left + tokens.edgeOffset,\r\n right: insets.right + tokens.edgeOffset,\r\n [placement]:\r\n insets[placement] +\r\n (placement === \"top\" ? tokens.topOffset : tokens.edgeOffset),\r\n transformOrigin: placement === \"top\" ? \"center top\" : \"center bottom\",\r\n zIndex: tokens.zIndexBase + layer,\r\n },\r\n animatedStyle,\r\n ],\r\n [styles.container, insets, tokens, placement, layer, animatedStyle],\r\n );\r\n\r\n useEffect(() => {\r\n animatedDepth.value = withSpring(stackDepth, {\r\n duration: tokens.stackDuration,\r\n dampingRatio: 1,\r\n });\r\n }, [animatedDepth, stackDepth, tokens.stackDuration]);\r\n\r\n useEffect(() => () => cancelAnimation(animatedDepth), [animatedDepth]);\r\n\r\n if (!lifecycle.mounted) {\r\n return null;\r\n }\r\n\r\n return (\r\n <ToastContext.Provider value={context}>\r\n <Animated.View\r\n pointerEvents={lifecycle.interactive ? \"auto\" : \"none\"}\r\n style={containerStyle}\r\n >\r\n {children}\r\n </Animated.View>\r\n </ToastContext.Provider>\r\n );\r\n});\r\n\r\nfunction themedStyles(theme: AppTheme) {\r\n const tokens = theme.components.toast;\r\n\r\n return StyleSheet.create({\r\n container: {\r\n position: \"absolute\",\r\n flexDirection: \"row\",\r\n alignItems: \"center\",\r\n gap: tokens.gap,\r\n padding: tokens.padding,\r\n borderRadius: tokens.borderRadius,\r\n borderWidth: tokens.borderWidth,\r\n borderColor: tokens.borderColor,\r\n backgroundColor: tokens.backgroundColor,\r\n },\r\n });\r\n}\r\n"],"mappings":"AAgGM;AAhGN,SAAS,MAAM,WAAW,eAAe;AACzC,SAAS,kBAAkB;AAC3B,OAAO;AAAA,EACL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,yBAAyB;AAGlC,SAAS,cAAc,uBAAuB;AAC9C,SAAS,qBAAqB,uBAAuB;AAGrD,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,yBAAyB;AAE3B,MAAM,YAAY,KAAK,SAASA,WAAU,OAAuB;AACtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,IAAI;AAEJ,QAAM,SAAS,kBAAkB;AAEjC,QAAM,SAAS,oBAAoB,EAAE;AAErC,QAAM,YAAY,kBAAkB,OAAO,QAAQ;AACnD,QAAM,aAAa,gBAAgB,IAAI,QAAW,aAAa,WAAW;AAC1E,QAAM,SAAS,gBAAgB,YAAY;AAC3C,QAAM,EAAE,SAAS,IAAI;AACrB,QAAM,aAAa,OAAO;AAC1B,QAAM,aAAa,KAAK;AAAA,IACtB,KAAK,IAAI,GAAG,UAAU;AAAA,IACtB,KAAK,IAAI,GAAG,OAAO,aAAa,CAAC;AAAA,EACnC;AACA,QAAM,gBAAgB,eAAe,UAAU;AAC/C,QAAM,gBAAgB,iBAAiB,OAAO;AAAA,IAC5C,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,SAAS,KAAK,CAAC;AAAA,IAChD,WAAW;AAAA,MACT;AAAA,QACE,aACG,IAAI,SAAS,UACX,cAAc,QAAQ,CAAC,aAAa,cACvC,cAAc,QAAQ,OAAO;AAAA,MACjC;AAAA,MACA,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,cAAc,QAAQ,OAAO,cAAc,EAAE;AAAA,IACxE;AAAA,EACF,EAAE;AAEF,QAAM,UAAU;AAAA,IACd,OAAO;AAAA,MACL;AAAA,MACA,aAAa,UAAU;AAAA,MACvB,OAAO,UAAU;AAAA,IACnB;AAAA,IACA,CAAC,MAAM,UAAU,aAAa,UAAU,KAAK;AAAA,EAC/C;AACA,QAAM,iBAAiB;AAAA,IACrB,MAAM;AAAA,MACJ,OAAO;AAAA,MACP;AAAA,QACE,MAAM,OAAO,OAAO,OAAO;AAAA,QAC3B,OAAO,OAAO,QAAQ,OAAO;AAAA,QAC7B,CAAC,SAAS,GACR,OAAO,SAAS,KACf,cAAc,QAAQ,OAAO,YAAY,OAAO;AAAA,QACnD,iBAAiB,cAAc,QAAQ,eAAe;AAAA,QACtD,QAAQ,OAAO,aAAa;AAAA,MAC9B;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,OAAO,WAAW,QAAQ,QAAQ,WAAW,OAAO,aAAa;AAAA,EACpE;AAEA,YAAU,MAAM;AACd,kBAAc,QAAQ,WAAW,YAAY;AAAA,MAC3C,UAAU,OAAO;AAAA,MACjB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,YAAY,OAAO,aAAa,CAAC;AAEpD,YAAU,MAAM,MAAM,gBAAgB,aAAa,GAAG,CAAC,aAAa,CAAC;AAErE,MAAI,CAAC,UAAU,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,SAC5B;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACC,eAAe,UAAU,cAAc,SAAS;AAAA,MAChD,OAAO;AAAA,MAEN;AAAA;AAAA,EACH,GACF;AAEJ,CAAC;AAED,SAAS,aAAa,OAAiB;AACrC,QAAM,SAAS,MAAM,WAAW;AAEhC,SAAO,WAAW,OAAO;AAAA,IACvB,WAAW;AAAA,MACT,UAAU;AAAA,MACV,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,KAAK,OAAO;AAAA,MACZ,SAAS,OAAO;AAAA,MAChB,cAAc,OAAO;AAAA,MACrB,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO;AAAA,MACpB,iBAAiB,OAAO;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;","names":["ToastRoot"]}
|
|
@@ -3,14 +3,14 @@ import { useEventCallback, useTimer } from "@impulse-ui-native/core";
|
|
|
3
3
|
import {
|
|
4
4
|
useOverlayContext,
|
|
5
5
|
useOverlayLifecycle,
|
|
6
|
-
|
|
6
|
+
useOverlaySpring
|
|
7
7
|
} from "@impulse-ui-native/overlay";
|
|
8
8
|
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
9
9
|
function useToastLifecycle(props, duration) {
|
|
10
10
|
const { id, open = true } = props;
|
|
11
11
|
const { store } = useOverlayContext();
|
|
12
12
|
const tokens = useComponentsTokens().toast;
|
|
13
|
-
const { options, progress } =
|
|
13
|
+
const { options, progress } = useOverlaySpring(tokens);
|
|
14
14
|
const lifecycle = useOverlayLifecycle({ ...props, open }, options);
|
|
15
15
|
const close = useEventCallback(() => store.close(id));
|
|
16
16
|
useTimer({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/use-toast-lifecycle.hook.ts"],"sourcesContent":["import { useMemo } from \"react\";\n\nimport { useEventCallback, useTimer } from \"@impulse-ui-native/core\";\nimport {\n useOverlayContext,\n useOverlayLifecycle,\n
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-toast-lifecycle.hook.ts"],"sourcesContent":["import { useMemo } from \"react\";\r\n\r\nimport { useEventCallback, useTimer } from \"@impulse-ui-native/core\";\r\nimport {\r\n useOverlayContext,\r\n useOverlayLifecycle,\r\n useOverlaySpring,\r\n} from \"@impulse-ui-native/overlay\";\r\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\r\n\r\nimport type { ToastRootProps } from \"../types\";\r\n\r\nexport function useToastLifecycle(props: ToastRootProps, duration: number) {\r\n const { id, open = true } = props;\r\n const { store } = useOverlayContext();\r\n const tokens = useComponentsTokens().toast;\r\n const { options, progress } = useOverlaySpring(tokens);\r\n const lifecycle = useOverlayLifecycle({ ...props, open }, options);\r\n const close = useEventCallback(() => store.close(id));\r\n\r\n useTimer({\r\n enabled: lifecycle.status === \"open\" && open,\r\n duration,\r\n callback: close,\r\n pauseOnBackground: true,\r\n });\r\n\r\n return useMemo(\r\n () => ({ ...lifecycle, progress, close }),\r\n [lifecycle, progress, close],\r\n );\r\n}\r\n"],"mappings":"AAAA,SAAS,eAAe;AAExB,SAAS,kBAAkB,gBAAgB;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AAI7B,SAAS,kBAAkB,OAAuB,UAAkB;AACzE,QAAM,EAAE,IAAI,OAAO,KAAK,IAAI;AAC5B,QAAM,EAAE,MAAM,IAAI,kBAAkB;AACpC,QAAM,SAAS,oBAAoB,EAAE;AACrC,QAAM,EAAE,SAAS,SAAS,IAAI,iBAAiB,MAAM;AACrD,QAAM,YAAY,oBAAoB,EAAE,GAAG,OAAO,KAAK,GAAG,OAAO;AACjE,QAAM,QAAQ,iBAAiB,MAAM,MAAM,MAAM,EAAE,CAAC;AAEpD,WAAS;AAAA,IACP,SAAS,UAAU,WAAW,UAAU;AAAA,IACxC;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB,CAAC;AAED,SAAO;AAAA,IACL,OAAO,EAAE,GAAG,WAAW,UAAU,MAAM;AAAA,IACvC,CAAC,WAAW,UAAU,KAAK;AAAA,EAC7B;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@impulse-ui-native/toast",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.0",
|
|
4
4
|
"description": "Compound toast notifications for ImpulseUI Native.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
],
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@impulse-ui-native/theme": "
|
|
31
|
-
"@impulse-ui-native/overlay": "
|
|
32
|
-
"@impulse-ui-native/primitives": "
|
|
33
|
-
"@impulse-ui-native/core": "
|
|
34
|
-
"@impulse-ui-native/icon": "
|
|
30
|
+
"@impulse-ui-native/theme": "17.0.0",
|
|
31
|
+
"@impulse-ui-native/overlay": "17.0.0",
|
|
32
|
+
"@impulse-ui-native/primitives": "17.0.0",
|
|
33
|
+
"@impulse-ui-native/core": "17.0.0",
|
|
34
|
+
"@impulse-ui-native/icon": "17.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@impulse-ui-native/eslint-config": "1.0.0",
|