regular-layout 0.1.0 → 0.2.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.
- package/LICENSE.md +1 -1
- package/README.md +6 -6
- package/dist/extensions.d.ts +5 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.js +15 -10
- package/dist/index.js.map +4 -4
- package/dist/{common → layout}/calculate_edge.d.ts +3 -2
- package/dist/{common → layout}/calculate_intersect.d.ts +13 -9
- package/dist/layout/constants.d.ts +81 -0
- package/dist/{common → layout}/flatten.d.ts +1 -1
- package/dist/{common → layout}/generate_grid.d.ts +5 -4
- package/dist/layout/generate_overlay.d.ts +2 -0
- package/dist/{common → layout}/insert_child.d.ts +3 -2
- package/dist/{common → layout}/redistribute_panel_sizes.d.ts +2 -2
- package/dist/{common → layout}/remove_child.d.ts +1 -1
- package/dist/{common/layout_config.d.ts → layout/types.d.ts} +6 -10
- package/dist/regular-layout-frame.d.ts +1 -4
- package/dist/regular-layout-tab.d.ts +26 -0
- package/dist/regular-layout.d.ts +37 -18
- package/package.json +9 -7
- package/src/extensions.ts +10 -4
- package/src/index.ts +3 -7
- package/src/layout/calculate_edge.ts +217 -0
- package/src/{common → layout}/calculate_intersect.ts +61 -101
- package/src/layout/constants.ts +119 -0
- package/src/{common → layout}/flatten.ts +1 -1
- package/src/{common → layout}/generate_grid.ts +120 -106
- package/src/{common → layout}/generate_overlay.ts +26 -12
- package/src/{common → layout}/insert_child.ts +105 -51
- package/src/{common → layout}/redistribute_panel_sizes.ts +11 -4
- package/src/{common → layout}/remove_child.ts +2 -2
- package/src/{common/layout_config.ts → layout/types.ts} +7 -19
- package/src/regular-layout-frame.ts +40 -74
- package/src/regular-layout-tab.ts +103 -0
- package/src/regular-layout.ts +260 -148
- package/themes/chicago.css +89 -0
- package/themes/fluxbox.css +110 -0
- package/themes/gibson.css +264 -0
- package/themes/hotdog.css +88 -0
- package/themes/lorax.css +130 -0
- package/dist/common/constants.d.ts +0 -29
- package/dist/common/generate_overlay.d.ts +0 -2
- package/src/common/calculate_edge.ts +0 -104
- package/src/common/constants.ts +0 -46
package/src/regular-layout.ts
CHANGED
|
@@ -16,23 +16,28 @@
|
|
|
16
16
|
* @packageDocumentation
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { EMPTY_PANEL
|
|
20
|
-
import { create_css_grid_layout } from "./
|
|
19
|
+
import { EMPTY_PANEL } from "./layout/types.ts";
|
|
20
|
+
import { create_css_grid_layout } from "./layout/generate_grid.ts";
|
|
21
21
|
import type {
|
|
22
22
|
LayoutPath,
|
|
23
23
|
Layout,
|
|
24
24
|
LayoutDivider,
|
|
25
25
|
TabLayout,
|
|
26
26
|
OverlayMode,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
27
|
+
Orientation,
|
|
28
|
+
} from "./layout/types.ts";
|
|
29
|
+
import { calculate_intersection } from "./layout/calculate_intersect.ts";
|
|
30
|
+
import { remove_child } from "./layout/remove_child.ts";
|
|
31
|
+
import { insert_child } from "./layout/insert_child.ts";
|
|
32
|
+
import { redistribute_panel_sizes } from "./layout/redistribute_panel_sizes.ts";
|
|
33
|
+
import { updateOverlaySheet } from "./layout/generate_overlay.ts";
|
|
34
|
+
import { calculate_edge } from "./layout/calculate_edge.ts";
|
|
35
|
+
import { flatten } from "./layout/flatten.ts";
|
|
36
|
+
import {
|
|
37
|
+
DEFAULT_PHYSICS,
|
|
38
|
+
type PhysicsUpdate,
|
|
39
|
+
type Physics,
|
|
40
|
+
} from "./layout/constants.ts";
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
43
|
* A Web Component that provides a resizable panel layout system.
|
|
@@ -43,8 +48,8 @@ import { OVERLAY_CLASSNAME, OVERLAY_DEFAULT } from "./common/constants.ts";
|
|
|
43
48
|
* @example
|
|
44
49
|
* ```html
|
|
45
50
|
* <regular-layout>
|
|
46
|
-
* <div
|
|
47
|
-
* <div
|
|
51
|
+
* <div name="sidebar">Sidebar content</div>
|
|
52
|
+
* <div name="main">Main content</div>
|
|
48
53
|
* </regular-layout>
|
|
49
54
|
* ```
|
|
50
55
|
*
|
|
@@ -71,19 +76,36 @@ export class RegularLayout extends HTMLElement {
|
|
|
71
76
|
private _shadowRoot: ShadowRoot;
|
|
72
77
|
private _panel: Layout;
|
|
73
78
|
private _stylesheet: CSSStyleSheet;
|
|
74
|
-
private
|
|
75
|
-
private
|
|
76
|
-
private
|
|
79
|
+
private _cursor_stylesheet: CSSStyleSheet;
|
|
80
|
+
private _drag_target?: [LayoutDivider, number, number];
|
|
81
|
+
private _cursor_override: boolean;
|
|
82
|
+
private _dimensions?: { box: DOMRect; style: CSSStyleDeclaration };
|
|
83
|
+
private _physics: Physics;
|
|
77
84
|
|
|
78
85
|
constructor() {
|
|
79
86
|
super();
|
|
87
|
+
this._physics = DEFAULT_PHYSICS;
|
|
80
88
|
this._panel = structuredClone(EMPTY_PANEL);
|
|
81
|
-
|
|
82
|
-
this
|
|
89
|
+
|
|
90
|
+
// Why does this implementation use a `<slot>` at all? We must use
|
|
91
|
+
// `<slot>` and the Shadow DOM to scope the grid CSS rules to each
|
|
92
|
+
// instance of `<regular-layout>` (without e.g. giving them unique
|
|
93
|
+
// `"id"` and injecting into `document,head`), and we can only select
|
|
94
|
+
// `::slotted` light DOM children from `adoptedStyleSheets` on the
|
|
95
|
+
// `ShadowRoot`.
|
|
96
|
+
|
|
97
|
+
// In addition, this model uses a single un-named `<slot>` to host all
|
|
98
|
+
// light-DOM children, and the child's `"name"` attribute to identify
|
|
99
|
+
// its position in the `Layout`. Alternatively, using named
|
|
83
100
|
this._shadowRoot = this.attachShadow({ mode: "open" });
|
|
84
|
-
this._shadowRoot.
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
101
|
+
this._shadowRoot.innerHTML = `<slot></slot>`;
|
|
102
|
+
this._stylesheet = new CSSStyleSheet();
|
|
103
|
+
this._cursor_stylesheet = new CSSStyleSheet();
|
|
104
|
+
this._cursor_override = false;
|
|
105
|
+
this._shadowRoot.adoptedStyleSheets = [
|
|
106
|
+
this._stylesheet,
|
|
107
|
+
this._cursor_stylesheet,
|
|
108
|
+
];
|
|
87
109
|
}
|
|
88
110
|
|
|
89
111
|
connectedCallback() {
|
|
@@ -98,6 +120,33 @@ export class RegularLayout extends HTMLElement {
|
|
|
98
120
|
this.removeEventListener("pointermove", this.onPointerMove);
|
|
99
121
|
}
|
|
100
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Determines which panel is at a given screen coordinate.
|
|
125
|
+
*
|
|
126
|
+
* @param column - X coordinate in screen pixels.
|
|
127
|
+
* @param row - Y coordinate in screen pixels.
|
|
128
|
+
* @returns Panel information if a panel is at that position, null otherwise.
|
|
129
|
+
*/
|
|
130
|
+
calculateIntersect = (
|
|
131
|
+
x: number,
|
|
132
|
+
y: number,
|
|
133
|
+
check_dividers: boolean = false,
|
|
134
|
+
): LayoutPath<Layout> | null => {
|
|
135
|
+
const [col, row, rect] = this.relativeCoordinates(x, y, false);
|
|
136
|
+
const panel = calculate_intersection(
|
|
137
|
+
col,
|
|
138
|
+
row,
|
|
139
|
+
this._panel,
|
|
140
|
+
check_dividers ? { rect, size: this._physics.GRID_DIVIDER_SIZE } : null,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (panel?.type === "layout-path") {
|
|
144
|
+
return { ...panel, layout: this.save() };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return null;
|
|
148
|
+
};
|
|
149
|
+
|
|
101
150
|
/**
|
|
102
151
|
* Sets the visual overlay state during drag-and-drop operations.
|
|
103
152
|
* Displays a preview of where a panel would be placed at the given coordinates.
|
|
@@ -116,38 +165,48 @@ export class RegularLayout extends HTMLElement {
|
|
|
116
165
|
x: number,
|
|
117
166
|
y: number,
|
|
118
167
|
{ slot }: LayoutPath<unknown>,
|
|
119
|
-
className: string = OVERLAY_CLASSNAME,
|
|
120
|
-
mode: OverlayMode = OVERLAY_DEFAULT,
|
|
168
|
+
className: string = this._physics.OVERLAY_CLASSNAME,
|
|
169
|
+
mode: OverlayMode = this._physics.OVERLAY_DEFAULT,
|
|
121
170
|
) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this._slots.get(slot)?.assignedElements()[0]?.classList.add(className);
|
|
127
|
-
}
|
|
171
|
+
const panel = remove_child(this._panel, slot);
|
|
172
|
+
Array.from(this.children)
|
|
173
|
+
.find((x) => x.getAttribute(this._physics.CHILD_ATTRIBUTE_NAME) === slot)
|
|
174
|
+
?.classList.add(className);
|
|
128
175
|
|
|
129
|
-
const [col, row, box] = this.relativeCoordinates(x, y);
|
|
130
|
-
let drop_target = calculate_intersection(col, row, panel
|
|
176
|
+
const [col, row, box, style] = this.relativeCoordinates(x, y, false);
|
|
177
|
+
let drop_target = calculate_intersection(col, row, panel);
|
|
131
178
|
if (drop_target) {
|
|
132
|
-
drop_target = calculate_edge(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
const css = `${create_css_grid_layout(panel)}}`;
|
|
144
|
-
this._stylesheet.replaceSync(css);
|
|
179
|
+
drop_target = calculate_edge(
|
|
180
|
+
col,
|
|
181
|
+
row,
|
|
182
|
+
panel,
|
|
183
|
+
slot,
|
|
184
|
+
drop_target,
|
|
185
|
+
box,
|
|
186
|
+
this._physics,
|
|
187
|
+
);
|
|
145
188
|
}
|
|
146
189
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
190
|
+
if (mode === "grid" && drop_target) {
|
|
191
|
+
const path: [string, string] = [slot, drop_target?.slot];
|
|
192
|
+
const css = create_css_grid_layout(panel, path, this._physics);
|
|
193
|
+
this._stylesheet.replaceSync(css);
|
|
194
|
+
} else if (mode === "absolute") {
|
|
195
|
+
const grid_css = create_css_grid_layout(panel, undefined, this._physics);
|
|
196
|
+
|
|
197
|
+
const overlay_css = updateOverlaySheet(
|
|
198
|
+
slot,
|
|
199
|
+
box,
|
|
200
|
+
style,
|
|
201
|
+
drop_target,
|
|
202
|
+
this._physics,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
this._stylesheet.replaceSync([grid_css, overlay_css].join("\n"));
|
|
206
|
+
}
|
|
150
207
|
|
|
208
|
+
const event_name = `${this._physics.CUSTOM_EVENT_NAME_PREFIX}-before-update`;
|
|
209
|
+
const event = new CustomEvent<Layout>(event_name, { detail: panel });
|
|
151
210
|
this.dispatchEvent(event);
|
|
152
211
|
};
|
|
153
212
|
|
|
@@ -166,21 +225,21 @@ export class RegularLayout extends HTMLElement {
|
|
|
166
225
|
clearOverlayState = (
|
|
167
226
|
x: number,
|
|
168
227
|
y: number,
|
|
169
|
-
drag_target: LayoutPath<
|
|
170
|
-
className: string = OVERLAY_CLASSNAME,
|
|
171
|
-
mode: OverlayMode = OVERLAY_DEFAULT,
|
|
228
|
+
drag_target: LayoutPath<Layout>,
|
|
229
|
+
className: string = this._physics.OVERLAY_CLASSNAME,
|
|
172
230
|
) => {
|
|
173
231
|
let panel = this._panel;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
232
|
+
panel = remove_child(panel, drag_target.slot);
|
|
233
|
+
Array.from(this.children)
|
|
234
|
+
.find(
|
|
235
|
+
(x) =>
|
|
236
|
+
x.getAttribute(this._physics.CHILD_ATTRIBUTE_NAME) ===
|
|
237
|
+
drag_target.slot,
|
|
238
|
+
)
|
|
239
|
+
?.classList.remove(className);
|
|
240
|
+
|
|
241
|
+
const [col, row, box] = this.relativeCoordinates(x, y, false);
|
|
242
|
+
let drop_target = calculate_intersection(col, row, panel);
|
|
184
243
|
if (drop_target) {
|
|
185
244
|
drop_target = calculate_edge(
|
|
186
245
|
col,
|
|
@@ -188,19 +247,22 @@ export class RegularLayout extends HTMLElement {
|
|
|
188
247
|
panel,
|
|
189
248
|
drag_target.slot,
|
|
190
249
|
drop_target,
|
|
250
|
+
box,
|
|
251
|
+
this._physics,
|
|
191
252
|
);
|
|
192
253
|
}
|
|
193
254
|
|
|
194
255
|
const { path, orientation } = drop_target ? drop_target : drag_target;
|
|
195
|
-
|
|
196
|
-
insert_child(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
256
|
+
const new_layout = drop_target
|
|
257
|
+
? insert_child(
|
|
258
|
+
panel,
|
|
259
|
+
drag_target.slot,
|
|
260
|
+
path,
|
|
261
|
+
drop_target?.is_edge ? orientation : undefined,
|
|
262
|
+
)
|
|
263
|
+
: drag_target.layout;
|
|
264
|
+
|
|
265
|
+
this.restore(new_layout);
|
|
204
266
|
};
|
|
205
267
|
|
|
206
268
|
/**
|
|
@@ -208,9 +270,25 @@ export class RegularLayout extends HTMLElement {
|
|
|
208
270
|
*
|
|
209
271
|
* @param name - Unique identifier for the new panel.
|
|
210
272
|
* @param path - Index path defining where to insert.
|
|
273
|
+
* @param split - Force a split in the layout at the end of `path`
|
|
274
|
+
* regardless if there is a leaf at this position or not. Optionally,
|
|
275
|
+
*. `split` may be your preferred `Orientation`, which will be used by
|
|
276
|
+
* the new `SplitPanel` _if_ there is an option of orientation (e.g. if
|
|
277
|
+
* the layout had no pre-existing `SplitPanel`)
|
|
211
278
|
*/
|
|
212
|
-
insertPanel = (
|
|
213
|
-
|
|
279
|
+
insertPanel = (
|
|
280
|
+
name: string,
|
|
281
|
+
path: number[] = [],
|
|
282
|
+
split?: boolean | Orientation,
|
|
283
|
+
) => {
|
|
284
|
+
let orientation: Orientation | undefined;
|
|
285
|
+
if (typeof split === "boolean" && split) {
|
|
286
|
+
orientation = "horizontal";
|
|
287
|
+
} else if (typeof split === "string") {
|
|
288
|
+
orientation = split;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
this.restore(insert_child(this._panel, name, path, orientation));
|
|
214
292
|
};
|
|
215
293
|
|
|
216
294
|
/**
|
|
@@ -247,27 +325,6 @@ export class RegularLayout extends HTMLElement {
|
|
|
247
325
|
return null;
|
|
248
326
|
};
|
|
249
327
|
|
|
250
|
-
/**
|
|
251
|
-
* Determines which panel is at a given screen coordinate.
|
|
252
|
-
*
|
|
253
|
-
* @param column - X coordinate in screen pixels.
|
|
254
|
-
* @param row - Y coordinate in screen pixels.
|
|
255
|
-
* @returns Panel information if a panel is at that position, null otherwise.
|
|
256
|
-
*/
|
|
257
|
-
calculateIntersect = (
|
|
258
|
-
x: number,
|
|
259
|
-
y: number,
|
|
260
|
-
check_dividers: boolean = false,
|
|
261
|
-
): LayoutPath<DOMRect> | null => {
|
|
262
|
-
const [col, row, box] = this.relativeCoordinates(x, y);
|
|
263
|
-
const panel = calculate_intersection(col, row, this._panel, check_dividers);
|
|
264
|
-
if (panel?.type === "layout-path") {
|
|
265
|
-
return { ...panel, box };
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return null;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
328
|
/**
|
|
272
329
|
* Clears the entire layout, unslotting all panels.
|
|
273
330
|
*/
|
|
@@ -289,13 +346,11 @@ export class RegularLayout extends HTMLElement {
|
|
|
289
346
|
*/
|
|
290
347
|
restore = (layout: Layout, _is_flattened: boolean = false) => {
|
|
291
348
|
this._panel = !_is_flattened ? flatten(layout) : layout;
|
|
292
|
-
const css = create_css_grid_layout(this._panel);
|
|
293
|
-
this._stylesheet.replaceSync(css);
|
|
294
|
-
this.updateSlots(this._panel);
|
|
295
|
-
const event = new CustomEvent("regular-layout-update", {
|
|
296
|
-
detail: this._panel,
|
|
297
|
-
});
|
|
349
|
+
const css = create_css_grid_layout(this._panel, undefined, this._physics);
|
|
298
350
|
|
|
351
|
+
this._stylesheet.replaceSync(css);
|
|
352
|
+
const event_name = `${this._physics.CUSTOM_EVENT_NAME_PREFIX}-update`;
|
|
353
|
+
const event = new CustomEvent<Layout>(event_name, { detail: this._panel });
|
|
299
354
|
this.dispatchEvent(event);
|
|
300
355
|
};
|
|
301
356
|
|
|
@@ -315,6 +370,27 @@ export class RegularLayout extends HTMLElement {
|
|
|
315
370
|
return structuredClone(this._panel);
|
|
316
371
|
};
|
|
317
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Override this instance's global constants.
|
|
375
|
+
*
|
|
376
|
+
* @param physics
|
|
377
|
+
*/
|
|
378
|
+
restorePhysics(physics: PhysicsUpdate) {
|
|
379
|
+
this._physics = Object.freeze({
|
|
380
|
+
...this._physics,
|
|
381
|
+
...physics,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get this instance's constants.
|
|
387
|
+
*
|
|
388
|
+
* @returns The current constants
|
|
389
|
+
*/
|
|
390
|
+
savePhysics(): Physics {
|
|
391
|
+
return this._physics;
|
|
392
|
+
}
|
|
393
|
+
|
|
318
394
|
/**
|
|
319
395
|
* Converts screen coordinates to relative layout coordinates.
|
|
320
396
|
*
|
|
@@ -331,44 +407,44 @@ export class RegularLayout extends HTMLElement {
|
|
|
331
407
|
relativeCoordinates = (
|
|
332
408
|
clientX: number,
|
|
333
409
|
clientY: number,
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
private updateSlots = (layout: Layout, overlay?: string) => {
|
|
342
|
-
const old = new Set(this._slots.keys());
|
|
343
|
-
if (overlay) {
|
|
344
|
-
old.delete(overlay);
|
|
410
|
+
recalculate_bounds: boolean = true,
|
|
411
|
+
): [number, number, DOMRect, CSSStyleDeclaration] => {
|
|
412
|
+
if (recalculate_bounds || !this._dimensions) {
|
|
413
|
+
this._dimensions = {
|
|
414
|
+
box: this.getBoundingClientRect(),
|
|
415
|
+
style: getComputedStyle(this),
|
|
416
|
+
};
|
|
345
417
|
}
|
|
346
418
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
this._slots.delete(key);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
419
|
+
const box = this._dimensions.box;
|
|
420
|
+
const style = this._dimensions.style;
|
|
421
|
+
const col =
|
|
422
|
+
(clientX - box.left - parseFloat(style.paddingLeft)) /
|
|
423
|
+
(box.width -
|
|
424
|
+
parseFloat(style.paddingLeft) -
|
|
425
|
+
parseFloat(style.paddingRight));
|
|
426
|
+
const row =
|
|
427
|
+
(clientY - box.top - parseFloat(style.paddingTop)) /
|
|
428
|
+
(box.height -
|
|
429
|
+
parseFloat(style.paddingTop) -
|
|
430
|
+
parseFloat(style.paddingBottom));
|
|
431
|
+
|
|
432
|
+
return [col, row, box, style];
|
|
364
433
|
};
|
|
365
434
|
|
|
366
435
|
private onPointerDown = (event: PointerEvent) => {
|
|
367
|
-
if (event.target === this) {
|
|
368
|
-
const [col, row] = this.relativeCoordinates(
|
|
369
|
-
|
|
436
|
+
if (!this._physics.GRID_DIVIDER_CHECK_TARGET || event.target === this) {
|
|
437
|
+
const [col, row, rect] = this.relativeCoordinates(
|
|
438
|
+
event.clientX,
|
|
439
|
+
event.clientY,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
const hit = calculate_intersection(col, row, this._panel, {
|
|
443
|
+
rect,
|
|
444
|
+
size: this._physics.GRID_DIVIDER_SIZE,
|
|
445
|
+
});
|
|
370
446
|
if (hit && hit.type !== "layout-path") {
|
|
371
|
-
this.
|
|
447
|
+
this._drag_target = [hit, col, row];
|
|
372
448
|
this.setPointerCapture(event.pointerId);
|
|
373
449
|
event.preventDefault();
|
|
374
450
|
}
|
|
@@ -376,31 +452,67 @@ export class RegularLayout extends HTMLElement {
|
|
|
376
452
|
};
|
|
377
453
|
|
|
378
454
|
private onPointerMove = (event: PointerEvent) => {
|
|
379
|
-
if (this.
|
|
380
|
-
const [col, row] = this.relativeCoordinates(
|
|
381
|
-
|
|
382
|
-
|
|
455
|
+
if (this._drag_target) {
|
|
456
|
+
const [col, row] = this.relativeCoordinates(
|
|
457
|
+
event.clientX,
|
|
458
|
+
event.clientY,
|
|
459
|
+
false,
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
const [{ path, type }, old_col, old_row] = this._drag_target;
|
|
383
463
|
const offset = type === "horizontal" ? old_col - col : old_row - row;
|
|
384
|
-
const panel = redistribute_panel_sizes(
|
|
385
|
-
this._stylesheet.replaceSync(
|
|
464
|
+
const panel = redistribute_panel_sizes(this._panel, path, offset);
|
|
465
|
+
this._stylesheet.replaceSync(
|
|
466
|
+
create_css_grid_layout(panel, undefined, this._physics),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (this._physics.GRID_DIVIDER_CHECK_TARGET && event.target !== this) {
|
|
471
|
+
if (this._cursor_override) {
|
|
472
|
+
this._cursor_override = false;
|
|
473
|
+
this._cursor_stylesheet.replaceSync("");
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const [col, row, rect] = this.relativeCoordinates(
|
|
480
|
+
event.clientX,
|
|
481
|
+
event.clientY,
|
|
482
|
+
false,
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
const divider = calculate_intersection(col, row, this._panel, {
|
|
486
|
+
rect,
|
|
487
|
+
size: this._physics.GRID_DIVIDER_SIZE,
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
if (divider?.type === "vertical") {
|
|
491
|
+
this._cursor_stylesheet.replaceSync(":host{cursor:row-resize");
|
|
492
|
+
this._cursor_override = true;
|
|
493
|
+
} else if (divider?.type === "horizontal") {
|
|
494
|
+
this._cursor_stylesheet.replaceSync(":host{cursor:col-resize");
|
|
495
|
+
this._cursor_override = true;
|
|
496
|
+
} else if (this._cursor_override) {
|
|
497
|
+
this._cursor_override = false;
|
|
498
|
+
this._cursor_stylesheet.replaceSync("");
|
|
386
499
|
}
|
|
387
500
|
};
|
|
388
501
|
|
|
389
502
|
private onPointerUp = (event: PointerEvent) => {
|
|
390
|
-
if (this.
|
|
503
|
+
if (this._drag_target) {
|
|
391
504
|
this.releasePointerCapture(event.pointerId);
|
|
392
|
-
const [col, row] = this.relativeCoordinates(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
this.restore(panel, true);
|
|
398
|
-
} else {
|
|
399
|
-
const panel = redistribute_panel_sizes(old_panel, path, old_row - row);
|
|
400
|
-
this.restore(panel, true);
|
|
401
|
-
}
|
|
505
|
+
const [col, row] = this.relativeCoordinates(
|
|
506
|
+
event.clientX,
|
|
507
|
+
event.clientY,
|
|
508
|
+
false,
|
|
509
|
+
);
|
|
402
510
|
|
|
403
|
-
|
|
511
|
+
const [{ path, type }, old_col, old_row] = this._drag_target;
|
|
512
|
+
const offset = type === "horizontal" ? old_col - col : old_row - row;
|
|
513
|
+
const panel = redistribute_panel_sizes(this._panel, path, offset);
|
|
514
|
+
this.restore(panel, true);
|
|
515
|
+
this._drag_target = undefined;
|
|
404
516
|
}
|
|
405
517
|
};
|
|
406
518
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
2
|
+
* ░░░░░░░░▄▀░█▀▄░█▀▀░█▀▀░█░█░█░░░█▀█░█▀▄░░░░░█░░░█▀█░█░█░█▀█░█░█░▀█▀░▀▄░░░░░░░░
|
|
3
|
+
* ░░░░░░░▀▄░░█▀▄░█▀▀░█░█░█░█░█░░░█▀█░█▀▄░▀▀▀░█░░░█▀█░░█░░█░█░█░█░░█░░░▄▀░░░░░░░
|
|
4
|
+
* ░░░░░░░░░▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀░▀░▀░▀░░░░░▀▀▀░▀░▀░░▀░░▀▀▀░▀▀▀░░▀░░▀░░░░░░░░░
|
|
5
|
+
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
6
|
+
* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
7
|
+
* ┃ * Copyright (c) 2026, the Regular Layout Authors. This file is part * ┃
|
|
8
|
+
* ┃ * of the Regular Layout library, distributed under the terms of the * ┃
|
|
9
|
+
* ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
|
|
10
|
+
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
regular-layout.chicago {
|
|
14
|
+
background-color: #008080;
|
|
15
|
+
font-family: "ui-monospace", "SFMono-Regular", "SF Mono", "Menlo", "Consolas", "Liberation Mono", monospace;
|
|
16
|
+
padding: 24px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Frame */
|
|
20
|
+
regular-layout.chicago regular-layout-frame {
|
|
21
|
+
position: relative;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 12px;
|
|
24
|
+
background: #C0C0C0;
|
|
25
|
+
border-width: 2px;
|
|
26
|
+
border-color: #FFFFFF #808080 #808080 #FFFFFF;
|
|
27
|
+
border-style: solid;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
regular-layout.chicago regular-layout-frame::part(close) {
|
|
31
|
+
border-width: 1px;
|
|
32
|
+
border-color: #FFFFFF #808080 #808080 #FFFFFF;
|
|
33
|
+
border-style: solid;
|
|
34
|
+
height: 16px;
|
|
35
|
+
background: #C0C0C0;
|
|
36
|
+
align-self: center;
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
padding: 0px 4px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
regular-layout.chicago regular-layout-frame::part(close):before {
|
|
43
|
+
content: "X";
|
|
44
|
+
font-size: 10px;
|
|
45
|
+
font-weight: bold;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
regular-layout.chicago regular-layout-frame::part(titlebar) {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: stretch;
|
|
51
|
+
padding-right: 0px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
regular-layout.chicago regular-layout-frame::part(tab) {
|
|
55
|
+
display: flex;
|
|
56
|
+
flex: 1 1 150px;
|
|
57
|
+
align-items: center;
|
|
58
|
+
padding: 0 3px 0 8px;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
text-overflow: ellipsis;
|
|
61
|
+
background: #808080;
|
|
62
|
+
color: #FFF;
|
|
63
|
+
font-family: "Tahoma", "Arial", sans-serif;
|
|
64
|
+
font-weight: bold;
|
|
65
|
+
font-size: 11px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
regular-layout.chicago regular-layout-frame::part(active-tab) {
|
|
69
|
+
background: #000080;
|
|
70
|
+
opacity: 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
regular-layout.chicago:has(.overlay)>* {
|
|
74
|
+
opacity: 0.8;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
regular-layout.chicago:has(.overlay)>.overlay {
|
|
78
|
+
opacity: 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Frame in Overlay Mode */
|
|
82
|
+
regular-layout.chicago regular-layout-frame.overlay {
|
|
83
|
+
margin: 0;
|
|
84
|
+
transition:
|
|
85
|
+
top 0.1s ease-in-out,
|
|
86
|
+
height 0.1s ease-in-out,
|
|
87
|
+
width 0.1s ease-in-out,
|
|
88
|
+
left 0.1s ease-in-out;
|
|
89
|
+
}
|