Add the onresize event handler to Element (#2479)
* Add the capability to handle resize event for web target * Add the capability to handle resize event for desktop target * Return all the sizes, not just the first one * Fix conversion from platform to generic ResizedData for liveview * Update the generated interpreter js code base * Fix clippy warnings * Fix inconsistent use of block_size and inline_size * Rename `onresized` event to `onresize` * Remove the the special-casing logic from the binding logic * Propagating the resize events using CustomEvent * Fix case convention in core ts * revert changes to unified bindings * Cleanup as suggested * add a resize example * Fix desktop resize events * remove tracing from resize example * use the raw resize entry so we can downcast on web * remove unused ResizeEventDetail --------- Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
1 parent
4d6fb74e87
commit
2f49a89638
19 files changed
+442
-50
No files matched your search
@@ -19,6 +19,8 @@ export class BaseInterpreter {
|
||||
|
||||
root: HTMLElement;
|
||||
handler: EventListener;
|
||||
resizeObserver: ResizeObserver;
|
||||
|
||||
nodes: Node[];
|
||||
stack: Node[];
|
||||
templates: {
|
||||
@@ -39,8 +41,35 @@ export class BaseInterpreter {
|
||||
this.stack = [root];
|
||||
this.templates = {};
|
||||
|
||||
if (handler) {
|
||||
this.handler = handler;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
handleResizeEvent(entry: ResizeObserverEntry) {
|
||||
const target = entry.target;
|
||||
|
||||
let event = new CustomEvent<ResizeObserverEntry>("resize", {
|
||||
bubbles: false,
|
||||
detail: entry,
|
||||
});
|
||||
|
||||
target.dispatchEvent(event);
|
||||
}
|
||||
|
||||
createObserver(element: HTMLElement) {
|
||||
// Lazily create the resize observer
|
||||
if (!this.resizeObserver) {
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
this.handleResizeEvent(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.resizeObserver.observe(element);
|
||||
}
|
||||
|
||||
removeObserver(element: HTMLElement) {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.unobserve(element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +88,10 @@ export class BaseInterpreter {
|
||||
}
|
||||
element.addEventListener(event_name, this.handler);
|
||||
}
|
||||
|
||||
if (event_name == "resize") {
|
||||
this.createObserver(element);
|
||||
}
|
||||
}
|
||||
|
||||
removeListener(element: HTMLElement, event_name: string, bubbles: boolean) {
|
||||
|
||||
@@ -98,6 +98,7 @@ export class NativeInterpreter extends JSChannel_ {
|
||||
// make sure we pass the handler to the base interpreter
|
||||
const handler: EventListener = (event) =>
|
||||
this.handleEvent(event, event.type, true);
|
||||
|
||||
super.initialize(root, handler);
|
||||
}
|
||||
|
||||
@@ -209,7 +210,7 @@ export class NativeInterpreter extends JSChannel_ {
|
||||
// This is to support the prevent_default: "onclick" attribute that dioxus has had for a while, but is not necessary
|
||||
// now that we expose preventDefault to the virtualdom on desktop
|
||||
// Liveview will still need to use this
|
||||
this.preventDefaults(event, target);
|
||||
this.preventDefaults(event);
|
||||
|
||||
// liveview does not have synchronous event handling, so we need to send the event to the host
|
||||
if (this.liveview) {
|
||||
@@ -262,7 +263,7 @@ export class NativeInterpreter extends JSChannel_ {
|
||||
// - prevent anchor tags from navigating
|
||||
// - prevent buttons from submitting forms
|
||||
// - let the virtualdom attempt to prevent the event
|
||||
preventDefaults(event: Event, target: EventTarget) {
|
||||
preventDefaults(event: Event) {
|
||||
if (event.type === "submit") {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
@@ -58,6 +58,13 @@ export function serializeEvent(
|
||||
extend({});
|
||||
}
|
||||
|
||||
if (event instanceof CustomEvent) {
|
||||
const detail = event.detail;
|
||||
if (detail instanceof ResizeObserverEntry) {
|
||||
extend(serializeResizeEventDetail(detail));
|
||||
}
|
||||
}
|
||||
|
||||
// safari is quirky and doesn't have TouchEvent
|
||||
if (typeof TouchEvent !== "undefined" && event instanceof TouchEvent) {
|
||||
extend(serializeTouchEvent(event));
|
||||
@@ -96,6 +103,47 @@ export function serializeEvent(
|
||||
return contents;
|
||||
}
|
||||
|
||||
function toSerializableResizeObserverSize(
|
||||
size: ResizeObserverSize,
|
||||
is_inline_width: boolean
|
||||
): Object {
|
||||
return [
|
||||
is_inline_width ? size.inlineSize : size.blockSize,
|
||||
is_inline_width ? size.blockSize : size.inlineSize,
|
||||
];
|
||||
}
|
||||
|
||||
export function serializeResizeEventDetail(
|
||||
detail: ResizeObserverEntry
|
||||
): SerializedEvent {
|
||||
let is_inline_width = true;
|
||||
if (detail.target instanceof HTMLElement) {
|
||||
let target_style = window.getComputedStyle(detail.target);
|
||||
let target_writing_mode = target_style.getPropertyValue("writing-mode");
|
||||
if (target_writing_mode !== "horizontal-tb") {
|
||||
is_inline_width = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
border_box_size:
|
||||
detail.borderBoxSize !== undefined
|
||||
? toSerializableResizeObserverSize(
|
||||
detail.borderBoxSize[0],
|
||||
is_inline_width
|
||||
)
|
||||
: detail.contentRect,
|
||||
content_box_size:
|
||||
detail.contentBoxSize !== undefined
|
||||
? toSerializableResizeObserverSize(
|
||||
detail.contentBoxSize[0],
|
||||
is_inline_width
|
||||
)
|
||||
: detail.contentRect,
|
||||
content_rect: detail.contentRect,
|
||||
};
|
||||
}
|
||||
|
||||
function serializeInputEvent(
|
||||
event: InputEvent,
|
||||
target: EventTarget
|
||||
|
||||
Reference in new issue
Block a user