@deck.gl-community/widgets 9.3.1-alpha.0 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/index.cjs +1858 -2188
  2. package/dist/index.cjs.map +4 -4
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/lib/settings/settings.d.ts +33 -7
  8. package/dist/lib/settings/settings.d.ts.map +1 -1
  9. package/dist/lib/settings/settings.js.map +1 -1
  10. package/dist/widget-panels/keyboard-shortcuts-widget.d.ts +0 -25
  11. package/dist/widget-panels/keyboard-shortcuts-widget.d.ts.map +1 -1
  12. package/dist/widget-panels/keyboard-shortcuts-widget.js +2 -147
  13. package/dist/widget-panels/keyboard-shortcuts-widget.js.map +1 -1
  14. package/dist/widget-panels/settings-panel.js +1 -1
  15. package/dist/widget-panels/settings-panel.js.map +1 -1
  16. package/dist/widget-panels/settings-panel.test.js +1 -1
  17. package/dist/widget-panels/settings-panel.test.js.map +1 -1
  18. package/package.json +2 -2
  19. package/src/index.ts +5 -8
  20. package/src/lib/settings/settings.ts +40 -15
  21. package/src/widget-panels/keyboard-shortcuts-widget.tsx +1 -247
  22. package/src/widget-panels/settings-panel.test.tsx +1 -1
  23. package/src/widget-panels/settings-panel.tsx +1 -1
  24. package/dist/widgets/keyboard-shortcuts-widget.d.ts +0 -28
  25. package/dist/widgets/keyboard-shortcuts-widget.d.ts.map +0 -1
  26. package/dist/widgets/keyboard-shortcuts-widget.js +0 -125
  27. package/dist/widgets/keyboard-shortcuts-widget.js.map +0 -1
  28. package/dist/widgets/settings-widget.d.ts +0 -64
  29. package/dist/widgets/settings-widget.d.ts.map +0 -1
  30. package/dist/widgets/settings-widget.js +0 -148
  31. package/dist/widgets/settings-widget.js.map +0 -1
  32. package/src/widgets/keyboard-shortcuts-widget.tsx +0 -245
  33. package/src/widgets/settings-widget.tsx +0 -277
@@ -1,148 +0,0 @@
1
- var _a;
2
- import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
3
- /** @jsxImportSource preact */
4
- import { Widget } from '@deck.gl/core';
5
- import { render } from 'preact';
6
- import { useEffect, useRef, useState } from 'preact/hooks';
7
- import { SettingsPanelContent } from "../widget-panels/settings-panel.js";
8
- import { IconButton, makeTextIcon } from "../widget-components/icon-button.js";
9
- const PANE_STYLE = {
10
- position: 'absolute',
11
- top: 'calc(100% + 8px)',
12
- left: 0,
13
- width: '380px',
14
- maxHeight: 'min(460px, calc(100vh - 60px))',
15
- borderRadius: '8px',
16
- border: '1px solid rgba(71, 85, 105, 0.55)',
17
- background: 'rgba(15, 23, 42, 0.94)',
18
- color: 'rgba(241, 245, 249, 0.98)',
19
- boxShadow: '0 12px 32px rgba(2, 6, 23, 0.55)',
20
- display: 'flex',
21
- flexDirection: 'column',
22
- overflow: 'hidden',
23
- pointerEvents: 'auto',
24
- zIndex: 20,
25
- '--button-background': 'rgba(30, 41, 59, 0.92)',
26
- '--button-background-hover': 'rgba(15, 23, 42, 0.9)',
27
- '--button-inner-stroke': '1px solid rgba(100, 116, 139, 0.72)',
28
- '--button-corner-radius': '8px',
29
- '--button-text': 'rgba(241, 245, 249, 0.98)',
30
- '--button-icon-idle': 'rgba(203, 213, 225, 0.92)',
31
- '--button-icon-hover': 'rgba(125, 211, 252, 0.98)',
32
- '--button-backdrop-filter': 'blur(10px)',
33
- '--container-background': 'rgba(15, 23, 42, 0.98)',
34
- '--menu-item-hover': 'rgba(51, 65, 85, 0.82)'
35
- };
36
- const HEADER_STYLE = {
37
- display: 'flex',
38
- alignItems: 'center',
39
- justifyContent: 'space-between',
40
- borderBottom: '1px solid rgba(100, 116, 139, 0.45)',
41
- padding: '10px 12px'
42
- };
43
- const SETTINGS_BUTTON_ICON = makeTextIcon('⚙', 24, 36);
44
- function stopPropagation(event) {
45
- event.stopPropagation();
46
- }
47
- const DEFAULT_SETTINGS_WIDGET_SCHEMA = { sections: [] };
48
- const DEFAULT_SETTINGS_WIDGET_STATE = {};
49
- function SettingsWidgetView({ label, schema, settings, onSettingsChange }) {
50
- const containerRef = useRef(null);
51
- const [isPaneOpen, setIsPaneOpen] = useState(false);
52
- useEffect(() => {
53
- if (isPaneOpen && typeof document !== 'undefined') {
54
- const handleDocumentPointerDown = (event) => {
55
- if (!containerRef.current || !event.target) {
56
- return;
57
- }
58
- if (!containerRef.current.contains(event.target)) {
59
- setIsPaneOpen(false);
60
- }
61
- };
62
- document.addEventListener('pointerdown', handleDocumentPointerDown);
63
- return () => {
64
- document.removeEventListener('pointerdown', handleDocumentPointerDown);
65
- };
66
- }
67
- return undefined;
68
- }, [isPaneOpen]);
69
- return (_jsxs("div", { ref: containerRef, style: { position: 'relative', pointerEvents: 'auto' }, children: [_jsx(IconButton, { icon: SETTINGS_BUTTON_ICON, title: label, className: isPaneOpen ? 'deck-widget-button-active' : '', onClick: () => setIsPaneOpen((previous) => !previous) }), isPaneOpen && (_jsxs("div", { role: "dialog", "aria-label": schema.title ?? label, style: PANE_STYLE, onPointerDown: (event) => stopPropagation(event), onMouseDown: (event) => stopPropagation(event), onWheel: (event) => stopPropagation(event), onClick: (event) => stopPropagation(event), children: [_jsxs("div", { style: HEADER_STYLE, children: [_jsx("div", { style: { fontSize: '13px', fontWeight: 700 }, children: schema.title ?? label }), _jsx("button", { type: "button", onClick: () => setIsPaneOpen(false), style: {
70
- border: 0,
71
- borderRadius: '4px',
72
- padding: '2px 6px',
73
- background: 'rgba(51, 65, 85, 0.8)',
74
- color: 'inherit',
75
- cursor: 'pointer',
76
- fontSize: '14px',
77
- lineHeight: 1
78
- }, title: "Close settings", "aria-label": "Close settings", children: "\u00D7" })] }), _jsx(SettingsPanelContent, { schema: schema, settings: settings, onSettingsChange: onSettingsChange })] }))] }));
79
- }
80
- export class SettingsWidget extends Widget {
81
- static defaultProps = {
82
- ...Widget.defaultProps,
83
- id: 'settings',
84
- placement: 'top-left',
85
- label: 'Settings',
86
- schema: DEFAULT_SETTINGS_WIDGET_SCHEMA,
87
- settings: DEFAULT_SETTINGS_WIDGET_STATE,
88
- onSettingsChange: undefined
89
- };
90
- className = 'deck-widget-settings';
91
- placement = _a.defaultProps.placement;
92
- #label = _a.defaultProps.label;
93
- #schema = _a.defaultProps.schema;
94
- #settings = _a.defaultProps.settings;
95
- #onSettingsChange = _a.defaultProps.onSettingsChange;
96
- #rootElement = null;
97
- constructor(props = {}) {
98
- super({ ..._a.defaultProps, ...props });
99
- if (props.placement !== undefined) {
100
- this.placement = props.placement;
101
- }
102
- if (props.label !== undefined) {
103
- this.#label = props.label;
104
- }
105
- if (props.schema !== undefined) {
106
- this.#schema = props.schema;
107
- }
108
- if (props.settings !== undefined) {
109
- this.#settings = props.settings;
110
- }
111
- if (props.onSettingsChange !== undefined) {
112
- this.#onSettingsChange = props.onSettingsChange;
113
- }
114
- }
115
- setProps(props) {
116
- if (props.placement !== undefined) {
117
- this.placement = props.placement;
118
- }
119
- if (props.label !== undefined) {
120
- this.#label = props.label;
121
- }
122
- if (props.schema !== undefined) {
123
- this.#schema = props.schema;
124
- }
125
- if (props.settings !== undefined) {
126
- this.#settings = props.settings;
127
- }
128
- if (props.onSettingsChange !== undefined) {
129
- this.#onSettingsChange = props.onSettingsChange;
130
- }
131
- super.setProps(props);
132
- }
133
- onRenderHTML(rootElement) {
134
- this.#rootElement = rootElement;
135
- const className = ['deck-widget', this.className, this.props.className]
136
- .filter(Boolean)
137
- .join(' ');
138
- rootElement.className = className;
139
- render(_jsx(SettingsWidgetView, { label: this.#label, schema: this.#schema, settings: this.#settings, onSettingsChange: this.#onSettingsChange }), rootElement);
140
- }
141
- onRemove() {
142
- if (this.#rootElement) {
143
- render(null, this.#rootElement);
144
- }
145
- }
146
- }
147
- _a = SettingsWidget;
148
- //# sourceMappingURL=settings-widget.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"settings-widget.js","sourceRoot":"","sources":["../../src/widgets/settings-widget.tsx"],"names":[],"mappings":"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"}
@@ -1,245 +0,0 @@
1
- /** @jsxImportSource preact */
2
- import {Widget} from '@deck.gl/core';
3
- import {render} from 'preact';
4
- import {useState} from 'preact/hooks';
5
-
6
- import {formatKey} from '../keyboard-shortcuts/keyboard-shortcuts';
7
- import {KeyboardShortcutsManager} from '../keyboard-shortcuts/keyboard-shortcuts-manager';
8
-
9
- import type {KeyboardShortcut} from '../keyboard-shortcuts/keyboard-shortcuts';
10
- import type {WidgetPlacement, WidgetProps} from '@deck.gl/core';
11
- import type {JSX} from 'preact';
12
-
13
- export type KeyboardShortcutsWidgetProps = WidgetProps & {
14
- placement?: WidgetPlacement;
15
- keyboardShortcuts: KeyboardShortcut[];
16
- installShortcuts?: boolean;
17
- };
18
-
19
- export class KeyboardShortcutsWidget extends Widget<KeyboardShortcutsWidgetProps> {
20
- static override defaultProps = {
21
- ...Widget.defaultProps,
22
- id: 'keyboard-bindings',
23
- placement: 'top-left',
24
- keyboardShortcuts: []
25
- } satisfies Required<WidgetProps> &
26
- Required<Pick<KeyboardShortcutsWidgetProps, 'placement' | 'keyboardShortcuts'>> &
27
- KeyboardShortcutsWidgetProps;
28
-
29
- className = 'deck-widget-keyboard-bindings';
30
- placement: WidgetPlacement = KeyboardShortcutsWidget.defaultProps.placement;
31
-
32
- #rootElement: HTMLElement | null = null;
33
- #keyboardShortcuts: KeyboardShortcut[] = KeyboardShortcutsWidget.defaultProps.keyboardShortcuts;
34
- #keyboardShortcutsManager: KeyboardShortcutsManager | null = null;
35
-
36
- constructor(props: KeyboardShortcutsWidgetProps) {
37
- super({...KeyboardShortcutsWidget.defaultProps, ...props});
38
- this.#keyboardShortcuts = props.keyboardShortcuts;
39
- if (props.placement !== undefined) {
40
- this.placement = props.placement;
41
- }
42
- }
43
-
44
- override setProps(props: Partial<KeyboardShortcutsWidgetProps>): void {
45
- if (props.keyboardShortcuts !== undefined) {
46
- this.#keyboardShortcuts = props.keyboardShortcuts;
47
- }
48
- if (props.placement !== undefined) {
49
- this.placement = props.placement;
50
- }
51
- super.setProps(props);
52
- }
53
-
54
- override onAdd(): void {
55
- // @ts-expect-error Accessing protected member 'eventManager'.
56
- const eventManager = this.deck?.eventManager;
57
- if (eventManager && this.props.installShortcuts) {
58
- this.#keyboardShortcutsManager = new KeyboardShortcutsManager(
59
- eventManager,
60
- this.#keyboardShortcuts
61
- );
62
- this.#keyboardShortcutsManager.start();
63
- }
64
- }
65
-
66
- override onRenderHTML(rootElement: HTMLElement): void {
67
- this.#rootElement = rootElement;
68
-
69
- const className = ['deck-widget', this.className, this.props.className]
70
- .filter(Boolean)
71
- .join(' ');
72
- rootElement.className = className;
73
-
74
- render(
75
- <KeyboardShortcutsWidgetView keyboardShortcuts={this.#keyboardShortcuts} />,
76
- rootElement
77
- );
78
- }
79
-
80
- override onRemove(): void {
81
- if (this.#rootElement) {
82
- render(null, this.#rootElement);
83
- }
84
- if (this.#keyboardShortcutsManager) {
85
- this.#keyboardShortcutsManager.stop();
86
- this.#keyboardShortcutsManager = null;
87
- }
88
- }
89
- }
90
-
91
- const MODAL_BACKDROP_STYLE: JSX.CSSProperties = {
92
- position: 'fixed',
93
- inset: 0,
94
- display: 'flex',
95
- alignItems: 'center',
96
- justifyContent: 'center',
97
- backgroundColor: 'rgba(15, 23, 42, 0.28)',
98
- pointerEvents: 'auto',
99
- zIndex: 1000
100
- };
101
-
102
- const MODAL_STYLE: JSX.CSSProperties = {
103
- width: 'min(420px, calc(100vw - 24px))',
104
- maxHeight: 'min(460px, calc(100vh - 24px))',
105
- borderRadius: '10px',
106
- border: '1px solid rgba(148, 163, 184, 0.75)',
107
- backgroundColor: 'rgba(255, 255, 255, 0.98)',
108
- boxShadow: '0 14px 40px rgba(15, 23, 42, 0.28)',
109
- display: 'flex',
110
- flexDirection: 'column',
111
- overflow: 'hidden'
112
- };
113
-
114
- const KEY_STYLE: JSX.CSSProperties = {
115
- borderRadius: '6px',
116
- border: '1px solid rgba(148, 163, 184, 0.85)',
117
- backgroundColor: 'rgba(248, 250, 252, 1)',
118
- padding: '2px 8px',
119
- fontSize: '11px',
120
- color: 'rgb(51, 65, 85)',
121
- whiteSpace: 'nowrap'
122
- };
123
-
124
- function KeyboardShortcutsWidgetView({keyboardShortcuts}: {keyboardShortcuts: KeyboardShortcut[]}) {
125
- const [isOpen, setIsOpen] = useState(false);
126
-
127
- return (
128
- <>
129
- <div className="deck-widget-button">
130
- <button
131
- className="deck-widget-icon-button"
132
- type="button"
133
- title="Keyboard shortcuts"
134
- aria-label="Keyboard shortcuts"
135
- onClick={() => setIsOpen(true)}
136
- >
137
- <span
138
- style={{
139
- fontSize: '12px',
140
- fontWeight: 700,
141
- color: 'var(--deck-widget-icon-color, #0f172a)'
142
- }}
143
- >
144
- <kbd
145
- style={{
146
- color: 'var(--deck-widget-icon-color, #0f172a)'
147
- }}
148
- >
149
- ?
150
- </kbd>
151
- </span>
152
- </button>
153
- </div>
154
-
155
- {isOpen && (
156
- <div style={MODAL_BACKDROP_STYLE} onClick={() => setIsOpen(false)}>
157
- <div
158
- style={MODAL_STYLE}
159
- role="dialog"
160
- aria-label="Keyboard Shortcuts"
161
- onClick={(event) => event.stopPropagation()}
162
- >
163
- <div
164
- style={{
165
- display: 'flex',
166
- alignItems: 'center',
167
- justifyContent: 'space-between',
168
- borderBottom: '1px solid rgba(226, 232, 240, 1)',
169
- padding: '10px 12px'
170
- }}
171
- >
172
- <div style={{fontSize: '14px', fontWeight: 700, color: 'rgb(30, 41, 59)'}}>
173
- Keyboard Shortcuts
174
- </div>
175
- <button
176
- type="button"
177
- onClick={() => setIsOpen(false)}
178
- style={{
179
- border: 0,
180
- background: 'transparent',
181
- color: 'rgb(71, 85, 105)',
182
- cursor: 'pointer',
183
- fontSize: '18px',
184
- lineHeight: '18px'
185
- }}
186
- aria-label="Close keyboard shortcuts"
187
- title="Close"
188
- >
189
- ×
190
- </button>
191
- </div>
192
-
193
- <div style={{overflowY: 'auto', padding: '10px 12px'}}>
194
- <div style={{display: 'grid', gap: '8px'}}>
195
- {keyboardShortcuts.map((shortcut, index) => (
196
- <div
197
- key={`${shortcut.name}-${shortcut.key}-${index}`}
198
- style={{
199
- display: 'flex',
200
- alignItems: 'center',
201
- justifyContent: 'space-between',
202
- gap: '8px'
203
- }}
204
- >
205
- <ShortcutKey shortcut={shortcut} />
206
- <span style={{fontSize: '12px', color: 'rgb(71, 85, 105)'}}>
207
- {shortcut.name}
208
- </span>
209
- </div>
210
- ))}
211
- </div>
212
- </div>
213
- </div>
214
- </div>
215
- )}
216
- </>
217
- );
218
- }
219
-
220
- function ShortcutKey({shortcut}: {shortcut: KeyboardShortcut}) {
221
- return (
222
- <div style={{color: 'rgb(51, 65, 85)', fontSize: '11px'}}>
223
- {shortcut.commandKey && (
224
- <span>
225
- <kbd style={KEY_STYLE}>⌘</kbd>
226
- {' + '}
227
- </span>
228
- )}
229
- {shortcut.ctrlKey && (
230
- <span>
231
- <kbd style={KEY_STYLE}>^</kbd>
232
- {' + '}
233
- </span>
234
- )}
235
- {shortcut.shiftKey && (
236
- <span>
237
- <kbd style={KEY_STYLE}>Shift</kbd>
238
- {' + '}
239
- </span>
240
- )}
241
- {shortcut.key && <kbd style={KEY_STYLE}>{formatKey(shortcut.key)}</kbd>}
242
- {shortcut.dragMouse && 'drag mouse'}
243
- </div>
244
- );
245
- }
@@ -1,277 +0,0 @@
1
- /** @jsxImportSource preact */
2
- import {Widget} from '@deck.gl/core';
3
- import {render} from 'preact';
4
- import {useEffect, useRef, useState} from 'preact/hooks';
5
-
6
- import {SettingsPanelContent} from '../widget-panels/settings-panel';
7
- import {IconButton, makeTextIcon} from '../widget-components/icon-button';
8
-
9
- import type {WidgetPlacement, WidgetProps} from '@deck.gl/core';
10
- import type {JSX} from 'preact';
11
-
12
- export type SettingsWidgetValue = boolean | number | string;
13
-
14
- export type SettingsWidgetSettingType = 'boolean' | 'number' | 'string' | 'select';
15
-
16
- export type SettingsWidgetOption =
17
- | SettingsWidgetValue
18
- | {
19
- label: string;
20
- value: SettingsWidgetValue;
21
- };
22
-
23
- export type SettingsWidgetSettingDescriptor = {
24
- /** Path in the settings object (dot notation supported). */
25
- name: string;
26
- /** Human-friendly label shown in the control list. Defaults to `name`. */
27
- label?: string;
28
- description?: string;
29
- type: SettingsWidgetSettingType;
30
- min?: number;
31
- max?: number;
32
- step?: number;
33
- options?: SettingsWidgetOption[];
34
- defaultValue?: SettingsWidgetValue;
35
- };
36
-
37
- export type SettingsWidgetSectionDescriptor = {
38
- /** Optional stable id for preserving collapse state across re-renders. */
39
- id?: string;
40
- name: string;
41
- description?: string;
42
- /** Whether this section starts collapsed when first seen. Defaults to true. */
43
- initiallyCollapsed?: boolean;
44
- settings: SettingsWidgetSettingDescriptor[];
45
- };
46
-
47
- export type SettingsWidgetSchema = {
48
- title?: string;
49
- sections: SettingsWidgetSectionDescriptor[];
50
- };
51
-
52
- export type SettingsWidgetState = Record<string, unknown>;
53
-
54
- export type SettingsWidgetProps = WidgetProps & {
55
- placement?: WidgetPlacement;
56
- label?: string;
57
- schema?: SettingsWidgetSchema;
58
- settings?: SettingsWidgetState;
59
- onSettingsChange?: (settings: SettingsWidgetState) => void;
60
- };
61
-
62
- const PANE_STYLE: JSX.CSSProperties & Record<string, string | number> = {
63
- position: 'absolute',
64
- top: 'calc(100% + 8px)',
65
- left: 0,
66
- width: '380px',
67
- maxHeight: 'min(460px, calc(100vh - 60px))',
68
- borderRadius: '8px',
69
- border: '1px solid rgba(71, 85, 105, 0.55)',
70
- background: 'rgba(15, 23, 42, 0.94)',
71
- color: 'rgba(241, 245, 249, 0.98)',
72
- boxShadow: '0 12px 32px rgba(2, 6, 23, 0.55)',
73
- display: 'flex',
74
- flexDirection: 'column',
75
- overflow: 'hidden',
76
- pointerEvents: 'auto',
77
- zIndex: 20,
78
- '--button-background': 'rgba(30, 41, 59, 0.92)',
79
- '--button-background-hover': 'rgba(15, 23, 42, 0.9)',
80
- '--button-inner-stroke': '1px solid rgba(100, 116, 139, 0.72)',
81
- '--button-corner-radius': '8px',
82
- '--button-text': 'rgba(241, 245, 249, 0.98)',
83
- '--button-icon-idle': 'rgba(203, 213, 225, 0.92)',
84
- '--button-icon-hover': 'rgba(125, 211, 252, 0.98)',
85
- '--button-backdrop-filter': 'blur(10px)',
86
- '--container-background': 'rgba(15, 23, 42, 0.98)',
87
- '--menu-item-hover': 'rgba(51, 65, 85, 0.82)'
88
- };
89
-
90
- const HEADER_STYLE: JSX.CSSProperties = {
91
- display: 'flex',
92
- alignItems: 'center',
93
- justifyContent: 'space-between',
94
- borderBottom: '1px solid rgba(100, 116, 139, 0.45)',
95
- padding: '10px 12px'
96
- };
97
-
98
- const SETTINGS_BUTTON_ICON = makeTextIcon('⚙', 24, 36);
99
-
100
- function stopPropagation(event: Event) {
101
- event.stopPropagation();
102
- }
103
-
104
- type SettingsWidgetViewProps = {
105
- label: string;
106
- schema: SettingsWidgetSchema;
107
- settings: SettingsWidgetState;
108
- onSettingsChange?: (settings: SettingsWidgetState) => void;
109
- };
110
-
111
- const DEFAULT_SETTINGS_WIDGET_SCHEMA: SettingsWidgetSchema = {sections: []};
112
- const DEFAULT_SETTINGS_WIDGET_STATE: SettingsWidgetState = {};
113
-
114
- function SettingsWidgetView({label, schema, settings, onSettingsChange}: SettingsWidgetViewProps) {
115
- const containerRef = useRef<HTMLDivElement | null>(null);
116
- const [isPaneOpen, setIsPaneOpen] = useState(false);
117
-
118
- useEffect(() => {
119
- if (isPaneOpen && typeof document !== 'undefined') {
120
- const handleDocumentPointerDown = (event: PointerEvent) => {
121
- if (!containerRef.current || !event.target) {
122
- return;
123
- }
124
- if (!containerRef.current.contains(event.target as Node)) {
125
- setIsPaneOpen(false);
126
- }
127
- };
128
-
129
- document.addEventListener('pointerdown', handleDocumentPointerDown);
130
- return () => {
131
- document.removeEventListener('pointerdown', handleDocumentPointerDown);
132
- };
133
- }
134
-
135
- return undefined;
136
- }, [isPaneOpen]);
137
-
138
- return (
139
- <div ref={containerRef} style={{position: 'relative', pointerEvents: 'auto'}}>
140
- <IconButton
141
- icon={SETTINGS_BUTTON_ICON}
142
- title={label}
143
- className={isPaneOpen ? 'deck-widget-button-active' : ''}
144
- onClick={() => setIsPaneOpen((previous) => !previous)}
145
- />
146
-
147
- {isPaneOpen && (
148
- <div
149
- role="dialog"
150
- aria-label={schema.title ?? label}
151
- style={PANE_STYLE}
152
- onPointerDown={(event) => stopPropagation(event as unknown as Event)}
153
- onMouseDown={(event) => stopPropagation(event as unknown as Event)}
154
- onWheel={(event) => stopPropagation(event as unknown as Event)}
155
- onClick={(event) => stopPropagation(event as unknown as Event)}
156
- >
157
- <div style={HEADER_STYLE}>
158
- <div style={{fontSize: '13px', fontWeight: 700}}>{schema.title ?? label}</div>
159
- <button
160
- type="button"
161
- onClick={() => setIsPaneOpen(false)}
162
- style={{
163
- border: 0,
164
- borderRadius: '4px',
165
- padding: '2px 6px',
166
- background: 'rgba(51, 65, 85, 0.8)',
167
- color: 'inherit',
168
- cursor: 'pointer',
169
- fontSize: '14px',
170
- lineHeight: 1
171
- }}
172
- title="Close settings"
173
- aria-label="Close settings"
174
- >
175
- ×
176
- </button>
177
- </div>
178
-
179
- <SettingsPanelContent
180
- schema={schema}
181
- settings={settings}
182
- onSettingsChange={onSettingsChange}
183
- />
184
- </div>
185
- )}
186
- </div>
187
- );
188
- }
189
-
190
- export class SettingsWidget extends Widget<SettingsWidgetProps> {
191
- static override defaultProps = {
192
- ...Widget.defaultProps,
193
- id: 'settings',
194
- placement: 'top-left',
195
- label: 'Settings',
196
- schema: DEFAULT_SETTINGS_WIDGET_SCHEMA,
197
- settings: DEFAULT_SETTINGS_WIDGET_STATE,
198
- onSettingsChange: undefined
199
- } satisfies Required<WidgetProps> &
200
- Required<Pick<SettingsWidgetProps, 'placement' | 'label' | 'schema' | 'settings'>> &
201
- SettingsWidgetProps;
202
-
203
- className = 'deck-widget-settings';
204
- placement: WidgetPlacement = SettingsWidget.defaultProps.placement;
205
-
206
- #label = SettingsWidget.defaultProps.label;
207
- #schema = SettingsWidget.defaultProps.schema;
208
- #settings = SettingsWidget.defaultProps.settings;
209
- #onSettingsChange: SettingsWidgetProps['onSettingsChange'] =
210
- SettingsWidget.defaultProps.onSettingsChange;
211
- #rootElement: HTMLElement | null = null;
212
-
213
- constructor(props: SettingsWidgetProps = {}) {
214
- super({...SettingsWidget.defaultProps, ...props});
215
-
216
- if (props.placement !== undefined) {
217
- this.placement = props.placement;
218
- }
219
- if (props.label !== undefined) {
220
- this.#label = props.label;
221
- }
222
- if (props.schema !== undefined) {
223
- this.#schema = props.schema;
224
- }
225
- if (props.settings !== undefined) {
226
- this.#settings = props.settings;
227
- }
228
- if (props.onSettingsChange !== undefined) {
229
- this.#onSettingsChange = props.onSettingsChange;
230
- }
231
- }
232
-
233
- override setProps(props: Partial<SettingsWidgetProps>): void {
234
- if (props.placement !== undefined) {
235
- this.placement = props.placement;
236
- }
237
- if (props.label !== undefined) {
238
- this.#label = props.label;
239
- }
240
- if (props.schema !== undefined) {
241
- this.#schema = props.schema;
242
- }
243
- if (props.settings !== undefined) {
244
- this.#settings = props.settings;
245
- }
246
- if (props.onSettingsChange !== undefined) {
247
- this.#onSettingsChange = props.onSettingsChange;
248
- }
249
- super.setProps(props);
250
- }
251
-
252
- override onRenderHTML(rootElement: HTMLElement): void {
253
- this.#rootElement = rootElement;
254
-
255
- const className = ['deck-widget', this.className, this.props.className]
256
- .filter(Boolean)
257
- .join(' ');
258
-
259
- rootElement.className = className;
260
-
261
- render(
262
- <SettingsWidgetView
263
- label={this.#label}
264
- schema={this.#schema}
265
- settings={this.#settings}
266
- onSettingsChange={this.#onSettingsChange}
267
- />,
268
- rootElement
269
- );
270
- }
271
-
272
- override onRemove(): void {
273
- if (this.#rootElement) {
274
- render(null, this.#rootElement);
275
- }
276
- }
277
- }