refactor base connection to use lit
This commit is contained in:
parent
7c9e614d76
commit
5b61fe8d42
|
|
@ -2,6 +2,7 @@ import { getBoxToBoxArrow } from 'perfect-arrows';
|
|||
import { FolkBaseConnection } from './folk-base-connection.ts';
|
||||
import { getSvgPathFromStroke, pointsOnBezierCurves } from './common/utils.ts';
|
||||
import { getStroke, StrokeOptions } from 'perfect-freehand';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
|
||||
export type Arrow = [
|
||||
/** The x position of the (padded) starting point. */
|
||||
|
|
@ -53,10 +54,12 @@ export class FolkArrow extends FolkBaseConnection {
|
|||
},
|
||||
};
|
||||
|
||||
override render() {
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
const { sourceRect, targetRect } = this;
|
||||
|
||||
if (sourceRect === undefined || targetRect === undefined) {
|
||||
if (sourceRect === null || targetRect === null) {
|
||||
this.style.clipPath = '';
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,97 +1,62 @@
|
|||
import { FolkShape } from './folk-shape.ts';
|
||||
import { parseVertex } from './common/utils.ts';
|
||||
import { ClientRectObserverEntry } from './common/client-rect-observer.ts';
|
||||
import { FolkObserver } from './common/folk-observer.ts';
|
||||
import { FolkElement } from './common/folk-element.ts';
|
||||
import { property, state } from '@lit/reactive-element/decorators.js';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
|
||||
const folkObserver = new FolkObserver();
|
||||
|
||||
export class FolkBaseConnection extends HTMLElement {
|
||||
static tagName = '';
|
||||
|
||||
static define() {
|
||||
if (customElements.get(this.tagName)) return;
|
||||
FolkShape.define();
|
||||
customElements.define(this.tagName, this);
|
||||
}
|
||||
|
||||
#source = '';
|
||||
/** A CSS selector for the source of the arrow. */
|
||||
get source() {
|
||||
return this.#source;
|
||||
}
|
||||
|
||||
set source(source) {
|
||||
this.#source = source;
|
||||
this.observeSource();
|
||||
}
|
||||
|
||||
#sourceRect: DOMRectReadOnly | undefined;
|
||||
get sourceRect() {
|
||||
return this.#sourceRect;
|
||||
}
|
||||
export class FolkBaseConnection extends FolkElement {
|
||||
@property({ type: String, reflect: true }) source = '';
|
||||
|
||||
#sourceElement: Element | null = null;
|
||||
|
||||
get sourceElement() {
|
||||
return this.#sourceElement;
|
||||
}
|
||||
@state() sourceRect: DOMRectReadOnly | null = null;
|
||||
|
||||
#sourceCallback = (entry: ClientRectObserverEntry) => {
|
||||
this.#sourceRect = entry.contentRect;
|
||||
this.#update();
|
||||
};
|
||||
@property({ type: String, reflect: true }) target = '';
|
||||
|
||||
#target = '';
|
||||
/** A CSS selector for the target of the arrow. */
|
||||
get target() {
|
||||
return this.#target;
|
||||
}
|
||||
set target(target) {
|
||||
this.#target = target;
|
||||
this.observeTarget();
|
||||
}
|
||||
|
||||
#targetRect: DOMRectReadOnly | undefined;
|
||||
get targetRect() {
|
||||
return this.#targetRect;
|
||||
}
|
||||
@state() targetRect: DOMRectReadOnly | null = null;
|
||||
|
||||
#targetElement: Element | null = null;
|
||||
get targetElement() {
|
||||
return this.#targetElement;
|
||||
}
|
||||
|
||||
#targetCallback = (entry: ClientRectObserverEntry) => {
|
||||
this.#targetRect = entry.contentRect;
|
||||
this.#update();
|
||||
};
|
||||
|
||||
connectedCallback() {
|
||||
this.source = this.getAttribute('source') || this.#source;
|
||||
this.target = this.getAttribute('target') || this.#target;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.unobserveSource();
|
||||
this.unobserveTarget();
|
||||
}
|
||||
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (changedProperties.has('source')) {
|
||||
this.observeSource();
|
||||
}
|
||||
|
||||
if (changedProperties.has('target')) {
|
||||
this.observeTarget();
|
||||
}
|
||||
}
|
||||
|
||||
#sourceCallback = (entry: ClientRectObserverEntry) => {
|
||||
this.sourceRect = entry.contentRect;
|
||||
};
|
||||
|
||||
observeSource() {
|
||||
this.unobserveSource();
|
||||
|
||||
const vertex = parseVertex(this.#source);
|
||||
const vertex = parseVertex(this.source);
|
||||
|
||||
if (vertex) {
|
||||
this.#sourceRect = DOMRectReadOnly.fromRect(vertex);
|
||||
this.#update();
|
||||
this.sourceRect = DOMRectReadOnly.fromRect(vertex);
|
||||
} else {
|
||||
this.#sourceElement = document.querySelector(this.source);
|
||||
|
||||
if (this.#sourceElement === null) {
|
||||
throw new Error('source is not a valid element');
|
||||
this.sourceRect = null;
|
||||
} else {
|
||||
folkObserver.observe(this.#sourceElement, this.#sourceCallback);
|
||||
}
|
||||
|
||||
folkObserver.observe(this.#sourceElement, this.#sourceCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,22 +66,25 @@ export class FolkBaseConnection extends HTMLElement {
|
|||
folkObserver.unobserve(this.#sourceElement, this.#sourceCallback);
|
||||
}
|
||||
|
||||
#targetCallback = (entry: ClientRectObserverEntry) => {
|
||||
this.targetRect = entry.contentRect;
|
||||
};
|
||||
|
||||
observeTarget() {
|
||||
this.unobserveTarget();
|
||||
|
||||
const vertex = parseVertex(this.#target);
|
||||
const vertex = parseVertex(this.target);
|
||||
|
||||
if (vertex) {
|
||||
this.#targetRect = DOMRectReadOnly.fromRect(vertex);
|
||||
this.#update();
|
||||
this.targetRect = DOMRectReadOnly.fromRect(vertex);
|
||||
} else {
|
||||
this.#targetElement = document.querySelector(this.#target);
|
||||
this.#targetElement = document.querySelector(this.target);
|
||||
|
||||
if (!this.#targetElement) {
|
||||
throw new Error('target is not a valid element');
|
||||
if (this.#targetElement === null) {
|
||||
this.targetRect = null;
|
||||
} else {
|
||||
folkObserver.observe(this.#targetElement, this.#targetCallback);
|
||||
}
|
||||
|
||||
folkObserver.observe(this.#targetElement, this.#targetCallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,13 +92,4 @@ export class FolkBaseConnection extends HTMLElement {
|
|||
if (this.#targetElement === null) return;
|
||||
folkObserver.unobserve(this.#targetElement, this.#targetCallback);
|
||||
}
|
||||
|
||||
#update() {
|
||||
if (this.#sourceRect === undefined || this.#targetRect === undefined) return;
|
||||
|
||||
this.render(this.#sourceRect, this.#targetRect);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Vector } from './common/Vector.ts';
|
|||
import type { Point } from './common/types.ts';
|
||||
import { DOMRectTransform } from './common/DOMRectTransform.ts';
|
||||
import { FolkBaseConnection } from './folk-base-connection.ts';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
|
||||
const lerp = (first: number, second: number, percentage: number) => first + (second - first) * percentage;
|
||||
|
||||
|
|
@ -120,7 +121,19 @@ export class FolkRope extends FolkBaseConnection {
|
|||
this.draw();
|
||||
};
|
||||
|
||||
override render(sourceRect: DOMRectTransform | DOMRectReadOnly, targetRect: DOMRectTransform | DOMRectReadOnly) {
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
const { sourceRect, targetRect } = this;
|
||||
|
||||
if (sourceRect === null || targetRect === null) {
|
||||
cancelAnimationFrame(this.#rAFId);
|
||||
this.#points = [];
|
||||
this.#path.removeAttribute('d');
|
||||
this.#path2.removeAttribute('d');
|
||||
return;
|
||||
}
|
||||
|
||||
let source: Point;
|
||||
let target: Point;
|
||||
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ export class FolkShape extends HTMLElement {
|
|||
|
||||
#rect = new DOMRectTransform();
|
||||
#previousRect = new DOMRectTransform();
|
||||
#readonlyRect = new DOMRectTransformReadonly();
|
||||
|
||||
#handles: Record<ResizeHandle | RotateHandle, HTMLElement>;
|
||||
|
||||
|
|
@ -294,17 +295,15 @@ export class FolkShape extends HTMLElement {
|
|||
}
|
||||
|
||||
#isConnected = false;
|
||||
|
||||
connectedCallback() {
|
||||
this.setAttribute('tabindex', '0');
|
||||
this.#isConnected = true;
|
||||
this.#update();
|
||||
}
|
||||
|
||||
getTransformDOMRectReadonly() {
|
||||
return new DOMRectTransformReadonly(this.#rect);
|
||||
}
|
||||
getTransformDOMRect() {
|
||||
return this.#rect;
|
||||
return this.#readonlyRect;
|
||||
}
|
||||
|
||||
// Similar to `Element.getClientBoundingRect()`, but returns an SVG path that precisely outlines the shape.
|
||||
|
|
@ -459,7 +458,9 @@ export class FolkShape extends HTMLElement {
|
|||
}
|
||||
|
||||
#dispatchTransformEvent() {
|
||||
const event = new TransformEvent(this.#rect, this.#previousRect);
|
||||
this.#readonlyRect = new DOMRectTransformReadonly(this.#rect);
|
||||
|
||||
const event = new TransformEvent(this.#readonlyRect, this.#previousRect);
|
||||
this.dispatchEvent(event);
|
||||
|
||||
if (event.xPrevented) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,16 @@
|
|||
import { FolkBaseConnection } from './folk-base-connection.js';
|
||||
import { verticesToPolygon } from './common/utils.js';
|
||||
import type { Point } from './common/types.js';
|
||||
import { PropertyValues } from '@lit/reactive-element';
|
||||
export class FolkXanadu extends FolkBaseConnection {
|
||||
static tagName = 'folk-xanadu';
|
||||
|
||||
render(sourceRect: DOMRectReadOnly, targetRect: DOMRectReadOnly): void {
|
||||
if (this.sourceElement === null || this.targetElement === null) {
|
||||
override update(changedProperties: PropertyValues<this>) {
|
||||
super.update(changedProperties);
|
||||
|
||||
let { sourceRect, targetRect } = this;
|
||||
|
||||
if (sourceRect === null || targetRect === null) {
|
||||
this.style.clipPath = '';
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"useDefineForClassFields": true,
|
||||
"useDefineForClassFields": false,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"noUnusedLocals": false,
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue