refactor event propagator to lit
This commit is contained in:
parent
24b9442a43
commit
fb3895e0d4
|
|
@ -41,14 +41,14 @@
|
|||
<folk-event-propagator
|
||||
source="folk-metronome"
|
||||
target="#kick"
|
||||
triggers="beat"
|
||||
trigger="beat"
|
||||
expression="play(): from.beat === 1"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="folk-metronome"
|
||||
target="#hat"
|
||||
triggers="beat"
|
||||
trigger="beat"
|
||||
expression="play(): from.beat % 3"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
|
|||
|
|
@ -90,14 +90,14 @@
|
|||
<folk-event-propagator
|
||||
source="#recipe"
|
||||
target="folk-llm"
|
||||
triggers="click"
|
||||
trigger="click"
|
||||
expression="prompt: `double this list of ingredients '${from.innerHTML}'`"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="folk-llm"
|
||||
target="folk-timer"
|
||||
triggers="started"
|
||||
trigger="started"
|
||||
expression="reset(): true
|
||||
start(): true"
|
||||
>
|
||||
|
|
@ -106,7 +106,7 @@ start(): true"
|
|||
<folk-event-propagator
|
||||
source="folk-llm"
|
||||
target="folk-timer"
|
||||
triggers="finished"
|
||||
trigger="finished"
|
||||
expression="stop(): true"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
<folk-event-propagator
|
||||
source="#box1"
|
||||
target="#box2"
|
||||
triggers="click"
|
||||
trigger="click"
|
||||
expression="textContent: to.textContent + 'r'"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
@ -48,13 +48,12 @@
|
|||
<folk-event-propagator
|
||||
source="#box3"
|
||||
target="#box4"
|
||||
triggers="transform"
|
||||
trigger="transform"
|
||||
expression="y: from.x,
|
||||
rotation: from.x"
|
||||
></folk-event-propagator>
|
||||
|
||||
<script type="module">
|
||||
import 'https://cdn.jsdelivr.net/npm/@zachleat/snow-fall';
|
||||
import '../src/standalone/folk-shape.ts';
|
||||
import '../src/standalone/folk-event-propagator.ts';
|
||||
|
||||
|
|
@ -80,6 +79,8 @@ rotation: from.x"
|
|||
}
|
||||
isBlowing = !isBlowing;
|
||||
});
|
||||
|
||||
requestIdleCallback(() => import('https://cdn.jsdelivr.net/npm/@zachleat/snow-fall'));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<folk-event-propagator
|
||||
source="#box1"
|
||||
target="#box2"
|
||||
triggers="click"
|
||||
trigger="click"
|
||||
expression="textContent: to.textContent + '!'"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<folk-event-propagator
|
||||
source="#box3"
|
||||
target="#box4"
|
||||
triggers="transform"
|
||||
trigger="transform"
|
||||
expression="y: from.x,
|
||||
rotation: from.x"
|
||||
></folk-event-propagator>
|
||||
|
|
|
|||
|
|
@ -52,21 +52,21 @@
|
|||
<folk-event-propagator
|
||||
source="textarea"
|
||||
target="sl-qr-code"
|
||||
triggers="input"
|
||||
trigger="input"
|
||||
expression="value: from.value"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="input[type='range']"
|
||||
target="sl-qr-code"
|
||||
triggers="input"
|
||||
trigger="input"
|
||||
expression="radius: from.value"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="input[type='color']"
|
||||
target="sl-qr-code"
|
||||
triggers="input"
|
||||
trigger="input"
|
||||
expression="fill: from.value"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
|
|||
|
|
@ -76,14 +76,14 @@
|
|||
<folk-event-propagator
|
||||
source="input[type='range']"
|
||||
target="folk-map"
|
||||
triggers="input"
|
||||
trigger="input"
|
||||
expression="lat: from.value"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="folk-map"
|
||||
target="input[type='range']"
|
||||
triggers="recenter"
|
||||
trigger="recenter"
|
||||
expression="value: from.lat"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
|
|||
|
|
@ -143,21 +143,21 @@
|
|||
<folk-event-propagator
|
||||
source="#map1"
|
||||
target="folk-cell[column='A'][row='1']"
|
||||
triggers="recenter"
|
||||
trigger="recenter"
|
||||
expression="expression: from.coordinates.lat"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="#map1"
|
||||
target="folk-cell[column='A'][row='2']"
|
||||
triggers="recenter"
|
||||
trigger="recenter"
|
||||
expression="expression: from.coordinates.lng"
|
||||
></folk-event-propagator>
|
||||
|
||||
<folk-event-propagator
|
||||
source="folk-cell[column='A'][row='3']"
|
||||
target="#map2"
|
||||
triggers="propagate"
|
||||
trigger="propagate"
|
||||
expression="coordinates: from.value"
|
||||
></folk-event-propagator>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ const folkObserver = new FolkObserver();
|
|||
export class FolkBaseConnection extends FolkElement {
|
||||
@property({ type: String, reflect: true }) source = '';
|
||||
|
||||
#sourceElement: Element | null = null;
|
||||
|
||||
get sourceElement() {
|
||||
return this.#sourceElement;
|
||||
}
|
||||
@state() sourceElement: Element | null = null;
|
||||
|
||||
@state() sourceRect: DOMRectReadOnly | null = null;
|
||||
|
||||
|
|
@ -22,11 +18,7 @@ export class FolkBaseConnection extends FolkElement {
|
|||
|
||||
@state() targetRect: DOMRectReadOnly | null = null;
|
||||
|
||||
#targetElement: Element | null = null;
|
||||
|
||||
get targetElement() {
|
||||
return this.#targetElement;
|
||||
}
|
||||
@state() targetElement: Element | null = null;
|
||||
|
||||
override disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
|
@ -58,20 +50,20 @@ export class FolkBaseConnection extends FolkElement {
|
|||
if (vertex) {
|
||||
this.sourceRect = DOMRectReadOnly.fromRect(vertex);
|
||||
} else {
|
||||
this.#sourceElement = document.querySelector(this.source);
|
||||
this.sourceElement = document.querySelector(this.source);
|
||||
|
||||
if (this.#sourceElement === null) {
|
||||
if (this.sourceElement === null) {
|
||||
this.sourceRect = null;
|
||||
} else {
|
||||
folkObserver.observe(this.#sourceElement, this.#sourceCallback);
|
||||
folkObserver.observe(this.sourceElement, this.#sourceCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unobserveSource() {
|
||||
if (this.#sourceElement === null) return;
|
||||
if (this.sourceElement === null) return;
|
||||
|
||||
folkObserver.unobserve(this.#sourceElement, this.#sourceCallback);
|
||||
folkObserver.unobserve(this.sourceElement, this.#sourceCallback);
|
||||
}
|
||||
|
||||
#targetCallback = (entry: ClientRectObserverEntry) => {
|
||||
|
|
@ -86,18 +78,18 @@ export class FolkBaseConnection extends FolkElement {
|
|||
if (vertex) {
|
||||
this.targetRect = DOMRectReadOnly.fromRect(vertex);
|
||||
} else {
|
||||
this.#targetElement = document.querySelector(this.target);
|
||||
this.targetElement = document.querySelector(this.target);
|
||||
|
||||
if (this.#targetElement === null) {
|
||||
if (this.targetElement === null) {
|
||||
this.targetRect = null;
|
||||
} else {
|
||||
folkObserver.observe(this.#targetElement, this.#targetCallback);
|
||||
folkObserver.observe(this.targetElement, this.#targetCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unobserveTarget() {
|
||||
if (this.#targetElement === null) return;
|
||||
folkObserver.unobserve(this.#targetElement, this.#targetCallback);
|
||||
if (this.targetElement === null) return;
|
||||
folkObserver.unobserve(this.targetElement, this.#targetCallback);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { css, PropertyValues } from '@lit/reactive-element';
|
||||
import { FolkRope } from './folk-rope.ts';
|
||||
import { property } from '@lit/reactive-element/decorators.js';
|
||||
// import * as parser from '@babel/parser';
|
||||
|
||||
export class FolkEventPropagator extends FolkRope {
|
||||
|
|
@ -30,30 +31,77 @@ export class FolkEventPropagator extends FolkRope {
|
|||
}
|
||||
`;
|
||||
|
||||
#triggers: string[] = [];
|
||||
get triggers() {
|
||||
return this.#triggers;
|
||||
}
|
||||
set triggers(triggers: string | string[]) {
|
||||
if (typeof triggers === 'string') {
|
||||
triggers = triggers.split(',');
|
||||
}
|
||||
this.#removeEventListenersToSource();
|
||||
@property({ type: String, reflect: true }) trigger = '';
|
||||
|
||||
this.#triggers = triggers;
|
||||
@property({ type: String, reflect: true }) expression = '';
|
||||
|
||||
this.#addEventListenersToSource();
|
||||
}
|
||||
|
||||
#expression = '';
|
||||
#function: Function | null = null;
|
||||
get expression() {
|
||||
return this.#expression;
|
||||
#triggerTextarea = document.createElement('textarea');
|
||||
#expressionTextarea = document.createElement('textarea');
|
||||
|
||||
override firstUpdated(changedProperties: PropertyValues<this>): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
|
||||
this.#triggerTextarea.addEventListener('change', () => {
|
||||
this.trigger = this.#triggerTextarea.value;
|
||||
});
|
||||
|
||||
this.#expressionTextarea.addEventListener('input', () => {
|
||||
this.expression = this.#expressionTextarea.value;
|
||||
});
|
||||
|
||||
this.#triggerTextarea.value = this.trigger;
|
||||
|
||||
this.#expressionTextarea.value = this.expression;
|
||||
|
||||
this.renderRoot.append(this.#triggerTextarea, this.#expressionTextarea);
|
||||
}
|
||||
set expression(expression) {
|
||||
this.mend();
|
||||
this.#expression = expression;
|
||||
const processedExp = expression.trim();
|
||||
|
||||
override updated(changedProperties: PropertyValues<this>): void {
|
||||
super.update(changedProperties);
|
||||
|
||||
if (changedProperties.has('trigger')) {
|
||||
this.sourceElement?.removeEventListener(this.trigger, this.#evaluateExpression);
|
||||
this.sourceElement?.addEventListener(this.trigger, this.#evaluateExpression);
|
||||
}
|
||||
|
||||
if (changedProperties.has('expression')) {
|
||||
this.#parseExpression();
|
||||
}
|
||||
|
||||
const previousSourceElement = changedProperties.get('sourceElement');
|
||||
if (previousSourceElement) {
|
||||
const trigger = changedProperties.get('trigger') || this.trigger;
|
||||
previousSourceElement.removeEventListener(trigger, this.#evaluateExpression);
|
||||
this.sourceElement?.addEventListener(this.trigger, this.#evaluateExpression);
|
||||
}
|
||||
}
|
||||
|
||||
override disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
this.sourceElement?.removeEventListener(this.trigger, this.#evaluateExpression);
|
||||
}
|
||||
|
||||
override draw() {
|
||||
super.draw();
|
||||
|
||||
const triggerPoint = this.points[Math.floor(this.points.length / 5)];
|
||||
|
||||
if (triggerPoint) {
|
||||
this.#triggerTextarea.style.left = `${triggerPoint.pos.x}px`;
|
||||
this.#triggerTextarea.style.top = `${triggerPoint.pos.y}px`;
|
||||
}
|
||||
|
||||
const expressionPoint = this.points[Math.floor(this.points.length / 2)];
|
||||
|
||||
if (expressionPoint) {
|
||||
this.#expressionTextarea.style.left = `${expressionPoint.pos.x}px`;
|
||||
this.#expressionTextarea.style.top = `${expressionPoint.pos.y}px`;
|
||||
}
|
||||
}
|
||||
|
||||
#parseExpression() {
|
||||
const processedExp = this.expression.trim();
|
||||
|
||||
const codeLines: string[] = [];
|
||||
|
||||
|
|
@ -103,6 +151,7 @@ to.${key} = ${value};`);
|
|||
try {
|
||||
// parseAst(functionBody);
|
||||
this.#function = new Function('from', 'to', 'event', functionBody);
|
||||
this.mend();
|
||||
} catch (error) {
|
||||
console.warn('Failed to parse expression:', error, functionBody);
|
||||
this.cut();
|
||||
|
|
@ -110,80 +159,8 @@ to.${key} = ${value};`);
|
|||
}
|
||||
}
|
||||
|
||||
#triggerTextarea = document.createElement('textarea');
|
||||
#expressionTextarea = document.createElement('textarea');
|
||||
|
||||
override firstUpdated(changedProperties: PropertyValues<this>): void {
|
||||
super.firstUpdated(changedProperties);
|
||||
|
||||
this.#triggerTextarea.addEventListener('change', () => {
|
||||
this.triggers = this.#triggerTextarea.value;
|
||||
});
|
||||
|
||||
this.triggers = this.#triggerTextarea.value = this.getAttribute('triggers') || '';
|
||||
|
||||
this.renderRoot.appendChild(this.#triggerTextarea);
|
||||
|
||||
this.#expressionTextarea.addEventListener('input', () => {
|
||||
this.expression = this.#expressionTextarea.value;
|
||||
});
|
||||
|
||||
this.renderRoot.appendChild(this.#expressionTextarea);
|
||||
|
||||
this.expression = this.#expressionTextarea.value = this.getAttribute('expression') || '';
|
||||
}
|
||||
|
||||
override draw() {
|
||||
super.draw();
|
||||
|
||||
const triggerPoint = this.points[Math.floor(this.points.length / 5)];
|
||||
|
||||
if (triggerPoint) {
|
||||
this.#triggerTextarea.style.left = `${triggerPoint.pos.x}px`;
|
||||
this.#triggerTextarea.style.top = `${triggerPoint.pos.y}px`;
|
||||
}
|
||||
|
||||
const expressionPoint = this.points[Math.floor(this.points.length / 2)];
|
||||
|
||||
if (expressionPoint) {
|
||||
this.#expressionTextarea.style.left = `${expressionPoint.pos.x}px`;
|
||||
this.#expressionTextarea.style.top = `${expressionPoint.pos.y}px`;
|
||||
}
|
||||
}
|
||||
|
||||
override observeSource() {
|
||||
super.observeSource();
|
||||
|
||||
this.#addEventListenersToSource();
|
||||
}
|
||||
|
||||
#addEventListenersToSource() {
|
||||
for (const trigger of this.#triggers) {
|
||||
// TODO: add special triggers for intersection, rAF, etc.
|
||||
this.sourceElement?.addEventListener(trigger, this.evaluateExpression);
|
||||
}
|
||||
}
|
||||
|
||||
override unobserveSource() {
|
||||
super.unobserveSource();
|
||||
this.#removeEventListenersToSource();
|
||||
}
|
||||
|
||||
#removeEventListenersToSource() {
|
||||
for (const trigger of this.#triggers) {
|
||||
this.sourceElement?.removeEventListener(trigger, this.evaluateExpression);
|
||||
}
|
||||
}
|
||||
|
||||
override observeTarget() {
|
||||
super.observeTarget();
|
||||
}
|
||||
|
||||
override unobserveTarget() {
|
||||
super.unobserveTarget();
|
||||
}
|
||||
|
||||
evaluateExpression = (event?: Event) => {
|
||||
#evaluateExpression = (event?: Event) => {
|
||||
console.log('eval');
|
||||
if (this.sourceElement === null || this.targetElement === null) return;
|
||||
this.stroke = 'black';
|
||||
if (!this.#function) return;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ export class FolkToolbar extends HTMLElement {
|
|||
<folk-event-propagator
|
||||
source="#${sourceId}"
|
||||
target="#${targetId}"
|
||||
triggers="click"
|
||||
trigger="click"
|
||||
expression="rotation: Math.random() * 360"
|
||||
></folk-event-propagator>
|
||||
`,
|
||||
|
|
|
|||
Loading…
Reference in New Issue