mirror of
https://github.com/nvms/soma3.git
synced 2025-12-15 15:10:53 +00:00
changes
This commit is contained in:
parent
02730daae5
commit
3c07b7568d
184
public/demo.js
184
public/demo.js
@ -253,7 +253,9 @@ var EventDirective = class {
|
|||||||
this.eventCount++;
|
this.eventCount++;
|
||||||
const handler = evalGet(context.scope, attr.value, element);
|
const handler = evalGet(context.scope, attr.value, element);
|
||||||
if (typeof handler === "function") {
|
if (typeof handler === "function") {
|
||||||
handler(event);
|
handler.call(context.scope, event);
|
||||||
|
} else {
|
||||||
|
execute(context.scope, this.expression, element, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
element.removeAttribute(attr.name);
|
element.removeAttribute(attr.name);
|
||||||
@ -272,10 +274,10 @@ var _for = (el, exp, ctx, component, componentProps, allProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nextNode = el.nextSibling;
|
const nextNode = el.nextSibling;
|
||||||
const parent = el.parentElement;
|
const parent2 = el.parentElement;
|
||||||
const anchor = new Text("");
|
const anchor = new Text("");
|
||||||
parent.insertBefore(anchor, el);
|
parent2.insertBefore(anchor, el);
|
||||||
parent.removeChild(el);
|
parent2.removeChild(el);
|
||||||
const sourceExp = inMatch[2].trim();
|
const sourceExp = inMatch[2].trim();
|
||||||
let valueExp = inMatch[1].trim().replace(stripParensRE, "").trim();
|
let valueExp = inMatch[1].trim().replace(stripParensRE, "").trim();
|
||||||
let destructureBindings;
|
let destructureBindings;
|
||||||
@ -345,7 +347,7 @@ var _for = (el, exp, ctx, component, componentProps, allProps) => {
|
|||||||
const mountBlock = (ctx2, ref2) => {
|
const mountBlock = (ctx2, ref2) => {
|
||||||
const block = new Block({ element: el, parentContext: ctx2, replacementType: "replace", component, componentProps, allProps });
|
const block = new Block({ element: el, parentContext: ctx2, replacementType: "replace", component, componentProps, allProps });
|
||||||
block.key = ctx2.key;
|
block.key = ctx2.key;
|
||||||
block.insert(parent, ref2);
|
block.insert(parent2, ref2);
|
||||||
return block;
|
return block;
|
||||||
};
|
};
|
||||||
ctx.effect(() => {
|
ctx.effect(() => {
|
||||||
@ -378,7 +380,7 @@ var _for = (el, exp, ctx, component, componentProps, allProps) => {
|
|||||||
if (blocks[oldIndex + 1] !== nextBlock || // If the next has moved, it must move too
|
if (blocks[oldIndex + 1] !== nextBlock || // If the next has moved, it must move too
|
||||||
prevMovedBlock === nextBlock) {
|
prevMovedBlock === nextBlock) {
|
||||||
prevMovedBlock = block;
|
prevMovedBlock = block;
|
||||||
block.insert(parent, nextBlock ? nextBlock.element : anchor);
|
block.insert(parent2, nextBlock ? nextBlock.element : anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,30 +394,30 @@ var _for = (el, exp, ctx, component, componentProps, allProps) => {
|
|||||||
|
|
||||||
// src/directives/if.ts
|
// src/directives/if.ts
|
||||||
function _if(el, exp, ctx, component, componentProps, allProps) {
|
function _if(el, exp, ctx, component, componentProps, allProps) {
|
||||||
const parent = el.parentElement;
|
const parent2 = el.parentElement;
|
||||||
const anchor = new Comment(":if");
|
const anchor = new Comment(":if");
|
||||||
parent.insertBefore(anchor, el);
|
parent2.insertBefore(anchor, el);
|
||||||
const branches = [{ exp, el }];
|
const branches = [{ exp, el }];
|
||||||
let elseEl;
|
let elseEl;
|
||||||
let elseExp;
|
let elseExp;
|
||||||
while (elseEl = el.nextElementSibling) {
|
while (elseEl = el.nextElementSibling) {
|
||||||
elseExp = null;
|
elseExp = null;
|
||||||
if (checkAndRemoveAttribute(elseEl, ":else") === "" || (elseExp = checkAndRemoveAttribute(elseEl, ":else-if"))) {
|
if (checkAndRemoveAttribute(elseEl, ":else") === "" || (elseExp = checkAndRemoveAttribute(elseEl, ":else-if"))) {
|
||||||
parent.removeChild(elseEl);
|
parent2.removeChild(elseEl);
|
||||||
branches.push({ exp: elseExp, el: elseEl });
|
branches.push({ exp: elseExp, el: elseEl });
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const nextNode = el.nextSibling;
|
const nextNode = el.nextSibling;
|
||||||
parent.removeChild(el);
|
parent2.removeChild(el);
|
||||||
let block;
|
let block;
|
||||||
let activeBranchIndex = -1;
|
let activeBranchIndex = -1;
|
||||||
const removeActiveBlock = () => {
|
const removeActiveBlock = () => {
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parent.insertBefore(anchor, block.element);
|
parent2.insertBefore(anchor, block.element);
|
||||||
block.remove();
|
block.remove();
|
||||||
block = void 0;
|
block = void 0;
|
||||||
};
|
};
|
||||||
@ -426,8 +428,8 @@ function _if(el, exp, ctx, component, componentProps, allProps) {
|
|||||||
if (i !== activeBranchIndex) {
|
if (i !== activeBranchIndex) {
|
||||||
removeActiveBlock();
|
removeActiveBlock();
|
||||||
block = new Block({ element: el2, parentContext: ctx, replacementType: "replace", component, componentProps, allProps });
|
block = new Block({ element: el2, parentContext: ctx, replacementType: "replace", component, componentProps, allProps });
|
||||||
block.insert(parent, anchor);
|
block.insert(parent2, anchor);
|
||||||
parent.removeChild(anchor);
|
parent2.removeChild(anchor);
|
||||||
activeBranchIndex = i;
|
activeBranchIndex = i;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -518,6 +520,7 @@ var ShowDirective = class {
|
|||||||
|
|
||||||
// src/directives/teleport.ts
|
// src/directives/teleport.ts
|
||||||
function _teleport(el, exp, ctx, component, componentProps, allProps) {
|
function _teleport(el, exp, ctx, component, componentProps, allProps) {
|
||||||
|
console.log("_teleport", ctx.scope);
|
||||||
const anchor = new Comment(":teleport anchor");
|
const anchor = new Comment(":teleport anchor");
|
||||||
insertBefore(anchor, el);
|
insertBefore(anchor, el);
|
||||||
const observed = new Comment(":teleport");
|
const observed = new Comment(":teleport");
|
||||||
@ -532,17 +535,19 @@ function _teleport(el, exp, ctx, component, componentProps, allProps) {
|
|||||||
el.style.display = "none";
|
el.style.display = "none";
|
||||||
let block;
|
let block;
|
||||||
target.appendChild(el);
|
target.appendChild(el);
|
||||||
|
console.log("appended", el, "to", target);
|
||||||
const observer = new MutationObserver((mutationsList) => {
|
const observer = new MutationObserver((mutationsList) => {
|
||||||
mutationsList.forEach((mutation) => {
|
mutationsList.forEach((mutation) => {
|
||||||
mutation.removedNodes.forEach((removedNode) => {
|
mutation.removedNodes.forEach((removedNode) => {
|
||||||
if (removedNode.contains(observed)) {
|
console.log("removedNode", removedNode, "observed:", observed);
|
||||||
|
if (removedNode.contains(anchor)) {
|
||||||
if (block.element) block.remove();
|
if (block.element) block.remove();
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
observer.observe(document.querySelector(exp) || document.body, { childList: true, subtree: true });
|
||||||
el.style.display = originalDisplay;
|
el.style.display = originalDisplay;
|
||||||
block = new Block({
|
block = new Block({
|
||||||
element: el,
|
element: el,
|
||||||
@ -832,6 +837,25 @@ var link = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// src/index.ts
|
// src/index.ts
|
||||||
|
function provide(key, value) {
|
||||||
|
if (!current2.componentBlock) {
|
||||||
|
console.warn("Can't provide: no current component block");
|
||||||
|
}
|
||||||
|
current2.componentBlock.provides.set(key, value);
|
||||||
|
}
|
||||||
|
function inject(key) {
|
||||||
|
if (!current2.componentBlock) {
|
||||||
|
console.warn("Can't inject: no current component block");
|
||||||
|
}
|
||||||
|
let c = current2.componentBlock;
|
||||||
|
while (c) {
|
||||||
|
if (c.provides.has(key)) {
|
||||||
|
return c.provides.get(key);
|
||||||
|
}
|
||||||
|
c = c.parentComponentBlock;
|
||||||
|
}
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
var App2 = class {
|
var App2 = class {
|
||||||
root;
|
root;
|
||||||
registry = /* @__PURE__ */ new Map();
|
registry = /* @__PURE__ */ new Map();
|
||||||
@ -892,6 +916,14 @@ function createContext({ parentContext, app: app2 }) {
|
|||||||
};
|
};
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
var extendScopedContext = (ctx, data = {}) => {
|
||||||
|
const parentScope = ctx.scope;
|
||||||
|
const mergedScope = { ...parentScope };
|
||||||
|
Object.defineProperties(mergedScope, Object.getOwnPropertyDescriptors(data));
|
||||||
|
const reactiveScope = reactive(mergedScope);
|
||||||
|
ctx.scope = reactiveScope;
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
var createScopedContext = (ctx, data = {}) => {
|
var createScopedContext = (ctx, data = {}) => {
|
||||||
const parentScope = ctx.scope;
|
const parentScope = ctx.scope;
|
||||||
const mergedScope = Object.create(parentScope);
|
const mergedScope = Object.create(parentScope);
|
||||||
@ -970,11 +1002,24 @@ var Block = class {
|
|||||||
}
|
}
|
||||||
if (opts.component) {
|
if (opts.component) {
|
||||||
this.componentProps = mergeProps(opts.componentProps ?? {}, opts.component.props ?? {});
|
this.componentProps = mergeProps(opts.componentProps ?? {}, opts.component.props ?? {});
|
||||||
if (opts.component.main) {
|
const componentScope = opts.component.main ? opts.component.main(this.componentProps) || {} : {};
|
||||||
this.context.scope = {
|
const providedKeys = /* @__PURE__ */ new Set();
|
||||||
...opts.component.main(this.componentProps) || {}
|
let currentBlock = this.parentComponentBlock;
|
||||||
};
|
while (currentBlock) {
|
||||||
|
currentBlock.provides.forEach((_, key) => providedKeys.add(key));
|
||||||
|
currentBlock = currentBlock.parentComponentBlock;
|
||||||
}
|
}
|
||||||
|
for (const key of providedKeys) {
|
||||||
|
if (componentScope[key] === void 0) {
|
||||||
|
const providedValue = inject(key);
|
||||||
|
if (providedValue !== void 0) {
|
||||||
|
componentScope[key] = providedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.context.scope = {
|
||||||
|
...componentScope
|
||||||
|
};
|
||||||
}
|
}
|
||||||
opts.allProps?.forEach((prop) => {
|
opts.allProps?.forEach((prop) => {
|
||||||
if (prop.isBind) {
|
if (prop.isBind) {
|
||||||
@ -1024,14 +1069,14 @@ var Block = class {
|
|||||||
this.componentProps[name] = value;
|
this.componentProps[name] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insert(parent, anchor = null) {
|
insert(parent2, anchor = null) {
|
||||||
if (this.isFragment) {
|
if (this.isFragment) {
|
||||||
if (this.start) {
|
if (this.start) {
|
||||||
let node = this.start;
|
let node = this.start;
|
||||||
let next;
|
let next;
|
||||||
while (node) {
|
while (node) {
|
||||||
next = node.nextSibling;
|
next = node.nextSibling;
|
||||||
parent.insertBefore(node, anchor);
|
parent2.insertBefore(node, anchor);
|
||||||
if (node === this.end) {
|
if (node === this.end) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1040,12 +1085,12 @@ var Block = class {
|
|||||||
} else {
|
} else {
|
||||||
this.start = new Text("");
|
this.start = new Text("");
|
||||||
this.end = new Text("");
|
this.end = new Text("");
|
||||||
parent.insertBefore(this.end, anchor);
|
parent2.insertBefore(this.end, anchor);
|
||||||
parent.insertBefore(this.start, this.end);
|
parent2.insertBefore(this.start, this.end);
|
||||||
parent.insertBefore(this.element, this.end);
|
parent2.insertBefore(this.element, this.end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parent.insertBefore(this.element, anchor);
|
parent2.insertBefore(this.element, anchor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remove() {
|
remove() {
|
||||||
@ -1056,12 +1101,15 @@ var Block = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.start) {
|
if (this.start) {
|
||||||
const parent = this.start.parentNode;
|
const parent2 = this.start.parentNode;
|
||||||
|
if (!parent2) {
|
||||||
|
throw new Error("Parent node is null");
|
||||||
|
}
|
||||||
let node = this.start;
|
let node = this.start;
|
||||||
let next;
|
let next;
|
||||||
while (node) {
|
while (node) {
|
||||||
next = node.nextSibling;
|
next = node.nextSibling;
|
||||||
parent.removeChild(node);
|
parent2.removeChild(node);
|
||||||
if (node === this.end) {
|
if (node === this.end) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1076,7 +1124,7 @@ var Block = class {
|
|||||||
this.context.blocks.forEach((block) => {
|
this.context.blocks.forEach((block) => {
|
||||||
block.teardown();
|
block.teardown();
|
||||||
});
|
});
|
||||||
this.context.effects.forEach((e) => e.stop());
|
this.context.effects.forEach((e) => void e.stop());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function isComponent(element, context) {
|
function isComponent(element, context) {
|
||||||
@ -1084,7 +1132,7 @@ function isComponent(element, context) {
|
|||||||
}
|
}
|
||||||
function warnInvalidDirectives(node, directives) {
|
function warnInvalidDirectives(node, directives) {
|
||||||
if (directives.every((d) => node.hasAttribute(d))) {
|
if (directives.every((d) => node.hasAttribute(d))) {
|
||||||
console.warn(`These directives cannot be used together on the same node:`, directives);
|
console.warn("These directives cannot be used together on the same node:", directives);
|
||||||
console.warn("Node ignored:", node);
|
console.warn("Node ignored:", node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1104,12 +1152,23 @@ function walk(node, context) {
|
|||||||
if (warnInvalidDirectives(node2, [":for", ":teleport"])) return;
|
if (warnInvalidDirectives(node2, [":for", ":teleport"])) return;
|
||||||
if (warnInvalidDirectives(node2, [":if", ":teleport"])) return;
|
if (warnInvalidDirectives(node2, [":if", ":teleport"])) return;
|
||||||
if (exp = checkAndRemoveAttribute(node2, ":scope")) {
|
if (exp = checkAndRemoveAttribute(node2, ":scope")) {
|
||||||
|
const scope = evalGet(context2.scope, exp, node2);
|
||||||
|
context2.scope = extendScopedContext(context2, scope).scope;
|
||||||
|
}
|
||||||
|
if (exp = checkAndRemoveAttribute(node2, ":scope:provide")) {
|
||||||
const scope = evalGet(context2.scope, exp, node2);
|
const scope = evalGet(context2.scope, exp, node2);
|
||||||
if (typeof scope === "object") {
|
if (typeof scope === "object") {
|
||||||
Object.assign(context2.scope, scope);
|
Object.assign(context2.scope, scope);
|
||||||
|
Object.entries(scope).forEach(([key, value]) => {
|
||||||
|
provide(key, value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp = checkAndRemoveAttribute(node2, ":if")) {
|
if (exp = checkAndRemoveAttribute(node2, ":if")) {
|
||||||
|
if (current2.componentBlock) {
|
||||||
|
const merged = extendScopedContext(context2, current2.componentBlock?.parentComponentBlock?.context.scope);
|
||||||
|
return _if(node2, exp, merged, component, componentProps, allProps);
|
||||||
|
}
|
||||||
return _if(node2, exp, context2, component, componentProps, allProps);
|
return _if(node2, exp, context2, component, componentProps, allProps);
|
||||||
}
|
}
|
||||||
if (exp = checkAndRemoveAttribute(node2, ":for")) {
|
if (exp = checkAndRemoveAttribute(node2, ":for")) {
|
||||||
@ -1175,7 +1234,7 @@ function walk(node, context) {
|
|||||||
return new Block({
|
return new Block({
|
||||||
element: node,
|
element: node,
|
||||||
app: current2.componentBlock.context.app,
|
app: current2.componentBlock.context.app,
|
||||||
// parentContext: context,
|
parentContext: context,
|
||||||
component,
|
component,
|
||||||
replacementType: "replace",
|
replacementType: "replace",
|
||||||
parentComponentBlock: current2.componentBlock,
|
parentComponentBlock: current2.componentBlock,
|
||||||
@ -1197,9 +1256,9 @@ function walk(node, context) {
|
|||||||
walkChildren(node, context);
|
walkChildren(node, context);
|
||||||
}
|
}
|
||||||
function walkChildren(node, context) {
|
function walkChildren(node, context) {
|
||||||
let child2 = node.firstChild;
|
let child = node.firstChild;
|
||||||
while (child2) {
|
while (child) {
|
||||||
child2 = walk(child2, context) || child2.nextSibling;
|
child = walk(child, context) || child.nextSibling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var evalFuncCache = {};
|
var evalFuncCache = {};
|
||||||
@ -1241,34 +1300,49 @@ function flattenRefs(scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// src/demo.ts
|
// src/demo.ts
|
||||||
var child = {
|
var app = new App2();
|
||||||
|
var parent = {
|
||||||
template: html`
|
template: html`
|
||||||
<div>
|
<div>
|
||||||
I am child and I have a cheeseburger: "{{food}}" (does not inherit)
|
<h1>parent, bool: {{bool}}</h1>
|
||||||
<div>
|
<card>
|
||||||
<slot />
|
<!-- default -->
|
||||||
</div>
|
<div :if="bool">
|
||||||
|
<div :teleport="body" id="teleported">
|
||||||
|
<div>showing 1-3 because bool is true</div>
|
||||||
|
<div>1</div>
|
||||||
|
<div>2</div>
|
||||||
|
<div>3</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
content 1 always shown
|
||||||
|
<div :if="bool">
|
||||||
|
content 2, animals:
|
||||||
|
<div :for="animal in animals">animal: {{animal}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- body -->
|
||||||
|
<template slot="body">card body from parent</template>
|
||||||
|
</card>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
main() {
|
main() {
|
||||||
const food = ref("\u{1F354}");
|
const bool = ref(true);
|
||||||
return { food };
|
const animals = reactive(["dog", "cat", "bear"]);
|
||||||
|
setInterval(() => {
|
||||||
|
bool.value = !bool.value;
|
||||||
|
}, 2e3);
|
||||||
|
return { bool, animals };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var main = {
|
var card = {
|
||||||
template: html`
|
template: html`<div>
|
||||||
<div class="hero sans-serif f2" :scope="{ drink: '🍹' }">
|
<h2>card</h2>
|
||||||
<div :scope="{ food: '🍕' }">
|
<h3><slot /></h3>
|
||||||
<div>Parent has pizza: {{food}} and scoped drink: {{drink}}</div>
|
<slot name="body" />
|
||||||
<child>Child slot, food: {{food}} {{drink}}</child>
|
</div>`
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
main() {
|
|
||||||
return { food: ref("nothing") };
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
var app = new App2();
|
app.register("card", card);
|
||||||
app.register("child", child);
|
var parentBlock = app.mount(parent, "body");
|
||||||
app.mount(main, "#app");
|
var cardBlock = parentBlock.context.blocks[0];
|
||||||
//# sourceMappingURL=demo.js.map
|
//# sourceMappingURL=demo.js.map
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
169
src/demo.ts
169
src/demo.ts
@ -31,53 +31,54 @@ import { html } from "./util";
|
|||||||
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// Slots, multiple default and named, :if and :for
|
// Slots, multiple default and named, :if and :for
|
||||||
// const app = new App();
|
const app = new App();
|
||||||
|
|
||||||
// const parent = {
|
const parent = {
|
||||||
// template: html`
|
template: html`
|
||||||
// <div>
|
<div>
|
||||||
// <h1>parent</h1>
|
<h1>parent, bool: {{bool}}</h1>
|
||||||
// <card>
|
<card>
|
||||||
// <!-- default -->
|
<!-- default -->
|
||||||
// <div :if="bool">
|
<div :if="bool">
|
||||||
// <div :teleport="body" id="teleported">
|
<div :teleport="body" id="teleported">
|
||||||
// <div>1</div>
|
<div>showing 1-3 because bool is true</div>
|
||||||
// <div>2</div>
|
<div>1</div>
|
||||||
// <div>3</div>
|
<div>2</div>
|
||||||
// </div>
|
<div>3</div>
|
||||||
// </div>
|
</div>
|
||||||
// content 1 always shown
|
</div>
|
||||||
// <div :if="bool">
|
content 1 always shown
|
||||||
// content 2, animals:
|
<div :if="bool">
|
||||||
// <div :for="animal in animals">animal: {{animal}}</div>
|
content 2, animals:
|
||||||
// </div>
|
<div :for="animal in animals">animal: {{animal}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
// <!-- body -->
|
<!-- body -->
|
||||||
// <template slot="body">card body from parent</template>
|
<template slot="body">card body from parent</template>
|
||||||
// </card>
|
</card>
|
||||||
// </div>
|
</div>
|
||||||
// `,
|
`,
|
||||||
// main() {
|
main() {
|
||||||
// const bool = ref(true);
|
const bool = ref(true);
|
||||||
// const animals = reactive(["dog", "cat", "bear"]);
|
const animals = reactive(["dog", "cat", "bear"]);
|
||||||
|
|
||||||
// setInterval(() => {
|
setInterval(() => {
|
||||||
// bool.value = !bool.value;
|
bool.value = !bool.value;
|
||||||
// }, 2000);
|
}, 2000);
|
||||||
|
|
||||||
// return { bool, animals };
|
return { bool, animals };
|
||||||
// },
|
},
|
||||||
// };
|
};
|
||||||
// const card = {
|
const card = {
|
||||||
// template: html`<div>
|
template: html`<div>
|
||||||
// <h2>card</h2>
|
<h2>card</h2>
|
||||||
// <h3><slot /></h3>
|
<h3><slot /></h3>
|
||||||
// <slot name="body" />
|
<slot name="body" />
|
||||||
// </div>`,
|
</div>`,
|
||||||
// };
|
};
|
||||||
// app.register("card", card);
|
app.register("card", card);
|
||||||
// const parentBlock = app.mount(parent, "body");
|
const parentBlock = app.mount(parent, "body");
|
||||||
// const cardBlock = parentBlock.context.blocks[0];
|
const cardBlock = parentBlock.context.blocks[0];
|
||||||
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// Component pros, mirror and spread, bind and no bind
|
// Component pros, mirror and spread, bind and no bind
|
||||||
@ -268,48 +269,50 @@ import { html } from "./util";
|
|||||||
// const ranks = reactive(["5", "10", "20", "30", "40", "50", "60", "70", "80", "90"]);
|
// const ranks = reactive(["5", "10", "20", "30", "40", "50", "60", "70", "80", "90"]);
|
||||||
// const basesReverse = computed(() => Array.from(ranks).reverse());
|
// const basesReverse = computed(() => Array.from(ranks).reverse());
|
||||||
// const bg = (variant: string, rank: string, index: number) => ({ backgroundColor: `var(--${variant}-${rank})`, color: `var(--${variant}-${basesReverse.value[index]})` });
|
// const bg = (variant: string, rank: string, index: number) => ({ backgroundColor: `var(--${variant}-${rank})`, color: `var(--${variant}-${basesReverse.value[index]})` });
|
||||||
|
//
|
||||||
// return { ranks, bg };
|
// return { ranks, bg };
|
||||||
// },
|
// },
|
||||||
// };
|
// };
|
||||||
|
//
|
||||||
// const app = new App();
|
// const app = new App();
|
||||||
// app.mount(main, "#app");
|
// app.mount(main, "#app");
|
||||||
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// :scope
|
// :scope
|
||||||
const child = {
|
// const child = {
|
||||||
template: html`
|
// template: html`
|
||||||
<div>
|
// <div>
|
||||||
I am child and I have a cheeseburger: "{{food}}" (does not inherit)
|
// I am child and I have a cheeseburger: "{{food}}" (does not inherit)
|
||||||
<div>
|
// <div>
|
||||||
<slot />
|
// <slot />
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
`,
|
// `,
|
||||||
main() {
|
// main() {
|
||||||
const food = ref("🍔");
|
// // Comment this out to implicitly inherit the
|
||||||
return { food };
|
// // provided :scope value from the parent.
|
||||||
},
|
// const food = ref("🍔");
|
||||||
};
|
// return { food };
|
||||||
|
// },
|
||||||
const main = {
|
// };
|
||||||
template: html`
|
//
|
||||||
<div class="hero sans-serif f2" :scope="{ drink: '🍹' }">
|
// const main = {
|
||||||
<div :scope="{ food: '🍕' }">
|
// template: html`
|
||||||
<div>Parent has pizza: {{food}} and scoped drink: {{drink}}</div>
|
// <div class="hero sans-serif f2" :scope:provide="{ drink: '🍹' }">
|
||||||
<child>Child slot, food: {{food}} {{drink}}</child>
|
// <div :scope:provide="{ food: '🍕' }">
|
||||||
</div>
|
// <div>Parent has pizza: {{food}} and scoped drink: {{drink}}</div>
|
||||||
</div>
|
// <child>Child slot, food: {{food}} {{drink}}</child>
|
||||||
`,
|
// </div>
|
||||||
main() {
|
// </div>
|
||||||
return { food: ref("nothing") };
|
// `,
|
||||||
},
|
// main() {
|
||||||
};
|
// // return { food: ref("nothing") };
|
||||||
|
// },
|
||||||
const app = new App();
|
// };
|
||||||
app.register("child", child);
|
//
|
||||||
app.mount(main, "#app");
|
// const app = new App();
|
||||||
|
// app.register("child", child);
|
||||||
|
// app.mount(main, "#app");
|
||||||
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// Practical :scope demo
|
// Practical :scope demo
|
||||||
@ -318,18 +321,16 @@ app.mount(main, "#app");
|
|||||||
// <div class="hero sans-serif f2" :scope="{ visible: true }">
|
// <div class="hero sans-serif f2" :scope="{ visible: true }">
|
||||||
// <div :show="visible">ON</div>
|
// <div :show="visible">ON</div>
|
||||||
// <div :show="!visible">OFF</div>
|
// <div :show="!visible">OFF</div>
|
||||||
// <button @click="() => visible = !visible" class="padding-x-1 padding-y-0_5 border-radius-1">Toggle</button>
|
// <button @click="visible = !visible" class="padding-x-1 padding-y-0_5 border-radius-0_25">Toggle</button>
|
||||||
|
// <div>visible: {{visible}} / foo: {{foo}}</div>
|
||||||
// </div>
|
// </div>
|
||||||
// `,
|
// `,
|
||||||
// main() {
|
// main() {
|
||||||
// const onClick = () => {
|
// const foo = ref("bar");
|
||||||
// console.log("ok");
|
// return { foo };
|
||||||
// };
|
|
||||||
//
|
|
||||||
// return { onClick };
|
|
||||||
// },
|
// },
|
||||||
// };
|
// };
|
||||||
//
|
|
||||||
// const app = new App();
|
// const app = new App();
|
||||||
// app.mount(main, "#app");
|
// app.mount(main, "#app");
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Context, evalGet } from "..";
|
import { Context, evalGet, execute } from "..";
|
||||||
|
|
||||||
interface EventDirectiveOptions {
|
interface EventDirectiveOptions {
|
||||||
element: Element;
|
element: Element;
|
||||||
@ -31,7 +31,9 @@ export class EventDirective {
|
|||||||
|
|
||||||
const handler = evalGet(context.scope, attr.value, element);
|
const handler = evalGet(context.scope, attr.value, element);
|
||||||
if (typeof handler === "function") {
|
if (typeof handler === "function") {
|
||||||
handler(event);
|
handler.call(context.scope, event);
|
||||||
|
} else {
|
||||||
|
execute(context.scope, this.expression, element, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ interface Branch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function _if(el: Element, exp: string, ctx: Context, component?: Component, componentProps?: Record<string, any>, allProps?: Record<string, any>) {
|
export function _if(el: Element, exp: string, ctx: Context, component?: Component, componentProps?: Record<string, any>, allProps?: Record<string, any>) {
|
||||||
|
// console.log("_if received scope", ctx.scope);
|
||||||
const parent = el.parentElement!;
|
const parent = el.parentElement!;
|
||||||
const anchor = new Comment(":if");
|
const anchor = new Comment(":if");
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ export function _if(el: Element, exp: string, ctx: Context, component?: Componen
|
|||||||
ctx.effect(() => {
|
ctx.effect(() => {
|
||||||
for (let i = 0; i < branches.length; i++) {
|
for (let i = 0; i < branches.length; i++) {
|
||||||
const { exp, el } = branches[i];
|
const { exp, el } = branches[i];
|
||||||
|
// console.log("scope", ctx.scope);
|
||||||
|
|
||||||
if (!exp || evalGet(ctx.scope, exp, el)) {
|
if (!exp || evalGet(ctx.scope, exp, el)) {
|
||||||
if (i !== activeBranchIndex) {
|
if (i !== activeBranchIndex) {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { Block, Component, Context } from "..";
|
import { Block, Component, Context, evalGet } from "..";
|
||||||
import { insertBefore } from "../util";
|
import { insertBefore, nextTick } from "../util";
|
||||||
|
|
||||||
export function _teleport(el: Element, exp: string, ctx: Context, component?: Component, componentProps?: Record<string, any>, allProps?: Record<string, any>) {
|
export function _teleport(el: Element, exp: string, ctx: Context, component?: Component, componentProps?: Record<string, any>, allProps?: Record<string, any>) {
|
||||||
|
console.log("_teleport", ctx.scope);
|
||||||
const anchor = new Comment(":teleport anchor");
|
const anchor = new Comment(":teleport anchor");
|
||||||
insertBefore(anchor, el);
|
insertBefore(anchor, el);
|
||||||
const observed = new Comment(":teleport");
|
const observed = new Comment(":teleport");
|
||||||
@ -23,12 +24,19 @@ export function _teleport(el: Element, exp: string, ctx: Context, component?: Co
|
|||||||
|
|
||||||
let block: Block;
|
let block: Block;
|
||||||
|
|
||||||
target.appendChild(el);
|
// nextTick(() => {
|
||||||
|
target.appendChild(el);
|
||||||
|
console.log("appended", el, "to", target);
|
||||||
|
// })
|
||||||
|
// setTimeout(() => {
|
||||||
|
// });
|
||||||
|
|
||||||
const observer = new MutationObserver((mutationsList) => {
|
const observer = new MutationObserver((mutationsList) => {
|
||||||
mutationsList.forEach((mutation) => {
|
mutationsList.forEach((mutation) => {
|
||||||
mutation.removedNodes.forEach((removedNode) => {
|
mutation.removedNodes.forEach((removedNode) => {
|
||||||
if (removedNode.contains(observed)) {
|
console.log("removedNode", removedNode, "observed:", observed);
|
||||||
|
// if (removedNode.contains(observed)) {
|
||||||
|
if (removedNode.contains(anchor)) {
|
||||||
if (block.element) block.remove();
|
if (block.element) block.remove();
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
}
|
}
|
||||||
@ -36,7 +44,8 @@ export function _teleport(el: Element, exp: string, ctx: Context, component?: Co
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
// observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
observer.observe(document.querySelector(exp) || document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
el.style.display = originalDisplay;
|
el.style.display = originalDisplay;
|
||||||
|
|||||||
147
src/index.ts
147
src/index.ts
@ -6,30 +6,12 @@ import { InterpolationDirective } from "./directives/interpolation";
|
|||||||
import { ShowDirective } from "./directives/show";
|
import { ShowDirective } from "./directives/show";
|
||||||
import { _teleport } from "./directives/teleport";
|
import { _teleport } from "./directives/teleport";
|
||||||
import { ValueDirective } from "./directives/value";
|
import { ValueDirective } from "./directives/value";
|
||||||
import { Plugin } from "./plugins";
|
import type { Plugin } from "./plugins";
|
||||||
import { isComputed } from "./reactivity/computed";
|
import { isComputed } from "./reactivity/computed";
|
||||||
import { effect as _effect } from "./reactivity/effect";
|
import { effect as _effect } from "./reactivity/effect";
|
||||||
import { reactive } from "./reactivity/reactive";
|
import { reactive } from "./reactivity/reactive";
|
||||||
import { isRef } from "./reactivity/ref";
|
import { isRef } from "./reactivity/ref";
|
||||||
import {
|
import { checkAndRemoveAttribute, componentHasPropByName, extractPropName, findSlotNodes, findTemplateNodes, isElement, isEventAttribute, isMirrorProp, isObject, isPropAttribute, isRegularProp, isSpreadProp, isText, type Slot, stringToElement, type Template, toDisplayString } from "./util";
|
||||||
checkAndRemoveAttribute,
|
|
||||||
componentHasPropByName,
|
|
||||||
extractPropName,
|
|
||||||
findSlotNodes,
|
|
||||||
findTemplateNodes,
|
|
||||||
isElement,
|
|
||||||
isEventAttribute,
|
|
||||||
isMirrorProp,
|
|
||||||
isObject,
|
|
||||||
isPropAttribute,
|
|
||||||
isRegularProp,
|
|
||||||
isSpreadProp,
|
|
||||||
isText,
|
|
||||||
Slot,
|
|
||||||
stringToElement,
|
|
||||||
Template,
|
|
||||||
toDisplayString,
|
|
||||||
} from "./util";
|
|
||||||
|
|
||||||
export * from "./plugins";
|
export * from "./plugins";
|
||||||
export * from "./plugins/router";
|
export * from "./plugins/router";
|
||||||
@ -145,9 +127,29 @@ export function createContext({ parentContext, app }: CreateContextOptions): Con
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// console.log('createContext, scope:', context.scope);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const extendScopedContext = (ctx: Context, data = {}): Context => {
|
||||||
|
const parentScope = ctx.scope;
|
||||||
|
|
||||||
|
// Create a new object that inherits from parentScope
|
||||||
|
const mergedScope = { ...parentScope };
|
||||||
|
|
||||||
|
// Add the new properties from data
|
||||||
|
Object.defineProperties(mergedScope, Object.getOwnPropertyDescriptors(data));
|
||||||
|
|
||||||
|
// Make it reactive
|
||||||
|
const reactiveScope = reactive(mergedScope);
|
||||||
|
|
||||||
|
// Assign it back to the context
|
||||||
|
ctx.scope = reactiveScope;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
|
|
||||||
export const createScopedContext = (ctx: Context, data = {}): Context => {
|
export const createScopedContext = (ctx: Context, data = {}): Context => {
|
||||||
const parentScope = ctx.scope;
|
const parentScope = ctx.scope;
|
||||||
const mergedScope = Object.create(parentScope);
|
const mergedScope = Object.create(parentScope);
|
||||||
@ -232,15 +234,15 @@ export class Block {
|
|||||||
context: Context;
|
context: Context;
|
||||||
parentContext: Context;
|
parentContext: Context;
|
||||||
component: Component;
|
component: Component;
|
||||||
provides = new Map<string, any>();
|
provides = new Map<string, unknown>();
|
||||||
parentComponentBlock: Block | undefined;
|
parentComponentBlock: Block | undefined;
|
||||||
componentProps: Record<string, any>;
|
componentProps: Record<string, unknown>;
|
||||||
allProps: Record<string, any>;
|
allProps: Record<string, unknown>;
|
||||||
|
|
||||||
isFragment: boolean;
|
isFragment: boolean;
|
||||||
start?: Text;
|
start?: Text;
|
||||||
end?: Text;
|
end?: Text;
|
||||||
key?: any;
|
key?: unknown;
|
||||||
|
|
||||||
constructor(opts: BlockOptions) {
|
constructor(opts: BlockOptions) {
|
||||||
this.isFragment = opts.element instanceof HTMLTemplateElement;
|
this.isFragment = opts.element instanceof HTMLTemplateElement;
|
||||||
@ -265,16 +267,39 @@ export class Block {
|
|||||||
this.parentContext = opts.parentContext ? opts.parentContext : createContext({});
|
this.parentContext = opts.parentContext ? opts.parentContext : createContext({});
|
||||||
this.parentContext.blocks.push(this);
|
this.parentContext.blocks.push(this);
|
||||||
this.context = createContext({ parentContext: opts.parentContext, app: opts.app });
|
this.context = createContext({ parentContext: opts.parentContext, app: opts.app });
|
||||||
|
// console.log('created context', this.context.scope);
|
||||||
|
// console.log('opts.parentContext was', opts.parentContext.scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.component) {
|
if (opts.component) {
|
||||||
this.componentProps = mergeProps(opts.componentProps ?? {}, opts.component.props ?? {});
|
this.componentProps = mergeProps(opts.componentProps ?? {}, opts.component.props ?? {});
|
||||||
|
|
||||||
if (opts.component.main) {
|
// Create the component scope
|
||||||
this.context.scope = {
|
const componentScope = opts.component.main ? opts.component.main(this.componentProps) || {} : {};
|
||||||
...(opts.component.main(this.componentProps) || {}),
|
|
||||||
};
|
// Check for provided values from parent components
|
||||||
|
// First, get all provided keys from parent components
|
||||||
|
const providedKeys = new Set<string>();
|
||||||
|
let currentBlock = this.parentComponentBlock;
|
||||||
|
while (currentBlock) {
|
||||||
|
currentBlock.provides.forEach((_, key) => providedKeys.add(key));
|
||||||
|
currentBlock = currentBlock.parentComponentBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then inject values for each provided key
|
||||||
|
for (const key of providedKeys) {
|
||||||
|
// Only inject if the component doesn't already define this value
|
||||||
|
if (componentScope[key] === undefined) {
|
||||||
|
const providedValue = inject(key);
|
||||||
|
if (providedValue !== undefined) {
|
||||||
|
componentScope[key] = providedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.context.scope = {
|
||||||
|
...componentScope,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.allProps?.forEach((prop: any) => {
|
opts.allProps?.forEach((prop: any) => {
|
||||||
@ -376,7 +401,10 @@ export class Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.start) {
|
if (this.start) {
|
||||||
const parent = this.start.parentNode!;
|
const parent = this.start.parentNode;
|
||||||
|
if (!parent) {
|
||||||
|
throw new Error("Parent node is null");
|
||||||
|
}
|
||||||
let node: Node | null = this.start;
|
let node: Node | null = this.start;
|
||||||
let next: Node | null;
|
let next: Node | null;
|
||||||
|
|
||||||
@ -402,7 +430,7 @@ export class Block {
|
|||||||
block.teardown();
|
block.teardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.context.effects.forEach((e) => e.stop());
|
this.context.effects.forEach((e) => void e.stop());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +440,7 @@ function isComponent(element: Element, context: Context) {
|
|||||||
|
|
||||||
function warnInvalidDirectives(node: Element, directives: string[]): boolean {
|
function warnInvalidDirectives(node: Element, directives: string[]): boolean {
|
||||||
if (directives.every((d) => node.hasAttribute(d))) {
|
if (directives.every((d) => node.hasAttribute(d))) {
|
||||||
console.warn(`These directives cannot be used together on the same node:`, directives);
|
console.warn("These directives cannot be used together on the same node:", directives);
|
||||||
console.warn("Node ignored:", node);
|
console.warn("Node ignored:", node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -426,7 +454,9 @@ function walk(node: Node, context: Context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isElement(node)) { return; }
|
if (!isElement(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let exp: string | null;
|
let exp: string | null;
|
||||||
|
|
||||||
@ -438,15 +468,39 @@ function walk(node: Node, context: Context) {
|
|||||||
// e.g. <div :scope="{ open: true }" />
|
// e.g. <div :scope="{ open: true }" />
|
||||||
// In this case, the scope is merged into context.scope and will overwrite
|
// In this case, the scope is merged into context.scope and will overwrite
|
||||||
// anything returned from `main`.
|
// anything returned from `main`.
|
||||||
|
// if ((exp = checkAndRemoveAttribute(node, ":scope"))) {
|
||||||
|
// const scope = evalGet(context.scope, exp, node);
|
||||||
|
// if (typeof scope === "object") {
|
||||||
|
// Object.assign(context.scope, scope);
|
||||||
|
// // context = createScopedContext(context, scope);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if ((exp = checkAndRemoveAttribute(node, ":scope"))) {
|
if ((exp = checkAndRemoveAttribute(node, ":scope"))) {
|
||||||
|
const scope = evalGet(context.scope, exp, node);
|
||||||
|
context.scope = extendScopedContext(context, scope).scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle :scope:provide directive - provides values to all descendants
|
||||||
|
if ((exp = checkAndRemoveAttribute(node, ":scope:provide"))) {
|
||||||
const scope = evalGet(context.scope, exp, node);
|
const scope = evalGet(context.scope, exp, node);
|
||||||
if (typeof scope === "object") {
|
if (typeof scope === "object") {
|
||||||
|
// First, merge into the current scope
|
||||||
Object.assign(context.scope, scope);
|
Object.assign(context.scope, scope);
|
||||||
// context = createScopedContext(context, scope);
|
|
||||||
|
// Then provide each key-value pair to descendants
|
||||||
|
Object.entries(scope).forEach(([key, value]) => {
|
||||||
|
provide(key, value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((exp = checkAndRemoveAttribute(node, ":if"))) {
|
if ((exp = checkAndRemoveAttribute(node, ":if"))) {
|
||||||
|
// TODO: Uh
|
||||||
|
if (current.componentBlock) {
|
||||||
|
const merged = extendScopedContext(context, current.componentBlock?.parentComponentBlock?.context.scope);
|
||||||
|
return _if(node, exp, merged, component, componentProps, allProps);
|
||||||
|
}
|
||||||
return _if(node, exp, context, component, componentProps, allProps);
|
return _if(node, exp, context, component, componentProps, allProps);
|
||||||
}
|
}
|
||||||
if ((exp = checkAndRemoveAttribute(node, ":for"))) {
|
if ((exp = checkAndRemoveAttribute(node, ":for"))) {
|
||||||
@ -486,17 +540,18 @@ function walk(node: Node, context: Context) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const processAttributes = (node: Element, component?: Component) => Array.from(node.attributes)
|
const processAttributes = (node: Element, component?: Component) =>
|
||||||
.filter((attr) => isSpreadProp(attr.name) || isMirrorProp(attr.name) || (isRegularProp(attr.name) && componentHasPropByName(extractPropName(attr.name), component)))
|
Array.from(node.attributes)
|
||||||
.map((attr) => ({
|
.filter((attr) => isSpreadProp(attr.name) || isMirrorProp(attr.name) || (isRegularProp(attr.name) && componentHasPropByName(extractPropName(attr.name), component)))
|
||||||
isMirror: isMirrorProp(attr.name),
|
.map((attr) => ({
|
||||||
isSpread: isSpreadProp(attr.name),
|
isMirror: isMirrorProp(attr.name),
|
||||||
isBind: attr.name.includes("bind"),
|
isSpread: isSpreadProp(attr.name),
|
||||||
originalName: attr.name,
|
isBind: attr.name.includes("bind"),
|
||||||
extractedName: extractPropName(attr.name),
|
originalName: attr.name,
|
||||||
exp: attr.value,
|
extractedName: extractPropName(attr.name),
|
||||||
value: isMirrorProp(attr.name) ? evalGet(context.scope, extractPropName(attr.name), node) : attr.value ? evalGet(context.scope, attr.value, node) : undefined,
|
exp: attr.value,
|
||||||
}));
|
value: isMirrorProp(attr.name) ? evalGet(context.scope, extractPropName(attr.name), node) : attr.value ? evalGet(context.scope, attr.value, node) : undefined,
|
||||||
|
}));
|
||||||
|
|
||||||
if (isComponent(node, context)) {
|
if (isComponent(node, context)) {
|
||||||
const component = context.app.getComponent(node.tagName.toLowerCase());
|
const component = context.app.getComponent(node.tagName.toLowerCase());
|
||||||
@ -522,7 +577,7 @@ function walk(node: Node, context: Context) {
|
|||||||
return new Block({
|
return new Block({
|
||||||
element: node,
|
element: node,
|
||||||
app: current.componentBlock.context.app,
|
app: current.componentBlock.context.app,
|
||||||
// parentContext: context,
|
parentContext: context,
|
||||||
component,
|
component,
|
||||||
replacementType: "replace",
|
replacementType: "replace",
|
||||||
parentComponentBlock: current.componentBlock,
|
parentComponentBlock: current.componentBlock,
|
||||||
@ -568,7 +623,7 @@ export function evalSet(scope: any, exp: string, value: unknown) {
|
|||||||
return execute(scope, `const ___target = (${exp.trim()}); return $isRef(___target) ? ___target.value = ${value} : ___target = ${value};`, null, false);
|
return execute(scope, `const ___target = (${exp.trim()}); return $isRef(___target) ? ___target.value = ${value} : ___target = ${value};`, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(scope: any, exp: string, el?: Node, flatRefs = true) {
|
export function execute(scope: any, exp: string, el?: Node, flatRefs = true) {
|
||||||
const newScope = flatRefs ? flattenRefs(scope) : scope;
|
const newScope = flatRefs ? flattenRefs(scope) : scope;
|
||||||
const fn = evalFuncCache[exp] || (evalFuncCache[exp] = toFunction(exp));
|
const fn = evalFuncCache[exp] || (evalFuncCache[exp] = toFunction(exp));
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user