mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-23 21:06:22 +08:00
refactor(editor): implement uni-component in AFFiNE (#10747)
This commit is contained in:
@@ -5,7 +5,7 @@ import type {
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { IS_MOBILE } from '@blocksuite/global/env';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||
import { computed, type ReadonlySignal } from '@preact/signals-core';
|
||||
import { computed, type ReadonlySignal, signal } from '@preact/signals-core';
|
||||
import { css, unsafeCSS } from 'lit';
|
||||
import { property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
@@ -63,7 +63,7 @@ export class DataViewRenderer extends SignalWatcher(
|
||||
}
|
||||
`;
|
||||
|
||||
private readonly _view = createRef<{
|
||||
private readonly _view = signal<{
|
||||
expose: DataViewInstance;
|
||||
}>();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
popMenu,
|
||||
popupTargetFromElement,
|
||||
} from '@blocksuite/affine-components/context-menu';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { SignalWatcher, WithDisposable } from '@blocksuite/global/lit';
|
||||
import {
|
||||
@@ -19,10 +20,7 @@ import { repeat } from 'lit/directives/repeat.js';
|
||||
import { html } from 'lit/static-html.js';
|
||||
|
||||
import { dataViewCommonStyle } from '../common/css-variable.js';
|
||||
import {
|
||||
renderUniLit,
|
||||
type UniComponent,
|
||||
} from '../utils/uni-component/uni-component.js';
|
||||
import { renderUniLit } from '../utils/uni-component/uni-component.js';
|
||||
import type { SingleView } from '../view-manager/single-view.js';
|
||||
import { DetailSelection } from './selection.js';
|
||||
|
||||
|
||||
@@ -11,11 +11,10 @@ import {
|
||||
MoveLeftIcon,
|
||||
MoveRightIcon,
|
||||
} from '@blocksuite/icons/lit';
|
||||
import { computed } from '@preact/signals-core';
|
||||
import { computed, signal } from '@preact/signals-core';
|
||||
import { css } from 'lit';
|
||||
import { property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { createRef } from 'lit/directives/ref.js';
|
||||
import { html } from 'lit/static-html.js';
|
||||
|
||||
import { inputConfig, typeConfig } from '../common/property-menu.js';
|
||||
@@ -109,7 +108,7 @@ export class RecordField extends SignalWatcher(
|
||||
}
|
||||
`;
|
||||
|
||||
private readonly _cell = createRef<DataViewCellLifeCycle>();
|
||||
private readonly _cell = signal<DataViewCellLifeCycle>();
|
||||
|
||||
_click = (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import type { TypeInstance } from '../logical/type.js';
|
||||
import type { UniComponent } from '../utils/index.js';
|
||||
|
||||
export type VariableRef = {
|
||||
type: 'ref';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import type { TypeInstance } from '../logical/type.js';
|
||||
import type { DVJSON } from '../property/types.js';
|
||||
import type { UniComponent } from '../utils/index.js';
|
||||
|
||||
export interface GroupRenderProps<
|
||||
Data extends NonNullable<unknown> = NonNullable<unknown>,
|
||||
|
||||
@@ -13,6 +13,10 @@ export abstract class BaseCellRenderer<
|
||||
extends SignalWatcher(WithDisposable(ShadowlessElement))
|
||||
implements DataViewCellLifeCycle, CellRenderProps<Data, Value>
|
||||
{
|
||||
get expose() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor cell!: Cell<Value, Data>;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { UniComponent } from '../utils/uni-component/index.js';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import type { Cell } from '../view-manager/cell.js';
|
||||
|
||||
export interface CellRenderProps<
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
createUniComponentFromWebComponent,
|
||||
type UniComponent,
|
||||
} from '../utils/uni-component/index.js';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import { createUniComponentFromWebComponent } from '../utils/uni-component/index.js';
|
||||
import type { BaseCellRenderer } from './base-cell.js';
|
||||
import type { CellRenderer, DataViewCellComponent } from './manager.js';
|
||||
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import type { UniComponent } from './uni-component.js';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
export const uniMap = <T, R, P extends NonNullable<unknown>>(
|
||||
component: UniComponent<T, P>,
|
||||
map: (r: R) => T
|
||||
): UniComponent<R, P> => {
|
||||
return (ele, props) => {
|
||||
const result = component(ele, map(props));
|
||||
return (ele, props, expose) => {
|
||||
const result = component(ele, map(props), expose);
|
||||
return {
|
||||
unmount: result.unmount,
|
||||
update: props => {
|
||||
result.update(map(props));
|
||||
},
|
||||
expose: result.expose,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
import type {
|
||||
UniComponent,
|
||||
UniComponentReturn,
|
||||
} from '@blocksuite/affine-shared/types';
|
||||
import { ShadowlessElement } from '@blocksuite/block-std';
|
||||
import { SignalWatcher } from '@blocksuite/global/lit';
|
||||
import type { Signal } from '@preact/signals-core';
|
||||
import type { LitElement, PropertyValues, TemplateResult } from 'lit';
|
||||
import { css, html } from 'lit';
|
||||
import { property } from 'lit/decorators.js';
|
||||
import type { Ref } from 'lit/directives/ref.js';
|
||||
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
export type UniComponentReturn<
|
||||
Props = NonNullable<unknown>,
|
||||
Expose extends NonNullable<unknown> = NonNullable<unknown>,
|
||||
> = {
|
||||
update: (props: Props) => void;
|
||||
unmount: () => void;
|
||||
expose: Expose;
|
||||
};
|
||||
export type UniComponent<
|
||||
Props = NonNullable<unknown>,
|
||||
Expose extends NonNullable<unknown> = NonNullable<unknown>,
|
||||
> = (ele: HTMLElement, props: Props) => UniComponentReturn<Props, Expose>;
|
||||
export const renderUniLit = <Props, Expose extends NonNullable<unknown>>(
|
||||
uni: UniComponent<Props, Expose> | undefined,
|
||||
props?: Props,
|
||||
options?: {
|
||||
ref?: Ref<Expose>;
|
||||
ref?: Signal<Expose | undefined>;
|
||||
style?: Readonly<StyleInfo>;
|
||||
class?: string;
|
||||
}
|
||||
@@ -45,18 +37,21 @@ export class UniLit<
|
||||
}
|
||||
`;
|
||||
|
||||
uniReturn?: UniComponentReturn<Props, Expose>;
|
||||
uniReturn?: UniComponentReturn<Props>;
|
||||
|
||||
private _expose?: Expose;
|
||||
|
||||
get expose(): Expose | undefined {
|
||||
return this.uniReturn?.expose;
|
||||
return this._expose;
|
||||
}
|
||||
|
||||
private mount() {
|
||||
this.uniReturn = this.uni?.(this, this.props);
|
||||
if (this.ref) {
|
||||
// @ts-expect-error FIXME: ts error
|
||||
this.ref.value = this.uniReturn?.expose;
|
||||
}
|
||||
this.uniReturn = this.uni?.(this, this.props, value => {
|
||||
if (this.ref) {
|
||||
this.ref.value = value;
|
||||
this._expose = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private unmount() {
|
||||
@@ -91,7 +86,7 @@ export class UniLit<
|
||||
accessor props!: Props;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor ref: Ref<Expose> | undefined = undefined;
|
||||
accessor ref: Signal<Expose | undefined> | undefined = undefined;
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor uni: UniComponent<Props, Expose> | undefined = undefined;
|
||||
@@ -103,10 +98,12 @@ export const createUniComponentFromWebComponent = <
|
||||
>(
|
||||
component: typeof LitElement
|
||||
): UniComponent<T, Expose> => {
|
||||
return (ele, props) => {
|
||||
return (ele, props, expose) => {
|
||||
const ins = new component();
|
||||
Object.assign(ins, props);
|
||||
ele.append(ins);
|
||||
// @ts-expect-error ins.expose may not exist in all component instances
|
||||
expose(ins.expose);
|
||||
return {
|
||||
update: props => {
|
||||
Object.assign(ins, props);
|
||||
@@ -115,7 +112,6 @@ export const createUniComponentFromWebComponent = <
|
||||
unmount: () => {
|
||||
ins.remove();
|
||||
},
|
||||
expose: ins as never as Expose,
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -140,12 +136,13 @@ export class UniAnyRender<
|
||||
export const defineUniComponent = <T, Expose extends NonNullable<unknown>>(
|
||||
renderTemplate: (props: T, expose: Expose) => TemplateResult
|
||||
): UniComponent<T, Expose> => {
|
||||
return (ele, props) => {
|
||||
return (ele, props, expose) => {
|
||||
const ins = new UniAnyRender<T, Expose>();
|
||||
ins.props = props;
|
||||
ins.expose = {} as Expose;
|
||||
ins.renderTemplate = renderTemplate;
|
||||
ele.append(ins);
|
||||
expose(ins.expose);
|
||||
return {
|
||||
update: props => {
|
||||
ins.props = props;
|
||||
@@ -154,7 +151,6 @@ export const defineUniComponent = <T, Expose extends NonNullable<unknown>>(
|
||||
unmount: () => {
|
||||
ins.remove();
|
||||
},
|
||||
expose: ins.expose,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
import { computed, type ReadonlySignal } from '@preact/signals-core';
|
||||
|
||||
import type { TypeInstance } from '../logical/type.js';
|
||||
import type { CellRenderer } from '../property/index.js';
|
||||
import type { PropertyDataUpdater } from '../types.js';
|
||||
import type { UniComponent } from '../utils/uni-component/index.js';
|
||||
import type { Cell } from './cell.js';
|
||||
import type { SingleView } from './single-view.js';
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
import type { InsertToPosition } from '@blocksuite/affine-shared/utils';
|
||||
import { computed, type ReadonlySignal, signal } from '@preact/signals-core';
|
||||
|
||||
@@ -8,7 +9,6 @@ import type { TypeInstance } from '../logical/type.js';
|
||||
import type { PropertyMetaConfig } from '../property/property-config.js';
|
||||
import type { TraitKey } from '../traits/key.js';
|
||||
import type { DatabaseFlags } from '../types.js';
|
||||
import type { UniComponent } from '../utils/uni-component/index.js';
|
||||
import type { DataViewDataType, ViewMeta } from '../view/data-view.js';
|
||||
import { type Cell, CellBase } from './cell.js';
|
||||
import type { Property } from './property.js';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { UniComponent } from '../utils/uni-component/index.js';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import type { SingleView } from '../view-manager/single-view.js';
|
||||
import type { ViewManager } from '../view-manager/view-manager.js';
|
||||
import type { DataViewInstance, DataViewProps } from './types.js';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { UniComponent } from '../utils/uni-component/index.js';
|
||||
import type { UniComponent } from '@blocksuite/affine-shared/types';
|
||||
|
||||
import type { DataViewInstance } from '../view/types.js';
|
||||
|
||||
export type DataViewWidgetProps = {
|
||||
|
||||
Reference in New Issue
Block a user