diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts index 9e22179f39..dfe7accb90 100644 --- a/src/compiler/compile/nodes/Binding.ts +++ b/src/compiler/compile/nodes/Binding.ts @@ -3,7 +3,7 @@ import get_object from '../utils/get_object'; import Expression from './shared/Expression'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; -import { dimensions, sizing } from '../../utils/patterns'; +import { dimensions, sizing_border_box, sizing_content_box, sizing_device_pixel_content_box } from '../../utils/patterns'; import { Node as ESTreeNode } from 'estree'; import { TemplateNode } from '../../interfaces'; import Element from './Element'; @@ -86,7 +86,10 @@ export default class Binding extends Node { const type = parent.get_static_attribute_value('type'); this.is_readonly = - dimensions.test(this.name) || sizing.test(this.name) || + dimensions.test(this.name) || + sizing_border_box.test(this.name) || + sizing_content_box.test(this.name) || + sizing_device_pixel_content_box.test(this.name) || (isElement(parent) && ((parent.is_media_node() && read_only_media_attributes.has(this.name)) || (parent.name === 'input' && type === 'file')) /* TODO others? */); diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index c79ae96288..cdbf4a2f13 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -11,7 +11,7 @@ import StyleDirective from './StyleDirective'; import Text from './Text'; import { namespaces } from '../../utils/namespaces'; import map_children from './shared/map_children'; -import { dimensions, sizing } from '../../utils/patterns'; +import { dimensions, sizing_border_box, sizing_content_box, sizing_device_pixel_content_box } from '../../utils/patterns'; import fuzzymatch from '../../utils/fuzzymatch'; import list from '../../utils/list'; import Let from './Let'; @@ -734,7 +734,12 @@ export default class Element extends Node { } else if (contenteditable && !contenteditable.is_static) { return component.error(contenteditable, compiler_errors.dynamic_contenteditable_attribute); } - } else if (name !== 'this' && !sizing.test(name)) { + } else if ( + name !== 'this' && + !sizing_border_box.test(name) && + !sizing_content_box.test(name) && + !sizing_device_pixel_content_box.test(name) + ) { return component.error(binding, compiler_errors.invalid_binding(binding.name)); } }); diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 8c348ecc1f..bc218a510b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -11,7 +11,6 @@ import { Node, Identifier } from 'estree'; import add_to_set from '../../../utils/add_to_set'; import mark_each_block_bindings from '../shared/mark_each_block_bindings'; import handle_select_value_binding from './handle_select_value_binding'; -import { sizing } from '../../../../utils/patterns'; export default class BindingWrapper { node: Binding; @@ -388,7 +387,7 @@ function get_event_handler( const value = get_value_from_dom(renderer, binding.parent, binding, block, contextual_dependencies); const mutation = b` - ${lhs} = ${sizing.test(name) ? `arg.${name}` : value}; + ${lhs} = ${value}; ${set_store} `; diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 62a83a2fe0..3bf3f6dee3 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -12,7 +12,7 @@ import { namespaces } from '../../../../utils/namespaces'; import AttributeWrapper from './Attribute'; import StyleAttributeWrapper from './StyleAttribute'; import SpreadAttributeWrapper from './SpreadAttribute'; -import { dimensions, sizing } from '../../../../utils/patterns'; +import { dimensions, sizing_border_box, sizing_content_box, sizing_device_pixel_content_box } from '../../../../utils/patterns'; import Binding from './Binding'; import add_to_set from '../../../utils/add_to_set'; import { add_event_handler } from '../shared/add_event_handlers'; @@ -63,9 +63,19 @@ const events = [ dimensions.test(name) }, { - event_names: ['elementresizeobserve'], + event_names: ['elementresizeobserveborderbox'], filter: (_node: Element, name: string) => - sizing.test(name) + sizing_border_box.test(name) + }, + { + event_names: ['elementresizeobservecontentbox'], + filter: (_node: Element, name: string) => + sizing_content_box.test(name) + }, + { + event_names: ['elementresizeobservedevicepixelcontentbox'], + filter: (_node: Element, name: string) => + sizing_device_pixel_content_box.test(name) }, // media events @@ -547,18 +557,30 @@ export default class ElementWrapper extends Wrapper { block.chunks.destroy.push( b`${resize_listener}();` ); - } else if (name === 'elementresizeobserve') { - // special case + } else if (name.startsWith('elementresizeobserve')) { const resize_observer = block.get_unique_name(`${this.var.name}_resize_observer`); block.add_variable(resize_observer); + let box = 'content-box' + switch (name) { + case 'elementresizeobserveborderbox': + box = 'border-box'; + break; + case 'elementresizeobservecontentbox': + box = 'content-box'; + break; + case 'elementresizeobservedevicepixelcontentbox': + box = 'device-pixel-content-box'; + break; + } + if (renderer.options.dev) { block.chunks.mount.push( - b`${resize_observer} = @add_resize_observer_dev(${this.var.name}, ${this.var}, ${callee}.bind(${this.var}));` + b`${resize_observer} = @add_resize_observer_dev(${this.var}, ${callee}, { box: "${box}" });` ); } else { block.chunks.mount.push( - b`${resize_observer} = @add_resize_observer(${this.var}, ${callee}.bind(${this.var}));` + b`${resize_observer} = @add_resize_observer(${this.var}, ${callee}, { box: "${box}" });` ); } diff --git a/src/compiler/utils/patterns.ts b/src/compiler/utils/patterns.ts index 6ecc136d1f..421fb53783 100644 --- a/src/compiler/utils/patterns.ts +++ b/src/compiler/utils/patterns.ts @@ -4,4 +4,6 @@ export const end_whitespace = /[ \t\r\n]*$/; export const dimensions = /^(?:offset|client)(?:Width|Height)$/; -export const sizing = /^(?:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize)$/; +export const sizing_content_box = /^(?:contentRect|contentBoxSize)$/; +export const sizing_border_box = /^(?:borderBoxSize)$/; +export const sizing_device_pixel_content_box = /^(?:devicePixelContentBoxSize)$/; diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts index 3c5466e4d3..1ebc722668 100644 --- a/src/runtime/internal/dev.ts +++ b/src/runtime/internal/dev.ts @@ -89,11 +89,11 @@ export function set_data_dev(text, data) { text.data = data; } -export function add_resize_observer_dev(binding_name: string, node: HTMLElement, fn: (arg: any) => void, opts?: ResizeObserverOptions) { - if ('ResizeObserver' in window) { +export function add_resize_observer_dev(node: HTMLElement, fn: (arg: any) => void, opts?: ResizeObserverOptions) { + if ('ResizeObserver' in window) { add_resize_observer(node, fn, opts); } else { - throw new Error(`${binding_name} uses the ResizeObserver API, but it is not supported in this browser.`); + throw new Error(`Sizing bindings uses the ResizeObserver API, but it is not supported in this browser.`); } } diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 5a2493b41c..cc9fadc66d 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -630,9 +630,9 @@ export function add_resize_listener(node: HTMLElement, fn: () => void) { }; } -export function add_resize_observer(node: HTMLElement, fn: (arg: any) => void, opts?: ResizeObserverOptions) { +export function add_resize_observer(node: HTMLElement, fn: () => void, opts?: ResizeObserverOptions) { // @ts-ignore ResizeObserver is not available in current tsconfig lib - const observer = new ResizeObserver(entries => fn(entries.values().next().value)); + const observer = new ResizeObserver(entries => fn.call(entries.values().next().value)); observer.observe(node, opts); return () => observer.disconnect(); }