diff --git a/demo/audio-beats-with-event-propagators.html b/demo/audio-beats-with-event-propagators.html index 7bd5d5c..6a19438 100644 --- a/demo/audio-beats-with-event-propagators.html +++ b/demo/audio-beats-with-event-propagators.html @@ -41,14 +41,14 @@ diff --git a/demo/embeddable-llm-with-propagators.html b/demo/embeddable-llm-with-propagators.html index acc185c..349dadd 100644 --- a/demo/embeddable-llm-with-propagators.html +++ b/demo/embeddable-llm-with-propagators.html @@ -90,14 +90,14 @@ @@ -106,7 +106,7 @@ start(): true" diff --git a/demo/event-propagators-with-weather.html b/demo/event-propagators-with-weather.html index 243da72..9a337fa 100644 --- a/demo/event-propagators-with-weather.html +++ b/demo/event-propagators-with-weather.html @@ -39,7 +39,7 @@ @@ -48,13 +48,12 @@ diff --git a/demo/event-propagators.html b/demo/event-propagators.html index a3df733..0ddcde9 100644 --- a/demo/event-propagators.html +++ b/demo/event-propagators.html @@ -30,7 +30,7 @@ @@ -39,7 +39,7 @@ diff --git a/demo/folk-interface-for-qr-codes.html b/demo/folk-interface-for-qr-codes.html index 3274ec7..190714e 100644 --- a/demo/folk-interface-for-qr-codes.html +++ b/demo/folk-interface-for-qr-codes.html @@ -52,21 +52,21 @@ diff --git a/demo/proximity-based-communication-and-event-propagators.html b/demo/proximity-based-communication-and-event-propagators.html index 2afe62b..028170f 100644 --- a/demo/proximity-based-communication-and-event-propagators.html +++ b/demo/proximity-based-communication-and-event-propagators.html @@ -76,14 +76,14 @@ diff --git a/demo/spreadsheet-map-propagator.html b/demo/spreadsheet-map-propagator.html index d9aa4f5..99e57e0 100644 --- a/demo/spreadsheet-map-propagator.html +++ b/demo/spreadsheet-map-propagator.html @@ -143,21 +143,21 @@ diff --git a/src/folk-base-connection.ts b/src/folk-base-connection.ts index dcc025c..3618005 100644 --- a/src/folk-base-connection.ts +++ b/src/folk-base-connection.ts @@ -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); } } diff --git a/src/folk-event-propagator.ts b/src/folk-event-propagator.ts index 8f724b3..62ce5d1 100644 --- a/src/folk-event-propagator.ts +++ b/src/folk-event-propagator.ts @@ -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): 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): 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): 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; diff --git a/src/folk-toolbar.ts b/src/folk-toolbar.ts index 7db0a92..80a458b 100644 --- a/src/folk-toolbar.ts +++ b/src/folk-toolbar.ts @@ -106,7 +106,7 @@ export class FolkToolbar extends HTMLElement { `,