regular-layout 0.5.0 → 0.6.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.
@@ -130,6 +130,7 @@ export class RegularLayout extends HTMLElement {
130
130
  private _presizeQueue: PresizeQueue;
131
131
  private _overlayController: OverlayController;
132
132
  private _maximized?: string;
133
+ private _resize_observer?: ResizeObserver;
133
134
 
134
135
  constructor() {
135
136
  super();
@@ -141,7 +142,13 @@ export class RegularLayout extends HTMLElement {
141
142
  this._cursor_stylesheet = new CSSStyleSheet();
142
143
  this._cursor_override = false;
143
144
  const event_name = `${this._physics.CUSTOM_EVENT_NAME_PREFIX}-before-resize`;
144
- this._presizeQueue = new PresizeQueue(this, event_name);
145
+ // Refresh the bounds cache once per layout transition, so consumers
146
+ // reading coordinates from a `before-resize` handler always see the
147
+ // element's current position - a `ResizeObserver` alone can't catch
148
+ // position-only moves of the host.
149
+ this._presizeQueue = new PresizeQueue(this, event_name, () => {
150
+ this._dimensions = undefined;
151
+ });
145
152
  this._overlayController = new OverlayController(this.create_overlay_host());
146
153
  this._shadowRoot.adoptedStyleSheets = [
147
154
  this._stylesheet,
@@ -150,6 +157,11 @@ export class RegularLayout extends HTMLElement {
150
157
  }
151
158
 
152
159
  connectedCallback() {
160
+ this._resize_observer ??= new ResizeObserver(() => {
161
+ this._dimensions = undefined;
162
+ });
163
+
164
+ this._resize_observer.observe(this);
153
165
  this.addEventListener("dblclick", this.onDblClick);
154
166
  this.addEventListener("pointerdown", this.onPointerDown);
155
167
  this.addEventListener("pointerup", this.onPointerUp);
@@ -157,6 +169,7 @@ export class RegularLayout extends HTMLElement {
157
169
  }
158
170
 
159
171
  disconnectedCallback() {
172
+ this._resize_observer?.disconnect();
160
173
  this.removeEventListener("dblclick", this.onDblClick);
161
174
  this.removeEventListener("pointerdown", this.onPointerDown);
162
175
  this.removeEventListener("pointerup", this.onPointerUp);
@@ -334,34 +347,54 @@ export class RegularLayout extends HTMLElement {
334
347
  * {@link save}, and any subsequent {@link restore} resets the layout to the
335
348
  * minimized (normal, multi-panel) view.
336
349
  *
350
+ * Before applying, dispatches a cancelable `regular-layout-before-resize`
351
+ * event (as {@link restore} does) whose paths describe the post-maximize
352
+ * geometry - a single full-window entry for `name`. If the event is
353
+ * cancelled via `preventDefault()`, the update is suspended until
354
+ * {@link resumeResize} is called.
355
+ *
337
356
  * Has no effect if `name` is not present in the current layout.
338
357
  *
339
358
  * @param name - The name of the panel to maximize.
340
359
  */
341
- maximize = (name: string) => {
360
+ maximize = async (name: string) => {
342
361
  if (!this.getPanel(name)) {
343
362
  return;
344
363
  }
345
364
 
346
- this._maximized = name;
347
- this._stylesheet.replaceSync(
348
- create_css_maximize_layout(name, this._physics),
349
- );
365
+ // The post-maximize geometry as a `Layout`: `name` alone, full-window.
366
+ // Panels hidden by the maximize are absent from the presize paths,
367
+ // consistent with `calculate_presize_paths`' visible-panels-only
368
+ // semantics.
369
+ const layout: Layout = { type: "tab-layout", tabs: [name], selected: 0 };
370
+ await this._presizeQueue.run(layout, () => {
371
+ this._maximized = name;
372
+ this._stylesheet.replaceSync(
373
+ create_css_maximize_layout(name, this._physics),
374
+ );
375
+ });
350
376
  };
351
377
 
352
378
  /**
353
379
  * Restores the normal multi-panel view after a {@link maximize}, without
354
380
  * altering the layout tree. No-op if no panel is currently maximized.
381
+ *
382
+ * Before applying, dispatches a cancelable `regular-layout-before-resize`
383
+ * event (as {@link restore} does) with paths for the restored multi-panel
384
+ * geometry. If the event is cancelled via `preventDefault()`, the update
385
+ * is suspended until {@link resumeResize} is called.
355
386
  */
356
- minimize = () => {
387
+ minimize = async () => {
357
388
  if (this._maximized === undefined) {
358
389
  return;
359
390
  }
360
391
 
361
- this._maximized = undefined;
362
- this._stylesheet.replaceSync(
363
- create_css_grid_layout(this._panel, undefined, this._physics),
364
- );
392
+ await this._presizeQueue.run(this._panel, () => {
393
+ this._maximized = undefined;
394
+ this._stylesheet.replaceSync(
395
+ create_css_grid_layout(this._panel, undefined, this._physics),
396
+ );
397
+ });
365
398
  };
366
399
 
367
400
  /**
@@ -371,6 +404,7 @@ export class RegularLayout extends HTMLElement {
371
404
  * @param layout - The layout tree to restore
372
405
  */
373
406
  restoreSync = (layout: Layout, _is_flattened: boolean = false) => {
407
+ this._dimensions = undefined;
374
408
  this._maximized = undefined;
375
409
  this._panel = !_is_flattened ? flatten(layout) : layout;
376
410
  const css = create_css_grid_layout(this._panel, undefined, this._physics);
@@ -23,12 +23,15 @@ regular-layout.borland regular-layout-frame {
23
23
  position: relative;
24
24
  box-sizing: border-box;
25
25
  margin: 4px;
26
- background: #0000aa;
27
- border: 1px solid #00aaaa;
28
- box-shadow: 1px 1px 0 #000000;
29
26
  }
30
27
 
28
+ /* Panel chrome lives on the content (only the selected frame shows it), so the
29
+ overlapping frame box stays transparent and every stacked tab is visible. */
31
30
  regular-layout.borland regular-layout-frame::part(container) {
31
+ background: #0000aa;
32
+ border: 1px solid #00aaaa;
33
+ box-shadow: 1px 1px 0 #000000;
34
+ box-sizing: border-box;
32
35
  padding: 4px 6px;
33
36
  color: #ffff55;
34
37
  }
@@ -59,7 +62,6 @@ regular-layout.borland regular-layout-frame::part(titlebar) {
59
62
  align-items: stretch;
60
63
  padding-right: 0;
61
64
  height: 22px;
62
- background: #0000aa;
63
65
  }
64
66
 
65
67
  regular-layout.borland regular-layout-frame::part(tab) {
@@ -23,13 +23,16 @@ regular-layout.chicago regular-layout-frame {
23
23
  position: relative;
24
24
  box-sizing: border-box;
25
25
  margin: 12px;
26
+ }
27
+
28
+ /* Panel chrome lives on the content (only the selected frame shows it), so the
29
+ overlapping frame box stays transparent and every stacked tab is visible. */
30
+ regular-layout.chicago regular-layout-frame::part(container) {
26
31
  background: #c0c0c0;
27
32
  border-width: 2px;
28
33
  border-color: #ffffff #808080 #808080 #ffffff;
29
34
  border-style: solid;
30
- }
31
-
32
- regular-layout.chicago regular-layout-frame::part(container) {
35
+ box-sizing: border-box;
33
36
  padding: 6px;
34
37
  }
35
38
 
@@ -58,8 +61,8 @@ regular-layout.chicago regular-layout-frame::part(titlebar) {
58
61
  }
59
62
 
60
63
  regular-layout.chicago regular-layout-frame::part(tab) {
64
+ box-sizing: border-box;
61
65
  display: flex;
62
- flex: 1 1 150px;
63
66
  align-items: center;
64
67
  padding: 0 3px 0 8px;
65
68
  cursor: pointer;
@@ -69,6 +72,11 @@ regular-layout.chicago regular-layout-frame::part(tab) {
69
72
  font-family: "Tahoma", "Arial", sans-serif;
70
73
  font-weight: bold;
71
74
  font-size: 11px;
75
+ /* Raised bevel - the frame box no longer carries the border in the
76
+ overlap model, so each tab frames itself. */
77
+ border-width: 2px;
78
+ border-color: #ffffff #808080 #808080 #ffffff;
79
+ border-style: solid;
72
80
  }
73
81
 
74
82
  regular-layout.chicago regular-layout-frame::part(active-tab) {
@@ -21,13 +21,16 @@ regular-layout.fluxbox regular-layout-frame {
21
21
  position: relative;
22
22
  box-sizing: border-box;
23
23
  margin: 8px;
24
- background: #ffffff;
25
- border: 1px solid #9dacbe;
26
- box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.15);
27
24
  }
28
25
 
26
+ /* Panel chrome lives on the content (only the selected frame shows it), so the
27
+ overlapping frame box stays transparent and every stacked tab is visible. */
29
28
  regular-layout.fluxbox regular-layout-frame::part(container) {
29
+ box-sizing: border-box;
30
30
  padding: 6px;
31
+ background: #ffffff;
32
+ border: 1px solid #9dacbe;
33
+ box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.15);
31
34
  }
32
35
 
33
36
  regular-layout.fluxbox regular-layout-frame::part(close) {
package/themes/gibson.css CHANGED
@@ -20,12 +20,9 @@ regular-layout.gibson {
20
20
 
21
21
  /* Frame */
22
22
  regular-layout.gibson regular-layout-frame {
23
- --titlebar-height: 28px;
24
23
  position: relative;
25
24
  box-sizing: border-box;
26
25
  margin: 8px;
27
- background: rgba(10, 10, 26, 0.85);
28
- backdrop-filter: blur(4px);
29
26
  color: white;
30
27
  text-shadow:
31
28
  0 0 5px #fff,
@@ -33,8 +30,13 @@ regular-layout.gibson regular-layout-frame {
33
30
  0 0 20px #fff;
34
31
  }
35
32
 
33
+ /* Panel chrome lives on the content (only the selected frame shows it), so the
34
+ overlapping frame box stays transparent and every stacked tab is visible. */
36
35
  regular-layout.gibson regular-layout-frame::part(container) {
37
36
  padding: 6px;
37
+ background: rgba(10, 10, 26, 0.85);
38
+ backdrop-filter: blur(4px);
39
+ box-sizing: border-box;
38
40
  }
39
41
 
40
42
  regular-layout.gibson regular-layout-frame::part(active-close) {
@@ -70,19 +72,11 @@ regular-layout.gibson regular-layout-frame::part(close) {
70
72
  }
71
73
 
72
74
  regular-layout.gibson regular-layout-frame::part(titlebar) {
73
- display: flex;
74
- justify-content: flex-end;
75
- align-items: stretch;
76
- padding-left: 12px;
77
75
  height: 32px;
78
-
79
- /* border-bottom: 1px solid rgba(0, 255, 255, 0.3); */
80
76
  }
81
77
 
82
78
  regular-layout.gibson regular-layout-frame::part(tab) {
83
79
  display: flex;
84
- flex: 1 1 150px;
85
- max-width: 200px;
86
80
  align-items: center;
87
81
  padding: 0 5px 0 12px;
88
82
  cursor: pointer;
@@ -131,6 +125,7 @@ regular-layout.gibson regular-layout-frame.overlay {
131
125
  inset 0 0 20px rgba(255, 0, 255, 0.2);
132
126
  margin: 0;
133
127
  transition:
128
+ margin 0.075s ease-out,
134
129
  top 0.075s ease-out,
135
130
  height 0.075s ease-out,
136
131
  width 0.075s ease-out,
@@ -138,18 +133,9 @@ regular-layout.gibson regular-layout-frame.overlay {
138
133
  }
139
134
 
140
135
  regular-layout.gibson regular-layout-frame::part(container) {
141
- display: none;
142
136
  border: 1px solid #00ffff;
143
- border-radius: 12px 0 12px 0;
144
- }
145
-
146
- regular-layout.gibson regular-layout-frame::part(titlebar) {
147
- display: none;
148
- }
149
-
150
- regular-layout.gibson regular-layout-frame:not(.overlay)::part(container),
151
- regular-layout.gibson regular-layout-frame:not(.overlay)::part(titlebar) {
152
- display: flex;
137
+ /* Square top so the tab strip sits flush; keep the asymmetric bottom. */
138
+ border-radius: 0 0 12px 0;
153
139
  }
154
140
 
155
141
  /* Cyberpunk color variations */
package/themes/hotdog.css CHANGED
@@ -21,13 +21,16 @@ regular-layout.hotdog {
21
21
  /* Frame */
22
22
  regular-layout.hotdog regular-layout-frame {
23
23
  margin: 12px;
24
+ }
25
+
26
+ /* Panel chrome lives on the content (only the selected frame shows it), so the
27
+ overlapping frame box stays transparent and every stacked tab is visible. */
28
+ regular-layout.hotdog regular-layout-frame::part(container) {
24
29
  background: #ffff00;
25
30
  border-width: 2px;
26
31
  border-color: #ff6b6b #8b0000 #8b0000 #ff6b6b;
27
32
  border-style: solid;
28
- }
29
-
30
- regular-layout.hotdog regular-layout-frame::part(container) {
33
+ box-sizing: border-box;
31
34
  padding: 6px;
32
35
  }
33
36
 
@@ -57,8 +60,8 @@ regular-layout.hotdog regular-layout-frame::part(titlebar) {
57
60
  }
58
61
 
59
62
  regular-layout.hotdog regular-layout-frame::part(tab) {
63
+ box-sizing: border-box;
60
64
  display: flex;
61
- flex: 1 1 150px;
62
65
  align-items: center;
63
66
  padding: 0 3px 0 8px;
64
67
  cursor: pointer;
@@ -68,6 +71,11 @@ regular-layout.hotdog regular-layout-frame::part(tab) {
68
71
  font-family: "Tahoma", "Arial", sans-serif;
69
72
  font-weight: bold;
70
73
  font-size: 11px;
74
+ /* Raised bevel - the frame box no longer carries the border in the
75
+ overlap model, so each tab frames itself. */
76
+ border-width: 2px;
77
+ border-color: #ff6b6b #8b0000 #8b0000 #ff6b6b;
78
+ border-style: solid;
71
79
  }
72
80
 
73
81
  regular-layout.hotdog regular-layout-frame::part(active-tab) {
@@ -87,6 +95,7 @@ regular-layout.hotdog:has(.overlay) > .overlay {
87
95
  regular-layout.hotdog regular-layout-frame.overlay {
88
96
  margin: 0;
89
97
  transition:
98
+ margin 0.1 ease-in-out,
90
99
  top 0.1s ease-in-out,
91
100
  height 0.1s ease-in-out,
92
101
  width 0.1s ease-in-out,
package/themes/lorax.css CHANGED
@@ -10,50 +10,62 @@
10
10
  * ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
11
11
  */
12
12
 
13
+ /*
14
+ * In the own-tab model, the frames of a stack overlap in one cell: each frame
15
+ * renders only its own tab (the engine tiles them into the shared titlebar) and
16
+ * only the selected frame shows its content. So this theme styles appearance,
17
+ * not layout - panel chrome lives on `::part(container)` (shown only for the
18
+ * selected frame) rather than the overlapping frame box, and the titlebar strip
19
+ * is transparent so every stacked frame's tab shows through.
20
+ */
21
+
13
22
  regular-layout.lorax {
14
23
  font-family:
15
24
  "ui-monospace", "SFMono-Regular", "SF Mono", "Menlo", "Consolas",
16
25
  "Liberation Mono", monospace;
17
26
  }
18
27
 
19
- /* Frame */
20
28
  regular-layout.lorax regular-layout-frame {
21
- margin: 3px;
22
- margin-top: 27px;
23
- border-radius: 0 6px 6px 6px;
24
- border: 1px solid #666;
25
- box-shadow: 0px 6px 6px -4px rgba(150, 150, 180);
29
+ --rl-tab-width: 200px;
26
30
  }
27
31
 
32
+ /* Panel content chrome (only the selected frame's container is rendered). */
28
33
  regular-layout.lorax regular-layout-frame::part(container) {
34
+ box-sizing: border-box;
35
+ margin: 0 3px 3px 3px;
29
36
  padding: 6px;
37
+ /* Square top so the tab strip sits flush; rounded bottom. */
38
+ border-radius: 0 6px 6px 6px;
39
+ border: 1px solid #666;
40
+ box-shadow: 0px 6px 6px -4px rgba(150, 150, 180);
30
41
  }
31
42
 
43
+ /* Transparent strip; the engine tiles the per-frame tabs across it. */
32
44
  regular-layout.lorax regular-layout-frame::part(titlebar) {
33
- display: flex;
34
- align-items: stretch;
35
- margin-left: -1px;
36
- margin-right: -1px;
37
- margin-bottom: 0px;
38
- margin-top: -24px;
39
- padding-right: 6px;
45
+ margin: 3px 6px 0 3px;
46
+ align-items: end;
40
47
  }
41
48
 
42
49
  regular-layout.lorax regular-layout-frame::part(tab) {
43
- display: flex;
44
- flex: 1 1 150px;
50
+ box-sizing: border-box;
45
51
  align-items: center;
46
- text-align: center;
52
+ justify-content: center;
47
53
  font-size: 10px;
48
54
  padding: 0 6px;
55
+ margin-right: 2px;
49
56
  cursor: pointer;
50
- max-width: 150px;
51
- text-overflow: ellipsis;
52
57
  border: 1px solid #666;
58
+ border-bottom: none;
53
59
  border-radius: 6px 6px 0 0;
54
60
  opacity: 0.5;
55
61
  }
56
62
 
63
+ regular-layout.lorax regular-layout-frame::part(title) {
64
+ overflow: hidden;
65
+ text-overflow: ellipsis;
66
+ white-space: nowrap;
67
+ }
68
+
57
69
  regular-layout.lorax regular-layout-frame::part(active-tab) {
58
70
  opacity: 1;
59
71
  }
@@ -71,67 +83,52 @@ regular-layout.lorax regular-layout-frame::part(close):hover {
71
83
  background-color: rgba(255, 0, 0, 0.2);
72
84
  }
73
85
 
74
- /* Frame in Overlay Mode */
75
86
  regular-layout.lorax regular-layout-frame.overlay {
76
- background-color: rgba(0, 0, 0, 0.2);
77
- border: 1px dashed rgb(0, 0, 0);
78
- border-radius: 6px;
79
- margin: 3px;
80
- box-shadow: none;
81
87
  transition:
88
+ maring 0.1s ease-in-out,
82
89
  top 0.1s ease-in-out,
83
90
  height 0.1s ease-in-out,
84
91
  width 0.1s ease-in-out,
85
92
  left 0.1s ease-in-out;
86
93
  }
87
94
 
88
- regular-layout.lorax regular-layout-frame::part(container),
89
- regular-layout.lorax regular-layout-frame::part(titlebar) {
90
- display: none;
91
- }
92
-
93
- regular-layout.lorax regular-layout-frame:not(.overlay)::part(container),
94
- regular-layout.lorax regular-layout-frame:not(.overlay)::part(titlebar) {
95
- display: flex;
96
- }
97
-
98
- /* Colors */
99
- regular-layout.lorax :nth-child(8n + 1),
95
+ /* Colors (per panel position) - the content area and its tab share a hue. */
96
+ regular-layout.lorax :nth-child(8n + 1)::part(container),
100
97
  regular-layout.lorax :nth-child(8n + 1)::part(tab) {
101
98
  background-color: #ffadadff;
102
99
  }
103
100
 
104
- regular-layout.lorax :nth-child(8n + 2),
101
+ regular-layout.lorax :nth-child(8n + 2)::part(container),
105
102
  regular-layout.lorax :nth-child(8n + 2)::part(tab) {
106
103
  background-color: #ffd6a5ff;
107
104
  }
108
105
 
109
- regular-layout.lorax :nth-child(8n + 3),
106
+ regular-layout.lorax :nth-child(8n + 3)::part(container),
110
107
  regular-layout.lorax :nth-child(8n + 3)::part(tab) {
111
108
  background-color: #fdffb6ff;
112
109
  }
113
110
 
114
- regular-layout.lorax :nth-child(8n + 4),
111
+ regular-layout.lorax :nth-child(8n + 4)::part(container),
115
112
  regular-layout.lorax :nth-child(8n + 4)::part(tab) {
116
113
  background-color: #caffbfff;
117
114
  }
118
115
 
119
- regular-layout.lorax :nth-child(8n + 5),
116
+ regular-layout.lorax :nth-child(8n + 5)::part(container),
120
117
  regular-layout.lorax :nth-child(8n + 5)::part(tab) {
121
118
  background-color: #9bf6ffff;
122
119
  }
123
120
 
124
- regular-layout.lorax :nth-child(8n + 6),
121
+ regular-layout.lorax :nth-child(8n + 6)::part(container),
125
122
  regular-layout.lorax :nth-child(8n + 6)::part(tab) {
126
123
  background-color: #a0c4ffff;
127
124
  }
128
125
 
129
- regular-layout.lorax :nth-child(8n + 7),
126
+ regular-layout.lorax :nth-child(8n + 7)::part(container),
130
127
  regular-layout.lorax :nth-child(8n + 7)::part(tab) {
131
128
  background-color: #bdb2ffff;
132
129
  }
133
130
 
134
- regular-layout.lorax :nth-child(8n + 8),
131
+ regular-layout.lorax :nth-child(8n + 8)::part(container),
135
132
  regular-layout.lorax :nth-child(8n + 8)::part(tab) {
136
133
  background-color: #ffc6ffff;
137
134
  }