diff --git a/src/card-controller/expand-manager.ts b/src/card-controller/expand-manager.ts index 77db3416..6820a1d4 100644 --- a/src/card-controller/expand-manager.ts +++ b/src/card-controller/expand-manager.ts @@ -1,3 +1,4 @@ +import { setOrRemoveAttribute } from '../utils/basic'; import { CardExpandAPI } from './types'; export class ExpandManager { @@ -28,6 +29,11 @@ export class ExpandManager { this._expanded = expanded; this._setConditionState(); + setOrRemoveAttribute( + this._api.getCardElementManager().getElement(), + expanded, + 'expanded', + ); this._api.getCardElementManager().update(); } diff --git a/src/scss/card.scss b/src/scss/card.scss index 766b88d4..cab7a493 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -36,8 +36,12 @@ // from other cards. Tip: Best way to test this is with multiple Advanced Camera // Cards, opening a submenu on the 1st (e.g. media players) and verifying the // menu of the 2nd card is not visible through the opened submenu on the 1st. -:host(:not(:hover)) { - z-index: #{$z-index-card-flatten}; +:host(:not(:hover):not([expanded])) { + z-index: auto; + + // Create a new stacking context to prevent z-index issues with children + // "breaking out" of the card. + isolation: isolate; } advanced-camera-card-loading { diff --git a/src/scss/z-index.scss b/src/scss/z-index.scss index 18f26221..2d5139b4 100644 --- a/src/scss/z-index.scss +++ b/src/scss/z-index.scss @@ -18,6 +18,3 @@ $z-index-submenu: 5; $z-index-menu: 4; $z-index-drawer: 3; $z-index-status-bar: 2; - -// The base z-index when the card is not hovered over. See note in card.scss . -$z-index-card-flatten: 0; diff --git a/tests/card-controller/expand-manager.test.ts b/tests/card-controller/expand-manager.test.ts index ad301c86..f1167378 100644 --- a/tests/card-controller/expand-manager.test.ts +++ b/tests/card-controller/expand-manager.test.ts @@ -1,7 +1,8 @@ import { describe, expect, it, vi } from 'vitest'; import { ExpandManager } from '../../src/card-controller/expand-manager'; -import { createCardAPI } from '../test-utils'; +import { createCardAPI, createLitElement } from '../test-utils'; +// @vitest-environment jsdom describe('ExpandManager', () => { it('should construct', () => { const api = createCardAPI(); @@ -19,6 +20,8 @@ describe('ExpandManager', () => { it('should set expanded', () => { const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(true); const manager = new ExpandManager(api); @@ -28,10 +31,13 @@ describe('ExpandManager', () => { expect(api.getFullscreenManager().setFullscreen).toBeCalledWith(false); expect(api.getConditionStateManager().setState).toBeCalledWith({ expand: true }); expect(api.getCardElementManager().update).toBeCalled(); + expect(element.hasAttribute('expanded')).toBeTruthy(); }); it('should not exit fullscreen when not in fullscreen', () => { const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(false); const manager = new ExpandManager(api); @@ -42,13 +48,45 @@ describe('ExpandManager', () => { it('should toggle expanded', () => { const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(false); const manager = new ExpandManager(api); manager.toggleExpanded(); expect(manager.isExpanded()).toBeTruthy(); + expect(element.hasAttribute('expanded')).toBeTruthy(); manager.toggleExpanded(); expect(manager.isExpanded()).toBeFalsy(); + expect(element.hasAttribute('expanded')).toBeFalsy(); + }); + + it('should set expanded attribute on card element when expanded', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(false); + const manager = new ExpandManager(api); + + expect(element.hasAttribute('expanded')).toBeFalsy(); + + manager.setExpanded(true); + + expect(element.hasAttribute('expanded')).toBeTruthy(); + }); + + it('should remove expanded attribute on card element when collapsed', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(false); + const manager = new ExpandManager(api); + + manager.setExpanded(true); + expect(element.hasAttribute('expanded')).toBeTruthy(); + + manager.setExpanded(false); + expect(element.hasAttribute('expanded')).toBeFalsy(); }); });