|
|
@ -26,105 +26,85 @@ import { Identifier } from 'estree';
|
|
|
|
import EventHandler from './EventHandler';
|
|
|
|
import EventHandler from './EventHandler';
|
|
|
|
import { extract_names } from 'periscopic';
|
|
|
|
import { extract_names } from 'periscopic';
|
|
|
|
import Action from '../../../nodes/Action';
|
|
|
|
import Action from '../../../nodes/Action';
|
|
|
|
|
|
|
|
import Transition from '../../../nodes/Transition';
|
|
|
|
|
|
|
|
|
|
|
|
const events = [
|
|
|
|
const events = [
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['input'],
|
|
|
|
event_names: ['input'],
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
node.name === 'textarea' ||
|
|
|
|
node.name === 'textarea' ||
|
|
|
|
node.name === 'input' && !/radio|checkbox|range|file/.test(node.get_static_attribute_value('type') as string)
|
|
|
|
(node.name === 'input' && !/radio|checkbox|range|file/.test(node.get_static_attribute_value('type') as string)),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['input'],
|
|
|
|
event_names: ['input'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
(name === 'textContent' || name === 'innerHTML') &&
|
|
|
|
(name === 'textContent' || name === 'innerHTML') &&
|
|
|
|
node.attributes.some(attribute => attribute.name === 'contenteditable')
|
|
|
|
node.attributes.some((attribute) => attribute.name === 'contenteditable'),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['change'],
|
|
|
|
event_names: ['change'],
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
node.name === 'select' ||
|
|
|
|
node.name === 'select' ||
|
|
|
|
node.name === 'input' && /radio|checkbox|file/.test(node.get_static_attribute_value('type') as string)
|
|
|
|
(node.name === 'input' && /radio|checkbox|file/.test(node.get_static_attribute_value('type') as string)),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['change', 'input'],
|
|
|
|
event_names: ['change', 'input'],
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
node.name === 'input' && node.get_static_attribute_value('type') === 'range'
|
|
|
|
node.name === 'input' && node.get_static_attribute_value('type') === 'range',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['elementresize'],
|
|
|
|
event_names: ['elementresize'],
|
|
|
|
filter: (_node: Element, name: string) =>
|
|
|
|
filter: (_node: Element, name: string) => dimensions.test(name),
|
|
|
|
dimensions.test(name)
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// media events
|
|
|
|
// media events
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['timeupdate'],
|
|
|
|
event_names: ['timeupdate'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
node.is_media_node() &&
|
|
|
|
node.is_media_node() && (name === 'currentTime' || name === 'played' || name === 'ended'),
|
|
|
|
(name === 'currentTime' || name === 'played' || name === 'ended')
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['durationchange'],
|
|
|
|
event_names: ['durationchange'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'duration',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'duration'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['play', 'pause'],
|
|
|
|
event_names: ['play', 'pause'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'paused',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'paused'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['progress'],
|
|
|
|
event_names: ['progress'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'buffered',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'buffered'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['loadedmetadata'],
|
|
|
|
event_names: ['loadedmetadata'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && (name === 'buffered' || name === 'seekable'),
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
(name === 'buffered' || name === 'seekable')
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['volumechange'],
|
|
|
|
event_names: ['volumechange'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'volume',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'volume'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['ratechange'],
|
|
|
|
event_names: ['ratechange'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'playbackRate',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'playbackRate'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['seeking', 'seeked'],
|
|
|
|
event_names: ['seeking', 'seeked'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'seeking',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
(name === 'seeking')
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['ended'],
|
|
|
|
event_names: ['ended'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && name === 'ended',
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
name === 'ended'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['resize'],
|
|
|
|
event_names: ['resize'],
|
|
|
|
filter: (node: Element, name: string) =>
|
|
|
|
filter: (node: Element, name: string) => node.is_media_node() && (name === 'videoHeight' || name === 'videoWidth'),
|
|
|
|
node.is_media_node() &&
|
|
|
|
|
|
|
|
(name === 'videoHeight' || name === 'videoWidth')
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// details event
|
|
|
|
// details event
|
|
|
|
{
|
|
|
|
{
|
|
|
|
event_names: ['toggle'],
|
|
|
|
event_names: ['toggle'],
|
|
|
|
filter: (node: Element, _name: string) =>
|
|
|
|
filter: (node: Element, _name: string) => node.name === 'details',
|
|
|
|
node.name === 'details'
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
@ -153,7 +133,7 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
super(renderer, block, parent, node);
|
|
|
|
super(renderer, block, parent, node);
|
|
|
|
this.var = {
|
|
|
|
this.var = {
|
|
|
|
type: 'Identifier',
|
|
|
|
type: 'Identifier',
|
|
|
|
name: node.name.replace(/[^a-zA-Z0-9_$]/g, '_')
|
|
|
|
name: node.name.replace(/[^a-zA-Z0-9_$]/g, '_'),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
this.void = is_void(node.name);
|
|
|
|
this.void = is_void(node.name);
|
|
|
@ -161,14 +141,14 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
this.class_dependencies = [];
|
|
|
|
this.class_dependencies = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (this.node.children.length) {
|
|
|
|
if (this.node.children.length) {
|
|
|
|
this.node.lets.forEach(l => {
|
|
|
|
this.node.lets.forEach((l) => {
|
|
|
|
extract_names(l.value || l.name).forEach(name => {
|
|
|
|
extract_names(l.value || l.name).forEach((name) => {
|
|
|
|
renderer.add_to_context(name, true);
|
|
|
|
renderer.add_to_context(name, true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.attributes = this.node.attributes.map(attribute => {
|
|
|
|
this.attributes = this.node.attributes.map((attribute) => {
|
|
|
|
if (attribute.name === 'slot') {
|
|
|
|
if (attribute.name === 'slot') {
|
|
|
|
// TODO make separate subclass for this?
|
|
|
|
// TODO make separate subclass for this?
|
|
|
|
let owner = this.parent;
|
|
|
|
let owner = this.parent;
|
|
|
@ -187,28 +167,28 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
if (owner && owner.node.type === 'InlineComponent') {
|
|
|
|
if (owner && owner.node.type === 'InlineComponent') {
|
|
|
|
const name = attribute.get_static_value() as string;
|
|
|
|
const name = attribute.get_static_value() as string;
|
|
|
|
|
|
|
|
|
|
|
|
if (!(owner as unknown as InlineComponentWrapper).slots.has(name)) {
|
|
|
|
if (!((owner as unknown) as InlineComponentWrapper).slots.has(name)) {
|
|
|
|
const child_block = block.child({
|
|
|
|
const child_block = block.child({
|
|
|
|
comment: create_debugging_comment(node, this.renderer.component),
|
|
|
|
comment: create_debugging_comment(node, this.renderer.component),
|
|
|
|
name: this.renderer.component.get_unique_name(`create_${sanitize(name)}_slot`),
|
|
|
|
name: this.renderer.component.get_unique_name(`create_${sanitize(name)}_slot`),
|
|
|
|
type: 'slot'
|
|
|
|
type: 'slot',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const { scope, lets } = this.node;
|
|
|
|
const { scope, lets } = this.node;
|
|
|
|
const seen = new Set(lets.map(l => l.name.name));
|
|
|
|
const seen = new Set(lets.map((l) => l.name.name));
|
|
|
|
|
|
|
|
|
|
|
|
(owner as unknown as InlineComponentWrapper).node.lets.forEach(l => {
|
|
|
|
((owner as unknown) as InlineComponentWrapper).node.lets.forEach((l) => {
|
|
|
|
if (!seen.has(l.name.name)) lets.push(l);
|
|
|
|
if (!seen.has(l.name.name)) lets.push(l);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
(owner as unknown as InlineComponentWrapper).slots.set(
|
|
|
|
((owner as unknown) as InlineComponentWrapper).slots.set(
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
get_slot_definition(child_block, scope, lets)
|
|
|
|
get_slot_definition(child_block, scope, lets)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
this.renderer.blocks.push(child_block);
|
|
|
|
this.renderer.blocks.push(child_block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.slot_block = (owner as unknown as InlineComponentWrapper).slots.get(name).block;
|
|
|
|
this.slot_block = ((owner as unknown) as InlineComponentWrapper).slots.get(name).block;
|
|
|
|
block = this.slot_block;
|
|
|
|
block = this.slot_block;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -221,9 +201,9 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
// ordinarily, there'll only be one... but we need to handle
|
|
|
|
// ordinarily, there'll only be one... but we need to handle
|
|
|
|
// the rare case where an element can have multiple bindings,
|
|
|
|
// the rare case where an element can have multiple bindings,
|
|
|
|
// e.g. <audio bind:paused bind:currentTime>
|
|
|
|
// e.g. <audio bind:paused bind:currentTime>
|
|
|
|
this.bindings = this.node.bindings.map(binding => new Binding(block, binding, this));
|
|
|
|
this.bindings = this.node.bindings.map((binding) => new Binding(block, binding, this));
|
|
|
|
|
|
|
|
|
|
|
|
this.event_handlers = this.node.handlers.map(event_handler => new EventHandler(event_handler, this));
|
|
|
|
this.event_handlers = this.node.handlers.map((event_handler) => new EventHandler(event_handler, this));
|
|
|
|
|
|
|
|
|
|
|
|
if (node.intro || node.outro) {
|
|
|
|
if (node.intro || node.outro) {
|
|
|
|
if (node.intro) block.add_intro(node.intro.is_local);
|
|
|
|
if (node.intro) block.add_intro(node.intro.is_local);
|
|
|
@ -235,27 +215,29 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// add directive and handler dependencies
|
|
|
|
// add directive and handler dependencies
|
|
|
|
[node.animation, node.outro, ...node.actions, ...node.classes].forEach(directive => {
|
|
|
|
[node.animation, node.outro, ...node.actions, ...node.classes].forEach((directive) => {
|
|
|
|
if (directive && directive.expression) {
|
|
|
|
if (directive && directive.expression) {
|
|
|
|
block.add_dependencies(directive.expression.dependencies);
|
|
|
|
block.add_dependencies(directive.expression.dependencies);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
node.handlers.forEach(handler => {
|
|
|
|
node.handlers.forEach((handler) => {
|
|
|
|
if (handler.expression) {
|
|
|
|
if (handler.expression) {
|
|
|
|
block.add_dependencies(handler.expression.dependencies);
|
|
|
|
block.add_dependencies(handler.expression.dependencies);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (this.parent) {
|
|
|
|
if (this.parent) {
|
|
|
|
if (node.actions.length > 0 ||
|
|
|
|
if (
|
|
|
|
|
|
|
|
renderer.options.dev ||
|
|
|
|
|
|
|
|
node.actions.length ||
|
|
|
|
|
|
|
|
node.bindings.length ||
|
|
|
|
|
|
|
|
node.handlers.length ||
|
|
|
|
|
|
|
|
node.classes.length ||
|
|
|
|
|
|
|
|
node.intro ||
|
|
|
|
|
|
|
|
node.outro ||
|
|
|
|
node.animation ||
|
|
|
|
node.animation ||
|
|
|
|
node.bindings.length > 0 ||
|
|
|
|
this.node.name === 'option'
|
|
|
|
node.classes.length > 0 ||
|
|
|
|
|
|
|
|
node.intro || node.outro ||
|
|
|
|
|
|
|
|
node.handlers.length > 0 ||
|
|
|
|
|
|
|
|
this.node.name === 'option' ||
|
|
|
|
|
|
|
|
renderer.options.dev
|
|
|
|
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
this.parent.cannot_use_innerhtml(); // need to use add_location
|
|
|
|
this.parent.cannot_use_innerhtml(); // need to use add_location
|
|
|
|
this.parent.not_static_content();
|
|
|
|
this.parent.not_static_content();
|
|
|
@ -289,32 +271,22 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
|
|
|
|
|
|
|
|
block.add_variable(node);
|
|
|
|
block.add_variable(node);
|
|
|
|
const render_statement = this.get_render_statement(block);
|
|
|
|
const render_statement = this.get_render_statement(block);
|
|
|
|
block.chunks.create.push(
|
|
|
|
block.chunks.create.push(b`${node} = ${render_statement};`);
|
|
|
|
b`${node} = ${render_statement};`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (renderer.options.hydratable) {
|
|
|
|
if (renderer.options.hydratable) {
|
|
|
|
if (parent_nodes) {
|
|
|
|
if (parent_nodes) {
|
|
|
|
block.chunks.claim.push(b`
|
|
|
|
block.chunks.claim.push(b`${node} = ${this.get_claim_statement(parent_nodes)};`);
|
|
|
|
${node} = ${this.get_claim_statement(parent_nodes)};
|
|
|
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!this.void && this.node.children.length > 0) {
|
|
|
|
if (!this.void && this.node.children.length > 0) {
|
|
|
|
block.chunks.claim.push(b`
|
|
|
|
block.chunks.claim.push(b`var ${nodes} = ${children};`);
|
|
|
|
var ${nodes} = ${children};
|
|
|
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
block.chunks.claim.push(
|
|
|
|
block.chunks.claim.push(b`${node} = ${render_statement};`);
|
|
|
|
b`${node} = ${render_statement};`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (parent_node) {
|
|
|
|
if (parent_node) {
|
|
|
|
block.chunks.mount.push(
|
|
|
|
block.chunks.mount.push(b`@append(${parent_node}, ${node});`);
|
|
|
|
b`@append(${parent_node}, ${node});`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (is_head(parent_node)) {
|
|
|
|
if (is_head(parent_node)) {
|
|
|
|
block.chunks.destroy.push(b`@detach(${node});`);
|
|
|
|
block.chunks.destroy.push(b`@detach(${node});`);
|
|
|
@ -339,39 +311,38 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
const state = {
|
|
|
|
const state = {
|
|
|
|
quasi: {
|
|
|
|
quasi: {
|
|
|
|
type: 'TemplateElement',
|
|
|
|
type: 'TemplateElement',
|
|
|
|
value: { raw: '' }
|
|
|
|
value: { raw: '' },
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const literal = {
|
|
|
|
const literal = {
|
|
|
|
type: 'TemplateLiteral',
|
|
|
|
type: 'TemplateLiteral',
|
|
|
|
expressions: [],
|
|
|
|
expressions: [],
|
|
|
|
quasis: []
|
|
|
|
quasis: [],
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const can_use_raw_text = !this.can_use_innerhtml && can_use_textcontent;
|
|
|
|
const can_use_raw_text = !this.can_use_innerhtml && can_use_textcontent;
|
|
|
|
to_html((this.fragment.nodes as unknown as Array<ElementWrapper | TextWrapper>), block, literal, state, can_use_raw_text);
|
|
|
|
to_html(
|
|
|
|
|
|
|
|
(this.fragment.nodes as unknown) as Array<ElementWrapper | TextWrapper>,
|
|
|
|
|
|
|
|
block,
|
|
|
|
|
|
|
|
literal,
|
|
|
|
|
|
|
|
state,
|
|
|
|
|
|
|
|
can_use_raw_text
|
|
|
|
|
|
|
|
);
|
|
|
|
literal.quasis.push(state.quasi);
|
|
|
|
literal.quasis.push(state.quasi);
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.create.push(
|
|
|
|
block.chunks.create.push(b`${node}.${this.can_use_innerhtml ? 'innerHTML' : 'textContent'} = ${literal};`);
|
|
|
|
b`${node}.${this.can_use_innerhtml ? 'innerHTML': 'textContent'} = ${literal};`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
this.fragment.nodes.forEach((child: Wrapper) => {
|
|
|
|
this.fragment.nodes.forEach((child: Wrapper) => {
|
|
|
|
child.render(
|
|
|
|
child.render(block, this.node.name === 'template' ? x`${node}.content` : node, nodes);
|
|
|
|
block,
|
|
|
|
|
|
|
|
this.node.name === 'template' ? x`${node}.content` : node,
|
|
|
|
|
|
|
|
nodes
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const event_handler_or_binding_uses_context = (
|
|
|
|
const event_handler_or_binding_uses_context =
|
|
|
|
this.bindings.some(binding => binding.handler.uses_context) ||
|
|
|
|
this.bindings.some((binding) => binding.handler.uses_context) ||
|
|
|
|
this.node.handlers.some(handler => handler.uses_context) ||
|
|
|
|
this.node.handlers.some((handler) => handler.uses_context) ||
|
|
|
|
this.node.actions.some(action => action.uses_context)
|
|
|
|
this.node.actions.some((action) => action.uses_context);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (event_handler_or_binding_uses_context) {
|
|
|
|
if (event_handler_or_binding_uses_context) {
|
|
|
|
block.maintain_context = true;
|
|
|
|
block.maintain_context = true;
|
|
|
@ -379,15 +350,23 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
|
|
|
|
|
|
|
|
this.add_attributes(block);
|
|
|
|
this.add_attributes(block);
|
|
|
|
this.add_directives_in_order(block);
|
|
|
|
this.add_directives_in_order(block);
|
|
|
|
this.add_transitions(block);
|
|
|
|
const { intro, outro } = this.node;
|
|
|
|
this.add_animation(block);
|
|
|
|
if (intro || outro) {
|
|
|
|
|
|
|
|
if (intro === outro) {
|
|
|
|
|
|
|
|
this.add_bidi_transition(block, intro);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.add_intro(block, intro, outro);
|
|
|
|
|
|
|
|
this.add_outro(block, intro, outro);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.node.animation) {
|
|
|
|
|
|
|
|
this.add_animation(block, intro, outro);
|
|
|
|
|
|
|
|
}
|
|
|
|
this.add_classes(block);
|
|
|
|
this.add_classes(block);
|
|
|
|
this.add_manual_style_scoping(block);
|
|
|
|
this.add_manual_style_scoping(block);
|
|
|
|
|
|
|
|
|
|
|
|
if (nodes && this.renderer.options.hydratable && !this.void) {
|
|
|
|
if (nodes && this.renderer.options.hydratable && !this.void) {
|
|
|
|
block.chunks.claim.push(
|
|
|
|
block.chunks.claim.push(b`${this.node.children.length > 0 ? nodes : children}.forEach(@detach);`);
|
|
|
|
b`${this.node.children.length > 0 ? nodes : children}.forEach(@detach);`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (renderer.options.dev) {
|
|
|
|
if (renderer.options.dev) {
|
|
|
@ -399,7 +378,10 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
can_use_textcontent() {
|
|
|
|
can_use_textcontent() {
|
|
|
|
return this.is_static_content && this.fragment.nodes.every(node => node.node.type === 'Text' || node.node.type === 'MustacheTag');
|
|
|
|
return (
|
|
|
|
|
|
|
|
this.is_static_content &&
|
|
|
|
|
|
|
|
this.fragment.nodes.every((node) => node.node.type === 'Text' || node.node.type === 'MustacheTag')
|
|
|
|
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
get_render_statement(block: Block) {
|
|
|
|
get_render_statement(block: Block) {
|
|
|
@ -413,7 +395,7 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
return x`@_document.createElementNS("${namespace}", "${name}")`;
|
|
|
|
return x`@_document.createElementNS("${namespace}", "${name}")`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const is = this.attributes.find(attr => attr.node.name === 'is');
|
|
|
|
const is = this.attributes.find((attr) => attr.node.name === 'is');
|
|
|
|
if (is) {
|
|
|
|
if (is) {
|
|
|
|
return x`@element_is("${name}", ${is.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`)})`;
|
|
|
|
return x`@element_is("${name}", ${is.render_chunks(block).reduce((lhs, rhs) => x`${lhs} + ${rhs}`)})`;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -426,9 +408,7 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
.filter((attr) => attr.type === 'Attribute')
|
|
|
|
.filter((attr) => attr.type === 'Attribute')
|
|
|
|
.map((attr) => p`${attr.name}: true`);
|
|
|
|
.map((attr) => p`${attr.name}: true`);
|
|
|
|
|
|
|
|
|
|
|
|
const name = this.node.namespace
|
|
|
|
const name = this.node.namespace ? this.node.name : this.node.name.toUpperCase();
|
|
|
|
? this.node.name
|
|
|
|
|
|
|
|
: this.node.name.toUpperCase();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const svg = this.node.namespace === namespaces.svg ? 1 : null;
|
|
|
|
const svg = this.node.namespace === namespaces.svg ? 1 : null;
|
|
|
|
|
|
|
|
|
|
|
@ -444,15 +424,15 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
type OrderedAttribute = EventHandler | BindingGroup | Binding | Action;
|
|
|
|
type OrderedAttribute = EventHandler | BindingGroup | Binding | Action;
|
|
|
|
|
|
|
|
|
|
|
|
const bindingGroups = events
|
|
|
|
const bindingGroups = events
|
|
|
|
.map(event => ({
|
|
|
|
.map((event) => ({
|
|
|
|
events: event.event_names,
|
|
|
|
events: event.event_names,
|
|
|
|
bindings: this.bindings
|
|
|
|
bindings: this.bindings
|
|
|
|
.filter(binding => binding.node.name !== 'this')
|
|
|
|
.filter((binding) => binding.node.name !== 'this')
|
|
|
|
.filter(binding => event.filter(this.node, binding.node.name))
|
|
|
|
.filter((binding) => event.filter(this.node, binding.node.name)),
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
.filter(group => group.bindings.length);
|
|
|
|
.filter((group) => group.bindings.length);
|
|
|
|
|
|
|
|
|
|
|
|
const this_binding = this.bindings.find(b => b.node.name === 'this');
|
|
|
|
const this_binding = this.bindings.find((b) => b.node.name === 'this');
|
|
|
|
|
|
|
|
|
|
|
|
function getOrder(item: OrderedAttribute) {
|
|
|
|
function getOrder(item: OrderedAttribute) {
|
|
|
|
if (item instanceof EventHandler) {
|
|
|
|
if (item instanceof EventHandler) {
|
|
|
@ -466,15 +446,10 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
([
|
|
|
|
([...bindingGroups, ...this.event_handlers, this_binding, ...this.node.actions] as OrderedAttribute[])
|
|
|
|
...bindingGroups,
|
|
|
|
|
|
|
|
...this.event_handlers,
|
|
|
|
|
|
|
|
this_binding,
|
|
|
|
|
|
|
|
...this.node.actions
|
|
|
|
|
|
|
|
] as OrderedAttribute[])
|
|
|
|
|
|
|
|
.filter(Boolean)
|
|
|
|
.filter(Boolean)
|
|
|
|
.sort((a, b) => getOrder(a) - getOrder(b))
|
|
|
|
.sort((a, b) => getOrder(a) - getOrder(b))
|
|
|
|
.forEach(item => {
|
|
|
|
.forEach((item) => {
|
|
|
|
if (item instanceof EventHandler) {
|
|
|
|
if (item instanceof EventHandler) {
|
|
|
|
add_event_handler(block, this.var, item);
|
|
|
|
add_event_handler(block, this.var, item);
|
|
|
|
} else if (item instanceof Binding) {
|
|
|
|
} else if (item instanceof Binding) {
|
|
|
@ -494,23 +469,23 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
|
|
|
|
|
|
|
|
renderer.component.has_reactive_assignments = true;
|
|
|
|
renderer.component.has_reactive_assignments = true;
|
|
|
|
|
|
|
|
|
|
|
|
const lock = bindingGroup.bindings.some(binding => binding.needs_lock) ?
|
|
|
|
const lock = bindingGroup.bindings.some((binding) => binding.needs_lock)
|
|
|
|
block.get_unique_name(`${this.var.name}_updating`) :
|
|
|
|
? block.get_unique_name(`${this.var.name}_updating`)
|
|
|
|
null;
|
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
|
|
if (lock) block.add_variable(lock, x`false`);
|
|
|
|
if (lock) block.add_variable(lock, x`false`);
|
|
|
|
|
|
|
|
|
|
|
|
[bindingGroup].forEach(group => {
|
|
|
|
[bindingGroup].forEach((group) => {
|
|
|
|
const handler = renderer.component.get_unique_name(`${this.var.name}_${group.events.join('_')}_handler`);
|
|
|
|
const handler = renderer.component.get_unique_name(`${this.var.name}_${group.events.join('_')}_handler`);
|
|
|
|
renderer.add_to_context(handler.name);
|
|
|
|
renderer.add_to_context(handler.name);
|
|
|
|
|
|
|
|
|
|
|
|
// TODO figure out how to handle locks
|
|
|
|
// TODO figure out how to handle locks
|
|
|
|
const needs_lock = group.bindings.some(binding => binding.needs_lock);
|
|
|
|
const needs_lock = group.bindings.some((binding) => binding.needs_lock);
|
|
|
|
|
|
|
|
|
|
|
|
const dependencies: Set<string> = new Set();
|
|
|
|
const dependencies: Set<string> = new Set();
|
|
|
|
const contextual_dependencies: Set<string> = new Set();
|
|
|
|
const contextual_dependencies: Set<string> = new Set();
|
|
|
|
|
|
|
|
|
|
|
|
group.bindings.forEach(binding => {
|
|
|
|
group.bindings.forEach((binding) => {
|
|
|
|
// TODO this is a mess
|
|
|
|
// TODO this is a mess
|
|
|
|
add_to_set(dependencies, binding.get_dependencies());
|
|
|
|
add_to_set(dependencies, binding.get_dependencies());
|
|
|
|
add_to_set(contextual_dependencies, binding.node.expression.contextual_dependencies);
|
|
|
|
add_to_set(contextual_dependencies, binding.node.expression.contextual_dependencies);
|
|
|
@ -534,7 +509,7 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
|
|
|
|
|
|
|
|
// TODO dry this out — similar code for event handlers and component bindings
|
|
|
|
// TODO dry this out — similar code for event handlers and component bindings
|
|
|
|
if (has_local_function) {
|
|
|
|
if (has_local_function) {
|
|
|
|
const args = Array.from(contextual_dependencies).map(name => renderer.reference(name));
|
|
|
|
const args = Array.from(contextual_dependencies).map((name) => renderer.reference(name));
|
|
|
|
|
|
|
|
|
|
|
|
// need to create a block-local function that calls an instance-level function
|
|
|
|
// need to create a block-local function that calls an instance-level function
|
|
|
|
if (animation_frame) {
|
|
|
|
if (animation_frame) {
|
|
|
@ -560,22 +535,22 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
callee = handler;
|
|
|
|
callee = handler;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const params = Array.from(contextual_dependencies).map(name => ({
|
|
|
|
const params = Array.from(contextual_dependencies).map((name) => ({
|
|
|
|
type: 'Identifier',
|
|
|
|
type: 'Identifier',
|
|
|
|
name
|
|
|
|
name,
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
this.renderer.component.partly_hoisted.push(b`
|
|
|
|
this.renderer.component.partly_hoisted.push(b`
|
|
|
|
function ${handler}(${params}) {
|
|
|
|
function ${handler}(${params}) {
|
|
|
|
${group.bindings.map(b => b.handler.mutation)}
|
|
|
|
${group.bindings.map((b) => b.handler.mutation)}
|
|
|
|
${Array.from(dependencies)
|
|
|
|
${Array.from(dependencies)
|
|
|
|
.filter(dep => dep[0] !== '$')
|
|
|
|
.filter((dep) => dep[0] !== '$')
|
|
|
|
.filter(dep => !contextual_dependencies.has(dep))
|
|
|
|
.filter((dep) => !contextual_dependencies.has(dep))
|
|
|
|
.map(dep => b`${this.renderer.invalidate(dep)};`)}
|
|
|
|
.map((dep) => b`${this.renderer.invalidate(dep)};`)}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
group.events.forEach(name => {
|
|
|
|
group.events.forEach((name) => {
|
|
|
|
if (name === 'elementresize') {
|
|
|
|
if (name === 'elementresize') {
|
|
|
|
// special case
|
|
|
|
// special case
|
|
|
|
const resize_listener = block.get_unique_name(`${this.var.name}_resize_listener`);
|
|
|
|
const resize_listener = block.get_unique_name(`${this.var.name}_resize_listener`);
|
|
|
@ -585,43 +560,34 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
|
|
|
|
b`${resize_listener} = @add_resize_listener(${this.var}, ${callee}.bind(${this.var}));`
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.destroy.push(
|
|
|
|
block.chunks.destroy.push(b`${resize_listener}();`);
|
|
|
|
b`${resize_listener}();`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
block.event_listeners.push(
|
|
|
|
block.event_listeners.push(x`@listen(${this.var}, "${name}", ${callee})`);
|
|
|
|
x`@listen(${this.var}, "${name}", ${callee})`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const some_initial_state_is_undefined = group.bindings
|
|
|
|
const some_initial_state_is_undefined = group.bindings
|
|
|
|
.map(binding => x`${binding.snippet} === void 0`)
|
|
|
|
.map((binding) => x`${binding.snippet} === void 0`)
|
|
|
|
.reduce((lhs, rhs) => x`${lhs} || ${rhs}`);
|
|
|
|
.reduce((lhs, rhs) => x`${lhs} || ${rhs}`);
|
|
|
|
|
|
|
|
|
|
|
|
const should_initialise = (
|
|
|
|
const should_initialise =
|
|
|
|
this.node.name === 'select' ||
|
|
|
|
this.node.name === 'select' ||
|
|
|
|
group.bindings.find(binding => {
|
|
|
|
group.bindings.find((binding) => {
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
binding.node.name === 'indeterminate' ||
|
|
|
|
binding.node.name === 'indeterminate' ||
|
|
|
|
binding.node.name === 'textContent' ||
|
|
|
|
binding.node.name === 'textContent' ||
|
|
|
|
binding.node.name === 'innerHTML' ||
|
|
|
|
binding.node.name === 'innerHTML' ||
|
|
|
|
binding.is_readonly_media_attribute()
|
|
|
|
binding.is_readonly_media_attribute()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
})
|
|
|
|
});
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (should_initialise) {
|
|
|
|
if (should_initialise) {
|
|
|
|
const callback = has_local_function ? handler : x`() => ${callee}.call(${this.var})`;
|
|
|
|
const callback = has_local_function ? handler : x`() => ${callee}.call(${this.var})`;
|
|
|
|
block.chunks.hydrate.push(
|
|
|
|
block.chunks.hydrate.push(b`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});`);
|
|
|
|
b`if (${some_initial_state_is_undefined}) @add_render_callback(${callback});`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (group.events[0] === 'elementresize') {
|
|
|
|
if (group.events[0] === 'elementresize') {
|
|
|
|
block.chunks.hydrate.push(
|
|
|
|
block.chunks.hydrate.push(b`@add_render_callback(() => ${callee}.call(${this.var}));`);
|
|
|
|
b`@add_render_callback(() => ${callee}.call(${this.var}));`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
@ -648,7 +614,7 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (this.node.attributes.some(attr => attr.is_spread)) {
|
|
|
|
if (this.node.attributes.some((attr) => attr.is_spread)) {
|
|
|
|
this.add_spread_attributes(block);
|
|
|
|
this.add_spread_attributes(block);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -665,11 +631,9 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
const initial_props = [];
|
|
|
|
const initial_props = [];
|
|
|
|
const updates = [];
|
|
|
|
const updates = [];
|
|
|
|
|
|
|
|
|
|
|
|
this.attributes
|
|
|
|
this.attributes.forEach((attr) => {
|
|
|
|
.forEach(attr => {
|
|
|
|
const condition =
|
|
|
|
const condition = attr.node.dependencies.size > 0
|
|
|
|
attr.node.dependencies.size > 0 ? block.renderer.dirty(Array.from(attr.node.dependencies)) : null;
|
|
|
|
? block.renderer.dirty(Array.from(attr.node.dependencies))
|
|
|
|
|
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (attr.node.is_spread) {
|
|
|
|
if (attr.node.is_spread) {
|
|
|
|
const snippet = attr.node.expression.manipulate(block);
|
|
|
|
const snippet = attr.node.expression.manipulate(block);
|
|
|
@ -700,181 +664,114 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
|
|
|
|
|
|
|
|
const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`;
|
|
|
|
const fn = this.node.namespace === namespaces.svg ? x`@set_svg_attributes` : x`@set_attributes`;
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.hydrate.push(
|
|
|
|
block.chunks.hydrate.push(b`${fn}(${this.var}, ${data});`);
|
|
|
|
b`${fn}(${this.var}, ${data});`
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.update.push(b`
|
|
|
|
block.chunks.update.push(b`${fn}(${this.var}, @get_spread_update(${levels}, [${updates}]));`);
|
|
|
|
${fn}(${this.var}, @get_spread_update(${levels}, [
|
|
|
|
|
|
|
|
${updates}
|
|
|
|
|
|
|
|
]));
|
|
|
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
add_bidi_transition(block: Block, intro: Transition) {
|
|
|
|
add_transitions(
|
|
|
|
const name = block.get_unique_name(`${this.var.name}_bidi_transition`);
|
|
|
|
block: Block
|
|
|
|
const snippet = intro.expression ? intro.expression.manipulate(block) : x`{}`;
|
|
|
|
) {
|
|
|
|
|
|
|
|
const { intro, outro } = this.node;
|
|
|
|
|
|
|
|
if (!intro && !outro) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intro === outro) {
|
|
|
|
|
|
|
|
// bidirectional transition
|
|
|
|
|
|
|
|
const name = block.get_unique_name(`${this.var.name}_transition`);
|
|
|
|
|
|
|
|
const snippet = intro.expression
|
|
|
|
|
|
|
|
? intro.expression.manipulate(block)
|
|
|
|
|
|
|
|
: x`{}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.add_variable(name);
|
|
|
|
block.add_variable(name);
|
|
|
|
|
|
|
|
|
|
|
|
const fn = this.renderer.reference(intro.name);
|
|
|
|
const fn = this.renderer.reference(intro.name);
|
|
|
|
|
|
|
|
|
|
|
|
const intro_block = b`
|
|
|
|
let intro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, true, ${snippet});`;
|
|
|
|
@add_render_callback(() => {
|
|
|
|
|
|
|
|
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, true);
|
|
|
|
|
|
|
|
${name}.run(1);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const outro_block = b`
|
|
|
|
let outro_block = b`${name} = @run_bidirectional_transition(${this.var}, ${fn}, false, ${snippet});`;
|
|
|
|
if (!${name}) ${name} = @create_bidirectional_transition(${this.var}, ${fn}, ${snippet}, false);
|
|
|
|
|
|
|
|
${name}.run(0);
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intro.is_local) {
|
|
|
|
if (intro.is_local) {
|
|
|
|
block.chunks.intro.push(b`
|
|
|
|
intro_block = b`if (#local) {${intro_block}}`;
|
|
|
|
if (#local) {
|
|
|
|
outro_block = b`if (#local) {${outro_block}}`;
|
|
|
|
${intro_block}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.outro.push(b`
|
|
|
|
|
|
|
|
if (#local) {
|
|
|
|
|
|
|
|
${outro_block}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
`);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
block.chunks.intro.push(intro_block);
|
|
|
|
block.chunks.intro.push(intro_block);
|
|
|
|
block.chunks.outro.push(outro_block);
|
|
|
|
block.chunks.outro.push(outro_block);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.destroy.push(b`if (detaching && ${name}) ${name}.end();`);
|
|
|
|
block.chunks.destroy.push(b`if (detaching && ${name}) ${name}();`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
add_intro(block: Block, intro: Transition, outro: Transition) {
|
|
|
|
else {
|
|
|
|
|
|
|
|
const intro_name = intro && block.get_unique_name(`${this.var.name}_intro`);
|
|
|
|
|
|
|
|
const outro_name = outro && block.get_unique_name(`${this.var.name}_outro`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intro) {
|
|
|
|
|
|
|
|
block.add_variable(intro_name);
|
|
|
|
|
|
|
|
const snippet = intro.expression
|
|
|
|
|
|
|
|
? intro.expression.manipulate(block)
|
|
|
|
|
|
|
|
: x`{}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const fn = this.renderer.reference(intro.name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let intro_block;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (outro) {
|
|
|
|
if (outro) {
|
|
|
|
intro_block = b`
|
|
|
|
const outro_var = block.alias(`${this.var.name}_outro`);
|
|
|
|
@add_render_callback(() => {
|
|
|
|
if (this.node.animation) {
|
|
|
|
if (${outro_name}) ${outro_name}.end(1);
|
|
|
|
const [unfreeze_var, rect_var, stop_animation_var, animationFn, params] = run_animation(this, block);
|
|
|
|
if (!${intro_name}) ${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
|
|
|
|
block.chunks.intro.push(b`
|
|
|
|
${intro_name}.start();
|
|
|
|
if (${outro_var}){
|
|
|
|
});
|
|
|
|
${outro_var}(1);
|
|
|
|
`;
|
|
|
|
if (${unfreeze_var}) {
|
|
|
|
|
|
|
|
${unfreeze_var}(), (unfreeze = undefined);
|
|
|
|
block.chunks.outro.push(b`if (${intro_name}) ${intro_name}.invalidate();`);
|
|
|
|
${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${animationFn}, ${params});
|
|
|
|
} else {
|
|
|
|
|
|
|
|
intro_block = b`
|
|
|
|
|
|
|
|
if (!${intro_name}) {
|
|
|
|
|
|
|
|
@add_render_callback(() => {
|
|
|
|
|
|
|
|
${intro_name} = @create_in_transition(${this.var}, ${fn}, ${snippet});
|
|
|
|
|
|
|
|
${intro_name}.start();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (intro.is_local) {
|
|
|
|
|
|
|
|
intro_block = b`
|
|
|
|
|
|
|
|
if (#local) {
|
|
|
|
|
|
|
|
${intro_block}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.intro.push(intro_block);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
`);
|
|
|
|
if (outro) {
|
|
|
|
} else {
|
|
|
|
block.add_variable(outro_name);
|
|
|
|
|
|
|
|
const snippet = outro.expression
|
|
|
|
|
|
|
|
? outro.expression.manipulate(block)
|
|
|
|
|
|
|
|
: x`{}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const fn = this.renderer.reference(outro.name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!intro) {
|
|
|
|
|
|
|
|
block.chunks.intro.push(b`
|
|
|
|
block.chunks.intro.push(b`
|
|
|
|
if (${outro_name}) ${outro_name}.end(1);
|
|
|
|
if (${outro_var}){
|
|
|
|
|
|
|
|
${outro_var}(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!intro) return;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO hide elements that have outro'd (unless they belong to a still-outroing
|
|
|
|
const [intro_var, node, transitionFn, params] = run_transition(this, block, intro, `intro`);
|
|
|
|
// group) prior to their removal from the DOM
|
|
|
|
block.add_variable(intro_var);
|
|
|
|
let outro_block = b`
|
|
|
|
|
|
|
|
${outro_name} = @create_out_transition(${this.var}, ${fn}, ${snippet});
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (outro.is_local) {
|
|
|
|
let start_intro = b`@add_render_callback(()=>{${intro_var} = @run_transition(${node}, ${transitionFn}, true, ${params});})`;
|
|
|
|
outro_block = b`
|
|
|
|
if (intro.is_local) start_intro = b`if (#local) ${start_intro};`;
|
|
|
|
if (#local) {
|
|
|
|
block.chunks.intro.push(start_intro);
|
|
|
|
${outro_block}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// hide elements that have outro'd prior to their removal from the DOM
|
|
|
|
|
|
|
|
// ( ...unless they belong to a still-outroing group )
|
|
|
|
|
|
|
|
add_outro(block: Block, intro: Transition, outro: Transition) {
|
|
|
|
|
|
|
|
if (intro) {
|
|
|
|
|
|
|
|
const intro_var = block.alias(`${this.var.name}_intro`);
|
|
|
|
|
|
|
|
block.chunks.outro.push(b`if (${intro_var}) ${intro_var}();`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!outro) return;
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.outro.push(outro_block);
|
|
|
|
const [outro_var, node, transitionFn, params] = run_transition(this, block, outro, `outro`);
|
|
|
|
|
|
|
|
block.add_variable(outro_var);
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.destroy.push(b`if (detaching && ${outro_name}) ${outro_name}.end();`);
|
|
|
|
let start_outro = b`${outro_var} = @run_transition(${node}, ${transitionFn}, false, ${params});`;
|
|
|
|
}
|
|
|
|
if (intro.is_local) start_outro = b`if (#local) ${start_outro};`;
|
|
|
|
}
|
|
|
|
block.chunks.outro.push(start_outro);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add_animation(block: Block) {
|
|
|
|
block.chunks.destroy.push(b`if (detaching && ${outro_var}) ${outro_var}();`);
|
|
|
|
if (!this.node.animation) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { outro } = this.node;
|
|
|
|
add_animation(block: Block, intro: Transition, outro: Transition) {
|
|
|
|
|
|
|
|
const intro_var = intro && block.alias(`${this.var.name}_intro`);
|
|
|
|
|
|
|
|
|
|
|
|
const rect = block.get_unique_name('rect');
|
|
|
|
const [unfreeze_var, rect_var, stop_animation_var, name_var, params_var] = run_animation(this, block);
|
|
|
|
const stop_animation = block.get_unique_name('stop_animation');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.add_variable(rect);
|
|
|
|
block.add_variable(unfreeze_var);
|
|
|
|
block.add_variable(stop_animation, x`@noop`);
|
|
|
|
block.add_variable(rect_var);
|
|
|
|
|
|
|
|
block.add_variable(stop_animation_var, x`@noop`);
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.measure.push(b`
|
|
|
|
block.chunks.measure.push(b`
|
|
|
|
${rect} = ${this.var}.getBoundingClientRect();
|
|
|
|
${rect_var} = ${this.var}.getBoundingClientRect();
|
|
|
|
|
|
|
|
${intro && b`if(${intro_var}) ${intro_var}();`}
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.fix.push(b`
|
|
|
|
block.chunks.fix.push(b`
|
|
|
|
@fix_position(${this.var});
|
|
|
|
${unfreeze_var} = @fix_position(${this.var});
|
|
|
|
${stop_animation}();
|
|
|
|
${stop_animation_var}();
|
|
|
|
${outro && b`@add_transform(${this.var}, ${rect});`}
|
|
|
|
${outro && b`@add_transform(${this.var}, ${rect_var});`}
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
const params = this.node.animation.expression ? this.node.animation.expression.manipulate(block) : x`{}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const name = this.renderer.reference(this.node.animation.name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.animate.push(b`
|
|
|
|
block.chunks.animate.push(b`
|
|
|
|
${stop_animation}();
|
|
|
|
if(${unfreeze_var}) return
|
|
|
|
${stop_animation} = @create_animation(${this.var}, ${rect}, ${name}, ${params});
|
|
|
|
${stop_animation_var}();
|
|
|
|
|
|
|
|
@add_render_callback(()=>{${stop_animation_var} = @run_animation(${this.var}, ${rect_var}, ${name_var}, ${params_var});});
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
block.chunks.destroy.push(b`${unfreeze_var} = undefined;`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
add_classes(block: Block) {
|
|
|
|
add_classes(block: Block) {
|
|
|
|
const has_spread = this.node.attributes.some(attr => attr.is_spread);
|
|
|
|
const has_spread = this.node.attributes.some((attr) => attr.is_spread);
|
|
|
|
this.node.classes.forEach(class_directive => {
|
|
|
|
this.node.classes.forEach((class_directive) => {
|
|
|
|
const { expression, name } = class_directive;
|
|
|
|
const { expression, name } = class_directive;
|
|
|
|
let snippet;
|
|
|
|
let snippet;
|
|
|
|
let dependencies;
|
|
|
|
let dependencies;
|
|
|
@ -912,46 +809,42 @@ export default class ElementWrapper extends Wrapper {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function to_html(wrappers: Array<ElementWrapper | TextWrapper | TagWrapper>, block: Block, literal: any, state: any, can_use_raw_text?: boolean) {
|
|
|
|
function to_html(
|
|
|
|
wrappers.forEach(wrapper => {
|
|
|
|
wrappers: Array<ElementWrapper | TextWrapper | TagWrapper>,
|
|
|
|
|
|
|
|
block: Block,
|
|
|
|
|
|
|
|
literal: any,
|
|
|
|
|
|
|
|
state: any,
|
|
|
|
|
|
|
|
can_use_raw_text?: boolean
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
wrappers.forEach((wrapper) => {
|
|
|
|
if (wrapper.node.type === 'Text') {
|
|
|
|
if (wrapper.node.type === 'Text') {
|
|
|
|
if ((wrapper as TextWrapper).use_space()) state.quasi.value.raw += ' ';
|
|
|
|
if ((wrapper as TextWrapper).use_space()) state.quasi.value.raw += ' ';
|
|
|
|
|
|
|
|
|
|
|
|
const parent = wrapper.node.parent as Element;
|
|
|
|
const parent = wrapper.node.parent as Element;
|
|
|
|
|
|
|
|
|
|
|
|
const raw = parent && (
|
|
|
|
const raw = parent && (parent.name === 'script' || parent.name === 'style' || can_use_raw_text);
|
|
|
|
parent.name === 'script' ||
|
|
|
|
|
|
|
|
parent.name === 'style' ||
|
|
|
|
|
|
|
|
can_use_raw_text
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.quasi.value.raw += (raw ? wrapper.node.data : escape_html(wrapper.node.data))
|
|
|
|
state.quasi.value.raw += (raw ? wrapper.node.data : escape_html(wrapper.node.data))
|
|
|
|
.replace(/\\/g, '\\\\')
|
|
|
|
.replace(/\\/g, '\\\\')
|
|
|
|
.replace(/`/g, '\\`')
|
|
|
|
.replace(/`/g, '\\`')
|
|
|
|
.replace(/\$/g, '\\$');
|
|
|
|
.replace(/\$/g, '\\$');
|
|
|
|
}
|
|
|
|
} else if (wrapper.node.type === 'MustacheTag' || wrapper.node.type === 'RawMustacheTag') {
|
|
|
|
|
|
|
|
|
|
|
|
else if (wrapper.node.type === 'MustacheTag' || wrapper.node.type === 'RawMustacheTag' ) {
|
|
|
|
|
|
|
|
literal.quasis.push(state.quasi);
|
|
|
|
literal.quasis.push(state.quasi);
|
|
|
|
literal.expressions.push(wrapper.node.expression.manipulate(block));
|
|
|
|
literal.expressions.push(wrapper.node.expression.manipulate(block));
|
|
|
|
state.quasi = {
|
|
|
|
state.quasi = {
|
|
|
|
type: 'TemplateElement',
|
|
|
|
type: 'TemplateElement',
|
|
|
|
value: { raw: '' }
|
|
|
|
value: { raw: '' },
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
} else if (wrapper.node.name === 'noscript') {
|
|
|
|
|
|
|
|
|
|
|
|
else if (wrapper.node.name === 'noscript') {
|
|
|
|
|
|
|
|
// do nothing
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
// element
|
|
|
|
// element
|
|
|
|
state.quasi.value.raw += `<${wrapper.node.name}`;
|
|
|
|
state.quasi.value.raw += `<${wrapper.node.name}`;
|
|
|
|
|
|
|
|
|
|
|
|
(wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => {
|
|
|
|
(wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => {
|
|
|
|
state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`;
|
|
|
|
state.quasi.value.raw += ` ${fix_attribute_casing(attr.node.name)}="`;
|
|
|
|
|
|
|
|
|
|
|
|
attr.node.chunks.forEach(chunk => {
|
|
|
|
attr.node.chunks.forEach((chunk) => {
|
|
|
|
if (chunk.type === 'Text') {
|
|
|
|
if (chunk.type === 'Text') {
|
|
|
|
state.quasi.value.raw += escape_html(chunk.data);
|
|
|
|
state.quasi.value.raw += escape_html(chunk.data);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -960,7 +853,7 @@ function to_html(wrappers: Array<ElementWrapper | TextWrapper | TagWrapper>, blo
|
|
|
|
|
|
|
|
|
|
|
|
state.quasi = {
|
|
|
|
state.quasi = {
|
|
|
|
type: 'TemplateElement',
|
|
|
|
type: 'TemplateElement',
|
|
|
|
value: { raw: '' }
|
|
|
|
value: { raw: '' },
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
@ -971,10 +864,36 @@ function to_html(wrappers: Array<ElementWrapper | TextWrapper | TagWrapper>, blo
|
|
|
|
state.quasi.value.raw += '>';
|
|
|
|
state.quasi.value.raw += '>';
|
|
|
|
|
|
|
|
|
|
|
|
if (!(wrapper as ElementWrapper).void) {
|
|
|
|
if (!(wrapper as ElementWrapper).void) {
|
|
|
|
to_html((wrapper as ElementWrapper).fragment.nodes as Array<ElementWrapper | TextWrapper>, block, literal, state);
|
|
|
|
to_html(
|
|
|
|
|
|
|
|
(wrapper as ElementWrapper).fragment.nodes as Array<ElementWrapper | TextWrapper>,
|
|
|
|
|
|
|
|
block,
|
|
|
|
|
|
|
|
literal,
|
|
|
|
|
|
|
|
state
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
state.quasi.value.raw += `</${wrapper.node.name}>`;
|
|
|
|
state.quasi.value.raw += `</${wrapper.node.name}>`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function run_animation(element: ElementWrapper, block: Block) {
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
|
|
block.alias('unfreeze'),
|
|
|
|
|
|
|
|
block.alias('rect'),
|
|
|
|
|
|
|
|
block.alias('stop_animation'),
|
|
|
|
|
|
|
|
element.renderer.reference(element.node.animation.name),
|
|
|
|
|
|
|
|
element.node.animation.expression ? element.node.animation.expression.manipulate(block) : x`{}`,
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function run_transition(element: ElementWrapper, block: Block, transition: Transition, type: string) {
|
|
|
|
|
|
|
|
// const run = b`
|
|
|
|
|
|
|
|
// 0 = @run_transition(1, `2`, ${
|
|
|
|
|
|
|
|
// type === 'intro' ? `true` : `false`
|
|
|
|
|
|
|
|
// }, ${params});
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
|
|
/* node_intro */ block.alias(`${element.var.name}_${type}`),
|
|
|
|
|
|
|
|
/* node */ element.var,
|
|
|
|
|
|
|
|
/* transitionFn */ element.renderer.reference(transition.name),
|
|
|
|
|
|
|
|
/* params */ transition.expression ? transition.expression.manipulate(block) : x`{}`,
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
}
|
|
|
|