diff --git a/src/components/utils/popover/index.ts b/src/components/utils/popover/index.ts index 8a1fda3c..fa7b048d 100644 --- a/src/components/utils/popover/index.ts +++ b/src/components/utils/popover/index.ts @@ -75,6 +75,11 @@ export default class Popover extends EventsDispatcher { */ private previouslyHoveredItem: PopoverItem | undefined | null; + /** + * Popover nesting level. 0 value means that it is a root popover + */ + private nestingLevel = 0; + /** * Popover CSS classes */ @@ -140,6 +145,10 @@ export default class Popover extends EventsDispatcher { this.scopeElement = params.scopeElement; } + if (params.nestingLevel) { + this.nestingLevel = params.nestingLevel; + } + if (params.messages) { this.messages = { ...this.messages, @@ -188,12 +197,20 @@ export default class Popover extends EventsDispatcher { return this.nodes.items.scrollTop; } + /** + * Returns visible element offset top + */ + public get offsetTop(): number { + return this.nodes.popoverContainer.offsetTop; + } + /** * Open popover */ public show(): void { + this.nodes.popover.style.setProperty('--popover-height', this.height + 'px'); + if (!this.shouldOpenBottom) { - this.nodes.popover.style.setProperty('--popover-height', this.height + 'px'); this.nodes.popover.classList.add(Popover.CSS.popoverOpenTop); } @@ -271,7 +288,12 @@ export default class Popover extends EventsDispatcher { this.listeners.on(this.nodes.popoverContainer, 'mouseover', (event: PointerEvent) => this.handleHover(event)); } - this.nodes.popover = Dom.make('div', [Popover.CSS.popover, this.params.class]); + this.nodes.popover = Dom.make('div', [ + Popover.CSS.popover, + this.nestingLevel > 0 ? Popover.CSS.popoverNested : undefined, + this.params.class, + ]); + this.nodes.overlay = Dom.make('div', [Popover.CSS.overlay, Popover.CSS.overlayHidden]); this.listeners.on(this.nodes.overlay, 'click', () => { @@ -448,22 +470,26 @@ export default class Popover extends EventsDispatcher { /** - * Creates and displays nested popover for specified item + * Creates and displays nested popover for specified item. + * Is used only on desktop * * @param item - item to display nested popover by */ private showNestedPopoverForItem(item: PopoverItem): void { this.nestedPopover = new Popover({ items: item.children, - class: Popover.CSS.popoverNested, + nestingLevel: this.nestingLevel + 1, }); const nestedPopoverEl = this.nestedPopover.getElement(); this.nodes.popover.appendChild(nestedPopoverEl); const itemOffsetTop = item.getElement().offsetTop - this.scrollTop; + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + const topOffset = this.offsetTop + itemOffsetTop - 4; - nestedPopoverEl.style.setProperty('--nesting-popover-item-top', itemOffsetTop + 'px'); + nestedPopoverEl.style.setProperty('--nested-popover-top', topOffset + 'px'); + nestedPopoverEl.style.setProperty('--nesting-level', this.nestedPopover.nestingLevel.toString()); this.nestedPopover.show(); this.flipper.deactivate(); diff --git a/src/components/utils/popover/popover.typings.ts b/src/components/utils/popover/popover.typings.ts index 5cc672ed..cf90075d 100644 --- a/src/components/utils/popover/popover.typings.ts +++ b/src/components/utils/popover/popover.typings.ts @@ -38,6 +38,11 @@ export interface PopoverParams { * CSS class name for popover root element */ class?: string; + + /** + * Popover nesting level. 0 value means that it is a root popover + */ + nestingLevel?: number; } /** diff --git a/src/styles/popover.css b/src/styles/popover.css index 1d7c57c5..65a5a2e2 100644 --- a/src/styles/popover.css +++ b/src/styles/popover.css @@ -48,7 +48,6 @@ } &--opened { - .ce-popover__container { opacity: 1; padding: var(--padding); @@ -64,6 +63,12 @@ } + &--open-top { + .ce-popover__container { + --popover-top: calc(-1 * (var(--offset-from-target) + var(--popover-height))); + } + } + &__items { overflow-y: auto; overscroll-behavior: contain; @@ -89,11 +94,6 @@ } } - &--open-top { - .ce-popover__container { - --popover-top: calc(-1 * (var(--offset-from-target) + var(--popover-height))); - } - } @media (--mobile) { @@ -149,21 +149,20 @@ } &--nested { - .ce-popover__container { - left: calc(var(--width) - 4px); - top: calc(var(--nesting-popover-item-top) + var(--popover-top) - 4px); + /* Variable --nesting-level is set via js in showNestedPopoverForItem() method */ + left: calc(var(--nesting-level) * var(--width) - 4px); + /* Variable --nested-popover-top is set via js in showNestedPopoverForItem() method */ + top: var(--nested-popover-top); position: absolute; } } &--open-top { - --parent-popover-height: var(--popover-height); - .ce-popover--nested { .ce-popover__container { /** Bottom edge of nested popover should not be lower than bottom edge of parent popover when opened upwards */ - top: calc(var(--popover-top) - var(--popover-height) + var(--parent-popover-height)); + top: min(var(--popover-top), var(--nested-popover-top)) } } }