@deck.gl/widgets 9.3.7 → 9.4.0-alpha.2

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.
@@ -4,20 +4,18 @@
4
4
 
5
5
  import {JSX, render} from 'preact';
6
6
  import {useState, useRef, useEffect} from 'preact/hooks';
7
- import {
8
- Widget,
9
- _deepEqual as deepEqual,
10
- type Deck,
11
- type WidgetProps,
12
- type View
13
- } from '@deck.gl/core';
14
-
15
- export type ViewLayout = {
7
+ import {Widget, _deepEqual as deepEqual, type WidgetProps, type View} from '@deck.gl/core';
8
+
9
+ import {buildViewsFromViewLayout} from './view-layout/build-views-from-view-layout';
10
+ import type {ViewLayoutSplitValues} from './view-layout/build-views-from-view-layout';
11
+ import type {ViewLayout, ViewLayoutChild} from './view-layout/view-layout';
12
+
13
+ export type SplitterWidgetViewLayout = {
16
14
  /** Stacking orientation of the sub views */
17
15
  orientation: 'vertical' | 'horizontal';
18
16
  /** Initial instances that describe the sub views.
19
17
  * x, y, width and height of the views' props will be overwritten by the SplitterWidget as split changes. */
20
- views: [view1: View | ViewLayout, view2: View | ViewLayout];
18
+ views: [view1: View | SplitterWidgetViewLayout, view2: View | SplitterWidgetViewLayout];
21
19
  /** The ratio of view1's share over the whole available height (vertical) or width (horizontal). Between 0-1.
22
20
  * @default 0.5
23
21
  */
@@ -38,6 +36,7 @@ export type ViewLayout = {
38
36
 
39
37
  type ManagedViewLayout = {
40
38
  id: number;
39
+ splitId: string;
41
40
  orientation: 'vertical' | 'horizontal';
42
41
  views: [view1: View | ManagedViewLayout, view2: View | ManagedViewLayout];
43
42
  split: number;
@@ -50,16 +49,27 @@ type ManagedViewLayout = {
50
49
  height: number;
51
50
  };
52
51
 
53
- function parseViewLayout(root: ViewLayout): ManagedViewLayout[] {
52
+ type AdaptedViewLayout = {
53
+ layout: ViewLayout;
54
+ viewLayouts: ManagedViewLayout[];
55
+ };
56
+
57
+ function adaptViewLayout(root: SplitterWidgetViewLayout): AdaptedViewLayout {
54
58
  const layoutsById: ManagedViewLayout[] = [];
55
- const isViewLayout = (v: View | ViewLayout): v is ViewLayout => 'views' in v;
56
- function createManagedViewLayout(l: ViewLayout): ManagedViewLayout {
59
+ const isViewLayout = (v: View | SplitterWidgetViewLayout): v is SplitterWidgetViewLayout =>
60
+ 'views' in v;
61
+ function adaptLayout(l: SplitterWidgetViewLayout): {
62
+ layout: ViewLayout;
63
+ managed: ManagedViewLayout;
64
+ } {
57
65
  const id = layoutsById.length;
66
+ const splitId = `splitter-${id}`;
58
67
  const minSplit = l.minSplit ?? 0.05;
59
68
  const maxSplit = l.maxSplit ?? 0.95;
60
69
  const split = Math.min(Math.max(l.initialSplit ?? 0.5, minSplit), maxSplit);
61
70
  const managed: ManagedViewLayout = {
62
71
  id,
72
+ splitId,
63
73
  orientation: l.orientation,
64
74
  views: l.views as [view1: View | ManagedViewLayout, view2: View | ManagedViewLayout],
65
75
  split,
@@ -72,85 +82,73 @@ function parseViewLayout(root: ViewLayout): ManagedViewLayout[] {
72
82
  height: 0
73
83
  };
74
84
  layoutsById.push(managed);
75
- managed.views = [
76
- isViewLayout(l.views[0]) ? createManagedViewLayout(l.views[0]) : l.views[0],
77
- isViewLayout(l.views[1]) ? createManagedViewLayout(l.views[1]) : l.views[1]
85
+
86
+ const childEntries = l.views.map(view => {
87
+ if (!isViewLayout(view)) {
88
+ return {layout: view, managed: view};
89
+ }
90
+ const adapted = adaptLayout(view);
91
+ return {layout: adapted.layout, managed: adapted.managed};
92
+ }) as [
93
+ {layout: ViewLayoutChild; managed: View | ManagedViewLayout},
94
+ {layout: ViewLayoutChild; managed: View | ManagedViewLayout}
78
95
  ];
79
- return managed;
96
+ managed.views = [childEntries[0].managed, childEntries[1].managed];
97
+
98
+ const layout: ViewLayout = {
99
+ orientation: l.orientation,
100
+ splitId,
101
+ initialSplit: split,
102
+ minSplit,
103
+ maxSplit,
104
+ views: [childEntries[0].layout, childEntries[1].layout]
105
+ };
106
+ return {layout, managed};
80
107
  }
81
- createManagedViewLayout(root);
82
- return layoutsById;
108
+
109
+ const {layout} = adaptLayout(root);
110
+ return {layout, viewLayouts: layoutsById};
83
111
  }
84
112
 
85
- function evaluateViews(root: ManagedViewLayout): View[] {
86
- const views: View[] = [];
87
- function evaluateViewLayout(
88
- l: ManagedViewLayout,
89
- x: number,
90
- y: number,
91
- width: number,
92
- height: number
93
- ) {
94
- l.x = x;
95
- l.y = y;
96
- l.width = width;
97
- l.height = height;
98
-
99
- const child1X = x;
100
- const child1Y = y;
101
- let child1Width = width;
102
- let child1Height = height;
103
- let child2X = x;
104
- let child2Y = y;
105
- let child2Width = width;
106
- let child2Height = height;
107
-
108
- if (l.orientation === 'horizontal') {
109
- child1Width = width * l.split;
110
- child2X = x + child1Width;
111
- child2Width = width - child1Width;
112
- } else {
113
- child1Height = height * l.split;
114
- child2Y = y + child1Height;
115
- child2Height = height - child1Height;
116
- }
113
+ function evaluateViews(
114
+ layout: ViewLayout,
115
+ viewLayouts: ManagedViewLayout[],
116
+ splitValues: ViewLayoutSplitValues
117
+ ): View[] {
118
+ const compiled = buildViewsFromViewLayout({
119
+ layout,
120
+ width: 100,
121
+ height: 100,
122
+ splitValues
123
+ });
117
124
 
118
- const [view1, view2] = l.views;
119
- if ('views' in view1) {
120
- evaluateViewLayout(view1, child1X, child1Y, child1Width, child1Height);
121
- } else {
122
- views.push(
123
- view1.clone({
124
- x: `${child1X}%`,
125
- y: `${child1Y}%`,
126
- width: `${child1Width}%`,
127
- height: `${child1Height}%`
128
- })
129
- );
130
- }
131
-
132
- if ('views' in view2) {
133
- evaluateViewLayout(view2, child2X, child2Y, child2Width, child2Height);
134
- } else {
135
- views.push(
136
- view2.clone({
137
- x: `${child2X}%`,
138
- y: `${child2Y}%`,
139
- width: `${child2Width}%`,
140
- height: `${child2Height}%`
141
- })
142
- );
125
+ for (const viewLayout of viewLayouts) {
126
+ const splitter = compiled.splittersById[viewLayout.splitId];
127
+ if (splitter) {
128
+ viewLayout.x = splitter.x;
129
+ viewLayout.y = splitter.y;
130
+ viewLayout.width = splitter.width;
131
+ viewLayout.height = splitter.height;
132
+ viewLayout.split = splitter.split;
133
+ viewLayout.minSplit = splitter.minSplit;
134
+ viewLayout.maxSplit = splitter.maxSplit;
143
135
  }
144
136
  }
145
137
 
146
- evaluateViewLayout(root, 0, 0, 100, 100);
147
- return views;
138
+ return compiled.views.map(view =>
139
+ view.clone({
140
+ x: `${view.props.x}%`,
141
+ y: `${view.props.y}%`,
142
+ width: `${view.props.width}%`,
143
+ height: `${view.props.height}%`
144
+ })
145
+ );
148
146
  }
149
147
 
150
148
  /** Properties for the SplitterWidget */
151
149
  export type SplitterWidgetProps<ViewsT extends View[] = View[]> = WidgetProps & {
152
150
  /** Stacking views descriptor */
153
- viewLayout: ViewLayout;
151
+ viewLayout: SplitterWidgetViewLayout;
154
152
  /** Callback invoked when the splitter is dragged with the new split value */
155
153
  onChange?: (views: ViewsT) => void;
156
154
  /** Callback invoked when dragging starts */
@@ -179,7 +177,9 @@ export class SplitterWidget<ViewsT extends View[] = View[]> extends Widget<
179
177
 
180
178
  className = 'deck-widget-splitter';
181
179
  placement = 'fill' as const;
180
+ viewLayout!: ViewLayout;
182
181
  viewLayouts!: ManagedViewLayout[];
182
+ splitValues: Record<string, number> = {};
183
183
  /** evaluated from the current viewLayouts */
184
184
  views!: ViewsT;
185
185
  /** views set in the last update */
@@ -188,17 +188,24 @@ export class SplitterWidget<ViewsT extends View[] = View[]> extends Widget<
188
188
 
189
189
  constructor(props: SplitterWidgetProps<ViewsT>) {
190
190
  super(props);
191
- this.viewLayouts = parseViewLayout(this.props.viewLayout);
191
+ this.updateViewLayout(this.props.viewLayout);
192
192
  }
193
193
 
194
194
  setProps(props: Partial<SplitterWidgetProps<ViewsT>>) {
195
195
  if (props.viewLayout && !deepEqual(props.viewLayout, this.props.viewLayout, -1)) {
196
- this.viewLayouts = parseViewLayout(props.viewLayout);
196
+ this.updateViewLayout(props.viewLayout);
197
197
  this.views = undefined!;
198
198
  }
199
199
  super.setProps(props);
200
200
  }
201
201
 
202
+ private updateViewLayout(viewLayout: SplitterWidgetViewLayout): void {
203
+ const adapted = adaptViewLayout(viewLayout);
204
+ this.viewLayout = adapted.layout;
205
+ this.viewLayouts = adapted.viewLayouts;
206
+ this.splitValues = {};
207
+ }
208
+
202
209
  onRedraw() {
203
210
  // Actually update DOM
204
211
  super.updateHTML();
@@ -210,7 +217,7 @@ export class SplitterWidget<ViewsT extends View[] = View[]> extends Widget<
210
217
  updateHTML() {
211
218
  if (!this.views) {
212
219
  // viewLayouts has changed, re-evaluate
213
- this.views = evaluateViews(this.viewLayouts[0]) as ViewsT;
220
+ this.views = evaluateViews(this.viewLayout, this.viewLayouts, this.splitValues) as ViewsT;
214
221
  // we send a copy to the callback so that externally set views can be differentiated from internal
215
222
  this.props.onChange(this.views.slice() as ViewsT);
216
223
  }
@@ -238,9 +245,9 @@ export class SplitterWidget<ViewsT extends View[] = View[]> extends Widget<
238
245
  }
239
246
 
240
247
  private onChange(newSplit: number, layout: ManagedViewLayout) {
241
- layout.split = newSplit;
248
+ this.splitValues = {...this.splitValues, [layout.splitId]: newSplit};
242
249
  // layout has updated, re-evaluate
243
- this.views = evaluateViews(this.viewLayouts[0]) as ViewsT;
250
+ this.views = evaluateViews(this.viewLayout, this.viewLayouts, this.splitValues) as ViewsT;
244
251
  // we send a copy to the callback so that externally set views can be differentiated from internal
245
252
  this.props.onChange(this.views.slice() as ViewsT);
246
253
  this.doUpdate();