fix: stable attachments

pull/15961/head
Rich Harris 4 months ago
parent 7183886a73
commit ef173e3a1a

@ -104,9 +104,10 @@ export function build_set_attributes(
); );
if (is_dynamic) { if (is_dynamic) {
context.state.init.push(b.let(attributes_id)); context.state.init.push(
const update = b.stmt(b.assignment('=', attributes_id, call)); b.let(attributes_id),
context.state.update.push(update); b.stmt(b.call('$.set_attribute_effect', element_id, b.thunk(b.object(values))))
);
} else { } else {
context.state.init.push(b.stmt(call)); context.state.init.push(b.stmt(call));
} }

@ -5,7 +5,7 @@ import { effect } from '../../reactivity/effects.js';
* @param {() => (node: Element) => void} get_fn * @param {() => (node: Element) => void} get_fn
*/ */
export function attach(node, get_fn) { export function attach(node, get_fn) {
effect(() => { return effect(() => {
const fn = get_fn(); const fn = get_fn();
// we use `&&` rather than `?.` so that things like // we use `&&` rather than `?.` so that things like

@ -18,6 +18,7 @@ import { clsx } from '../../../shared/attributes.js';
import { set_class } from './class.js'; import { set_class } from './class.js';
import { set_style } from './style.js'; import { set_style } from './style.js';
import { ATTACHMENT_KEY, NAMESPACE_HTML } from '../../../../constants.js'; import { ATTACHMENT_KEY, NAMESPACE_HTML } from '../../../../constants.js';
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
export const CLASS = Symbol('class'); export const CLASS = Symbol('class');
export const STYLE = Symbol('style'); export const STYLE = Symbol('style');
@ -456,6 +457,49 @@ export function set_attributes(element, prev, next, css_hash, skip_warning = fal
return current; return current;
} }
/**
* @param {Element & ElementCSSInlineStyle} element
* @param {() => Record<string | symbol, any>} fn
* @param {string} [css_hash]
* @param {boolean} [skip_warning]
*/
export function set_attribute_effect(element, fn, css_hash, skip_warning = false) {
/** @type {Record<string | symbol, any>} */
var prev = {};
/** @type {Record<symbol, import('#client').Effect>} */
var effects = {};
block(() => {
var next = fn();
for (const key in prev) {
if (!next[key]) {
element.removeAttribute(key);
}
}
for (let symbol of Object.getOwnPropertySymbols(prev)) {
if (!next[symbol]) {
destroy_effect(effects[symbol]);
delete effects[symbol];
}
}
for (const key in next) {
set_attribute(element, key, next[key], skip_warning);
}
for (let symbol of Object.getOwnPropertySymbols(next)) {
if (symbol.description === ATTACHMENT_KEY && next[symbol] !== prev[symbol]) {
effects[symbol] = branch(() => attach(element, () => next[symbol]));
}
}
prev = next;
});
}
/** /**
* *
* @param {Element} element * @param {Element} element

@ -28,6 +28,7 @@ export {
remove_input_defaults, remove_input_defaults,
set_attribute, set_attribute,
set_attributes, set_attributes,
set_attribute_effect,
set_custom_element_data, set_custom_element_data,
set_xlink_attribute, set_xlink_attribute,
set_value, set_value,

Loading…
Cancel
Save