This commit is contained in:
nvms 2024-10-19 10:26:39 -04:00
parent 31fea795bf
commit 2c4e66bd8d
6 changed files with 109 additions and 65 deletions

View File

@ -195,7 +195,6 @@ var AttributeDirective = class {
if (this.is.spread) {
this.expression = this.extractedAttributeName;
}
console.log("attribute", attr.name, "spread?", this.is.spread);
element.removeAttribute(attr.name);
if (this.is.bound) {
context.effect(this.update.bind(this));
@ -504,6 +503,25 @@ var InterpolationDirective = class {
}
};
// src/directives/show.ts
var ShowDirective = class {
element;
context;
expression;
originalDisplay;
constructor({ element, context, expression }) {
this.element = element;
this.context = context;
this.expression = expression;
this.originalDisplay = getComputedStyle(this.element).display;
context.effect(this.update.bind(this));
}
update() {
const shouldShow = Boolean(evalGet(this.context.scope, this.expression));
this.element.style.display = shouldShow ? this.originalDisplay : "none";
}
};
// src/directives/teleport.ts
function _teleport(el, exp, ctx) {
const anchor = new Comment(":teleport");
@ -515,18 +533,22 @@ function _teleport(el, exp, ctx) {
}
nextTick(() => {
target.appendChild(el);
});
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.removedNodes.forEach((removedNode) => {
if (removedNode.contains(anchor)) {
el.remove();
observer.disconnect();
}
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.removedNodes.forEach((removedNode) => {
if (removedNode.contains(anchor)) {
el.remove();
observer.disconnect();
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
new Block({
element: el,
parentContext: ctx
});
});
observer.observe(document.body, { childList: true, subtree: true });
return anchor;
}
@ -1089,6 +1111,9 @@ function walk(node, context) {
if (exp = checkAndRemoveAttribute(node, ":for")) {
return _for(node, exp, context, component, componentProps, allProps);
}
if (exp = checkAndRemoveAttribute(node, ":show")) {
new ShowDirective({ element: node, context, expression: exp });
}
const templates = findTemplateNodes(node);
const block = new Block({
element: node,
@ -1117,6 +1142,9 @@ function walk(node, context) {
if (exp = checkAndRemoveAttribute(node, ":value")) {
new ValueDirective({ element: node, context, expression: exp });
}
if (exp = checkAndRemoveAttribute(node, ":show")) {
new ShowDirective({ element: node, context, expression: exp });
}
Array.from(node.attributes).forEach((attr) => {
if (isPropAttribute(attr.name)) {
new AttributeDirective({ element: node, context, attr });
@ -1178,23 +1206,19 @@ function flattenRefs(scope) {
var counter = {
template: html`
<div>
<div :teleport="body">true</div>
<p {style:bind}>Count: {{count}}{{count >= 2 ? '!!!' : ''}}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
<div :teleport="body" :if="style.color === 'gray'">true</div>
<h3 {style:bind}>Count: {{count}}{{count >= 2 ? '!!!' : ''}}</h3>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
`,
main() {
const count = ref(0);
const style = reactive({ color: "red" });
const style = reactive({ color: "gray" });
const increment = () => count.value++;
const decrement = () => count.value--;
setInterval(() => {
if (style.color === "red") {
style.color = "blue";
} else {
style.color = "red";
}
style.color = style.color === "gray" ? "white" : "gray";
}, 500);
return { count, increment, decrement, style };
}

File diff suppressed because one or more lines are too long

View File

@ -53,8 +53,6 @@ export class AttributeDirective {
this.expression = this.extractedAttributeName;
}
console.log("attribute", attr.name, "spread?", this.is.spread)
element.removeAttribute(attr.name);
if (this.is.bound) {

29
src/directives/show.ts Normal file
View File

@ -0,0 +1,29 @@
import { Context, evalGet } from "..";
interface ShowDirectiveOptions {
element: Element;
context: Context;
expression: string;
}
export class ShowDirective {
element: Element;
context: Context;
expression: string;
originalDisplay: string;
constructor({ element, context, expression }: ShowDirectiveOptions) {
this.element = element;
this.context = context;
this.expression = expression;
this.originalDisplay = getComputedStyle(this.element).display;
context.effect(this.update.bind(this));
}
update() {
const shouldShow = Boolean(evalGet(this.context.scope, this.expression));
// @ts-ignore
this.element.style.display = shouldShow ? this.originalDisplay : "none";
}
}

View File

@ -1,4 +1,4 @@
import { Context } from "..";
import { Block, Context } from "..";
import { nextTick } from "../util";
export function _teleport(el: Element, exp: string, ctx: Context) {
@ -13,20 +13,27 @@ export function _teleport(el: Element, exp: string, ctx: Context) {
nextTick(() => {
target.appendChild(el);
});
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.removedNodes.forEach((removedNode) => {
if (removedNode.contains(anchor)) {
el.remove();
observer.disconnect();
}
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
mutation.removedNodes.forEach((removedNode) => {
if (removedNode.contains(anchor)) {
el.remove();
observer.disconnect();
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
// Walks the tree of this teleported element.
new Block({
element: el,
parentContext: ctx,
});
});
observer.observe(document.body, { childList: true, subtree: true });
// Return the anchor so walk continues down the tree in the right order.
return anchor;
}

View File

@ -3,6 +3,7 @@ import { EventDirective } from "./directives/event";
import { _for } from "./directives/for";
import { _if } from "./directives/if";
import { InterpolationDirective } from "./directives/interpolation";
import { ShowDirective } from "./directives/show";
import { _teleport } from "./directives/teleport";
import { ValueDirective } from "./directives/value";
import { Plugin } from "./plugins";
@ -455,6 +456,10 @@ function walk(node: Node, context: Context) {
return _for(node, exp, context, component, componentProps, allProps);
}
if ((exp = checkAndRemoveAttribute(node, ":show"))) {
new ShowDirective({ element: node, context, expression: exp });
}
const templates = findTemplateNodes(node);
const block = new Block({
@ -491,6 +496,10 @@ function walk(node: Node, context: Context) {
new ValueDirective({ element: node, context, expression: exp });
}
if ((exp = checkAndRemoveAttribute(node, ":show"))) {
new ShowDirective({ element: node, context, expression: exp });
}
Array.from(node.attributes).forEach((attr) => {
if (isPropAttribute(attr.name)) {
new AttributeDirective({ element: node, context, attr });
@ -731,24 +740,20 @@ function flattenRefs(scope: any): any {
const counter = {
template: html`
<div>
<div :teleport="body">true</div>
<p {style:bind}>Count: {{count}}{{count >= 2 ? '!!!' : ''}}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
<div :teleport="body" :if="style.color === 'gray'">true</div>
<h3 {style:bind}>Count: {{count}}{{count >= 2 ? '!!!' : ''}}</h3>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
`,
main() {
const count = ref(0);
const style = reactive({ color: "red" });
const style = reactive({ color: "gray" });
const increment = () => count.value++;
const decrement = () => count.value--;
setInterval(() => {
if (style.color === "red") {
style.color = "blue";
} else {
style.color = "red";
}
style.color = style.color === "gray" ? "white" : "gray";
}, 500);
return { count, increment, decrement, style };
@ -757,22 +762,3 @@ const counter = {
const app = new App();
app.mount(counter, "#app");
// ------------------------------------------------
// Vue SFC syntax of the above counter component
// <template>
// <div>
// <p>Count: {{ count }}</p>
// <button @click="increment">Increment</button>
// <button @click="decrement">Decrement</button>
// </div>
// </template>
// <script setup>
// import { ref } from 'vue';
// const count = ref(0);
// const increment = () => count.value++;
// const decrement = () => count.value--;
// </script>