staffa 0.7.4 → 0.8.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 +113 -7
- package/dist/components/box.d.ts +20 -0
- package/dist/components/box.js +43 -3
- package/dist/components/layers.d.ts +330 -0
- package/dist/components/layers.js +888 -0
- package/dist/components/main.d.ts +98 -6
- package/dist/components/main.js +222 -37
- package/dist/components/menu.d.ts +14 -1
- package/dist/components/menu.js +32 -4
- package/dist/components/panels.d.ts +349 -0
- package/dist/components/panels.js +933 -0
- package/dist/components/tabs.d.ts +5 -0
- package/dist/components/tabs.js +125 -19
- package/dist/core.d.ts +7 -0
- package/dist/core.js +7 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/staffa.esm.js +1 -1
- package/package.json +7 -5
- package/skill/BoxOptions.md +18 -0
- package/skill/MainOptions.md +99 -3
- package/skill/Page.md +108 -0
- package/skill/PathParams.md +7 -0
- package/skill/SKILL.md +173 -9
- package/skill/SegParams.md +8 -0
- package/skill/box.md +4 -0
- package/skill/isFloatingMenuOpen.md +12 -0
- package/skill/main.md +14 -2
- package/skill/panels.md +10 -0
- package/skill/tabs.md +5 -0
- package/src/components/box.ts +57 -2
- package/src/components/main.ts +314 -40
- package/src/components/menu.ts +33 -5
- package/src/components/panels.ts +1167 -0
- package/src/components/tabs.ts +126 -19
- package/src/core.ts +8 -0
- package/src/index.ts +2 -1
package/src/components/menu.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import A from "aberdeen";
|
|
2
2
|
import { matchCurrent } from "aberdeen/route";
|
|
3
3
|
import { type Slot, type Attributes, drawSlot, mountPortal, focusFirst } from "../core.js";
|
|
4
|
+
import { mk } from "../icons-helpers.js";
|
|
4
5
|
import { button, type ButtonOptions } from "./button.js";
|
|
5
6
|
|
|
7
|
+
// The two glyphs the shell draws for itself. As inline SVG (built with the icon
|
|
8
|
+
// set's own helper, so no icon data is pulled in) rather than the `☰`/`✕`
|
|
9
|
+
// characters: a text glyph is at the mercy of the system font, and next to a real
|
|
10
|
+
// icon it lands thin and undersized. These match Lucide's `menu` and `x` exactly,
|
|
11
|
+
// so a nav trigger sits beside app icons as an equal.
|
|
12
|
+
/** `☰` — opens a menu or the nav. */
|
|
13
|
+
export const menuGlyph = mk('<path d="M4 6h16"/><path d="M4 12h16"/><path d="M4 18h16"/>');
|
|
14
|
+
/** `✕` — dismisses what the {@link menuGlyph} opened. */
|
|
15
|
+
export const closeGlyph = mk('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>');
|
|
16
|
+
|
|
6
17
|
/**
|
|
7
18
|
* A clickable item in a menu or sidebar nav.
|
|
8
19
|
*
|
|
@@ -109,8 +120,12 @@ A.insertGlobalCss({
|
|
|
109
120
|
"transition: color 0.12s, transform 0.12s, text-shadow 0.12s;",
|
|
110
121
|
".s-menu-item:focus-visible:not([aria-current=page]), .s-menu-item:hover:not([aria-disabled=true]):not([aria-current=page])":
|
|
111
122
|
"filter:none color: color-mix(in lab, $s-primary 33%, $s-text);",
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
// The active row is simply drawn in the surface's accent — the brand colour on a
|
|
124
|
+
// neutral surface, the ink on an accent one. No glow and no brightening: those
|
|
125
|
+
// pushed it off the brand colour, so it read as a lit-up variant of it rather
|
|
126
|
+
// than as the colour itself. `filter:none` keeps the global `a:hover` brighten
|
|
127
|
+
// off it too, since the hover rule above deliberately skips the active row.
|
|
128
|
+
".s-menu-item[aria-current=page]": "color:$s-accent filter:none",
|
|
114
129
|
".s-menu-item[aria-disabled=true]":
|
|
115
130
|
"opacity:0.45 cursor:not-allowed pointer-events:none",
|
|
116
131
|
".s-menu-icon": "flex-shrink:0",
|
|
@@ -201,9 +216,22 @@ function closeFloating(): void {
|
|
|
201
216
|
* Whether a floating menu is currently open. Reflects live state (cleared the
|
|
202
217
|
* instant it closes), unlike the DOM — the panel lingers briefly while its
|
|
203
218
|
* `destroy=` transition plays out.
|
|
219
|
+
*
|
|
220
|
+
* @param anchor When given, only reports `true` for a menu opened from *this*
|
|
221
|
+
* anchor — so a component can ask about its own menu rather than any menu.
|
|
222
|
+
*/
|
|
223
|
+
export function isFloatingMenuOpen(anchor?: HTMLElement): boolean {
|
|
224
|
+
const opts = $floating.opts;
|
|
225
|
+
return opts != null && (anchor == null || opts.anchor === anchor);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Close the open floating menu (if any), returning focus to its anchor. With an
|
|
230
|
+
* `anchor`, only closes when the open menu belongs to it, so dismissing your own
|
|
231
|
+
* menu can't steal someone else's.
|
|
204
232
|
*/
|
|
205
|
-
export function
|
|
206
|
-
|
|
233
|
+
export function closeFloatingMenu(anchor?: HTMLElement): void {
|
|
234
|
+
if (isFloatingMenuOpen(anchor)) closeFloating();
|
|
207
235
|
}
|
|
208
236
|
|
|
209
237
|
function positionMenu(menuEl: HTMLElement, rect: { left: number; right: number; top: number; bottom: number }): void {
|
|
@@ -353,7 +381,7 @@ export function menuButton(opts: MenuOptions): void {
|
|
|
353
381
|
A.clean(() => { if ($floating.opts?.anchor === myEl) closeFloating(); });
|
|
354
382
|
|
|
355
383
|
button({
|
|
356
|
-
icon: () =>
|
|
384
|
+
icon: () => menuGlyph({ size: "1.4em" }),
|
|
357
385
|
// Only label the trigger "Open menu" when it has no visible text of its
|
|
358
386
|
// own — an aria-label would otherwise *hide* that text from AT.
|
|
359
387
|
...(opts.button?.content == null ? { ariaLabel: "Open menu" } : null),
|