@impulse-ui-native/toast 0.0.0-stage → 6.1.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/LICENSE +21 -0
- package/README.md +111 -2
- package/dist/components/index.d.mts +20 -0
- package/dist/components/index.js +7 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/toast-action.d.mts +10 -0
- package/dist/components/toast-action.js +64 -0
- package/dist/components/toast-action.js.map +1 -0
- package/dist/components/toast-close.d.mts +10 -0
- package/dist/components/toast-close.js +13 -0
- package/dist/components/toast-close.js.map +1 -0
- package/dist/components/toast-content.d.mts +10 -0
- package/dist/components/toast-content.js +27 -0
- package/dist/components/toast-content.js.map +1 -0
- package/dist/components/toast-description.d.mts +10 -0
- package/dist/components/toast-description.js +22 -0
- package/dist/components/toast-description.js.map +1 -0
- package/dist/components/toast-icon.d.mts +10 -0
- package/dist/components/toast-icon.js +33 -0
- package/dist/components/toast-icon.js.map +1 -0
- package/dist/components/toast-parts.d.mts +18 -0
- package/dist/components/toast-parts.js +20 -0
- package/dist/components/toast-parts.js.map +1 -0
- package/dist/components/toast-root.d.mts +10 -0
- package/dist/components/toast-root.js +103 -0
- package/dist/components/toast-root.js.map +1 -0
- package/dist/components/toast-title.d.mts +10 -0
- package/dist/components/toast-title.js +22 -0
- package/dist/components/toast-title.js.map +1 -0
- package/dist/components/toast.d.mts +10 -0
- package/dist/components/toast.js +48 -0
- package/dist/components/toast.js.map +1 -0
- package/dist/constants/toast-icons.constants.d.mts +17 -0
- package/dist/constants/toast-icons.constants.js +14 -0
- package/dist/constants/toast-icons.constants.js.map +1 -0
- package/dist/constants/toast.constants.d.mts +6 -0
- package/dist/constants/toast.constants.js +11 -0
- package/dist/constants/toast.constants.js.map +1 -0
- package/dist/contexts/toast.context.d.mts +9 -0
- package/dist/contexts/toast.context.js +8 -0
- package/dist/contexts/toast.context.js.map +1 -0
- package/dist/hooks/use-toast-context.hook.d.mts +9 -0
- package/dist/hooks/use-toast-context.hook.js +13 -0
- package/dist/hooks/use-toast-context.hook.js.map +1 -0
- package/dist/hooks/use-toast-lifecycle.hook.d.mts +15 -0
- package/dist/hooks/use-toast-lifecycle.hook.js +129 -0
- package/dist/hooks/use-toast-lifecycle.hook.js.map +1 -0
- package/dist/hooks/use-toast-timer.hook.d.mts +3 -0
- package/dist/hooks/use-toast-timer.hook.js +50 -0
- package/dist/hooks/use-toast-timer.hook.js.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.mts +5 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/toast.types.d.mts +35 -0
- package/dist/types/toast.types.js +1 -0
- package/dist/types/toast.types.js.map +1 -0
- package/package.json +67 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ToastProps } from '../types/toast.types.mjs';
|
|
4
|
+
import '@impulse-ui-native/overlay';
|
|
5
|
+
import '@impulse-ui-native/primitives';
|
|
6
|
+
import '@impulse-ui-native/theme';
|
|
7
|
+
|
|
8
|
+
declare const ToastComponent: react.MemoExoticComponent<({ children, title, description, action, actionProps, tone, hideIcon, hideClose, ...props }: ToastProps) => react_jsx_runtime.JSX.Element>;
|
|
9
|
+
|
|
10
|
+
export { ToastComponent };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memo } from "react";
|
|
3
|
+
import { Icon } from "@impulse-ui-native/icon/components/icon";
|
|
4
|
+
import { XIcon } from "@impulse-ui-native/icon/icons/x";
|
|
5
|
+
import { useComponentsTokens } from "@impulse-ui-native/theme";
|
|
6
|
+
import { ToastIcons } from "../constants/toast-icons.constants";
|
|
7
|
+
import { Toast } from "./toast-parts";
|
|
8
|
+
const ToastComponent = memo(function ToastComponent2({
|
|
9
|
+
children,
|
|
10
|
+
title,
|
|
11
|
+
description,
|
|
12
|
+
action,
|
|
13
|
+
actionProps,
|
|
14
|
+
tone = "success",
|
|
15
|
+
hideIcon = false,
|
|
16
|
+
hideClose = false,
|
|
17
|
+
...props
|
|
18
|
+
}) {
|
|
19
|
+
const tokens = useComponentsTokens().toast;
|
|
20
|
+
return /* @__PURE__ */ jsxs(Toast.Root, { ...props, tone, children: [
|
|
21
|
+
!hideIcon ? /* @__PURE__ */ jsx(Toast.Icon, { children: /* @__PURE__ */ jsx(
|
|
22
|
+
Icon,
|
|
23
|
+
{
|
|
24
|
+
icon: ToastIcons[tone],
|
|
25
|
+
size: tokens.iconSize,
|
|
26
|
+
color: tokens.tones[tone].value
|
|
27
|
+
}
|
|
28
|
+
) }) : null,
|
|
29
|
+
/* @__PURE__ */ jsxs(Toast.Content, { children: [
|
|
30
|
+
title ? /* @__PURE__ */ jsx(Toast.Title, { children: title }) : null,
|
|
31
|
+
description !== null && description !== void 0 ? /* @__PURE__ */ jsx(Toast.Description, { children: description }) : null,
|
|
32
|
+
children
|
|
33
|
+
] }),
|
|
34
|
+
action !== null && action !== void 0 ? /* @__PURE__ */ jsx(Toast.Action, { ...actionProps, children: action }) : null,
|
|
35
|
+
!hideClose ? /* @__PURE__ */ jsx(Toast.Close, { children: /* @__PURE__ */ jsx(
|
|
36
|
+
Icon,
|
|
37
|
+
{
|
|
38
|
+
icon: XIcon,
|
|
39
|
+
size: tokens.iconSize,
|
|
40
|
+
color: tokens.descriptionColor
|
|
41
|
+
}
|
|
42
|
+
) }) : null
|
|
43
|
+
] });
|
|
44
|
+
});
|
|
45
|
+
export {
|
|
46
|
+
ToastComponent
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=toast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/toast.tsx"],"sourcesContent":["import { memo } from \"react\";\n\nimport { Icon } from \"@impulse-ui-native/icon/components/icon\";\nimport { XIcon } from \"@impulse-ui-native/icon/icons/x\";\nimport { useComponentsTokens } from \"@impulse-ui-native/theme\";\n\nimport type { ToastProps } from \"../types\";\nimport { ToastIcons } from \"../constants/toast-icons.constants\";\nimport { Toast } from \"./toast-parts\";\n\nexport const ToastComponent = memo(function ToastComponent({\n children,\n title,\n description,\n action,\n actionProps,\n tone = \"success\",\n hideIcon = false,\n hideClose = false,\n ...props\n}: ToastProps) {\n const tokens = useComponentsTokens().toast;\n\n return (\n <Toast.Root {...props} tone={tone}>\n {!hideIcon ? (\n <Toast.Icon>\n <Icon\n icon={ToastIcons[tone]}\n size={tokens.iconSize}\n color={tokens.tones[tone].value}\n />\n </Toast.Icon>\n ) : null}\n <Toast.Content>\n {title ? <Toast.Title>{title}</Toast.Title> : null}\n {description !== null && description !== undefined ? (\n <Toast.Description>{description}</Toast.Description>\n ) : null}\n {children}\n </Toast.Content>\n {action !== null && action !== undefined ? (\n <Toast.Action {...actionProps}>{action}</Toast.Action>\n ) : null}\n {!hideClose ? (\n <Toast.Close>\n <Icon\n icon={XIcon}\n size={tokens.iconSize}\n color={tokens.descriptionColor}\n />\n </Toast.Close>\n ) : null}\n </Toast.Root>\n );\n});\n"],"mappings":"AA2BU,cAOJ,YAPI;AA3BV,SAAS,YAAY;AAErB,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,2BAA2B;AAGpC,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AAEf,MAAM,iBAAiB,KAAK,SAASA,gBAAe;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,GAAG;AACL,GAAe;AACb,QAAM,SAAS,oBAAoB,EAAE;AAErC,SACE,qBAAC,MAAM,MAAN,EAAY,GAAG,OAAO,MACpB;AAAA,KAAC,WACA,oBAAC,MAAM,MAAN,EACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,WAAW,IAAI;AAAA,QACrB,MAAM,OAAO;AAAA,QACb,OAAO,OAAO,MAAM,IAAI,EAAE;AAAA;AAAA,IAC5B,GACF,IACE;AAAA,IACJ,qBAAC,MAAM,SAAN,EACE;AAAA,cAAQ,oBAAC,MAAM,OAAN,EAAa,iBAAM,IAAiB;AAAA,MAC7C,gBAAgB,QAAQ,gBAAgB,SACvC,oBAAC,MAAM,aAAN,EAAmB,uBAAY,IAC9B;AAAA,MACH;AAAA,OACH;AAAA,IACC,WAAW,QAAQ,WAAW,SAC7B,oBAAC,MAAM,QAAN,EAAc,GAAG,aAAc,kBAAO,IACrC;AAAA,IACH,CAAC,YACA,oBAAC,MAAM,OAAN,EACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA;AAAA,IAChB,GACF,IACE;AAAA,KACN;AAEJ,CAAC;","names":["ToastComponent"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { SvgProps } from 'react-native-svg';
|
|
4
|
+
|
|
5
|
+
type IconVariant = "bold" | "duotone" | "fill" | "light" | "regular" | "thin";
|
|
6
|
+
interface IconWrapperProps extends SvgProps {
|
|
7
|
+
variant?: IconVariant;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
declare const ToastIcons: {
|
|
11
|
+
info: react.MemoExoticComponent<(props: IconWrapperProps) => react_jsx_runtime.JSX.Element>;
|
|
12
|
+
success: react.MemoExoticComponent<(props: IconWrapperProps) => react_jsx_runtime.JSX.Element>;
|
|
13
|
+
warning: react.MemoExoticComponent<(props: IconWrapperProps) => react_jsx_runtime.JSX.Element>;
|
|
14
|
+
error: react.MemoExoticComponent<(props: IconWrapperProps) => react_jsx_runtime.JSX.Element>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { ToastIcons };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CheckCircleIcon } from "@impulse-ui-native/icon/icons/check-circle";
|
|
2
|
+
import { InfoIcon } from "@impulse-ui-native/icon/icons/info";
|
|
3
|
+
import { WarningIcon } from "@impulse-ui-native/icon/icons/warning";
|
|
4
|
+
import { XCircleIcon } from "@impulse-ui-native/icon/icons/x-circle";
|
|
5
|
+
const ToastIcons = {
|
|
6
|
+
info: InfoIcon,
|
|
7
|
+
success: CheckCircleIcon,
|
|
8
|
+
warning: WarningIcon,
|
|
9
|
+
error: XCircleIcon
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
ToastIcons
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=toast-icons.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/constants/toast-icons.constants.ts"],"sourcesContent":["import { CheckCircleIcon } from \"@impulse-ui-native/icon/icons/check-circle\";\nimport { InfoIcon } from \"@impulse-ui-native/icon/icons/info\";\nimport { WarningIcon } from \"@impulse-ui-native/icon/icons/warning\";\nimport { XCircleIcon } from \"@impulse-ui-native/icon/icons/x-circle\";\n\nexport const ToastIcons = {\n info: InfoIcon,\n success: CheckCircleIcon,\n warning: WarningIcon,\n error: XCircleIcon,\n};\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAErB,MAAM,aAAa;AAAA,EACxB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/constants/toast.constants.ts"],"sourcesContent":["export const DefaultDuration = 4000;\nexport const EnterDuration = 180;\nexport const ExitDuration = 150;\nexport const StackDuration = 220;\n"],"mappings":"AAAO,MAAM,kBAAkB;AACxB,MAAM,gBAAgB;AACtB,MAAM,eAAe;AACrB,MAAM,gBAAgB;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ToastContextValue } from '../types/toast.types.mjs';
|
|
3
|
+
import '@impulse-ui-native/overlay';
|
|
4
|
+
import '@impulse-ui-native/primitives';
|
|
5
|
+
import '@impulse-ui-native/theme';
|
|
6
|
+
|
|
7
|
+
declare const ToastContext: react.Context<ToastContextValue | undefined>;
|
|
8
|
+
|
|
9
|
+
export { ToastContext };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/contexts/toast.context.ts"],"sourcesContent":["import { createContext } from \"react\";\n\nimport type { ToastContextValue } from \"../types\";\n\nexport const ToastContext = createContext<ToastContextValue | undefined>(\n undefined,\n);\n"],"mappings":"AAAA,SAAS,qBAAqB;AAIvB,MAAM,eAAe;AAAA,EAC1B;AACF;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToastContextValue } from '../types/toast.types.mjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '@impulse-ui-native/overlay';
|
|
4
|
+
import '@impulse-ui-native/primitives';
|
|
5
|
+
import '@impulse-ui-native/theme';
|
|
6
|
+
|
|
7
|
+
declare function useToastContext(): ToastContextValue;
|
|
8
|
+
|
|
9
|
+
export { useToastContext };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { ToastContext } from "../contexts/toast.context";
|
|
3
|
+
function useToastContext() {
|
|
4
|
+
const context = useContext(ToastContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error("Toast children must be rendered inside Toast.Root");
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
useToastContext
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=use-toast-context.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-toast-context.hook.ts"],"sourcesContent":["import { useContext } from \"react\";\n\nimport { ToastContext } from \"../contexts/toast.context\";\n\nexport function useToastContext() {\n const context = useContext(ToastContext);\n\n if (!context) {\n throw new Error(\"Toast children must be rendered inside Toast.Root\");\n }\n\n return context;\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAE3B,SAAS,oBAAoB;AAEtB,SAAS,kBAAkB;AAChC,QAAM,UAAU,WAAW,YAAY;AAEvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_native_reanimated from 'react-native-reanimated';
|
|
2
|
+
import { ToastRootProps } from '../types/toast.types.mjs';
|
|
3
|
+
import 'react';
|
|
4
|
+
import '@impulse-ui-native/overlay';
|
|
5
|
+
import '@impulse-ui-native/primitives';
|
|
6
|
+
import '@impulse-ui-native/theme';
|
|
7
|
+
|
|
8
|
+
declare function useToastLifecycle(props: ToastRootProps, duration: number): {
|
|
9
|
+
progress: react_native_reanimated.SharedValue<number>;
|
|
10
|
+
close: () => void;
|
|
11
|
+
finished: boolean;
|
|
12
|
+
interactive: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { useToastLifecycle };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
cancelAnimation,
|
|
4
|
+
useSharedValue,
|
|
5
|
+
withTiming
|
|
6
|
+
} from "react-native-reanimated";
|
|
7
|
+
import { scheduleOnRN } from "react-native-worklets";
|
|
8
|
+
import { useEventCallback } from "@impulse-ui-native/core";
|
|
9
|
+
import { useOverlayContext } from "@impulse-ui-native/overlay";
|
|
10
|
+
import { EnterDuration, ExitDuration } from "../constants/toast.constants";
|
|
11
|
+
import { useToastTimer } from "./use-toast-timer.hook";
|
|
12
|
+
function useToastLifecycle(props, duration) {
|
|
13
|
+
const {
|
|
14
|
+
id,
|
|
15
|
+
open = true,
|
|
16
|
+
onOpen,
|
|
17
|
+
onOpenFinished,
|
|
18
|
+
onClose,
|
|
19
|
+
onCloseFinished
|
|
20
|
+
} = props;
|
|
21
|
+
const { store } = useOverlayContext();
|
|
22
|
+
const [entered, setEntered] = useState(false);
|
|
23
|
+
const [finished, setFinished] = useState(false);
|
|
24
|
+
const opened = useRef(false);
|
|
25
|
+
const closing = useRef(false);
|
|
26
|
+
const settled = useRef(false);
|
|
27
|
+
const transitionId = useRef(0);
|
|
28
|
+
const progress = useSharedValue(0);
|
|
29
|
+
const close = useEventCallback(() => store.close(id));
|
|
30
|
+
const notifyOpen = useEventCallback(() => onOpen?.(id));
|
|
31
|
+
const notifyEntered = useEventCallback(() => onOpenFinished?.(id));
|
|
32
|
+
const notifyClose = useEventCallback(() => onClose?.(id));
|
|
33
|
+
const finishClose = useEventCallback(() => {
|
|
34
|
+
if (settled.current) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
settled.current = true;
|
|
38
|
+
setFinished(true);
|
|
39
|
+
onCloseFinished?.(id);
|
|
40
|
+
});
|
|
41
|
+
const finishTransition = useEventCallback(
|
|
42
|
+
(completedTransitionId, entering) => {
|
|
43
|
+
if (transitionId.current !== completedTransitionId || settled.current) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (entering) {
|
|
47
|
+
setEntered(true);
|
|
48
|
+
notifyEntered();
|
|
49
|
+
} else {
|
|
50
|
+
finishClose();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
useToastTimer(entered && open && !finished, duration, close);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (finished) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const currentTransitionId = ++transitionId.current;
|
|
60
|
+
if (!open) {
|
|
61
|
+
const firstClose = !closing.current;
|
|
62
|
+
closing.current = true;
|
|
63
|
+
if (!opened.current) {
|
|
64
|
+
try {
|
|
65
|
+
if (firstClose) {
|
|
66
|
+
notifyClose();
|
|
67
|
+
}
|
|
68
|
+
} finally {
|
|
69
|
+
finishClose();
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
if (firstClose) {
|
|
75
|
+
notifyClose();
|
|
76
|
+
}
|
|
77
|
+
} finally {
|
|
78
|
+
progress.value = withTiming(
|
|
79
|
+
0,
|
|
80
|
+
{ duration: ExitDuration },
|
|
81
|
+
(completed) => {
|
|
82
|
+
if (completed) {
|
|
83
|
+
scheduleOnRN(finishTransition, currentTransitionId, false);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
return () => {
|
|
89
|
+
transitionId.current += 1;
|
|
90
|
+
cancelAnimation(progress);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const firstOpen = !opened.current;
|
|
94
|
+
opened.current = true;
|
|
95
|
+
try {
|
|
96
|
+
if (firstOpen) {
|
|
97
|
+
notifyOpen();
|
|
98
|
+
}
|
|
99
|
+
} finally {
|
|
100
|
+
progress.value = withTiming(
|
|
101
|
+
1,
|
|
102
|
+
{ duration: EnterDuration },
|
|
103
|
+
(completed) => {
|
|
104
|
+
if (completed) {
|
|
105
|
+
scheduleOnRN(finishTransition, currentTransitionId, true);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return () => {
|
|
111
|
+
transitionId.current += 1;
|
|
112
|
+
cancelAnimation(progress);
|
|
113
|
+
};
|
|
114
|
+
}, [
|
|
115
|
+
finishClose,
|
|
116
|
+
finishTransition,
|
|
117
|
+
finished,
|
|
118
|
+
notifyClose,
|
|
119
|
+
notifyEntered,
|
|
120
|
+
notifyOpen,
|
|
121
|
+
open,
|
|
122
|
+
progress
|
|
123
|
+
]);
|
|
124
|
+
return { progress, close, finished, interactive: open && !finished };
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
useToastLifecycle
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=use-toast-lifecycle.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-toast-lifecycle.hook.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n cancelAnimation,\n useSharedValue,\n withTiming,\n} from \"react-native-reanimated\";\nimport { scheduleOnRN } from \"react-native-worklets\";\n\nimport { useEventCallback } from \"@impulse-ui-native/core\";\nimport { useOverlayContext } from \"@impulse-ui-native/overlay\";\n\nimport type { ToastRootProps } from \"../types\";\nimport { EnterDuration, ExitDuration } from \"../constants/toast.constants\";\nimport { useToastTimer } from \"./use-toast-timer.hook\";\n\nexport function useToastLifecycle(props: ToastRootProps, duration: number) {\n const {\n id,\n open = true,\n onOpen,\n onOpenFinished,\n onClose,\n onCloseFinished,\n } = props;\n\n const { store } = useOverlayContext();\n\n const [entered, setEntered] = useState(false);\n const [finished, setFinished] = useState(false);\n\n const opened = useRef(false);\n const closing = useRef(false);\n const settled = useRef(false);\n const transitionId = useRef(0);\n\n const progress = useSharedValue(0);\n\n const close = useEventCallback(() => store.close(id));\n\n const notifyOpen = useEventCallback(() => onOpen?.(id));\n\n const notifyEntered = useEventCallback(() => onOpenFinished?.(id));\n\n const notifyClose = useEventCallback(() => onClose?.(id));\n\n const finishClose = useEventCallback(() => {\n if (settled.current) {\n return;\n }\n\n settled.current = true;\n\n setFinished(true);\n\n onCloseFinished?.(id);\n });\n\n const finishTransition = useEventCallback(\n (completedTransitionId: number, entering: boolean) => {\n if (transitionId.current !== completedTransitionId || settled.current) {\n return;\n }\n\n if (entering) {\n setEntered(true);\n\n notifyEntered();\n } else {\n finishClose();\n }\n },\n );\n\n useToastTimer(entered && open && !finished, duration, close);\n\n useEffect(() => {\n if (finished) {\n return;\n }\n\n const currentTransitionId = ++transitionId.current;\n\n if (!open) {\n const firstClose = !closing.current;\n\n closing.current = true;\n\n if (!opened.current) {\n try {\n if (firstClose) {\n notifyClose();\n }\n } finally {\n finishClose();\n }\n\n return;\n }\n\n try {\n if (firstClose) {\n notifyClose();\n }\n } finally {\n progress.value = withTiming(\n 0,\n { duration: ExitDuration },\n (completed) => {\n if (completed) {\n scheduleOnRN(finishTransition, currentTransitionId, false);\n }\n },\n );\n }\n\n return () => {\n transitionId.current += 1;\n\n cancelAnimation(progress);\n };\n }\n\n const firstOpen = !opened.current;\n\n opened.current = true;\n\n try {\n if (firstOpen) {\n notifyOpen();\n }\n } finally {\n progress.value = withTiming(\n 1,\n { duration: EnterDuration },\n (completed) => {\n if (completed) {\n scheduleOnRN(finishTransition, currentTransitionId, true);\n }\n },\n );\n }\n\n return () => {\n transitionId.current += 1;\n\n cancelAnimation(progress);\n };\n }, [\n finishClose,\n finishTransition,\n finished,\n notifyClose,\n notifyEntered,\n notifyOpen,\n open,\n progress,\n ]);\n\n return { progress, close, finished, interactive: open && !finished };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { AppState } from "react-native";
|
|
3
|
+
import { useEventCallback } from "@impulse-ui-native/core";
|
|
4
|
+
function useToastTimer(active, duration, close) {
|
|
5
|
+
const dismiss = useEventCallback(close);
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (!active || !Number.isFinite(duration) || duration <= 0) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
let remaining = duration;
|
|
11
|
+
let startedAt = 0;
|
|
12
|
+
let timeout;
|
|
13
|
+
const pause = () => {
|
|
14
|
+
if (timeout === void 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
clearTimeout(timeout);
|
|
18
|
+
timeout = void 0;
|
|
19
|
+
remaining = Math.max(0, remaining - (Date.now() - startedAt));
|
|
20
|
+
};
|
|
21
|
+
const resume = () => {
|
|
22
|
+
if (timeout !== void 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
startedAt = Date.now();
|
|
26
|
+
timeout = setTimeout(() => {
|
|
27
|
+
timeout = void 0;
|
|
28
|
+
dismiss();
|
|
29
|
+
}, remaining);
|
|
30
|
+
};
|
|
31
|
+
const subscription = AppState.addEventListener("change", (state) => {
|
|
32
|
+
if (state === "active") {
|
|
33
|
+
resume();
|
|
34
|
+
} else {
|
|
35
|
+
pause();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
if (AppState.currentState === "active") {
|
|
39
|
+
resume();
|
|
40
|
+
}
|
|
41
|
+
return () => {
|
|
42
|
+
pause();
|
|
43
|
+
subscription.remove();
|
|
44
|
+
};
|
|
45
|
+
}, [active, dismiss, duration]);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
useToastTimer
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=use-toast-timer.hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-toast-timer.hook.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { AppState } from \"react-native\";\n\nimport { useEventCallback } from \"@impulse-ui-native/core\";\n\nexport function useToastTimer(\n active: boolean,\n duration: number,\n close: () => void,\n) {\n const dismiss = useEventCallback(close);\n\n useEffect(() => {\n if (!active || !Number.isFinite(duration) || duration <= 0) {\n return;\n }\n\n let remaining = duration;\n let startedAt = 0;\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n const pause = () => {\n if (timeout === undefined) {\n return;\n }\n\n clearTimeout(timeout);\n\n timeout = undefined;\n remaining = Math.max(0, remaining - (Date.now() - startedAt));\n };\n\n const resume = () => {\n if (timeout !== undefined) {\n return;\n }\n\n startedAt = Date.now();\n timeout = setTimeout(() => {\n timeout = undefined;\n\n dismiss();\n }, remaining);\n };\n\n const subscription = AppState.addEventListener(\"change\", (state) => {\n if (state === \"active\") {\n resume();\n } else {\n pause();\n }\n });\n\n if (AppState.currentState === \"active\") {\n resume();\n }\n\n return () => {\n pause();\n subscription.remove();\n };\n }, [active, dismiss, duration]);\n}\n"],"mappings":"AAAA,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AAEzB,SAAS,wBAAwB;AAE1B,SAAS,cACd,QACA,UACA,OACA;AACA,QAAM,UAAU,iBAAiB,KAAK;AAEtC,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY,GAAG;AAC1D;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,QAAI,YAAY;AAChB,QAAI;AAEJ,UAAM,QAAQ,MAAM;AAClB,UAAI,YAAY,QAAW;AACzB;AAAA,MACF;AAEA,mBAAa,OAAO;AAEpB,gBAAU;AACV,kBAAY,KAAK,IAAI,GAAG,aAAa,KAAK,IAAI,IAAI,UAAU;AAAA,IAC9D;AAEA,UAAM,SAAS,MAAM;AACnB,UAAI,YAAY,QAAW;AACzB;AAAA,MACF;AAEA,kBAAY,KAAK,IAAI;AACrB,gBAAU,WAAW,MAAM;AACzB,kBAAU;AAEV,gBAAQ;AAAA,MACV,GAAG,SAAS;AAAA,IACd;AAEA,UAAM,eAAe,SAAS,iBAAiB,UAAU,CAAC,UAAU;AAClE,UAAI,UAAU,UAAU;AACtB,eAAO;AAAA,MACT,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF,CAAC;AAED,QAAI,SAAS,iBAAiB,UAAU;AACtC,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AACX,YAAM;AACN,mBAAa,OAAO;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,QAAQ,CAAC;AAChC;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Toast } from './components/index.mjs';
|
|
2
|
+
export { ToastActionProps, ToastCloseProps, ToastContentProps, ToastContextValue, ToastDescriptionProps, ToastIconProps, ToastPlacement, ToastProps, ToastRootProps, ToastTitleProps } from './types/toast.types.mjs';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
|
5
|
+
import '@impulse-ui-native/overlay';
|
|
6
|
+
import '@impulse-ui-native/primitives';
|
|
7
|
+
import '@impulse-ui-native/theme';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from \"./components\";\nexport * from \"./types\";\n"],"mappings":"AAAA,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ToastActionProps, ToastCloseProps, ToastContentProps, ToastContextValue, ToastDescriptionProps, ToastIconProps, ToastPlacement, ToastProps, ToastRootProps, ToastTitleProps } from './toast.types.mjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '@impulse-ui-native/overlay';
|
|
4
|
+
import '@impulse-ui-native/primitives';
|
|
5
|
+
import '@impulse-ui-native/theme';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/index.ts"],"sourcesContent":["export * from \"./toast.types\";\n"],"mappings":"AAAA,cAAc;","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { OverlayComponentProps } from '@impulse-ui-native/overlay';
|
|
3
|
+
import { ButtonProps, ViewProps, TextProps } from '@impulse-ui-native/primitives';
|
|
4
|
+
import { ToastTone } from '@impulse-ui-native/theme';
|
|
5
|
+
|
|
6
|
+
type ToastPlacement = "top" | "bottom";
|
|
7
|
+
interface ToastRootProps extends OverlayComponentProps {
|
|
8
|
+
placement?: ToastPlacement;
|
|
9
|
+
tone?: ToastTone;
|
|
10
|
+
/** Milliseconds after entry completes. Zero persists until dismissed. */
|
|
11
|
+
duration?: number;
|
|
12
|
+
}
|
|
13
|
+
interface ToastProps extends ToastRootProps {
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
action?: ReactNode;
|
|
16
|
+
actionProps?: Omit<ToastActionProps, "children">;
|
|
17
|
+
hideIcon?: boolean;
|
|
18
|
+
hideClose?: boolean;
|
|
19
|
+
}
|
|
20
|
+
type ToastContentProps = ViewProps;
|
|
21
|
+
type ToastTitleProps = TextProps;
|
|
22
|
+
type ToastDescriptionProps = TextProps;
|
|
23
|
+
type ToastIconProps = ViewProps;
|
|
24
|
+
interface ToastActionProps extends Omit<ButtonProps, "children" | "size" | "variant"> {
|
|
25
|
+
children?: ReactNode;
|
|
26
|
+
closeOnPress?: boolean;
|
|
27
|
+
}
|
|
28
|
+
type ToastCloseProps = Omit<ToastActionProps, "closeOnPress">;
|
|
29
|
+
interface ToastContextValue {
|
|
30
|
+
tone: ToastTone;
|
|
31
|
+
interactive: boolean;
|
|
32
|
+
close: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type { ToastActionProps, ToastCloseProps, ToastContentProps, ToastContextValue, ToastDescriptionProps, ToastIconProps, ToastPlacement, ToastProps, ToastRootProps, ToastTitleProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=toast.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@impulse-ui-native/toast",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "6.1.0",
|
|
4
|
+
"description": "Compound toast notifications for ImpulseUI Native.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react-native",
|
|
7
|
+
"toast",
|
|
8
|
+
"notifications",
|
|
9
|
+
"components"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"source": "src/index.ts",
|
|
13
|
+
"module": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.mts",
|
|
15
|
+
"react-native": "src/index.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"react-native": "./src/index.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@impulse-ui-native/theme": "6.1.0",
|
|
31
|
+
"@impulse-ui-native/primitives": "6.1.0",
|
|
32
|
+
"@impulse-ui-native/overlay": "6.1.0",
|
|
33
|
+
"@impulse-ui-native/core": "6.1.0",
|
|
34
|
+
"@impulse-ui-native/icon": "6.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "~19.2.14",
|
|
38
|
+
"eslint": "^9.38.0",
|
|
39
|
+
"prettier": "^3.6.2",
|
|
40
|
+
"react": "19.2.3",
|
|
41
|
+
"react-native": "0.86.2",
|
|
42
|
+
"react-native-reanimated": "4.5.1",
|
|
43
|
+
"react-native-worklets": "0.10.1",
|
|
44
|
+
"react-native-safe-area-context": "~5.7.0",
|
|
45
|
+
"typescript": "~6.0.3",
|
|
46
|
+
"react-native-svg": "15.15.4",
|
|
47
|
+
"@impulse-ui-native/eslint-config": "1.0.0",
|
|
48
|
+
"@impulse-ui-native/prettier-config": "1.0.0",
|
|
49
|
+
"@impulse-ui-native/tsconfig": "1.0.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": ">=18",
|
|
53
|
+
"react-native": ">=0.73",
|
|
54
|
+
"react-native-reanimated": ">=4.0.0",
|
|
55
|
+
"react-native-worklets": ">=0.5",
|
|
56
|
+
"react-native-safe-area-context": ">=5.0.0",
|
|
57
|
+
"react-native-svg": ">=13.9.0"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
62
|
+
"prettier": "@impulse-ui-native/prettier-config",
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup --config tsup.config.ts",
|
|
65
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
66
|
+
"lint": "pnpm exec eslint . --fix",
|
|
67
|
+
"format": "prettier --write \"./**/*.{ts,tsx,js,jsx,json,md}\" --ignore-path ../../.prettierignore",
|
|
68
|
+
"test": "node --test tests/*.test.mjs"
|
|
69
|
+
}
|
|
6
70
|
}
|