Skip to content

Commit e2ae3a1

Browse files
authored
Feature/toast (#82)
* Init toast * add event bus #76 (initial approach only)
1 parent 75a0275 commit e2ae3a1

20 files changed

+825
-9
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"release": "lerna publish from-package --force-publish"
2323
},
2424
"dependencies": {
25+
"@trutoo/event-bus": "^2.2.0",
2526
"codejar": "^3.7.0",
2627
"copy-to-clipboard": "^3.3.3",
2728
"highlight.js": "^11.7.0",

packages/angular/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
}
2424
},
2525
"dependencies": {
26+
"@trutoo/event-bus": "^2.2.0",
2627
"codejar": "^3.7.0",
2728
"copy-to-clipboard": "^3.3.3",
2829
"highlight.js": "^11.7.0",

packages/preact/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
}
2424
},
2525
"dependencies": {
26+
"@trutoo/event-bus": "^2.2.0",
2627
"codejar": "^3.7.0",
2728
"copy-to-clipboard": "^3.3.3",
2829
"highlight.js": "^11.7.0",

packages/qwik/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
}
3030
},
3131
"dependencies": {
32+
"@trutoo/event-bus": "^2.2.0",
3233
"codejar": "^3.7.0",
3334
"copy-to-clipboard": "^3.3.3",
3435
"highlight.js": "^11.7.0",

packages/react/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
}
2424
},
2525
"dependencies": {
26+
"@trutoo/event-bus": "^2.2.0",
2627
"codejar": "^3.7.0",
2728
"copy-to-clipboard": "^3.3.3",
2829
"highlight.js": "^11.7.0",

packages/react/yarn.lock

+357
Large diffs are not rendered by default.

packages/svelte/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
}
2525
},
2626
"dependencies": {
27+
"@trutoo/event-bus": "^2.2.0",
2728
"codejar": "^3.7.0",
2829
"copy-to-clipboard": "^3.3.3",
2930
"highlight.js": "^11.7.0",

packages/vue/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
}
2424
},
2525
"dependencies": {
26+
"@trutoo/event-bus": "^2.2.0",
2627
"codejar": "^3.7.0",
2728
"copy-to-clipboard": "^3.3.3",
2829
"highlight.js": "^11.7.0",
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as useToastExtension } from './toast.hook';
2+
export { default } from './toast.lite';
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { EventBus } from '@trutoo/event-bus';
2+
import { ToastCallback, ToastPayload } from './toast.model';
3+
4+
const BUS_NAME = 'toast';
5+
const bus = new EventBus();
6+
const state: ToastPayload[] = [];
7+
8+
// TODO: If more buses in the future, move to generic
9+
const subscribe = (callback: ToastCallback<ToastPayload>) => bus.subscribe(BUS_NAME, callback);
10+
const register = (optionsType = { type: Object }) => bus.register(BUS_NAME, optionsType);
11+
const publish = (payload: ToastPayload) => {
12+
state.push(payload);
13+
bus.publish(BUS_NAME, payload);
14+
};
15+
16+
// TODO: Can i move all the logic to the service??
17+
18+
export const toastBus = {
19+
subscribe,
20+
register,
21+
publish,
22+
state: () => state
23+
};
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@import '~/styles/build.css';
2+
3+
.pa-toast {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { debug } from '~/helpers';
2+
import { toastBus } from './toast.bus';
3+
import './toast.css';
4+
import { ToastPayload } from './toast.model';
5+
6+
const themes = {};
7+
8+
const actions: {
9+
[key: string]: (payload: ToastPayload) => void;
10+
} = {};
11+
12+
function actionFactory(name) {
13+
return (payload: ToastPayload) => {
14+
toastBus.publish({
15+
id: `${Math.random()}`,
16+
...payload
17+
});
18+
};
19+
}
20+
21+
function createTheme(name: string) {
22+
const properties = ['background', 'foreground'];
23+
const theme = {};
24+
25+
properties.forEach((property) => (theme[property] = `var(--pa-toast-${property}-${name})`));
26+
27+
debug(`ToastService createTheme: ${name}: ${JSON.stringify(theme)}`);
28+
29+
toastBus.register();
30+
themes[name] = theme;
31+
actions[name] = actionFactory(name);
32+
}
33+
34+
function triggerCustomAction(name: string, payload: ToastPayload) {
35+
return actions[name](payload);
36+
}
37+
38+
export default function useToastExtension() {
39+
createTheme('success');
40+
createTheme('error');
41+
42+
return { success: actions.success, error: actions.error, createTheme, trigger: triggerCustomAction };
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { For, onMount, onUnMount, useMetadata, useStore } from '@builder.io/mitosis';
2+
import './toast.css';
3+
import type { ToastProps, ToastState } from './toast.model';
4+
import { toastService } from './toast.service';
5+
6+
useMetadata({ isAttachedToShadowDom: true });
7+
8+
export default function Toast(props: ToastProps) {
9+
const state = useStore<ToastState>({
10+
get classes() {
11+
return toastService.getClasses(props.disabled, props.className || props.classList);
12+
},
13+
get toasts() {
14+
return toastService.getToasts();
15+
},
16+
toastSubscription: null
17+
});
18+
19+
onMount(() => {
20+
if (state.toastSubscription) {
21+
return;
22+
}
23+
24+
// TODO: This approach doesnt work looks like is not reactive enough I will try other approach
25+
state.toastSubscription = toastService.subscribe();
26+
});
27+
28+
onUnMount(() => {
29+
if (!state.toastSubscription) {
30+
return;
31+
}
32+
33+
state.toastSubscription.unsubscribe();
34+
});
35+
36+
return (
37+
<div class={state.classes.base}>
38+
<For each={state.toasts}>{(toast) => <div>{toast.message}</div>}</For>
39+
{props.children}
40+
</div>
41+
);
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { BaseProps, BaseState } from '~/models';
2+
3+
export interface ToastProps extends BaseProps {
4+
disabled?: boolean;
5+
}
6+
7+
export interface ToastState extends BaseState {
8+
classes: { base: string };
9+
toasts: ToastPayload[];
10+
toastSubscription: {
11+
unsubscribe(): void;
12+
};
13+
}
14+
15+
export type ToastPayload = {
16+
id?: string;
17+
message: string;
18+
};
19+
20+
// TODO Move to generic
21+
export type ToastChannelEvent<T> = {
22+
channel: string;
23+
payload: T | undefined;
24+
};
25+
26+
export type ToastCallback<T> = (event: ToastChannelEvent<T>) => void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { classesToString, debug } from '~/helpers';
2+
import { toastBus } from './toast.bus';
3+
import { ToastChannelEvent, ToastPayload } from './toast.model';
4+
5+
class ToastService {
6+
private toasts: ToastPayload[] = [];
7+
8+
private onChangeToasts(event: ToastChannelEvent<ToastPayload>) {
9+
this.toasts = toastBus.state();
10+
debug(`ToastService onChangeToasts: toasts: ${this.toasts}`);
11+
}
12+
13+
public getClasses(disabled: boolean, className: string) {
14+
const base = classesToString(['pa-toast', [disabled, 'is-disabled'], className || '']);
15+
16+
debug(`ToastService getClasses: base: ${base}`);
17+
return { base };
18+
}
19+
20+
public getToasts() {
21+
return this.toasts;
22+
}
23+
24+
public subscribe() {
25+
debug('ToastService subscribe');
26+
return toastBus.subscribe(this.onChangeToasts);
27+
}
28+
}
29+
30+
export const toastService = new ToastService();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs';
2+
import { Customization, Codesandbox } from '../../../../.storybook/components';
3+
import { Toast, useToastExtension } from '../../../../packages/react/src';
4+
5+
<Meta
6+
title="🧩Elements/Extensions/Toast"
7+
argTypes={{
8+
title: {
9+
name: 'title',
10+
description: 'A sample of attribute title',
11+
table: {},
12+
control: 'text'
13+
}
14+
}}
15+
/>
16+
17+
export const Template = (args) => (
18+
<div className="toast-example">
19+
{(() => {
20+
window.toast = useToastExtension();
21+
return '';
22+
})()}
23+
<div>
24+
<Toast />
25+
<span
26+
onClick={() => {
27+
// toast.success({ message: 'example' })
28+
window.toast.success({ message: 'example' + Math.random() });
29+
}}
30+
>
31+
Click me
32+
</span>
33+
</div>
34+
</div>
35+
);
36+
37+
# Toast
38+
39+
TODO
40+
41+
## Showcase
42+
43+
<Canvas>
44+
<Story
45+
name="Toast"
46+
args={{
47+
title: 'Title of my tooltip'
48+
}}
49+
>
50+
{Template.bind({})}
51+
</Story>
52+
</Canvas>
53+
54+
### Customization
55+
56+
<Customization showCode={false} />
57+
58+
### Properties
59+
60+
<ArgsTable story="Tooltip" />
61+
62+
## How to use this extension
63+
64+
### Angular
65+
66+
<Codesandbox
67+
extensions={['useTooltipExtension']}
68+
platform="angular"
69+
code={`
70+
<span title="Example of a tooltip">Hover me</span>`}
71+
/>
72+
73+
### Preact
74+
75+
<Codesandbox
76+
extensions={['useTooltipExtension']}
77+
platform="preact"
78+
code={`
79+
<span title="Example of a tooltip">Hover me</span>`}
80+
/>
81+
82+
### Qwik
83+
84+
<Codesandbox
85+
extensions={['useTooltipExtension']}
86+
platform="qwik"
87+
code={`
88+
<span title="Example of a tooltip">Hover me</span>`}
89+
/>
90+
91+
### React
92+
93+
<Codesandbox
94+
extensions={['useTooltipExtension']}
95+
platform="react"
96+
code={`
97+
<span title="Example of a tooltip">Hover me</span>`}
98+
/>
99+
100+
### Solid
101+
102+
<Codesandbox
103+
extensions={['useTooltipExtension']}
104+
platform="solid"
105+
code={`
106+
<span title="Example of a tooltip">Hover me</span>`}
107+
/>
108+
109+
### Svelte
110+
111+
<Codesandbox
112+
extensions={['useTooltipExtension']}
113+
platform="svelte"
114+
code={`
115+
<span title="Example of a tooltip">Hover me</span>`}
116+
/>
117+
118+
### Vue
119+
120+
<Codesandbox
121+
extensions={['useTooltipExtension']}
122+
platform="vue"
123+
code={`
124+
<span title="Example of a tooltip">Hover me</span>`}
125+
/>
126+
127+
### Web Components
128+
129+
<Codesandbox
130+
extensions={['useTooltipExtension']}
131+
platform="webcomponents"
132+
code={`<span title="Example of a tooltip">Hover me</span>`}
133+
/>
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { default } from './tooltip';
1+
export { default } from './tooltip.hook';

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export { default as Pill } from './elements/components/pill';
1010
export { default as Spinner } from './elements/components/spinner';
1111
export { default as Itchio } from './elements/enterprise/itchio';
1212
export { default as useTooltipExtension } from './elements/extensions/tooltip';
13+
// TODO this breaks command --element
14+
export { default as Toast, useToastExtension } from './elements/extensions/toast';
1315
export { default as Column } from './elements/layout/column';
1416
export { default as Container } from './elements/layout/container';
1517
export { default as Row } from './elements/layout/row';

0 commit comments

Comments
 (0)