UNPKG

x-widget

Version:

Adds the ability to define reusable Widgets (WebComponents) using Alpinejs.

67 lines (56 loc) 1.61 kB
import { addScopeToNode, closestDataStack, mergeProxies } from 'alpinejs/src/scope.js' import { lazyEvaluator } from './lazy-evaluator.mjs' const snakeToCamel = (name) => name.replace(/-([a-zA-Z])/g, (m) => m[1].toUpperCase() + m.substr(2)) export function xPropDirective( el, { value: attribName, expression }, { cleanup } ) { // <x-table x-prop:rows="rows"></x-table> const propName = snakeToCamel(attribName) const read = lazyEvaluator( expression === propName ? el.parentElement : el, expression ) // allow assignment of unsafe left hand side by just using the new value without bubbling up let unsafeValue const setter = safeLeftHandSide(el, expression) ? lazyEvaluator(el.parentElement, `${expression} = __`) : (_, { scope: { __: newValue } }) => (unsafeValue = newValue) const propObj = {} Object.defineProperty(propObj, propName, { get() { let result if (typeof unsafeValue !== 'undefined') { return unsafeValue } read((newValue) => (result = newValue)) return result }, set(newValue) { if (propName !== 'value') { el[propName] = newValue } setter(() => {}, { scope: { __: newValue } }) } }) if (propName !== 'value') { el[propName] = propObj[propName] } const removeScope = addScopeToNode(el, propObj) cleanup(() => removeScope()) } export function safeLeftHandSide(el, lhs) { try { let scope = mergeProxies(closestDataStack(el)) new Function('scope', `with(scope) {${lhs} = ${lhs}}`)(scope) return true } catch { return false } }