fix: render `selected` options for `<select multiple>` with an array `value` on the server (#18720)

Follow-up to #18591.

---------

Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
pull/18722/head
Nic Polumeyv 3 days ago committed by GitHub
parent 864de81bb6
commit 2e8b57bc58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -89,7 +89,7 @@ export class Renderer {
* State that is local to the branch it is declared in.
* It will be shallow-copied to all children.
*
* @type {{ select_value: any, select_default_multiple: boolean }}
* @type {{ select_value: any, multiple: boolean }}
*/
local;
@ -101,9 +101,7 @@ export class Renderer {
this.#parent = parent;
this.global = global;
this.local = parent
? { ...parent.local }
: { select_value: undefined, select_default_multiple: false };
this.local = parent ? { ...parent.local } : { select_value: undefined, multiple: false };
this.type = parent ? parent.type : 'body';
}
@ -346,8 +344,7 @@ export class Renderer {
this.push(`<select${attributes(select_attrs, css_hash, classes, styles, flags)}>`);
this.child((renderer) => {
renderer.local.select_value = value === undefined ? defaultValue : value;
renderer.local.select_default_multiple =
value === undefined && Boolean(select_attrs.multiple);
renderer.local.multiple = !!select_attrs.multiple;
fn(renderer);
});
this.push(`${is_rich ? '<!>' : ''}</select>`);
@ -375,10 +372,14 @@ export class Renderer {
value = attrs.value;
}
var select_value = this.local.select_value;
if (
this.local.select_default_multiple
? is_array(this.local.select_value) && this.local.select_value.includes(value)
: value === this.local.select_value
// Super edge-case, but theoretically someone could use arrays with non-multiple selects,
// so we gotta check for the multiple attribute presence, too.
this.local.multiple && is_array(select_value)
? select_value.includes(value)
: value === select_value
) {
renderer.#out.push(' selected=""');
}

@ -6,17 +6,30 @@ export default test({
return { selected: ['two', 'three'] };
},
html: `
ssrHtml: `
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option selected>two</option>
<option selected>three</option>
</select>
<p>selected: two, three</p>
`,
test({ assert, component, target, window }) {
test({ assert, component, target, window, variant }) {
const selected = variant === 'hydrate' ? ' selected' : '';
assert.htmlEqual(
target.innerHTML,
`
<select multiple>
<option>one</option>
<option${selected}>two</option>
<option${selected}>three</option>
</select>
<p>selected: two, three</p>
`
);
const select = target.querySelector('select');
ok(select);
const options = [...target.querySelectorAll('option')];
@ -33,8 +46,8 @@ export default test({
`
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option${selected}>two</option>
<option${selected}>three</option>
</select>
<p>selected: three</p>
@ -51,8 +64,8 @@ export default test({
`
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option${selected}>two</option>
<option${selected}>three</option>
</select>
<p>selected: one, three</p>
@ -70,8 +83,8 @@ export default test({
`
<select multiple>
<option>one</option>
<option>two</option>
<option>three</option>
<option${selected}>two</option>
<option${selected}>three</option>
</select>
<p>selected: one, two</p>

@ -0,0 +1,5 @@
<select multiple="">
<option selected="" value="a">A</option>
<option value="b">B</option>
<option selected="" value="c">C</option>
</select>

@ -0,0 +1,5 @@
<select multiple value={['a', 'c']}>
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
</select>
Loading…
Cancel
Save