diff --git a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts index 46f1cfc043..cb5a159ffe 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Binding.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Binding.ts @@ -416,12 +416,12 @@ function get_value_from_dom( //
if (regex_box_size.test(name)) { - const functionName = { + const functionName = ({ "contentRect": "get_content_rect", "contentBoxSize": "get_content_box_size", "borderBoxSize": "get_border_box_size", "devicePixelContentBoxSize": "get_device_pixel_content_box_size", - } + })[name]; return x`@${functionName}(this)`; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index 8418cd9531..09b9f4aaa6 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 { regex_dimensions, regex_starts_with_newline, regex_backslashes, regex_border_box_size, regex_content_box_size, regex_device_pixel_content_box_size } from '../../../../utils/patterns'; +import { regex_dimensions, regex_starts_with_newline, regex_backslashes, regex_border_box_size, regex_content_box_size, regex_device_pixel_content_box_size, regex_content_rect } 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'; @@ -71,15 +71,20 @@ const events = [ }, { - event_names: ['elementresizeobserveborderbox'], + event_names: ['elementresizeobservecontentrect'], filter: (_node: Element, name: string) => - regex_border_box_size.test(name) + regex_content_rect.test(name) }, { event_names: ['elementresizeobservecontentbox'], filter: (_node: Element, name: string) => regex_content_box_size.test(name) }, + { + event_names: ['elementresizeobserveborderbox'], + filter: (_node: Element, name: string) => + regex_border_box_size.test(name) + }, { event_names: ['elementresizeobservedevicepixelcontentbox'], filter: (_node: Element, name: string) => @@ -710,6 +715,7 @@ export default class ElementWrapper extends Wrapper { const functionName = ({ "elementresize": "add_iframe_resize_listener", + "elementresizeobservecontentrect": "add_content_rect_observer", "elementresizeobservecontentbox": "add_content_box_observer", "elementresizeobserveborderbox": "add_border_box_observer", "elementresizeobservedevicepixelcontentbox": "add_device_pixel_content_box_observer", diff --git a/src/compiler/utils/patterns.ts b/src/compiler/utils/patterns.ts index 2a19d2d89f..e4cf3a8506 100644 --- a/src/compiler/utils/patterns.ts +++ b/src/compiler/utils/patterns.ts @@ -23,7 +23,8 @@ export const regex_invalid_variable_identifier_characters = /[^a-zA-Z0-9_$]/g; export const regex_dimensions = /^(?:offset|client)(?:Width|Height)$/; -export const regex_content_box_size = /^(?:contentRect|contentBoxSize)$/; +export const regex_content_rect = /^(?:contentRect)$/; +export const regex_content_box_size = /^(?:contentBoxSize)$/; export const regex_border_box_size = /^(?:borderBoxSize)$/; export const regex_device_pixel_content_box_size = /^(?:devicePixelContentBoxSize)$/; export const regex_box_size = /^(?:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize)$/ \ No newline at end of file diff --git a/src/runtime/internal/ResizeObserverSingleton.ts b/src/runtime/internal/ResizeObserverSingleton.ts index beaaeede05..a8e4788e5c 100644 --- a/src/runtime/internal/ResizeObserverSingleton.ts +++ b/src/runtime/internal/ResizeObserverSingleton.ts @@ -1,4 +1,4 @@ -const MapImplementation = "WeakMap" in window ? WeakMap : Map; +const MapImplementation = "WeakMap" in window ? WeakMap : ("Map" in window ? Map : undefined); /** * Resize observer singleton @@ -8,53 +8,37 @@ export class ResizeObserverSingleton { constructor(readonly options?: ResizeObserverOptions) {} addListener(element: Element, callback: Callback) { - if (!this._subscriptions.has(element)) { - this._subscriptions.set(element, new Subscription(new Set([callback]))); - this._getObserver().observe(element, this.options); - } else { - const subscription = this._subscriptions.get(element)!; - subscription.listeners.add(callback); - callback.call(element, subscription.lastEntry!); - } + this._subscriptions.set(element, new Subscription(callback)); + this._getObserver().observe(element, this.options); } - removeListener(element: Element, callback: Callback) { - const subscription = this._subscriptions.get(element); - if (!subscription) return; - if (subscription.listeners.size > 1) { - subscription.listeners.delete(callback); - } else { - this._subscriptions.delete(element); - this._getObserver().unobserve(element); - } + removeListener(element: Element) { + this._subscriptions.delete(element); + this._getObserver().unobserve(element); } getLastEntry(element: Element) { return this._subscriptions.get(element)?.lastEntry; } - private readonly _subscriptions: WeakMap = new MapImplementation(); + private readonly _subscriptions: WeakMap = MapImplementation ? new MapImplementation() : undefined; private _observer: ResizeObserver|undefined = undefined; private _getObserver() { return this._observer ?? (this._observer = new ResizeObserver((entries)=>{ for (const entry of entries) { - const element = entry.target; - const subscription = this._subscriptions.get(element); - if (!subscription) continue; + const subscription = this._subscriptions.get(entry.target)!; subscription.lastEntry = entry; - for (const callback of subscription.listeners) callback.call(element, entry); + subscription.listener(entry); } })); } } -type Callback = (this: Element, entry: ResizeObserverEntry)=>any; +type Callback = (entry: ResizeObserverEntry)=>any; class Subscription { - // TODO: consider using Array instead of Set? - // If we can guarantee one listener per element, we can simplify even more. constructor( - readonly listeners: Set, + readonly listener: Callback, public lastEntry?: ResizeObserverEntry, ) {} } \ No newline at end of file diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 1d2b59bb1a..946dfb97b1 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -641,27 +641,33 @@ export function add_iframe_resize_listener(node: HTMLElement, fn: () => void) { }; } +const resize_observer_content_rect = new ResizeObserverSingleton({ box: "content-box" }); const resize_observer_content_box = new ResizeObserverSingleton({ box: "content-box" }); const resize_observer_border_box = new ResizeObserverSingleton({ box: "border-box" }); const resize_observer_device_pixel_content_box = new ResizeObserverSingleton({ box: "device-pixel-content-box" }); +export function add_content_rect_observer(node: Element, fn: () => void) { + resize_observer_content_rect.addListener(node, fn); + return ()=> resize_observer_content_rect.removeListener(node); +} + export function add_content_box_observer(node: Element, fn: () => void) { resize_observer_content_box.addListener(node, fn); - return ()=> resize_observer_content_box.removeListener(node, fn); + return ()=> resize_observer_content_box.removeListener(node); } export function add_border_box_observer(node: Element, fn: () => void) { resize_observer_border_box.addListener(node, fn); - return ()=> resize_observer_border_box.removeListener(node, fn); + return ()=> resize_observer_border_box.removeListener(node); } export function add_device_pixel_content_box_observer(node: Element, fn: () => void) { resize_observer_device_pixel_content_box.addListener(node, fn); - return ()=> resize_observer_device_pixel_content_box.removeListener(node, fn); + return ()=> resize_observer_device_pixel_content_box.removeListener(node); } export function get_content_rect(node: Element) { - return resize_observer_content_box.getLastEntry(node)?.contentRect; + return resize_observer_content_rect.getLastEntry(node)?.contentRect; } export function get_content_box_size(node: Element) {