Skip to content

Commit 80665be

Browse files
committed
refactor: Fullscreen logic into a controller
Removed global fullscreen controller for tile manager. Tiles now have their own controller to handle fullscreen logic. Tile headers invoke the fullscreen logic through the context object. Removed double click trigger for fullscreen and adjusted tests where applicable.
1 parent 1db557f commit 80665be

File tree

7 files changed

+113
-117
lines changed

7 files changed

+113
-117
lines changed

src/components/common/context.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
import { createContext } from '@lit/context';
22
import type IgcCarouselComponent from '../carousel/carousel.js';
3-
import type { TileManagerContext } from '../tile-manager/tile-manager.js';
3+
import type IgcTileManagerComponent from '../tile-manager/tile-manager.js';
44
import type IgcTileComponent from '../tile-manager/tile.js';
55

6-
export const carouselContext = createContext<IgcCarouselComponent>(
6+
export type TileManagerContext = {
7+
instance: IgcTileManagerComponent;
8+
draggedItem: IgcTileComponent | null;
9+
};
10+
11+
export type TileContext = {
12+
instance: IgcTileComponent;
13+
setFullscreenState: (
14+
fullscreen: boolean,
15+
isUserTriggered?: boolean
16+
) => unknown;
17+
};
18+
19+
const carouselContext = createContext<IgcCarouselComponent>(
720
Symbol('carousel-context')
821
);
922

10-
export const tileContext = createContext<IgcTileComponent>(
11-
Symbol('tile-context')
12-
);
23+
const tileContext = createContext<TileContext>(Symbol('tile-context'));
1324

14-
export const tileManagerContext = createContext<TileManagerContext>(
25+
const tileManagerContext = createContext<TileManagerContext>(
1526
Symbol('tile-manager-context')
1627
);
28+
29+
export { carouselContext, tileContext, tileManagerContext };
Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,61 @@
1-
import type { ReactiveController } from 'lit';
2-
import { isElement } from '../../common/util.js';
3-
import type IgcTileManagerComponent from '../tile-manager.js';
4-
import IgcTileComponent from '../tile.js';
1+
import type { ReactiveController, ReactiveControllerHost } from 'lit';
52

6-
class TileManagerFullscreenController implements ReactiveController {
7-
private _host: IgcTileManagerComponent;
3+
type FullscreenControllerCallback = (state: boolean) => boolean;
84

9-
constructor(host: IgcTileManagerComponent) {
5+
class FullscreenController implements ReactiveController {
6+
private _host: ReactiveControllerHost & HTMLElement;
7+
private _callback?: FullscreenControllerCallback;
8+
9+
private _fullscreen = false;
10+
11+
public get fullscreen(): boolean {
12+
return this._fullscreen;
13+
}
14+
15+
constructor(
16+
host: ReactiveControllerHost & HTMLElement,
17+
callback?: FullscreenControllerCallback
18+
) {
1019
this._host = host;
11-
this._host.addController(this);
20+
this._callback = callback;
21+
host.addController(this);
1222
}
1323

14-
private _isOwnTile(node: unknown): node is IgcTileComponent {
15-
return (
16-
isElement(node) &&
17-
node.matches(IgcTileComponent.tagName) &&
18-
this._host.contains(node)
19-
);
24+
public setState(fullscreen: boolean, isUserTriggered = false): void {
25+
if (isUserTriggered && this._callback) {
26+
if (!this._callback.call(this._host, fullscreen)) {
27+
return;
28+
}
29+
}
30+
31+
this._fullscreen = fullscreen;
32+
33+
if (this._fullscreen) {
34+
this._host.requestFullscreen();
35+
} else if (document.fullscreenElement) {
36+
document.exitFullscreen();
37+
}
2038
}
2139

22-
public handleEvent({ target }: Event): void {
23-
if (this._isOwnTile(target)) {
24-
target.draggable = !target.draggable;
40+
public handleEvent() {
41+
const isFullscreen = document.fullscreenElement === this._host;
42+
if (!isFullscreen && this._fullscreen) {
43+
this.setState(false, true);
2544
}
2645
}
2746

2847
public hostConnected(): void {
29-
document.addEventListener('fullscreenchange', this);
48+
this._host.addEventListener('fullscreenchange', this);
3049
}
3150

3251
public hostDisconnected(): void {
33-
document.addEventListener('fullscreenchange', this);
52+
this._host.removeEventListener('fullscreenchange', this);
3453
}
3554
}
3655

37-
export function addFullscreenController(host: IgcTileManagerComponent) {
38-
return new TileManagerFullscreenController(host);
56+
export function addFullscreenController(
57+
host: ReactiveControllerHost & HTMLElement,
58+
callback?: FullscreenControllerCallback
59+
) {
60+
return new FullscreenController(host, callback);
3961
}

src/components/tile-manager/tile-header.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ import { consume } from '@lit/context';
22
import { LitElement, html } from 'lit';
33
import { themes } from '../../theming/theming-decorator.js';
44
import IgcIconButtonComponent from '../button/icon-button.js';
5-
import { tileContext } from '../common/context.js';
5+
import { type TileContext, tileContext } from '../common/context.js';
66
import { registerComponent } from '../common/definitions/register.js';
77
import IgcDividerComponent from '../divider/divider.js';
88
import { all } from './themes/header.js';
99
import { styles as shared } from './themes/shared/header/tile-header.common.css.js';
1010
import { styles } from './themes/tile-header.base.css.js';
11-
import type IgcTileComponent from './tile.js';
1211

1312
/** A container for tile's header
1413
* @element igc-tile-header
@@ -35,7 +34,11 @@ export default class IgcTileHeaderComponent extends LitElement {
3534
}
3635

3736
@consume({ context: tileContext, subscribe: true })
38-
private _tile?: IgcTileComponent;
37+
private _tileContext?: TileContext;
38+
39+
private get _tile() {
40+
return this._tileContext?.instance;
41+
}
3942

4043
private get _isMaximized() {
4144
return this._tile ? this._tile.maximized : false;
@@ -52,8 +55,10 @@ export default class IgcTileHeaderComponent extends LitElement {
5255
}
5356

5457
private handleFullscreen() {
55-
if (this._tile) {
56-
this._tile.toggleFullscreen();
58+
if (this._tileContext) {
59+
this._tileContext.setFullscreenState(!this._isFullscreen, true);
60+
// REVIEW: Leave the `requestUpdate` call or trigger through `setValue` from the tile context?
61+
this.requestUpdate();
5762
}
5863
}
5964

@@ -64,6 +69,8 @@ export default class IgcTileHeaderComponent extends LitElement {
6469

6570
if (this._tile) {
6671
this._tile.maximized = !this._tile.maximized;
72+
// REVIEW: Leave the `requestUpdate` call or trigger through `setValue` from the tile context?
73+
this.requestUpdate();
6774
}
6875
}
6976

src/components/tile-manager/tile-manager.spec.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ describe('Tile Manager component', () => {
338338
restore();
339339
});
340340

341-
it('should correctly change fullscreen state on double click', async () => {
341+
it.skip('should correctly change fullscreen state on double click', async () => {
342342
simulateDoubleClick(tile);
343343
await elementUpdated(tileManager);
344344

@@ -378,13 +378,15 @@ describe('Tile Manager component', () => {
378378
});
379379

380380
it('can cancel `igcTileFullscreen` event', async () => {
381+
const tile = first(tileManager.tiles);
381382
const eventSpy = spy(tile, 'emitEvent');
383+
const fullscreenButton = getActionButtons(tile)[1];
382384

383385
tile.addEventListener('igcTileFullscreen', (ev: CustomEvent) => {
384386
ev.preventDefault();
385387
});
386388

387-
simulateDoubleClick(tile);
389+
simulateClick(fullscreenButton!);
388390
await elementUpdated(tileManager);
389391

390392
expect(eventSpy).to.have.been.calledWith(
@@ -422,14 +424,6 @@ describe('Tile Manager component', () => {
422424
await elementUpdated(tileManager);
423425
expect(btnFullscreen.name).equals('fullscreen_exit');
424426

425-
simulateDoubleClick(tile);
426-
await elementUpdated(tileManager);
427-
expect(btnFullscreen.name).equals('fullscreen');
428-
429-
simulateDoubleClick(tile);
430-
await elementUpdated(tileManager);
431-
expect(btnFullscreen.name).equals('fullscreen_exit');
432-
433427
simulateClick(btnFullscreen);
434428
await elementUpdated(tileManager);
435429
expect(btnFullscreen.name).equals('fullscreen');

src/components/tile-manager/tile-manager.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { registerComponent } from '../common/definitions/register.js';
1212
import type { Constructor } from '../common/mixins/constructor.js';
1313
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
1414
import { asNumber, findElementFromEventPath } from '../common/util.js';
15-
import { addFullscreenController } from './controllers/fullscreen.js';
1615
import { createTilesState, isSameTile, swapTiles } from './position.js';
1716
import { createSerializer } from './serializer.js';
1817
import { all } from './themes/container.js';
@@ -25,11 +24,6 @@ export interface IgcTileManagerComponentEventMap {
2524
igcTileDragStarted: CustomEvent<IgcTileComponent>;
2625
}
2726

28-
export type TileManagerContext = {
29-
instance: IgcTileManagerComponent;
30-
draggedItem: IgcTileComponent | null;
31-
};
32-
3327
/**
3428
* The tile manager component enables the dynamic arrangement, resizing, and interaction of tiles.
3529
*
@@ -169,7 +163,6 @@ export default class IgcTileManagerComponent extends EventEmitterMixin<
169163

170164
constructor() {
171165
super();
172-
addFullscreenController(this);
173166

174167
createMutationController(this, {
175168
callback: this._observerCallback,

0 commit comments

Comments
 (0)