@sproutsocial/seeds-react-toast 1.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/dist/index.js ADDED
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ TOAST_Z_INDEX: () => TOAST_Z_INDEX,
34
+ ToastContainer: () => ToastContainer2,
35
+ ToastContentContainer: () => ToastContentContainer,
36
+ ToastHighlight: () => ToastHighlight,
37
+ toast: () => toast,
38
+ toastDismiss: () => toastDismiss,
39
+ toastIsActive: () => toastIsActive,
40
+ toastUpdate: () => toastUpdate
41
+ });
42
+ module.exports = __toCommonJS(src_exports);
43
+
44
+ // src/Toast.tsx
45
+ var import_react_toastify2 = require("react-toastify");
46
+ var import_seeds_react_box2 = __toESM(require("@sproutsocial/seeds-react-box"));
47
+ var import_seeds_react_icon = __toESM(require("@sproutsocial/seeds-react-icon"));
48
+ var import_seeds_react_text = __toESM(require("@sproutsocial/seeds-react-text"));
49
+
50
+ // src/styles.ts
51
+ var import_styled_components = __toESM(require("styled-components"));
52
+ var import_ReactToastify = require("react-toastify/dist/ReactToastify.css");
53
+ var import_seeds_react_box = __toESM(require("@sproutsocial/seeds-react-box"));
54
+ var import_react_toastify = require("react-toastify");
55
+ var TOAST_Z_INDEX = 9999;
56
+ var Container = (0, import_styled_components.default)(import_seeds_react_box.default)`
57
+ display: flex;
58
+ align-items: center;
59
+ gap: ${({ theme }) => theme.space[350]};
60
+ font-family: ${({ theme }) => theme.fontFamily};
61
+ ${({ theme }) => theme.typography[200]}
62
+ position: relative;
63
+ padding: ${({ theme }) => theme.space[350]};
64
+ `;
65
+ var ToastRoot = (0, import_styled_components.default)(import_react_toastify.ToastContainer).attrs({
66
+ toastClassName: "Toastify-toast-overrides",
67
+ hideProgressBar: true,
68
+ closeButton: false,
69
+ icon: false,
70
+ position: "bottom-right"
71
+ })`
72
+ --toastify-z-index: ${TOAST_Z_INDEX};
73
+ --toastify-toast-offset: ${({ theme }) => theme.space[400]};
74
+ --toastify-toast-width: 360px;
75
+ --toastify-toast-min-height: 48px;
76
+ --toastify-toast-max-height: 70vh;
77
+ --toastify-toast-bd-radius: ${({ theme }) => theme.radii[400]};
78
+ --toastify-toast-background: ${({ theme }) => theme.colors.container.background.base};
79
+ /* there's margin-bottom on the last toast so we can remove this */
80
+ --toastify-toast-bottom: 0;
81
+
82
+ padding: 0;
83
+
84
+ .Toastify-toast-overrides {
85
+ background: ${({ theme }) => theme.colors.container.background.base};
86
+ color: ${({ theme }) => theme.colors.text.body};
87
+ box-shadow: ${({ theme }) => theme.shadows.low};
88
+ padding: 0;
89
+ margin-bottom: var(--toastify-toast-offset);
90
+ }
91
+
92
+ .Toastify__toast-body {
93
+ padding: 0;
94
+ margin: 0;
95
+ }
96
+
97
+ /* Override React Toastify's mobile width styles */
98
+ @media only screen and (max-width: 480px) {
99
+ .Toastify-container-overrides {
100
+ min-width: initial !important;
101
+ }
102
+ }
103
+
104
+ /* Zoom animation */
105
+ @keyframes SproutToast__zoom-in {
106
+ from {
107
+ opacity: 0;
108
+ transform: scale3d(0.3, 0.3, 0.3);
109
+ }
110
+ 50% {
111
+ opacity: 1;
112
+ }
113
+ }
114
+ @keyframes SproutToast__zoom-out {
115
+ from {
116
+ opacity: 1;
117
+ }
118
+ 50% {
119
+ opacity: 0;
120
+ transform: scale3d(0.3, 0.3, 0.3) translate3d(0, var(--y), 0);
121
+ }
122
+ to {
123
+ opacity: 0;
124
+ }
125
+ }
126
+ .SproutToast__zoom-in {
127
+ animation: SproutToast__zoom-in ${({ theme }) => theme.duration.medium}
128
+ ${({ theme }) => theme.easing.ease_out} both;
129
+ }
130
+ .SproutToast__zoom-out {
131
+ animation: SproutToast__zoom-out ${({ theme }) => theme.duration.slow}
132
+ ${({ theme }) => theme.easing.ease_in} both;
133
+ }
134
+
135
+ /* No animation (it's still necessary to define classes for no animation to work properly) */
136
+ @keyframes SproutToast__none-in {
137
+ from {
138
+ opacity: 0;
139
+ }
140
+ to {
141
+ opacity: 1;
142
+ }
143
+ }
144
+ @keyframes SproutToast__none-out {
145
+ from {
146
+ opacity: 1;
147
+ }
148
+ to {
149
+ opacity: 0;
150
+ }
151
+ }
152
+ .SproutToast__none-in {
153
+ animation: SproutToast__none-in 0s both;
154
+ }
155
+ .SproutToast__none-out {
156
+ animation: SproutToast__none-out 0s both;
157
+ }
158
+ `;
159
+
160
+ // src/Toast.tsx
161
+ var import_styled_components2 = __toESM(require("styled-components"));
162
+ var import_jsx_runtime = require("react/jsx-runtime");
163
+ var toastDismiss = (...input) => (
164
+ // @ts-ignore Not sure what this type is supposed to be
165
+ import_react_toastify2.toast.dismiss(...input)
166
+ );
167
+ var toastIsActive = (...input) => import_react_toastify2.toast.isActive(...input);
168
+ var toastUpdate = (...input) => import_react_toastify2.toast.update(...input);
169
+ var NoTransition = (0, import_react_toastify2.cssTransition)({
170
+ enter: "SproutToast__none-in",
171
+ exit: "SproutToast__none-out"
172
+ });
173
+ var SproutZoomTransition = (0, import_react_toastify2.cssTransition)({
174
+ enter: "SproutToast__zoom-in",
175
+ exit: "SproutToast__zoom-out"
176
+ });
177
+ var ToastContainer2 = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastRoot, { ...props });
178
+ var themeIcon = {
179
+ success: "circle-check-outline",
180
+ info: "circle-i-outline",
181
+ warning: "triangle-exclamation-outline",
182
+ error: "triangle-exclamation-outline"
183
+ };
184
+ function toast(options) {
185
+ const {
186
+ closeOnClick = true,
187
+ content,
188
+ onClose,
189
+ persist,
190
+ toastId: inputToastId,
191
+ useTransition = true,
192
+ position = "bottom-right",
193
+ autoClose = persist ? false : 6e3,
194
+ transition = useTransition ? SproutZoomTransition : NoTransition,
195
+ ...rest
196
+ } = options;
197
+ let toastId = inputToastId;
198
+ if (!toastId && typeof content === "string") {
199
+ toastId = content;
200
+ }
201
+ const renderToast = (toastInput) => {
202
+ const renderedContent = typeof content === "function" ? content(toastInput) : content;
203
+ if (options.theme === "custom") {
204
+ return renderedContent;
205
+ }
206
+ const theme = options.theme || "info";
207
+ const iconName = options.icon || themeIcon[theme];
208
+ const containerColor = options.color || {
209
+ success: "container.border.success",
210
+ error: "container.border.error",
211
+ info: "container.border.info",
212
+ warning: "container.border.warning"
213
+ }[theme];
214
+ const iconColor = options.color || {
215
+ success: "icon.success",
216
+ error: "icon.error",
217
+ info: "icon.info",
218
+ warning: "icon.warning"
219
+ }[theme];
220
+ return (
221
+ // TODO: if this closes when clicked, there should be a label saying "Click to close" that can be overridden
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
223
+ ToastContentContainer,
224
+ {
225
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_icon.default, { name: iconName, color: iconColor }),
226
+ close: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_icon.default, { name: "x-outline", color: "icon.base", "aria-hidden": true }),
227
+ highlightColor: containerColor,
228
+ children: renderedContent
229
+ }
230
+ )
231
+ );
232
+ };
233
+ const toastOptions = {
234
+ autoClose,
235
+ closeOnClick,
236
+ onClose,
237
+ toastId: toastId || void 0,
238
+ transition,
239
+ position,
240
+ ...rest,
241
+ icon: void 0,
242
+ color: void 0
243
+ };
244
+ if (toastId && toastIsActive(toastId)) {
245
+ import_react_toastify2.toast.update(toastId, {
246
+ ...toastOptions,
247
+ render: renderToast
248
+ });
249
+ } else {
250
+ toastId = (0, import_react_toastify2.toast)(renderToast, toastOptions);
251
+ }
252
+ return toastId;
253
+ }
254
+ var ToastContentContainer = ({
255
+ children,
256
+ icon,
257
+ close,
258
+ highlightColor
259
+ }) => {
260
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Container, { "data-qa-toast": "", children: [
261
+ highlightColor ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastHighlight, { bg: highlightColor, "aria-hidden": true }) : null,
262
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_box2.default, { css: "line-height: 1;", children: icon }),
263
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_box2.default, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_text.default, { as: "div", color: "text.body", "data-qa-toast-content": "", children }) }),
264
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_box2.default, { css: "line-height: 1;", children: close })
265
+ ] });
266
+ };
267
+ var ToastHighlight = (0, import_styled_components2.default)(import_seeds_react_box2.default)`
268
+ position: absolute;
269
+ top: 0;
270
+ bottom: 0;
271
+ left: 0;
272
+ width: 2px;
273
+ `;
274
+
275
+ // src/ToastTypes.ts
276
+ var import_seeds_react_icon2 = require("@sproutsocial/seeds-react-icon");
277
+ // Annotate the CommonJS export names for ESM import in node:
278
+ 0 && (module.exports = {
279
+ TOAST_Z_INDEX,
280
+ ToastContainer,
281
+ ToastContentContainer,
282
+ ToastHighlight,
283
+ toast,
284
+ toastDismiss,
285
+ toastIsActive,
286
+ toastUpdate
287
+ });
288
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/Toast.tsx","../src/styles.ts","../src/ToastTypes.ts"],"sourcesContent":["export * from \"./Toast\";\nexport * from \"./ToastTypes\";\nexport { TOAST_Z_INDEX } from \"./styles\";\n","import type { PropsWithChildren, ReactNode, ComponentProps } from \"react\";\nimport {\n toast as toastifyToast,\n cssTransition,\n type ToastContent,\n} from \"react-toastify\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport Icon, { type TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport Text from \"@sproutsocial/seeds-react-text\";\nimport { Container, ToastRoot } from \"./styles\";\nimport type { TypeToastOptions, TypeToastTheme } from \"./ToastTypes\";\nimport styled from \"styled-components\";\n\nexport const toastDismiss: typeof toastifyToast.dismiss = (...input) =>\n // @ts-ignore Not sure what this type is supposed to be\n toastifyToast.dismiss(...input);\nexport const toastIsActive: typeof toastifyToast.isActive = (...input) =>\n toastifyToast.isActive(...input);\nexport const toastUpdate: typeof toastifyToast.update = (...input) =>\n toastifyToast.update(...input);\n\nconst NoTransition = cssTransition({\n enter: \"SproutToast__none-in\",\n exit: \"SproutToast__none-out\",\n});\nconst SproutZoomTransition = cssTransition({\n enter: \"SproutToast__zoom-in\",\n exit: \"SproutToast__zoom-out\",\n});\n\nexport const ToastContainer = (\n props: Partial<ComponentProps<typeof ToastRoot>>\n) => <ToastRoot {...props} />;\n\nconst themeIcon: Record<TypeToastTheme, TypeIconName> = {\n success: \"circle-check-outline\",\n info: \"circle-i-outline\",\n warning: \"triangle-exclamation-outline\",\n error: \"triangle-exclamation-outline\",\n} as const;\n\nexport function toast<TData = unknown>(\n options: TypeToastOptions<TData>\n): ReturnType<typeof toastifyToast> {\n const {\n closeOnClick = true,\n content,\n onClose,\n persist,\n toastId: inputToastId,\n useTransition = true,\n position = \"bottom-right\",\n autoClose = persist ? false : 6000,\n transition = useTransition ? SproutZoomTransition : NoTransition,\n ...rest\n } = options;\n\n let toastId = inputToastId;\n if (!toastId && typeof content === \"string\") {\n toastId = content;\n }\n\n const renderToast: ToastContent<TData> = (toastInput) => {\n const renderedContent =\n typeof content === \"function\" ? content(toastInput) : content;\n\n if (options.theme === \"custom\") {\n return renderedContent;\n }\n\n const theme = options.theme || \"info\";\n const iconName = options.icon || themeIcon[theme];\n const containerColor =\n options.color ||\n (\n {\n success: \"container.border.success\",\n error: \"container.border.error\",\n info: \"container.border.info\",\n warning: \"container.border.warning\",\n } as const\n )[theme];\n const iconColor =\n options.color ||\n (\n {\n success: \"icon.success\",\n error: \"icon.error\",\n info: \"icon.info\",\n warning: \"icon.warning\",\n } as const\n )[theme];\n\n return (\n // TODO: if this closes when clicked, there should be a label saying \"Click to close\" that can be overridden\n <ToastContentContainer\n icon={<Icon name={iconName} color={iconColor} />}\n close={<Icon name=\"x-outline\" color=\"icon.base\" aria-hidden />}\n highlightColor={containerColor}\n >\n {renderedContent}\n </ToastContentContainer>\n );\n };\n\n const toastOptions = {\n autoClose,\n closeOnClick,\n onClose,\n toastId: toastId || undefined,\n transition,\n position,\n ...rest,\n icon: undefined,\n color: undefined,\n } as const;\n\n if (toastId && toastIsActive(toastId)) {\n toastifyToast.update<TData>(toastId, {\n ...toastOptions,\n render: renderToast,\n });\n } else {\n toastId = toastifyToast<TData>(renderToast, toastOptions);\n }\n\n return toastId;\n}\n\nexport default ToastContainer;\n\nexport const ToastContentContainer = ({\n children,\n icon,\n close,\n highlightColor,\n}: PropsWithChildren<{\n /**\n * A ReactNode in the icon slot\n */\n icon: ReactNode;\n /**\n * A ReactNode in the close button slot\n */\n close: ReactNode;\n highlightColor?: ComponentProps<typeof Box>[\"bg\"];\n}>) => {\n return (\n <Container data-qa-toast=\"\">\n {highlightColor ? (\n <ToastHighlight bg={highlightColor} aria-hidden />\n ) : null}\n\n <Box css=\"line-height: 1;\">{icon}</Box>\n\n <Box flex={1}>\n <Text as=\"div\" color=\"text.body\" data-qa-toast-content=\"\">\n {children}\n </Text>\n </Box>\n\n <Box css=\"line-height: 1;\">{close}</Box>\n </Container>\n );\n};\n\nexport const ToastHighlight = styled(Box)<ComponentProps<typeof Box>>`\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 2px;\n`;\n","import styled from \"styled-components\";\nimport type { ComponentProps } from \"react\";\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport \"react-toastify/dist/ReactToastify.css\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport { ToastContainer } from \"react-toastify\";\n\nexport const TOAST_Z_INDEX = 9999;\n\nexport const Container = styled(Box)<ComponentProps<typeof Box>>`\n display: flex;\n align-items: center;\n gap: ${({ theme }) => theme.space[350]};\n font-family: ${({ theme }) => theme.fontFamily};\n ${({ theme }) => theme.typography[200]}\n position: relative;\n padding: ${({ theme }) => theme.space[350]};\n`;\n\nexport const ToastRoot = styled(ToastContainer).attrs({\n toastClassName: \"Toastify-toast-overrides\",\n hideProgressBar: true,\n closeButton: false,\n icon: false,\n position: \"bottom-right\",\n})`\n --toastify-z-index: ${TOAST_Z_INDEX};\n --toastify-toast-offset: ${({ theme }) => theme.space[400]};\n --toastify-toast-width: 360px;\n --toastify-toast-min-height: 48px;\n --toastify-toast-max-height: 70vh;\n --toastify-toast-bd-radius: ${({ theme }) => theme.radii[400]};\n --toastify-toast-background: ${({ theme }) =>\n theme.colors.container.background.base};\n /* there's margin-bottom on the last toast so we can remove this */\n --toastify-toast-bottom: 0;\n\n padding: 0;\n\n .Toastify-toast-overrides {\n background: ${({ theme }) => theme.colors.container.background.base};\n color: ${({ theme }) => theme.colors.text.body};\n box-shadow: ${({ theme }) => theme.shadows.low};\n padding: 0;\n margin-bottom: var(--toastify-toast-offset);\n }\n\n .Toastify__toast-body {\n padding: 0;\n margin: 0;\n }\n\n /* Override React Toastify's mobile width styles */\n @media only screen and (max-width: 480px) {\n .Toastify-container-overrides {\n min-width: initial !important;\n }\n }\n\n /* Zoom animation */\n @keyframes SproutToast__zoom-in {\n from {\n opacity: 0;\n transform: scale3d(0.3, 0.3, 0.3);\n }\n 50% {\n opacity: 1;\n }\n }\n @keyframes SproutToast__zoom-out {\n from {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n transform: scale3d(0.3, 0.3, 0.3) translate3d(0, var(--y), 0);\n }\n to {\n opacity: 0;\n }\n }\n .SproutToast__zoom-in {\n animation: SproutToast__zoom-in ${({ theme }) => theme.duration.medium}\n ${({ theme }) => theme.easing.ease_out} both;\n }\n .SproutToast__zoom-out {\n animation: SproutToast__zoom-out ${({ theme }) => theme.duration.slow}\n ${({ theme }) => theme.easing.ease_in} both;\n }\n\n /* No animation (it's still necessary to define classes for no animation to work properly) */\n @keyframes SproutToast__none-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n @keyframes SproutToast__none-out {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n }\n .SproutToast__none-in {\n animation: SproutToast__none-in 0s both;\n }\n .SproutToast__none-out {\n animation: SproutToast__none-out 0s both;\n }\n`;\n","import type { ComponentProps } from \"react\";\nimport { type Icon, type TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport type { ToastContent, ToastOptions } from \"react-toastify\";\n\nexport type TypeToastTheme = \"info\" | \"success\" | \"warning\" | \"error\";\n\ninterface BaseToastOptions<TData>\n extends Omit<ToastOptions<TData>, \"closeButton\" | \"icon\" | \"type\"> {\n theme?: TypeToastTheme | \"custom\";\n content: ToastContent<TData>;\n persist?: boolean;\n useTransition?: boolean;\n}\n\ninterface ThemedToastOptions<TData> extends BaseToastOptions<TData> {\n /**\n * One of `info`, `success`, `warning`, or `error`.\n */\n theme?: TypeToastTheme;\n /**\n * @deprecated Use `custom` theme instead.\n */\n color?: ComponentProps<typeof Icon>[\"color\"];\n /**\n * @deprecated Use `custom` theme instead.\n */\n icon?: TypeIconName;\n}\ninterface CustomToastOptions<TData> extends BaseToastOptions<TData> {\n /**\n * If you need to break out of the supported styles you can use the `custom` theme. You can use `ToastContentContainer` with `Icon` and `ToastHighlight` to build your custom toast.\n */\n theme: \"custom\";\n}\n\nexport type TypeToastOptions<TData> =\n | ThemedToastOptions<TData>\n | CustomToastOptions<TData>;\n"],"mappings":"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","names":["ToastContainer","import_react_toastify","import_seeds_react_box","styled","Box","import_styled_components","toastifyToast","ToastContainer","Icon","Box","Text","styled","import_seeds_react_icon"]}
package/jest.config.js ADDED
@@ -0,0 +1,9 @@
1
+ const baseConfig = require("@sproutsocial/seeds-testing");
2
+
3
+ /** * @type {import('jest').Config} */
4
+ const config = {
5
+ ...baseConfig,
6
+ displayName: "seeds-react-toast",
7
+ };
8
+
9
+ module.exports = config;
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@sproutsocial/seeds-react-toast",
3
+ "version": "1.0.0",
4
+ "description": "Seeds React Toast",
5
+ "author": "Sprout Social, Inc.",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "module": "dist/esm/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "scripts": {
11
+ "build": "tsup --dts",
12
+ "build:debug": "tsup --dts --metafile",
13
+ "dev": "tsup --watch --dts",
14
+ "clean": "rm -rf .turbo dist",
15
+ "clean:modules": "rm -rf node_modules",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "@sproutsocial/seeds-react-theme": "*",
20
+ "@sproutsocial/seeds-react-system-props": "*",
21
+ "@sproutsocial/seeds-react-icon": "*",
22
+ "@sproutsocial/seeds-react-box": "*",
23
+ "@sproutsocial/seeds-react-text": "*"
24
+ },
25
+ "devDependencies": {
26
+ "@types/react": "^18.0.0",
27
+ "@types/styled-components": "^5.1.26",
28
+ "@sproutsocial/eslint-config-seeds": "*",
29
+ "react": "^18.0.0",
30
+ "styled-components": "^5.2.3",
31
+ "tsup": "^8.0.2",
32
+ "typescript": "^5.6.2",
33
+ "@sproutsocial/seeds-tsconfig": "*",
34
+ "@sproutsocial/seeds-testing": "*",
35
+ "@sproutsocial/seeds-react-testing-library": "*",
36
+ "react-toastify": "^10.0.0"
37
+ },
38
+ "peerDependencies": {
39
+ "styled-components": "^5.2.3",
40
+ "react-toastify": "^9.0.0 || ^10.0.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ }
45
+ }
@@ -0,0 +1,300 @@
1
+ /* eslint-disable no-console */
2
+ import React, { useState } from "react";
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+ import type { ToastContent as ToastifyToastContent } from "react-toastify";
5
+ import { css } from "styled-components";
6
+ import Icon, { type TypeIconName } from "@sproutsocial/seeds-react-icon";
7
+ import Box from "@sproutsocial/seeds-react-box";
8
+ import Button from "@sproutsocial/seeds-react-button";
9
+ import Fieldset from "@sproutsocial/seeds-react-fieldset";
10
+ import Input from "@sproutsocial/seeds-react-input";
11
+ import Link from "@sproutsocial/seeds-react-link";
12
+ import Radio from "@sproutsocial/seeds-react-radio";
13
+ import Switch from "@sproutsocial/seeds-react-switch";
14
+ import Text from "@sproutsocial/seeds-react-text";
15
+ import {
16
+ toast,
17
+ toastDismiss,
18
+ ToastContainer,
19
+ ToastContentContainer,
20
+ ToastHighlight,
21
+ } from "./Toast";
22
+ import type { TypeToastTheme } from "./ToastTypes";
23
+
24
+ const ToastContent = ({ verbose = false }) => (
25
+ <Box>
26
+ <Text as="div" color="text.header" fontWeight="semibold">
27
+ New Message
28
+ </Text>
29
+ <Text as="div" color="text.body">
30
+ Your message is scheduled for July 4, 2020.
31
+ </Text>
32
+ {verbose && (
33
+ <Text as="div" color="text.body">
34
+ Your message is scheduled for July 4, 2020. Your message is scheduled
35
+ for July 4, 2020. Your message is scheduled for July 4, 2020. Your
36
+ message is scheduled for July 4, 2020. Your message is scheduled for
37
+ July 4, 2020. Your message is scheduled for July 4, 2020.
38
+ </Text>
39
+ )}
40
+ <Text fontSize={100}>Now: {new Date().toLocaleString()}</Text>
41
+ </Box>
42
+ );
43
+
44
+ const meta: Meta = {
45
+ title: "Components/Toast",
46
+ };
47
+ export default meta;
48
+
49
+ type Story = StoryObj;
50
+
51
+ export const Default: Story = {
52
+ render: () => <DefaultStoryComponent />,
53
+ };
54
+
55
+ const DefaultStoryComponent = () => {
56
+ const [animation, setAnimation] = useState(true);
57
+ const [persist, setPersist] = useState(true);
58
+ const [toastId, setToastId] = useState("");
59
+ const positions = [
60
+ "top-left",
61
+ "top-center",
62
+ "top-right",
63
+ "bottom-left",
64
+ "bottom-center",
65
+ "bottom-right",
66
+ ] as const;
67
+ const [position, setPosition] =
68
+ useState<(typeof positions)[number]>("bottom-right");
69
+
70
+ const triggerToast = ({
71
+ theme,
72
+ verbose,
73
+ icon,
74
+ content,
75
+ color,
76
+ closeOnClick,
77
+ }: {
78
+ theme?: TypeToastTheme | "custom";
79
+ verbose?: boolean;
80
+ icon?: TypeIconName;
81
+ content?: ToastifyToastContent<unknown>;
82
+ color?: string;
83
+ closeOnClick?: boolean;
84
+ }) =>
85
+ toast({
86
+ content: content || <ToastContent verbose={verbose} />,
87
+ theme,
88
+ icon,
89
+ color,
90
+ persist,
91
+ toastId,
92
+ position,
93
+ useTransition: animation,
94
+ closeOnClick,
95
+
96
+ onOpen: () => {
97
+ console.log("Toast opened");
98
+ },
99
+ onClose: () => {
100
+ console.log("Toast closed");
101
+ },
102
+ onClick: () => {
103
+ console.log("Toast clicked");
104
+ },
105
+ });
106
+
107
+ return (
108
+ <>
109
+ <Box
110
+ bg="container.background.decorative.neutral"
111
+ height="100vh"
112
+ display="flex"
113
+ flexDirection="column"
114
+ gap={400}
115
+ >
116
+ <Fieldset label="Position" layout="horizontal">
117
+ {positions.map((value) => (
118
+ <Box key={value} display="flex" alignItems="center">
119
+ <Radio
120
+ id={`toast-position-${value}`}
121
+ name="position"
122
+ value={value}
123
+ label={value}
124
+ checked={value === position}
125
+ onChange={() => setPosition(value)}
126
+ mr={300}
127
+ mb={300}
128
+ />
129
+ </Box>
130
+ ))}
131
+ </Fieldset>
132
+ <Fieldset label="Animation" layout="horizontal">
133
+ <Switch
134
+ id="toast-animation"
135
+ checked={animation}
136
+ onClick={() => {
137
+ setAnimation((prev) => !prev);
138
+ }}
139
+ />
140
+ </Fieldset>
141
+ <Fieldset label="Persist">
142
+ <Switch
143
+ id="toast-persist"
144
+ checked={persist}
145
+ onClick={() => {
146
+ setPersist((prev) => !prev);
147
+ }}
148
+ />
149
+ </Fieldset>
150
+ <Fieldset label="ID">
151
+ <Input
152
+ id="toast-id-input"
153
+ name="toast-id"
154
+ onChange={(e) => {
155
+ setToastId(e.currentTarget.value);
156
+ }}
157
+ />
158
+ </Fieldset>
159
+ <Fieldset label="Variants" layout="horizontal">
160
+ <Button
161
+ appearance="secondary"
162
+ onClick={() =>
163
+ triggerToast({
164
+ content: <div>Now: {new Date().toLocaleString()}</div>,
165
+ })
166
+ }
167
+ >
168
+ Default
169
+ </Button>
170
+ <Button
171
+ appearance="secondary"
172
+ onClick={() => triggerToast({ theme: "info" })}
173
+ >
174
+ Info
175
+ </Button>
176
+ <Button
177
+ appearance="secondary"
178
+ onClick={() => triggerToast({ theme: "success" })}
179
+ >
180
+ Success
181
+ </Button>
182
+ <Button
183
+ appearance="secondary"
184
+ onClick={() => triggerToast({ theme: "warning" })}
185
+ >
186
+ Warning
187
+ </Button>
188
+ <Button
189
+ appearance="secondary"
190
+ onClick={() => triggerToast({ theme: "error" })}
191
+ >
192
+ Error
193
+ </Button>
194
+ <Button
195
+ appearance="secondary"
196
+ onClick={() => triggerToast({ theme: "info", verbose: true })}
197
+ >
198
+ Verbose
199
+ </Button>
200
+ <Button
201
+ appearance="secondary"
202
+ onClick={() =>
203
+ triggerToast({
204
+ icon: "tripadvisor",
205
+ color: "network.tripadvisor",
206
+ })
207
+ }
208
+ >
209
+ Social Network
210
+ </Button>
211
+ <Button
212
+ appearance="secondary"
213
+ onClick={() =>
214
+ triggerToast({
215
+ theme: "custom",
216
+ closeOnClick: false,
217
+ content: ({ closeToast }) => (
218
+ <ToastContentContainer
219
+ icon={<Icon name="hand-sparkle-outline" />}
220
+ close={
221
+ <Button onClick={closeToast} aria-label="Close" mr={-300}>
222
+ <Icon name="x-outline" color="icon.base" aria-hidden />
223
+ </Button>
224
+ }
225
+ >
226
+ <ToastHighlight
227
+ css={css`
228
+ background: linear-gradient(
229
+ to bottom,
230
+ ${({ theme }) => theme.colors.teal[900]},
231
+ ${({ theme }) => theme.colors.blue[800]}
232
+ );
233
+ `}
234
+ />
235
+ <Box display="flex" gap={400} alignItems="center">
236
+ <Text as="p">How did AI Assist do?</Text>
237
+ <Icon name="thumbs-up-outline" size="mini" />
238
+ <Icon name="thumbs-down-outline" size="mini" />
239
+ </Box>
240
+ </ToastContentContainer>
241
+ ),
242
+ })
243
+ }
244
+ >
245
+ Custom
246
+ </Button>
247
+ </Fieldset>
248
+ <Fieldset label="Global Actions" layout="horizontal">
249
+ <Button
250
+ appearance="secondary"
251
+ onClick={() => {
252
+ toastDismiss();
253
+ }}
254
+ >
255
+ Clear all
256
+ </Button>
257
+ </Fieldset>
258
+ </Box>
259
+
260
+ <ToastContainer />
261
+ </>
262
+ );
263
+ };
264
+
265
+ export const WithLink: Story = {
266
+ render: () => {
267
+ const triggerToast = () =>
268
+ toast({
269
+ persist: true,
270
+ content: (
271
+ <Box
272
+ display="inline-flex"
273
+ width="100%"
274
+ justifyContent="space-between"
275
+ alignItems="flex-start"
276
+ >
277
+ <Text>Message completed</Text>
278
+ <Link
279
+ onClick={() => alert("Clicked!")}
280
+ ml={300}
281
+ fontSize={200}
282
+ p={0}
283
+ >
284
+ Undo
285
+ </Link>
286
+ </Box>
287
+ ),
288
+ });
289
+
290
+ return (
291
+ <Box>
292
+ <ToastContainer />
293
+
294
+ <Button appearance="secondary" onClick={triggerToast}>
295
+ Fire toast
296
+ </Button>
297
+ </Box>
298
+ );
299
+ },
300
+ };