Skip to content

Commit

Permalink
support for svelte:element
Browse files Browse the repository at this point in the history
  • Loading branch information
adiguba committed Dec 21, 2024
1 parent d7c92d9 commit 313a561
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, ObjectExpression, Statement } from 'estree' */
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, ObjectExpression, Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { SourceLocation } from '#shared' */
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
Expand All @@ -22,7 +22,8 @@ import {
build_attribute_value,
build_class_directives,
build_style_directives,
build_set_attributes
build_set_attributes,
build_display_directive
} from './shared/element.js';
import { process_children } from './shared/fragment.js';
import {
Expand Down Expand Up @@ -422,55 +423,22 @@ export function RegularElement(node, context) {
}
}

if (display_directive) {
if (display_directive || node.fragment.nodes.some((node) => node.type === 'SnippetBlock')) {
// Wrap children in `{...}` to avoid declaration conflicts
const block = b.block([
...child_state.init,
...element_state.init,
child_state.update.length > 0 ? build_render_statement(child_state.update) : b.empty,
...child_state.after_update,
...element_state.after_update
]);

const visibility = b.thunk(
/** @type {Expression} */ (context.visit(display_directive.expression))
);

/** @type {Expression | undefined} */
let value = undefined;

/** @type {Expression | undefined} */
let important = undefined;

if (style_display) {
value =
style_display.value === true
? build_getter({ name: style_display.name, type: 'Identifier' }, context.state)
: build_attribute_value(style_display.value, context).value;

if (style_display.metadata.expression.has_call) {
const id = b.id(state.scope.generate('style_directive'));

state.init.push(b.const(id, create_derived(state, b.thunk(value))));
value = b.call('$.get', id);
}
value = b.thunk(value);
important = style_display.modifiers.includes('important') ? b.true : undefined;
if (display_directive) {
context.state.init.push(
build_display_directive(node_id, display_directive, style_display, block, context)
);
} else {
context.state.init.push(block);
}

context.state.init.push(
b.stmt(b.call('$.display', node_id, visibility, b.arrow([], block), value, important))
);
} else if (node.fragment.nodes.some((node) => node.type === 'SnippetBlock')) {
// Wrap children in `{...}` to avoid declaration conflicts
context.state.init.push(
b.block([
...child_state.init,
...element_state.init,
child_state.update.length > 0 ? build_render_statement(child_state.update) : b.empty,
...child_state.after_update,
...element_state.after_update
])
);
} else if (node.fragment.metadata.dynamic) {
context.state.init.push(...child_state.init, ...element_state.init);
context.state.update.push(...child_state.update);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { determine_namespace_for_children } from '../../utils.js';
import {
build_attribute_value,
build_class_directives,
build_display_directive,
build_set_attributes,
build_style_directives
} from './shared/element.js';
Expand All @@ -36,6 +37,12 @@ export function SvelteElement(node, context) {
/** @type {AST.StyleDirective[]} */
const style_directives = [];

/** @type {AST.DisplayDirective | null} */
let display_directive = null;

/** @type {AST.StyleDirective | null} */
let style_display = null;

/** @type {ExpressionStatement[]} */
const lets = [];

Expand Down Expand Up @@ -73,11 +80,21 @@ export function SvelteElement(node, context) {
} else if (attribute.type === 'OnDirective') {
const handler = /** @type {Expression} */ (context.visit(attribute, inner_context.state));
inner_context.state.after_update.push(b.stmt(handler));
} else if (attribute.type === 'DisplayDirective') {
display_directive = attribute;
} else {
context.visit(attribute, inner_context.state);
}
}

if (display_directive !== null) {
const idx = style_directives.findIndex((d) => d.name === 'display');
if (idx > 0) {
style_display = style_directives[idx];
style_directives.splice(idx, 1);
}
}

// Let bindings first, they can be used on attributes
context.state.init.push(...lets); // create computeds in the outer context; the dynamic element is the single child of this slot

Expand Down Expand Up @@ -140,14 +157,22 @@ export function SvelteElement(node, context) {

const location = dev && locator(node.start);

let render_element = b.block(inner);

if (display_directive) {
render_element = b.block([
build_display_directive(element_id, display_directive, style_display, render_element, context)
]);
}

context.state.init.push(
b.stmt(
b.call(
'$.element',
context.state.node,
get_tag,
node.metadata.svg || node.metadata.mathml ? b.true : b.false,
inner.length > 0 && b.arrow([element_id, b.id('$$anchor')], b.block(inner)),
inner.length > 0 && b.arrow([element_id, b.id('$$anchor')], render_element),
dynamic_namespace && b.thunk(build_attribute_value(dynamic_namespace, context).value),
location && b.array([b.literal(location.line), b.literal(location.column)])
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { Expression, Identifier, ObjectExpression } from 'estree' */
/** @import { BlockStatement, Expression, Identifier, ObjectExpression } from 'estree' */
/** @import { AST, Namespace } from '#compiler' */
/** @import { ComponentClientTransformState, ComponentContext } from '../../types' */
import { normalize_attribute } from '../../../../../../utils.js';
Expand Down Expand Up @@ -214,3 +214,38 @@ export function get_attribute_name(element, attribute) {

return attribute.name;
}

/**
* @param {Identifier} node_id
* @param {AST.DisplayDirective} display
* @param {AST.StyleDirective | null} style
* @param {BlockStatement} block
* @param {ComponentContext} context
*/
export function build_display_directive(node_id, display, style, block, context) {
const visibility = b.thunk(/** @type {Expression} */ (context.visit(display.expression)));

/** @type {Expression | undefined} */
let value = undefined;

/** @type {Expression | undefined} */
let important = undefined;

if (style) {
value =
style.value === true
? build_getter({ name: style.name, type: 'Identifier' }, context.state)
: build_attribute_value(style.value, context).value;

if (style.metadata.expression.has_call) {
const id = b.id(context.state.scope.generate('style_directive'));

context.state.init.push(b.const(id, create_derived(context.state, b.thunk(value))));
value = b.call('$.get', id);
}
value = b.thunk(value);
important = style.modifiers.includes('important') ? b.true : undefined;
}

return b.stmt(b.call('$.display', node_id, visibility, b.arrow([], block), value, important));
}

0 comments on commit 313a561

Please sign in to comment.