From 25423820ed74fbef425c0a944fd89d4f3744ec49 Mon Sep 17 00:00:00 2001 From: Bruno Boi Date: Mon, 9 Oct 2023 11:22:14 +0200 Subject: [PATCH] [REF] web,mail: add popover props: arrow,animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better API as the arrow was not displayed when the fixedPosition prop was true, which is as we were mixing apples and pears. And as for the animation prop, it permits to remove the hacky "o-fast-popover" class usages. closes odoo/odoo#135188 Signed-off-by: Michaƫl Mattiello (mcm) --- .../mail/static/src/core/common/composer.scss | 7 -- addons/mail/static/src/core/common/picker.js | 3 +- .../src/core/emoji_picker/emoji_picker.js | 2 +- addons/web/static/src/core/popover/popover.js | 99 ++++++++++++------- .../web/static/src/core/popover/popover.scss | 35 ------- .../web/static/src/core/popover/popover.xml | 2 +- .../src/core/popover/popover_service.js | 4 + .../fields/properties/properties_field.js | 6 +- 8 files changed, 73 insertions(+), 85 deletions(-) diff --git a/addons/mail/static/src/core/common/composer.scss b/addons/mail/static/src/core/common/composer.scss index 1c04322c361..ab2987dd148 100644 --- a/addons/mail/static/src/core/common/composer.scss +++ b/addons/mail/static/src/core/common/composer.scss @@ -63,13 +63,6 @@ --Avatar-size: #{$o-mail-Avatar-size}; } -.o-fast-popover { - animation: 0.02s slide-right !important; - animation: 0.02s slide-left !important; - animation: 0.02s slide-top !important; - animation: 0.02s slide-bottom !important; -} - .o-mail-Composer-fake { height: 0; top: -10000px; diff --git a/addons/mail/static/src/core/common/picker.js b/addons/mail/static/src/core/common/picker.js index e49f5f81725..2c0c0636943 100644 --- a/addons/mail/static/src/core/common/picker.js +++ b/addons/mail/static/src/core/common/picker.js @@ -65,7 +65,8 @@ export class Picker extends Component { fixedPosition: true, onClose: () => this.close(), closeOnClickAway: false, - popoverClass: "o-fast-popover", + animation: false, + arrow: false, }); useExternalListener( browser, diff --git a/addons/web/static/src/core/emoji_picker/emoji_picker.js b/addons/web/static/src/core/emoji_picker/emoji_picker.js index 943bff29c09..b318a91c657 100644 --- a/addons/web/static/src/core/emoji_picker/emoji_picker.js +++ b/addons/web/static/src/core/emoji_picker/emoji_picker.js @@ -32,7 +32,7 @@ import { useAutofocus, useService } from "@web/core/utils/hooks"; */ export function useEmojiPicker(ref, props, options = {}) { const targets = []; - const popover = usePopover(EmojiPicker, { ...options, popoverClass: "o-fast-popover" }); + const popover = usePopover(EmojiPicker, { ...options, animation: false }); props.storeScroll = { scrollValue: 0, set: (value) => { diff --git a/addons/web/static/src/core/popover/popover.js b/addons/web/static/src/core/popover/popover.js index 81905ce5fa1..4cecc3615ef 100644 --- a/addons/web/static/src/core/popover/popover.js +++ b/addons/web/static/src/core/popover/popover.js @@ -5,9 +5,11 @@ import { useForwardRefToParent } from "../utils/hooks"; import { usePosition } from "@web/core/position_hook"; export class Popover extends Component { + static animationTime = 200; setup() { useForwardRefToParent("ref"); - const position = usePosition( + this.shouldAnimate = this.props.animation; + this.position = usePosition( "ref", () => this.props.target, { @@ -15,7 +17,7 @@ export class Popover extends Component { (this.props.onPositioned || this.onPositioned.bind(this))(el, solution); if (this.props.fixedPosition) { // Prevent further positioning updates if fixed position is wanted - position.lock(); + this.position.lock(); } }, position: this.props.position, @@ -43,40 +45,56 @@ export class Popover extends Component { } // reset all arrow classes - const arrowEl = el.querySelector(".popover-arrow"); - if (!arrowEl) { - return; + if (this.props.arrow) { + const arrowEl = el.querySelector(":scope > .popover-arrow"); + arrowEl.className = "popover-arrow"; + switch (position) { + case "tm": // top-middle + case "bm": // bottom-middle + case "tf": // top-fit + case "bf": // bottom-fit + arrowEl.classList.add("start-0", "end-0", "mx-auto"); + break; + case "lm": // left-middle + case "rm": // right-middle + case "lf": // left-fit + case "rf": // right-fit + arrowEl.classList.add("top-0", "bottom-0", "my-auto"); + break; + case "ts": // top-start + case "bs": // bottom-start + arrowEl.classList.add("end-auto"); + break; + case "te": // top-end + case "be": // bottom-end + arrowEl.classList.add("start-auto"); + break; + case "ls": // left-start + case "rs": // right-start + arrowEl.classList.add("bottom-auto"); + break; + case "le": // left-end + case "re": // right-end + arrowEl.classList.add("top-auto"); + break; + } } - arrowEl.className = "popover-arrow"; - switch (position) { - case "tm": // top-middle - case "bm": // bottom-middle - case "tf": // top-fit - case "bf": // bottom-fit - arrowEl.classList.add("start-0", "end-0", "mx-auto"); - break; - case "lm": // left-middle - case "rm": // right-middle - case "lf": // left-fit - case "rf": // right-fit - arrowEl.classList.add("top-0", "bottom-0", "my-auto"); - break; - case "ts": // top-start - case "bs": // bottom-start - arrowEl.classList.add("end-auto"); - break; - case "te": // top-end - case "be": // bottom-end - arrowEl.classList.add("start-auto"); - break; - case "ls": // left-start - case "rs": // right-start - arrowEl.classList.add("bottom-auto"); - break; - case "le": // left-end - case "re": // right-end - arrowEl.classList.add("top-auto"); - break; + + // opening animation + if (this.shouldAnimate) { + this.shouldAnimate = false; // animate only once + const transform = { + top: ["translateY(-5%)", "translateY(0)"], + right: ["translateX(5%)", "translateX(0)"], + bottom: ["translateY(5%)", "translateY(0)"], + left: ["translateX(-5%)", "translateX(0)"], + }[direction]; + this.position.lock(); + const animation = el.animate( + { opacity: [0, 1], transform }, + this.constructor.animationTime + ); + animation.finished.then(this.position.unlock); } } } @@ -85,6 +103,9 @@ Popover.template = "web.PopoverWowl"; Popover.defaultProps = { position: "bottom", class: "", + fixedPosition: false, + arrow: true, + animation: true, }; Popover.props = { ref: { @@ -114,6 +135,14 @@ Popover.props = { type: Boolean, optional: true, }, + arrow: { + type: Boolean, + optional: true, + }, + animation: { + type: Boolean, + optional: true, + }, target: { validate: (target) => { // target may be inside an iframe, so get the Element constructor diff --git a/addons/web/static/src/core/popover/popover.scss b/addons/web/static/src/core/popover/popover.scss index e9b38e8408b..ae011d9a199 100644 --- a/addons/web/static/src/core/popover/popover.scss +++ b/addons/web/static/src/core/popover/popover.scss @@ -1,40 +1,5 @@ /*!rtl:begin:ignore*/ - -@keyframes slide-top { - 0% { - opacity: 0; - transform: translateY(-5%); - } -} - -@keyframes slide-end { - 0% { - opacity: 0; - transform: translateX(5%); - } -} - -@keyframes slide-bottom { - 0% { - opacity: 0; - transform: translateY(5%); - } -} - -@keyframes slide-start { - 0% { - opacity: 0; - transform: translateX(-5%); - } -} - .o_popover { - @each $direction in (top, end, bottom, start) { - &.bs-popover-#{$direction} { - animation: 0.2s slide-#{$direction}; - } - } - &.o-popover-top, &.o-popover-auto[x-placement^="top"] { margin-bottom: 0.5rem; } diff --git a/addons/web/static/src/core/popover/popover.xml b/addons/web/static/src/core/popover/popover.xml index ed2341c8e7f..79ffef425fd 100644 --- a/addons/web/static/src/core/popover/popover.xml +++ b/addons/web/static/src/core/popover/popover.xml @@ -4,7 +4,7 @@