mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 18:26:05 +08:00
chore: merge blocksuite source code (#9213)
This commit is contained in:
39
blocksuite/affine/components/src/toast/create.ts
Normal file
39
blocksuite/affine/components/src/toast/create.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { BlockComponent, EditorHost } from '@blocksuite/block-std';
|
||||
import { html } from 'lit';
|
||||
|
||||
import { htmlToElement } from './html-to-element.js';
|
||||
|
||||
export const createToastContainer = (editorHost: EditorHost) => {
|
||||
const styles = `
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 16px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
bottom: 78px;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
align-items: center;
|
||||
`;
|
||||
const template = html`<div class="toast-container" style="${styles}"></div>`;
|
||||
const element = htmlToElement<HTMLDivElement>(template);
|
||||
const { std, doc } = editorHost;
|
||||
|
||||
let container = document.body;
|
||||
if (doc.root) {
|
||||
const rootComponent = std.view.getBlock(doc.root.id) as BlockComponent & {
|
||||
viewportElement: HTMLElement;
|
||||
};
|
||||
if (rootComponent) {
|
||||
const viewportElement = rootComponent.viewportElement;
|
||||
const editorContainer = viewportElement.parentElement;
|
||||
if (editorContainer) {
|
||||
container = editorContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
container.append(element);
|
||||
|
||||
return element;
|
||||
};
|
||||
19
blocksuite/affine/components/src/toast/html-to-element.ts
Normal file
19
blocksuite/affine/components/src/toast/html-to-element.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
/**
|
||||
* DO NOT USE FOR USER INPUT
|
||||
* See https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518
|
||||
*/
|
||||
export const htmlToElement = <T extends ChildNode>(
|
||||
html: string | TemplateResult
|
||||
) => {
|
||||
const template = document.createElement('template');
|
||||
if (typeof html === 'string') {
|
||||
html = html.trim(); // Never return a text node of whitespace as the result
|
||||
template.innerHTML = html;
|
||||
} else {
|
||||
const htmlString = String.raw(html.strings, ...html.values);
|
||||
template.innerHTML = htmlString;
|
||||
}
|
||||
return template.content.firstChild as T;
|
||||
};
|
||||
1
blocksuite/affine/components/src/toast/index.ts
Normal file
1
blocksuite/affine/components/src/toast/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { toast } from './toast.js';
|
||||
80
blocksuite/affine/components/src/toast/toast.ts
Normal file
80
blocksuite/affine/components/src/toast/toast.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import type { EditorHost } from '@blocksuite/block-std';
|
||||
import { baseTheme } from '@toeverything/theme';
|
||||
import { html } from 'lit';
|
||||
|
||||
import { createToastContainer } from './create.js';
|
||||
import { htmlToElement } from './html-to-element.js';
|
||||
|
||||
let ToastContainer: HTMLDivElement | null = null;
|
||||
|
||||
/**
|
||||
* @example
|
||||
* ```ts
|
||||
* toast('Hello World');
|
||||
* ```
|
||||
*/
|
||||
export const toast = (
|
||||
editorHost: EditorHost,
|
||||
message: string,
|
||||
duration = 2500
|
||||
) => {
|
||||
if (!ToastContainer) {
|
||||
ToastContainer = createToastContainer(editorHost);
|
||||
}
|
||||
|
||||
const styles = `
|
||||
max-width: 480px;
|
||||
text-align: center;
|
||||
font-family: ${baseTheme.fontSansFamily};
|
||||
font-size: var(--affine-font-sm);
|
||||
padding: 6px 12px;
|
||||
margin: 10px 0 0 0;
|
||||
color: var(--affine-white);
|
||||
background: var(--affine-tooltip);
|
||||
box-shadow: var(--affine-float-button-shadow);
|
||||
border-radius: 10px;
|
||||
transition: all 230ms cubic-bezier(0.21, 1.02, 0.73, 1);
|
||||
opacity: 0;
|
||||
`;
|
||||
|
||||
const template = html`<div style="${styles}"></div>`;
|
||||
const element = htmlToElement<HTMLDivElement>(template);
|
||||
// message is not trusted
|
||||
element.textContent = message;
|
||||
ToastContainer?.append(element);
|
||||
|
||||
const fadeIn = [
|
||||
{
|
||||
opacity: 0,
|
||||
},
|
||||
{ opacity: 1 },
|
||||
];
|
||||
const options = {
|
||||
duration: 230,
|
||||
easing: 'cubic-bezier(0.21, 1.02, 0.73, 1)',
|
||||
fill: 'forwards' as const,
|
||||
}; // satisfies KeyframeAnimationOptions;
|
||||
element.animate(fadeIn, options);
|
||||
|
||||
setTimeout(() => {
|
||||
const fadeOut = fadeIn.reverse();
|
||||
const animation = element.animate(fadeOut, options);
|
||||
animation.finished
|
||||
.then(() => {
|
||||
element.style.maxHeight = '0';
|
||||
element.style.margin = '0';
|
||||
element.style.padding = '0';
|
||||
element.addEventListener(
|
||||
'transitionend',
|
||||
() => {
|
||||
element.remove();
|
||||
},
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(console.error);
|
||||
}, duration);
|
||||
return element;
|
||||
};
|
||||
Reference in New Issue
Block a user