@simplybusiness/mobius 7.0.0 → 7.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.
@@ -0,0 +1,13 @@
1
+ import type { ToastOptions } from "./types";
2
+ export declare const toast: {
3
+ /** Show an info toast */
4
+ info: (message: string, options?: ToastOptions) => string | number;
5
+ /** Show a success toast */
6
+ success: (message: string, options?: ToastOptions) => string | number;
7
+ /** Show a warning toast */
8
+ warning: (message: string, options?: ToastOptions) => string | number;
9
+ /** Show an error toast */
10
+ error: (message: string, options?: ToastOptions) => string | number;
11
+ /** Dismiss a specific toast by ID or all toasts */
12
+ dismiss: (toastId?: string | number) => string | number;
13
+ };
@@ -0,0 +1,9 @@
1
+ import type { ToastOptions } from "./types";
2
+ /**
3
+ * Documentation-only component for ToastOptions.
4
+ * Exists solely to provide ArgTypes for the toast() function options.
5
+ */
6
+ export declare const ToastOptionsDoc: {
7
+ (_props: ToastOptions): null;
8
+ displayName: string;
9
+ };
@@ -0,0 +1,19 @@
1
+ import type { ToastPosition } from "./types";
2
+ export interface ToasterProps {
3
+ /** Position of the toast container */
4
+ position?: ToastPosition;
5
+ /** Whether to show the close (X) button on toasts */
6
+ closeButton?: boolean;
7
+ /** Whether toasts expand on hover */
8
+ expand?: boolean;
9
+ /** Duration in milliseconds before auto-dismiss (default: 4000) */
10
+ duration?: number;
11
+ /** Maximum number of visible toasts */
12
+ visibleToasts?: number;
13
+ /** Gap between toasts in pixels */
14
+ gap?: number;
15
+ }
16
+ export declare const Toaster: {
17
+ ({ position, closeButton, expand, duration, visibleToasts, gap, }: ToasterProps): import("react/jsx-runtime").JSX.Element;
18
+ displayName: string;
19
+ };
@@ -0,0 +1,4 @@
1
+ export { toast } from "./Toast";
2
+ export { Toaster } from "./Toaster";
3
+ export type { ToasterProps } from "./Toaster";
4
+ export type { ToastOptions, ToastVariant, ToastPosition } from "./types";
@@ -0,0 +1,3 @@
1
+ export declare const toastState: {
2
+ showCloseButton: boolean;
3
+ };
@@ -0,0 +1,27 @@
1
+ import type { ReactNode } from "react";
2
+ export type ToastVariant = "info" | "success" | "warning" | "error";
3
+ export type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
4
+ export type ToastOptions = {
5
+ /** Title of the toast */
6
+ title?: string;
7
+ /** Description/body text of the toast */
8
+ description?: ReactNode;
9
+ /** Duration in milliseconds before auto-dismiss */
10
+ duration?: number;
11
+ /** Action button configuration */
12
+ action?: {
13
+ label: string;
14
+ onClick: () => void;
15
+ };
16
+ /** Cancel button configuration */
17
+ cancel?: {
18
+ label: string;
19
+ onClick?: () => void;
20
+ };
21
+ /** Callback when toast is dismissed */
22
+ onDismiss?: () => void;
23
+ /** Callback when toast auto-closes */
24
+ onAutoClose?: () => void;
25
+ /** Whether to show the close button (defaults to Toaster's closeButton prop) */
26
+ showCloseButton?: boolean;
27
+ };
@@ -43,6 +43,7 @@ export * from "./TextAreaInput";
43
43
  export * from "./TextField";
44
44
  export * from "./TextOrHTML";
45
45
  export * from "./Title";
46
+ export * from "./Toast";
46
47
  export * from "./Trust";
47
48
  export * from "./ExpandableText";
48
49
  export * from "./VisuallyHidden";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@simplybusiness/mobius",
3
3
  "license": "UNLICENSED",
4
- "version": "7.0.0",
4
+ "version": "7.1.0",
5
5
  "description": "Core library of Mobius react components",
6
6
  "repository": {
7
7
  "type": "git",
@@ -89,7 +89,8 @@
89
89
  "dialog-polyfill": "^0.5.6",
90
90
  "lodash.debounce": "^4.0.8",
91
91
  "react-accessible-dropdown-menu-hook": "^4.0.1",
92
- "react-imask": "^7.6.1"
92
+ "react-imask": "^7.6.1",
93
+ "sonner": "^2.0.7"
93
94
  },
94
95
  "lint-staged": {
95
96
  "*.{js,ts,jsx,tsx}": "eslint --fix"
@@ -210,6 +210,7 @@ const ComboboxInner = <T extends ComboboxOption>({
210
210
  blurTimeoutRef.current = setTimeout(() => {
211
211
  onBlur?.(e);
212
212
  setIsOpen(false);
213
+ setIsChanging(false);
213
214
  }, 150);
214
215
  };
215
216
 
@@ -0,0 +1,233 @@
1
+ /* Toaster container positioning (keep Sonner's positioning logic) */
2
+ [data-sonner-toaster] {
3
+ font-family: var(--font-family);
4
+ }
5
+
6
+ /* Base toast styles */
7
+ .mobius-toast {
8
+ position: relative;
9
+ font-family: var(--font-family);
10
+ font-size: var(--font-size-regular);
11
+ line-height: var(--line-height-normal);
12
+ color: var(--color-text);
13
+ background-color: var(--color-background);
14
+ border: 2px solid var(--color-border);
15
+ border-radius: var(--radius-1);
16
+ box-shadow: var(--shadow-md);
17
+ padding: var(--size-md);
18
+ display: flex;
19
+ align-items: flex-start;
20
+ gap: var(--size-sm);
21
+ width: var(--toast-width);
22
+ max-width: calc(100vw - var(--size-lg) * 2);
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ /* Variant styles */
27
+ .mobius-toast.--info {
28
+ border-color: var(--color-info);
29
+ background-color: var(--color-info-background);
30
+ }
31
+
32
+ .mobius-toast.--success {
33
+ border-color: var(--color-valid);
34
+ background-color: var(--color-valid-background);
35
+ }
36
+
37
+ .mobius-toast.--warning {
38
+ border-color: var(--color-warning);
39
+ background-color: var(--color-warning-background);
40
+ }
41
+
42
+ .mobius-toast.--error {
43
+ border-color: var(--color-error);
44
+ background-color: var(--color-error-background);
45
+ }
46
+
47
+ /* Icon */
48
+ .mobius-toast__icon {
49
+ flex-shrink: 0;
50
+ display: flex;
51
+ align-items: center;
52
+ padding-top: 2px;
53
+ }
54
+
55
+ .mobius-toast__icon .mobius-icon {
56
+ width: 1.25em;
57
+ height: 1.25em;
58
+ }
59
+
60
+ /* Body wrapper for content + actions */
61
+ .mobius-toast__body {
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: var(--size-sm);
65
+ flex: 1;
66
+ min-width: 0;
67
+ padding-right: var(--size-lg);
68
+ }
69
+
70
+ /* Content wrapper (title + description) */
71
+ .mobius-toast__content {
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: var(--size-xxs);
75
+ }
76
+
77
+ /* Title */
78
+ .mobius-toast__title {
79
+ font-size: var(--font-size-regular);
80
+ font-weight: 600;
81
+ line-height: var(--line-height-normal);
82
+ color: var(--color-text);
83
+ margin: 0;
84
+ }
85
+
86
+ /* Description */
87
+ .mobius-toast__description {
88
+ font-size: var(--font-size-regular);
89
+ line-height: var(--line-height-normal);
90
+ color: var(--color-text);
91
+ margin: 0;
92
+ }
93
+
94
+ /* Actions wrapper - separate row for buttons */
95
+ .mobius-toast__actions {
96
+ display: flex;
97
+ justify-content: flex-end;
98
+ gap: var(--size-xs);
99
+ flex-wrap: wrap;
100
+ }
101
+
102
+ /* Shared button styles */
103
+ .mobius-toast__action,
104
+ .mobius-toast__cancel {
105
+ font-family: var(--font-family);
106
+ font-size: var(--font-size-small);
107
+ font-weight: 600;
108
+ padding: var(--size-xs) var(--size-sm);
109
+ border-radius: var(--radius-1);
110
+ cursor: pointer;
111
+ transition: background-color 0.15s ease;
112
+ flex-shrink: 0;
113
+ display: inline-flex;
114
+ align-items: center;
115
+ justify-content: center;
116
+ }
117
+
118
+ /* Action button (primary) */
119
+ .mobius-toast__action {
120
+ background-color: var(--button-primary-color);
121
+ color: var(--button-primary-content-color);
122
+ border: none;
123
+ }
124
+
125
+ .mobius-toast__action:hover {
126
+ filter: brightness(0.9);
127
+ }
128
+
129
+ /* Action button variant colors */
130
+ .mobius-toast.--info .mobius-toast__action {
131
+ background-color: var(--color-info);
132
+ }
133
+
134
+ .mobius-toast.--success .mobius-toast__action {
135
+ background-color: var(--color-valid);
136
+ }
137
+
138
+ .mobius-toast.--warning .mobius-toast__action {
139
+ background-color: var(--color-warning);
140
+ }
141
+
142
+ .mobius-toast.--error .mobius-toast__action {
143
+ background-color: var(--color-error);
144
+ }
145
+
146
+ /* Cancel button (secondary) */
147
+ .mobius-toast__cancel {
148
+ background-color: transparent;
149
+ color: var(--color-text);
150
+ border: 1px solid var(--color-border);
151
+ }
152
+
153
+ .mobius-toast__cancel:hover {
154
+ background-color: var(--color-background-hover);
155
+ }
156
+
157
+ /* Cancel button variant border colors */
158
+ .mobius-toast.--info .mobius-toast__cancel {
159
+ border-color: var(--color-info);
160
+ color: var(--color-info);
161
+ }
162
+
163
+ .mobius-toast.--success .mobius-toast__cancel {
164
+ border-color: var(--color-valid);
165
+ color: var(--color-valid);
166
+ }
167
+
168
+ .mobius-toast.--warning .mobius-toast__cancel {
169
+ border-color: var(--color-warning);
170
+ color: var(--color-warning);
171
+ }
172
+
173
+ .mobius-toast.--error .mobius-toast__cancel {
174
+ border-color: var(--color-error);
175
+ color: var(--color-error);
176
+ }
177
+
178
+ /* Close button */
179
+ .mobius-toast__close {
180
+ position: absolute;
181
+ top: var(--size-md);
182
+ right: var(--size-sm);
183
+ background: transparent;
184
+ border: none;
185
+ border-radius: var(--radius-1);
186
+ cursor: pointer;
187
+ padding: var(--size-xxs);
188
+ width: var(--size-md);
189
+ height: var(--size-md);
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: center;
193
+ color: var(--color-text-muted);
194
+ transition: color 0.15s ease;
195
+ }
196
+
197
+ .mobius-toast__close:hover {
198
+ color: var(--color-text);
199
+ }
200
+
201
+ /* Close icon */
202
+ .mobius-toast__close-icon {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ }
207
+
208
+ .mobius-toast__close-icon .mobius-icon {
209
+ width: 1.25em;
210
+ height: 1.25em;
211
+ }
212
+
213
+ /* Close button variant colors */
214
+ .mobius-toast.--info .mobius-toast__close {
215
+ color: var(--color-info);
216
+ }
217
+
218
+ .mobius-toast.--success .mobius-toast__close {
219
+ color: var(--color-valid);
220
+ }
221
+
222
+ .mobius-toast.--warning .mobius-toast__close {
223
+ color: var(--color-warning);
224
+ }
225
+
226
+ .mobius-toast.--error .mobius-toast__close {
227
+ color: var(--color-error);
228
+ }
229
+
230
+ /* Close button hover - darken slightly */
231
+ .mobius-toast .mobius-toast__close:hover {
232
+ filter: brightness(0.8);
233
+ }
@@ -0,0 +1,131 @@
1
+ {/* prettier-ignore-start */}
2
+
3
+ import { Meta, Canvas, ArgTypes } from "@storybook/addon-docs/blocks";
4
+ import { Toaster } from "./Toaster";
5
+ import { ToastOptionsDoc } from "./ToastOptionsDoc";
6
+ import * as ToastStories from "./Toast.stories";
7
+
8
+ <Meta of={ToastStories} />
9
+
10
+ # Toast
11
+
12
+ Toast notifications provide brief, non-blocking feedback messages to users. Built on [Sonner](https://sonner.emilkowal.ski/), toasts automatically dismiss after a configurable duration and support keyboard dismissal.
13
+
14
+ ## Usage
15
+
16
+ ```tsx
17
+ import { Toaster, toast } from "@simplybusiness/mobius";
18
+
19
+ // 1. Add the Toaster component once at your app root
20
+ function App() {
21
+ return (
22
+ <>
23
+ <Toaster />
24
+ <YourApp />
25
+ </>
26
+ );
27
+ }
28
+
29
+ // 2. Call toast functions from anywhere in your app
30
+ function SaveButton() {
31
+ const handleSave = async () => {
32
+ await saveData();
33
+ toast.success("Your changes have been saved");
34
+ };
35
+
36
+ return <Button onClick={handleSave}>Save</Button>;
37
+ }
38
+ ```
39
+
40
+ ## Variants
41
+
42
+ Toasts come in four variants that match the Alert component styling:
43
+
44
+ <Canvas of={ToastStories.AllVariants} />
45
+
46
+ ### Info
47
+
48
+ Use for neutral informational messages.
49
+
50
+ ```tsx
51
+ toast.info("Your session will expire in 5 minutes");
52
+ ```
53
+
54
+ ### Success
55
+
56
+ Use to confirm successful operations.
57
+
58
+ ```tsx
59
+ toast.success("Your changes have been saved");
60
+ ```
61
+
62
+ ### Warning
63
+
64
+ Use to alert users to potential issues.
65
+
66
+ ```tsx
67
+ toast.warning("Please review your input before continuing");
68
+ ```
69
+
70
+ ### Error
71
+
72
+ Use to inform users of errors or failures.
73
+
74
+ ```tsx
75
+ toast.error("Something went wrong. Please try again.");
76
+ ```
77
+
78
+ ## With Title
79
+
80
+ Add a title for more structured messages:
81
+
82
+ <Canvas of={ToastStories.WithTitle} />
83
+
84
+ ```tsx
85
+ toast.success("Your quote has been saved and sent to your email.", {
86
+ title: "Quote saved",
87
+ });
88
+ ```
89
+
90
+ ## Toaster Props
91
+
92
+ <ArgTypes of={Toaster} />
93
+
94
+ ## Toast Options
95
+
96
+ All toast functions accept an optional second parameter with these options:
97
+
98
+ <ArgTypes of={ToastOptionsDoc} />
99
+
100
+ ## Dismissing Toasts
101
+
102
+ Toasts can be dismissed in several ways:
103
+
104
+ 1. **Auto-dismiss**: After the configured duration (default 4 seconds)
105
+ 2. **Close button**: Clicking the X button
106
+ 3. **Keyboard**: Pressing Escape
107
+ 4. **Programmatically**: Using `toast.dismiss()`
108
+
109
+ ```tsx
110
+ // Dismiss all toasts
111
+ toast.dismiss();
112
+
113
+ // Dismiss a specific toast by ID
114
+ const toastId = toast.info("Loading...");
115
+ toast.dismiss(toastId);
116
+ ```
117
+
118
+ ## Accessibility
119
+
120
+ - Toasts use appropriate ARIA attributes for announcements
121
+ - Keyboard dismissal with Escape key
122
+ - Respects `prefers-reduced-motion` for animations
123
+ - Focus management for action buttons
124
+
125
+ ## Interactive Demo
126
+
127
+ Press 'R' to show a random toast in the interactive demo below:
128
+
129
+ <Canvas of={ToastStories.InteractiveDemo} />
130
+
131
+ {/* prettier-ignore-end */}