@impulse-ui-native/toast 15.0.5 → 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
@@ -1,134 +1,131 @@
1
- # @impulse-ui-native/toast
2
-
3
- Native toast notifications built from theme tokens and the overlay lifecycle.
4
-
5
- ## Installation
6
-
7
- `pnpm add @impulse-ui-native/toast`
8
-
9
- Install the React, React Native, react-native-svg, react-native-safe-area-context, react-native-reanimated (4 or newer) and react-native-worklets peers. Configure Reanimated and Worklets in the native host. Place a ThemeProvider, SafeAreaProvider, OverlayProvider and OverlayHost at the application root, like Flyout. Keep OverlayHost outside scrolling content.
10
-
11
- ## Ready-made Toast and imperative opening
12
-
13
- ```tsx
14
- import type { OverlayComponentProps } from "@impulse-ui-native/overlay";
15
- import { OverlayStore } from "@impulse-ui-native/overlay";
16
- import { Toast } from "@impulse-ui-native/toast";
17
-
18
- export const overlays = new OverlayStore(); // Supply to OverlayProvider.
19
-
20
- function SuccessToast(props: OverlayComponentProps) {
21
- return <Toast {...props} tone="success" placement="bottom" duration={4000} />;
22
- }
23
-
24
- function SavedContent() {
25
- return <Toast.Description>Your workspace is up to date.</Toast.Description>;
26
- }
27
-
28
- // Register once for a reusable singleton, like Flyout.
29
- const saved = overlays.register({
30
- id: "saved",
31
- Component: SuccessToast,
32
- Content: SavedContent,
33
- title: "Changes saved",
34
- });
35
- saved.open();
36
- saved.close();
37
-
38
- // Register on each invocation to open independent notifications.
39
- function notifySaved() {
40
- return overlays
41
- .register({
42
- id: "saved",
43
- Component: SuccessToast,
44
- Content: SavedContent,
45
- title: "Changes saved",
46
- })
47
- .open();
48
- }
49
- ```
50
-
51
- Content props remain typed by `OverlayStore.register`, and `open` returns the overlay ID. Use `overlays.close(id)` to close an entry. A singleton controller ignores another open until its current entry has been removed after exit.
52
-
53
- Like Input, `Toast` assembles its default UI from composable parts. It supplies the semantic icon and close icon, renders `title` and `description`, and places children inside `Toast.Content`. Pass `action` and `actionProps` to add an action; `actionProps` accepts `onPress`, `disabled`, `loading`, and `closeOnPress`. Use `hideIcon` or `hideClose` to omit those default parts.
54
-
55
- ```tsx
56
- <Toast
57
- id="saved"
58
- title="Changes saved"
59
- description="Your workspace is up to date."
60
- action="Undo"
61
- actionProps={undoActionProps}
62
- />
63
- ```
64
-
65
- Supply a stable `undoActionProps` object with your `onPress` handler.
66
-
67
- ## Custom composition
68
-
69
- Composable parts render the children you supply. They do not create fallback icons or content. Use `Toast.Root` when you want to assemble the whole notification yourself:
70
-
71
- ```tsx
72
- import { Icon } from "@impulse-ui-native/icon";
73
- import { XIcon } from "@impulse-ui-native/icon/icons/x";
74
-
75
- <Toast.Root id="custom" duration={0}>
76
- <Toast.Content>
77
- <Toast.Title>Custom notification</Toast.Title>
78
- <Toast.Description>Choose your own content and actions.</Toast.Description>
79
- </Toast.Content>
80
- <Toast.Close>
81
- <Icon icon={XIcon} size={18} />
82
- </Toast.Close>
83
- </Toast.Root>;
84
- ```
85
-
86
- ## Parts
87
-
88
- - `Toast`: ready-made component with semantic icon, title/description, optional action, and close button.
89
- - `Toast.Root`: overlay lifecycle and themed surface; renders only supplied children. Defaults: bottom placement, success tone, 4000 ms duration. The inherited overlay title is rendered by `Toast`, not Root.
90
- - `Toast.Content`: flexible vertical text container.
91
- - `Toast.Title` and `Toast.Description`: token-aware typography with native text props.
92
- - `Toast.Icon`: themed semantic icon container; supply the icon as children.
93
- - `Toast.Action`: runs onPress and dismisses by default; `closeOnPress={false}` keeps the toast open. Disabled and loading actions block presses.
94
- - `Toast.Close`: dismiss action that renders supplied children, with an optional onPress callback.
95
-
96
- ## Overlay lifecycle
97
-
98
- OverlayStore owns the entries and their open/close state. Toast adds no store, queue, or capacity limit. Each entry opens immediately at its placement, using the layer supplied by OverlayHost; newer entries at the same placement appear above older ones. There is no modal backdrop, so the surrounding application remains interactive.
99
-
100
- The timer starts after entry animation finishes, pauses when the app leaves the active state, and resumes with the remaining time. `duration={0}` (or a non-finite/non-positive duration) persists until dismissal. Use a persistent duration for messages that require a response.
101
-
102
- onOpen and onOpenFinished run during entry; onClose runs on dismissal, and onCloseFinished lets OverlayHost remove the entry after exit. Automatic dismissal calls the existing OverlayStore.close(id). Duration, foreground/background timer handling, and animation are component-owned. Unmounting cancels animation, timer and app-state subscriptions.
103
-
104
- Toasts fade and translate by the theme edge offset. Top toasts sit 8 px below the top safe-area inset, using the toast topOffset token; bottom and side gaps use the 16 px edgeOffset token. The newest toast is full size at the screen edge. Older toasts stack downward at both placements by the existing `gap` token and shrink by `stackScaleStep` (4%) per level. Changes to stack depth animate position and scale together over 220 ms, including moving forward when newer entries are removed. `stackLimit` defaults to five visual levels: scales are 100%, 96%, 92%, 88%, and 84%. All further toasts share the fifth level's scale and offset, behind newer entries; the limit does not discard or queue toasts. Component identity is the registered `Component`, including wrappers. Placements and IDs should remain stable for an entry's lifetime. Root is designed for imperative OverlayStore registration; use the returned controller to dismiss it.
105
-
106
- ## Theme
107
-
108
- Toast uses `theme.components.toast` for surfaces, geometry, typography, actions and semantic icon colors. Override those tokens through ThemeProvider's components prop, including a factory that derives custom values from the active light/dark theme. The default close icon uses closeIconSize (18) and closeColor (text.tertiary), matching Modal and Popover. Semantic icons retain their independent iconSize (24) and feedback colors. No additional toast provider or host is needed.
109
-
110
- ## Verification
111
-
112
- Use the Toast stories in the on-device Storybook host to verify rendering, touch interaction, timer pause/resume, and lifecycle cancellation on iOS and Android.
113
-
114
- Toast uses the shared useOverlayLifecycle hook from the overlay package.
115
- onStatusChange(id, status) reports opening, open, closing, and closed.
116
- The duration timer starts when status reaches open.
117
-
118
- ## Theme motion and action typography
119
-
120
- `components.toast.enterDuration`, `exitDuration`, and `stackDuration` configure
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.
124
-
125
- ## Repository palette consistency
126
-
127
- Toast keeps feedback tones (success, info, warning, error). The action foreground
128
- now follows the same feedback tone as its icon; disabled actions remain neutral.
129
- Custom action colors move to toast.tones[tone].actionColor. The elevated surface,
130
- title, description, and close control keep their neutral semantic roles.
131
-
132
- ## Agent and design reference
133
-
134
- Start with the [capability guide](../../docs/design-system/capabilities/toast.md) for supported exports, props, defaults, composition rules, setup, and recipes. Use the [component chooser](../../docs/design-system/component-chooser.md) to select a package. These references describe the repository source; verify your installed package version before copying examples.
1
+ # @impulse-ui-native/toast
2
+
3
+ Native toast notifications built from theme tokens and the overlay lifecycle.
4
+
5
+ ## Installation
6
+
7
+ `pnpm add @impulse-ui-native/toast`
8
+
9
+ Install the React, React Native, react-native-svg, react-native-safe-area-context, react-native-reanimated (4 or newer) and react-native-worklets peers. Configure Reanimated and Worklets in the native host. Place a ThemeProvider, SafeAreaProvider, OverlayProvider and OverlayHost at the application root, like Flyout. Keep OverlayHost outside scrolling content.
10
+
11
+ ## Ready-made Toast and imperative opening
12
+
13
+ ```tsx
14
+ import type { OverlayComponentProps } from "@impulse-ui-native/overlay";
15
+ import { OverlayStore } from "@impulse-ui-native/overlay";
16
+ import { Toast } from "@impulse-ui-native/toast";
17
+
18
+ export const overlays = new OverlayStore(); // Supply to OverlayProvider.
19
+
20
+ function SuccessToast(props: OverlayComponentProps) {
21
+ return <Toast {...props} tone="success" placement="bottom" duration={4000} />;
22
+ }
23
+
24
+ function SavedContent() {
25
+ return <Toast.Description>Your workspace is up to date.</Toast.Description>;
26
+ }
27
+
28
+ // Register once for a reusable singleton, like Flyout.
29
+ const saved = overlays.register({
30
+ id: "saved",
31
+ Component: SuccessToast,
32
+ Content: SavedContent,
33
+ title: "Changes saved",
34
+ });
35
+ saved.open();
36
+ saved.close();
37
+
38
+ // Register on each invocation to open independent notifications.
39
+ function notifySaved() {
40
+ return overlays
41
+ .register({
42
+ id: "saved",
43
+ Component: SuccessToast,
44
+ Content: SavedContent,
45
+ title: "Changes saved",
46
+ })
47
+ .open();
48
+ }
49
+ ```
50
+
51
+ Content props remain typed by `OverlayStore.register`, and `open` returns the overlay ID. Use `overlays.close(id)` to close an entry. A singleton controller ignores another open until its current entry has been removed after exit.
52
+
53
+ Like Input, `Toast` assembles its default UI from composable parts. It supplies the semantic icon and close icon, renders `title` and `description`, and places children inside `Toast.Content`. Pass `action` and `actionProps` to add an action; `actionProps` accepts `onPress`, `disabled`, `loading`, and `closeOnPress`. Use `hideIcon` or `hideClose` to omit those default parts.
54
+
55
+ ```tsx
56
+ <Toast
57
+ id="saved"
58
+ title="Changes saved"
59
+ description="Your workspace is up to date."
60
+ action="Undo"
61
+ actionProps={undoActionProps}
62
+ />
63
+ ```
64
+
65
+ Supply a stable `undoActionProps` object with your `onPress` handler.
66
+
67
+ ## Custom composition
68
+
69
+ Composable parts render the children you supply. They do not create fallback icons or content. Use `Toast.Root` when you want to assemble the whole notification yourself:
70
+
71
+ ```tsx
72
+ import { Icon } from "@impulse-ui-native/icon";
73
+ import { XIcon } from "@impulse-ui-native/icon/icons/x";
74
+
75
+ <Toast.Root id="custom" duration={0}>
76
+ <Toast.Content>
77
+ <Toast.Title>Custom notification</Toast.Title>
78
+ <Toast.Description>Choose your own content and actions.</Toast.Description>
79
+ </Toast.Content>
80
+ <Toast.Close>
81
+ <Icon icon={XIcon} size={18} />
82
+ </Toast.Close>
83
+ </Toast.Root>;
84
+ ```
85
+
86
+ ## Parts
87
+
88
+ - `Toast`: ready-made component with semantic icon, title/description, optional action, and close button.
89
+ - `Toast.Root`: overlay lifecycle and themed surface; renders only supplied children. Defaults: bottom placement, success tone, 4000 ms duration. The inherited overlay title is rendered by `Toast`, not Root.
90
+ - `Toast.Content`: flexible vertical text container.
91
+ - `Toast.Title` and `Toast.Description`: token-aware typography with native text props.
92
+ - `Toast.Icon`: themed semantic icon container; supply the icon as children.
93
+ - `Toast.Action`: runs onPress and dismisses by default; `closeOnPress={false}` keeps the toast open. Disabled and loading actions block presses.
94
+ - `Toast.Close`: dismiss action that renders supplied children, with an optional onPress callback.
95
+
96
+ ## Overlay lifecycle
97
+
98
+ OverlayStore owns the entries and their open/close state. Toast adds no store, queue, or capacity limit. Each entry opens immediately at its placement, using the layer supplied by OverlayHost; newer entries at the same placement appear above older ones. There is no modal backdrop, so the surrounding application remains interactive.
99
+
100
+ The timer starts after entry animation finishes, pauses when the app leaves the active state, and resumes with the remaining time. `duration={0}` (or a non-finite/non-positive duration) persists until dismissal. Use a persistent duration for messages that require a response.
101
+
102
+ onOpen and onOpenFinished run during entry; onClose runs on dismissal, and onCloseFinished lets OverlayHost remove the entry after exit. Automatic dismissal calls the existing OverlayStore.close(id). Duration, foreground/background timer handling, and animation are component-owned. Unmounting cancels animation, timer and app-state subscriptions.
103
+
104
+ Toasts fade and translate by the theme edge offset. Top toasts sit 8 px below the top safe-area inset, using the toast topOffset token; bottom and side gaps use the 16 px edgeOffset token. The newest toast is full size at the screen edge. Older toasts stack downward at both placements by the existing `gap` token and shrink by `stackScaleStep` (4%) per level. Changes to stack depth animate position and scale together over 220 ms, including moving forward when newer entries are removed. `stackLimit` defaults to five visual levels: scales are 100%, 96%, 92%, 88%, and 84%. All further toasts share the fifth level's scale and offset, behind newer entries; the limit does not discard or queue toasts. Component identity is the registered `Component`, including wrappers. Placements and IDs should remain stable for an entry's lifetime. Root is designed for imperative OverlayStore registration; use the returned controller to dismiss it.
105
+
106
+ ## Theme
107
+
108
+ Toast uses `theme.components.toast` for surfaces, geometry, typography, actions and semantic icon colors. Override those tokens through ThemeProvider's components prop, including a factory that derives custom values from the active light/dark theme. The default close icon uses closeIconSize (18) and closeColor (text.tertiary), matching Modal and Popover. Semantic icons retain their independent iconSize (24) and feedback colors. No additional toast provider or host is needed.
109
+
110
+ ## Verification
111
+
112
+ Use the Toast stories in the on-device Storybook host to verify rendering, touch interaction, timer pause/resume, and lifecycle cancellation on iOS and Android.
113
+
114
+ Toast uses the shared useOverlayLifecycle hook from the overlay package.
115
+ onStatusChange(id, status) reports opening, open, closing, and closed.
116
+ The duration timer starts when status reaches open.
117
+
118
+ ## Theme motion and action typography
119
+
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.
121
+
122
+ ## Repository palette consistency
123
+
124
+ Toast keeps feedback tones (success, info, warning, error). The action foreground
125
+ now follows the same feedback tone as its icon; disabled actions remain neutral.
126
+ Custom action colors move to toast.tones[tone].actionColor. The elevated surface,
127
+ title, description, and close control keep their neutral semantic roles.
128
+
129
+ ## Agent and design reference
130
+
131
+ Start with the [capability guide](../../docs/design-system/capabilities/toast.md) for supported exports, props, defaults, composition rules, setup, and recipes. Use the [component chooser](../../docs/design-system/component-chooser.md) to select a package. These references describe the repository source; verify your installed package version before copying examples.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/toast-action.tsx"],"sourcesContent":["import type { GestureResponderEvent } from \"react-native\";\nimport { memo, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\n\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\nimport { useEventCallback } from \"@impulse-ui-native/core\";\nimport { Pressable, Typography } from \"@impulse-ui-native/primitives\";\nimport { useComponentsTokens, useThemedStyles } from \"@impulse-ui-native/theme\";\n\nimport type { ToastActionProps } from \"../types\";\nimport type { ToastActionThemeProps } from \"../types/toast-theme.types\";\nimport { useToastContext } from \"../hooks/use-toast-context.hook\";\n\nexport const ToastAction = memo(function ToastAction({\n children,\n closeOnPress = true,\n onPress,\n disabled,\n loading,\n style,\n ...props\n}: ToastActionProps) {\n const { interactive, close, tone } = useToastContext();\n const tokens = useComponentsTokens().toast;\n\n const blocked = disabled === true || loading === true || !interactive;\n\n const styles = useThemedStyles(themedStyles, { blocked, tone }, [\n blocked,\n tone,\n ]);\n\n const actionStyle = useMemo(\n () => [styles.action, style],\n [styles.action, style],\n );\n\n const handlePress = useEventCallback((event: GestureResponderEvent) => {\n if (blocked) {\n return;\n }\n\n onPress?.(event);\n\n if (closeOnPress) {\n close();\n }\n });\n\n return (\n <Pressable\n hitSlop={styles.action.paddingHorizontal}\n {...props}\n disabled={blocked}\n onPress={handlePress}\n style={actionStyle}\n >\n {typeof children === \"string\" ? (\n <Typography.Label\n fontWeight={tokens.actionFontWeight}\n style={styles.label}\n >\n {children}\n </Typography.Label>\n ) : (\n children\n )}\n </Pressable>\n );\n});\n\nfunction themedStyles(\n theme: AppTheme,\n { blocked, tone }: ToastActionThemeProps,\n) {\n const tokens = theme.components.toast;\n\n return StyleSheet.create({\n action: {\n minHeight: tokens.actionMinSize,\n minWidth: tokens.actionMinSize,\n alignItems: \"center\",\n justifyContent: \"center\",\n paddingHorizontal: tokens.gap,\n },\n label: {\n color: blocked ? tokens.disabledColor : tokens.tones[tone].actionColor,\n },\n });\n}\n"],"mappings":"AA0DQ;AAzDR,SAAS,MAAM,eAAe;AAC9B,SAAS,kBAAkB;AAG3B,SAAS,wBAAwB;AACjC,SAAS,WAAW,kBAAkB;AACtC,SAAS,qBAAqB,uBAAuB;AAIrD,SAAS,uBAAuB;AAEzB,MAAM,cAAc,KAAK,SAASA,aAAY;AAAA,EACnD;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqB;AACnB,QAAM,EAAE,aAAa,OAAO,KAAK,IAAI,gBAAgB;AACrD,QAAM,SAAS,oBAAoB,EAAE;AAErC,QAAM,UAAU,aAAa,QAAQ,YAAY,QAAQ,CAAC;AAE1D,QAAM,SAAS,gBAAgB,cAAc,EAAE,SAAS,KAAK,GAAG;AAAA,IAC9D;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,MAAM,CAAC,OAAO,QAAQ,KAAK;AAAA,IAC3B,CAAC,OAAO,QAAQ,KAAK;AAAA,EACvB;AAEA,QAAM,cAAc,iBAAiB,CAAC,UAAiC;AACrE,QAAI,SAAS;AACX;AAAA,IACF;AAEA,cAAU,KAAK;AAEf,QAAI,cAAc;AAChB,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,OAAO,OAAO;AAAA,MACtB,GAAG;AAAA,MACJ,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO;AAAA,MAEN,iBAAO,aAAa,WACnB;AAAA,QAAC,WAAW;AAAA,QAAX;AAAA,UACC,YAAY,OAAO;AAAA,UACnB,OAAO,OAAO;AAAA,UAEb;AAAA;AAAA,MACH,IAEA;AAAA;AAAA,EAEJ;AAEJ,CAAC;AAED,SAAS,aACP,OACA,EAAE,SAAS,KAAK,GAChB;AACA,QAAM,SAAS,MAAM,WAAW;AAEhC,SAAO,WAAW,OAAO;AAAA,IACvB,QAAQ;AAAA,MACN,WAAW,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,mBAAmB,OAAO;AAAA,IAC5B;AAAA,IACA,OAAO;AAAA,MACL,OAAO,UAAU,OAAO,gBAAgB,OAAO,MAAM,IAAI,EAAE;AAAA,IAC7D;AAAA,EACF,CAAC;AACH;","names":["ToastAction"]}
1
+ {"version":3,"sources":["../../src/components/toast-action.tsx"],"sourcesContent":["import type { GestureResponderEvent } from \"react-native\";\r\nimport { memo, useMemo } from \"react\";\r\nimport { StyleSheet } from \"react-native\";\r\n\r\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\r\nimport { useEventCallback } from \"@impulse-ui-native/core\";\r\nimport { Pressable, Typography } from \"@impulse-ui-native/primitives\";\r\nimport { useComponentsTokens, useThemedStyles } from \"@impulse-ui-native/theme\";\r\n\r\nimport type { ToastActionProps } from \"../types\";\r\nimport type { ToastActionThemeProps } from \"../types/toast-theme.types\";\r\nimport { useToastContext } from \"../hooks/use-toast-context.hook\";\r\n\r\nexport const ToastAction = memo(function ToastAction({\r\n children,\r\n closeOnPress = true,\r\n onPress,\r\n disabled,\r\n loading,\r\n style,\r\n ...props\r\n}: ToastActionProps) {\r\n const { interactive, close, tone } = useToastContext();\r\n const tokens = useComponentsTokens().toast;\r\n\r\n const blocked = disabled === true || loading === true || !interactive;\r\n\r\n const styles = useThemedStyles(themedStyles, { blocked, tone }, [\r\n blocked,\r\n tone,\r\n ]);\r\n\r\n const actionStyle = useMemo(\r\n () => [styles.action, style],\r\n [styles.action, style],\r\n );\r\n\r\n const handlePress = useEventCallback((event: GestureResponderEvent) => {\r\n if (blocked) {\r\n return;\r\n }\r\n\r\n onPress?.(event);\r\n\r\n if (closeOnPress) {\r\n close();\r\n }\r\n });\r\n\r\n return (\r\n <Pressable\r\n hitSlop={styles.action.paddingHorizontal}\r\n {...props}\r\n disabled={blocked}\r\n onPress={handlePress}\r\n style={actionStyle}\r\n >\r\n {typeof children === \"string\" ? (\r\n <Typography.Label\r\n fontWeight={tokens.actionFontWeight}\r\n style={styles.label}\r\n >\r\n {children}\r\n </Typography.Label>\r\n ) : (\r\n children\r\n )}\r\n </Pressable>\r\n );\r\n});\r\n\r\nfunction themedStyles(\r\n theme: AppTheme,\r\n { blocked, tone }: ToastActionThemeProps,\r\n) {\r\n const tokens = theme.components.toast;\r\n\r\n return StyleSheet.create({\r\n action: {\r\n minHeight: tokens.actionMinSize,\r\n minWidth: tokens.actionMinSize,\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n paddingHorizontal: tokens.gap,\r\n },\r\n label: {\r\n color: blocked ? tokens.disabledColor : tokens.tones[tone].actionColor,\r\n },\r\n });\r\n}\r\n"],"mappings":"AA0DQ;AAzDR,SAAS,MAAM,eAAe;AAC9B,SAAS,kBAAkB;AAG3B,SAAS,wBAAwB;AACjC,SAAS,WAAW,kBAAkB;AACtC,SAAS,qBAAqB,uBAAuB;AAIrD,SAAS,uBAAuB;AAEzB,MAAM,cAAc,KAAK,SAASA,aAAY;AAAA,EACnD;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAqB;AACnB,QAAM,EAAE,aAAa,OAAO,KAAK,IAAI,gBAAgB;AACrD,QAAM,SAAS,oBAAoB,EAAE;AAErC,QAAM,UAAU,aAAa,QAAQ,YAAY,QAAQ,CAAC;AAE1D,QAAM,SAAS,gBAAgB,cAAc,EAAE,SAAS,KAAK,GAAG;AAAA,IAC9D;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,MAAM,CAAC,OAAO,QAAQ,KAAK;AAAA,IAC3B,CAAC,OAAO,QAAQ,KAAK;AAAA,EACvB;AAEA,QAAM,cAAc,iBAAiB,CAAC,UAAiC;AACrE,QAAI,SAAS;AACX;AAAA,IACF;AAEA,cAAU,KAAK;AAEf,QAAI,cAAc;AAChB,YAAM;AAAA,IACR;AAAA,EACF,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,OAAO,OAAO;AAAA,MACtB,GAAG;AAAA,MACJ,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO;AAAA,MAEN,iBAAO,aAAa,WACnB;AAAA,QAAC,WAAW;AAAA,QAAX;AAAA,UACC,YAAY,OAAO;AAAA,UACnB,OAAO,OAAO;AAAA,UAEb;AAAA;AAAA,MACH,IAEA;AAAA;AAAA,EAEJ;AAEJ,CAAC;AAED,SAAS,aACP,OACA,EAAE,SAAS,KAAK,GAChB;AACA,QAAM,SAAS,MAAM,WAAW;AAEhC,SAAO,WAAW,OAAO;AAAA,IACvB,QAAQ;AAAA,MACN,WAAW,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,mBAAmB,OAAO;AAAA,IAC5B;AAAA,IACA,OAAO;AAAA,MACL,OAAO,UAAU,OAAO,gBAAgB,OAAO,MAAM,IAAI,EAAE;AAAA,IAC7D;AAAA,EACF,CAAC;AACH;","names":["ToastAction"]}
@@ -5,7 +5,7 @@ import Animated, {
5
5
  cancelAnimation,
6
6
  useAnimatedStyle,
7
7
  useSharedValue,
8
- withTiming
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 = withTiming(stackDepth, {
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 withTiming,\n} from \"react-native-reanimated\";\nimport { useSafeAreaInsets } from \"react-native-safe-area-context\";\n\nimport type { AppTheme } from \"@impulse-ui-native/theme\";\nimport { OverlayOrder, useOverlayLayer } from \"@impulse-ui-native/overlay\";\nimport { useComponentsTokens, useThemedStyles } from \"@impulse-ui-native/theme\";\n\nimport type { ToastRootProps } from \"../types\";\nimport { DefaultDuration } from \"../constants/toast.constants\";\nimport { ToastContext } from \"../contexts/toast.context\";\nimport { useToastLifecycle } from \"../hooks/use-toast-lifecycle.hook\";\n\nexport const ToastRoot = memo(function ToastRoot(props: ToastRootProps) {\n const {\n id,\n children,\n placement = \"bottom\",\n tone = \"success\",\n duration = DefaultDuration,\n layer = 0,\n } = props;\n\n const insets = useSafeAreaInsets();\n\n const tokens = useComponentsTokens().toast;\n\n const lifecycle = useToastLifecycle(props, duration);\n const toastLayer = useOverlayLayer(id, undefined, OverlayOrder.NewestFirst);\n const styles = useThemedStyles(themedStyles);\n const { progress } = lifecycle;\n const edgeOffset = tokens.edgeOffset;\n const stackDepth = Math.min(\n Math.max(0, toastLayer),\n Math.max(0, tokens.stackLimit - 1),\n );\n const animatedDepth = useSharedValue(stackDepth);\n const animatedStyle = useAnimatedStyle(() => ({\n opacity: progress.value,\n transform: [\n {\n translateY:\n (1 - progress.value) *\n (placement === \"top\" ? -edgeOffset : edgeOffset) +\n animatedDepth.value * tokens.gap,\n },\n { scale: Math.max(0, 1 - animatedDepth.value * tokens.stackScaleStep) },\n ],\n }));\n\n const context = useMemo(\n () => ({\n tone,\n interactive: lifecycle.interactive,\n close: lifecycle.close,\n }),\n [tone, lifecycle.interactive, lifecycle.close],\n );\n const containerStyle = useMemo(\n () => [\n styles.container,\n {\n left: insets.left + tokens.edgeOffset,\n right: insets.right + tokens.edgeOffset,\n [placement]:\n insets[placement] +\n (placement === \"top\" ? tokens.topOffset : tokens.edgeOffset),\n transformOrigin: \"center top\",\n zIndex: tokens.zIndexBase + layer,\n },\n animatedStyle,\n ],\n [styles.container, insets, tokens, placement, layer, animatedStyle],\n );\n\n useEffect(() => {\n animatedDepth.value = withTiming(stackDepth, {\n duration: tokens.stackDuration,\n });\n\n return () => cancelAnimation(animatedDepth);\n }, [animatedDepth, stackDepth, tokens.stackDuration]);\n\n if (!lifecycle.mounted) {\n return null;\n }\n\n return (\n <ToastContext.Provider value={context}>\n <Animated.View\n pointerEvents={lifecycle.interactive ? \"auto\" : \"none\"}\n style={containerStyle}\n >\n {children}\n </Animated.View>\n </ToastContext.Provider>\n );\n});\n\nfunction themedStyles(theme: AppTheme) {\n const tokens = theme.components.toast;\n\n return StyleSheet.create({\n container: {\n position: \"absolute\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: tokens.gap,\n padding: tokens.padding,\n borderRadius: tokens.borderRadius,\n borderWidth: tokens.borderWidth,\n borderColor: tokens.borderColor,\n backgroundColor: tokens.backgroundColor,\n },\n });\n}\n"],"mappings":"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","names":["ToastRoot"]}
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":"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","names":["ToastRoot"]}
@@ -3,14 +3,14 @@ import { useEventCallback, useTimer } from "@impulse-ui-native/core";
3
3
  import {
4
4
  useOverlayContext,
5
5
  useOverlayLifecycle,
6
- useOverlayTiming
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 } = useOverlayTiming(tokens);
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 useOverlayTiming,\n} from \"@impulse-ui-native/overlay\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { ToastRootProps } from \"../types\";\n\nexport function useToastLifecycle(props: ToastRootProps, duration: number) {\n const { id, open = true } = props;\n const { store } = useOverlayContext();\n const tokens = useComponentsTokens().toast;\n const { options, progress } = useOverlayTiming(tokens);\n const lifecycle = useOverlayLifecycle({ ...props, open }, options);\n const close = useEventCallback(() => store.close(id));\n\n useTimer({\n enabled: lifecycle.status === \"open\" && open,\n duration,\n callback: close,\n pauseOnBackground: true,\n });\n\n return useMemo(\n () => ({ ...lifecycle, progress, close }),\n [lifecycle, progress, close],\n );\n}\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":[]}
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": "15.0.5",
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": "15.0.5",
31
- "@impulse-ui-native/overlay": "15.0.5",
32
- "@impulse-ui-native/primitives": "15.0.5",
33
- "@impulse-ui-native/core": "15.0.5",
34
- "@impulse-ui-native/icon": "15.0.5"
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",