UNPKG

14.1 kBTypeScriptView Raw
1import * as React from 'react';
2
3export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
4
5/**
6 * type MyType = {
7 * a: string
8 * b: never
9 * }
10 *
11 * OmitNever<MyType> --> { a: string }
12 */
13type OmitNever<T> = Pick<
14 T,
15 {
16 [Prop in keyof T]: [T[Prop]] extends [never] ? never : Prop;
17 }[keyof T]
18>;
19
20/**
21 * type Type1 = { a: string; b: number }
22 * type Type2 = { b: boolean; c: string }
23 *
24 * Override<Type1, Type2> --> {
25 * a: string
26 * b: boolean
27 * c: string
28 * }
29 */
30type Override<T, U> = Omit<T, keyof U> & U;
31
32type MarkInvalidVariantAsNever<T> = {
33 [Key in keyof T]: T[Key] extends true ? T[Key] : T[Key] extends Record<string, unknown> ? T[Key] : never;
34};
35
36type GetWhitelistedVariants<V extends string, U> = OmitNever<MarkInvalidVariantAsNever<Override<Record<V, true>, U>>>;
37
38export interface TransitionDuration {
39 enter?: number;
40 exit?: number;
41}
42
43export type TransitionStatus = 'entering' | 'entered' | 'exiting' | 'exited' | 'unmounted';
44
45export interface TransitionComponentProps extends Omit<TransitionProps, 'children'> {
46 children: (status: TransitionStatus, childProps: Record<string, any>) => React.ReactNode;
47 nodeRef: React.RefObject<HTMLDivElement>;
48}
49
50/**
51 * @category Shared
52 */
53export interface TransitionHandlerProps {
54 /**
55 * Callback fired before the transition is entering.
56 */
57 onEnter: (node: HTMLElement, isAppearing: boolean, key: SnackbarKey) => void;
58 /**
59 * Callback fired when the transition has entered.
60 */
61 onEntered: (node: HTMLElement, isAppearing: boolean, key: SnackbarKey) => void;
62 /**
63 * Callback fired before the transition is exiting.
64 */
65 onExit: (node: HTMLElement, key: SnackbarKey) => void;
66 /**
67 * Callback fired when the transition has exited.
68 */
69 onExited: (node: HTMLElement, key: SnackbarKey) => void;
70}
71
72export type SlideTransitionDirection = 'down' | 'left' | 'right' | 'up';
73
74export interface TransitionProps {
75 appear?: boolean;
76 /**
77 * Show the component; triggers the enter or exit states
78 */
79 in?: boolean;
80 /**
81 * The duration of the transition, in milliseconds
82 */
83 timeout?: number | TransitionDuration;
84 /**
85 * Enable or disable enter transitions.
86 */
87 enter?: boolean;
88 /**
89 * Enable or disable exit transitions.
90 */
91 exit?: boolean;
92 /**
93 * By default the child component is mounted immediately along with the
94 * parent Transition component. If you want to "lazy mount" the component on
95 * the first `in={true}` you can set `mountOnEnter`. After the first enter
96 * transition the component will stay mounted, even on "exited", unless you
97 * also specify `unmountOnExit`.
98 */
99 mountOnEnter?: boolean;
100 /**
101 * By default the child component stays mounted after it reaches the
102 * 'exited' state. Set `unmountOnExit` if you'd prefer to unmount the
103 * component after it finishes exiting.
104 */
105 unmountOnExit?: boolean;
106 /**
107 * Can be used to apply a custom `transitionTimingFunction` (e.g. your own easing),
108 * `transitionDuration` and `transitionDelay`.
109 */
110 style?: React.CSSProperties;
111 /**
112 * The direction in which a snackbar slides into the screen.
113 * Only applicable if `TransitionComponent` is Slide
114 */
115 direction?: SlideTransitionDirection;
116 children: React.ReactNode;
117 /**
118 * Callback fired before the transition is entering.
119 */
120 onEnter?: (node: HTMLElement, isAppearing: boolean) => void;
121 /**
122 * Callback fired when the transition has entered.
123 */
124 onEntered?: (node: HTMLElement, isAppearing: boolean) => void;
125 /**
126 * Callback fired when the transition is entering.
127 */
128 onEntering?: (node: HTMLElement, isAppearing: boolean) => void;
129 /**
130 * Callback fired before the transition is exiting.
131 */
132 onExit?: (node: HTMLElement) => void;
133 /**
134 * Callback fired when the transition has exited.
135 */
136 onExited?: (node: HTMLElement) => void;
137 /**
138 * Callback fired when the transition is existing.
139 */
140 onExiting?: (node: HTMLElement) => void;
141 addEndListener?: (node: HTMLElement | HTMLDivElement, callback: () => void) => void;
142}
143
144export type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>;
145
146// eslint-disable-next-line @typescript-eslint/no-empty-interface
147interface VariantOverrides {}
148
149type VariantMap = GetWhitelistedVariants<BaseVariant, VariantOverrides>;
150
151type BaseVariant = 'default' | 'error' | 'success' | 'warning' | 'info';
152
153export type VariantType = keyof VariantMap;
154
155export type SnackbarKey = string | number;
156export type CloseReason = 'timeout' | 'maxsnack' | 'instructed';
157
158export type SnackbarMessage = string | React.ReactNode;
159export type SnackbarAction = React.ReactNode | ((key: SnackbarKey) => React.ReactNode);
160export type SnackbarContentCallback =
161 | React.ReactNode
162 | ((key: SnackbarKey, message?: SnackbarMessage) => React.ReactNode);
163
164export type SnackbarClassKey =
165 | 'root'
166 | 'anchorOriginTopCenter'
167 | 'anchorOriginBottomCenter'
168 | 'anchorOriginTopRight'
169 | 'anchorOriginBottomRight'
170 | 'anchorOriginTopLeft'
171 | 'anchorOriginBottomLeft';
172
173export type ContainerClassKey =
174 | 'containerRoot'
175 | 'containerAnchorOriginTopCenter'
176 | 'containerAnchorOriginBottomCenter'
177 | 'containerAnchorOriginTopRight'
178 | 'containerAnchorOriginBottomRight'
179 | 'containerAnchorOriginTopLeft'
180 | 'containerAnchorOriginBottomLeft';
181
182export type CombinedClassKey = ContainerClassKey | SnackbarClassKey;
183
184export interface SnackbarOrigin {
185 vertical: 'top' | 'bottom';
186 horizontal: 'left' | 'center' | 'right';
187}
188
189export type SnackbarContentProps = React.HTMLAttributes<HTMLDivElement>;
190
191/**
192 * @category Shared
193 */
194export interface SharedProps<V extends VariantType = VariantType> extends Partial<TransitionHandlerProps> {
195 className?: string;
196 style?: React.CSSProperties;
197 /**
198 * The anchor of the `Snackbar`.
199 * @default { horizontal: left, vertical: bottom }
200 */
201 anchorOrigin?: SnackbarOrigin;
202 /**
203 * The number of milliseconds to wait before automatically calling the
204 * `onClose` function. By default snackbars get closed after 5000 milliseconds.
205 * Set autoHideDuration to 'null' if you don't want snackbars to automatically close.
206 * Alternatively pass `persist: true` in the options parameter of enqueueSnackbar.
207 * @default 5000
208 */
209 autoHideDuration?: number | null;
210 /**
211 * If `true`, the `autoHideDuration` timer will expire even if the window is not focused.
212 * @default false
213 */
214 disableWindowBlurListener?: boolean;
215 /**
216 * The component used for the transition. See how you can use a different transition:
217 * https://notistack.com/examples/advanced/custom-transition
218 * @default Slide
219 */
220 TransitionComponent?: React.JSXElementConstructor<TransitionProps & { children: React.ReactElement<any, any> }>;
221 /**
222 * The duration for the transition, in milliseconds.
223 *
224 * You may specify a single timeout for both enter and exit transitions:
225 * ```js
226 * timeout={500}
227 * ```
228 * or individually:
229 * ```js
230 * timeout={{ enter: 300, exit: 500 }}
231 * ```
232 * @default { enter: 225, exit: 195 }
233 */
234 transitionDuration?: TransitionProps['timeout'];
235 /**
236 * Properties applied to Transition component
237 */
238 TransitionProps?: Partial<TransitionProps>;
239 /**
240 * Used to easily display different variant of snackbars. When passed to `SnackbarProvider`
241 * all snackbars inherit the `variant`, unless you override it in `enqueueSnackbar` options.
242 * @default default
243 */
244 variant?: V;
245 /**
246 * Ignores displaying multiple snackbars with the same `message`
247 * @default false
248 */
249 preventDuplicate?: boolean;
250 /**
251 * Callback used for getting action(s). actions are mostly buttons displayed in Snackbar.
252 * @param {string|number} key key of a snackbar
253 */
254 action?: SnackbarAction;
255 /**
256 * Hides iconVariant if set to `true`.
257 * @default false
258 */
259 hideIconVariant?: boolean;
260 /**
261 * Properties applied to the Snackbar root element. You'd only want to use
262 * this prop to apply html attributes for accessibility or data-* attributes.
263 */
264 SnackbarProps?: React.HTMLAttributes<HTMLDivElement>;
265 /**
266 * Replace the snackbar. Callback used for displaying entirely customized snackbars.
267 * @param {string|number} key key of a snackbar
268 *
269 * @ignore
270 * @deprecated - Will be removed in future releases. You should use `Components` prop of
271 * `SnackbarProvider` to display a custom snackbar. This is to have more control over
272 * custom snackbars.
273 */
274 content?: SnackbarContentCallback;
275 /**
276 * Callback fired before snackbar requests to get closed.
277 * The `reason` parameter can optionally be used to control the response to `onClose`.
278 *
279 * @param {object} event The event source of the callback
280 * @param {string} reason Can be:`"timeout"` (`autoHideDuration` expired) or: `"maxsnack"`
281 * (snackbar was closed because `maxSnack` has reached) or: `"instructed"` (snackbar was
282 * closed programmatically)
283 * @param {string|number|undefined} key key of a Snackbar. key will be `undefined` if closeSnackbar
284 * is called with no key (user requested all the snackbars to be closed)
285 */
286 onClose?: (event: React.SyntheticEvent<any> | null, reason: CloseReason, key?: SnackbarKey) => void;
287}
288
289/**
290 * @category Enqueue
291 */
292export interface OptionsObject<V extends VariantType = VariantType> extends SharedProps<V> {
293 /**
294 * Unique identifier to reference a snackbar.
295 * @default string random unique string
296 */
297 key?: SnackbarKey;
298 /**
299 * Snackbar stays on the screen, unless it is dismissed (programmatically or through user interaction).
300 * @default false
301 */
302 persist?: boolean;
303}
304
305/** Properties of the internal snack which should not be exposed to outside world */
306interface InternalSnackAttributes {
307 open: boolean;
308 entered: boolean;
309 requestClose: boolean;
310}
311
312type NeededByInternalSnack =
313 | 'style'
314 | 'persist'
315 | 'variant'
316 | 'anchorOrigin'
317 | 'TransitionComponent'
318 | 'TransitionProps'
319 | 'transitionDuration'
320 | 'hideIconVariant'
321 | 'disableWindowBlurListener';
322
323/**
324 * Properties of a snackbar internal to notistack implementation. Not to be used by outside
325 * world. If you find yourself using this, you're probably looking for `CustomContentProps` type.
326 */
327export interface InternalSnack
328 extends RequiredBy<Omit<OptionsObject, 'key' | 'preventDuplicate'>, NeededByInternalSnack>,
329 InternalSnackAttributes {
330 id: SnackbarKey;
331 message?: SnackbarMessage;
332 iconVariant: Record<string, React.ReactNode>;
333}
334
335type NotNeededByCustomSnackbar =
336 | keyof InternalSnackAttributes
337 | keyof TransitionHandlerProps
338 | 'onClose'
339 | 'SnackbarProps'
340 | 'disableWindowBlurListener'
341 | 'TransitionComponent'
342 | 'transitionDuration'
343 | 'TransitionProps'
344 | 'dense'
345 | 'content';
346
347/**
348 * Props that will be passed to a custom component in `SnackbarProvider` `Components` prop
349 */
350export type CustomContentProps = Omit<InternalSnack, NotNeededByCustomSnackbar>;
351
352/**
353 * @category Provider
354 */
355export interface SnackbarProviderProps extends SharedProps {
356 /**
357 * Most of the time this is your App. every component from this point onward
358 * will be able to show snackbars.
359 */
360 children?: React.ReactNode | React.ReactNode[];
361 /**
362 * Denser margins for snackbars. Recommended to be used on mobile devices.
363 * @default false
364 */
365 dense?: boolean;
366 /**
367 * Maximum snackbars that can be stacked on top of one another.
368 * @default 3
369 */
370 maxSnack?: number;
371 /**
372 * Valid HTML Node element, used to target `ReactDOM.createPortal`. If you are
373 * using this prop, most likely you also want to apply `position: absolute` to SnackbarContainer.
374 */
375 domRoot?: HTMLElement;
376 /**
377 * Override or extend the styles applied to the container component or Snackbars.
378 */
379 classes?: Partial<ClassNameMap<CombinedClassKey>>;
380 /**
381 * Mapping between variants and an icon component
382 */
383 iconVariant?: Partial<Record<VariantType, React.ReactNode>>;
384 /**
385 * @ignore
386 * SnackbarProvider's ref
387 */
388 ref?: React.Ref<SnackbarProvider>;
389 /**
390 * Mapping between variants and a custom component.
391 */
392 Components?: {
393 [variant in VariantType]?: React.JSXElementConstructor<any>;
394 };
395}
396
397type OptionsWithExtraProps<V extends VariantType> = VariantMap[V] extends true
398 ? OptionsObject<V>
399 : OptionsObject<V> & VariantMap[V];
400
401interface EnqueueSnackbar {
402 <V extends VariantType>(options: OptionsWithExtraProps<V> & { message?: SnackbarMessage }): SnackbarKey;
403 <V extends VariantType>(message: SnackbarMessage, options?: OptionsWithExtraProps<V>): SnackbarKey;
404}
405
406export interface ProviderContext {
407 enqueueSnackbar: EnqueueSnackbar;
408 closeSnackbar: (key?: SnackbarKey) => void;
409}
410
411export declare class SnackbarProvider extends React.Component<SnackbarProviderProps> {
412 enqueueSnackbar: ProviderContext['enqueueSnackbar'];
413 closeSnackbar: ProviderContext['closeSnackbar'];
414 render(): React.ReactNode;
415}
416
417export declare function useSnackbar(): ProviderContext;
418
419export declare const enqueueSnackbar: ProviderContext['enqueueSnackbar'];
420export declare const closeSnackbar: ProviderContext['closeSnackbar'];
421
422export declare const SnackbarContent: (
423 props: SnackbarContentProps & React.RefAttributes<HTMLDivElement>
424) => React.ReactElement<any, any>;
425
426export declare const Transition: React.JSXElementConstructor<TransitionComponentProps>;
427
428export declare const MaterialDesignContent: (
429 props: CustomContentProps & React.RefAttributes<HTMLDivElement>
430) => React.ReactElement<any, any>;