refactor(editor): extract common components (#9277)

This commit is contained in:
Saul-Mirone
2024-12-24 04:42:53 +00:00
parent 475e3d80b2
commit ea0a345533
10 changed files with 42 additions and 42 deletions

View File

@@ -0,0 +1,74 @@
import type { BlockComponent } from '@blocksuite/block-std';
import { SignalWatcher } from '@blocksuite/global/utils';
import { css, LitElement, type PropertyValues } from 'lit';
import { property } from 'lit/decorators.js';
/**
* Renders a the block selection.
*
* @example
* ```ts
* class Block extends LitElement {
* state override styles = css`
* :host {
* position: relative;
* }
*
* render() {
* return html`<affine-block-selection></affine-block-selection>
* };
* }
* ```
*/
export class BlockSelection extends SignalWatcher(LitElement) {
static override styles = css`
:host {
position: absolute;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
background-color: var(--affine-hover-color);
border-color: transparent;
border-style: solid;
}
`;
override connectedCallback(): void {
super.connectedCallback();
this.style.borderRadius = `${this.borderRadius}px`;
if (this.borderWidth !== 0) {
this.style.boxSizing = 'content-box';
this.style.transform = `translate(-${this.borderWidth}px, -${this.borderWidth}px)`;
}
this.style.borderWidth = `${this.borderWidth}px`;
}
override disconnectedCallback() {
super.disconnectedCallback();
this.block = null as unknown as BlockComponent; // force gc
}
protected override updated(_changedProperties: PropertyValues): void {
super.updated(_changedProperties);
this.style.display = this.block.selected?.is('block') ? 'block' : 'none';
}
@property({ attribute: false })
accessor block!: BlockComponent;
@property({ attribute: false })
accessor borderRadius: number = 5;
@property({ attribute: false })
accessor borderWidth: number = 0;
}
declare global {
interface HTMLElementTagNameMap {
'affine-block-selection': BlockSelection;
}
}

View File

@@ -0,0 +1,54 @@
import { stopPropagation } from '@blocksuite/affine-shared/utils';
import type { BlockComponent } from '@blocksuite/block-std';
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { focusTextModel } from '../rich-text';
export class BlockZeroWidth extends LitElement {
static override styles = css`
.block-zero-width {
position: absolute;
bottom: -15px;
height: 10px;
width: 100%;
cursor: text;
z-index: 1;
}
`;
_handleClick = (e: MouseEvent) => {
stopPropagation(e);
if (this.block.doc.readonly) return;
const nextBlock = this.block.doc.getNext(this.block.model);
if (nextBlock?.flavour !== 'affine:paragraph') {
const [paragraphId] = this.block.doc.addSiblingBlocks(this.block.model, [
{ flavour: 'affine:paragraph' },
]);
focusTextModel(this.block.host.std, paragraphId);
}
};
override connectedCallback(): void {
super.connectedCallback();
this.addEventListener('click', this._handleClick);
}
override disconnectedCallback(): void {
this.removeEventListener('click', this._handleClick);
super.disconnectedCallback();
}
override render() {
return html`<div class="block-zero-width"></div>`;
}
@property({ attribute: false })
accessor block!: BlockComponent;
}
declare global {
interface HTMLElementTagNameMap {
'block-zero-width': BlockZeroWidth;
}
}

View File

@@ -1,16 +1,19 @@
import { MenuButton, MobileMenuButton } from './button.js';
import { MenuInput, MobileMenuInput } from './input.js';
import { MenuComponent, MobileMenuComponent } from './menu-renderer.js';
import { MenuSubMenu, MobileSubMenu } from './sub-menu.js';
import { MenuButton, MobileMenuButton } from './button';
import { MenuInput, MobileMenuInput } from './input';
import { MenuDivider } from './menu-divider';
import { MenuComponent, MobileMenuComponent } from './menu-renderer';
import { MenuSubMenu, MobileSubMenu } from './sub-menu';
export * from './button.js';
export * from './focusable.js';
export * from './group.js';
export * from './input.js';
export * from './item.js';
export * from './menu.js';
export * from './menu-renderer.js';
export * from './sub-menu.js';
export * from './button';
export * from './focusable';
export * from './group';
export * from './input';
export * from './item';
export * from './menu';
export * from './menu-all';
export * from './menu-divider';
export * from './menu-renderer';
export * from './sub-menu';
export function effects() {
customElements.define('affine-menu', MenuComponent);
@@ -21,6 +24,7 @@ export function effects() {
customElements.define('mobile-menu-input', MobileMenuInput);
customElements.define('affine-menu-sub-menu', MenuSubMenu);
customElements.define('mobile-sub-menu', MobileSubMenu);
customElements.define('menu-divider', MenuDivider);
}
export * from './types.js';

View File

@@ -0,0 +1,14 @@
import { menuButtonItems } from './button';
import { menuDynamicItems } from './dynamic';
import { menuGroupItems } from './group';
import { menuInputItems } from './input';
import { subMenuItems } from './sub-menu';
import type { MenuItemRender } from './types';
export const menu = {
...menuButtonItems,
...subMenuItems,
...menuInputItems,
...menuGroupItems,
...menuDynamicItems,
} satisfies Record<string, MenuItemRender<never>>;

View File

@@ -0,0 +1,50 @@
import { css, html, LitElement } from 'lit';
import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
// FIXME: horizontal
export class MenuDivider extends LitElement {
static override styles = css`
:host {
display: inline-block;
}
.divider {
background-color: var(--affine-border-color);
}
.divider.vertical {
width: 1px;
height: 100%;
margin: 0 var(--divider-margin);
}
.divider.horizontal {
width: 100%;
height: 1px;
margin: var(--divider-margin) 0;
}
`;
override render() {
const dividerStyles = styleMap({
'--divider-margin': `${this.dividerMargin}px`,
});
return html`<div
class="divider ${this.vertical ? 'vertical' : 'horizontal'}"
style=${dividerStyles}
></div>`;
}
@property({ attribute: false })
accessor dividerMargin = 7;
@property({ attribute: false })
accessor vertical = false;
}
declare global {
interface HTMLElementTagNameMap {
'menu-divider': MenuDivider;
}
}

View File

@@ -2,23 +2,9 @@ import { IS_MOBILE } from '@blocksuite/global/env';
import { computed, signal } from '@preact/signals-core';
import type { TemplateResult } from 'lit';
import { menuButtonItems } from './button.js';
import { menuDynamicItems } from './dynamic.js';
import { MenuFocusable } from './focusable.js';
import { menuGroupItems } from './group.js';
import { menuInputItems } from './input.js';
// eslint-disable-next-line
import { MenuComponent, MobileMenuComponent } from './menu-renderer.js';
import { subMenuItems } from './sub-menu.js';
import type { MenuComponentInterface, MenuItemRender } from './types.js';
import type { MenuComponentInterface } from './types.js';
export const menu = {
...menuButtonItems,
...subMenuItems,
...menuInputItems,
...menuGroupItems,
...menuDynamicItems,
} satisfies Record<string, MenuItemRender<never>>;
export type MenuConfig = (
menu: Menu,
index: number
@@ -83,8 +69,8 @@ export class Menu {
constructor(public options: MenuOptions) {
this.menuElement = IS_MOBILE
? new MobileMenuComponent()
: new MenuComponent();
? document.createElement('affine-menu-mobile')
: document.createElement('affine-menu');
this.menuElement.menu = this;
// Call global menu open listeners