From 15a63968eaf81e642e9c3d7b6cf3f7fedfb8f89e Mon Sep 17 00:00:00 2001 From: Astrian Zheng Date: Wed, 21 May 2025 14:36:30 +1000 Subject: [PATCH] chore: split two-way binding logic into another file --- package.json | 4 ++- src/main.ts | 32 +--------------------- src/utils/processTemplateMarco.ts | 45 +++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 4c8ee6a..eb00821 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "build": "tsc && rollup -c && npm run cleanup-intermediate", "prepare": "npm run build", "cleanup-intermediate": "rimraf dist/main.js dist/types", - "quality-check": "biome ci ." + "quality-check": "biome ci .", + "qc": "npm run quality-check", + "lint": "biome format . --write" }, "repository": { "type": "git", diff --git a/src/main.ts b/src/main.ts index 31fc7b7..ccd97b5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -156,7 +156,6 @@ export default (options: ComponentOptions) => { setupArrowFunctionHandler: this._setupArrowFunctionHandler.bind(this), setupFunctionCallHandler: this._setupFunctionCallHandler.bind(this), setupExpressionHandler: this._setupExpressionHandler.bind(this), - setupTwoWayBinding: this._setupTwoWayBinding.bind(this), setupConditionRendering: this._setupConditionRendering.bind(this), setupListRendering: this._setupListRendering.bind(this), stateToElementsMap: this._stateToElementsMap, @@ -168,6 +167,7 @@ export default (options: ComponentOptions) => { typeof (this as Record)[name] === 'function' && name !== 'constructor', ), + stateListeners: this._statesListeners, }) } @@ -200,36 +200,6 @@ export default (options: ComponentOptions) => { } } - // Handle two-way data binding (%connect macro) - private _setupTwoWayBinding(element: Element, expr: string) { - // Get the initial value - const value = this._getNestedState(expr) - - // Set the initial value - if (value !== undefined) - element.setAttribute('data-laterano-connect', String(value)) - else - console.error( - `State \`${expr}\` not found in the component state. Although Laterano will try to work with it, it may has potentially unexpected behavior.`, - ) - - // Add event listener for input events - element.addEventListener('input', (event: Event) => { - const target = event.target as HTMLInputElement - const newValue = target.value - - // Update the state - this.setState(expr, newValue) - }) - - // Add event listener for state changes - this._statesListeners[expr] = (newValue: unknown) => { - if (element instanceof HTMLInputElement) - element.value = newValue as string - else element.setAttribute('data-laterano-connect', String(newValue)) - } - } - // Handle condition rendering (%if macro) private _setupConditionRendering(element: Element, expr: string) { const placeholder = document.createComment(` %if: ${expr} `) diff --git a/src/utils/processTemplateMarco.ts b/src/utils/processTemplateMarco.ts index 5e3020a..8ab73c3 100644 --- a/src/utils/processTemplateMarco.ts +++ b/src/utils/processTemplateMarco.ts @@ -24,7 +24,6 @@ export default function processTemplateMacros( eventName: string, handlerValue: string, ) => void - setupTwoWayBinding: (element: Element, expr: string) => void setupConditionRendering: (element: Element, expr: string) => void setupListRendering: (element: Element, expr: string) => void stateToElementsMap: Record> @@ -34,6 +33,7 @@ export default function processTemplateMacros( originalContent: string }[] availableFuncs: string[] + stateListeners: Record void> }, ) { /* @@ -194,7 +194,11 @@ export default function processTemplateMacros( // Handle different types of macros if (macroName === 'connect') // Handle state connection: %connect="stateName" - options.setupTwoWayBinding(currentElementNode, expr) + setupTwoWayBinding(currentElementNode, expr, { + getNestedState: context.getState.bind(context), + setState: context.setState.bind(context), + statesListeners: options.stateListeners, + }) else if (macroName === 'if') { ifDirectivesToProcess.push({ element: currentElementNode, expr }) } else if (macroName === 'for') @@ -213,3 +217,40 @@ export default function processTemplateMacros( options.setupConditionRendering(ifElement, expr) } } + +// Handle two-way data binding (%connect macro) +function setupTwoWayBinding( + element: Element, + expr: string, + ops: { + getNestedState: (path: string) => unknown + setState: (path: string, value: unknown) => void + statesListeners: Record void> + }, +) { + // Get the initial value + const value = ops.getNestedState(expr) + + // Set the initial value + if (value !== undefined) + element.setAttribute('data-laterano-connect', String(value)) + else + console.error( + `State \`${expr}\` not found in the component state. Although Laterano will try to work with it, it may has potentially unexpected behavior.`, + ) + + // Add event listener for input events + element.addEventListener('input', (event: Event) => { + const target = event.target as HTMLInputElement + const newValue = target.value + + // Update the state + ops.setState(expr, newValue) + }) + + // Add event listener for state changes + ops.statesListeners[expr] = (newValue: unknown) => { + if (element instanceof HTMLInputElement) element.value = newValue as string + else element.setAttribute('data-laterano-connect', String(newValue)) + } +}