From fdecad6cddef0d133d893ca9e0d830ab2a939896 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 6 Jun 2024 14:19:24 -0400 Subject: [PATCH] chore: better bind_property implementation (#11904) - better name for bidirectional bindings - cleanup implementation --- .../3-transform/client/visitors/template.js | 5 ++- .../svelte/src/compiler/phases/bindings.js | 6 ++-- .../client/dom/elements/bindings/universal.js | 36 +++++++++---------- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index e7bd5765f..195f06486 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -2747,10 +2747,9 @@ export const template_visitors = { '$.bind_property', b.literal(node.name), b.literal(property.event), - b.literal(property.type ?? 'get'), state.node, - getter, - setter + setter, + property.bidirectional && getter ); } else { // special cases diff --git a/packages/svelte/src/compiler/phases/bindings.js b/packages/svelte/src/compiler/phases/bindings.js index ad998b3ab..eee84473a 100644 --- a/packages/svelte/src/compiler/phases/bindings.js +++ b/packages/svelte/src/compiler/phases/bindings.js @@ -2,7 +2,7 @@ * @typedef BindingProperty * @property {string} [event] This is set if the binding corresponds to the property name on the dom element it's bound to * and there's an event that notifies of a change to that property - * @property {string} [type] Set this to `set` if updates are written to the dom property + * @property {boolean} [bidirectional] Set this to `true` if updates are written to the dom property * @property {boolean} [omit_in_ssr] Set this to true if the binding should not be included in SSR * @property {string[]} [valid_elements] If this is set, the binding is only valid on the given elements * @property {string[]} [invalid_elements] If this is set, the binding is invalid on the given elements @@ -175,7 +175,7 @@ export const binding_properties = { // checkbox/radio indeterminate: { event: 'change', - type: 'set', + bidirectional: true, valid_elements: ['input'], omit_in_ssr: true // no corresponding attribute }, @@ -200,7 +200,7 @@ export const binding_properties = { }, open: { event: 'toggle', - type: 'set', + bidirectional: true, valid_elements: ['details'] }, value: { diff --git a/packages/svelte/src/internal/client/dom/elements/bindings/universal.js b/packages/svelte/src/internal/client/dom/elements/bindings/universal.js index f42f67d59..7e8b3f3bf 100644 --- a/packages/svelte/src/internal/client/dom/elements/bindings/universal.js +++ b/packages/svelte/src/internal/client/dom/elements/bindings/universal.js @@ -33,40 +33,36 @@ export function bind_content_editable(property, element, get_value, update) { /** * @param {string} property * @param {string} event_name - * @param {'get' | 'set'} type * @param {Element} element - * @param {() => unknown} get_value - * @param {(value: unknown) => void} update + * @param {(value: unknown) => void} set + * @param {() => unknown} [get] * @returns {void} */ -export function bind_property(property, event_name, type, element, get_value, update) { - var target_handler = () => { +export function bind_property(property, event_name, element, set, get) { + var handler = () => { // @ts-ignore - update(element[property]); + set(element[property]); }; - element.addEventListener(event_name, target_handler); + element.addEventListener(event_name, handler); - if (type === 'set') { + if (get) { render_effect(() => { // @ts-ignore - element[property] = get_value(); + element[property] = get(); }); + } else { + handler(); } - if (type === 'get') { - // @ts-ignore - update(element[property]); - } - - render_effect(() => { - // @ts-ignore - if (element === document.body || element === window || element === document) { + // @ts-ignore + if (element === document.body || element === window || element === document) { + render_effect(() => { return () => { - element.removeEventListener(event_name, target_handler); + element.removeEventListener(event_name, handler); }; - } - }); + }); + } } /**