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
|
@@ -9,24 +9,25 @@
|
|
|
9
9
|
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
|
|
10
10
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
11
|
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
import { GRID_DIVIDER_SIZE } from "./constants.ts";
|
|
13
|
+
import type { LayoutPath, LayoutDivider, Layout, ViewWindow } from "./types.ts";
|
|
14
|
+
|
|
15
|
+
const VIEW_WINDOW = {
|
|
16
|
+
row_start: 0,
|
|
17
|
+
row_end: 1,
|
|
18
|
+
col_start: 0,
|
|
19
|
+
col_end: 1,
|
|
20
|
+
};
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* Determines which panel or divider is located at a given position in the
|
|
21
24
|
* layout.
|
|
22
25
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* height
|
|
25
|
-
* @param column - Horizontal position as a fraction (0-1) of the
|
|
26
|
-
* container width
|
|
26
|
+
* @param column - Horizontal position as a fraction (0-1) of the container width
|
|
27
|
+
* @param row - Vertical position as a fraction (0-1) of the container height
|
|
27
28
|
* @param layout - The layout tree to search
|
|
28
29
|
* @param check_dividers - Whether `LayoutDivider` intersection should be
|
|
29
|
-
* checked, which
|
|
30
|
+
* checked, which you may not want for e.g. `drop` actions.
|
|
30
31
|
* @returns The panel path if over a panel, a divider if over a resizable
|
|
31
32
|
* boundary, or null if outside all panels
|
|
32
33
|
*/
|
|
@@ -34,44 +35,37 @@ export function calculate_intersection(
|
|
|
34
35
|
column: number,
|
|
35
36
|
row: number,
|
|
36
37
|
layout: Layout,
|
|
37
|
-
check_dividers
|
|
38
|
-
): LayoutPath;
|
|
38
|
+
check_dividers?: null,
|
|
39
|
+
): LayoutPath | null;
|
|
39
40
|
|
|
40
41
|
export function calculate_intersection(
|
|
41
42
|
column: number,
|
|
42
43
|
row: number,
|
|
43
44
|
layout: Layout,
|
|
44
|
-
check_dividers
|
|
45
|
+
check_dividers?: DOMRect,
|
|
45
46
|
): LayoutPath | null | LayoutDivider;
|
|
46
47
|
|
|
47
48
|
export function calculate_intersection(
|
|
48
49
|
column: number,
|
|
49
50
|
row: number,
|
|
50
51
|
layout: Layout,
|
|
51
|
-
check_dividers?:
|
|
52
|
+
check_dividers?: DOMRect | null,
|
|
52
53
|
): LayoutPath | null | LayoutDivider;
|
|
53
54
|
|
|
54
55
|
export function calculate_intersection(
|
|
55
56
|
column: number,
|
|
56
57
|
row: number,
|
|
57
58
|
layout: Layout,
|
|
58
|
-
check_dividers:
|
|
59
|
+
check_dividers: DOMRect | null = null,
|
|
59
60
|
): LayoutPath | null | LayoutDivider {
|
|
60
61
|
return calculate_intersection_recursive(column, row, layout, check_dividers);
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
const VIEW_WINDOW = {
|
|
64
|
-
row_start: 0,
|
|
65
|
-
row_end: 1,
|
|
66
|
-
col_start: 0,
|
|
67
|
-
col_end: 1,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
64
|
function calculate_intersection_recursive(
|
|
71
65
|
column: number,
|
|
72
66
|
row: number,
|
|
73
67
|
panel: Layout,
|
|
74
|
-
check_dividers:
|
|
68
|
+
check_dividers: DOMRect | null,
|
|
75
69
|
parent_orientation: "horizontal" | "vertical" | null = null,
|
|
76
70
|
view_window: ViewWindow = structuredClone(VIEW_WINDOW),
|
|
77
71
|
path: number[] = [],
|
|
@@ -83,104 +77,68 @@ function calculate_intersection_recursive(
|
|
|
83
77
|
// Base case: if this is a child panel, return its name
|
|
84
78
|
if (panel.type === "child-panel") {
|
|
85
79
|
const selected = panel.selected ?? 0;
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
(view_window.col_end - view_window.col_start);
|
|
89
|
-
|
|
90
|
-
const row_offset =
|
|
91
|
-
(row - view_window.row_start) /
|
|
92
|
-
(view_window.row_end - view_window.row_start);
|
|
93
|
-
|
|
80
|
+
const col_width = view_window.col_end - view_window.col_start;
|
|
81
|
+
const row_height = view_window.row_end - view_window.row_start;
|
|
94
82
|
return {
|
|
95
83
|
type: "layout-path",
|
|
96
|
-
|
|
84
|
+
layout: undefined,
|
|
97
85
|
slot: panel.child[selected],
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
view_window: view_window,
|
|
86
|
+
path,
|
|
87
|
+
view_window,
|
|
101
88
|
is_edge: false,
|
|
102
89
|
column,
|
|
103
90
|
row,
|
|
104
|
-
column_offset,
|
|
105
|
-
row_offset,
|
|
91
|
+
column_offset: (column - view_window.col_start) / col_width,
|
|
92
|
+
row_offset: (row - view_window.row_start) / row_height,
|
|
106
93
|
orientation: parent_orientation || "horizontal",
|
|
107
94
|
};
|
|
108
95
|
}
|
|
109
96
|
|
|
110
97
|
// For split panels, determine which child was hit
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
98
|
+
const is_vertical = panel.orientation === "vertical";
|
|
99
|
+
const position = is_vertical ? row : column;
|
|
100
|
+
const start_key = is_vertical ? "row_start" : "col_start";
|
|
101
|
+
const end_key = is_vertical ? "row_end" : "col_end";
|
|
102
|
+
const rect_dim = is_vertical ? check_dividers?.height : check_dividers?.width;
|
|
103
|
+
let current_pos = view_window[start_key];
|
|
104
|
+
const total_size = view_window[end_key] - view_window[start_key];
|
|
105
|
+
for (let i = 0; i < panel.children.length; i++) {
|
|
106
|
+
const next_pos = current_pos + total_size * panel.sizes[i];
|
|
107
|
+
|
|
108
|
+
// Check if position is on a divider
|
|
109
|
+
if (check_dividers && rect_dim) {
|
|
110
|
+
const divider_threshold = GRID_DIVIDER_SIZE / rect_dim;
|
|
111
|
+
if (Math.abs(position - next_pos) < divider_threshold) {
|
|
118
112
|
return {
|
|
119
113
|
path: [...path, i],
|
|
120
|
-
type:
|
|
114
|
+
type: panel.orientation,
|
|
121
115
|
view_window: {
|
|
122
116
|
...view_window,
|
|
123
|
-
|
|
124
|
-
|
|
117
|
+
[start_key]: current_pos,
|
|
118
|
+
[end_key]: next_pos,
|
|
125
119
|
},
|
|
126
120
|
};
|
|
127
121
|
}
|
|
128
|
-
|
|
129
|
-
if (row >= current_row && row < next_row) {
|
|
130
|
-
return calculate_intersection_recursive(
|
|
131
|
-
column,
|
|
132
|
-
row,
|
|
133
|
-
panel.children[i],
|
|
134
|
-
check_dividers,
|
|
135
|
-
"vertical",
|
|
136
|
-
{
|
|
137
|
-
...view_window,
|
|
138
|
-
row_start: current_row,
|
|
139
|
-
row_end: next_row,
|
|
140
|
-
},
|
|
141
|
-
[...path, i],
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
current_row = next_row;
|
|
146
122
|
}
|
|
147
|
-
} else {
|
|
148
|
-
// Horizontal orientation = columns
|
|
149
|
-
let current_col = view_window.col_start;
|
|
150
|
-
for (let i = 0; i < panel.children.length; i++) {
|
|
151
|
-
const total_size = view_window.col_end - view_window.col_start;
|
|
152
|
-
const next_col = current_col + total_size * panel.sizes[i];
|
|
153
|
-
if (check_dividers && Math.abs(column - next_col) < 0.01) {
|
|
154
|
-
return {
|
|
155
|
-
path: [...path, i],
|
|
156
|
-
type: "horizontal",
|
|
157
|
-
view_window: {
|
|
158
|
-
...view_window,
|
|
159
|
-
col_start: current_col,
|
|
160
|
-
col_end: next_col,
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Check if the column falls within this child's bounds.
|
|
166
|
-
if (column >= current_col && column < next_col) {
|
|
167
|
-
return calculate_intersection_recursive(
|
|
168
|
-
column,
|
|
169
|
-
row,
|
|
170
|
-
panel.children[i],
|
|
171
|
-
check_dividers,
|
|
172
|
-
"horizontal",
|
|
173
|
-
{
|
|
174
|
-
...view_window,
|
|
175
|
-
col_start: current_col,
|
|
176
|
-
col_end: next_col,
|
|
177
|
-
},
|
|
178
|
-
[...path, i],
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
123
|
|
|
182
|
-
|
|
124
|
+
// Check if position falls within this child's bounds
|
|
125
|
+
if (position >= current_pos && position < next_pos) {
|
|
126
|
+
return calculate_intersection_recursive(
|
|
127
|
+
column,
|
|
128
|
+
row,
|
|
129
|
+
panel.children[i],
|
|
130
|
+
check_dividers,
|
|
131
|
+
panel.orientation,
|
|
132
|
+
{
|
|
133
|
+
...view_window,
|
|
134
|
+
[start_key]: current_pos,
|
|
135
|
+
[end_key]: next_pos,
|
|
136
|
+
},
|
|
137
|
+
[...path, i],
|
|
138
|
+
);
|
|
183
139
|
}
|
|
140
|
+
|
|
141
|
+
current_pos = next_pos;
|
|
184
142
|
}
|
|
185
143
|
|
|
186
144
|
// If we get here, the hit was outside all children (possibly in a gap or
|
|
@@ -9,7 +9,13 @@
|
|
|
9
9
|
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
|
|
10
10
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
11
|
|
|
12
|
-
import type { OverlayMode } from "./
|
|
12
|
+
import type { OverlayMode } from "./types";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The prefix to use for `CustomEvent`s generated by `regular-layout`, e.g.
|
|
16
|
+
* `"regular-layout-before-update"`.
|
|
17
|
+
*/
|
|
18
|
+
export const CUSTOM_EVENT_NAME_PREFIX = "regular-layout";
|
|
13
19
|
|
|
14
20
|
/**
|
|
15
21
|
* The minimum number of pixels the mouse must move to be considered a drag.
|
|
@@ -32,6 +38,12 @@ export const MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD = 0.15;
|
|
|
32
38
|
*/
|
|
33
39
|
export const SPLIT_EDGE_TOLERANCE = 0.25;
|
|
34
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Threshold from _container_ edge that is considered a split action on the root
|
|
43
|
+
* node.
|
|
44
|
+
*/
|
|
45
|
+
export const SPLIT_ROOT_EDGE_TOLERANCE = 0.01;
|
|
46
|
+
|
|
35
47
|
/**
|
|
36
48
|
* Tolerance threshold for considering two grid track positions as identical.
|
|
37
49
|
*
|
|
@@ -44,3 +56,8 @@ export const GRID_TRACK_COLLAPSE_TOLERANCE = 0.001;
|
|
|
44
56
|
* The overlay default behavior.
|
|
45
57
|
*/
|
|
46
58
|
export const OVERLAY_DEFAULT: OverlayMode = "absolute";
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Width of split panel dividers in pixels (for hit-test purposes).
|
|
62
|
+
*/
|
|
63
|
+
export const GRID_DIVIDER_SIZE = 6;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
|
|
10
10
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
11
|
|
|
12
|
-
import type { Layout } from "./
|
|
12
|
+
import type { Layout } from "./types.ts";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Flattens the layout tree by merging parent and child split panels that have
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
11
|
|
|
12
12
|
import { GRID_TRACK_COLLAPSE_TOLERANCE } from "./constants.ts";
|
|
13
|
-
import type { Layout } from "./
|
|
14
|
-
import { remove_child } from "./remove_child.ts";
|
|
13
|
+
import type { Layout } from "./types.ts";
|
|
15
14
|
|
|
16
15
|
interface GridCell {
|
|
17
16
|
child: string;
|
|
@@ -21,26 +20,23 @@ interface GridCell {
|
|
|
21
20
|
rowEnd: number;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
function
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const result = [sorted[0]];
|
|
31
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
32
|
-
if (
|
|
33
|
-
Math.abs(sorted[i] - result[result.length - 1]) >
|
|
34
|
-
GRID_TRACK_COLLAPSE_TOLERANCE
|
|
35
|
-
) {
|
|
36
|
-
result.push(sorted[i]);
|
|
37
|
-
}
|
|
23
|
+
function dedupe_sort(result: number[], pos: number) {
|
|
24
|
+
if (
|
|
25
|
+
result.length === 0 ||
|
|
26
|
+
Math.abs(pos - result[result.length - 1]) > GRID_TRACK_COLLAPSE_TOLERANCE
|
|
27
|
+
) {
|
|
28
|
+
result.push(pos);
|
|
38
29
|
}
|
|
39
30
|
|
|
40
31
|
return result;
|
|
41
32
|
}
|
|
42
33
|
|
|
43
|
-
function
|
|
34
|
+
function dedupe_positions(positions: number[]): number[] {
|
|
35
|
+
const sorted = positions.sort((a, b) => a - b);
|
|
36
|
+
return sorted.reduce(dedupe_sort, []);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function collect_track_positions(
|
|
44
40
|
panel: Layout,
|
|
45
41
|
orientation: "horizontal" | "vertical",
|
|
46
42
|
start: number,
|
|
@@ -50,51 +46,44 @@ function collectTrackPositions(
|
|
|
50
46
|
return [start, end];
|
|
51
47
|
}
|
|
52
48
|
|
|
49
|
+
const positions: number[] = [start, end];
|
|
53
50
|
if (panel.orientation === orientation) {
|
|
54
|
-
const positions: number[] = [start, end];
|
|
55
51
|
let current = start;
|
|
52
|
+
const range = end - start;
|
|
56
53
|
for (let i = 0; i < panel.children.length; i++) {
|
|
57
54
|
const size = panel.sizes[i];
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
const next = current + size * range;
|
|
56
|
+
positions.push(
|
|
57
|
+
...collect_track_positions(
|
|
58
|
+
panel.children[i],
|
|
59
|
+
orientation,
|
|
60
|
+
current,
|
|
61
|
+
next,
|
|
62
|
+
),
|
|
63
63
|
);
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
current = current + size * (end - start);
|
|
65
|
+
current = next;
|
|
67
66
|
}
|
|
68
|
-
|
|
69
|
-
return dedupePositions(positions);
|
|
70
67
|
} else {
|
|
71
|
-
const allPositions: number[] = [start, end];
|
|
72
68
|
for (const child of panel.children) {
|
|
73
|
-
|
|
74
|
-
child,
|
|
75
|
-
orientation,
|
|
76
|
-
start,
|
|
77
|
-
end,
|
|
69
|
+
positions.push(
|
|
70
|
+
...collect_track_positions(child, orientation, start, end),
|
|
78
71
|
);
|
|
79
|
-
|
|
80
|
-
allPositions.push(...childPositions);
|
|
81
72
|
}
|
|
82
|
-
|
|
83
|
-
return dedupePositions(allPositions);
|
|
84
73
|
}
|
|
74
|
+
|
|
75
|
+
return dedupe_positions(positions);
|
|
85
76
|
}
|
|
86
77
|
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
}
|
|
78
|
+
function find_track_index(positions: number[], value: number): number {
|
|
79
|
+
const index = positions.findIndex(
|
|
80
|
+
(pos) => Math.abs(pos - value) < GRID_TRACK_COLLAPSE_TOLERANCE,
|
|
81
|
+
);
|
|
93
82
|
|
|
94
|
-
|
|
83
|
+
return index === -1 ? 0 : index;
|
|
95
84
|
}
|
|
96
85
|
|
|
97
|
-
function
|
|
86
|
+
function build_cells(
|
|
98
87
|
panel: Layout,
|
|
99
88
|
colPositions: number[],
|
|
100
89
|
rowPositions: number[],
|
|
@@ -108,22 +97,24 @@ function buildCells(
|
|
|
108
97
|
return [
|
|
109
98
|
{
|
|
110
99
|
child: panel.child[selected],
|
|
111
|
-
colStart:
|
|
112
|
-
colEnd:
|
|
113
|
-
rowStart:
|
|
114
|
-
rowEnd:
|
|
100
|
+
colStart: find_track_index(colPositions, colStart),
|
|
101
|
+
colEnd: find_track_index(colPositions, colEnd),
|
|
102
|
+
rowStart: find_track_index(rowPositions, rowStart),
|
|
103
|
+
rowEnd: find_track_index(rowPositions, rowEnd),
|
|
115
104
|
},
|
|
116
105
|
];
|
|
117
106
|
}
|
|
118
107
|
|
|
119
|
-
const cells: GridCell[] = [];
|
|
120
108
|
const { children, sizes, orientation } = panel;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
const isHorizontal = orientation === "horizontal";
|
|
110
|
+
let current = isHorizontal ? colStart : rowStart;
|
|
111
|
+
const range = isHorizontal ? colEnd - colStart : rowEnd - rowStart;
|
|
112
|
+
const cells: GridCell[] = [];
|
|
113
|
+
for (let i = 0; i < children.length; i++) {
|
|
114
|
+
const next = current + sizes[i] * range;
|
|
115
|
+
if (isHorizontal) {
|
|
125
116
|
cells.push(
|
|
126
|
-
...
|
|
117
|
+
...build_cells(
|
|
127
118
|
children[i],
|
|
128
119
|
colPositions,
|
|
129
120
|
rowPositions,
|
|
@@ -133,15 +124,9 @@ function buildCells(
|
|
|
133
124
|
rowEnd,
|
|
134
125
|
),
|
|
135
126
|
);
|
|
136
|
-
|
|
137
|
-
current = next;
|
|
138
|
-
}
|
|
139
|
-
} else {
|
|
140
|
-
let current = rowStart;
|
|
141
|
-
for (let i = 0; i < children.length; i++) {
|
|
142
|
-
const next = current + sizes[i] * (rowEnd - rowStart);
|
|
127
|
+
} else {
|
|
143
128
|
cells.push(
|
|
144
|
-
...
|
|
129
|
+
...build_cells(
|
|
145
130
|
children[i],
|
|
146
131
|
colPositions,
|
|
147
132
|
rowPositions,
|
|
@@ -151,19 +136,19 @@ function buildCells(
|
|
|
151
136
|
next,
|
|
152
137
|
),
|
|
153
138
|
);
|
|
154
|
-
|
|
155
|
-
current = next;
|
|
156
139
|
}
|
|
140
|
+
|
|
141
|
+
current = next;
|
|
157
142
|
}
|
|
158
143
|
|
|
159
144
|
return cells;
|
|
160
145
|
}
|
|
161
146
|
|
|
162
147
|
const host_template = (rowTemplate: string, colTemplate: string) =>
|
|
163
|
-
`:host {
|
|
148
|
+
`:host ::slotted(*){display:none}:host{display:grid;grid-template-rows:${rowTemplate};grid-template-columns:${colTemplate}}`;
|
|
164
149
|
|
|
165
150
|
const child_template = (slot: string, rowPart: string, colPart: string) =>
|
|
166
|
-
`:host ::slotted([
|
|
151
|
+
`:host ::slotted([name="${slot}"]){display:flex;grid-column:${colPart};grid-row:${rowPart}}`;
|
|
167
152
|
|
|
168
153
|
/**
|
|
169
154
|
* Generates CSS Grid styles to render a layout tree.
|
|
@@ -191,8 +176,8 @@ const child_template = (slot: string, rowPart: string, colPart: string) =>
|
|
|
191
176
|
* const css = create_css_grid_layout(layout);
|
|
192
177
|
* // Returns CSS like:
|
|
193
178
|
* // :host { display: grid; grid-template-columns: 25% 75%; ... }
|
|
194
|
-
* // :host ::slotted([
|
|
195
|
-
* // :host ::slotted([
|
|
179
|
+
* // :host ::slotted([name=sidebar]) { grid-column: 1; grid-row: 1; }
|
|
180
|
+
* // :host ::slotted([name=main]) { grid-column: 2; grid-row: 1; }
|
|
196
181
|
* ```
|
|
197
182
|
*/
|
|
198
183
|
export function create_css_grid_layout(
|
|
@@ -200,51 +185,36 @@ export function create_css_grid_layout(
|
|
|
200
185
|
round: boolean = false,
|
|
201
186
|
overlay?: [string, string],
|
|
202
187
|
): string {
|
|
203
|
-
if (overlay) {
|
|
204
|
-
layout = remove_child(layout, overlay[0]);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
188
|
if (layout.type === "child-panel") {
|
|
208
189
|
const selected = layout.selected ?? 0;
|
|
209
190
|
return `${host_template("100%", "100%")}\n${child_template(layout.child[selected], "1", "1")}`;
|
|
210
191
|
}
|
|
211
192
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
.map((s) => `${round ? Math.round(s * 100) : s * 100}%`)
|
|
230
|
-
.join(" ");
|
|
231
|
-
|
|
232
|
-
const cells = buildCells(layout, colPositions, rowPositions, 0, 1, 0, 1);
|
|
193
|
+
const createTemplate = (positions: number[]) => {
|
|
194
|
+
const sizes = positions
|
|
195
|
+
.slice(0, -1)
|
|
196
|
+
.map((pos, i) => positions[i + 1] - pos);
|
|
197
|
+
return sizes
|
|
198
|
+
.map((s) => `${round ? Math.round(s * 100) : s * 100}fr`)
|
|
199
|
+
.join(" ");
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const colPositions = collect_track_positions(layout, "horizontal", 0, 1);
|
|
203
|
+
const colTemplate = createTemplate(colPositions);
|
|
204
|
+
const rowPositions = collect_track_positions(layout, "vertical", 0, 1);
|
|
205
|
+
const rowTemplate = createTemplate(rowPositions);
|
|
206
|
+
const formatGridLine = (start: number, end: number) =>
|
|
207
|
+
end - start === 1 ? `${start + 1}` : `${start + 1} / ${end + 1}`;
|
|
208
|
+
|
|
209
|
+
const cells = build_cells(layout, colPositions, rowPositions, 0, 1, 0, 1);
|
|
233
210
|
const css = [host_template(rowTemplate, colTemplate)];
|
|
234
211
|
for (const cell of cells) {
|
|
235
|
-
const colPart =
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
: `${cell.colStart + 1} / ${cell.colEnd + 1}`;
|
|
239
|
-
const rowPart =
|
|
240
|
-
cell.rowEnd - cell.rowStart === 1
|
|
241
|
-
? `${cell.rowStart + 1}`
|
|
242
|
-
: `${cell.rowStart + 1} / ${cell.rowEnd + 1}`;
|
|
243
|
-
|
|
244
|
-
css.push(`${child_template(cell.child, rowPart, colPart)}`);
|
|
212
|
+
const colPart = formatGridLine(cell.colStart, cell.colEnd);
|
|
213
|
+
const rowPart = formatGridLine(cell.rowStart, cell.rowEnd);
|
|
214
|
+
css.push(child_template(cell.child, rowPart, colPart));
|
|
245
215
|
if (cell.child === overlay?.[1]) {
|
|
246
|
-
css.push(
|
|
247
|
-
css.push(`:host ::slotted([
|
|
216
|
+
css.push(child_template(overlay[0], rowPart, colPart));
|
|
217
|
+
css.push(`:host ::slotted([name=${overlay[0]}]){z-index:1}`);
|
|
248
218
|
}
|
|
249
219
|
}
|
|
250
220
|
|
|
@@ -9,20 +9,32 @@
|
|
|
9
9
|
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
|
|
10
10
|
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
11
11
|
|
|
12
|
-
import type { LayoutPath } from "./
|
|
12
|
+
import type { LayoutPath } from "./types";
|
|
13
13
|
|
|
14
14
|
export function updateOverlaySheet(
|
|
15
15
|
slot: string,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}: LayoutPath<DOMRect>,
|
|
16
|
+
box: DOMRect,
|
|
17
|
+
style: CSSStyleDeclaration,
|
|
18
|
+
drag_target: LayoutPath<undefined> | null,
|
|
20
19
|
) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
if (!drag_target) {
|
|
21
|
+
return `:host ::slotted([name="${slot}"]){display:none;}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
view_window: { row_start, row_end, col_start, col_end },
|
|
26
|
+
} = drag_target;
|
|
27
|
+
|
|
28
|
+
const box_height =
|
|
29
|
+
box.height - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom);
|
|
30
|
+
|
|
31
|
+
const box_width =
|
|
32
|
+
box.width - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
33
|
+
|
|
34
|
+
const top = row_start * box_height + parseFloat(style.paddingTop);
|
|
35
|
+
const left = col_start * box_width + parseFloat(style.paddingLeft);
|
|
36
|
+
const height = (row_end - row_start) * box_height;
|
|
37
|
+
const width = (col_end - col_start) * box_width;
|
|
38
|
+
const css = `display:flex;position:absolute!important;z-index:1;top:${top}px;left:${left}px;height:${height}px;width:${width}px;`;
|
|
39
|
+
return `::slotted([name="${slot}"]){${css}}`;
|
|
28
40
|
}
|