regular-layout 0.2.0 → 0.2.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.
@@ -12,52 +12,108 @@
12
12
  import type { OverlayMode } from "./types";
13
13
 
14
14
  /**
15
- * The prefix to use for `CustomEvent`s generated by `regular-layout`, e.g.
16
- * `"regular-layout-before-update"`.
15
+ * Instance-specific constants which define the behavior and rendering details
16
+ * of a `<regular-layout>`.
17
17
  */
18
- export const CUSTOM_EVENT_NAME_PREFIX = "regular-layout";
18
+ export interface Physics {
19
+ /**
20
+ * The prefix to use for `CustomEvent`s generated by `regular-layout`, e.g.
21
+ * `"regular-layout-before-update"`.
22
+ */
23
+ CUSTOM_EVENT_NAME_PREFIX: string;
19
24
 
20
- /**
21
- * The minimum number of pixels the mouse must move to be considered a drag.
22
- */
23
- export const MIN_DRAG_DISTANCE = 10;
25
+ /**
26
+ * The attribute name to use for matching child `Element`s to grid
27
+ * positions.
28
+ */
29
+ CHILD_ATTRIBUTE_NAME: string;
24
30
 
25
- /**
26
- * Class name to use for child elements in overlay position (dragging).
27
- */
28
- export const OVERLAY_CLASSNAME = "overlay";
31
+ /**
32
+ * The minimum number of pixels the mouse must move to be considered a drag.
33
+ */
34
+ MIN_DRAG_DISTANCE: number;
29
35
 
30
- /**
31
- * The percentage of the maximum resize distance that will be clamped.
32
- *
33
- */
34
- export const MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD = 0.15;
36
+ /**
37
+ * Should floating point pixel calculations be rounded. Useful for testing.
38
+ */
39
+ SHOULD_ROUND: boolean;
35
40
 
36
- /**
37
- * Threshold from panel edge that is considered a split vs drop action.
38
- */
39
- export const SPLIT_EDGE_TOLERANCE = 0.25;
41
+ /**
42
+ * Class name to use for child elements in overlay position (dragging).
43
+ */
44
+ OVERLAY_CLASSNAME: string;
40
45
 
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
+ /**
47
+ * The percentage of the maximum resize distance that will be clamped.
48
+ */
49
+ MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD: number;
46
50
 
47
- /**
48
- * Tolerance threshold for considering two grid track positions as identical.
49
- *
50
- * When collecting and deduplicating track positions, any positions closer than
51
- * this value are treated as the same position to avoid redundant grid tracks.
52
- */
53
- export const GRID_TRACK_COLLAPSE_TOLERANCE = 0.001;
51
+ /**
52
+ * Threshold from panel edge that is considered a split vs drop action.
53
+ */
54
+ SPLIT_EDGE_TOLERANCE: number;
54
55
 
55
- /**
56
- * The overlay default behavior.
57
- */
58
- export const OVERLAY_DEFAULT: OverlayMode = "absolute";
56
+ /**
57
+ * Threshold from _container_ edge that is considered a split action on the root
58
+ * node.
59
+ */
60
+ SPLIT_ROOT_EDGE_TOLERANCE: number;
61
+
62
+ /**
63
+ * Tolerance threshold for considering two grid track positions as identical.
64
+ *
65
+ * When collecting and deduplicating track positions, any positions closer than
66
+ * this value are treated as the same position to avoid redundant grid tracks.
67
+ */
68
+ GRID_TRACK_COLLAPSE_TOLERANCE: number;
69
+
70
+ /**
71
+ * The overlay default behavior.
72
+ */
73
+ OVERLAY_DEFAULT: OverlayMode;
74
+
75
+ /**
76
+ * Width of split panel dividers in pixels (for hit-test purposes).
77
+ */
78
+ GRID_DIVIDER_SIZE: number;
79
+
80
+ /**
81
+ * Whether the grid should trigger column resize if the grid itself is not
82
+ * the `event.target`.
83
+ */
84
+ GRID_DIVIDER_CHECK_TARGET: boolean;
85
+ }
59
86
 
60
87
  /**
61
- * Width of split panel dividers in pixels (for hit-test purposes).
88
+ * Like `GlobalPhysics`, but suitable for partial definition for incremental
89
+ * updates.
62
90
  */
63
- export const GRID_DIVIDER_SIZE = 6;
91
+ export interface PhysicsUpdate {
92
+ CUSTOM_EVENT_NAME_PREFIX?: string;
93
+ CHILD_ATTRIBUTE_NAME?: string;
94
+ MIN_DRAG_DISTANCE?: number;
95
+ SHOULD_ROUND?: boolean;
96
+ OVERLAY_CLASSNAME?: string;
97
+ MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD?: number;
98
+ SPLIT_EDGE_TOLERANCE?: number;
99
+ SPLIT_ROOT_EDGE_TOLERANCE?: number;
100
+ GRID_TRACK_COLLAPSE_TOLERANCE?: number;
101
+ OVERLAY_DEFAULT?: OverlayMode;
102
+ GRID_DIVIDER_SIZE?: number;
103
+ GRID_DIVIDER_CHECK_TARGET?: boolean;
104
+ }
105
+
106
+ export const DEFAULT_PHYSICS: Physics = Object.freeze({
107
+ CUSTOM_EVENT_NAME_PREFIX: "regular-layout",
108
+ CHILD_ATTRIBUTE_NAME: "name",
109
+ MIN_DRAG_DISTANCE: 10,
110
+ SHOULD_ROUND: false,
111
+ OVERLAY_CLASSNAME: "overlay",
112
+ MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD: 0.15,
113
+ SPLIT_EDGE_TOLERANCE: 0.25,
114
+ SPLIT_ROOT_EDGE_TOLERANCE: 0.01,
115
+ GRID_TRACK_COLLAPSE_TOLERANCE: 0.001,
116
+ OVERLAY_DEFAULT: "absolute",
117
+ GRID_DIVIDER_SIZE: 6,
118
+ GRID_DIVIDER_CHECK_TARGET: true,
119
+ });
@@ -9,7 +9,7 @@
9
9
  // ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
10
10
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
11
11
 
12
- import { GRID_TRACK_COLLAPSE_TOLERANCE } from "./constants.ts";
12
+ import { DEFAULT_PHYSICS, type Physics } from "./constants.ts";
13
13
  import type { Layout } from "./types.ts";
14
14
 
15
15
  interface GridCell {
@@ -20,10 +20,11 @@ interface GridCell {
20
20
  rowEnd: number;
21
21
  }
22
22
 
23
- function dedupe_sort(result: number[], pos: number) {
23
+ function dedupe_sort(physics: Physics, result: number[], pos: number) {
24
24
  if (
25
25
  result.length === 0 ||
26
- Math.abs(pos - result[result.length - 1]) > GRID_TRACK_COLLAPSE_TOLERANCE
26
+ Math.abs(pos - result[result.length - 1]) >
27
+ physics.GRID_TRACK_COLLAPSE_TOLERANCE
27
28
  ) {
28
29
  result.push(pos);
29
30
  }
@@ -31,9 +32,9 @@ function dedupe_sort(result: number[], pos: number) {
31
32
  return result;
32
33
  }
33
34
 
34
- function dedupe_positions(positions: number[]): number[] {
35
+ function dedupe_positions(physics: Physics, positions: number[]): number[] {
35
36
  const sorted = positions.sort((a, b) => a - b);
36
- return sorted.reduce(dedupe_sort, []);
37
+ return sorted.reduce(dedupe_sort.bind(undefined, physics), []);
37
38
  }
38
39
 
39
40
  function collect_track_positions(
@@ -41,6 +42,7 @@ function collect_track_positions(
41
42
  orientation: "horizontal" | "vertical",
42
43
  start: number,
43
44
  end: number,
45
+ physics: Physics,
44
46
  ): number[] {
45
47
  if (panel.type === "child-panel") {
46
48
  return [start, end];
@@ -59,6 +61,7 @@ function collect_track_positions(
59
61
  orientation,
60
62
  current,
61
63
  next,
64
+ physics,
62
65
  ),
63
66
  );
64
67
 
@@ -67,17 +70,21 @@ function collect_track_positions(
67
70
  } else {
68
71
  for (const child of panel.children) {
69
72
  positions.push(
70
- ...collect_track_positions(child, orientation, start, end),
73
+ ...collect_track_positions(child, orientation, start, end, physics),
71
74
  );
72
75
  }
73
76
  }
74
77
 
75
- return dedupe_positions(positions);
78
+ return dedupe_positions(physics, positions);
76
79
  }
77
80
 
78
- function find_track_index(positions: number[], value: number): number {
81
+ function find_track_index(
82
+ physics: Physics,
83
+ positions: number[],
84
+ value: number,
85
+ ): number {
79
86
  const index = positions.findIndex(
80
- (pos) => Math.abs(pos - value) < GRID_TRACK_COLLAPSE_TOLERANCE,
87
+ (pos) => Math.abs(pos - value) < physics.GRID_TRACK_COLLAPSE_TOLERANCE,
81
88
  );
82
89
 
83
90
  return index === -1 ? 0 : index;
@@ -91,16 +98,17 @@ function build_cells(
91
98
  colEnd: number,
92
99
  rowStart: number,
93
100
  rowEnd: number,
101
+ physics: Physics,
94
102
  ): GridCell[] {
95
103
  if (panel.type === "child-panel") {
96
104
  const selected = panel.selected ?? 0;
97
105
  return [
98
106
  {
99
- child: panel.child[selected],
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),
107
+ child: panel.tabs[selected],
108
+ colStart: find_track_index(physics, colPositions, colStart),
109
+ colEnd: find_track_index(physics, colPositions, colEnd),
110
+ rowStart: find_track_index(physics, rowPositions, rowStart),
111
+ rowEnd: find_track_index(physics, rowPositions, rowEnd),
104
112
  },
105
113
  ];
106
114
  }
@@ -122,6 +130,7 @@ function build_cells(
122
130
  next,
123
131
  rowStart,
124
132
  rowEnd,
133
+ physics,
125
134
  ),
126
135
  );
127
136
  } else {
@@ -134,6 +143,7 @@ function build_cells(
134
143
  colEnd,
135
144
  current,
136
145
  next,
146
+ physics,
137
147
  ),
138
148
  );
139
149
  }
@@ -147,8 +157,13 @@ function build_cells(
147
157
  const host_template = (rowTemplate: string, colTemplate: string) =>
148
158
  `:host ::slotted(*){display:none}:host{display:grid;grid-template-rows:${rowTemplate};grid-template-columns:${colTemplate}}`;
149
159
 
150
- const child_template = (slot: string, rowPart: string, colPart: string) =>
151
- `:host ::slotted([name="${slot}"]){display:flex;grid-column:${colPart};grid-row:${rowPart}}`;
160
+ const child_template = (
161
+ physics: Physics,
162
+ slot: string,
163
+ rowPart: string,
164
+ colPart: string,
165
+ ) =>
166
+ `:host ::slotted([${physics.CHILD_ATTRIBUTE_NAME}="${slot}"]){display:flex;grid-column:${colPart};grid-row:${rowPart}}`;
152
167
 
153
168
  /**
154
169
  * Generates CSS Grid styles to render a layout tree.
@@ -167,8 +182,8 @@ const child_template = (slot: string, rowPart: string, colPart: string) =>
167
182
  * type: "split-panel",
168
183
  * orientation: "horizontal",
169
184
  * children: [
170
- * { type: "child-panel", child: "sidebar" },
171
- * { type: "child-panel", child: "main" }
185
+ * { type: "child-panel", tabs: "sidebar" },
186
+ * { type: "child-panel", tabs: "main" }
172
187
  * ],
173
188
  * sizes: [0.25, 0.75]
174
189
  * };
@@ -182,12 +197,15 @@ const child_template = (slot: string, rowPart: string, colPart: string) =>
182
197
  */
183
198
  export function create_css_grid_layout(
184
199
  layout: Layout,
185
- round: boolean = false,
186
200
  overlay?: [string, string],
201
+ physics: Physics = DEFAULT_PHYSICS,
187
202
  ): string {
188
203
  if (layout.type === "child-panel") {
189
204
  const selected = layout.selected ?? 0;
190
- return `${host_template("100%", "100%")}\n${child_template(layout.child[selected], "1", "1")}`;
205
+ return [
206
+ host_template("100%", "100%"),
207
+ child_template(physics, layout.tabs[selected], "1", "1"),
208
+ ].join("\n");
191
209
  }
192
210
 
193
211
  const createTemplate = (positions: number[]) => {
@@ -195,26 +213,52 @@ export function create_css_grid_layout(
195
213
  .slice(0, -1)
196
214
  .map((pos, i) => positions[i + 1] - pos);
197
215
  return sizes
198
- .map((s) => `${round ? Math.round(s * 100) : s * 100}fr`)
216
+ .map((s) => `${physics.SHOULD_ROUND ? Math.round(s * 100) : s * 100}fr`)
199
217
  .join(" ");
200
218
  };
201
219
 
202
- const colPositions = collect_track_positions(layout, "horizontal", 0, 1);
220
+ const colPositions = collect_track_positions(
221
+ layout,
222
+ "horizontal",
223
+ 0,
224
+ 1,
225
+ physics,
226
+ );
227
+
203
228
  const colTemplate = createTemplate(colPositions);
204
- const rowPositions = collect_track_positions(layout, "vertical", 0, 1);
229
+ const rowPositions = collect_track_positions(
230
+ layout,
231
+ "vertical",
232
+ 0,
233
+ 1,
234
+ physics,
235
+ );
236
+
205
237
  const rowTemplate = createTemplate(rowPositions);
206
238
  const formatGridLine = (start: number, end: number) =>
207
239
  end - start === 1 ? `${start + 1}` : `${start + 1} / ${end + 1}`;
208
240
 
209
- const cells = build_cells(layout, colPositions, rowPositions, 0, 1, 0, 1);
241
+ const cells = build_cells(
242
+ layout,
243
+ colPositions,
244
+ rowPositions,
245
+ 0,
246
+ 1,
247
+ 0,
248
+ 1,
249
+ physics,
250
+ );
251
+
210
252
  const css = [host_template(rowTemplate, colTemplate)];
211
253
  for (const cell of cells) {
212
254
  const colPart = formatGridLine(cell.colStart, cell.colEnd);
213
255
  const rowPart = formatGridLine(cell.rowStart, cell.rowEnd);
214
- css.push(child_template(cell.child, rowPart, colPart));
256
+ css.push(child_template(physics, cell.child, rowPart, colPart));
215
257
  if (cell.child === overlay?.[1]) {
216
- css.push(child_template(overlay[0], rowPart, colPart));
217
- css.push(`:host ::slotted([name=${overlay[0]}]){z-index:1}`);
258
+ css.push(child_template(physics, overlay[0], rowPart, colPart));
259
+ css.push(
260
+ `:host ::slotted([${physics.CHILD_ATTRIBUTE_NAME}=${overlay[0]}]){z-index:1}`,
261
+ );
218
262
  }
219
263
  }
220
264
 
@@ -9,16 +9,18 @@
9
9
  // ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
10
10
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
11
11
 
12
+ import { DEFAULT_PHYSICS } from "./constants";
12
13
  import type { LayoutPath } from "./types";
13
14
 
14
15
  export function updateOverlaySheet(
15
16
  slot: string,
16
17
  box: DOMRect,
17
18
  style: CSSStyleDeclaration,
18
- drag_target: LayoutPath<undefined> | null,
19
+ drag_target: LayoutPath | null,
20
+ physics = DEFAULT_PHYSICS,
19
21
  ) {
20
22
  if (!drag_target) {
21
- return `:host ::slotted([name="${slot}"]){display:none;}`;
23
+ return `:host ::slotted([${physics.CHILD_ATTRIBUTE_NAME}="${slot}"]){display:none;}`;
22
24
  }
23
25
 
24
26
  const {
@@ -36,5 +38,5 @@ export function updateOverlaySheet(
36
38
  const height = (row_end - row_start) * box_height;
37
39
  const width = (col_end - col_start) * box_width;
38
40
  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}}`;
41
+ return `::slotted([${physics.CHILD_ATTRIBUTE_NAME}="${slot}"]){${css}}`;
40
42
  }
@@ -33,7 +33,7 @@ export function insert_child(
33
33
  ): Layout {
34
34
  const createChildPanel = (childId: string): Layout => ({
35
35
  type: "child-panel",
36
- child: [childId],
36
+ tabs: [childId],
37
37
  });
38
38
 
39
39
  if (path.length === 0) {
@@ -42,7 +42,7 @@ export function insert_child(
42
42
  // Add to existing child-panel as a tab
43
43
  return {
44
44
  type: "child-panel",
45
- child: [child, ...panel.child],
45
+ tabs: [child, ...panel.tabs],
46
46
  };
47
47
  } else if (orientation) {
48
48
  // When inserting at edge of root, wrap the entire panel in a new split
@@ -105,13 +105,13 @@ export function insert_child(
105
105
  restPath.length === 0 &&
106
106
  orientation === undefined &&
107
107
  index >= 0 &&
108
- index <= panel.child.length
108
+ index <= panel.tabs.length
109
109
  ) {
110
- const newChild = [...panel.child];
110
+ const newChild = [...panel.tabs];
111
111
  newChild.splice(index, 0, child);
112
112
  return {
113
113
  ...panel,
114
- child: newChild,
114
+ tabs: newChild,
115
115
  };
116
116
  }
117
117
 
@@ -9,7 +9,7 @@
9
9
  // ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
10
10
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
11
11
 
12
- import { MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD } from "./constants.ts";
12
+ import { DEFAULT_PHYSICS } from "./constants.ts";
13
13
  import type { Layout } from "./types.ts";
14
14
 
15
15
  /**
@@ -32,7 +32,8 @@ import type { Layout } from "./types.ts";
32
32
  export function redistribute_panel_sizes(
33
33
  panel: Layout,
34
34
  path: number[],
35
- delta: number,
35
+ delta: number | undefined,
36
+ physics = DEFAULT_PHYSICS,
36
37
  ): Layout {
37
38
  // Clone the entire panel structure
38
39
  const result = structuredClone(panel);
@@ -40,7 +41,7 @@ export function redistribute_panel_sizes(
40
41
  // Find the orientation of the insertion panel,
41
42
  // and scale the delta on the respective axis if aligned.
42
43
  let current: Layout = result;
43
- const deltas = { horizontal: delta, vertical: delta };
44
+ const deltas = { horizontal: delta || 0, vertical: delta || 0 };
44
45
  for (let i = 0; i < path.length - 1; i++) {
45
46
  if (current.type === "split-panel") {
46
47
  deltas[current.orientation] /= current.sizes[path[i]];
@@ -50,12 +51,21 @@ export function redistribute_panel_sizes(
50
51
 
51
52
  // Apply the redistribution at the final path index
52
53
  if (current.type === "split-panel") {
53
- const delta = deltas[current.orientation];
54
- const index = path[path.length - 1];
54
+ if (delta === undefined) {
55
+ current.sizes = current.sizes.map((_) => 1 / current.sizes.length);
56
+ } else {
57
+ const delta = deltas[current.orientation];
58
+ const index = path[path.length - 1];
55
59
 
56
- // It would be fun to remove this condition.
57
- if (index < current.sizes.length - 1) {
58
- current.sizes = add_and_redistribute(current.sizes, index, delta);
60
+ // It would be fun to remove this condition.
61
+ if (index < current.sizes.length - 1) {
62
+ current.sizes = add_and_redistribute(
63
+ physics,
64
+ current.sizes,
65
+ index,
66
+ delta,
67
+ );
68
+ }
59
69
  }
60
70
  }
61
71
 
@@ -63,6 +73,7 @@ export function redistribute_panel_sizes(
63
73
  }
64
74
 
65
75
  function add_and_redistribute(
76
+ physics: typeof DEFAULT_PHYSICS,
66
77
  arr: number[],
67
78
  index: number,
68
79
  delta: number,
@@ -83,7 +94,7 @@ function add_and_redistribute(
83
94
  Math.sign(delta) *
84
95
  Math.min(
85
96
  Math.abs(delta),
86
- (1 - MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD) *
97
+ (1 - physics.MINIMUM_REDISTRIBUTION_SIZE_THRESHOLD) *
87
98
  (delta > 0 ? before_total : after_total),
88
99
  );
89
100
 
@@ -26,14 +26,14 @@ import { EMPTY_PANEL } from "./types.ts";
26
26
  export function remove_child(panel: Layout, child: string): Layout {
27
27
  // If this is a child panel, handle tab removal
28
28
  if (panel.type === "child-panel") {
29
- if (panel.child.includes(child)) {
30
- const newChild = panel.child.filter((c) => c !== child);
29
+ if (panel.tabs.includes(child)) {
30
+ const newChild = panel.tabs.filter((c) => c !== child);
31
31
  if (newChild.length === 0) {
32
32
  return structuredClone(EMPTY_PANEL);
33
33
  }
34
34
  return {
35
35
  type: "child-panel",
36
- child: newChild,
36
+ tabs: newChild,
37
37
  };
38
38
  }
39
39
 
@@ -46,7 +46,7 @@ export function remove_child(panel: Layout, child: string): Layout {
46
46
  // Try to remove the child from this split panel's children
47
47
  const index = result.children.findIndex((p) => {
48
48
  if (p.type === "child-panel") {
49
- return p.child.includes(child);
49
+ return p.tabs.includes(child);
50
50
  }
51
51
 
52
52
  return false;
@@ -54,7 +54,7 @@ export function remove_child(panel: Layout, child: string): Layout {
54
54
 
55
55
  if (index !== -1) {
56
56
  const tab_layout = result.children[index] as TabLayout;
57
- if (tab_layout.child.length === 1) {
57
+ if (tab_layout.tabs.length === 1) {
58
58
  // Found the child at this level - remove it
59
59
  const newChildren = result.children.filter((_, i) => i !== index);
60
60
  const newSizes = remove_and_redistribute(result.sizes, index);
@@ -67,10 +67,10 @@ export function remove_child(panel: Layout, child: string): Layout {
67
67
  result.children = newChildren;
68
68
  result.sizes = newSizes;
69
69
  } else {
70
- tab_layout.child.splice(tab_layout.child.indexOf(child), 1);
70
+ tab_layout.tabs.splice(tab_layout.tabs.indexOf(child), 1);
71
71
  if (
72
72
  tab_layout.selected &&
73
- tab_layout.selected >= tab_layout.child.length
73
+ tab_layout.selected >= tab_layout.tabs.length
74
74
  ) {
75
75
  tab_layout.selected--;
76
76
  }
@@ -58,7 +58,7 @@ export interface SplitLayout {
58
58
  */
59
59
  export interface TabLayout {
60
60
  type: "child-panel";
61
- child: string[];
61
+ tabs: string[];
62
62
  selected?: number;
63
63
  }
64
64
 
@@ -75,12 +75,8 @@ export interface LayoutDivider {
75
75
 
76
76
  /**
77
77
  * Represents a panel location result from hit detection.
78
- *
79
- * Contains both the panel identifier and its grid position in relative units.
80
- * The generic parameter `T` allows DOM-only properties (e.g. `DOMRect`) to be
81
- * shared in this cross-platform module.
82
78
  */
83
- export interface LayoutPath<T = undefined> {
79
+ export interface LayoutPath {
84
80
  type: "layout-path";
85
81
  slot: string;
86
82
  path: number[];
@@ -91,7 +87,7 @@ export interface LayoutPath<T = undefined> {
91
87
  row_offset: number;
92
88
  orientation: Orientation;
93
89
  is_edge: boolean;
94
- layout: T;
90
+ layout: Layout;
95
91
  }
96
92
 
97
93
  /**