chore: split two-way binding logic into another file
This commit is contained in:
parent
9ea14fc2b9
commit
15a63968ea
|
@ -8,7 +8,9 @@
|
||||||
"build": "tsc && rollup -c && npm run cleanup-intermediate",
|
"build": "tsc && rollup -c && npm run cleanup-intermediate",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"cleanup-intermediate": "rimraf dist/main.js dist/types",
|
"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": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
32
src/main.ts
32
src/main.ts
|
@ -156,7 +156,6 @@ export default (options: ComponentOptions) => {
|
||||||
setupArrowFunctionHandler: this._setupArrowFunctionHandler.bind(this),
|
setupArrowFunctionHandler: this._setupArrowFunctionHandler.bind(this),
|
||||||
setupFunctionCallHandler: this._setupFunctionCallHandler.bind(this),
|
setupFunctionCallHandler: this._setupFunctionCallHandler.bind(this),
|
||||||
setupExpressionHandler: this._setupExpressionHandler.bind(this),
|
setupExpressionHandler: this._setupExpressionHandler.bind(this),
|
||||||
setupTwoWayBinding: this._setupTwoWayBinding.bind(this),
|
|
||||||
setupConditionRendering: this._setupConditionRendering.bind(this),
|
setupConditionRendering: this._setupConditionRendering.bind(this),
|
||||||
setupListRendering: this._setupListRendering.bind(this),
|
setupListRendering: this._setupListRendering.bind(this),
|
||||||
stateToElementsMap: this._stateToElementsMap,
|
stateToElementsMap: this._stateToElementsMap,
|
||||||
|
@ -168,6 +167,7 @@ export default (options: ComponentOptions) => {
|
||||||
typeof (this as Record<string, unknown>)[name] === 'function' &&
|
typeof (this as Record<string, unknown>)[name] === 'function' &&
|
||||||
name !== 'constructor',
|
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)
|
// Handle condition rendering (%if macro)
|
||||||
private _setupConditionRendering(element: Element, expr: string) {
|
private _setupConditionRendering(element: Element, expr: string) {
|
||||||
const placeholder = document.createComment(` %if: ${expr} `)
|
const placeholder = document.createComment(` %if: ${expr} `)
|
||||||
|
|
|
@ -24,7 +24,6 @@ export default function processTemplateMacros(
|
||||||
eventName: string,
|
eventName: string,
|
||||||
handlerValue: string,
|
handlerValue: string,
|
||||||
) => void
|
) => void
|
||||||
setupTwoWayBinding: (element: Element, expr: string) => void
|
|
||||||
setupConditionRendering: (element: Element, expr: string) => void
|
setupConditionRendering: (element: Element, expr: string) => void
|
||||||
setupListRendering: (element: Element, expr: string) => void
|
setupListRendering: (element: Element, expr: string) => void
|
||||||
stateToElementsMap: Record<string, Set<HTMLElement>>
|
stateToElementsMap: Record<string, Set<HTMLElement>>
|
||||||
|
@ -34,6 +33,7 @@ export default function processTemplateMacros(
|
||||||
originalContent: string
|
originalContent: string
|
||||||
}[]
|
}[]
|
||||||
availableFuncs: string[]
|
availableFuncs: string[]
|
||||||
|
stateListeners: Record<string, (newValue: unknown) => void>
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
|
@ -194,7 +194,11 @@ export default function processTemplateMacros(
|
||||||
// Handle different types of macros
|
// Handle different types of macros
|
||||||
if (macroName === 'connect')
|
if (macroName === 'connect')
|
||||||
// Handle state connection: %connect="stateName"
|
// 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') {
|
else if (macroName === 'if') {
|
||||||
ifDirectivesToProcess.push({ element: currentElementNode, expr })
|
ifDirectivesToProcess.push({ element: currentElementNode, expr })
|
||||||
} else if (macroName === 'for')
|
} else if (macroName === 'for')
|
||||||
|
@ -213,3 +217,40 @@ export default function processTemplateMacros(
|
||||||
options.setupConditionRendering(ifElement, expr)
|
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<string, (newValue: unknown) => 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user