-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
744 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import type { Subscription } from 'rxjs'; | ||
|
||
import { useEffect, useMemo } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
|
||
import { useImmer, usePrefixConfig } from '../../hooks'; | ||
import { DToast, ToastService, toastSubject } from '../toast'; | ||
|
||
export function Toast() { | ||
//#region Context | ||
const dPrefix = usePrefixConfig(); | ||
//#endregion | ||
|
||
const [toasts, setToasts] = useImmer(new Map<number, any>()); | ||
|
||
useEffect(() => { | ||
const obs: Subscription[] = []; | ||
const mergeProps = (uniqueId: number, props: any) => { | ||
return { | ||
onClose: () => { | ||
props.onClose?.(); | ||
|
||
ToastService.close(uniqueId); | ||
}, | ||
afterVisibleChange: (visible: boolean) => { | ||
props.afterVisibleChange?.(visible); | ||
|
||
if (!visible) { | ||
setToasts((draft) => { | ||
draft.delete(uniqueId); | ||
}); | ||
} | ||
}, | ||
}; | ||
}; | ||
obs.push( | ||
toastSubject.open.subscribe({ | ||
next: ({ uniqueId, props }) => { | ||
setToasts((draft) => { | ||
draft.set(uniqueId, { ...props, dVisible: true, ...mergeProps(uniqueId, props) }); | ||
}); | ||
}, | ||
}), | ||
toastSubject.close.subscribe({ | ||
next: (uniqueId) => { | ||
setToasts((draft) => { | ||
const props = draft.get(uniqueId); | ||
if (props) { | ||
draft.set(uniqueId, { ...props, dVisible: false }); | ||
} | ||
}); | ||
}, | ||
}), | ||
toastSubject.rerender.subscribe({ | ||
next: ({ uniqueId, props: newProps }) => { | ||
setToasts((draft) => { | ||
const props = draft.get(uniqueId); | ||
if (props) { | ||
draft.set(uniqueId, { ...newProps, dVisible: props.dVisible, ...mergeProps(uniqueId, newProps) }); | ||
} | ||
}); | ||
}, | ||
}), | ||
toastSubject.closeAll.subscribe({ | ||
next: (animation) => { | ||
setToasts((draft) => { | ||
if (animation) { | ||
for (const props of draft.values()) { | ||
props.dVisible = false; | ||
} | ||
} else { | ||
draft.clear(); | ||
} | ||
}); | ||
}, | ||
}) | ||
); | ||
}, [setToasts]); | ||
|
||
const [toastTRoot, toastBRoot] = useMemo(() => { | ||
const getRoot = (id: string) => { | ||
let root = document.getElementById(`${dPrefix}toast-root`); | ||
if (!root) { | ||
root = document.createElement('div'); | ||
root.id = `${dPrefix}toast-root`; | ||
document.body.appendChild(root); | ||
} | ||
|
||
let el = document.getElementById(id); | ||
if (!el) { | ||
el = document.createElement('div'); | ||
el.id = id; | ||
root.appendChild(el); | ||
} | ||
return el; | ||
}; | ||
|
||
return [getRoot(`${dPrefix}toast-t-root`), getRoot(`${dPrefix}toast-b-root`)]; | ||
}, [dPrefix]); | ||
|
||
return ( | ||
<> | ||
{ReactDOM.createPortal( | ||
Array.from(toasts.entries()) | ||
.filter(([uniqueId, toastProps]) => (toastProps.dPlacement ?? 'top') === 'top') | ||
.map(([uniqueId, toastProps]) => <DToast key={uniqueId} {...toastProps}></DToast>), | ||
toastTRoot | ||
)} | ||
{ReactDOM.createPortal( | ||
Array.from(toasts.entries()) | ||
.filter(([uniqueId, toastProps]) => toastProps.dPlacement === 'bottom') | ||
.map(([uniqueId, toastProps]) => <DToast key={uniqueId} {...toastProps}></DToast>), | ||
toastBRoot | ||
)} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
--- | ||
group: Feedback | ||
title: Toast | ||
--- | ||
|
||
Toast. | ||
|
||
## When To Use | ||
|
||
Global display operation feedback information. | ||
|
||
## API | ||
|
||
### DToastProps | ||
|
||
Extend `React.HTMLAttributes<HTMLDivElement>`. | ||
|
||
<!-- prettier-ignore-start --> | ||
| Property | Description | Type | Default | | ||
| --- | --- | --- | --- | | ||
| dType | Toast type | 'success' \| 'warning' \| 'error' \| 'info' | - | | ||
| dIcon | Custom toast icon | React.ReactNode | - | | ||
| dContent | Content | React.ReactNode | - | | ||
| dDuration | Display duration, will not be closed automatically when it is 0 | number | 9.6 | | ||
| dPlacement | Toast pop-up direction | 'top' \| 'bottom' | 'top' | | ||
| onClose | Callback when the toast is closed | `() => void` | - | | ||
| afterVisibleChange | Callback to the end of the opening/closing animation | `(visible: boolean) => void` | - | | ||
<!-- prettier-ignore-end --> | ||
|
||
### ToastService | ||
|
||
```tsx | ||
class ToastService { | ||
// Toast list | ||
static readonly toasts: Toast[]; | ||
|
||
// Open toast | ||
static open(props: DToastProps): Toast; | ||
|
||
// Close toast | ||
static close(uniqueId: number): void; | ||
|
||
// Update toast | ||
static rerender(uniqueId: number, props: DToastProps): void; | ||
|
||
// Close all toasts | ||
static closeAll(animation = true): void; | ||
} | ||
``` | ||
|
||
### Toast | ||
|
||
```tsx | ||
class Toast { | ||
// Uniquely identifies | ||
readonly uniqueId: number; | ||
|
||
// Close toast | ||
close(): void; | ||
|
||
// Update toast | ||
rerender(props: DToastProps): void; | ||
} | ||
``` |
Oops, something went wrong.