Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toaster: Add methods to close individual or all toasts #5537

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2470,7 +2470,8 @@ export namespace Components {
"_value"?: string;
}
interface KolToastContainer {
"enqueue": (toast: Toast) => Promise<void>;
"closeAll": () => Promise<void>;
"enqueue": (toast: Toast) => Promise<() => void>;
}
interface KolTooltipWc {
/**
Expand Down
1 change: 0 additions & 1 deletion packages/components/src/components/accordion/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export class KolAccordion implements API {
<kol-heading-wc _label="" _level={this.state._level}>
<kol-button-wc
ref={this.catchRef}
slot="expert"
deleonio marked this conversation as resolved.
Show resolved Hide resolved
_ariaControls={this.nonce}
_ariaExpanded={this.state._open}
_icons={this.state._open ? 'codicon codicon-remove' : 'codicon codicon-add'}
Expand Down
26 changes: 20 additions & 6 deletions packages/components/src/components/toaster/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class KolToastContainer implements API {
// Stencil requires async function:
// eslint-disable-next-line @typescript-eslint/require-await
@Method()
async enqueue(toast: Toast) {
public async enqueue(toast: Toast) {
const newToastState: ToastState = {
toast,
status: 'adding',
Expand All @@ -37,7 +37,7 @@ export class KolToastContainer implements API {
this.state = {
...this.state,
_toastStates: this.state._toastStates.map((localToastState) =>
localToastState === newToastState
localToastState.id === newToastState.id
? {
...localToastState,
status: 'settled',
Expand All @@ -46,13 +46,17 @@ export class KolToastContainer implements API {
),
};
}, TRANSITION_TIMEOUT);

return () => {
this.handleClose(newToastState);
};
}

private handleClose(toastState: ToastState) {
this.state = {
...this.state,
_toastStates: this.state._toastStates.map((localToastState) => {
if (localToastState === toastState) {
if (localToastState.id === toastState.id) {
localToastState.status = 'removing';
}
return localToastState;
Expand All @@ -62,12 +66,14 @@ export class KolToastContainer implements API {
setTimeout(() => {
this.state = {
...this.state,
_toastStates: this.state._toastStates.filter((localToastState) => localToastState !== toastState),
_toastStates: this.state._toastStates.filter((localToastState) => localToastState.id !== toastState.id),
};
}, TRANSITION_TIMEOUT);
}

private handleCloseAllClick() {
// eslint-disable-next-line @typescript-eslint/require-await
@Method()
public async closeAll() {
this.state = {
...this.state,
_toastStates: this.state._toastStates.map((localToastState) => ({
Expand All @@ -88,7 +94,15 @@ export class KolToastContainer implements API {
return (
<>
{this.state._toastStates.length > 1 && (
<kol-button _label={translate('kol-toast-close-all')} class="close-all" _on={{ onClick: this.handleCloseAllClick.bind(this) }}></kol-button>
<kol-button
_label={translate('kol-toast-close-all')}
class="close-all"
_on={{
onClick: () => {
void this.closeAll();
},
}}
></kol-button>
)}
{this.state._toastStates.map((toastState) => (
<InternalToast toastState={toastState} onClose={() => this.handleClose(toastState)} key={toastState.id} />
Expand Down
9 changes: 8 additions & 1 deletion packages/components/src/components/toaster/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ toaster.enqueue({
});
```

### Weitere Service-Methoden

- `closeAll`: Schließt alle Toasts
- `dispose`: Entfernt den Toast Container. Die Toaster-Instanz kann nicht weiter genutzt werden.

## Verwendung

### Überschrift
Expand All @@ -37,7 +42,7 @@ Alternativ zur statischen Description können Sie über das Attribut **`_render`
HTMLElement der Toast-Komponente aufgerufen. Zudem wird auch ein Objekt übergeben, das eine `close`-Funktion zum Schließen des Toasts bereitstellt.

```ts
void toaster.enqueue({
const closeToast = toaster.enqueue({
render: (element: HTMLElement, { close }) => {
element.textContent = 'Mein Inhalt';
const customCloseButton = document.createElement('button');
Expand All @@ -46,6 +51,8 @@ void toaster.enqueue({
customCloseButton.addEventListener('click', close, { once: true });
},
});

/* Optional: Toast wieder schließen mit `closeToast()` */
```

### Anzeigetyp des Toast
Expand Down
10 changes: 8 additions & 2 deletions packages/components/src/components/toaster/toaster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@ export class ToasterService {
}
}

public async enqueue(toast: Toast) {
public enqueue(toast: Toast): Promise<() => void> | undefined {
/**
* We need this condition for SSR. The toast container is not rendered on the server,
* so we can't enqueue toasts.
*/
if (this.toastContainerElement && typeof this.toastContainerElement.enqueue === 'function') {
await this.toastContainerElement.enqueue(toast);
return this.toastContainerElement.enqueue(toast);
}
}

public closeAll(): void {
if (this.toastContainerElement && typeof this.toastContainerElement.closeAll === 'function') {
void this.toastContainerElement.closeAll();
}
}
}
92 changes: 58 additions & 34 deletions packages/samples/react/src/components/toast/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,63 @@ import { getRoot } from '../../shares/react-roots';

const toaster = ToasterService.getInstance(document);

const handleButtonClickSimple = () => {
void toaster.enqueue({
description: 'Toasty',
label: `Initial Toast`,
type: 'warning',
});
};
export const ToastBasic: FC = () => {
const handleButtonClickSimple = () => {
void toaster.enqueue({
description: 'Toasty',
label: `Initial Toast`,
type: 'warning',
});
};

const handleButtonClickComplex = () => {
void toaster.enqueue({
render: (element: HTMLElement, { close }) => {
getRoot(element).render(
<>
<KolButton
_label={'Hello World from Toast!'}
_on={{
onClick: () => {
console.log('Toast Button clicked!');
close();
},
}}
/>
</>,
);
},
label: `Initial Toast`,
type: 'warning',
});
};
const handleButtonClickComplex = () => {
void toaster.enqueue({
render: (element: HTMLElement, { close }) => {
getRoot(element).render(
<>
<KolButton
_label={'Hello World from Toast!'}
_on={{
onClick: () => {
console.log('Toast Button clicked!');
close();
},
}}
/>
</>,
);
},
label: `Initial Toast`,
type: 'warning',
});
};

const handleButtonClickOpenAndClose = async () => {
const close = await toaster.enqueue({
description: 'I will disappear in two seconds...',
label: `Good Bye`,
type: 'warning',
});

export const ToastBasic: FC = () => (
<div>
<KolButton _label="Show simple toast" _on={{ onClick: handleButtonClickSimple }}></KolButton>
<KolButton _label="Show complex toast" _on={{ onClick: handleButtonClickComplex }}></KolButton>
</div>
);
if (close) {
setTimeout(close, 2000);
}
};

const closeAll = () => {
toaster.closeAll();
};

return (
<div>
<KolButton _label="Show simple toast" _on={{ onClick: handleButtonClickSimple }}></KolButton>
<KolButton _label="Show complex toast" _on={{ onClick: handleButtonClickComplex }}></KolButton>
<br />
<br />
<KolButton _label="Show toast and close after 2 seconds" _on={{ onClick: () => void handleButtonClickOpenAndClose() }}></KolButton>
<br />
<br />
<KolButton _label="Close all toasts" _on={{ onClick: closeAll }}></KolButton>
</div>
);
};
Loading