@awcrotwell/motion
Version:
Motion allows you to build reactive, real-time frontend UI components in your Amber application using pure Crystal that are reusable, testable & encapsulated. For brevity, we will call them MotionComponents.
48 lines (47 loc) • 2.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const morphdom_1 = __importDefault(require("morphdom"));
exports.default = (rootElement, newState, keyAttribute) => {
if (typeof newState !== 'string') {
throw new TypeError('Expected raw HTML for reconcile newState');
}
// remove root element when component sends an empty state
if (!newState)
return rootElement.remove();
const rootKey = rootElement.getAttribute(keyAttribute);
if (!rootKey) {
throw new TypeError('Expected key on reconcile rootElement');
}
const onBeforeElUpdated = (fromElement, toElement) => {
// When we are doing an inner update, propgrate the key and replace.
if (rootElement === fromElement) {
toElement.setAttribute(keyAttribute, rootKey);
return true;
}
// When we are doing an outer update, do not replace if the key is the same.
const toKey = toElement.getAttribute(keyAttribute);
if (toKey && toKey === fromElement.getAttribute(keyAttribute)) {
return false;
}
if (
// For some reason, it it seems like all TEXTAREAs are equal to eachother
// regardless of their content which is super werid because the same thing
// does not seem to be true for INPUTs or SELECTs whose value has changed.
fromElement.tagName !== 'TEXTAREA' &&
// When two nodes have (deep) DOM equality, don't replace. This is correct
// because we checked above that we are reconsiling against an HTML string
// (which cannot possibly have state outside of the DOM because no handles
// have been allowed to leave this function since parsing).
fromElement.isEqualNode(toElement)) {
return false;
}
// Otherwise, take the new version.
return true;
};
return morphdom_1.default(rootElement, newState, {
onBeforeElUpdated,
});
};