[REF] web,mail: add popover props: arrow,animation

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) <mcm@odoo.com>
This commit is contained in:
Bruno Boi
2023-10-13 21:11:52 +00:00
parent 31c52824be
commit 25423820ed
8 changed files with 73 additions and 85 deletions
@@ -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;
+2 -1
View File
@@ -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,
@@ -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) => {
+64 -35
View File
@@ -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
@@ -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;
}
@@ -4,7 +4,7 @@
<t t-name="web.PopoverWowl">
<div role="tooltip" class="o_popover popover mw-100" t-att-class="props.class" t-ref="ref">
<t t-slot="default" />
<div t-if="!props.fixedPosition" class="popover-arrow"/>
<div t-if="props.arrow" class="popover-arrow"/>
</div>
</t>
@@ -9,6 +9,8 @@ import { PopoverController } from "./popover_controller";
* closeOnClickAway?: boolean | (target: HTMLElement) => boolean;
* onClose?: () => void;
* popoverClass?: string;
* animation?: Boolean;
* arrow?: Boolean;
* position?: import("@web/core/position_hook").Options["position"];
* fixedPosition?: boolean;
* onPositioned?: import("@web/core/position_hook").PositionEventHandler;
@@ -43,6 +45,8 @@ export const popoverService = {
popoverProps: {
target,
class: options.popoverClass,
animation: options.animation,
arrow: options.arrow,
position: options.position,
onPositioned: options.onPositioned,
fixedPosition: options.fixedPosition,
@@ -45,6 +45,7 @@ export class PropertiesField extends Component {
position: "top",
onClose: () => this.onCloseCurrentPopover?.(),
fixedPosition: true,
arrow: false,
});
this.propertiesRef = useRef("properties");
@@ -753,11 +754,6 @@ export class PropertiesField extends Component {
);
reposition(popover, target, { position: "top", margin: 10 });
const arrow = popover.querySelector(".popover-arrow");
if (arrow) {
arrow.classList.add("d-none");
}
}
/**