[REF] web_tour: replace a deprecated function

**Before this commit**
The TourPointer component make use of a deprecated
function (reposition) in order to position itself.

**After this commit**
The TourPointer now make use of the usePosition hook,
which is the recommended way to compute this kind of positioning.

Part-of: odoo/odoo#135188
This commit is contained in:
Bruno Boi
2023-10-13 21:11:52 +00:00
parent b449ae6036
commit 31c52824be
2 changed files with 80 additions and 91 deletions
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Component, useEffect, useRef } from "@odoo/owl";
import { reposition } from "@web/core/position_hook";
import { usePosition } from "@web/core/position_hook";
/**
* @typedef {import("../tour_service/tour_pointer_state").TourPointerState} TourPointerState
@@ -48,6 +48,26 @@ export class TourPointer extends Component {
static height = 28; // in pixels
setup() {
const positionOptions = {
margin: 6,
onPositioned: (pointer, position) => {
const popperRect = pointer.getBoundingClientRect();
const { top, left, direction } = position;
if (direction === "top") {
// position from the bottom instead of the top as it is needed
// to ensure the expand animation is properly done
pointer.style.bottom = `${window.innerHeight - top - popperRect.height}px`;
pointer.style.removeProperty("top");
} else if (direction === "left") {
// position from the right instead of the left as it is needed
// to ensure the expand animation is properly done
pointer.style.right = `${window.innerWidth - left - popperRect.width}px`;
pointer.style.removeProperty("left");
}
},
};
Object.defineProperty(positionOptions, "position", { get: () => this.position, enumerable: true });
const position = usePosition("pointer", () => this.props.pointerState.anchor, positionOptions);
const rootRef = useRef("pointer");
/** @type {DOMREct | null} */
let dimensions = null;
@@ -55,96 +75,66 @@ export class TourPointer extends Component {
let lastOpenState = this.isOpen;
let lastAnchor;
let [anchorX, anchorY] = [0, 0];
useEffect(() => {
const { el: pointer } = rootRef;
if (pointer) {
const hasContentChanged = lastMeasuredContent !== this.content;
const hasOpenStateChanged = lastOpenState !== this.isOpen;
lastOpenState = this.isOpen;
useEffect(
() => {
const { el: pointer } = rootRef;
if (pointer) {
const hasContentChanged = lastMeasuredContent !== this.content;
const hasOpenStateChanged = lastOpenState !== this.isOpen;
lastOpenState = this.isOpen;
// Content changed: we must re-measure the dimensions of the text.
if (hasContentChanged) {
lastMeasuredContent = this.content;
pointer.style.removeProperty("width");
pointer.style.removeProperty("height");
dimensions = pointer.getBoundingClientRect();
}
// If the content or the "is open" state changed: we must apply
// new width and height properties
if (hasContentChanged || hasOpenStateChanged) {
const [width, height] = this.isOpen
? [dimensions.width, dimensions.height]
: [this.constructor.width, this.constructor.height];
if (this.isOpen) {
pointer.style.removeProperty("transition");
} else {
// No transition if switching from open to closed
pointer.style.setProperty("transition", "none");
}
pointer.style.setProperty("width", `${width}px`);
pointer.style.setProperty("height", `${height}px`);
}
if (!this.isOpen) {
const { anchor } = this.props.pointerState;
if (anchor === lastAnchor) {
const { x, y, width } = anchor.getBoundingClientRect();
const [lastAnchorX, lastAnchorY] = [anchorX, anchorY];
[anchorX, anchorY] = [x, y];
// Let's just say that the anchor is static if it moved less than 1px.
const delta = Math.sqrt(
Math.pow(x - lastAnchorX, 2) + Math.pow(y - lastAnchorY, 2)
);
if (delta < 1) {
return;
}
const wouldOverflow =
window.innerWidth - x - width / 2 < dimensions?.width;
pointer.classList.toggle("o_expand_left", wouldOverflow);
}
lastAnchor = anchor;
pointer.style.bottom = "";
pointer.style.right = "";
reposition(
pointer,
anchor,
{
position: this.position,
margin: 6,
onPositioned: (_, position) => {
const popperRect = pointer.getBoundingClientRect();
const { top, left, direction } = position;
if (direction === "top") {
// position from the bottom instead of the top as it is needed
// to ensure the expand animation is properly done
pointer.style.bottom = `${
window.innerHeight - top - popperRect.height
}px`;
pointer.style.removeProperty("top");
} else if (direction === "left") {
// position from the right instead of the left as it is needed
// to ensure the expand animation is properly done
pointer.style.right = `${
window.innerWidth - left - popperRect.width
}px`;
pointer.style.removeProperty("left");
}
},
}
);
}
} else {
lastMeasuredContent = null;
lastOpenState = false;
lastAnchor = null;
dimensions = null;
// Content changed: we must re-measure the dimensions of the text.
if (hasContentChanged) {
lastMeasuredContent = this.content;
pointer.style.removeProperty("width");
pointer.style.removeProperty("height");
dimensions = pointer.getBoundingClientRect();
}
},
() => [this.props.pointerState.rev]
);
// If the content or the "is open" state changed: we must apply
// new width and height properties
if (hasContentChanged || hasOpenStateChanged) {
const [width, height] = this.isOpen
? [dimensions.width, dimensions.height]
: [this.constructor.width, this.constructor.height];
if (this.isOpen) {
pointer.style.removeProperty("transition");
} else {
// No transition if switching from open to closed
pointer.style.setProperty("transition", "none");
}
pointer.style.setProperty("width", `${width}px`);
pointer.style.setProperty("height", `${height}px`);
}
if (!this.isOpen) {
const { anchor } = this.props.pointerState;
if (anchor === lastAnchor) {
const { x, y, width } = anchor.getBoundingClientRect();
const [lastAnchorX, lastAnchorY] = [anchorX, anchorY];
[anchorX, anchorY] = [x, y];
// Let's just say that the anchor is static if it moved less than 1px.
const delta = Math.sqrt(
Math.pow(x - lastAnchorX, 2) + Math.pow(y - lastAnchorY, 2)
);
if (delta < 1) {
position.lock();
return;
}
const wouldOverflow = window.innerWidth - x - width / 2 < dimensions?.width;
pointer.classList.toggle("o_expand_left", wouldOverflow);
}
lastAnchor = anchor;
pointer.style.bottom = "";
pointer.style.right = "";
position.unlock();
}
} else {
lastMeasuredContent = null;
lastOpenState = false;
lastAnchor = null;
dimensions = null;
}
});
}
get content() {
@@ -94,7 +94,7 @@ export function createPointerState() {
* @param {Partial<TourPointerState>} newState
*/
const setState = (newState) => {
Object.assign(state, newState, { rev: currentRev++ });
Object.assign(state, newState);
};
/**
@@ -171,7 +171,6 @@ export function createPointerState() {
}
}
let currentRev = 1;
/** @type {TourPointerState} */
const state = reactive({});
const intersection = new Intersection();