From d550c20662866cc321f7c0cb3a654ad3456b1447 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 10:09:42 -0500 Subject: [PATCH 01/36] add Style node, interfaces --- src/compiler/compile/nodes/Style.ts | 22 ++++++++++++++++++++++ src/compiler/compile/nodes/interfaces.ts | 2 ++ src/compiler/interfaces.ts | 2 ++ 3 files changed, 26 insertions(+) create mode 100644 src/compiler/compile/nodes/Style.ts diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts new file mode 100644 index 000000000000..996118679b3b --- /dev/null +++ b/src/compiler/compile/nodes/Style.ts @@ -0,0 +1,22 @@ +import Node from './shared/Node'; +import Expression from './shared/Expression'; +import { TemplateNode } from '../../interfaces'; +import TemplateScope from './shared/TemplateScope'; +import Component from '../Component'; + +// @paul +export default class Style extends Node { + type: 'Style'; + name: string; + expression: Expression; + + constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { + super(component, parent, scope, info); + + this.name = info.name; + + this.expression = info.expression + ? new Expression(component, this, scope, info.expression) + : null; + } +} diff --git a/src/compiler/compile/nodes/interfaces.ts b/src/compiler/compile/nodes/interfaces.ts index a98c21511fb7..2e2fa8b5e05f 100644 --- a/src/compiler/compile/nodes/interfaces.ts +++ b/src/compiler/compile/nodes/interfaces.ts @@ -8,6 +8,7 @@ import Binding from './Binding'; import Body from './Body'; import CatchBlock from './CatchBlock'; import Class from './Class'; +import Style from './Style'; import Comment from './Comment'; import DebugTag from './DebugTag'; import EachBlock from './EachBlock'; @@ -62,6 +63,7 @@ export type INode = Action | Slot | SlotTemplate | DefaultSlotTemplate +| Style | Tag | Text | ThenBlock diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index ce585b5b7822..122c873d029d 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -24,10 +24,12 @@ export interface MustacheTag extends BaseNode { expression: Node; } +// @paul export type DirectiveType = 'Action' | 'Animation' | 'Binding' | 'Class' +| 'Style' | 'EventHandler' | 'Let' | 'Ref' From 6c3718dcf624bb63655c103f076a726e8656a18f Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 14:15:14 -0500 Subject: [PATCH 02/36] style-directives: add parser and runtime test --- .../input.svelte | 1 + .../output.json | 41 +++++++++++++++++++ .../inline-style-directive.solo/_config.js | 12 ++++++ .../inline-style-directive.solo/main.svelte | 5 +++ 4 files changed, 59 insertions(+) create mode 100644 test/parser/samples/attribute-style-directive.solo/input.svelte create mode 100644 test/parser/samples/attribute-style-directive.solo/output.json create mode 100644 test/runtime/samples/inline-style-directive.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive.solo/main.svelte diff --git a/test/parser/samples/attribute-style-directive.solo/input.svelte b/test/parser/samples/attribute-style-directive.solo/input.svelte new file mode 100644 index 000000000000..536d162326c0 --- /dev/null +++ b/test/parser/samples/attribute-style-directive.solo/input.svelte @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/parser/samples/attribute-style-directive.solo/output.json b/test/parser/samples/attribute-style-directive.solo/output.json new file mode 100644 index 000000000000..36906045ce16 --- /dev/null +++ b/test/parser/samples/attribute-style-directive.solo/output.json @@ -0,0 +1,41 @@ +{ + "html": { + "start": 0, + "end": 33, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 33, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 26, + "type": "Style", + "name": "color", + "modifiers": [], + "expression": { + "type": "Identifier", + "start": 18, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 18 + }, + "end": { + "line": 1, + "column": 25 + } + }, + "name": "myColor" + } + } + ], + "children": [] + } + ] + } +} \ No newline at end of file diff --git a/test/runtime/samples/inline-style-directive.solo/_config.js b/test/runtime/samples/inline-style-directive.solo/_config.js new file mode 100644 index 000000000000..cf6626f1b262 --- /dev/null +++ b/test/runtime/samples/inline-style-directive.solo/_config.js @@ -0,0 +1,12 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + } +}; diff --git a/test/runtime/samples/inline-style-directive.solo/main.svelte b/test/runtime/samples/inline-style-directive.solo/main.svelte new file mode 100644 index 000000000000..2360d64351cd --- /dev/null +++ b/test/runtime/samples/inline-style-directive.solo/main.svelte @@ -0,0 +1,5 @@ + + +

\ No newline at end of file From b2a9e67b0f188efd190ed06f9d55418efcac097f Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 14:17:30 -0500 Subject: [PATCH 03/36] style-directives: push styles in to styles array on Element --- src/compiler/compile/nodes/Element.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 66e963d579cd..aea4447eafeb 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -7,6 +7,7 @@ import Transition from './Transition'; import Animation from './Animation'; import Action from './Action'; import Class from './Class'; +import Style from './Style'; import Text from './Text'; import { namespaces } from '../../utils/namespaces'; import map_children from './shared/map_children'; @@ -121,6 +122,7 @@ export default class Element extends Node { actions: Action[] = []; bindings: Binding[] = []; classes: Class[] = []; + styles: Style[] = []; handlers: EventHandler[] = []; lets: Let[] = []; intro?: Transition = null; @@ -203,6 +205,11 @@ export default class Element extends Node { this.classes.push(new Class(component, this, scope, node)); break; + // @paul + case 'Style': + this.styles.push(new Style(component, this, scope, node)); + break; + case 'EventHandler': this.handlers.push(new EventHandler(component, this, scope, node)); break; From 856f1329243d66cd9a6a1fd1d89d375a21deec96 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 14:21:24 -0500 Subject: [PATCH 04/36] style-directives: minimal ssr work --- .../compile/render_ssr/handlers/Element.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 35a15aff6358..6ca78cf96003 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -36,6 +36,15 @@ export default function(node: Element, renderer: Renderer, options: RenderOption class_expression_list.length > 0 && class_expression_list.reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); + const style_expression_list = node.styles.map(style_directive => { + const { name, expression: { node: expression } } = style_directive; + return x`"${name}: " + ${expression} + ";"`; + }); + + const style_expression = + style_expression_list.length > 0 && + style_expression_list.reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); + if (node.attributes.some(attr => attr.is_spread)) { // TODO dry this out const args = []; @@ -68,7 +77,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_expression(x`@spread([${args}], ${class_expression})`); } else { let add_class_attribute = !!class_expression; + let add_style_attribute = !!style_expression; node.attributes.forEach(attribute => { + // console.log("SSR NODE ATTRIBUTE", attribute) const name = attribute.name.toLowerCase(); const attr_name = node.namespace === namespaces.foreign ? attribute.name : fix_attribute_casing(attribute.name); if (name === 'value' && node.name.toLowerCase() === 'textarea') { @@ -88,6 +99,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_string(` ${attr_name}="`); renderer.add_expression(x`[${get_class_attribute_value(attribute)}, ${class_expression}].join(' ').trim()`); renderer.add_string('"'); + } else if (name === 'style' && style_expression) { + add_style_attribute = false; + // TODO } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { const snippet = (attribute.chunks[0] as Expression).node; renderer.add_expression(x`@add_attribute("${attr_name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); @@ -100,6 +114,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption if (add_class_attribute) { renderer.add_expression(x`@add_classes([${class_expression}].join(' ').trim())`); } + if (add_style_attribute) { + renderer.add_expression(x`@add_styles(${style_expression})`); + } } node.bindings.forEach(binding => { From 52a7473e40573ab25958aa4ab3c4754238c4c66b Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 14:23:16 -0500 Subject: [PATCH 05/36] style-directives: ssr add_styles --- src/runtime/internal/ssr.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index c64d88fa7553..73f564d55df9 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -147,3 +147,7 @@ export function add_attribute(name, value, boolean) { export function add_classes(classes) { return classes ? ` class="${classes}"` : ''; } + +export function add_styles(styles) { + return styles ? ` style="${styles}"` : ''; +} From 8f4faf450e8b6eb67ff7cb834f1ebfba6a47e940 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 15:02:24 -0500 Subject: [PATCH 06/36] style-directive: tests --- .../input.svelte | 1 + .../output.json | 41 +++++++++++++++++++ .../samples/attribute-style.solo/input.svelte | 1 + .../samples/attribute-style.solo/output.json | 41 +++++++++++++++++++ .../main.svelte | 5 +++ .../inline-style-directive.solo/main.svelte | 4 +- .../samples/inline-style.solo/_config.js | 12 ++++++ .../samples/inline-style.solo/main.svelte | 1 + 8 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 test/parser/samples/attribute-class-directive.solo/input.svelte create mode 100644 test/parser/samples/attribute-class-directive.solo/output.json create mode 100644 test/parser/samples/attribute-style.solo/input.svelte create mode 100644 test/parser/samples/attribute-style.solo/output.json create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr/main.svelte create mode 100644 test/runtime/samples/inline-style.solo/_config.js create mode 100644 test/runtime/samples/inline-style.solo/main.svelte diff --git a/test/parser/samples/attribute-class-directive.solo/input.svelte b/test/parser/samples/attribute-class-directive.solo/input.svelte new file mode 100644 index 000000000000..629df2e29fce --- /dev/null +++ b/test/parser/samples/attribute-class-directive.solo/input.svelte @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/test/parser/samples/attribute-class-directive.solo/output.json b/test/parser/samples/attribute-class-directive.solo/output.json new file mode 100644 index 000000000000..abb2e0c0becd --- /dev/null +++ b/test/parser/samples/attribute-class-directive.solo/output.json @@ -0,0 +1,41 @@ +{ + "html": { + "start": 0, + "end": 29, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 29, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 22, + "type": "Class", + "name": "foo", + "modifiers": [], + "expression": { + "type": "Identifier", + "start": 16, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "name": "isFoo" + } + } + ], + "children": [] + } + ] + } +} \ No newline at end of file diff --git a/test/parser/samples/attribute-style.solo/input.svelte b/test/parser/samples/attribute-style.solo/input.svelte new file mode 100644 index 000000000000..12872605ad66 --- /dev/null +++ b/test/parser/samples/attribute-style.solo/input.svelte @@ -0,0 +1 @@ +
red
\ No newline at end of file diff --git a/test/parser/samples/attribute-style.solo/output.json b/test/parser/samples/attribute-style.solo/output.json new file mode 100644 index 000000000000..95c0c8a7a460 --- /dev/null +++ b/test/parser/samples/attribute-style.solo/output.json @@ -0,0 +1,41 @@ +{ + "html": { + "start": 0, + "end": 34, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 34, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 24, + "type": "Attribute", + "name": "style", + "value": [ + { + "start": 12, + "end": 23, + "type": "Text", + "raw": "color: red;", + "data": "color: red;" + } + ] + } + ], + "children": [ + { + "start": 25, + "end": 28, + "type": "Text", + "raw": "red", + "data": "red" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte new file mode 100644 index 000000000000..fdcdc9e66e7b --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte @@ -0,0 +1,5 @@ + + +

{color}

diff --git a/test/runtime/samples/inline-style-directive.solo/main.svelte b/test/runtime/samples/inline-style-directive.solo/main.svelte index 2360d64351cd..1d60aefa6fd3 100644 --- a/test/runtime/samples/inline-style-directive.solo/main.svelte +++ b/test/runtime/samples/inline-style-directive.solo/main.svelte @@ -1,5 +1,5 @@ -

\ No newline at end of file +

diff --git a/test/runtime/samples/inline-style.solo/_config.js b/test/runtime/samples/inline-style.solo/_config.js new file mode 100644 index 000000000000..3e984d4c6992 --- /dev/null +++ b/test/runtime/samples/inline-style.solo/_config.js @@ -0,0 +1,12 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('div'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + } +}; diff --git a/test/runtime/samples/inline-style.solo/main.svelte b/test/runtime/samples/inline-style.solo/main.svelte new file mode 100644 index 000000000000..0f37a04c994f --- /dev/null +++ b/test/runtime/samples/inline-style.solo/main.svelte @@ -0,0 +1 @@ +
\ No newline at end of file From a59c8a224d7a411913f2e54251c1a2bbb44ed5f2 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sat, 16 Jan 2021 15:04:41 -0500 Subject: [PATCH 07/36] style-directives: work in progress --- .../render_dom/wrappers/Element/index.ts | 26 +++++++++++++++++++ src/compiler/parse/state/tag.ts | 8 ++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 20dfed891d4d..2d1d362f090b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -340,6 +340,7 @@ export default class ElementWrapper extends Wrapper { this.add_transitions(block); this.add_animation(block); this.add_classes(block); + this.add_styles(block); this.add_manual_style_scoping(block); if (nodes && this.renderer.options.hydratable && !this.void) { @@ -906,6 +907,31 @@ export default class ElementWrapper extends Wrapper { }); } + add_styles(block: Block) { + this.node.styles.forEach(style_directive => { + + // @FIXME: + // Hmm, I thought this would work: + + // const { name, expression: { node: expression } } = style_directive; + // const updater = b`@set_style(${this.var}, "${name}", ${expression}, false)`; + + // But that results in this, and `myColor` is undefined: + + /* + c() { + p$ = element$("p"); + set_style$(p$, "color", myColor, false); + }, + */ + + const { name } = style_directive; + const updater = b`@set_style(${this.var}, "${name}", "red", false)`; + + block.chunks.hydrate.push(updater); + }); + } + add_manual_style_scoping(block) { if (this.node.needs_manual_style_scoping) { const updater = b`@toggle_class(${this.var}, "${this.node.component.stylesheet.id}", true);`; diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index c7def68f6e0e..8095928d3901 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -365,7 +365,10 @@ function read_attribute(parser: Parser, unique_names: Set) { if (value[0]) { if ((value as any[]).length > 1 || value[0].type === 'Text') { - parser.error(parser_errors.invalid_directive_value, value[0].start); + // @FIXME: Is this okay? -@paul + if (type !== 'Style') { + parser.error(parser_errors.invalid_directive_value, value[0].start); + } } } @@ -384,7 +387,7 @@ function read_attribute(parser: Parser, unique_names: Set) { directive.outro = direction === 'out' || direction === 'transition'; } - if (!directive.expression && (type === 'Binding' || type === 'Class')) { + if (!directive.expression && (type === 'Binding' || type === 'Class' || type === 'Style')) { directive.expression = { start: directive.start + colon_index + 1, end: directive.end, @@ -412,6 +415,7 @@ function get_directive_type(name: string): DirectiveType { if (name === 'animate') return 'Animation'; if (name === 'bind') return 'Binding'; if (name === 'class') return 'Class'; + if (name === 'style') return 'Style'; if (name === 'on') return 'EventHandler'; if (name === 'let') return 'Let'; if (name === 'ref') return 'Ref'; From fafca0895021f95310e19b72eff91ba0bb08b3f4 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sun, 24 Jan 2021 10:29:23 -0500 Subject: [PATCH 08/36] obviously incorrect hard-coded color --- .../compile/render_dom/wrappers/Element/index.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 2d1d362f090b..69adaa182307 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -911,20 +911,14 @@ export default class ElementWrapper extends Wrapper { this.node.styles.forEach(style_directive => { // @FIXME: + // I'm not sure how to set the right value expression here // Hmm, I thought this would work: // const { name, expression: { node: expression } } = style_directive; // const updater = b`@set_style(${this.var}, "${name}", ${expression}, false)`; + - // But that results in this, and `myColor` is undefined: - - /* - c() { - p$ = element$("p"); - set_style$(p$, "color", myColor, false); - }, - */ - + // @FIXME: This is obviously wrong, hardcoding the color const { name } = style_directive; const updater = b`@set_style(${this.var}, "${name}", "red", false)`; From bb1255af67b1c66b3e015d03a4b29d8b5be3a79f Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Sun, 24 Jan 2021 10:37:47 -0500 Subject: [PATCH 09/36] tweak --- src/compiler/parse/state/tag.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 8095928d3901..fb959be1d8c0 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -365,7 +365,8 @@ function read_attribute(parser: Parser, unique_names: Set) { if (value[0]) { if ((value as any[]).length > 1 || value[0].type === 'Text') { - // @FIXME: Is this okay? -@paul + // @paul + // @FIXME: Is this okay? if (type !== 'Style') { parser.error(parser_errors.invalid_directive_value, value[0].start); } From 3924a2bf6027f2a7265c9447786bd50bf3c4f587 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:14:13 -0500 Subject: [PATCH 10/36] style directive interface --- src/compiler/interfaces.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index 122c873d029d..a76e5617c93c 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -48,6 +48,11 @@ export interface Transition extends BaseDirective{ outro: boolean; } +export interface StyleDirective extends BaseDirective { + type: 'Style'; + text: string; +} + export type Directive = BaseDirective | Transition; export type TemplateNode = Text From d603b06d6f114ecae7168cc87e08e2d6c3a0438b Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:14:43 -0500 Subject: [PATCH 11/36] style-directives: get text from info in Style node --- src/compiler/compile/nodes/Style.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts index 996118679b3b..5f5a7733456c 100644 --- a/src/compiler/compile/nodes/Style.ts +++ b/src/compiler/compile/nodes/Style.ts @@ -9,12 +9,15 @@ export default class Style extends Node { type: 'Style'; name: string; expression: Expression; + text: string; constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { super(component, parent, scope, info); this.name = info.name; + this.text = info.text || null; + this.expression = info.expression ? new Expression(component, this, scope, info.expression) : null; From 1f8e0b98dd2537058b5fba603c25aaad2440b213 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:15:58 -0500 Subject: [PATCH 12/36] style-directives: add_styles func in ElementWrapper --- .../render_dom/wrappers/Element/index.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 69adaa182307..4119b97dc3d3 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -908,19 +908,19 @@ export default class ElementWrapper extends Wrapper { } add_styles(block: Block) { - this.node.styles.forEach(style_directive => { - - // @FIXME: - // I'm not sure how to set the right value expression here - // Hmm, I thought this would work: - - // const { name, expression: { node: expression } } = style_directive; - // const updater = b`@set_style(${this.var}, "${name}", ${expression}, false)`; - - - // @FIXME: This is obviously wrong, hardcoding the color - const { name } = style_directive; - const updater = b`@set_style(${this.var}, "${name}", "red", false)`; + this.node.styles.forEach((style_directive) => { + const { name, expression, text } = style_directive; + + let snippet; + if (text) { + snippet = `"${text}"`; + } else if (expression) { + snippet = expression.manipulate(block); + } else { + snippet = name; + } + + const updater = b`@set_style(${this.var}, "${name}", ${snippet}, false)`; block.chunks.hydrate.push(updater); }); From a9244a0f536c817fbfb134134fdcc4ae9111ebeb Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:16:27 -0500 Subject: [PATCH 13/36] style-directives: ssr rendering --- src/compiler/compile/render_ssr/handlers/Element.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 6ca78cf96003..07a4bad6b9c8 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -37,7 +37,10 @@ export default function(node: Element, renderer: Renderer, options: RenderOption class_expression_list.reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); const style_expression_list = node.styles.map(style_directive => { - const { name, expression: { node: expression } } = style_directive; + const { name, expression: { node: expression }, text } = style_directive; + if (text) { + return x`"${name}: ${text};"`; + } return x`"${name}: " + ${expression} + ";"`; }); @@ -74,7 +77,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption } }); - renderer.add_expression(x`@spread([${args}], ${class_expression})`); + renderer.add_expression(x`@spread([${args}], { classes: ${class_expression}, styles: ${style_expression} })`); } else { let add_class_attribute = !!class_expression; let add_style_attribute = !!style_expression; @@ -101,7 +104,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_string('"'); } else if (name === 'style' && style_expression) { add_style_attribute = false; - // TODO + renderer.add_string(` ${attribute.name}="`); + renderer.add_expression(x`[${get_attribute_value(attribute)}, ${style_expression}].join(' ').trim()`); + renderer.add_string('"'); } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { const snippet = (attribute.chunks[0] as Expression).node; renderer.add_expression(x`@add_attribute("${attr_name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); From 195eae753e82834467d2dbe52514acd0159f597d Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:16:57 -0500 Subject: [PATCH 14/36] handle text-only style directive in tag.ts --- src/compiler/parse/state/tag.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index fb959be1d8c0..27e9a1754097 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -363,13 +363,19 @@ function read_attribute(parser: Parser, unique_names: Set) { parser.error(parser_errors.invalid_ref_directive(directive_name), start); } - if (value[0]) { - if ((value as any[]).length > 1 || value[0].type === 'Text') { - // @paul - // @FIXME: Is this okay? - if (type !== 'Style') { - parser.error(parser_errors.invalid_directive_value, value[0].start); + const firstValue = value[0]; + let expression = null; + let text = null; + + if (firstValue) { + if ((value as any[]).length > 1 || firstValue.type === 'Text') { + if (type === 'Style') { + text = firstValue.data; + } else { + parser.error(parser_errors.invalid_directive_value, firstValue.start); } + } else { + expression = firstValue.expression || null; } } @@ -379,7 +385,7 @@ function read_attribute(parser: Parser, unique_names: Set) { type, name: directive_name, modifiers, - expression: (value[0] && value[0].expression) || null + expression }; if (type === 'Transition') { @@ -388,6 +394,7 @@ function read_attribute(parser: Parser, unique_names: Set) { directive.outro = direction === 'out' || direction === 'transition'; } + // Directive name is expression, e.g.

if (!directive.expression && (type === 'Binding' || type === 'Class' || type === 'Style')) { directive.expression = { start: directive.start + colon_index + 1, @@ -397,6 +404,10 @@ function read_attribute(parser: Parser, unique_names: Set) { } as any; } + if (type === 'Style' && text) { + directive.text = text; + } + return directive; } From 5a8a473c5dce6f1c94e61995db6b1a752bc52577 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:17:16 -0500 Subject: [PATCH 15/36] style-directives: handle spread styles in ssr --- src/runtime/internal/ssr.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index 73f564d55df9..936cb57c30f8 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -6,15 +6,26 @@ export const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFF // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 // https://infra.spec.whatwg.org/#noncharacter -export function spread(args, classes_to_add) { +export function spread(args, add) { const attributes = Object.assign({}, ...args); - if (classes_to_add) { - if (attributes.class == null) { - attributes.class = classes_to_add; - } else { - attributes.class += ' ' + classes_to_add; + if (add) { + if (add.classes) { + if (attributes.class == null) { + attributes.class = add.classes; + } else { + attributes.class += ' ' + add.classes; + } + } + + if (add.styles) { + if (attributes.style == null) { + attributes.style = add.styles; + } else { + attributes.style += '; ' + add.styles; + } } } + let str = ''; Object.keys(attributes).forEach(name => { From e5a6e4e3053fce5b89a1fe314cb98184df1a4e41 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:17:50 -0500 Subject: [PATCH 16/36] style-directives: more parser tests --- .../input.svelte | 1 + .../output.json | 31 ++++++++++++++++++ .../input.svelte | 1 + .../output.json | 32 +++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte create mode 100644 test/parser/samples/attribute-style-directive-shorthand.solo/output.json create mode 100644 test/parser/samples/attribute-style-directive-string.solo/input.svelte create mode 100644 test/parser/samples/attribute-style-directive-string.solo/output.json diff --git a/test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte b/test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte new file mode 100644 index 000000000000..3e2c66f21808 --- /dev/null +++ b/test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte @@ -0,0 +1 @@ +

\ No newline at end of file diff --git a/test/parser/samples/attribute-style-directive-shorthand.solo/output.json b/test/parser/samples/attribute-style-directive-shorthand.solo/output.json new file mode 100644 index 000000000000..d4e81b6e4be2 --- /dev/null +++ b/test/parser/samples/attribute-style-directive-shorthand.solo/output.json @@ -0,0 +1,31 @@ +{ + "html": { + "start": 0, + "end": 23, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 23, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 16, + "type": "Style", + "name": "color", + "modifiers": [], + "expression": { + "start": 11, + "end": 16, + "name": "color", + "type": "Identifier" + } + } + ], + "children": [] + } + ] + } +} diff --git a/test/parser/samples/attribute-style-directive-string.solo/input.svelte b/test/parser/samples/attribute-style-directive-string.solo/input.svelte new file mode 100644 index 000000000000..b2eb6bfef8ce --- /dev/null +++ b/test/parser/samples/attribute-style-directive-string.solo/input.svelte @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/parser/samples/attribute-style-directive-string.solo/output.json b/test/parser/samples/attribute-style-directive-string.solo/output.json new file mode 100644 index 000000000000..2e5e678e9360 --- /dev/null +++ b/test/parser/samples/attribute-style-directive-string.solo/output.json @@ -0,0 +1,32 @@ +{ + "html": { + "start": 0, + "end": 29, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 29, + "type": "Element", + "name": "div", + "attributes": [ + { + "start": 5, + "end": 22, + "type": "Style", + "name": "color", + "modifiers": [], + "expression": { + "end": 22, + "name": "color", + "start": 11, + "type": "Identifier" + }, + "text": "red" + } + ], + "children": [] + } + ] + } +} From 94e41374811624017dcfd7117cbc8ebb150b14f4 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:18:13 -0500 Subject: [PATCH 17/36] style-directives: more inline tests --- .../_config.js | 13 +++++++++++++ .../main.svelte | 5 +++++ .../main.svelte | 5 ----- .../_config.js | 12 ++++++++++++ .../main.svelte | 5 +++++ .../inline-style-directive-spread.solo/_config.js | 14 ++++++++++++++ .../inline-style-directive-spread.solo/main.svelte | 1 + .../inline-style-directive-string.solo/_config.js | 12 ++++++++++++ .../inline-style-directive-string.solo/main.svelte | 1 + 9 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte delete mode 100644 test/runtime/samples/inline-style-directive-and-style-attr/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-shorthand.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-spread.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive-spread.solo/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-string.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive-string.solo/main.svelte diff --git a/test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js new file mode 100644 index 000000000000..93d6187fec5a --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js @@ -0,0 +1,13 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + assert.equal(styles.height, '40px'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte new file mode 100644 index 000000000000..e2ba0fa591cb --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte @@ -0,0 +1,5 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte deleted file mode 100644 index fdcdc9e66e7b..000000000000 --- a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - -

{color}

diff --git a/test/runtime/samples/inline-style-directive-shorthand.solo/_config.js b/test/runtime/samples/inline-style-directive-shorthand.solo/_config.js new file mode 100644 index 000000000000..cf6626f1b262 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-shorthand.solo/_config.js @@ -0,0 +1,12 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte b/test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte new file mode 100644 index 000000000000..65bbff910b91 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte @@ -0,0 +1,5 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-spread.solo/_config.js b/test/runtime/samples/inline-style-directive-spread.solo/_config.js new file mode 100644 index 000000000000..8193c74c4e3a --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread.solo/_config.js @@ -0,0 +1,14 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'blue'); + assert.equal(styles.width, '65px'); + assert.equal(p.id, 'my-id'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-spread.solo/main.svelte b/test/runtime/samples/inline-style-directive-spread.solo/main.svelte new file mode 100644 index 000000000000..51291146c79a --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread.solo/main.svelte @@ -0,0 +1 @@ +

diff --git a/test/runtime/samples/inline-style-directive-string.solo/_config.js b/test/runtime/samples/inline-style-directive-string.solo/_config.js new file mode 100644 index 000000000000..cf6626f1b262 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-string.solo/_config.js @@ -0,0 +1,12 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-string.solo/main.svelte b/test/runtime/samples/inline-style-directive-string.solo/main.svelte new file mode 100644 index 000000000000..4e7ce22b2266 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-string.solo/main.svelte @@ -0,0 +1 @@ +

From 4273e42692a07b1e62992e31e8da7b4d60de4c19 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:22:27 -0500 Subject: [PATCH 18/36] style-directives: remove solo tests --- .../input.svelte | 0 .../output.json | 0 .../input.svelte | 0 .../output.json | 0 .../input.svelte | 0 .../output.json | 0 .../input.svelte | 0 .../output.json | 0 .../{attribute-style.solo => attribute-style}/input.svelte | 0 .../samples/{attribute-style.solo => attribute-style}/output.json | 0 .../_config.js | 0 .../main.svelte | 0 .../_config.js | 0 .../main.svelte | 0 .../_config.js | 0 .../main.svelte | 0 .../_config.js | 0 .../main.svelte | 0 .../_config.js | 0 .../main.svelte | 0 .../samples/{inline-style.solo => inline-style}/_config.js | 0 .../samples/{inline-style.solo => inline-style}/main.svelte | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename test/parser/samples/{attribute-class-directive.solo => attribute-class-directive}/input.svelte (100%) rename test/parser/samples/{attribute-class-directive.solo => attribute-class-directive}/output.json (100%) rename test/parser/samples/{attribute-style-directive-shorthand.solo => attribute-style-directive-shorthand}/input.svelte (100%) rename test/parser/samples/{attribute-style-directive-shorthand.solo => attribute-style-directive-shorthand}/output.json (100%) rename test/parser/samples/{attribute-style-directive-string.solo => attribute-style-directive-string}/input.svelte (100%) rename test/parser/samples/{attribute-style-directive-string.solo => attribute-style-directive-string}/output.json (100%) rename test/parser/samples/{attribute-style-directive.solo => attribute-style-directive}/input.svelte (100%) rename test/parser/samples/{attribute-style-directive.solo => attribute-style-directive}/output.json (100%) rename test/parser/samples/{attribute-style.solo => attribute-style}/input.svelte (100%) rename test/parser/samples/{attribute-style.solo => attribute-style}/output.json (100%) rename test/runtime/samples/{inline-style-directive-and-style-attr.solo => inline-style-directive-and-style-attr}/_config.js (100%) rename test/runtime/samples/{inline-style-directive-and-style-attr.solo => inline-style-directive-and-style-attr}/main.svelte (100%) rename test/runtime/samples/{inline-style-directive-shorthand.solo => inline-style-directive-shorthand}/_config.js (100%) rename test/runtime/samples/{inline-style-directive-shorthand.solo => inline-style-directive-shorthand}/main.svelte (100%) rename test/runtime/samples/{inline-style-directive-spread.solo => inline-style-directive-spread}/_config.js (100%) rename test/runtime/samples/{inline-style-directive-spread.solo => inline-style-directive-spread}/main.svelte (100%) rename test/runtime/samples/{inline-style-directive-string.solo => inline-style-directive-string}/_config.js (100%) rename test/runtime/samples/{inline-style-directive-string.solo => inline-style-directive-string}/main.svelte (100%) rename test/runtime/samples/{inline-style-directive.solo => inline-style-directive}/_config.js (100%) rename test/runtime/samples/{inline-style-directive.solo => inline-style-directive}/main.svelte (100%) rename test/runtime/samples/{inline-style.solo => inline-style}/_config.js (100%) rename test/runtime/samples/{inline-style.solo => inline-style}/main.svelte (100%) diff --git a/test/parser/samples/attribute-class-directive.solo/input.svelte b/test/parser/samples/attribute-class-directive/input.svelte similarity index 100% rename from test/parser/samples/attribute-class-directive.solo/input.svelte rename to test/parser/samples/attribute-class-directive/input.svelte diff --git a/test/parser/samples/attribute-class-directive.solo/output.json b/test/parser/samples/attribute-class-directive/output.json similarity index 100% rename from test/parser/samples/attribute-class-directive.solo/output.json rename to test/parser/samples/attribute-class-directive/output.json diff --git a/test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte b/test/parser/samples/attribute-style-directive-shorthand/input.svelte similarity index 100% rename from test/parser/samples/attribute-style-directive-shorthand.solo/input.svelte rename to test/parser/samples/attribute-style-directive-shorthand/input.svelte diff --git a/test/parser/samples/attribute-style-directive-shorthand.solo/output.json b/test/parser/samples/attribute-style-directive-shorthand/output.json similarity index 100% rename from test/parser/samples/attribute-style-directive-shorthand.solo/output.json rename to test/parser/samples/attribute-style-directive-shorthand/output.json diff --git a/test/parser/samples/attribute-style-directive-string.solo/input.svelte b/test/parser/samples/attribute-style-directive-string/input.svelte similarity index 100% rename from test/parser/samples/attribute-style-directive-string.solo/input.svelte rename to test/parser/samples/attribute-style-directive-string/input.svelte diff --git a/test/parser/samples/attribute-style-directive-string.solo/output.json b/test/parser/samples/attribute-style-directive-string/output.json similarity index 100% rename from test/parser/samples/attribute-style-directive-string.solo/output.json rename to test/parser/samples/attribute-style-directive-string/output.json diff --git a/test/parser/samples/attribute-style-directive.solo/input.svelte b/test/parser/samples/attribute-style-directive/input.svelte similarity index 100% rename from test/parser/samples/attribute-style-directive.solo/input.svelte rename to test/parser/samples/attribute-style-directive/input.svelte diff --git a/test/parser/samples/attribute-style-directive.solo/output.json b/test/parser/samples/attribute-style-directive/output.json similarity index 100% rename from test/parser/samples/attribute-style-directive.solo/output.json rename to test/parser/samples/attribute-style-directive/output.json diff --git a/test/parser/samples/attribute-style.solo/input.svelte b/test/parser/samples/attribute-style/input.svelte similarity index 100% rename from test/parser/samples/attribute-style.solo/input.svelte rename to test/parser/samples/attribute-style/input.svelte diff --git a/test/parser/samples/attribute-style.solo/output.json b/test/parser/samples/attribute-style/output.json similarity index 100% rename from test/parser/samples/attribute-style.solo/output.json rename to test/parser/samples/attribute-style/output.json diff --git a/test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive-and-style-attr.solo/_config.js rename to test/runtime/samples/inline-style-directive-and-style-attr/_config.js diff --git a/test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive-and-style-attr.solo/main.svelte rename to test/runtime/samples/inline-style-directive-and-style-attr/main.svelte diff --git a/test/runtime/samples/inline-style-directive-shorthand.solo/_config.js b/test/runtime/samples/inline-style-directive-shorthand/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive-shorthand.solo/_config.js rename to test/runtime/samples/inline-style-directive-shorthand/_config.js diff --git a/test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte b/test/runtime/samples/inline-style-directive-shorthand/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive-shorthand.solo/main.svelte rename to test/runtime/samples/inline-style-directive-shorthand/main.svelte diff --git a/test/runtime/samples/inline-style-directive-spread.solo/_config.js b/test/runtime/samples/inline-style-directive-spread/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive-spread.solo/_config.js rename to test/runtime/samples/inline-style-directive-spread/_config.js diff --git a/test/runtime/samples/inline-style-directive-spread.solo/main.svelte b/test/runtime/samples/inline-style-directive-spread/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive-spread.solo/main.svelte rename to test/runtime/samples/inline-style-directive-spread/main.svelte diff --git a/test/runtime/samples/inline-style-directive-string.solo/_config.js b/test/runtime/samples/inline-style-directive-string/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive-string.solo/_config.js rename to test/runtime/samples/inline-style-directive-string/_config.js diff --git a/test/runtime/samples/inline-style-directive-string.solo/main.svelte b/test/runtime/samples/inline-style-directive-string/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive-string.solo/main.svelte rename to test/runtime/samples/inline-style-directive-string/main.svelte diff --git a/test/runtime/samples/inline-style-directive.solo/_config.js b/test/runtime/samples/inline-style-directive/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive.solo/_config.js rename to test/runtime/samples/inline-style-directive/_config.js diff --git a/test/runtime/samples/inline-style-directive.solo/main.svelte b/test/runtime/samples/inline-style-directive/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive.solo/main.svelte rename to test/runtime/samples/inline-style-directive/main.svelte diff --git a/test/runtime/samples/inline-style.solo/_config.js b/test/runtime/samples/inline-style/_config.js similarity index 100% rename from test/runtime/samples/inline-style.solo/_config.js rename to test/runtime/samples/inline-style/_config.js diff --git a/test/runtime/samples/inline-style.solo/main.svelte b/test/runtime/samples/inline-style/main.svelte similarity index 100% rename from test/runtime/samples/inline-style.solo/main.svelte rename to test/runtime/samples/inline-style/main.svelte From eb3d735154fcd60de13552e61f1edc945deaf93c Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:24:49 -0500 Subject: [PATCH 19/36] style-directives: cleanup --- src/compiler/compile/nodes/Element.ts | 1 - src/compiler/compile/nodes/Style.ts | 1 - src/compiler/interfaces.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index aea4447eafeb..675cbb16e7db 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -205,7 +205,6 @@ export default class Element extends Node { this.classes.push(new Class(component, this, scope, node)); break; - // @paul case 'Style': this.styles.push(new Style(component, this, scope, node)); break; diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts index 5f5a7733456c..2868d7a07e29 100644 --- a/src/compiler/compile/nodes/Style.ts +++ b/src/compiler/compile/nodes/Style.ts @@ -4,7 +4,6 @@ import { TemplateNode } from '../../interfaces'; import TemplateScope from './shared/TemplateScope'; import Component from '../Component'; -// @paul export default class Style extends Node { type: 'Style'; name: string; diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index a76e5617c93c..0cc21be292ce 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -24,7 +24,6 @@ export interface MustacheTag extends BaseNode { expression: Node; } -// @paul export type DirectiveType = 'Action' | 'Animation' | 'Binding' From 69e566a746d0897c0240710c9e20161552db0b57 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:33:44 -0500 Subject: [PATCH 20/36] style-directives: tweak spread ssr internal --- src/runtime/internal/ssr.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index 936cb57c30f8..7004289c2f24 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -6,22 +6,25 @@ export const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFF // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 // https://infra.spec.whatwg.org/#noncharacter -export function spread(args, add) { +export function spread(args, attrs_to_add) { const attributes = Object.assign({}, ...args); - if (add) { - if (add.classes) { + if (attrs_to_add) { + const classes_to_add = attrs_to_add.classes; + const styles_to_add = attrs_to_add.styles; + + if (classes_to_add) { if (attributes.class == null) { - attributes.class = add.classes; + attributes.class = classes_to_add; } else { - attributes.class += ' ' + add.classes; + attributes.class += ' ' + classes_to_add; } } - if (add.styles) { + if (styles_to_add) { if (attributes.style == null) { - attributes.style = add.styles; + attributes.style = styles_to_add; } else { - attributes.style += '; ' + add.styles; + attributes.style += '; ' + styles_to_add; } } } From e8a8f6399a2e075af4c8929a8f7bdb8e6fd4cc68 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:44:27 -0500 Subject: [PATCH 21/36] style-directives: push updater into update chunks; add dynamic test; --- .../compile/render_dom/wrappers/Element/index.ts | 1 + .../inline-style-directive-dynamic.solo/_config.js | 12 ++++++++++++ .../inline-style-directive-dynamic.solo/main.svelte | 5 +++++ 3 files changed, 18 insertions(+) create mode 100644 test/runtime/samples/inline-style-directive-dynamic.solo/_config.js create mode 100644 test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 4119b97dc3d3..1ab4cbfe3183 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -923,6 +923,7 @@ export default class ElementWrapper extends Wrapper { const updater = b`@set_style(${this.var}, "${name}", ${snippet}, false)`; block.chunks.hydrate.push(updater); + block.chunks.update.push(updater); }); } diff --git a/test/runtime/samples/inline-style-directive-dynamic.solo/_config.js b/test/runtime/samples/inline-style-directive-dynamic.solo/_config.js new file mode 100644 index 000000000000..a3d37fa6f70b --- /dev/null +++ b/test/runtime/samples/inline-style-directive-dynamic.solo/_config.js @@ -0,0 +1,12 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target }) { + component.myColor = 'blue'; + assert.htmlEqual(target.innerHTML, ` +

+ `); + } +}; diff --git a/test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte b/test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte new file mode 100644 index 000000000000..1d60aefa6fd3 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte @@ -0,0 +1,5 @@ + + +

From 0da09fe80163c89ba2756c7500ac2eee713e612d Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:45:26 -0500 Subject: [PATCH 22/36] remove .solo --- .../_config.js | 0 .../main.svelte | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test/runtime/samples/{inline-style-directive-dynamic.solo => inline-style-directive-dynamic}/_config.js (100%) rename test/runtime/samples/{inline-style-directive-dynamic.solo => inline-style-directive-dynamic}/main.svelte (100%) diff --git a/test/runtime/samples/inline-style-directive-dynamic.solo/_config.js b/test/runtime/samples/inline-style-directive-dynamic/_config.js similarity index 100% rename from test/runtime/samples/inline-style-directive-dynamic.solo/_config.js rename to test/runtime/samples/inline-style-directive-dynamic/_config.js diff --git a/test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte b/test/runtime/samples/inline-style-directive-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/inline-style-directive-dynamic.solo/main.svelte rename to test/runtime/samples/inline-style-directive-dynamic/main.svelte From 3c1591cace2e882adc7d957ae4e3c498b5191b08 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 20:48:40 -0500 Subject: [PATCH 23/36] check for dynamic dependencies before adding update chunk --- src/compiler/compile/render_dom/wrappers/Element/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 1ab4cbfe3183..95fa5764d190 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -923,7 +923,10 @@ export default class ElementWrapper extends Wrapper { const updater = b`@set_style(${this.var}, "${name}", ${snippet}, false)`; block.chunks.hydrate.push(updater); - block.chunks.update.push(updater); + + if (expression && expression.dynamic_dependencies().length) { + block.chunks.update.push(updater); + } }); } From 4969b6c6a4cbf4fab135aff5e12132201079250d Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 21:37:50 -0500 Subject: [PATCH 24/36] add test of multiple styles; remove null styles; --- src/runtime/internal/dom.ts | 6 +++++- .../inline-style-directive-multiple/_config.js | 16 ++++++++++++++++ .../inline-style-directive-multiple/main.svelte | 13 +++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/runtime/samples/inline-style-directive-multiple/_config.js create mode 100644 test/runtime/samples/inline-style-directive-multiple/main.svelte diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index a055bee4460a..cacd5e4beaa3 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -430,7 +430,11 @@ export function set_input_type(input, type) { } export function set_style(node, key, value, important) { - node.style.setProperty(key, value, important ? 'important' : ''); + if (value === null) { + node.style.removeProperty(key); + } else { + node.style.setProperty(key, value, important ? 'important' : ''); + } } export function select_option(select, value) { diff --git a/test/runtime/samples/inline-style-directive-multiple/_config.js b/test/runtime/samples/inline-style-directive-multiple/_config.js new file mode 100644 index 000000000000..2aa46ba60947 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-multiple/_config.js @@ -0,0 +1,16 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + }, + + skip_if_ssr: true + // SSR renders "null" string for null values: + //

+}; diff --git a/test/runtime/samples/inline-style-directive-multiple/main.svelte b/test/runtime/samples/inline-style-directive-multiple/main.svelte new file mode 100644 index 000000000000..06f03206d54d --- /dev/null +++ b/test/runtime/samples/inline-style-directive-multiple/main.svelte @@ -0,0 +1,13 @@ + + +

From 7a44cd44d567c6fbb7565baddb7068dd73542d8d Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 21:57:53 -0500 Subject: [PATCH 25/36] style-directives: docs; more tests of multiple styles --- site/content/docs/02-template-syntax.md | 40 +++++++++++++++++++ .../_config.js | 13 ++++++ .../main.svelte | 5 +++ .../_config.js | 4 +- .../main.svelte | 2 +- 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index ca0c1d4993da..d89831e55e44 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -791,6 +791,46 @@ A `class:` directive provides a shorter way of toggling a class on an element.

...
``` +#### style:*property* + +```sv +style:property={value} +``` +```sv +style:property="value" +``` +```sv +style:property +``` + +--- + +The `style:` directive provides a shorthand for setting multiple styles on an element. + +```sv + +
...
+
...
+ + +
...
+ + +
...
+ + +
...
+``` + +--- + +When `style:` directives are combined with `style` attributes, the directives will take precedence: + +```sv +
This will be red
+``` + + #### use:*action* diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js new file mode 100644 index 000000000000..93d6187fec5a --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js @@ -0,0 +1,13 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'red'); + assert.equal(styles.height, '40px'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte new file mode 100644 index 000000000000..e2ba0fa591cb --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte @@ -0,0 +1,5 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js index 93d6187fec5a..36c46d12de4c 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js @@ -9,5 +9,7 @@ export default { const styles = window.getComputedStyle(p); assert.equal(styles.color, 'red'); assert.equal(styles.height, '40px'); - } + }, + + skip_if_ssr: true }; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte index e2ba0fa591cb..6f3e86b9bfed 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte +++ b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte @@ -2,4 +2,4 @@ export let color = 'red'; -

+

From 34f7250acc57335726aa3ff205a7faf8d2d2e3be Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 22:27:36 -0500 Subject: [PATCH 26/36] style-directives: use camelcase --- src/compiler/parse/state/tag.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 27e9a1754097..2749cb6d7ac2 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -363,19 +363,19 @@ function read_attribute(parser: Parser, unique_names: Set) { parser.error(parser_errors.invalid_ref_directive(directive_name), start); } - const firstValue = value[0]; + const first_value = value[0]; let expression = null; let text = null; - if (firstValue) { - if ((value as any[]).length > 1 || firstValue.type === 'Text') { + if (first_value) { + if ((value as any[]).length > 1 || first_value.type === 'Text') { if (type === 'Style') { - text = firstValue.data; + text = first_value.data; } else { - parser.error(parser_errors.invalid_directive_value, firstValue.start); + parser.error(parser_errors.invalid_directive_value, first_value.start); } } else { - expression = firstValue.expression || null; + expression = first_value.expression || null; } } From fcfa80ca19c5839f59aae1f9133f64c698f1d198 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Tue, 26 Jan 2021 22:29:52 -0500 Subject: [PATCH 27/36] style-directives: cleanup --- src/compiler/compile/render_ssr/handlers/Element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index 07a4bad6b9c8..ec9804f078df 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -82,7 +82,6 @@ export default function(node: Element, renderer: Renderer, options: RenderOption let add_class_attribute = !!class_expression; let add_style_attribute = !!style_expression; node.attributes.forEach(attribute => { - // console.log("SSR NODE ATTRIBUTE", attribute) const name = attribute.name.toLowerCase(); const attr_name = node.namespace === namespaces.foreign ? attribute.name : fix_attribute_casing(attribute.name); if (name === 'value' && node.name.toLowerCase() === 'textarea') { From 8f33ac9723732d4971eeb74a2b8ed1916bb786c9 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Mon, 15 Feb 2021 13:50:36 -0500 Subject: [PATCH 28/36] style-directives: fix mustache template case with template literal --- src/compiler/compile/nodes/Style.ts | 3 -- .../render_dom/wrappers/Element/index.ts | 6 ++-- .../compile/render_ssr/handlers/Element.ts | 5 +-- src/compiler/parse/state/tag.ts | 34 +++++++++++++++---- .../output.json | 21 ++++++++---- .../_config.js | 13 +++++++ .../main.svelte | 5 +++ 7 files changed, 62 insertions(+), 25 deletions(-) create mode 100644 test/runtime/samples/inline-style-directive-string-variable/_config.js create mode 100644 test/runtime/samples/inline-style-directive-string-variable/main.svelte diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts index 2868d7a07e29..6f794c1357ae 100644 --- a/src/compiler/compile/nodes/Style.ts +++ b/src/compiler/compile/nodes/Style.ts @@ -8,15 +8,12 @@ export default class Style extends Node { type: 'Style'; name: string; expression: Expression; - text: string; constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { super(component, parent, scope, info); this.name = info.name; - this.text = info.text || null; - this.expression = info.expression ? new Expression(component, this, scope, info.expression) : null; diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 95fa5764d190..fceb0c3c34eb 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -909,12 +909,10 @@ export default class ElementWrapper extends Wrapper { add_styles(block: Block) { this.node.styles.forEach((style_directive) => { - const { name, expression, text } = style_directive; + const { name, expression } = style_directive; let snippet; - if (text) { - snippet = `"${text}"`; - } else if (expression) { + if (expression) { snippet = expression.manipulate(block); } else { snippet = name; diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index ec9804f078df..c2290c3f38a0 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -37,10 +37,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption class_expression_list.reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); const style_expression_list = node.styles.map(style_directive => { - const { name, expression: { node: expression }, text } = style_directive; - if (text) { - return x`"${name}: ${text};"`; - } + const { name, expression: { node: expression } } = style_directive; return x`"${name}: " + ${expression} + ";"`; }); diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 2749cb6d7ac2..4c35cfb9446f 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -1,3 +1,4 @@ +import { TemplateLiteral } from 'estree'; import read_expression from '../read/expression'; import read_script from '../read/script'; import read_style from '../read/style'; @@ -268,6 +269,29 @@ function read_tag_name(parser: Parser) { return name; } +function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { + + const literal: TemplateLiteral = { + type: "TemplateLiteral", + expressions: [], + quasis: [] + }; + + value.forEach((node) => { + if (node.type === "Text") { + literal.quasis.push({ + type: 'TemplateElement', + value: { raw: node.raw, cooked: null }, + tail: false + }); + } else if (node.type === "MustacheTag") { + literal.expressions.push(node.expression); + } + }); + + return literal; +} + function read_attribute(parser: Parser, unique_names: Set) { const start = parser.index; @@ -365,12 +389,11 @@ function read_attribute(parser: Parser, unique_names: Set) { const first_value = value[0]; let expression = null; - let text = null; if (first_value) { if ((value as any[]).length > 1 || first_value.type === 'Text') { if (type === 'Style') { - text = first_value.data; + expression = node_to_template_literal(value as TemplateNode[]); } else { parser.error(parser_errors.invalid_directive_value, first_value.start); } @@ -404,9 +427,6 @@ function read_attribute(parser: Parser, unique_names: Set) { } as any; } - if (type === 'Style' && text) { - directive.text = text; - } return directive; } @@ -458,6 +478,8 @@ function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] { data: null }; + const chunks: TemplateNode[] = []; + function flush() { if (current_chunk.raw) { current_chunk.data = decode_character_references(current_chunk.raw); @@ -466,8 +488,6 @@ function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] { } } - const chunks: TemplateNode[] = []; - while (parser.index < parser.template.length) { const index = parser.index; diff --git a/test/parser/samples/attribute-style-directive-string/output.json b/test/parser/samples/attribute-style-directive-string/output.json index 2e5e678e9360..aeb258a1c271 100644 --- a/test/parser/samples/attribute-style-directive-string/output.json +++ b/test/parser/samples/attribute-style-directive-string/output.json @@ -17,16 +17,23 @@ "name": "color", "modifiers": [], "expression": { - "end": 22, - "name": "color", - "start": 11, - "type": "Identifier" - }, - "text": "red" + "type": "TemplateLiteral", + "expressions": [], + "quasis": [ + { + "type": "TemplateElement", + "value": { + "raw": "red", + "cooked": null + }, + "tail": false + } + ] + } } ], "children": [] } ] } -} +} \ No newline at end of file diff --git a/test/runtime/samples/inline-style-directive-string-variable/_config.js b/test/runtime/samples/inline-style-directive-string-variable/_config.js new file mode 100644 index 000000000000..1d9e7404e5c6 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-string-variable/_config.js @@ -0,0 +1,13 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'green'); + assert.equal(styles.transform, 'translateX(45px)'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-string-variable/main.svelte b/test/runtime/samples/inline-style-directive-string-variable/main.svelte new file mode 100644 index 000000000000..eaf48da1a3b7 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-string-variable/main.svelte @@ -0,0 +1,5 @@ + + +

From 88f63a572e45c7ce34b468826c16036ab83d77e2 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Mon, 15 Feb 2021 13:54:28 -0500 Subject: [PATCH 29/36] style-directives: use ternary --- src/compiler/compile/render_dom/wrappers/Element/index.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index fceb0c3c34eb..630937b6e986 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -911,12 +911,7 @@ export default class ElementWrapper extends Wrapper { this.node.styles.forEach((style_directive) => { const { name, expression } = style_directive; - let snippet; - if (expression) { - snippet = expression.manipulate(block); - } else { - snippet = name; - } + const snippet = expression ? expression.manipulate(block) : name; const updater = b`@set_style(${this.var}, "${name}", ${snippet}, false)`; From 8b803ca022999fb386f0c6b0e6d8c66278d3179b Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Mon, 15 Feb 2021 14:01:33 -0500 Subject: [PATCH 30/36] style-directives: linting --- src/compiler/parse/state/tag.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 4c35cfb9446f..babd3efd2da7 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -272,19 +272,19 @@ function read_tag_name(parser: Parser) { function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { const literal: TemplateLiteral = { - type: "TemplateLiteral", + type: 'TemplateLiteral', expressions: [], quasis: [] }; value.forEach((node) => { - if (node.type === "Text") { + if (node.type === 'Text') { literal.quasis.push({ type: 'TemplateElement', value: { raw: node.raw, cooked: null }, tail: false }); - } else if (node.type === "MustacheTag") { + } else if (node.type === 'MustacheTag') { literal.expressions.push(node.expression); } }); @@ -427,7 +427,6 @@ function read_attribute(parser: Parser, unique_names: Set) { } as any; } - return directive; } From 81c560ee16de0ae6c19323988c0760d2aa0e5167 Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Mon, 15 Feb 2021 14:12:49 -0500 Subject: [PATCH 31/36] style-directives: remove "text" from interface --- src/compiler/interfaces.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index 0cc21be292ce..12dc1bca89f3 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -49,7 +49,6 @@ export interface Transition extends BaseDirective{ export interface StyleDirective extends BaseDirective { type: 'Style'; - text: string; } export type Directive = BaseDirective | Transition; From 77e6aea8e466074614172f5a3e07c95e161e928d Mon Sep 17 00:00:00 2001 From: pmurray73 Date: Mon, 15 Feb 2021 14:14:57 -0500 Subject: [PATCH 32/36] style-directives: actually, remove StyleDirective interface entriely --- src/compiler/interfaces.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index 12dc1bca89f3..026a4fc128ff 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -41,16 +41,12 @@ interface BaseDirective extends BaseNode { modifiers: string[]; } -export interface Transition extends BaseDirective{ +export interface Transition extends BaseDirective { type: 'Transition'; intro: boolean; outro: boolean; } -export interface StyleDirective extends BaseDirective { - type: 'Style'; -} - export type Directive = BaseDirective | Transition; export type TemplateNode = Text From 36e49d82a89d2aee46c2ba257f02bcfb197c309c Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 12 Jul 2021 15:05:28 +0800 Subject: [PATCH 33/36] add more test, fix test for ssr --- src/compiler/compile/nodes/Style.ts | 7 ++-- .../render_dom/wrappers/Element/index.ts | 29 ++++++++++++-- .../compile/render_ssr/handlers/Element.ts | 16 ++++---- src/compiler/parse/state/tag.ts | 23 +++++++---- src/runtime/internal/ssr.ts | 39 +++++++++++++++++-- .../output.json | 2 +- .../_config.js | 2 +- .../main.svelte | 5 +++ .../main.svelte | 5 --- .../_config.js | 4 +- .../main.svelte | 2 +- .../_config.js | 20 +++++++--- .../_config.js | 8 +++- .../_config.js | 5 +++ .../main.svelte | 11 ++++++ .../_config.js | 37 ++++++++++++++++++ .../main.svelte | 11 ++++++ .../_config.js | 38 ++++++++++++++++++ .../main.svelte | 5 +++ .../_config.js | 11 +++++- .../main.svelte | 4 +- 21 files changed, 236 insertions(+), 48 deletions(-) rename test/runtime/samples/{inline-style-directive-and-style-attr-ssr => inline-style-directive-and-style-attr-merged}/_config.js (98%) create mode 100644 test/runtime/samples/inline-style-directive-and-style-attr-merged/main.svelte delete mode 100644 test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js create mode 100644 test/runtime/samples/inline-style-directive-spread-and-attr-empty/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-spread-and-attr/_config.js create mode 100644 test/runtime/samples/inline-style-directive-spread-and-attr/main.svelte create mode 100644 test/runtime/samples/inline-style-directive-spread-dynamic/_config.js create mode 100644 test/runtime/samples/inline-style-directive-spread-dynamic/main.svelte diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts index 6f794c1357ae..19bc5fd80543 100644 --- a/src/compiler/compile/nodes/Style.ts +++ b/src/compiler/compile/nodes/Style.ts @@ -8,14 +8,15 @@ export default class Style extends Node { type: 'Style'; name: string; expression: Expression; + should_cache: boolean; constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { super(component, parent, scope, info); this.name = info.name; - this.expression = info.expression - ? new Expression(component, this, scope, info.expression) - : null; + this.expression = new Expression(component, this, scope, info.expression) + + this.should_cache = info.expression.type === 'TemplateLiteral' && info.expression.expressions.length > 0 } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 630937b6e986..85ba53d80dcf 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -908,17 +908,38 @@ export default class ElementWrapper extends Wrapper { } add_styles(block: Block) { + const has_spread = this.node.attributes.some(attr => attr.is_spread); this.node.styles.forEach((style_directive) => { - const { name, expression } = style_directive; + const { name, expression, should_cache } = style_directive; - const snippet = expression ? expression.manipulate(block) : name; + let snippet = expression.manipulate(block); + let cached_snippet; + if (should_cache) { + cached_snippet = block.get_unique_name(`style_${name}`); + block.add_variable(cached_snippet, snippet); + } - const updater = b`@set_style(${this.var}, "${name}", ${snippet}, false)`; + const updater = b`@set_style(${this.var}, "${name}", ${should_cache ? cached_snippet : snippet}, false)`; block.chunks.hydrate.push(updater); - if (expression && expression.dynamic_dependencies().length) { + const dependencies = expression.dynamic_dependencies(); + if (has_spread) { block.chunks.update.push(updater); + } else if (dependencies.length > 0) { + if (should_cache) { + block.chunks.update.push(b` + if (${block.renderer.dirty(dependencies)} && (${cached_snippet} !== (${cached_snippet} = ${snippet}))) { + ${updater} + } + `); + } else { + block.chunks.update.push(b` + if (${block.renderer.dirty(dependencies)}) { + ${updater} + } + `); + } } }); } diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index c2290c3f38a0..66a886cbd9c7 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -3,7 +3,7 @@ import { get_attribute_expression, get_attribute_value, get_class_attribute_valu import { boolean_attributes } from './shared/boolean_attributes'; import Renderer, { RenderOptions } from '../Renderer'; import Element from '../../nodes/Element'; -import { x } from 'code-red'; +import { p, x } from 'code-red'; import Expression from '../../nodes/shared/Expression'; import remove_whitespace_children from './utils/remove_whitespace_children'; import fix_attribute_casing from '../../render_dom/wrappers/Element/fix_attribute_casing'; @@ -38,12 +38,12 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const style_expression_list = node.styles.map(style_directive => { const { name, expression: { node: expression } } = style_directive; - return x`"${name}: " + ${expression} + ";"`; + return p`"${name}": ${expression}`; }); - const style_expression = - style_expression_list.length > 0 && - style_expression_list.reduce((lhs, rhs) => x`${lhs} + ' ' + ${rhs}`); + const style_expression = + style_expression_list.length > 0 && + x`{ ${style_expression_list} }`; if (node.attributes.some(attr => attr.is_spread)) { // TODO dry this out @@ -100,9 +100,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption renderer.add_string('"'); } else if (name === 'style' && style_expression) { add_style_attribute = false; - renderer.add_string(` ${attribute.name}="`); - renderer.add_expression(x`[${get_attribute_value(attribute)}, ${style_expression}].join(' ').trim()`); - renderer.add_string('"'); + renderer.add_expression(x`@add_styles(@merge_ssr_styles(${get_attribute_value(attribute)}, ${style_expression}))`); } else if (attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text') { const snippet = (attribute.chunks[0] as Expression).node; renderer.add_expression(x`@add_attribute("${attr_name}", ${snippet}, ${boolean_attributes.has(name) ? 1 : 0})`); @@ -113,7 +111,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption } }); if (add_class_attribute) { - renderer.add_expression(x`@add_classes([${class_expression}].join(' ').trim())`); + renderer.add_expression(x`@add_classes((${class_expression}).trim())`); } if (add_style_attribute) { renderer.add_expression(x`@add_styles(${style_expression})`); diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index babd3efd2da7..d28a6557a449 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -1,4 +1,4 @@ -import { TemplateLiteral } from 'estree'; +import { TemplateLiteral, TemplateElement } from 'estree'; import read_expression from '../read/expression'; import read_script from '../read/script'; import read_style from '../read/style'; @@ -270,7 +270,11 @@ function read_tag_name(parser: Parser) { } function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { - + let quasi: TemplateElement = { + type: 'TemplateElement', + value: { raw: '', cooked: null }, + tail: false + }; const literal: TemplateLiteral = { type: 'TemplateLiteral', expressions: [], @@ -279,16 +283,19 @@ function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { value.forEach((node) => { if (node.type === 'Text') { - literal.quasis.push({ - type: 'TemplateElement', - value: { raw: node.raw, cooked: null }, - tail: false - }); + quasi.value.raw += node.raw; } else if (node.type === 'MustacheTag') { + literal.quasis.push(quasi); literal.expressions.push(node.expression); + quasi = { + type: 'TemplateElement', + value: { raw: '', cooked: null }, + tail: false + } } }); - + quasi.tail = true; + literal.quasis.push(quasi); return literal; } diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index 7004289c2f24..d3938b0626bf 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -22,9 +22,9 @@ export function spread(args, attrs_to_add) { if (styles_to_add) { if (attributes.style == null) { - attributes.style = styles_to_add; + attributes.style = style_object_to_string(styles_to_add); } else { - attributes.style += '; ' + styles_to_add; + attributes.style = style_object_to_string(merge_ssr_styles(attributes.style, styles_to_add)); } } } @@ -46,6 +46,28 @@ export function spread(args, attrs_to_add) { return str; } +export function merge_ssr_styles(style_attribute, style_directive) { + const style_object = {}; + for (const individual_style of style_attribute.split(';')) { + const colon_index = individual_style.indexOf(':'); + const name = individual_style.slice(0, colon_index).trim(); + const value = individual_style.slice(colon_index + 1).trim(); + if (!name) continue; + style_object[name] = value; + } + + for (const name in style_directive) { + const value = style_directive[name]; + if (value) { + style_object[name] = value; + } else { + delete style_object[name]; + } + } + + return style_object; +} + export const escaped = { '"': '"', "'": ''', @@ -162,6 +184,15 @@ export function add_classes(classes) { return classes ? ` class="${classes}"` : ''; } -export function add_styles(styles) { - return styles ? ` style="${styles}"` : ''; +function style_object_to_string(style_object) { + return Object.keys(style_object) + .filter(key => style_object[key]) + .map(key => `${key}: ${style_object[key]};`) + .join(' '); +} + +export function add_styles(style_object) { + const styles = style_object_to_string(style_object) + + return styles ? ` style="${styles}"` : ''; } diff --git a/test/parser/samples/attribute-style-directive-string/output.json b/test/parser/samples/attribute-style-directive-string/output.json index aeb258a1c271..4cf2bd30c2e5 100644 --- a/test/parser/samples/attribute-style-directive-string/output.json +++ b/test/parser/samples/attribute-style-directive-string/output.json @@ -26,7 +26,7 @@ "raw": "red", "cooked": null }, - "tail": false + "tail": true } ] } diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js similarity index 98% rename from test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js rename to test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js index 93d6187fec5a..e033a3c510c5 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js @@ -9,5 +9,5 @@ export default { const styles = window.getComputedStyle(p); assert.equal(styles.color, 'red'); assert.equal(styles.height, '40px'); - } + }, }; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-merged/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr-merged/main.svelte new file mode 100644 index 000000000000..6f3e86b9bfed --- /dev/null +++ b/test/runtime/samples/inline-style-directive-and-style-attr-merged/main.svelte @@ -0,0 +1,5 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte deleted file mode 100644 index e2ba0fa591cb..000000000000 --- a/test/runtime/samples/inline-style-directive-and-style-attr-ssr/main.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - -

diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js index 36c46d12de4c..93d6187fec5a 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js @@ -9,7 +9,5 @@ export default { const styles = window.getComputedStyle(p); assert.equal(styles.color, 'red'); assert.equal(styles.height, '40px'); - }, - - skip_if_ssr: true + } }; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte index 6f3e86b9bfed..e2ba0fa591cb 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte +++ b/test/runtime/samples/inline-style-directive-and-style-attr/main.svelte @@ -2,4 +2,4 @@ export let color = 'red'; -

+

diff --git a/test/runtime/samples/inline-style-directive-multiple/_config.js b/test/runtime/samples/inline-style-directive-multiple/_config.js index 2aa46ba60947..3b2d5c94f883 100644 --- a/test/runtime/samples/inline-style-directive-multiple/_config.js +++ b/test/runtime/samples/inline-style-directive-multiple/_config.js @@ -1,16 +1,24 @@ export default { html: ` -

+

`, test({ assert, component, target, window }) { const p = target.querySelector('p'); - const styles = window.getComputedStyle(p); + let styles = window.getComputedStyle(p); assert.equal(styles.color, 'red'); - }, - skip_if_ssr: true - // SSR renders "null" string for null values: - //

+ component.myColor = 'pink'; + component.width = '100vh' + component.absolute = true; + component.bold = false; + + styles = window.getComputedStyle(p); + assert.htmlEqual(target.innerHTML, '

') + assert.equal(styles.color, 'pink'); + assert.equal(styles.width, '100vh'); + assert.equal(styles.fontWeight, '100'); + assert.equal(styles.position, 'absolute'); + }, }; diff --git a/test/runtime/samples/inline-style-directive-shorthand/_config.js b/test/runtime/samples/inline-style-directive-shorthand/_config.js index cf6626f1b262..d59de75d3053 100644 --- a/test/runtime/samples/inline-style-directive-shorthand/_config.js +++ b/test/runtime/samples/inline-style-directive-shorthand/_config.js @@ -6,7 +6,13 @@ export default { test({ assert, component, target, window }) { const p = target.querySelector('p'); - const styles = window.getComputedStyle(p); + let styles = window.getComputedStyle(p); assert.equal(styles.color, 'red'); + + component.color = 'blue'; + assert.htmlEqual(target.innerHTML, '

') + + styles = window.getComputedStyle(p); + assert.equal(styles.color, 'blue'); } }; diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js new file mode 100644 index 000000000000..63bc6ba0a92c --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js @@ -0,0 +1,5 @@ +export default { + html: ` +

+ `, +}; diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr-empty/main.svelte b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/main.svelte new file mode 100644 index 000000000000..c2d5cb4d3f27 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/main.svelte @@ -0,0 +1,11 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js b/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js new file mode 100644 index 000000000000..eab5b5bef21e --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js @@ -0,0 +1,37 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + let styles = window.getComputedStyle(p); + assert.equal(styles.color, 'green'); + + component.color = null; + assert.htmlEqual(target.innerHTML, '

'); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + + component.spread = { style: 'color: yellow; padding: 30px;' }; + + assert.htmlEqual(target.innerHTML, '

'); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + assert.equal(styles.padding, '30px'); + + component.spread = {}; + component.style = 'color: blue; background-color: green;'; + assert.htmlEqual(target.innerHTML, '

'); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + assert.equal(styles.backgroundColor, 'green'); + + component.color = 'purple'; + assert.htmlEqual(target.innerHTML, '

'); + styles = window.getComputedStyle(p); + assert.equal(styles.color, 'purple'); + assert.equal(styles.backgroundColor, 'green'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr/main.svelte b/test/runtime/samples/inline-style-directive-spread-and-attr/main.svelte new file mode 100644 index 000000000000..a9696df67573 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-and-attr/main.svelte @@ -0,0 +1,11 @@ + + +

diff --git a/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js b/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js new file mode 100644 index 000000000000..ae26ff4b70fc --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js @@ -0,0 +1,38 @@ +export default { + html: ` +

+ `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'blue'); + assert.equal(styles.width, '65px'); + assert.equal(p.id, 'my-id'); + + component.color = 'red'; + + assert.htmlEqual(target.innerHTML, ` +

+ `); + + component.obj = { style: 'height: 72px;' }; + + assert.htmlEqual(target.innerHTML, ` +

+ `); + + component.obj = { style: 'border-radius: 2px; color: orange' }; + + assert.htmlEqual(target.innerHTML, ` +

+ `); + + component.obj = {}; + + assert.htmlEqual(target.innerHTML, ` +

+ `); + } +}; diff --git a/test/runtime/samples/inline-style-directive-spread-dynamic/main.svelte b/test/runtime/samples/inline-style-directive-spread-dynamic/main.svelte new file mode 100644 index 000000000000..a514e4856f83 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-spread-dynamic/main.svelte @@ -0,0 +1,5 @@ + +

diff --git a/test/runtime/samples/inline-style-directive-string-variable/_config.js b/test/runtime/samples/inline-style-directive-string-variable/_config.js index 1d9e7404e5c6..3848dfe21a6f 100644 --- a/test/runtime/samples/inline-style-directive-string-variable/_config.js +++ b/test/runtime/samples/inline-style-directive-string-variable/_config.js @@ -1,6 +1,6 @@ export default { html: ` -

+

`, test({ assert, component, target, window }) { @@ -9,5 +9,14 @@ export default { const styles = window.getComputedStyle(p); assert.equal(styles.color, 'green'); assert.equal(styles.transform, 'translateX(45px)'); + assert.equal(styles.border, '100px solid pink'); + + component.translate_x = '100%'; + component.border_width = 20; + component.border_color = 'yellow'; + + assert.htmlEqual(target.innerHTML, ` +

+ `) } }; diff --git a/test/runtime/samples/inline-style-directive-string-variable/main.svelte b/test/runtime/samples/inline-style-directive-string-variable/main.svelte index eaf48da1a3b7..1f0b5019f400 100644 --- a/test/runtime/samples/inline-style-directive-string-variable/main.svelte +++ b/test/runtime/samples/inline-style-directive-string-variable/main.svelte @@ -1,5 +1,7 @@ -

+

From a0cb068e2c97680c6229c4dc6a21b2fb2aba2a50 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 12 Jul 2021 15:33:01 +0800 Subject: [PATCH 34/36] fix lint and tidy up --- src/compiler/compile/nodes/Style.ts | 4 +-- .../render_dom/wrappers/Element/index.ts | 2 +- src/compiler/parse/state/tag.ts | 23 ++++++++--------- src/runtime/internal/ssr.ts | 2 +- .../_config.js | 6 ++--- .../_config.js | 4 +-- .../inline-style-directive-dynamic/_config.js | 4 +-- .../_config.js | 9 ++++--- .../_config.js | 2 +- .../_config.js | 2 +- .../_config.js | 10 ++++++-- .../_config.js | 25 ++++++++++--------- .../_config.js | 7 +++--- 13 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/compiler/compile/nodes/Style.ts b/src/compiler/compile/nodes/Style.ts index 19bc5fd80543..e922f6f5783a 100644 --- a/src/compiler/compile/nodes/Style.ts +++ b/src/compiler/compile/nodes/Style.ts @@ -15,8 +15,8 @@ export default class Style extends Node { this.name = info.name; - this.expression = new Expression(component, this, scope, info.expression) + this.expression = new Expression(component, this, scope, info.expression); - this.should_cache = info.expression.type === 'TemplateLiteral' && info.expression.expressions.length > 0 + this.should_cache = info.expression.type === 'TemplateLiteral' && info.expression.expressions.length > 0; } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 85ba53d80dcf..45ea36f448a2 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -912,7 +912,7 @@ export default class ElementWrapper extends Wrapper { this.node.styles.forEach((style_directive) => { const { name, expression, should_cache } = style_directive; - let snippet = expression.manipulate(block); + const snippet = expression.manipulate(block); let cached_snippet; if (should_cache) { cached_snippet = block.get_unique_name(`style_${name}`); diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index d28a6557a449..3d8d0b13c242 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -1,11 +1,11 @@ -import { TemplateLiteral, TemplateElement } from 'estree'; +import { TemplateLiteral, TemplateElement, Expression } from 'estree'; import read_expression from '../read/expression'; import read_script from '../read/script'; import read_style from '../read/style'; import { decode_character_references, closing_tag_omitted } from '../utils/html'; import { is_void } from '../../utils/names'; import { Parser } from '../index'; -import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces'; +import { Directive, DirectiveType, TemplateNode, Text, MustacheTag } from '../../interfaces'; import fuzzymatch from '../../utils/fuzzymatch'; import parser_errors from '../errors'; @@ -269,7 +269,7 @@ function read_tag_name(parser: Parser) { return name; } -function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { +function node_to_template_literal(value: Array): TemplateLiteral { let quasi: TemplateElement = { type: 'TemplateElement', value: { raw: '', cooked: null }, @@ -286,12 +286,12 @@ function node_to_template_literal(value: TemplateNode[]): TemplateLiteral { quasi.value.raw += node.raw; } else if (node.type === 'MustacheTag') { literal.quasis.push(quasi); - literal.expressions.push(node.expression); + literal.expressions.push(node.expression as Expression); quasi = { type: 'TemplateElement', value: { raw: '', cooked: null }, tail: false - } + }; } }); quasi.tail = true; @@ -398,14 +398,13 @@ function read_attribute(parser: Parser, unique_names: Set) { let expression = null; if (first_value) { - if ((value as any[]).length > 1 || first_value.type === 'Text') { - if (type === 'Style') { - expression = node_to_template_literal(value as TemplateNode[]); - } else { - parser.error(parser_errors.invalid_directive_value, first_value.start); - } + const attribute_contains_text = (value as any[]).length > 1 || first_value.type === 'Text'; + if (type === 'Style') { + expression = attribute_contains_text ? node_to_template_literal(value as Array) : first_value.expression; + } else if (attribute_contains_text) { + parser.error(parser_errors.invalid_directive_value, first_value.start); } else { - expression = first_value.expression || null; + expression = first_value.expression; } } diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index d3938b0626bf..ad83d2c1ee80 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -192,7 +192,7 @@ function style_object_to_string(style_object) { } export function add_styles(style_object) { - const styles = style_object_to_string(style_object) + const styles = style_object_to_string(style_object); return styles ? ` style="${styles}"` : ''; } diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js index e033a3c510c5..1b5f3b76e35c 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js @@ -7,7 +7,7 @@ export default { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); - assert.equal(styles.color, 'red'); - assert.equal(styles.height, '40px'); - }, + assert.equal(styles.color, 'red'); + assert.equal(styles.height, '40px'); + } }; diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js index 93d6187fec5a..1b5f3b76e35c 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js @@ -7,7 +7,7 @@ export default { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); - assert.equal(styles.color, 'red'); - assert.equal(styles.height, '40px'); + assert.equal(styles.color, 'red'); + assert.equal(styles.height, '40px'); } }; diff --git a/test/runtime/samples/inline-style-directive-dynamic/_config.js b/test/runtime/samples/inline-style-directive-dynamic/_config.js index a3d37fa6f70b..a2214fd872ab 100644 --- a/test/runtime/samples/inline-style-directive-dynamic/_config.js +++ b/test/runtime/samples/inline-style-directive-dynamic/_config.js @@ -5,8 +5,6 @@ export default { test({ assert, component, target }) { component.myColor = 'blue'; - assert.htmlEqual(target.innerHTML, ` -

- `); + assert.htmlEqual(target.innerHTML, '

'); } }; diff --git a/test/runtime/samples/inline-style-directive-multiple/_config.js b/test/runtime/samples/inline-style-directive-multiple/_config.js index 3b2d5c94f883..725d03c4feb3 100644 --- a/test/runtime/samples/inline-style-directive-multiple/_config.js +++ b/test/runtime/samples/inline-style-directive-multiple/_config.js @@ -10,15 +10,18 @@ export default { assert.equal(styles.color, 'red'); component.myColor = 'pink'; - component.width = '100vh' + component.width = '100vh'; component.absolute = true; component.bold = false; styles = window.getComputedStyle(p); - assert.htmlEqual(target.innerHTML, '

') + assert.htmlEqual( + target.innerHTML, + '

' + ); assert.equal(styles.color, 'pink'); assert.equal(styles.width, '100vh'); assert.equal(styles.fontWeight, '100'); assert.equal(styles.position, 'absolute'); - }, + } }; diff --git a/test/runtime/samples/inline-style-directive-shorthand/_config.js b/test/runtime/samples/inline-style-directive-shorthand/_config.js index d59de75d3053..64043e52698f 100644 --- a/test/runtime/samples/inline-style-directive-shorthand/_config.js +++ b/test/runtime/samples/inline-style-directive-shorthand/_config.js @@ -10,7 +10,7 @@ export default { assert.equal(styles.color, 'red'); component.color = 'blue'; - assert.htmlEqual(target.innerHTML, '

') + assert.htmlEqual(target.innerHTML, '

'); styles = window.getComputedStyle(p); assert.equal(styles.color, 'blue'); diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js index 63bc6ba0a92c..f3dcbc8823ff 100644 --- a/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js +++ b/test/runtime/samples/inline-style-directive-spread-and-attr-empty/_config.js @@ -1,5 +1,5 @@ export default { html: `

- `, + ` }; diff --git a/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js b/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js index eab5b5bef21e..b3660bd5caa8 100644 --- a/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js +++ b/test/runtime/samples/inline-style-directive-spread-and-attr/_config.js @@ -23,13 +23,19 @@ export default { component.spread = {}; component.style = 'color: blue; background-color: green;'; - assert.htmlEqual(target.innerHTML, '

'); + assert.htmlEqual( + target.innerHTML, + '

' + ); styles = window.getComputedStyle(p); assert.equal(styles.color, ''); assert.equal(styles.backgroundColor, 'green'); component.color = 'purple'; - assert.htmlEqual(target.innerHTML, '

'); + assert.htmlEqual( + target.innerHTML, + '

' + ); styles = window.getComputedStyle(p); assert.equal(styles.color, 'purple'); assert.equal(styles.backgroundColor, 'green'); diff --git a/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js b/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js index ae26ff4b70fc..152e4036a07a 100644 --- a/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js +++ b/test/runtime/samples/inline-style-directive-spread-dynamic/_config.js @@ -13,26 +13,27 @@ export default { component.color = 'red'; - assert.htmlEqual(target.innerHTML, ` -

- `); + assert.htmlEqual( + target.innerHTML, + '

' + ); component.obj = { style: 'height: 72px;' }; - assert.htmlEqual(target.innerHTML, ` -

- `); + assert.htmlEqual( + target.innerHTML, + '

' + ); component.obj = { style: 'border-radius: 2px; color: orange' }; - assert.htmlEqual(target.innerHTML, ` -

- `); + assert.htmlEqual( + target.innerHTML, + '

' + ); component.obj = {}; - assert.htmlEqual(target.innerHTML, ` -

- `); + assert.htmlEqual(target.innerHTML, '

'); } }; diff --git a/test/runtime/samples/inline-style-directive-string-variable/_config.js b/test/runtime/samples/inline-style-directive-string-variable/_config.js index 3848dfe21a6f..411a42db8e1d 100644 --- a/test/runtime/samples/inline-style-directive-string-variable/_config.js +++ b/test/runtime/samples/inline-style-directive-string-variable/_config.js @@ -15,8 +15,9 @@ export default { component.border_width = 20; component.border_color = 'yellow'; - assert.htmlEqual(target.innerHTML, ` -

- `) + assert.htmlEqual( + target.innerHTML, + '

' + ); } }; From f0bc96dff4512df26b095fb3ec838f91a2ca1214 Mon Sep 17 00:00:00 2001 From: tanhauhau Date: Sun, 28 Nov 2021 01:00:42 +0800 Subject: [PATCH 35/36] add test for css variables --- .../samples/inline-style-directive-css-vars/_config.js | 9 +++++++++ .../samples/inline-style-directive-css-vars/main.svelte | 5 +++++ 2 files changed, 14 insertions(+) create mode 100644 test/runtime/samples/inline-style-directive-css-vars/_config.js create mode 100644 test/runtime/samples/inline-style-directive-css-vars/main.svelte diff --git a/test/runtime/samples/inline-style-directive-css-vars/_config.js b/test/runtime/samples/inline-style-directive-css-vars/_config.js new file mode 100644 index 000000000000..99762eeb9c34 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-css-vars/_config.js @@ -0,0 +1,9 @@ +export default { + html: '

', + + test({ assert, component, target, window }) { + component.myColor = 'blue'; + + assert.htmlEqual(target.innerHTML, '

'); + } +}; diff --git a/test/runtime/samples/inline-style-directive-css-vars/main.svelte b/test/runtime/samples/inline-style-directive-css-vars/main.svelte new file mode 100644 index 000000000000..689a2333f500 --- /dev/null +++ b/test/runtime/samples/inline-style-directive-css-vars/main.svelte @@ -0,0 +1,5 @@ + + +

From ec88a1f986ace4f492545ac05d717757c8773d62 Mon Sep 17 00:00:00 2001 From: Paul Murray Date: Thu, 2 Dec 2021 10:41:11 -0500 Subject: [PATCH 36/36] fix linting errors --- .../inline-style-directive-and-style-attr-merged/_config.js | 2 +- .../samples/inline-style-directive-and-style-attr/_config.js | 2 +- test/runtime/samples/inline-style-directive-css-vars/_config.js | 2 +- test/runtime/samples/inline-style-directive-spread/_config.js | 2 +- test/runtime/samples/inline-style-directive-string/_config.js | 2 +- test/runtime/samples/inline-style-directive/_config.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js index 1b5f3b76e35c..f5780daf80eb 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr-merged/_config.js @@ -3,7 +3,7 @@ export default {

`, - test({ assert, component, target, window }) { + test({ assert, target, window }) { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); diff --git a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js index 1b5f3b76e35c..f5780daf80eb 100644 --- a/test/runtime/samples/inline-style-directive-and-style-attr/_config.js +++ b/test/runtime/samples/inline-style-directive-and-style-attr/_config.js @@ -3,7 +3,7 @@ export default {

`, - test({ assert, component, target, window }) { + test({ assert, target, window }) { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); diff --git a/test/runtime/samples/inline-style-directive-css-vars/_config.js b/test/runtime/samples/inline-style-directive-css-vars/_config.js index 99762eeb9c34..c8b239a42bcd 100644 --- a/test/runtime/samples/inline-style-directive-css-vars/_config.js +++ b/test/runtime/samples/inline-style-directive-css-vars/_config.js @@ -1,7 +1,7 @@ export default { html: '

', - test({ assert, component, target, window }) { + test({ assert, component, target }) { component.myColor = 'blue'; assert.htmlEqual(target.innerHTML, '

'); diff --git a/test/runtime/samples/inline-style-directive-spread/_config.js b/test/runtime/samples/inline-style-directive-spread/_config.js index 8193c74c4e3a..adb8a2654484 100644 --- a/test/runtime/samples/inline-style-directive-spread/_config.js +++ b/test/runtime/samples/inline-style-directive-spread/_config.js @@ -3,7 +3,7 @@ export default {

`, - test({ assert, component, target, window }) { + test({ assert, target, window }) { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); diff --git a/test/runtime/samples/inline-style-directive-string/_config.js b/test/runtime/samples/inline-style-directive-string/_config.js index cf6626f1b262..ec32e157e51b 100644 --- a/test/runtime/samples/inline-style-directive-string/_config.js +++ b/test/runtime/samples/inline-style-directive-string/_config.js @@ -3,7 +3,7 @@ export default {

`, - test({ assert, component, target, window }) { + test({ assert, target, window }) { const p = target.querySelector('p'); const styles = window.getComputedStyle(p); diff --git a/test/runtime/samples/inline-style-directive/_config.js b/test/runtime/samples/inline-style-directive/_config.js index cf6626f1b262..ec32e157e51b 100644 --- a/test/runtime/samples/inline-style-directive/_config.js +++ b/test/runtime/samples/inline-style-directive/_config.js @@ -3,7 +3,7 @@ export default {

`, - test({ assert, component, target, window }) { + test({ assert, target, window }) { const p = target.querySelector('p'); const styles = window.getComputedStyle(p);