-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathfullscreen-widget.tsx
More file actions
140 lines (123 loc) · 4.31 KB
/
Copy pathfullscreen-widget.tsx
File metadata and controls
140 lines (123 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
/* global document */
import {log, Widget, type WidgetProps, type WidgetPlacement} from '@deck.gl/core';
import {render} from 'preact';
import {IconButton} from './lib/components/icon-button';
/* eslint-enable max-len */
export type FullscreenWidgetProps = WidgetProps & {
id?: string;
/** Widget positioning within the view. Default 'top-left'. */
placement?: WidgetPlacement;
/** View to attach to and interact with. Required when using multiple views. */
viewId?: string | null;
/** Tooltip message when out of fullscreen. */
enterLabel?: string;
/** Tooltip message when fullscreen. */
exitLabel?: string;
/** Custom tooltip content when out of fullscreen. Overrides enterLabel for tooltip display. */
enterTooltip?: string | HTMLElement | false;
/** Custom tooltip content when fullscreen. Overrides exitLabel for tooltip display. */
exitTooltip?: string | HTMLElement | false;
/**
* A compatible DOM element which should be made full screen. By default, the map container element will be made full screen.
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen#Compatible_elements
*/
container?: HTMLElement;
/**
* Callback when fullscreen state changes (via user click or browser fullscreen events).
*/
onFullscreenChange?: (fullscreen: boolean) => void;
};
export class FullscreenWidget extends Widget<FullscreenWidgetProps> {
static defaultProps: Required<FullscreenWidgetProps> = {
...Widget.defaultProps,
id: 'fullscreen',
placement: 'top-left',
viewId: null,
enterLabel: 'Enter Fullscreen',
exitLabel: 'Exit Fullscreen',
enterTooltip: undefined!,
exitTooltip: undefined!,
container: undefined!,
onFullscreenChange: () => {}
};
className = 'deck-widget-fullscreen';
placement: WidgetPlacement = 'top-left';
fullscreen: boolean = false;
constructor(props: FullscreenWidgetProps = {}) {
super(props);
this.setProps(this.props);
}
onAdd(): void {
document.addEventListener('fullscreenchange', this.onFullscreenChange.bind(this));
}
onRemove() {
document.removeEventListener('fullscreenchange', this.onFullscreenChange.bind(this));
}
onRenderHTML(rootElement: HTMLElement): void {
const isFullscreen = this.getFullscreen();
render(
<IconButton
onClick={() => {
this.handleClick().catch(err => log.error(err)());
}}
label={isFullscreen ? this.props.exitLabel : this.props.enterLabel}
tooltip={isFullscreen ? this.props.exitTooltip : this.props.enterTooltip}
className={isFullscreen ? 'deck-widget-fullscreen-exit' : 'deck-widget-fullscreen-enter'}
/>,
rootElement
);
}
setProps(props: Partial<FullscreenWidgetProps>) {
this.placement = props.placement ?? this.placement;
this.viewId = props.viewId ?? this.viewId;
super.setProps(props);
}
getContainer() {
return this.props.container || this.deck?.props.parent || this.deck?.getCanvas()?.parentElement;
}
getFullscreen(): boolean {
return this.fullscreen;
}
onFullscreenChange() {
const fullscreen = document.fullscreenElement === this.getContainer();
if (fullscreen !== this.fullscreen) {
this.fullscreen = fullscreen;
this.props.onFullscreenChange?.(fullscreen);
this.updateHTML();
}
}
async handleClick() {
const isFullscreen = this.getFullscreen();
if (isFullscreen) {
await this.exitFullscreen();
} else {
await this.requestFullscreen();
}
// Note: updateHTML is called by onFullscreenChange event handler
}
async requestFullscreen() {
const container = this.getContainer();
if (container?.requestFullscreen) {
await container.requestFullscreen({navigationUI: 'hide'});
} else {
this.togglePseudoFullscreen();
}
}
async exitFullscreen() {
if (document.exitFullscreen) {
await document.exitFullscreen();
} else {
this.togglePseudoFullscreen();
}
}
togglePseudoFullscreen() {
this.getContainer()?.classList.toggle('deck-pseudo-fullscreen');
// No fullscreenchange event fires for pseudo-fullscreen, so manually update state
this.fullscreen = !this.fullscreen;
this.props.onFullscreenChange?.(this.fullscreen);
this.updateHTML();
}
}