From bf17a24704af4d43d9dc2e0817bd40593aeaa569 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 31 Oct 2024 16:01:55 +0800 Subject: [PATCH] Make dialog popup rendered by bootstrap overlay library This makes it more dynamic and eases proper placement in case of vertical layout Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 113 ++++++++++++------------- static/js/shop/OptionsWrapper.jsx | 7 +- static/js/shop/options/DialogPopup.jsx | 80 +++++++++-------- 3 files changed, 99 insertions(+), 101 deletions(-) diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index 4078d7e..84b6c1e 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -484,6 +484,12 @@ button { background-color: #ebebeb; padding: 5px 5px 12px; position: relative; + + &.horizontal { + flex-direction: column; + min-height: 50px; + overflow-y: auto; + } > div { display: flex; @@ -571,67 +577,6 @@ button { } } - .overlayVariant { - top: 24px; - width: 140px; - min-height: 40px; - max-height: 320px; - overflow-y: scroll; - position: absolute; - display: flex; - align-items: start; - text-align: left; - background-color: white; - color: black; - flex-direction: column; - cursor: pointer; - padding: 0.2rem 0; - - p { - font-size: .65rem; - margin: 0; - } - - div { - margin: 0.1rem 0.2rem; - font-size: 0.75rem; - - input { - padding: 0; - font-size: 0.75rem; - line-height: 1.1; - } - - label { - margin-bottom: 0.1rem; - } - - .options-icon { - display: inline; - height: .875rem; - margin-right: 0.2rem; - margin-left: 0.2rem; - } - } - - .form-check { - min-height: 1rem; - } - } - } - - .overlay-smallcard { - left: -38.5px; // (card width (63) - overlay width (140)) / 2 - - &.overlay-first { - left: 0; - } - &.overlay-last { - left: -67px; - } - } - .overlay-bigcard { - left: -7px; // (card width (126) - overlay width (140)) / 2 } .hovered { @@ -778,3 +723,49 @@ button { } } +.overlayVariant { + width: 140px; + min-height: 40px; + max-height: 320px; + overflow-y: scroll; + position: absolute; + display: flex; + align-items: start; + text-align: left; + background-color: white; + color: black; + flex-direction: column; + cursor: pointer; + padding: 0.2rem 0; + + p { + font-size: .65rem; + margin: 0; + } + + div { + margin: 0.1rem 0.2rem; + font-size: 0.75rem; + + input { + padding: 0; + font-size: 0.75rem; + line-height: 1.1; + } + + label { + margin-bottom: 0.1rem; + } + + .options-icon { + display: inline; + height: .875rem; + margin-right: 0.2rem; + margin-left: 0.2rem; + } + } + + .form-check { + min-height: 1rem; + } +} diff --git a/static/js/shop/OptionsWrapper.jsx b/static/js/shop/OptionsWrapper.jsx index 5a2103c..9105955 100644 --- a/static/js/shop/OptionsWrapper.jsx +++ b/static/js/shop/OptionsWrapper.jsx @@ -3,12 +3,11 @@ import React from "react"; import {useShopStore} from "./shop_store"; import {SummaryPopup} from "./options/SummaryPopup"; -export function OptionsDialogWrapper({crate_index, card_index, first, last}) { +export function OptionsDialogWrapper({crate_index, card_index, horizontal}) { const crate_id = useShopStore((state) => state.crates[crate_index].id); const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options); const options = useShopStore((state) => state.crates[crate_index].items[card_index][use_options]); const options_data = useShopStore((state) => state.crates[crate_index].items[card_index].options_data); - const card_size = useShopStore((state) => state.crates[crate_index].items[card_index].size); const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id); const options_class = useShopStore((state) => state.crates[crate_index].items[card_index].options_class); const sideMenuIsOpen = useShopStore((state) => state.sideMenuIsOpen); @@ -27,12 +26,10 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) { options_class={options_class} key={"popover" + crate_id +card_id} id={"popover"+ crate_id + card_id} - big={card_size === "big"} - first={first} - last={last} sideMenuIsOpen={sideMenuIsOpen} onHideNotification={hideNotification} displayNotification={displayNotification} + horizontal={horizontal} target={{ construct: ((outvar, value) => { // #!options_log diff --git a/static/js/shop/options/DialogPopup.jsx b/static/js/shop/options/DialogPopup.jsx index 443c308..7611c45 100644 --- a/static/js/shop/options/DialogPopup.jsx +++ b/static/js/shop/options/DialogPopup.jsx @@ -1,46 +1,56 @@ -import React, {useState} from "react"; -import {useClickAway} from "./useClickAway"; +import React, {useRef, useState} from "react"; import {ProcessOptions} from "./Options"; import {Notification} from "./Notification"; +import {Overlay} from "react-bootstrap"; -export function DialogPopup({options, data, target, id, big, first, last, options_class, - sideMenuIsOpen, displayNotification, onHideNotification}) { +export function DialogPopup({options, data, target, id, options_class, + sideMenuIsOpen, displayNotification, onHideNotification, horizontal}) { const [show, setShow] = useState(false); - const ref = useClickAway((e) => { - if (e.type === "mousedown") // ignore touchstart - setShow(false) - } - ); + const ref = useRef(null); + + let div_classes = `overlayVariant border rounded ${options_class || ""}`; - let div_classes = `overlayVariant border rounded ${big ? "overlay-bigcard" : "overlay-smallcard"} ${(!big && first) ? "overlay-first" : ""} ${(!big && last && !first) ? "overlay-last" : ""} ${options_class || ""}`; const handleClick = (_event) => { setShow(!show); }; - return ( -
- - } - /> -
- -
-
- ); + return (<> + + } + /> + setShow(false)} + rootClose={true}> + {({ + placement: _placement, + arrowProps: _arrowProps, + show: _show, + popper: _popper, + hasDoneInitialMeasure: _hasDoneInitialMeasure, + ...props + }) => ( +
+ +
+ )} +
+ ); }