Convert src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts to JavaScript

pull/8569/head
Simon Holthausen 3 years ago
parent 461dda587e
commit 94efa51b4d

@ -37,6 +37,7 @@ import {
import create_debugging_comment from '../shared/create_debugging_comment.js';
import { push_array } from '../../../../utils/push_array.js';
import CommentWrapper from '../Comment.js';
const regex_contains_radio_or_checkbox_or_file = /radio|checkbox|file/;
const regex_contains_radio_or_checkbox_or_range_or_file = /radio|checkbox|range|file/;
const events = [
@ -504,6 +505,7 @@ export default class ElementWrapper extends Wrapper {
// skip textcontent for <template>. append nodes to TemplateElement.content instead
if (can_optimise_to_html_string) {
if (this.fragment.nodes.length === 1 && this.fragment.nodes[0].node.type === 'Text') {
/** @type {import('estree').Node} */
let text = string_literal(
/** @type {import('../Text.js').default} */ (this.fragment.nodes[0]).data
);
@ -525,6 +527,7 @@ export default class ElementWrapper extends Wrapper {
value: { raw: '' }
}
};
/** @type {import('estree').Node} */
let literal = {
type: 'TemplateLiteral',
expressions: [],
@ -633,15 +636,15 @@ export default class ElementWrapper extends Wrapper {
}: true`
);
/** @type {Class<x>>} */
/** @type {string | ReturnType<typeof x>} */
let reference;
if (this.node.tag_expr.node.type === 'Literal') {
if (this.node.namespace) {
reference = `"${this.node.tag_expr.node.value}"`;
} else {
reference = `"${(
/** @type {String} */ (this.node.tag_expr.node.value) || ''
).toUpperCase()}"`;
reference = `"${
/** @type {String} */ (this.node.tag_expr.node.value || '').toUpperCase()
}"`;
}
} else if (this.node.namespace) {
reference = x`${this.node.tag_expr.manipulate(block)}`;
@ -660,6 +663,8 @@ export default class ElementWrapper extends Wrapper {
/** @param {import('../../Block.js').default} block */
add_directives_in_order(block) {
/** @typedef {EventHandler | BindingGroup | Binding | Action} OrderedAttribute */
const binding_groups = events
.map((event) => ({
events: event.event_names,
@ -1121,7 +1126,7 @@ export default class ElementWrapper extends Wrapper {
${outro && b`@add_transform(${this.var}, ${rect});`}
`);
/** @type {Class<x>>} */
/** @type {import('estree').Node | ReturnType<typeof x>} */
let params;
if (this.node.animation.expression) {
params = this.node.animation.expression.manipulate(block);

@ -1,114 +1,94 @@
import Wrapper from '../shared/Wrapper';
import BindingWrapper from '../Element/Binding';
import Renderer from '../../Renderer';
import Block from '../../Block';
import InlineComponent from '../../../nodes/InlineComponent';
import FragmentWrapper from '../Fragment';
import SlotTemplateWrapper from '../SlotTemplate';
import { sanitize } from '../../../../utils/names';
import add_to_set from '../../../utils/add_to_set';
import Wrapper from '../shared/Wrapper.js';
import BindingWrapper from '../Element/Binding.js';
import SlotTemplateWrapper from '../SlotTemplate.js';
import { sanitize } from '../../../../utils/names.js';
import add_to_set from '../../../utils/add_to_set.js';
import { b, x, p } from 'code-red';
import Attribute from '../../../nodes/Attribute';
import TemplateScope from '../../../nodes/shared/TemplateScope';
import is_dynamic from '../shared/is_dynamic';
import bind_this from '../shared/bind_this';
import { Node, Identifier, ObjectExpression } from 'estree';
import EventHandler from '../Element/EventHandler';
import is_dynamic from '../shared/is_dynamic.js';
import bind_this from '../shared/bind_this.js';
import EventHandler from '../Element/EventHandler.js';
import { extract_names } from 'periscopic';
import mark_each_block_bindings from '../shared/mark_each_block_bindings';
import { string_to_member_expression } from '../../../utils/string_to_member_expression';
import SlotTemplate from '../../../nodes/SlotTemplate';
import { is_head } from '../shared/is_head';
import compiler_warnings from '../../../compiler_warnings';
import { namespaces } from '../../../../utils/namespaces';
import { extract_ignores_above_node } from '../../../../utils/extract_svelte_ignore';
type SlotDefinition = {
block: Block;
scope: TemplateScope;
get_context?: Node;
get_changes?: Node;
};
import mark_each_block_bindings from '../shared/mark_each_block_bindings.js';
import { string_to_member_expression } from '../../../utils/string_to_member_expression.js';
import { is_head } from '../shared/is_head.js';
import compiler_warnings from '../../../compiler_warnings.js';
import { namespaces } from '../../../../utils/namespaces.js';
import { extract_ignores_above_node } from '../../../../utils/extract_svelte_ignore.js';
const regex_invalid_variable_identifier_characters = /[^a-zA-Z_$]/g;
/** @extends Wrapper */
export default class InlineComponentWrapper extends Wrapper {
var: Identifier;
slots: Map<string, SlotDefinition> = new Map();
node: InlineComponent;
fragment: FragmentWrapper;
children: Array<Wrapper | FragmentWrapper> = [];
constructor(
renderer: Renderer,
block: Block,
parent: Wrapper,
node: InlineComponent,
strip_whitespace: boolean,
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
/** @type {import('estree').Identifier} */
var;
/** @type {Map<string, SlotDefinition>} */
slots = new Map();
/** @type {import('../../../nodes/InlineComponent.js').default} */
node;
/** @type {import('../Fragment.js').default} */
fragment;
/** @type {Array<Wrapper | import('../Fragment.js').default>} */
children = [];
/**
* @param {import('../../Renderer.js').default} renderer
* @param {import('../../Block.js').default} block
* @param {import('../shared/Wrapper.js').default} parent
* @param {import('../../../nodes/InlineComponent.js').default} node
* @param {boolean} strip_whitespace
* @param {import('../shared/Wrapper.js').default} next_sibling
*/
constructor(renderer, block, parent, node, strip_whitespace, next_sibling) {
super(renderer, block, parent, node);
if (this.node.expression) {
block.add_dependencies(this.node.expression.dependencies);
}
this.node.attributes.forEach((attr) => {
block.add_dependencies(attr.dependencies);
});
this.node.bindings.forEach((binding) => {
if (binding.is_contextual) {
mark_each_block_bindings(this, binding);
}
block.add_dependencies(binding.expression.dependencies);
});
this.node.handlers.forEach((handler) => {
if (handler.expression) {
block.add_dependencies(handler.expression.dependencies);
}
});
this.node.css_custom_properties.forEach((attr) => {
block.add_dependencies(attr.dependencies);
});
this.var = {
type: 'Identifier',
name: (this.node.name === 'svelte:self'
? renderer.component.name.name
: this.node.name === 'svelte:component'
? 'switch_instance'
: sanitize(this.node.name)
).toLowerCase()
: sanitize(this.node.name)).toLowerCase()
};
if (this.node.children.length) {
this.node.lets.forEach((l) => {
extract_names(l.value || l.name).forEach((name) => {
renderer.add_to_context(name, true);
});
});
this.children = this.node.children.map(
(child) =>
new SlotTemplateWrapper(
renderer,
block,
this,
child as SlotTemplate,
strip_whitespace,
next_sibling
)
);
this.children = this.node.children.map((child) => new SlotTemplateWrapper(renderer, block, this,
/** @type {import('../../../nodes/SlotTemplate.js').default} */ (child), strip_whitespace, next_sibling));
}
block.add_outro();
}
set_slot(name: string, slot_definition: SlotDefinition) {
/**
* @param {string} name
* @param {SlotDefinition} slot_definition
*/
set_slot(name, slot_definition) {
if (this.slots.has(name)) {
if (name === 'default') {
throw new Error('Found elements without slot attribute when using slot="default"');
@ -117,14 +97,12 @@ export default class InlineComponentWrapper extends Wrapper {
}
this.slots.set(name, slot_definition);
}
warn_if_reactive() {
const { name } = this.node;
const variable = this.renderer.component.var_lookup.get(name);
if (!variable) {
return;
}
const ignores = extract_ignores_above_node(this.node);
this.renderer.component.push_ignores(ignores);
if (variable.reassigned || variable.export_name || variable.is_reactive_dependency) {
@ -133,30 +111,33 @@ export default class InlineComponentWrapper extends Wrapper {
this.renderer.component.pop_ignores();
}
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
/**
* @param {import('../../Block.js').default} block
* @param {import('estree').Identifier} parent_node
* @param {import('estree').Identifier} parent_nodes
*/
render(block, parent_node, parent_nodes) {
this.warn_if_reactive();
const { renderer } = this;
const { component } = renderer;
const name = this.var;
block.add_variable(name);
const component_opts = /** @type {import('estree').ObjectExpression} */ (x `{}`);
const component_opts = x`{}` as ObjectExpression;
const statements: Array<Node | Node[]> = [];
const updates: Array<Node | Node[]> = [];
/** @type {Array<Node | import('estree').Node[]>} */
const statements = [];
/** @type {Array<Node | import('estree').Node[]>} */
const updates = [];
this.children.forEach((child) => {
this.renderer.add_to_context('$$scope', true);
child.render(block, null, x`#nodes` as Identifier);
child.render(block, null, /** @type {import('estree').Identifier} */ (x `#nodes`));
});
let props: Identifier | undefined;
/** @type {import('estree').Identifier | undefined} */
let props;
const name_changes = block.get_unique_name(`${name.name}_changes`);
const uses_spread = !!this.node.attributes.find((a) => a.is_spread);
// removing empty slot
for (const slot of this.slots.keys()) {
if (!this.slots.get(slot).block.has_content()) {
@ -164,7 +145,6 @@ export default class InlineComponentWrapper extends Wrapper {
this.slots.delete(slot);
}
}
const has_css_custom_properties = this.node.css_custom_properties.length > 0;
const is_svg_namespace = this.node.namespace === namespaces.svg;
const css_custom_properties_wrapper_element = is_svg_namespace ? 'g' : 'div';
@ -174,15 +154,11 @@ export default class InlineComponentWrapper extends Wrapper {
if (has_css_custom_properties) {
block.add_variable(css_custom_properties_wrapper);
}
const initial_props =
this.slots.size > 0
const initial_props = this.slots.size > 0
? [
p `$$slots: {
${Array.from(this.slots).map(([name, slot]) => {
return p`${name}: [${slot.block.name}, ${slot.get_context || null}, ${
slot.get_changes || null
}]`;
return p `${name}: [${slot.block.name}, ${slot.get_context || null}, ${slot.get_changes || null}]`;
})}
}`,
p `$$scope: {
@ -190,23 +166,21 @@ export default class InlineComponentWrapper extends Wrapper {
}`
]
: [];
const attribute_object = uses_spread
? x `{ ${initial_props} }`
: x `{
${this.node.attributes.map((attr) => p `${attr.name}: ${attr.get_value(block)}`)},
${initial_props}
}`;
if (this.node.attributes.length || this.node.bindings.length || initial_props.length) {
if (!uses_spread && this.node.bindings.length === 0) {
component_opts.properties.push(p `props: ${attribute_object}`);
} else {
}
else {
props = block.get_unique_name(`${name.name}_props`);
component_opts.properties.push(p `props: ${props}`);
}
}
if (component.compile_options.dev) {
// TODO this is a terrible hack, but without it the component
// will complain that options.target is missing. This would
@ -214,106 +188,91 @@ export default class InlineComponentWrapper extends Wrapper {
// APIs
component_opts.properties.push(p `$$inline: true`);
}
const fragment_dependencies = new Set(this.slots.size ? ['$$scope'] : []);
this.slots.forEach((slot) => {
slot.block.dependencies.forEach((name) => {
const is_let = slot.scope.is_let(name);
const variable = renderer.component.var_lookup.get(name);
if (is_let || is_dynamic(variable)) fragment_dependencies.add(name);
if (is_let || is_dynamic(variable))
fragment_dependencies.add(name);
});
});
const dynamic_attributes = this.node.attributes.filter((a) => a.get_dependencies().length > 0);
if (
!uses_spread &&
if (!uses_spread &&
(dynamic_attributes.length > 0 ||
this.node.bindings.length > 0 ||
fragment_dependencies.size > 0)
) {
fragment_dependencies.size > 0)) {
updates.push(b `const ${name_changes} = {};`);
}
if (this.node.attributes.length) {
if (uses_spread) {
const levels = block.get_unique_name(`${this.var.name}_spread_levels`);
const initial_props = [];
const changes = [];
const all_dependencies: Set<string> = new Set();
/** @type {Set<string>} */
const all_dependencies = new Set();
this.node.attributes.forEach((attr) => {
add_to_set(all_dependencies, attr.dependencies);
});
this.node.attributes.forEach((attr, i) => {
const { name, dependencies } = attr;
const condition =
dependencies.size > 0 && dependencies.size !== all_dependencies.size
const condition = dependencies.size > 0 && dependencies.size !== all_dependencies.size
? renderer.dirty(Array.from(dependencies))
: null;
const unchanged = dependencies.size === 0;
let change_object: Node | ReturnType<typeof x>;
/** @type {Class<x>>} */
let change_object;
if (attr.is_spread) {
const value = attr.expression.manipulate(block);
initial_props.push(value);
let value_object = value;
if (attr.expression.node.type !== 'ObjectExpression') {
value_object = x `@get_spread_object(${value})`;
}
change_object = value_object;
} else {
}
else {
const obj = x `{ ${name}: ${attr.get_value(block)} }`;
initial_props.push(obj);
change_object = obj;
}
changes.push(
unchanged
changes.push(unchanged
? x `${levels}[${i}]`
: condition
? x `${condition} && ${change_object}`
: change_object
);
: change_object);
});
block.chunks.init.push(b `
const ${levels} = [
${initial_props}
];
`);
statements.push(b `
for (let #i = 0; #i < ${levels}.length; #i += 1) {
${props} = @assign(${props}, ${levels}[#i]);
}
`);
if (all_dependencies.size) {
const condition = renderer.dirty(Array.from(all_dependencies));
updates.push(b `
const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [
${changes}
]) : {}
`);
} else {
}
else {
updates.push(b `
const ${name_changes} = {};
`);
}
} else {
dynamic_attributes.forEach((attribute: Attribute) => {
}
else {
dynamic_attributes.forEach((attribute) => {
const dependencies = attribute.get_dependencies();
if (dependencies.length > 0) {
const condition = renderer.dirty(dependencies);
updates.push(b `
if (${condition}) ${name_changes}.${attribute.name} = ${attribute.get_value(block)};
`);
@ -321,35 +280,27 @@ export default class InlineComponentWrapper extends Wrapper {
});
}
}
if (fragment_dependencies.size > 0) {
updates.push(b `
if (${renderer.dirty(Array.from(fragment_dependencies))}) {
${name_changes}.$$scope = { dirty: #dirty, ctx: #ctx };
}`);
}
const munged_bindings = this.node.bindings.map((binding) => {
component.has_reactive_assignments = true;
if (binding.name === 'this') {
return bind_this(component, block, new BindingWrapper(block, binding, this), this.var);
}
const id = component.get_unique_name(`${this.var.name}_${binding.name}_binding`);
renderer.add_to_context(id.name);
const callee = renderer.reference(id);
const updating = block.get_unique_name(`updating_${binding.name}`);
block.add_variable(updating);
const snippet = binding.expression.manipulate(block);
statements.push(b `
if (${snippet} !== void 0) {
${props}.${binding.name} = ${snippet};
}`);
updates.push(b `
if (!${updating} && ${renderer.dirty(Array.from(binding.expression.dependencies))}) {
${updating} = true;
@ -357,12 +308,9 @@ export default class InlineComponentWrapper extends Wrapper {
@add_flush_callback(() => ${updating} = false);
}
`);
const contextual_dependencies = Array.from(binding.expression.contextual_dependencies);
const dependencies = Array.from(binding.expression.dependencies);
let lhs = binding.raw_expression;
if (binding.is_contextual && binding.expression.node.type === 'Identifier') {
// bind:x={y} — we can't just do `y = x`, we need to
// to `array[index] = x;
@ -372,7 +320,8 @@ export default class InlineComponentWrapper extends Wrapper {
contextual_dependencies.push(object.name, property.name);
}
const params: Identifier[] = [x`#value` as Identifier];
/** @type {import('estree').Identifier[]} */
const params = [/** @type {import('estree').Identifier} */ (x `#value`)];
const args = [x `#value`];
if (contextual_dependencies.length > 0) {
contextual_dependencies.forEach((name) => {
@ -380,20 +329,16 @@ export default class InlineComponentWrapper extends Wrapper {
type: 'Identifier',
name
});
renderer.add_to_context(name, true);
args.push(renderer.reference(name));
});
block.maintain_context = true; // TODO put this somewhere more logical
}
block.chunks.init.push(b `
function ${id}(#value) {
${callee}(${args});
}
`);
let invalidate_binding = b `
${lhs} = #value;
${renderer.invalidate(dependencies[0])};
@ -405,58 +350,42 @@ export default class InlineComponentWrapper extends Wrapper {
}
`;
}
const body = b `
function ${id}(${params}) {
${invalidate_binding}
}
`;
component.partly_hoisted.push(body);
return b `@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`;
});
const munged_handlers = this.node.handlers.map((handler) => {
const event_handler = new EventHandler(handler, this);
let snippet = event_handler.get_snippet(block);
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
if (handler.modifiers.has('once'))
snippet = x `@once(${snippet})`;
return b `${name}.$on("${handler.name}", ${snippet});`;
});
const mount_target = has_css_custom_properties
? css_custom_properties_wrapper
: parent_node || '#target';
const mount_anchor = has_css_custom_properties ? 'null' : parent_node ? 'null' : '#anchor';
const to_claim = parent_nodes && this.renderer.options.hydratable;
let claim_nodes = parent_nodes;
if (this.node.name === 'svelte:component') {
const switch_value = block.get_unique_name('switch_value');
const switch_props = block.get_unique_name('switch_props');
const snippet = this.node.expression.manipulate(block);
const dependencies = this.node.expression.dynamic_dependencies();
if (has_css_custom_properties) {
this.set_css_custom_properties(
block,
css_custom_properties_wrapper,
css_custom_properties_wrapper_element,
is_svg_namespace
);
this.set_css_custom_properties(block, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace);
}
block.chunks.init.push(b `
var ${switch_value} = ${snippet};
function ${switch_props}(#ctx) {
${
(this.node.attributes.length > 0 || this.node.bindings.length > 0) &&
${(this.node.attributes.length > 0 || this.node.bindings.length > 0) &&
b `
${props && b`let ${props} = ${attribute_object};`}`
}
${props && b `let ${props} = ${attribute_object};`}`}
${statements}
return ${component_opts};
}
@ -468,55 +397,33 @@ export default class InlineComponentWrapper extends Wrapper {
${munged_handlers}
}
`);
block.chunks.create.push(b `if (${name}) @create_component(${name}.$$.fragment);`);
if (css_custom_properties_wrapper)
this.create_css_custom_properties_wrapper_mount_chunk(
block,
parent_node,
css_custom_properties_wrapper
);
block.chunks.mount.push(
b`if (${name}) @mount_component(${name}, ${mount_target}, ${mount_anchor});`
);
this.create_css_custom_properties_wrapper_mount_chunk(block, parent_node, css_custom_properties_wrapper);
block.chunks.mount.push(b `if (${name}) @mount_component(${name}, ${mount_target}, ${mount_anchor});`);
if (to_claim) {
if (css_custom_properties_wrapper)
claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(
block,
claim_nodes,
css_custom_properties_wrapper,
css_custom_properties_wrapper_element,
is_svg_namespace
);
block.chunks.claim.push(
b`if (${name}) @claim_component(${name}.$$.fragment, ${claim_nodes});`
);
claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(block, claim_nodes, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace);
block.chunks.claim.push(b `if (${name}) @claim_component(${name}.$$.fragment, ${claim_nodes});`);
}
if (updates.length) {
block.chunks.update.push(b `
${updates}
`);
}
const tmp_anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
const anchor = has_css_custom_properties ? 'null' : tmp_anchor;
const update_mount_node = has_css_custom_properties
? css_custom_properties_wrapper
: this.get_update_mount_node(tmp_anchor);
const update_insert =
css_custom_properties_wrapper &&
const update_insert = css_custom_properties_wrapper &&
(tmp_anchor.name !== 'null'
? b `@insert(${tmp_anchor}.parentNode, ${css_custom_properties_wrapper}, ${tmp_anchor});`
: b `@insert(${parent_node}, ${css_custom_properties_wrapper}, ${tmp_anchor});`);
let update_condition = x `${switch_value} !== (${switch_value} = ${snippet})`;
if (dependencies.length > 0) {
update_condition = x `${block.renderer.dirty(dependencies)} && ${update_condition}`;
}
block.chunks.update.push(b `
if (${update_condition}) {
if (${name}) {
@ -546,111 +453,84 @@ export default class InlineComponentWrapper extends Wrapper {
${updates.length > 0 && b `${name}.$set(${name_changes});`}
}
`);
block.chunks.intro.push(b `
if (${name}) @transition_in(${name}.$$.fragment, #local);
`);
block.chunks.outro.push(b `if (${name}) @transition_out(${name}.$$.fragment, #local);`);
block.chunks.destroy.push(
b`if (${name}) @destroy_component(${name}, ${parent_node ? null : 'detaching'});`
);
} else {
const expression =
this.node.name === 'svelte:self'
block.chunks.destroy.push(b `if (${name}) @destroy_component(${name}, ${parent_node ? null : 'detaching'});`);
}
else {
const expression = this.node.name === 'svelte:self'
? component.name
: this.renderer.reference(string_to_member_expression(this.node.name));
block.chunks.init.push(b `
${
(this.node.attributes.length > 0 || this.node.bindings.length > 0) &&
${(this.node.attributes.length > 0 || this.node.bindings.length > 0) &&
b `
${props && b`let ${props} = ${attribute_object};`}`
}
${props && b `let ${props} = ${attribute_object};`}`}
${statements}
${name} = new ${expression}(${component_opts});
${munged_bindings}
${munged_handlers}
`);
if (has_css_custom_properties) {
this.set_css_custom_properties(
block,
css_custom_properties_wrapper,
css_custom_properties_wrapper_element,
is_svg_namespace
);
this.set_css_custom_properties(block, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace);
}
block.chunks.create.push(b `@create_component(${name}.$$.fragment);`);
if (css_custom_properties_wrapper)
this.create_css_custom_properties_wrapper_mount_chunk(
block,
parent_node,
css_custom_properties_wrapper
);
this.create_css_custom_properties_wrapper_mount_chunk(block, parent_node, css_custom_properties_wrapper);
block.chunks.mount.push(b `@mount_component(${name}, ${mount_target}, ${mount_anchor});`);
if (to_claim) {
if (css_custom_properties_wrapper)
claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(
block,
claim_nodes,
css_custom_properties_wrapper,
css_custom_properties_wrapper_element,
is_svg_namespace
);
claim_nodes = this.create_css_custom_properties_wrapper_claim_chunk(block, claim_nodes, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace);
block.chunks.claim.push(b `@claim_component(${name}.$$.fragment, ${claim_nodes});`);
}
block.chunks.intro.push(b `
@transition_in(${name}.$$.fragment, #local);
`);
if (updates.length) {
block.chunks.update.push(b `
${updates}
${name}.$set(${name_changes});
`);
}
block.chunks.destroy.push(b `
@destroy_component(${name}, ${parent_node ? null : 'detaching'});
`);
block.chunks.outro.push(b `@transition_out(${name}.$$.fragment, #local);`);
}
}
private create_css_custom_properties_wrapper_mount_chunk(
block: Block,
parent_node: Identifier,
css_custom_properties_wrapper: Identifier | null
) {
/**
* @private
* @param {import('../../Block.js').default} block
* @param {import('estree').Identifier} parent_node
* @param {import('estree').Identifier | null} css_custom_properties_wrapper
*/
create_css_custom_properties_wrapper_mount_chunk(block, parent_node, css_custom_properties_wrapper) {
if (parent_node) {
block.chunks.mount.push(b `@append(${parent_node}, ${css_custom_properties_wrapper})`);
if (is_head(parent_node)) {
block.chunks.destroy.push(b `@detach(${css_custom_properties_wrapper});`);
}
} else {
}
else {
block.chunks.mount.push(b `@insert(#target, ${css_custom_properties_wrapper}, #anchor);`);
// TODO we eventually need to consider what happens to elements
// that belong to the same outgroup as an outroing element...
block.chunks.destroy.push(
b`if (detaching && ${this.var}) @detach(${css_custom_properties_wrapper});`
);
block.chunks.destroy.push(b `if (detaching && ${this.var}) @detach(${css_custom_properties_wrapper});`);
}
}
private create_css_custom_properties_wrapper_claim_chunk(
block: Block,
parent_nodes: Identifier,
css_custom_properties_wrapper: Identifier | null,
css_custom_properties_wrapper_element: string,
is_svg_namespace: boolean
) {
/**
* @private
* @param {import('../../Block.js').default} block
* @param {import('estree').Identifier} parent_nodes
* @param {import('estree').Identifier | null} css_custom_properties_wrapper
* @param {string} css_custom_properties_wrapper_element
* @param {boolean} is_svg_namespace
*/
create_css_custom_properties_wrapper_claim_chunk(block, parent_nodes, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace) {
const nodes = block.get_unique_name(`${css_custom_properties_wrapper.name}_nodes`);
const claim_element = is_svg_namespace ? x `@claim_svg_element` : x `@claim_element`;
block.chunks.claim.push(b `
@ -660,38 +540,32 @@ export default class InlineComponentWrapper extends Wrapper {
return nodes;
}
private set_css_custom_properties(
block: Block,
css_custom_properties_wrapper: Identifier,
css_custom_properties_wrapper_element: string,
is_svg_namespace: boolean
) {
/**
* @private
* @param {import('../../Block.js').default} block
* @param {import('estree').Identifier} css_custom_properties_wrapper
* @param {string} css_custom_properties_wrapper_element
* @param {boolean} is_svg_namespace
*/
set_css_custom_properties(block, css_custom_properties_wrapper, css_custom_properties_wrapper_element, is_svg_namespace) {
const element = is_svg_namespace ? x `@svg_element` : x `@element`;
block.chunks.create.push(
b`${css_custom_properties_wrapper} = ${element}("${css_custom_properties_wrapper_element}");`
);
block.chunks.create.push(b `${css_custom_properties_wrapper} = ${element}("${css_custom_properties_wrapper_element}");`);
if (!is_svg_namespace)
block.chunks.hydrate.push(
b`@set_style(${css_custom_properties_wrapper}, "display", "contents");`
);
block.chunks.hydrate.push(b `@set_style(${css_custom_properties_wrapper}, "display", "contents");`);
this.node.css_custom_properties.forEach((attr) => {
const dependencies = attr.get_dependencies();
const should_cache = attr.should_cache();
const last =
should_cache &&
block.get_unique_name(
`${attr.name.replace(regex_invalid_variable_identifier_characters, '_')}_last`
);
if (should_cache) block.add_variable(last);
const last = should_cache &&
block.get_unique_name(`${attr.name.replace(regex_invalid_variable_identifier_characters, '_')}_last`);
if (should_cache)
block.add_variable(last);
const value = attr.get_value(block);
const init = should_cache ? x `${last} = ${value}` : value;
block.chunks.hydrate.push(
b`@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${init});`
);
block.chunks.hydrate.push(b `@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${init});`);
if (dependencies.length > 0) {
let condition = block.renderer.dirty(dependencies);
if (should_cache) condition = x`${condition} && (${last} !== (${last} = ${value}))`;
if (should_cache)
condition = x `${condition} && (${last} !== (${last} = ${value}))`;
block.chunks.update.push(b `
if (${condition}) {
@set_style(${css_custom_properties_wrapper}, "${attr.name}", ${should_cache ? last : value});
@ -701,3 +575,14 @@ export default class InlineComponentWrapper extends Wrapper {
});
}
}
/**
* @typedef {{
* block: Block;
* scope: TemplateScope;
* get_context?: Node;
* get_changes?: Node;
* }} SlotDefinition
*/

Loading…
Cancel
Save