diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js index 2928ca9173..4c248cb19c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js @@ -7,7 +7,7 @@ import { dev, locator } from '../../../../state.js'; import * as b from '#compiler/builders'; import { clean_nodes, determine_namespace_for_children } from '../../utils.js'; import { build_element_attributes } from './shared/element.js'; -import { process_children, build_template } from './shared/utils.js'; +import { process_children, build_template, build_attribute_value } from './shared/utils.js'; /** * @param {AST.RegularElement} node @@ -71,6 +71,42 @@ export function RegularElement(node, context) { ); } + let select_with_value = false; + + if (node.name === 'select') { + const value = node.attributes.find( + (attribute) => + ((attribute.type === 'Attribute' || attribute.type === 'BindDirective') && + attribute.name === 'value') || + attribute.type === 'SpreadAttribute' + ); + if (value) { + select_with_value = true; + const left = b.id('$$payload.select_value'); + if (value.type === 'SpreadAttribute') { + state.template.push( + b.stmt(b.assignment('=', left, b.member(value.expression, 'value', false, true))) + ); + } else if (value.type === 'Attribute') { + state.template.push( + b.stmt(b.assignment('=', left, build_attribute_value(value.value, context))) + ); + } else if (value.type === 'BindDirective') { + state.template.push( + b.stmt( + b.assignment( + '=', + left, + value.expression.type === 'SequenceExpression' + ? b.call(value.expression.expressions[0]) + : value.expression + ) + ) + ); + } + } + } + if (body === null) { process_children(trimmed, { ...context, state }); } else { @@ -96,6 +132,10 @@ export function RegularElement(node, context) { ); } + if (select_with_value) { + state.template.push(b.stmt(b.assignment('=', b.id('$$payload.select_value'), b.void0))); + } + if (!node_is_void) { state.template.push(b.literal(``)); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js index b0bcb8fd6f..e57afbb42a 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js @@ -236,6 +236,16 @@ export function build_element_attributes(node, context) { ); } + if (node.name === 'option' && name === 'value') { + context.state.template.push( + b.call( + '$.maybe_selected', + b.id('$$payload'), + literal_value != null ? b.literal(/** @type {any} */ (literal_value)) : b.void0 + ) + ); + } + continue; } @@ -260,6 +270,10 @@ export function build_element_attributes(node, context) { b.call('$.attr', b.literal(name), value, is_boolean_attribute(name) && b.true) ); } + + if (name === 'value' && node.name === 'option') { + context.state.template.push(b.call('$.maybe_selected', b.id('$$payload'), value)); + } } } diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index 29e09fe4dd..a815d0755e 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -535,3 +535,12 @@ export function derived(fn) { return updated_value; }; } + +/** + * + * @param {Payload} payload + * @param {*} value + */ +export function maybe_selected(payload, value) { + return value === payload.select_value ? ' selected' : ''; +} diff --git a/packages/svelte/src/internal/server/payload.js b/packages/svelte/src/internal/server/payload.js index 8df5787ba4..a31120ae16 100644 --- a/packages/svelte/src/internal/server/payload.js +++ b/packages/svelte/src/internal/server/payload.js @@ -18,6 +18,7 @@ export class Payload { css = new Set(); out = ''; uid = () => ''; + select_value = undefined; head = new HeadPayload(); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js index 335c46d53d..842d8e855c 100644 --- a/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js +++ b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js @@ -4,7 +4,7 @@ import { ok, test } from '../../test'; export default test({ html: ` selected: a diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html b/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html new file mode 100644 index 0000000000..96d1d8b233 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/select-value/_expected.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte b/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte new file mode 100644 index 0000000000..811d752d4e --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/select-value/main.svelte @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js index a587c05e2c..0532ec5aa9 100644 --- a/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/skip-static-subtree/_expected/server/index.svelte.js @@ -3,5 +3,5 @@ import * as $ from 'svelte/internal/server'; export default function Skip_static_subtree($$payload, $$props) { let { title, content } = $$props; - $$payload.out += `

${$.escape(title)}

we don't need to traverse these nodes

or

these

ones

${$.html(content)}

these

trailing

nodes

can

be

completely

ignored

`; + $$payload.out += `

${$.escape(title)}

we don't need to traverse these nodes

or

these

ones

${$.html(content)}

these

trailing

nodes

can

be

completely

ignored

`; } \ No newline at end of file