staffa 0.9.0 → 0.10.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.
- package/README.md +106 -48
- package/dist/components/autocomplete.js +1 -1
- package/dist/components/box.d.ts +8 -16
- package/dist/components/box.js +21 -27
- package/dist/components/button.d.ts +40 -0
- package/dist/components/button.js +85 -12
- package/dist/components/buttonChooser.js +1 -1
- package/dist/components/checkbox.js +3 -3
- package/dist/components/field.js +3 -3
- package/dist/components/main.d.ts +134 -71
- package/dist/components/main.js +245 -174
- package/dist/components/menu.d.ts +77 -14
- package/dist/components/menu.js +239 -34
- package/dist/components/pages.d.ts +638 -0
- package/dist/components/pages.js +1510 -0
- package/dist/components/panels.d.ts +448 -225
- package/dist/components/panels.js +819 -435
- package/dist/components/tabs.d.ts +37 -0
- package/dist/components/tabs.js +128 -69
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/glyphs.d.ts +24 -0
- package/dist/glyphs.js +25 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -4
- package/dist/staffa.esm.js +1 -1
- package/dist/theme.d.ts +67 -0
- package/dist/theme.js +12 -2
- package/package.json +2 -2
- package/skill/BoxOptions.md +7 -12
- package/skill/IconButtonOptions.md +41 -0
- package/skill/MainOptions.md +106 -58
- package/skill/MenuItem.md +21 -1
- package/skill/MenuListOptions.md +24 -0
- package/skill/MenuOptions.md +3 -2
- package/skill/Panel.md +190 -0
- package/skill/PanelStack.md +106 -0
- package/skill/SKILL.md +172 -64
- package/skill/ScrollStripOptions.md +21 -0
- package/skill/box.md +1 -4
- package/skill/closeNav.md +3 -3
- package/skill/iconButton.md +27 -0
- package/skill/main.md +13 -9
- package/skill/menu.md +29 -0
- package/skill/scrollStrip.md +28 -0
- package/src/components/autocomplete.ts +1 -1
- package/src/components/box.ts +29 -39
- package/src/components/button.ts +109 -8
- package/src/components/buttonChooser.ts +1 -1
- package/src/components/checkbox.ts +3 -3
- package/src/components/field.ts +3 -3
- package/src/components/main.ts +381 -188
- package/src/components/menu.ts +278 -37
- package/src/components/panels.ts +1136 -526
- package/src/components/tabs.ts +134 -68
- package/src/core.ts +1 -1
- package/src/index.ts +4 -4
- package/src/theme.ts +14 -3
- package/skill/Page.md +0 -119
- package/skill/panels.md +0 -10
|
@@ -12,6 +12,15 @@ export interface Tab {
|
|
|
12
12
|
/** Disables selecting this tab. */
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
}
|
|
15
|
+
/** Options for {@link scrollStrip}. */
|
|
16
|
+
export interface ScrollStripOptions {
|
|
17
|
+
/** The row's content, laid out left to right. */
|
|
18
|
+
content: Slot;
|
|
19
|
+
/** Aberdeen attr/style string applied to the outer element. */
|
|
20
|
+
attrs?: Attributes;
|
|
21
|
+
/** Aberdeen attr/style string applied to the scrolling row itself. */
|
|
22
|
+
stripAttrs?: Attributes;
|
|
23
|
+
}
|
|
15
24
|
/** Options for {@link tabs}. */
|
|
16
25
|
export interface TabsOptions {
|
|
17
26
|
/** Aberdeen attr/style string applied to the outermost element. */
|
|
@@ -26,6 +35,34 @@ export interface TabsOptions {
|
|
|
26
35
|
/** Aberdeen attr/style string applied to the active panel. */
|
|
27
36
|
contentAttrs?: Attributes;
|
|
28
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* A horizontal row that scrolls when its content outgrows it, with a ‹ / ›
|
|
40
|
+
* button appearing over whichever end still has something left to reach — a
|
|
41
|
+
* bare scroll area says nothing about itself to a mouse, and a scrollbar under
|
|
42
|
+
* a row of chrome reads as a mistake. The row's own scrollbar is hidden, and
|
|
43
|
+
* the buttons scroll it by most of a width at a time.
|
|
44
|
+
*
|
|
45
|
+
* This is what {@link tabs} puts its tab strip in, and what the routed
|
|
46
|
+
* {@link main} shell puts its breadcrumb stack in. Reach for it for any row of
|
|
47
|
+
* chrome that can outgrow its space: a filter bar, a row of chips, a toolbar.
|
|
48
|
+
* To bring one of its children into view — after selecting it from elsewhere,
|
|
49
|
+
* say — call {@link revealInStrip} with that child.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* S.scrollStrip({
|
|
54
|
+
* attrs: "gap:$1",
|
|
55
|
+
* content: () => { for (const tag of tags) S.button({ content: tag, attrs: ".small" }); },
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function scrollStrip(opts: ScrollStripOptions): void;
|
|
60
|
+
/**
|
|
61
|
+
* Scroll `el`'s {@link scrollStrip} just far enough to bring it into view,
|
|
62
|
+
* clearing the buttons that overlay the row's ends. Does nothing when `el`
|
|
63
|
+
* isn't in a strip, or is already comfortably visible.
|
|
64
|
+
*/
|
|
65
|
+
export declare function revealInStrip(el: HTMLElement): void;
|
|
29
66
|
/**
|
|
30
67
|
* A tabbed view. Renders an ARIA `tablist` of buttons and a single live panel
|
|
31
68
|
* for the selected tab. Supports keyboard navigation (left/right/home/end).
|
package/dist/components/tabs.js
CHANGED
|
@@ -7,24 +7,43 @@ import { mk } from "../icons-helpers.js";
|
|
|
7
7
|
const chevronLeft = mk('<path d="m15 18-6-6 6-6"/>');
|
|
8
8
|
const chevronRight = mk('<path d="m9 18 6-6-6-6"/>');
|
|
9
9
|
A.insertGlobalCss({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
//
|
|
17
|
-
|
|
10
|
+
// A row that scrolls sideways once its content outgrows it, with a ‹ / ›
|
|
11
|
+
// button appearing over whichever end still has something to reach. Its own
|
|
12
|
+
// scrollbar is hidden — a raw scrollbar under a row of chrome reads as a
|
|
13
|
+
// mistake — so those buttons, and the fade they sit in, are the affordance.
|
|
14
|
+
// Shared by `tabs()` and the shell's breadcrumb stack; see `scrollStrip()`.
|
|
15
|
+
".s-strip": {
|
|
16
|
+
// The positioning context the buttons overlay from.
|
|
17
|
+
"&": "position:relative display:flex min-width:0",
|
|
18
18
|
// `overflow-y:hidden` is load-bearing: `overflow-x:auto` alone forces the
|
|
19
19
|
// computed `overflow-y` off `visible`, which turned the active tab's 1px
|
|
20
20
|
// overhang into a stray couple of pixels of *vertical* scroll.
|
|
21
|
-
".s-
|
|
22
|
-
"overflow-x:auto overflow-y:hidden scrollbar-width:none scroll-behavior:smooth
|
|
21
|
+
"> .s-strip-row": "display:flex align-items:center flex:1 min-width:0 " +
|
|
22
|
+
"overflow-x:auto overflow-y:hidden scrollbar-width:none scroll-behavior:smooth",
|
|
23
|
+
"> .s-strip-row::-webkit-scrollbar": "display:none",
|
|
24
|
+
// The buttons overlay the row's ends rather than sitting beside it, so no
|
|
25
|
+
// width is reserved when there's nothing to scroll — and the content slides
|
|
26
|
+
// out from under a fade instead of stopping at a hard edge.
|
|
27
|
+
"> .s-strip-btn": "position:absolute top:0 bottom:0 z-index:1 display:none align-items:center justify-content:center " +
|
|
28
|
+
"width:2.4em border:0 padding:0 cursor:pointer fg:$s-muted " +
|
|
29
|
+
"transition: color 0.15s;",
|
|
30
|
+
"> .s-strip-btn:hover": "fg:$s-text",
|
|
31
|
+
"> .s-strip-btn-left": "left:0 justify-content:flex-start background: linear-gradient(to right, $s-bg 45%, transparent)",
|
|
32
|
+
"> .s-strip-btn-right": "right:0 justify-content:flex-end background: linear-gradient(to left, $s-bg 45%, transparent)",
|
|
33
|
+
// Shown only for the direction there is actually something to scroll towards,
|
|
34
|
+
// so the pair doubles as a position indicator.
|
|
35
|
+
"&.s-can-left > .s-strip-btn-left, &.s-can-right > .s-strip-btn-right": "display:flex",
|
|
36
|
+
},
|
|
37
|
+
".s-tabs": {
|
|
38
|
+
"&": "display:flex flex-direction:column gap:$3",
|
|
39
|
+
// The bar owns the hairline, so it runs the full width — under the scroll
|
|
40
|
+
// buttons too.
|
|
41
|
+
".s-tabbar": "border-bottom: 1px solid $s-faint;",
|
|
42
|
+
".s-tablist": "gap:$1 align-items:stretch " +
|
|
23
43
|
// Pulls the strip 1px down over the bar's hairline, so the active tab's
|
|
24
44
|
// underline lands *on* it rather than stacking above it. On the strip, not
|
|
25
45
|
// the tabs: a negative margin inside a scroll container is overflow.
|
|
26
46
|
"margin-bottom:-1px",
|
|
27
|
-
".s-tablist::-webkit-scrollbar": "display:none",
|
|
28
47
|
".s-tab": "display:inline-flex align-items:center gap:$2 cursor:pointer background:transparent " +
|
|
29
48
|
"border:0 color: $s-muted; font-weight:600 padding: 0.6em 0.9em; white-space:nowrap " +
|
|
30
49
|
"border-bottom: 3px solid transparent; " +
|
|
@@ -34,21 +53,56 @@ A.insertGlobalCss({
|
|
|
34
53
|
// painting, and an outset ring on the first/last tab would be shaved off.
|
|
35
54
|
".s-tab:focus-visible": "outline:none box-shadow: inset 0 0 0 2px $s-focus; r: $s-radius;",
|
|
36
55
|
".s-tab[aria-selected=true]": "border-image: $s-gradient 1;",
|
|
37
|
-
// The scroll buttons overlay the strip's ends rather than sitting beside it,
|
|
38
|
-
// so no width is reserved when there's nothing to scroll — and the tabs slide
|
|
39
|
-
// out from under a fade instead of stopping at a hard edge.
|
|
40
|
-
".s-tabscroll": "position:absolute top:0 bottom:0 z-index:1 display:none align-items:center justify-content:center " +
|
|
41
|
-
"width:2.4em border:0 padding:0 cursor:pointer fg:$s-muted " +
|
|
42
|
-
"transition: color 0.15s;",
|
|
43
|
-
".s-tabscroll:hover": "fg:$s-text",
|
|
44
|
-
".s-tabscroll-left": "left:0 justify-content:flex-start background: linear-gradient(to right, $s-bg 45%, transparent)",
|
|
45
|
-
".s-tabscroll-right": "right:0 justify-content:flex-end background: linear-gradient(to left, $s-bg 45%, transparent)",
|
|
46
|
-
// Shown only for the direction there is actually something to scroll towards,
|
|
47
|
-
// so the pair doubles as a position indicator.
|
|
48
|
-
".s-tabbar.s-can-left > .s-tabscroll-left, .s-tabbar.s-can-right > .s-tabscroll-right": "display:flex",
|
|
49
56
|
".s-tabpanel": "display:block",
|
|
50
57
|
},
|
|
51
58
|
});
|
|
59
|
+
/**
|
|
60
|
+
* A horizontal row that scrolls when its content outgrows it, with a ‹ / ›
|
|
61
|
+
* button appearing over whichever end still has something left to reach — a
|
|
62
|
+
* bare scroll area says nothing about itself to a mouse, and a scrollbar under
|
|
63
|
+
* a row of chrome reads as a mistake. The row's own scrollbar is hidden, and
|
|
64
|
+
* the buttons scroll it by most of a width at a time.
|
|
65
|
+
*
|
|
66
|
+
* This is what {@link tabs} puts its tab strip in, and what the routed
|
|
67
|
+
* {@link main} shell puts its breadcrumb stack in. Reach for it for any row of
|
|
68
|
+
* chrome that can outgrow its space: a filter bar, a row of chips, a toolbar.
|
|
69
|
+
* To bring one of its children into view — after selecting it from elsewhere,
|
|
70
|
+
* say — call {@link revealInStrip} with that child.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* S.scrollStrip({
|
|
75
|
+
* attrs: "gap:$1",
|
|
76
|
+
* content: () => { for (const tag of tags) S.button({ content: tag, attrs: ".small" }); },
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export function scrollStrip(opts) {
|
|
81
|
+
A("div.s-strip", opts.attrs, () => {
|
|
82
|
+
const row = A("div.s-strip-row", opts.stripAttrs, () => drawSlot(opts.content));
|
|
83
|
+
drawScrollButton(row, -1);
|
|
84
|
+
drawScrollButton(row, 1);
|
|
85
|
+
watchScroll(row);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Scroll `el`'s {@link scrollStrip} just far enough to bring it into view,
|
|
90
|
+
* clearing the buttons that overlay the row's ends. Does nothing when `el`
|
|
91
|
+
* isn't in a strip, or is already comfortably visible.
|
|
92
|
+
*/
|
|
93
|
+
export function revealInStrip(el) {
|
|
94
|
+
const row = el.parentElement;
|
|
95
|
+
if (!row || !el.isConnected)
|
|
96
|
+
return;
|
|
97
|
+
// The overlays are 2.4em wide; clearing a little more than that keeps the
|
|
98
|
+
// revealed item from sitting right against one.
|
|
99
|
+
const pad = parseFloat(getComputedStyle(row).fontSize) * 2.6;
|
|
100
|
+
const box = el.getBoundingClientRect(), strip = row.getBoundingClientRect();
|
|
101
|
+
if (box.left < strip.left + pad)
|
|
102
|
+
row.scrollBy({ left: box.left - strip.left - pad, behavior: "smooth" });
|
|
103
|
+
else if (box.right > strip.right - pad)
|
|
104
|
+
row.scrollBy({ left: box.right - strip.right + pad, behavior: "smooth" });
|
|
105
|
+
}
|
|
52
106
|
/**
|
|
53
107
|
* A tabbed view. Renders an ARIA `tablist` of buttons and a single live panel
|
|
54
108
|
* for the selected tab. Supports keyboard navigation (left/right/home/end).
|
|
@@ -82,12 +136,14 @@ export function tabs(opts) {
|
|
|
82
136
|
$sel.value = keyOf(tab, index);
|
|
83
137
|
};
|
|
84
138
|
A("div.s-tabs", opts.attrs, () => {
|
|
85
|
-
|
|
86
|
-
|
|
139
|
+
scrollStrip({
|
|
140
|
+
attrs: ".s-tabbar",
|
|
141
|
+
stripAttrs: ".s-tablist role=tablist",
|
|
142
|
+
content: () => {
|
|
87
143
|
opts.tabs.forEach((tab, index) => {
|
|
88
144
|
const key = keyOf(tab, index);
|
|
89
145
|
const tabEl = A("button.s-tab type=button role=tab", () => {
|
|
90
|
-
A(
|
|
146
|
+
A("id=", `${groupId}-tab-${key}`, "aria-controls=", `${groupId}-panel-${key}`);
|
|
91
147
|
A(() => {
|
|
92
148
|
const selected = $sel.value === key;
|
|
93
149
|
A("aria-selected=", selected ? "true" : "false");
|
|
@@ -96,7 +152,7 @@ export function tabs(opts) {
|
|
|
96
152
|
// view, so the strip follows the selection however it was made:
|
|
97
153
|
// a click, the arrow keys, or a `bind` written from elsewhere.
|
|
98
154
|
if (selected)
|
|
99
|
-
requestAnimationFrame(() =>
|
|
155
|
+
requestAnimationFrame(() => revealInStrip(tabEl));
|
|
100
156
|
});
|
|
101
157
|
if (tab.disabled)
|
|
102
158
|
A("disabled=true");
|
|
@@ -106,10 +162,7 @@ export function tabs(opts) {
|
|
|
106
162
|
drawSlot(tab.label);
|
|
107
163
|
});
|
|
108
164
|
});
|
|
109
|
-
}
|
|
110
|
-
drawScrollButton(listEl, -1);
|
|
111
|
-
drawScrollButton(listEl, 1);
|
|
112
|
-
watchScroll(listEl);
|
|
165
|
+
},
|
|
113
166
|
});
|
|
114
167
|
A("div.s-tabpanel role=tabpanel", opts.contentAttrs, () => {
|
|
115
168
|
A(() => {
|
|
@@ -118,69 +171,75 @@ export function tabs(opts) {
|
|
|
118
171
|
const tab = opts.tabs[index] ?? opts.tabs[0];
|
|
119
172
|
if (!tab)
|
|
120
173
|
return;
|
|
121
|
-
A(
|
|
174
|
+
A("id=", `${groupId}-panel-${keyOf(tab, index)}`, "aria-labelledby=", `${groupId}-tab-${keyOf(tab, index)}`);
|
|
122
175
|
drawSlot(tab.content);
|
|
123
176
|
});
|
|
124
177
|
});
|
|
125
178
|
});
|
|
126
179
|
}
|
|
127
180
|
/**
|
|
128
|
-
* One of the two scroll buttons overlaying the ends of the
|
|
129
|
-
* the left one and 1 for the right.
|
|
130
|
-
*
|
|
181
|
+
* One of the two scroll buttons overlaying the ends of the row. `dir` is -1 for
|
|
182
|
+
* the left one and 1 for the right. Most of a width at a time (not one item at a
|
|
183
|
+
* time): the row scrolls smoothly, so a nudge that moved a single tab or crumb
|
|
184
|
+
* would read as a twitch.
|
|
131
185
|
*/
|
|
132
|
-
function drawScrollButton(
|
|
133
|
-
A(`button.s-
|
|
134
|
-
// The
|
|
135
|
-
//
|
|
136
|
-
//
|
|
186
|
+
function drawScrollButton(row, dir) {
|
|
187
|
+
A(`button.s-strip-btn.s-strip-btn-${dir < 0 ? "left" : "right"} type=button`, () => {
|
|
188
|
+
// The row's own items are the real control; this is a convenience it offers
|
|
189
|
+
// a mouse. Keeping it out of the tab order means Tab still steps from the
|
|
190
|
+
// row straight into whatever follows.
|
|
137
191
|
A("tabindex=-1 aria-hidden=true");
|
|
138
|
-
A("click=", () =>
|
|
192
|
+
A("click=", () => row.scrollBy({ left: dir * row.clientWidth * 0.8, behavior: "smooth" }));
|
|
139
193
|
(dir < 0 ? chevronLeft : chevronRight)({ size: "1.1em" });
|
|
140
194
|
});
|
|
141
195
|
}
|
|
142
196
|
/**
|
|
143
|
-
* Keep the `.s-can-left` / `.s-can-right` classes on the
|
|
197
|
+
* Keep the `.s-can-left` / `.s-can-right` classes on the strip in step with what
|
|
144
198
|
* there is left to scroll towards, so each button appears exactly when it has
|
|
145
|
-
* somewhere to go. Watches the
|
|
146
|
-
*
|
|
199
|
+
* somewhere to go. Watches the row's own scrolling *and* its size — and its
|
|
200
|
+
* children's, since items arriving or leaving (a pushed page's crumb, a tab)
|
|
201
|
+
* changes the answer without any scrolling at all.
|
|
147
202
|
*/
|
|
148
|
-
function watchScroll(
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
203
|
+
function watchScroll(row) {
|
|
204
|
+
const strip = row.parentElement;
|
|
205
|
+
if (!strip || typeof ResizeObserver === "undefined")
|
|
151
206
|
return; // No-op outside the browser.
|
|
152
207
|
const update = () => {
|
|
153
208
|
// A sub-pixel slack: fractional layout widths otherwise leave a permanent
|
|
154
209
|
// half-pixel of "scrollable" at an end that is plainly already reached.
|
|
155
|
-
const max =
|
|
156
|
-
|
|
157
|
-
|
|
210
|
+
const max = row.scrollWidth - row.clientWidth;
|
|
211
|
+
strip.classList.toggle("s-can-left", row.scrollLeft > 1);
|
|
212
|
+
strip.classList.toggle("s-can-right", row.scrollLeft < max - 1);
|
|
158
213
|
};
|
|
159
|
-
|
|
214
|
+
row.addEventListener("scroll", update, { passive: true });
|
|
160
215
|
const ro = new ResizeObserver(update);
|
|
161
|
-
ro.observe(
|
|
162
|
-
|
|
163
|
-
|
|
216
|
+
ro.observe(row);
|
|
217
|
+
// The children are watched through one observer that follows the row's live
|
|
218
|
+
// contents, so a strip whose items come and go keeps answering correctly.
|
|
219
|
+
// Removed children are unobserved: a strip whose items churn (the breadcrumb
|
|
220
|
+
// row redraws on navigation) would otherwise grow the observation list — and
|
|
221
|
+
// retain the detached elements — without bound.
|
|
222
|
+
const mo = typeof MutationObserver === "undefined" ? undefined : new MutationObserver((records) => {
|
|
223
|
+
for (const record of records) {
|
|
224
|
+
for (const el of record.addedNodes)
|
|
225
|
+
if (el instanceof Element)
|
|
226
|
+
ro.observe(el);
|
|
227
|
+
for (const el of record.removedNodes)
|
|
228
|
+
if (el instanceof Element)
|
|
229
|
+
ro.unobserve(el);
|
|
230
|
+
}
|
|
231
|
+
update();
|
|
232
|
+
});
|
|
233
|
+
mo?.observe(row, { childList: true });
|
|
234
|
+
for (const kid of Array.from(row.children))
|
|
235
|
+
ro.observe(kid);
|
|
164
236
|
update();
|
|
165
237
|
A.clean(() => {
|
|
166
|
-
|
|
238
|
+
row.removeEventListener("scroll", update);
|
|
167
239
|
ro.disconnect();
|
|
240
|
+
mo?.disconnect();
|
|
168
241
|
});
|
|
169
242
|
}
|
|
170
|
-
/** Scroll `el`'s strip just far enough to clear the buttons overlaying its ends. */
|
|
171
|
-
function reveal(el) {
|
|
172
|
-
const list = el.parentElement;
|
|
173
|
-
if (!list || !el.isConnected)
|
|
174
|
-
return;
|
|
175
|
-
// The overlays are 2.4em wide; clearing a little more than that keeps the tab
|
|
176
|
-
// from sitting right against one.
|
|
177
|
-
const pad = parseFloat(getComputedStyle(list).fontSize) * 2.6;
|
|
178
|
-
const tab = el.getBoundingClientRect(), strip = list.getBoundingClientRect();
|
|
179
|
-
if (tab.left < strip.left + pad)
|
|
180
|
-
list.scrollBy({ left: tab.left - strip.left - pad, behavior: "smooth" });
|
|
181
|
-
else if (tab.right > strip.right - pad)
|
|
182
|
-
list.scrollBy({ left: tab.right - strip.right + pad, behavior: "smooth" });
|
|
183
|
-
}
|
|
184
243
|
/** Roving-tabindex keyboard handling for the tab strip. */
|
|
185
244
|
function onKey(e, list, index, select) {
|
|
186
245
|
let next = index;
|
package/dist/core.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export interface ContentOptions {
|
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Shell width — not viewport width — at or below which the app shell goes
|
|
54
|
-
* "narrow": the nav sidebar collapses to a hamburger, and a routed
|
|
54
|
+
* "narrow": the nav sidebar collapses to a hamburger, and a routed shell
|
|
55
55
|
* has room for exactly one full-bleed column. Shared by the `@container` queries
|
|
56
56
|
* that do the switching and by the JS that has to agree with them.
|
|
57
57
|
*/
|
package/dist/core.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import A from "aberdeen";
|
|
2
2
|
/**
|
|
3
3
|
* Shell width — not viewport width — at or below which the app shell goes
|
|
4
|
-
* "narrow": the nav sidebar collapses to a hamburger, and a routed
|
|
4
|
+
* "narrow": the nav sidebar collapses to a hamburger, and a routed shell
|
|
5
5
|
* has room for exactly one full-bleed column. Shared by the `@container` queries
|
|
6
6
|
* that do the switching and by the JS that has to agree with them.
|
|
7
7
|
*/
|
package/dist/glyphs.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The handful of glyphs Staffa's own chrome draws: the nav trigger, the ✕ that
|
|
3
|
+
* dismisses things, the « that leaves a panel.
|
|
4
|
+
*
|
|
5
|
+
* They are inline SVG (built with the icon set's own helper, so no icon data is
|
|
6
|
+
* pulled in) rather than the `☰`/`✕`/`«` characters, because a text glyph is at
|
|
7
|
+
* the mercy of the system font: it lands thin and undersized next to a real
|
|
8
|
+
* icon, and a font without it renders an empty box instead. Each matches its
|
|
9
|
+
* Lucide counterpart exactly, so shell chrome sits beside an app's icons as an
|
|
10
|
+
* equal.
|
|
11
|
+
*/
|
|
12
|
+
/** `☰` — Lucide `menu`. Opens a menu, or the collapsed nav. */
|
|
13
|
+
export declare const menuGlyph: (opts?: import("./icons-helpers.js").IconOptions) => void;
|
|
14
|
+
/** `✕` — Lucide `x`. Dismisses a panel, a box, or whatever the {@link menuGlyph} opened. */
|
|
15
|
+
export declare const closeGlyph: (opts?: import("./icons-helpers.js").IconOptions) => void;
|
|
16
|
+
/**
|
|
17
|
+
* `«` — Lucide `chevrons-left`. Leaves the top panel: on a narrow shell it takes
|
|
18
|
+
* the {@link menuGlyph}'s place in the top bar, since at depth you go back first
|
|
19
|
+
* and navigate after. A chevron pair rather than an arrow, so it reads as
|
|
20
|
+
* *back out of here* beside the single chevrons a pager uses for prev/next.
|
|
21
|
+
*/
|
|
22
|
+
export declare const backGlyph: (opts?: import("./icons-helpers.js").IconOptions) => void;
|
|
23
|
+
/** `›` — Lucide `chevron-right`. Separates the top bar's breadcrumbs. */
|
|
24
|
+
export declare const chevronGlyph: (opts?: import("./icons-helpers.js").IconOptions) => void;
|
package/dist/glyphs.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { mk } from "./icons-helpers.js";
|
|
2
|
+
/**
|
|
3
|
+
* The handful of glyphs Staffa's own chrome draws: the nav trigger, the ✕ that
|
|
4
|
+
* dismisses things, the « that leaves a panel.
|
|
5
|
+
*
|
|
6
|
+
* They are inline SVG (built with the icon set's own helper, so no icon data is
|
|
7
|
+
* pulled in) rather than the `☰`/`✕`/`«` characters, because a text glyph is at
|
|
8
|
+
* the mercy of the system font: it lands thin and undersized next to a real
|
|
9
|
+
* icon, and a font without it renders an empty box instead. Each matches its
|
|
10
|
+
* Lucide counterpart exactly, so shell chrome sits beside an app's icons as an
|
|
11
|
+
* equal.
|
|
12
|
+
*/
|
|
13
|
+
/** `☰` — Lucide `menu`. Opens a menu, or the collapsed nav. */
|
|
14
|
+
export const menuGlyph = mk('<path d="M4 6h16"/><path d="M4 12h16"/><path d="M4 18h16"/>');
|
|
15
|
+
/** `✕` — Lucide `x`. Dismisses a panel, a box, or whatever the {@link menuGlyph} opened. */
|
|
16
|
+
export const closeGlyph = mk('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>');
|
|
17
|
+
/**
|
|
18
|
+
* `«` — Lucide `chevrons-left`. Leaves the top panel: on a narrow shell it takes
|
|
19
|
+
* the {@link menuGlyph}'s place in the top bar, since at depth you go back first
|
|
20
|
+
* and navigate after. A chevron pair rather than an arrow, so it reads as
|
|
21
|
+
* *back out of here* beside the single chevrons a pager uses for prev/next.
|
|
22
|
+
*/
|
|
23
|
+
export const backGlyph = mk('<path d="m11 17-5-5 5-5"/><path d="m18 17-5-5 5-5"/>');
|
|
24
|
+
/** `›` — Lucide `chevron-right`. Separates the top bar's breadcrumbs. */
|
|
25
|
+
export const chevronGlyph = mk('<path d="m9 18 6-6-6-6"/>');
|
package/dist/index.d.ts
CHANGED
|
@@ -32,17 +32,17 @@
|
|
|
32
32
|
export { setDarkMode, getDarkMode } from "./theme.js";
|
|
33
33
|
export { autocomplete, type AutocompleteOptions, type AutocompleteOptionInput } from "./components/autocomplete.js";
|
|
34
34
|
export { box, type BoxOptions } from "./components/box.js";
|
|
35
|
-
export { button, type ButtonOptions } from "./components/button.js";
|
|
35
|
+
export { button, iconButton, type ButtonOptions, type IconButtonOptions } from "./components/button.js";
|
|
36
36
|
export { buttonChooser, type ButtonChooserOptions } from "./components/buttonChooser.js";
|
|
37
37
|
export { buttonGroup, type ButtonGroupOptions } from "./components/buttonGroup.js";
|
|
38
38
|
export { checkbox, type CheckboxOptions } from "./components/checkbox.js";
|
|
39
39
|
export { form, type FormOptions } from "./components/form.js";
|
|
40
40
|
export { main, closeNav, type MainOptions } from "./components/main.js";
|
|
41
|
-
export {
|
|
42
|
-
export { menuButton, showFloatingMenu, addContextMenu, isFloatingMenuOpen, closeFloatingMenu, type MenuOptions, type MenuEntry, type MenuItem, type MenuSeparator, type FloatingMenuOptions, type ContextMenuOptions } from "./components/menu.js";
|
|
41
|
+
export { type PanelStack, type Panel, type Routes, type RouteHandler, type RouteTable, type AncestorsHandler, type AncestorTable, type PathParams, type SegParams } from "./components/panels.js";
|
|
42
|
+
export { menu, menuButton, showFloatingMenu, addContextMenu, isFloatingMenuOpen, closeFloatingMenu, type MenuListOptions, type MenuOptions, type MenuEntry, type MenuItem, type MenuSeparator, type FloatingMenuOptions, type ContextMenuOptions } from "./components/menu.js";
|
|
43
43
|
export { dialog, alert, confirm, prompt, isDialogOpen, type DialogOptions } from "./components/dialog.js";
|
|
44
44
|
export { select, type SelectOptions, type SelectOptionInput } from "./components/select.js";
|
|
45
|
-
export { tabs, type Tab, type TabsOptions } from "./components/tabs.js";
|
|
45
|
+
export { tabs, scrollStrip, revealInStrip, type Tab, type TabsOptions, type ScrollStripOptions } from "./components/tabs.js";
|
|
46
46
|
export { textarea, type TextareaOptions } from "./components/textarea.js";
|
|
47
47
|
export { textline, type TextlineOptions, type TextlineType } from "./components/textline.js";
|
|
48
48
|
export { toast, type ToastOptions } from "./components/toast.js";
|
package/dist/index.js
CHANGED
|
@@ -35,17 +35,16 @@
|
|
|
35
35
|
export { setDarkMode, getDarkMode } from "./theme.js";
|
|
36
36
|
export { autocomplete } from "./components/autocomplete.js";
|
|
37
37
|
export { box } from "./components/box.js";
|
|
38
|
-
export { button } from "./components/button.js";
|
|
38
|
+
export { button, iconButton } from "./components/button.js";
|
|
39
39
|
export { buttonChooser } from "./components/buttonChooser.js";
|
|
40
40
|
export { buttonGroup } from "./components/buttonGroup.js";
|
|
41
41
|
export { checkbox } from "./components/checkbox.js";
|
|
42
42
|
export { form } from "./components/form.js";
|
|
43
43
|
export { main, closeNav } from "./components/main.js";
|
|
44
|
-
export {
|
|
45
|
-
export { menuButton, showFloatingMenu, addContextMenu, isFloatingMenuOpen, closeFloatingMenu } from "./components/menu.js";
|
|
44
|
+
export { menu, menuButton, showFloatingMenu, addContextMenu, isFloatingMenuOpen, closeFloatingMenu } from "./components/menu.js";
|
|
46
45
|
export { dialog, alert, confirm, prompt, isDialogOpen } from "./components/dialog.js";
|
|
47
46
|
export { select } from "./components/select.js";
|
|
48
|
-
export { tabs } from "./components/tabs.js";
|
|
47
|
+
export { tabs, scrollStrip, revealInStrip } from "./components/tabs.js";
|
|
49
48
|
export { textarea } from "./components/textarea.js";
|
|
50
49
|
export { textline } from "./components/textline.js";
|
|
51
50
|
export { toast } from "./components/toast.js";
|