mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 00:56:26 +08:00
refactor(editor): separate lit and slot in global (#10666)
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
export * from './signal-watcher.js';
|
||||
export * from './with-disposable.js';
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2023 Google LLC
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
import { effect } from '@preact/signals-core';
|
||||
import type { ReactiveElement } from 'lit';
|
||||
|
||||
type ReactiveElementConstructor = abstract new (
|
||||
...args: any[]
|
||||
) => ReactiveElement;
|
||||
|
||||
/**
|
||||
* Adds the ability for a LitElement or other ReactiveElement class to
|
||||
* watch for access to Preact signals during the update lifecycle and
|
||||
* trigger a new update when signals values change.
|
||||
*/
|
||||
export function SignalWatcher<T extends ReactiveElementConstructor>(
|
||||
Base: T
|
||||
): T {
|
||||
abstract class SignalWatcher extends Base {
|
||||
private __dispose?: () => void;
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
// In order to listen for signals again after re-connection, we must
|
||||
// re-render to capture all the current signal accesses.
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this.__dispose?.();
|
||||
}
|
||||
|
||||
override performUpdate() {
|
||||
// ReactiveElement.performUpdate() also does this check, so we want to
|
||||
// also bail early so we don't erroneously appear to not depend on any
|
||||
// signals.
|
||||
if (this.isUpdatePending === false || this.isConnected === false) {
|
||||
return;
|
||||
}
|
||||
// If we have a previous effect, dispose it
|
||||
this.__dispose?.();
|
||||
|
||||
// Tracks whether the effect callback is triggered by this performUpdate
|
||||
// call directly, or by a signal change.
|
||||
let updateFromLit = true;
|
||||
|
||||
// We create a new effect to capture all signal access within the
|
||||
// performUpdate phase (update, render, updated, etc) of the element.
|
||||
// Q: Do we need to create a new effect each render?
|
||||
// TODO: test various combinations of render triggers:
|
||||
// - from requestUpdate()
|
||||
// - from signals
|
||||
// - from both (do we get one or two re-renders)
|
||||
// and see if we really need a new effect here.
|
||||
this.__dispose = effect(() => {
|
||||
if (updateFromLit) {
|
||||
updateFromLit = false;
|
||||
super.performUpdate();
|
||||
} else {
|
||||
// This branch is an effect run from Preact signals.
|
||||
// This will cause another call into performUpdate, which will
|
||||
// then create a new effect watching that update pass.
|
||||
this.requestUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return SignalWatcher;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { LitElement } from 'lit';
|
||||
|
||||
import { DisposableGroup } from '../slot/disposable.js';
|
||||
import type { Constructor } from '../utils/types.js';
|
||||
|
||||
// See https://lit.dev/docs/composition/mixins/#mixins-in-typescript
|
||||
// This definition should be exported, see https://github.com/microsoft/TypeScript/issues/30355#issuecomment-839834550
|
||||
export declare class DisposableClass {
|
||||
protected _disposables: DisposableGroup;
|
||||
|
||||
readonly disposables: DisposableGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin that adds a `_disposables: DisposableGroup` property to the class.
|
||||
*
|
||||
* The `_disposables` property is initialized in `connectedCallback` and disposed in `disconnectedCallback`.
|
||||
*
|
||||
* see https://lit.dev/docs/composition/mixins/
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* class MyElement extends WithDisposable(ShadowlessElement) {
|
||||
* onClick() {
|
||||
* this._disposables.add(...);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function WithDisposable<T extends Constructor<LitElement>>(
|
||||
SuperClass: T
|
||||
) {
|
||||
class DerivedClass extends SuperClass {
|
||||
protected _disposables = new DisposableGroup();
|
||||
|
||||
get disposables() {
|
||||
return this._disposables;
|
||||
}
|
||||
|
||||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (this._disposables.disposed) {
|
||||
this._disposables = new DisposableGroup();
|
||||
}
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this._disposables.dispose();
|
||||
}
|
||||
}
|
||||
return DerivedClass as unknown as T & Constructor<DisposableClass>;
|
||||
}
|
||||
Reference in New Issue
Block a user