staffa 0.12.0 → 0.13.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/README.md +7 -5
- package/dist/components/main.d.ts +25 -0
- package/dist/components/main.js +60 -26
- package/dist/components/panels.d.ts +75 -21
- package/dist/components/panels.js +102 -77
- package/dist/staffa.esm.js +1 -1
- package/package.json +3 -3
- package/skill/MainOptions.md +29 -0
- package/skill/Panel.md +41 -5
- package/skill/PanelStack.md +5 -0
- package/skill/SKILL.md +7 -5
- package/src/components/main.ts +86 -28
- package/src/components/panels.ts +148 -82
package/README.md
CHANGED
|
@@ -180,17 +180,19 @@ Navigations settle asynchronously (closes travel through the browser's history),
|
|
|
180
180
|
|
|
181
181
|
Navigating faster than the shell can settle is fine: closing travels through the browser's history, so it takes a moment to land, and anything asked for in the meantime waits for it rather than being dropped. Two quick Escapes (or back gestures) peel two panels, each aimed at the stack the one before it was heading for.
|
|
182
182
|
|
|
183
|
-
**Every panel must work at 360–540px**, because that is what it gets whenever two columns fit. `$panel.maxWidth` says how much *more* it can usefully take. The content area is
|
|
183
|
+
**Every panel must work at 360–540px**, because that is what it gets whenever two columns fit. `$panel.maxWidth` says how much *more* it can usefully take. The content area is what `S.main()`'s `fullWidth` says it is — 1080px by default:
|
|
184
184
|
|
|
185
185
|
| `maxWidth` | How wide the panel gets | Good for |
|
|
186
186
|
| --- | --- | --- |
|
|
187
187
|
| `"half"` | Half the content area: 360 to 540px. | lists, detail forms — anything that reads well at phone width |
|
|
188
|
-
| `"full"` (default) | The whole content area: up to
|
|
189
|
-
| `"screen"` | The whole window, no upper limit: ~
|
|
188
|
+
| `"full"` (default) | The whole content area: up to 1080px. | ordinary screens; the safe default |
|
|
189
|
+
| `"screen"` | The whole window, no upper limit: ~1720px on a 1920px screen. | boards, wide tables, dense dashboards |
|
|
190
190
|
|
|
191
|
-
Below the width two columns need, everything takes the whole content area whatever it asked for.
|
|
191
|
+
Below the width two columns need, everything takes the whole content area whatever it asked for. Nothing fits beside a `"full"` on a standard page, but on a wide enough window a `"half"` still can, and the page grows to hold both.
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
The standard page is those 1080px plus the nav sidebar's 200 — the 1280px an app is usually seen at, though neither figure is fixed: `S.main({ navWidth, fullWidth })` sets both, and everything above follows from them.
|
|
194
|
+
|
|
195
|
+
A column's width depends only on the size of the window, never on what else is open. So opening or closing a panel never resizes the ones already on screen, and never reflows what someone was reading. A lone `"half"` leaves its other half empty, and that is exactly where the next one lands. When more columns fit than the standard page holds (three halves, say), the page itself grows, staying centred, to hold them — though the top bar and footer keep to the standard width, so the chrome holds still while the columns come and go.
|
|
194
196
|
|
|
195
197
|
Columns tile that area, separated by a hairline and no gutter — a column brings its own padding, so their contents stay comfortably apart regardless.
|
|
196
198
|
|
|
@@ -217,6 +217,20 @@ export interface MainOptions<R = Routes> {
|
|
|
217
217
|
* themselves up with them.
|
|
218
218
|
*/
|
|
219
219
|
maxWidth?: string;
|
|
220
|
+
/**
|
|
221
|
+
* How wide a `"full"` panel gets, in pixels — and with it the whole content
|
|
222
|
+
* area, since a `"full"` fills it exactly. A `"half"` gets half of this, and
|
|
223
|
+
* a `"screen"` ignores it and takes the window. Defaults to 1080; the window
|
|
224
|
+
* caps it when there is less room than that. Routed mode only.
|
|
225
|
+
*
|
|
226
|
+
* This plus {@link MainOptions.navWidth} is the app's standard page — see
|
|
227
|
+
* there.
|
|
228
|
+
*
|
|
229
|
+
* Live, like {@link MainOptions.columns}: pass a proxied options object (or
|
|
230
|
+
* make this field a getter) and a change is adopted in one layout pass,
|
|
231
|
+
* every panel keeping its state.
|
|
232
|
+
*/
|
|
233
|
+
fullWidth?: number;
|
|
220
234
|
/** Aberdeen attr/style string applied to the content area. */
|
|
221
235
|
contentAttrs?: Attributes;
|
|
222
236
|
/** Aberdeen attr/style string applied to the top bar. */
|
|
@@ -243,6 +257,17 @@ export interface MainOptions<R = Routes> {
|
|
|
243
257
|
* chrome goes assumes they are one.
|
|
244
258
|
*/
|
|
245
259
|
navPosition?: "left" | "right";
|
|
260
|
+
/**
|
|
261
|
+
* How wide the nav sidebar column is, in pixels — its hairline included.
|
|
262
|
+
* Defaults to 200.
|
|
263
|
+
*
|
|
264
|
+
* Together with {@link MainOptions.fullWidth} this is the app's *standard
|
|
265
|
+
* page*: the width the top bar and footer keep to, and the width the
|
|
266
|
+
* columns settle back to. The defaults come to the familiar 1280px.
|
|
267
|
+
*
|
|
268
|
+
* Live, like {@link MainOptions.fullWidth}.
|
|
269
|
+
*/
|
|
270
|
+
navWidth?: number;
|
|
246
271
|
/** Aberdeen attr/style string applied to the sidebar nav panel. */
|
|
247
272
|
navAttrs?: Attributes;
|
|
248
273
|
/** Aberdeen attr/style string applied to the narrow-screen full-page nav. */
|
package/dist/components/main.js
CHANGED
|
@@ -9,6 +9,15 @@ import { menu as menuIcon, x as closeIcon } from "../icons.js";
|
|
|
9
9
|
import { iconButton } from "./button.js";
|
|
10
10
|
import { isDialogOpen } from "./dialog.js";
|
|
11
11
|
import { PanelStackController } from "./panels.js";
|
|
12
|
+
/**
|
|
13
|
+
* The default nav column (hairline included) and the default width of a
|
|
14
|
+
* `"full"` panel — see {@link MainOptions.navWidth} and
|
|
15
|
+
* {@link MainOptions.fullWidth}. Side by side they come to the 1280px page the
|
|
16
|
+
* shell is usually seen as, but that figure lives nowhere: the browser adds
|
|
17
|
+
* these two up, and an app that changes either simply gets a different page.
|
|
18
|
+
*/
|
|
19
|
+
const NAV_W = 200;
|
|
20
|
+
const FULL_W = 1080;
|
|
12
21
|
A.insertGlobalCss({
|
|
13
22
|
".s-main": {
|
|
14
23
|
// container-type so @container queries below can respond to shell width.
|
|
@@ -26,8 +35,10 @@ A.insertGlobalCss({
|
|
|
26
35
|
// The bar reads `[leading] [title] …spacer… [trailing]`. The spacer is the
|
|
27
36
|
// trailing slot's own growth: it takes the free space and right-aligns
|
|
28
37
|
// itself in it, which is what lets a search box live there. When the two
|
|
29
|
-
// compete, the
|
|
30
|
-
//
|
|
38
|
+
// compete, the titles give way first: the trailing slot's near-zero
|
|
39
|
+
// shrink factor keeps a row of actions at its natural width while the
|
|
40
|
+
// crumbs absorb the squeeze — but only down to the titles' floor, past
|
|
41
|
+
// which the trailing slot shrinks after all: a wide search box must not
|
|
31
42
|
// starve the titles to nothing (the crumb strip's overlay buttons would
|
|
32
43
|
// escape their zero-width strip, over the ☰ beside it).
|
|
33
44
|
"> header > .s-bar, > footer > .s-bar": "display:flex align-items:center width:100% margin-inline:auto gap:$3 padding: $2 $3;",
|
|
@@ -48,13 +59,16 @@ A.insertGlobalCss({
|
|
|
48
59
|
// which their classes then provide. (`filter:none` keeps the global
|
|
49
60
|
// `a:hover` brighten off the gradient text.)
|
|
50
61
|
"> header a.s-logo, > header a.s-title": "text-decoration:none filter:none cursor:pointer",
|
|
51
|
-
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 1 auto; min-width:0",
|
|
62
|
+
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 0.1 auto; min-width:0",
|
|
52
63
|
// Body always wraps <main> (with or without a sidebar) so max-width centering
|
|
53
64
|
// and scrollbar alignment work identically in both cases.
|
|
54
65
|
// .s-body centres .s-body-inner; .s-body-inner caps the content to maxWidth.
|
|
55
66
|
// It's also the positioning + clipping context for the narrow-screen nav panel,
|
|
56
|
-
// which slides in and out across its left edge.
|
|
57
|
-
|
|
67
|
+
// which slides in and out across its left edge. `overflow:clip` rather than
|
|
68
|
+
// `hidden` for the same reason as `.s-panels`: a hidden box can still be
|
|
69
|
+
// scrolled (find-in-page, an anchor, an extension), and a stray scroll here
|
|
70
|
+
// would shove the whole row — sidebar and columns — out of place for good.
|
|
71
|
+
".s-body": "flex:1 overflow:clip display:flex flex-direction:row min-height:0 justify-content:center position:relative",
|
|
58
72
|
".s-body-inner": "flex:1 min-width:0 display:flex flex-direction:row min-height:0",
|
|
59
73
|
// Put the sidebar on the right (content fills the left) for right-hand navs.
|
|
60
74
|
"&.s-nav-right .s-body-inner": "flex-direction:row-reverse",
|
|
@@ -84,21 +98,25 @@ A.insertGlobalCss({
|
|
|
84
98
|
".s-body main.s-scroll-y": "margin-right:$3",
|
|
85
99
|
// Routed mode takes its width from the stack instead of from
|
|
86
100
|
// `maxWidth`: the layout engine publishes the ensemble width (sidebar +
|
|
87
|
-
// separator + content area) as --s-shell-w — the standard
|
|
88
|
-
// normally, the
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// the
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
// separator + content area) as --s-shell-w — the standard page
|
|
102
|
+
// normally, wider while the columns outgrow it (a "screen" page, or
|
|
103
|
+
// extra columns fitting a wide window) — and the body row caps itself
|
|
104
|
+
// to it, staying centred around the columns. Changing the custom
|
|
105
|
+
// property animates the max-width consuming it, with no JS in the loop:
|
|
106
|
+
// the body recentres in step with the panel whose arrival or departure
|
|
107
|
+
// moved it, over the same --s-panel-ms (see panels.ts). During a window
|
|
108
|
+
// resize (and the very first pass) the layout engine raises
|
|
109
|
+
// `.s-shell-snap` so the new width is adopted instantly instead of
|
|
110
|
+
// chasing the window through a transition.
|
|
111
|
+
"&.s-routed > .s-body > .s-body-inner": "max-width: var(--s-shell-w, 100%); transition: max-width var(--s-panel-ms) ease;",
|
|
112
|
+
"&.s-routed.s-shell-snap > .s-body > .s-body-inner": "transition:none",
|
|
113
|
+
// The bars don't follow the ensemble past the standard page: a header
|
|
114
|
+
// stretching to the window's edges and back with every "screen" panel
|
|
115
|
+
// reads as the whole app flexing, so the chrome holds still and only
|
|
116
|
+
// the columns grow. (Below the standard width the ensemble is simply
|
|
117
|
+
// the window, which only a resize changes — so the bars never animate,
|
|
118
|
+
// and take no part in the transition above.)
|
|
119
|
+
"&.s-routed > header > .s-bar, &.s-routed > footer > .s-bar": "max-width: calc(var(--s-nav-w) + var(--s-full-w))",
|
|
102
120
|
},
|
|
103
121
|
// Sidebar nav panel. Items reuse the shared `.s-menu-item` /
|
|
104
122
|
// `.s-menu-sep` styles from menu.ts, so the sidebar and the floating
|
|
@@ -109,7 +127,10 @@ A.insertGlobalCss({
|
|
|
109
127
|
// The generous horizontal padding is what keeps the rows clear of the content
|
|
110
128
|
// separator on one side and the shell edge on the other; the vertical scroll
|
|
111
129
|
// (overflow-y:auto, which also clips overflow-x) leaves no room to bleed past it.
|
|
112
|
-
|
|
130
|
+
// `--s-nav-w` measures the whole column, hairline included, so the panel
|
|
131
|
+
// itself gives that 1px back — and the app's two widths then add up to
|
|
132
|
+
// exactly the page the bars above and below keep to.
|
|
133
|
+
"&": "display:flex flex-direction:column overflow-y:auto flex-shrink:0 width: calc(var(--s-nav-w) - 1px); padding:$3 gap:$1",
|
|
113
134
|
},
|
|
114
135
|
// The narrow-screen nav: a full "panel" that slides in over the content from the
|
|
115
136
|
// left, rather than a dropdown — on a phone a nav is a screenful of UI, not a
|
|
@@ -187,6 +208,9 @@ export function main(opts = {}) {
|
|
|
187
208
|
notFound: opts.notFound,
|
|
188
209
|
ancestors: opts.ancestors,
|
|
189
210
|
title: opts.title,
|
|
211
|
+
// Corrected below, and on every change, from the app's own option:
|
|
212
|
+
// read here it would subscribe the whole shell to it.
|
|
213
|
+
fullWidth: FULL_W,
|
|
190
214
|
$shell,
|
|
191
215
|
})
|
|
192
216
|
: null;
|
|
@@ -198,6 +222,7 @@ export function main(opts = {}) {
|
|
|
198
222
|
// the new link default. Nothing else of the shell is touched.
|
|
199
223
|
A(() => ctl.setColumns(opts.columns));
|
|
200
224
|
A(() => ctl.setLinkNavigation(opts.linkNavigation));
|
|
225
|
+
A(() => ctl.setFullWidth(opts.fullWidth ?? FULL_W));
|
|
201
226
|
}
|
|
202
227
|
// Where the brand mark and the app's name link — or nowhere, when the app
|
|
203
228
|
// said `home: null` (a title slot holding a control of its own, say).
|
|
@@ -206,13 +231,22 @@ export function main(opts = {}) {
|
|
|
206
231
|
// rather than to `maxWidth`.
|
|
207
232
|
const capWidth = ctl ? null : opts.maxWidth;
|
|
208
233
|
const root = A(`div.s-main${ctl ? ".s-routed" : ""}`, opts.attrs, () => {
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
234
|
+
// The two widths the CSS above works from, and with them the standard page
|
|
235
|
+
// the bars keep to. Each sits in a scope of its own — one that draws
|
|
236
|
+
// nothing, so re-running it is a single style write: an app that changes
|
|
237
|
+
// either on a proxied options object resizes the shell in place, panels
|
|
238
|
+
// and their state untouched.
|
|
239
|
+
A(() => A(`--s-full-w: ${opts.fullWidth ?? FULL_W}px`));
|
|
240
|
+
// `--s-nav-w` is the sidebar's whole column, and nothing at all when there
|
|
241
|
+
// is no sidebar to give it to — a shell without one lines its bars up with
|
|
242
|
+
// the content. This scope also tags the shell with the side the sidebar is
|
|
243
|
+
// on, for the CSS above to hang off (see `nav` above: reading `nav.items`
|
|
244
|
+
// here subscribes this scope alone, never the shell entire).
|
|
212
245
|
A(() => {
|
|
213
246
|
if (nav == null || !nav.items.length)
|
|
214
|
-
|
|
215
|
-
|
|
247
|
+
A("--s-nav-w: 0px");
|
|
248
|
+
else
|
|
249
|
+
A(`.s-nav-${navPos}`, `--s-nav-w: ${opts.navWidth ?? NAV_W}px`);
|
|
216
250
|
});
|
|
217
251
|
// Top bar: `[leading] [identity] …spacer… [trailing]`, where each slot's
|
|
218
252
|
// contents depend on how much room the shell has and — in routed mode — on
|
|
@@ -157,17 +157,25 @@ export interface Panel<P = Record<string, string | number | string[]>> {
|
|
|
157
157
|
* because that is what it gets when two columns fit; this says how much
|
|
158
158
|
* *more* it can take.
|
|
159
159
|
*
|
|
160
|
-
* - `"half"` — nothing more. Half the content area (
|
|
161
|
-
* column fits beside it. For
|
|
162
|
-
*
|
|
160
|
+
* - `"half"` — nothing more. Half the content area (360px up to half of
|
|
161
|
+
* {@link MainOptions.fullWidth}), so a second column fits beside it. For
|
|
162
|
+
* lists and detail forms.
|
|
163
|
+
* - `"full"` (the default) — the whole content area, which is exactly
|
|
164
|
+
* {@link MainOptions.fullWidth}: 1080px unless the app says otherwise.
|
|
163
165
|
* - `"screen"` — the whole window, unbounded: boards, wide tables, dense
|
|
164
|
-
* dashboards. While one is open the
|
|
165
|
-
*
|
|
166
|
+
* dashboards. While one is open the columns stretch to the screen edges
|
|
167
|
+
* instead of stopping at the standard page; the top bar and footer hold
|
|
168
|
+
* the standard width throughout.
|
|
166
169
|
*
|
|
167
170
|
* Below the width two columns need, everything takes the content area
|
|
168
171
|
* whatever it asked for. Widths depend only on the window, never on what
|
|
169
172
|
* else is open, so opening or closing a panel never resizes another.
|
|
170
173
|
*
|
|
174
|
+
* This is a *layout regime*, not a width guarantee: handle whatever width
|
|
175
|
+
* the bucket yields, and ask only for what your content can actually use —
|
|
176
|
+
* a screen that would cap its own content narrower than its ask is holding
|
|
177
|
+
* room that would have let another column fit beside it.
|
|
178
|
+
*
|
|
171
179
|
* Set it at the top of your handler and the panel is already that wide when
|
|
172
180
|
* you draw (see {@link Panel.width}); set it later — when your data tells you
|
|
173
181
|
* — and the panel reflows without being redrawn, keeping its state, while
|
|
@@ -243,6 +251,31 @@ export interface Panel<P = Record<string, string | number | string[]>> {
|
|
|
243
251
|
* ```
|
|
244
252
|
*/
|
|
245
253
|
close(): Promise<boolean>;
|
|
254
|
+
/**
|
|
255
|
+
* Opens `href` exactly as a click on a link inside this panel does — the
|
|
256
|
+
* shell's own link handling runs through this very call, so the two can't
|
|
257
|
+
* drift apart. By default that is a push: the target opens on top of this
|
|
258
|
+
* panel, closing the panels after it first (pinned ones ride along
|
|
259
|
+
* beneath the new panel, unsaved ones park), and a path that is already
|
|
260
|
+
* open is returned to rather than opened twice. `how` plays the part of a
|
|
261
|
+
* link's `data-panel` attribute: `"replace"` puts the target in this
|
|
262
|
+
* panel's place, `"open"` leaves the panel behind and gives the target
|
|
263
|
+
* its own stack, and omitting it follows the shell's
|
|
264
|
+
* {@link MainOptions.linkNavigation}, like a link without the attribute.
|
|
265
|
+
*
|
|
266
|
+
* This is the one for navigation that can't be a link: a row's click
|
|
267
|
+
* handler, a keyboard shortcut acting on this screen. The stack's
|
|
268
|
+
* {@link PanelStack.pushPanel} builds on the *current* panel instead — a
|
|
269
|
+
* different panel exactly when the interaction happened in a column
|
|
270
|
+
* beside it, where it would pile the new panel on top of the open detail
|
|
271
|
+
* rather than pruning back to this one.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```ts
|
|
275
|
+
* A("div.row click=", () => void $panel.open(`/contacts/${id}`), ...);
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
open(href: string, how?: "push" | "replace" | "open"): Promise<boolean>;
|
|
246
279
|
}
|
|
247
280
|
/** Options the stack needs from its shell. */
|
|
248
281
|
export interface PanelStackOptions {
|
|
@@ -254,6 +287,8 @@ export interface PanelStackOptions {
|
|
|
254
287
|
columns?: "auto" | "single";
|
|
255
288
|
/** What a bare link does. See {@link MainOptions.linkNavigation}. */
|
|
256
289
|
linkNavigation?: "push" | "replace" | "open";
|
|
290
|
+
/** How wide a `"full"` panel gets, in px. See {@link MainOptions.fullWidth}. */
|
|
291
|
+
fullWidth: number;
|
|
257
292
|
/** The shell's own title, used as the suffix of `document.title`. */
|
|
258
293
|
title?: unknown;
|
|
259
294
|
/**
|
|
@@ -315,6 +350,11 @@ export interface PanelStack {
|
|
|
315
350
|
* than opening it twice, and a panel holding {@link Panel.unsaved} work is
|
|
316
351
|
* never closed, only parked. That's what a plain link does, and what
|
|
317
352
|
* `data-panel=push` says outright.
|
|
353
|
+
*
|
|
354
|
+
* Note that a link builds on the panel it is *drawn in*, which is the
|
|
355
|
+
* current panel only while no column beside it has the focus. Code
|
|
356
|
+
* navigating on behalf of a particular screen — a row's click handler —
|
|
357
|
+
* wants that panel's own {@link Panel.open} instead.
|
|
318
358
|
*/
|
|
319
359
|
pushPanel(path: string): Promise<boolean>;
|
|
320
360
|
/**
|
|
@@ -411,8 +451,8 @@ export declare class PanelStackController implements PanelStack {
|
|
|
411
451
|
private containerEl?;
|
|
412
452
|
/** The shell's measurements, shared by everything drawn since they were taken. */
|
|
413
453
|
private geom?;
|
|
414
|
-
/** The
|
|
415
|
-
private
|
|
454
|
+
/** The measurements the last layout ran on; a change in them → snap. */
|
|
455
|
+
private lastGeom?;
|
|
416
456
|
private layoutQueued;
|
|
417
457
|
private timers;
|
|
418
458
|
/** The arrangement the navigation in flight is heading for; see {@link intended}. */
|
|
@@ -581,11 +621,22 @@ export declare class PanelStackController implements PanelStack {
|
|
|
581
621
|
*/
|
|
582
622
|
private closePath;
|
|
583
623
|
/**
|
|
584
|
-
* Navigate to `href
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
* the
|
|
624
|
+
* Navigate to `href` — the one implementation behind a link click,
|
|
625
|
+
* {@link Panel.open} and the stack's own methods, so none of them can
|
|
626
|
+
* behave differently.
|
|
627
|
+
*
|
|
628
|
+
* `from` is the path of the panel the navigation starts from — the one
|
|
629
|
+
* the link lives in — or absent when it has none: a nav item, or a call
|
|
630
|
+
* that means the whole stack, which is then built instead (see
|
|
631
|
+
* {@link deriveStack}), or taken outright from `beneath`, for callers
|
|
632
|
+
* that know it.
|
|
633
|
+
*
|
|
634
|
+
* `how` is the link's `data-panel` attribute (or the caller's word for
|
|
635
|
+
* it): absent — like a link without the attribute — it is the shell's
|
|
636
|
+
* `linkNavigation` default, an unrecognised value is a push on top of
|
|
637
|
+
* `from`, `"replace"` swaps `from` out rather than stacking on it, and
|
|
638
|
+
* `"open"` drops `from` altogether so the target arrives with its own
|
|
639
|
+
* stack, the way a nav item's link does.
|
|
589
640
|
*
|
|
590
641
|
* Resolves the way every {@link PanelStack} method does: `true` once the
|
|
591
642
|
* navigation lands, `false` when it doesn't (already there counts as
|
|
@@ -596,18 +647,15 @@ export declare class PanelStackController implements PanelStack {
|
|
|
596
647
|
private pushPath;
|
|
597
648
|
/**
|
|
598
649
|
* Link handling through `route.interceptLinks()`, whose handler hook hands us
|
|
599
|
-
* the anchor so we can decide what the click *means
|
|
600
|
-
* `.s-panel` (which decides what the click truncates), the `data-panel`
|
|
601
|
-
* attribute, and return-to-an-open-panel semantics. The exclusion rules
|
|
650
|
+
* the anchor so we can decide what the click *means*. The exclusion rules
|
|
602
651
|
* (targets, downloads, modified clicks, external URLs) live in Aberdeen; the
|
|
603
652
|
* close guards run in `checkChange` when our navigation reaches the router.
|
|
604
653
|
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
* an unrecognised value is a `push`.
|
|
654
|
+
* A link inside a panel is that panel's {@link Panel.open}, the `data-panel`
|
|
655
|
+
* attribute as its `how` (see {@link navigate}, the shared implementation).
|
|
656
|
+
* A link that isn't inside any panel — a nav item, one in a dialog — has no
|
|
657
|
+
* panel to build on, so it replaces the stack as a whole, exactly as a cold
|
|
658
|
+
* link to the same URL would open it.
|
|
611
659
|
*/
|
|
612
660
|
private interceptLinks;
|
|
613
661
|
get currentPanel(): Panel | undefined;
|
|
@@ -621,6 +669,12 @@ export declare class PanelStackController implements PanelStack {
|
|
|
621
669
|
setColumns(columns: "auto" | "single" | undefined): void;
|
|
622
670
|
/** Adopt a changed `linkNavigation` default; the next click reads it. */
|
|
623
671
|
setLinkNavigation(mode: "push" | "replace" | "open" | undefined): void;
|
|
672
|
+
/**
|
|
673
|
+
* Adopt a changed `fullWidth`: one layout pass, nothing redrawn. A changed
|
|
674
|
+
* `navWidth` needs no counterpart — resizing the sidebar resizes the column
|
|
675
|
+
* region, which the layout engine is already observing.
|
|
676
|
+
*/
|
|
677
|
+
setFullWidth(px: number): void;
|
|
624
678
|
/**
|
|
625
679
|
* The breadcrumb stack, drawn by `main()` into the top bar: every open
|
|
626
680
|
* panel, oldest first, the ones on screen right now in bold, pinned ones
|