regular-layout 0.1.0 → 0.2.0
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 +2 -2
- package/dist/{common → layout}/calculate_intersect.d.ts +7 -9
- package/dist/{common → layout}/constants.d.ts +15 -1
- package/dist/{common → layout}/flatten.d.ts +1 -1
- package/dist/{common → layout}/generate_grid.d.ts +3 -3
- 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 +1 -1
- 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 +23 -18
- package/package.json +9 -7
- package/src/extensions.ts +10 -4
- package/src/index.ts +3 -7
- package/src/layout/calculate_edge.ts +209 -0
- package/src/{common → layout}/calculate_intersect.ts +59 -101
- package/src/{common → layout}/constants.ts +18 -1
- package/src/{common → layout}/flatten.ts +1 -1
- package/src/{common → layout}/generate_grid.ts +76 -106
- package/src/{common → layout}/generate_overlay.ts +24 -12
- package/src/{common → layout}/insert_child.ts +105 -51
- package/src/{common → layout}/redistribute_panel_sizes.ts +1 -1
- package/src/{common → layout}/remove_child.ts +2 -2
- package/src/{common/layout_config.ts → layout/types.ts} +6 -19
- package/src/regular-layout-frame.ts +34 -71
- package/src/regular-layout-tab.ts +103 -0
- package/src/regular-layout.ts +190 -141
- 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 +129 -0
- package/dist/common/generate_overlay.d.ts +0 -2
- package/src/common/calculate_edge.ts +0 -104
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
|
+
CUSTOM_EVENT_NAME_PREFIX,
|
|
38
|
+
OVERLAY_CLASSNAME,
|
|
39
|
+
OVERLAY_DEFAULT,
|
|
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,34 @@ 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 };
|
|
77
83
|
|
|
78
84
|
constructor() {
|
|
79
85
|
super();
|
|
80
86
|
this._panel = structuredClone(EMPTY_PANEL);
|
|
81
|
-
|
|
82
|
-
this
|
|
87
|
+
|
|
88
|
+
// Why does this implementation use a `<slot>` at all? We must use
|
|
89
|
+
// `<slot>` and the Shadow DOM to scope the grid CSS rules to each
|
|
90
|
+
// instance of `<regular-layout>` (without e.g. giving them unique
|
|
91
|
+
// `"id"` and injecting into `document,head`), and we can only select
|
|
92
|
+
// `::slotted` light DOM children from `adoptedStyleSheets` on the
|
|
93
|
+
// `ShadowRoot`.
|
|
94
|
+
|
|
95
|
+
// In addition, this model uses a single un-named `<slot>` to host all
|
|
96
|
+
// light-DOM children, and the child's `"name"` attribute to identify
|
|
97
|
+
// its position in the `Layout`. Alternatively, using named
|
|
83
98
|
this._shadowRoot = this.attachShadow({ mode: "open" });
|
|
84
|
-
this._shadowRoot.
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
99
|
+
this._shadowRoot.innerHTML = `<slot></slot>`;
|
|
100
|
+
this._stylesheet = new CSSStyleSheet();
|
|
101
|
+
this._cursor_stylesheet = new CSSStyleSheet();
|
|
102
|
+
this._cursor_override = false;
|
|
103
|
+
this._shadowRoot.adoptedStyleSheets = [
|
|
104
|
+
this._stylesheet,
|
|
105
|
+
this._cursor_stylesheet,
|
|
106
|
+
];
|
|
87
107
|
}
|
|
88
108
|
|
|
89
109
|
connectedCallback() {
|
|
@@ -98,6 +118,33 @@ export class RegularLayout extends HTMLElement {
|
|
|
98
118
|
this.removeEventListener("pointermove", this.onPointerMove);
|
|
99
119
|
}
|
|
100
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Determines which panel is at a given screen coordinate.
|
|
123
|
+
*
|
|
124
|
+
* @param column - X coordinate in screen pixels.
|
|
125
|
+
* @param row - Y coordinate in screen pixels.
|
|
126
|
+
* @returns Panel information if a panel is at that position, null otherwise.
|
|
127
|
+
*/
|
|
128
|
+
calculateIntersect = (
|
|
129
|
+
x: number,
|
|
130
|
+
y: number,
|
|
131
|
+
check_dividers: boolean = false,
|
|
132
|
+
): LayoutPath<Layout> | null => {
|
|
133
|
+
const [col, row, box] = this.relativeCoordinates(x, y, false);
|
|
134
|
+
const panel = calculate_intersection(
|
|
135
|
+
col,
|
|
136
|
+
row,
|
|
137
|
+
this._panel,
|
|
138
|
+
check_dividers ? box : null,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
if (panel?.type === "layout-path") {
|
|
142
|
+
return { ...panel, layout: this.save() };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return null;
|
|
146
|
+
};
|
|
147
|
+
|
|
101
148
|
/**
|
|
102
149
|
* Sets the visual overlay state during drag-and-drop operations.
|
|
103
150
|
* Displays a preview of where a panel would be placed at the given coordinates.
|
|
@@ -119,35 +166,29 @@ export class RegularLayout extends HTMLElement {
|
|
|
119
166
|
className: string = OVERLAY_CLASSNAME,
|
|
120
167
|
mode: OverlayMode = OVERLAY_DEFAULT,
|
|
121
168
|
) => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
this._slots.get(slot)?.assignedElements()[0]?.classList.add(className);
|
|
127
|
-
}
|
|
169
|
+
const panel = remove_child(this._panel, slot);
|
|
170
|
+
Array.from(this.children)
|
|
171
|
+
.find((x) => x.getAttribute("name") === slot)
|
|
172
|
+
?.classList.add(className);
|
|
128
173
|
|
|
129
|
-
const [col, row, box] = this.relativeCoordinates(x, y);
|
|
130
|
-
let drop_target = calculate_intersection(col, row, panel
|
|
174
|
+
const [col, row, box, style] = this.relativeCoordinates(x, y, false);
|
|
175
|
+
let drop_target = calculate_intersection(col, row, panel);
|
|
131
176
|
if (drop_target) {
|
|
132
|
-
drop_target = calculate_edge(col, row, panel, slot, drop_target);
|
|
133
|
-
if (mode === "grid") {
|
|
134
|
-
const path: [string, string] = [slot, drop_target.slot];
|
|
135
|
-
const css = create_css_grid_layout(this._panel, false, path);
|
|
136
|
-
this._stylesheet.replaceSync(css);
|
|
137
|
-
} else if (mode === "absolute") {
|
|
138
|
-
const grid_css = create_css_grid_layout(panel);
|
|
139
|
-
const overlay_css = updateOverlaySheet(slot, { ...drop_target, box });
|
|
140
|
-
this._stylesheet.replaceSync([grid_css, overlay_css].join("\n"));
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
const css = `${create_css_grid_layout(panel)}}`;
|
|
144
|
-
this._stylesheet.replaceSync(css);
|
|
177
|
+
drop_target = calculate_edge(col, row, panel, slot, drop_target, box);
|
|
145
178
|
}
|
|
146
179
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
180
|
+
if (mode === "grid" && drop_target) {
|
|
181
|
+
const path: [string, string] = [slot, drop_target?.slot];
|
|
182
|
+
const css = create_css_grid_layout(panel, false, path);
|
|
183
|
+
this._stylesheet.replaceSync(css);
|
|
184
|
+
} else if (mode === "absolute") {
|
|
185
|
+
const grid_css = create_css_grid_layout(panel);
|
|
186
|
+
const overlay_css = updateOverlaySheet(slot, box, style, drop_target);
|
|
187
|
+
this._stylesheet.replaceSync([grid_css, overlay_css].join("\n"));
|
|
188
|
+
}
|
|
150
189
|
|
|
190
|
+
const event_name = `${CUSTOM_EVENT_NAME_PREFIX}-before-update`;
|
|
191
|
+
const event = new CustomEvent<Layout>(event_name, { detail: panel });
|
|
151
192
|
this.dispatchEvent(event);
|
|
152
193
|
};
|
|
153
194
|
|
|
@@ -166,21 +207,17 @@ export class RegularLayout extends HTMLElement {
|
|
|
166
207
|
clearOverlayState = (
|
|
167
208
|
x: number,
|
|
168
209
|
y: number,
|
|
169
|
-
drag_target: LayoutPath<
|
|
210
|
+
drag_target: LayoutPath<Layout>,
|
|
170
211
|
className: string = OVERLAY_CLASSNAME,
|
|
171
|
-
mode: OverlayMode = OVERLAY_DEFAULT,
|
|
172
212
|
) => {
|
|
173
213
|
let panel = this._panel;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
?.assignedElements()[0]
|
|
179
|
-
?.classList.remove(className);
|
|
180
|
-
}
|
|
214
|
+
panel = remove_child(panel, drag_target.slot);
|
|
215
|
+
Array.from(this.children)
|
|
216
|
+
.find((x) => x.getAttribute("name") === drag_target.slot)
|
|
217
|
+
?.classList.remove(className);
|
|
181
218
|
|
|
182
|
-
const [col, row,
|
|
183
|
-
let drop_target = calculate_intersection(col, row, panel
|
|
219
|
+
const [col, row, box] = this.relativeCoordinates(x, y, false);
|
|
220
|
+
let drop_target = calculate_intersection(col, row, panel);
|
|
184
221
|
if (drop_target) {
|
|
185
222
|
drop_target = calculate_edge(
|
|
186
223
|
col,
|
|
@@ -188,19 +225,21 @@ export class RegularLayout extends HTMLElement {
|
|
|
188
225
|
panel,
|
|
189
226
|
drag_target.slot,
|
|
190
227
|
drop_target,
|
|
228
|
+
box,
|
|
191
229
|
);
|
|
192
230
|
}
|
|
193
231
|
|
|
194
232
|
const { path, orientation } = drop_target ? drop_target : drag_target;
|
|
195
|
-
|
|
196
|
-
insert_child(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
233
|
+
const new_layout = drop_target
|
|
234
|
+
? insert_child(
|
|
235
|
+
panel,
|
|
236
|
+
drag_target.slot,
|
|
237
|
+
path,
|
|
238
|
+
drop_target?.is_edge ? orientation : undefined,
|
|
239
|
+
)
|
|
240
|
+
: drag_target.layout;
|
|
241
|
+
|
|
242
|
+
this.restore(new_layout);
|
|
204
243
|
};
|
|
205
244
|
|
|
206
245
|
/**
|
|
@@ -208,9 +247,25 @@ export class RegularLayout extends HTMLElement {
|
|
|
208
247
|
*
|
|
209
248
|
* @param name - Unique identifier for the new panel.
|
|
210
249
|
* @param path - Index path defining where to insert.
|
|
250
|
+
* @param split - Force a split in the layout at the end of `path`
|
|
251
|
+
* regardless if there is a leaf at this position or not. Optionally,
|
|
252
|
+
*. `split` may be your preferred `Orientation`, which will be used by
|
|
253
|
+
* the new `SplitPanel` _if_ there is an option of orientation (e.g. if
|
|
254
|
+
* the layout had no pre-existing `SplitPanel`)
|
|
211
255
|
*/
|
|
212
|
-
insertPanel = (
|
|
213
|
-
|
|
256
|
+
insertPanel = (
|
|
257
|
+
name: string,
|
|
258
|
+
path: number[] = [],
|
|
259
|
+
split?: boolean | Orientation,
|
|
260
|
+
) => {
|
|
261
|
+
let orientation: Orientation | undefined;
|
|
262
|
+
if (typeof split === "boolean" && split) {
|
|
263
|
+
orientation = "horizontal";
|
|
264
|
+
} else if (typeof split === "string") {
|
|
265
|
+
orientation = split;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.restore(insert_child(this._panel, name, path, orientation));
|
|
214
269
|
};
|
|
215
270
|
|
|
216
271
|
/**
|
|
@@ -247,27 +302,6 @@ export class RegularLayout extends HTMLElement {
|
|
|
247
302
|
return null;
|
|
248
303
|
};
|
|
249
304
|
|
|
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
305
|
/**
|
|
272
306
|
* Clears the entire layout, unslotting all panels.
|
|
273
307
|
*/
|
|
@@ -291,11 +325,8 @@ export class RegularLayout extends HTMLElement {
|
|
|
291
325
|
this._panel = !_is_flattened ? flatten(layout) : layout;
|
|
292
326
|
const css = create_css_grid_layout(this._panel);
|
|
293
327
|
this._stylesheet.replaceSync(css);
|
|
294
|
-
|
|
295
|
-
const event = new CustomEvent(
|
|
296
|
-
detail: this._panel,
|
|
297
|
-
});
|
|
298
|
-
|
|
328
|
+
const event_name = `${CUSTOM_EVENT_NAME_PREFIX}-update`;
|
|
329
|
+
const event = new CustomEvent<Layout>(event_name, { detail: this._panel });
|
|
299
330
|
this.dispatchEvent(event);
|
|
300
331
|
};
|
|
301
332
|
|
|
@@ -331,44 +362,41 @@ export class RegularLayout extends HTMLElement {
|
|
|
331
362
|
relativeCoordinates = (
|
|
332
363
|
clientX: number,
|
|
333
364
|
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);
|
|
365
|
+
recalculate_bounds: boolean = true,
|
|
366
|
+
): [number, number, DOMRect, CSSStyleDeclaration] => {
|
|
367
|
+
if (recalculate_bounds || !this._dimensions) {
|
|
368
|
+
this._dimensions = {
|
|
369
|
+
box: this.getBoundingClientRect(),
|
|
370
|
+
style: getComputedStyle(this),
|
|
371
|
+
};
|
|
345
372
|
}
|
|
346
373
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
this._slots.delete(key);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
374
|
+
const box = this._dimensions.box;
|
|
375
|
+
const style = this._dimensions.style;
|
|
376
|
+
const col =
|
|
377
|
+
(clientX - box.left - parseFloat(style.paddingLeft)) /
|
|
378
|
+
(box.width -
|
|
379
|
+
parseFloat(style.paddingLeft) -
|
|
380
|
+
parseFloat(style.paddingRight));
|
|
381
|
+
const row =
|
|
382
|
+
(clientY - box.top - parseFloat(style.paddingTop)) /
|
|
383
|
+
(box.height -
|
|
384
|
+
parseFloat(style.paddingTop) -
|
|
385
|
+
parseFloat(style.paddingBottom));
|
|
386
|
+
|
|
387
|
+
return [col, row, box, style];
|
|
364
388
|
};
|
|
365
389
|
|
|
366
390
|
private onPointerDown = (event: PointerEvent) => {
|
|
367
391
|
if (event.target === this) {
|
|
368
|
-
const [col, row] = this.relativeCoordinates(
|
|
369
|
-
|
|
392
|
+
const [col, row, box] = this.relativeCoordinates(
|
|
393
|
+
event.clientX,
|
|
394
|
+
event.clientY,
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
const hit = calculate_intersection(col, row, this._panel, box);
|
|
370
398
|
if (hit && hit.type !== "layout-path") {
|
|
371
|
-
this.
|
|
399
|
+
this._drag_target = [hit, col, row];
|
|
372
400
|
this.setPointerCapture(event.pointerId);
|
|
373
401
|
event.preventDefault();
|
|
374
402
|
}
|
|
@@ -376,31 +404,52 @@ export class RegularLayout extends HTMLElement {
|
|
|
376
404
|
};
|
|
377
405
|
|
|
378
406
|
private onPointerMove = (event: PointerEvent) => {
|
|
379
|
-
if (this.
|
|
380
|
-
const [col, row] = this.relativeCoordinates(
|
|
381
|
-
|
|
382
|
-
|
|
407
|
+
if (this._drag_target) {
|
|
408
|
+
const [col, row] = this.relativeCoordinates(
|
|
409
|
+
event.clientX,
|
|
410
|
+
event.clientY,
|
|
411
|
+
false,
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
const [{ path, type }, old_col, old_row] = this._drag_target;
|
|
383
415
|
const offset = type === "horizontal" ? old_col - col : old_row - row;
|
|
384
|
-
const panel = redistribute_panel_sizes(
|
|
416
|
+
const panel = redistribute_panel_sizes(this._panel, path, offset);
|
|
385
417
|
this._stylesheet.replaceSync(create_css_grid_layout(panel));
|
|
418
|
+
} else if (event.target === this) {
|
|
419
|
+
const [col, row, box] = this.relativeCoordinates(
|
|
420
|
+
event.clientX,
|
|
421
|
+
event.clientY,
|
|
422
|
+
false,
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
const divider = calculate_intersection(col, row, this._panel, box);
|
|
426
|
+
if (divider?.type === "vertical") {
|
|
427
|
+
this._cursor_stylesheet.replaceSync(":host{cursor:row-resize");
|
|
428
|
+
this._cursor_override = true;
|
|
429
|
+
} else if (divider?.type === "horizontal") {
|
|
430
|
+
this._cursor_stylesheet.replaceSync(":host{cursor:col-resize");
|
|
431
|
+
this._cursor_override = true;
|
|
432
|
+
}
|
|
433
|
+
} else if (this._cursor_override) {
|
|
434
|
+
this._cursor_override = false;
|
|
435
|
+
this._cursor_stylesheet.replaceSync("");
|
|
386
436
|
}
|
|
387
437
|
};
|
|
388
438
|
|
|
389
439
|
private onPointerUp = (event: PointerEvent) => {
|
|
390
|
-
if (this.
|
|
440
|
+
if (this._drag_target) {
|
|
391
441
|
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
|
-
}
|
|
442
|
+
const [col, row] = this.relativeCoordinates(
|
|
443
|
+
event.clientX,
|
|
444
|
+
event.clientY,
|
|
445
|
+
false,
|
|
446
|
+
);
|
|
402
447
|
|
|
403
|
-
|
|
448
|
+
const [{ path, type }, old_col, old_row] = this._drag_target;
|
|
449
|
+
const offset = type === "horizontal" ? old_col - col : old_row - row;
|
|
450
|
+
const panel = redistribute_panel_sizes(this._panel, path, offset);
|
|
451
|
+
this.restore(panel, true);
|
|
452
|
+
this._drag_target = undefined;
|
|
404
453
|
}
|
|
405
454
|
};
|
|
406
455
|
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
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.fluxbox {
|
|
14
|
+
background-color: #DBDFE6;
|
|
15
|
+
font-family: "ui-sans-serif", "Helvetica", "Arial", sans-serif;
|
|
16
|
+
padding: 16px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Frame */
|
|
20
|
+
regular-layout.fluxbox regular-layout-frame {
|
|
21
|
+
position: relative;
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
margin: 8px;
|
|
24
|
+
background: #FFFFFF;
|
|
25
|
+
border: 1px solid #9DACBE;
|
|
26
|
+
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.15);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
regular-layout.fluxbox regular-layout-frame::part(close) {
|
|
30
|
+
border: 1px solid #8A96A3;
|
|
31
|
+
height: 14px;
|
|
32
|
+
background: linear-gradient(to bottom, #E8ECEF 0%, #CDD5DD 100%);
|
|
33
|
+
align-self: center;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
justify-content: center;
|
|
37
|
+
padding: 0px;
|
|
38
|
+
width: 14px;
|
|
39
|
+
margin-right: 2px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
regular-layout.fluxbox regular-layout-frame::part(close):hover {
|
|
43
|
+
background: linear-gradient(to bottom, #F0F3F5 0%, #D8DFE6 100%);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
regular-layout.fluxbox regular-layout-frame::part(close):active {
|
|
47
|
+
background: linear-gradient(to bottom, #C5CFD9 0%, #B3BEC9 100%);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
regular-layout.fluxbox regular-layout-frame::part(close):before {
|
|
51
|
+
content: "×";
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
font-weight: normal;
|
|
54
|
+
color: #444444;
|
|
55
|
+
line-height: 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
regular-layout.fluxbox regular-layout-frame::part(titlebar) {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: stretch;
|
|
61
|
+
padding-right: 0px;
|
|
62
|
+
height: 22px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
regular-layout.fluxbox regular-layout-frame::part(tab) {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex: 1 1 150px;
|
|
68
|
+
align-items: center;
|
|
69
|
+
padding: 0 8px;
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
text-overflow: ellipsis;
|
|
72
|
+
background: linear-gradient(to bottom, #C7D1DB 0%, #B3BEC9 100%);
|
|
73
|
+
color: #4A4A4A;
|
|
74
|
+
font-size: 11px;
|
|
75
|
+
font-weight: normal;
|
|
76
|
+
border-right: 1px solid #9DACBE;
|
|
77
|
+
opacity: 0.85;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
regular-layout.fluxbox regular-layout-frame::part(tab):hover {
|
|
81
|
+
background: linear-gradient(to bottom, #D2DBE4 0%, #BEC9D4 100%);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
regular-layout.fluxbox regular-layout-frame::part(active-tab) {
|
|
85
|
+
background: linear-gradient(to bottom, #E0E7EF 0%, #D1DAE3 100%);
|
|
86
|
+
color: #1A1A1A;
|
|
87
|
+
opacity: 1;
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
regular-layout.fluxbox:has(.overlay)>* {
|
|
92
|
+
opacity: 0.7;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
regular-layout.fluxbox:has(.overlay)>.overlay {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Frame in Overlay Mode */
|
|
100
|
+
regular-layout.fluxbox regular-layout-frame.overlay {
|
|
101
|
+
margin: 0;
|
|
102
|
+
background-color: rgba(155, 172, 190, 0.25);
|
|
103
|
+
border: 1px solid #6B7C8F;
|
|
104
|
+
box-shadow: none;
|
|
105
|
+
transition:
|
|
106
|
+
top 0.1s ease-in-out,
|
|
107
|
+
height 0.1s ease-in-out,
|
|
108
|
+
width 0.1s ease-in-out,
|
|
109
|
+
left 0.1s ease-in-out;
|
|
110
|
+
}
|