@muban/muban
Version:
Writing components for server-rendered HTML
104 lines (103 loc) • 3.48 kB
JavaScript
/* eslint-disable @typescript-eslint/naming-convention,@typescript-eslint/no-explicit-any */
import { unref } from '@vue/reactivity';
import { watch } from '@vue/runtime-core';
import { getCurrentComponentInstance } from '../Component';
import { applyBindings } from './applyBindings';
///
// Component functions
// These are called from within your components' setup function, and return the response from one of the
// `BindXXX` functions below, wrapped through the refDefinitions they apply to.
// The `getBindingDefinition` just forwards the props, but passes long the target Elements/Components
// inside a `ref` so they can be updated when the DOM changes
///
export function bind(target,
// make sure that if we bind props onto multiple components,
// we only allow setting props that exist on all of them
props) {
return target.getBindingDefinition(props);
}
export function bindMap(target, getProps) {
const instance = getCurrentComponentInstance();
if (instance) {
// If we pass an array of refs instead of a refCollection,
// these are only set up once
if (Array.isArray(target)) {
return target.map((ref, index) => bind(ref, getProps(ref, index)));
}
// target.getRefs() is reactive and triggers this watchEffect to update
// as soon as the underlying ref array updates when the items in the DOM
// are updated
const disposeWatch = watch(() => target.getRefs(), (refs, oldValue, onInvalidate) => {
const bindings = refs.map((ref, index) => bind(ref, getProps(ref, index)));
const removeBindingList = applyBindings(bindings, instance) || [];
onInvalidate(() => {
removeBindingList.forEach((binding) => binding === null || binding === void 0 ? void 0 : binding());
});
}, { immediate: true });
return [
{
type: 'bindMap',
getElements: () => [],
props: {},
dispose() {
disposeWatch();
},
},
];
}
return [];
}
export function BindTemplate(props) {
return {
type: 'template',
props,
getElements() {
var _a;
return ((_a = props.ref) === null || _a === void 0 ? void 0 : _a.element) ? [props.ref.element] : [];
},
};
}
export function bindTemplate(target, onUpdate, options = {}) {
return BindTemplate(Object.assign({ ref: target, onUpdate }, options));
}
export function bindElement(ref, props) {
return {
ref,
type: 'element',
props,
getElements() {
return ref.value ? [ref.value] : [];
},
};
}
export function bindCollection(ref, props) {
return {
ref,
type: 'collection',
props,
getElements() {
return ref.value.map((r) => unref(r));
},
};
}
export function BindComponent(ref, props) {
return {
ref,
type: 'component',
props,
getElements() {
var _a;
return ((_a = ref.value) === null || _a === void 0 ? void 0 : _a.element) ? [ref.value.element] : [];
},
};
}
export function bindComponentCollection(ref, props) {
return {
ref,
type: 'componentCollection',
props,
getElements() {
return ref.value.map((refItem) => refItem.value.element);
},
};
}