From 9a5fd562d5027a7af487fa4fad259ea642f780b2 Mon Sep 17 00:00:00 2001 From: Andi Rady Kurniawan Date: Mon, 15 Nov 2021 00:08:05 +0800 Subject: [PATCH 1/2] allow to use class directive on (#3105) --- src/compiler/compile/nodes/Body.ts | 4 ++ .../compile/render_dom/wrappers/Body.ts | 45 ++++++++++++++++++- .../samples/class-body-boolean/_config.js | 3 ++ .../samples/class-body-boolean/main.svelte | 1 + .../samples/class-body-shortcut/_config.js | 16 +++++++ .../samples/class-body-shortcut/main.svelte | 7 +++ 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 test/runtime/samples/class-body-boolean/_config.js create mode 100644 test/runtime/samples/class-body-boolean/main.svelte create mode 100644 test/runtime/samples/class-body-shortcut/_config.js create mode 100644 test/runtime/samples/class-body-shortcut/main.svelte diff --git a/src/compiler/compile/nodes/Body.ts b/src/compiler/compile/nodes/Body.ts index fc350ca3cde5..bef958d76134 100644 --- a/src/compiler/compile/nodes/Body.ts +++ b/src/compiler/compile/nodes/Body.ts @@ -1,6 +1,7 @@ import Node from './shared/Node'; import EventHandler from './EventHandler'; import Action from './Action'; +import Class from './Class'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; import { Element } from '../../interfaces'; @@ -9,6 +10,7 @@ export default class Body extends Node { type: 'Body'; handlers: EventHandler[] = []; actions: Action[] = []; + classes: Class[] = []; constructor(component: Component, parent: Node, scope: TemplateScope, info: Element) { super(component, parent, scope, info); @@ -18,6 +20,8 @@ export default class Body extends Node { this.handlers.push(new EventHandler(component, this, scope, node)); } else if (node.type === 'Action') { this.actions.push(new Action(component, this, scope, node)); + } else if (node.type === 'Class') { + this.classes.push(new Class(component, this, scope, node)); } else { // TODO there shouldn't be anything else here... } diff --git a/src/compiler/compile/render_dom/wrappers/Body.ts b/src/compiler/compile/render_dom/wrappers/Body.ts index 0e82fca79f14..c9180fb1b175 100644 --- a/src/compiler/compile/render_dom/wrappers/Body.ts +++ b/src/compiler/compile/render_dom/wrappers/Body.ts @@ -1,25 +1,66 @@ import Block from '../Block'; import Wrapper from './shared/Wrapper'; -import { x } from 'code-red'; +import { b, x } from 'code-red'; import Body from '../../nodes/Body'; -import { Identifier } from 'estree'; +import { Node, Identifier } from 'estree'; import EventHandler from './Element/EventHandler'; import add_event_handlers from './shared/add_event_handlers'; import { TemplateNode } from '../../../interfaces'; import Renderer from '../Renderer'; import add_actions from './shared/add_actions'; +import is_dynamic from './shared/is_dynamic'; export default class BodyWrapper extends Wrapper { node: Body; handlers: EventHandler[]; + class_dependencies: string[]; constructor(renderer: Renderer, block: Block, parent: Wrapper, node: TemplateNode) { super(renderer, block, parent, node); this.handlers = this.node.handlers.map(handler => new EventHandler(handler, this)); + this.class_dependencies = []; + } + + add_classes(block: Block) { + this.node.classes.forEach(class_directive => { + const { expression, name } = class_directive; + let snippet: Node | string; + let dependencies: Set; + if (expression) { + snippet = expression.manipulate(block); + dependencies = expression.dependencies; + } else { + snippet = name; + dependencies = new Set([name]); + } + const updater = b`@toggle_class(@_document.body, "${name}", ${snippet});`; + + block.chunks.hydrate.push(updater); + + if ((dependencies && dependencies.size > -1) || this.class_dependencies.length) { + const all_dependencies = this.class_dependencies.concat(...dependencies); + const condition = block.renderer.dirty(all_dependencies); + + // If all of the dependencies are non-dynamic (don't get updated) then there is no reason + // to add an updater for this. + const any_dynamic_dependencies = all_dependencies.some((dep) => { + const variable = this.renderer.component.var_lookup.get(dep); + return !variable || is_dynamic(variable); + }); + if (any_dynamic_dependencies) { + block.chunks.update.push(b` + if (${condition}) { + ${updater} + } + `); + } + } + }); } render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) { add_event_handlers(block, x`@_document.body`, this.handlers); add_actions(block, x`@_document.body`, this.node.actions); + this.add_classes(block); } } diff --git a/test/runtime/samples/class-body-boolean/_config.js b/test/runtime/samples/class-body-boolean/_config.js new file mode 100644 index 000000000000..8b2a64606240 --- /dev/null +++ b/test/runtime/samples/class-body-boolean/_config.js @@ -0,0 +1,3 @@ +export default { + html: '' +}; \ No newline at end of file diff --git a/test/runtime/samples/class-body-boolean/main.svelte b/test/runtime/samples/class-body-boolean/main.svelte new file mode 100644 index 000000000000..0eab85636cbd --- /dev/null +++ b/test/runtime/samples/class-body-boolean/main.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/runtime/samples/class-body-shortcut/_config.js b/test/runtime/samples/class-body-shortcut/_config.js new file mode 100644 index 000000000000..eec120b5f16c --- /dev/null +++ b/test/runtime/samples/class-body-shortcut/_config.js @@ -0,0 +1,16 @@ +export default { + props: { + foo: true, + bar: true + }, + + html: '', + + test({ assert, component, target }) { + component.foo = false; + + assert.htmlEqual(target.innerHTML, ` + + `); + } +}; diff --git a/test/runtime/samples/class-body-shortcut/main.svelte b/test/runtime/samples/class-body-shortcut/main.svelte new file mode 100644 index 000000000000..694b598cfc65 --- /dev/null +++ b/test/runtime/samples/class-body-shortcut/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file From c6bbad1267579b96fc81eb0cfbc550393e8b08c0 Mon Sep 17 00:00:00 2001 From: Andi Rady Kurniawan Date: Mon, 15 Nov 2021 00:30:35 +0800 Subject: [PATCH 2/2] Fix failing lint --- test/runtime/samples/class-body-boolean/_config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtime/samples/class-body-boolean/_config.js b/test/runtime/samples/class-body-boolean/_config.js index 8b2a64606240..95985996d664 100644 --- a/test/runtime/samples/class-body-boolean/_config.js +++ b/test/runtime/samples/class-body-boolean/_config.js @@ -1,3 +1,3 @@ export default { html: '' -}; \ No newline at end of file +};