@kerfjs/ui 5.0.0-beta.57 → 5.0.0-beta.58
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 +18 -5
- package/ai/component-catalog.json +3 -1
- package/ai/components/toolbar-control-group.md +2 -0
- package/ai/public-api-signatures-v1.md +19 -17
- package/ai/skill.md +1 -1
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.js +2 -2
- package/dist/{chunk-G2RKFVRB.js → chunk-2CCMJTVY.js} +2 -2
- package/dist/chunk-2CCMJTVY.js.map +1 -0
- package/dist/{chunk-ZIYOJFZD.js → chunk-7JUBXOIV.js} +17 -4
- package/dist/chunk-7JUBXOIV.js.map +1 -0
- package/dist/{chunk-XCO6YCYM.js → chunk-QPUPLNNB.js} +16 -5
- package/dist/chunk-QPUPLNNB.js.map +1 -0
- package/dist/{chunk-PWXNJS2B.js → chunk-W4XKTST6.js} +2 -2
- package/dist/{chunk-PWXNJS2B.js.map → chunk-W4XKTST6.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +8 -8
- package/dist/collapsible-panel.js +2 -2
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/{panel-toolbar-BN4x0rth.d.ts → panel-toolbar-DqwtBxQL.d.ts} +10 -11
- package/dist/split-view.js +1 -1
- package/dist/toolbar-control-group.d.ts +3 -1
- package/dist/toolbar-control-group.js +1 -1
- package/dist/workbench.d.ts +5 -5
- package/dist/workbench.js +1 -1
- package/docs/collapsible-panel.md +12 -7
- package/docs/component-selection.md +3 -2
- package/docs/workbench.md +12 -11
- package/package.json +1 -1
- package/dist/chunk-G2RKFVRB.js.map +0 -1
- package/dist/chunk-XCO6YCYM.js.map +0 -1
- package/dist/chunk-ZIYOJFZD.js.map +0 -1
package/README.md
CHANGED
|
@@ -39,13 +39,15 @@ npm install kerfjs @kerfjs/ui
|
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
```tsx
|
|
42
|
+
import { mount } from "kerfjs";
|
|
42
43
|
import { ListItem } from "@kerfjs/ui/list-item";
|
|
43
44
|
import { ListHeader } from "@kerfjs/ui/list-header";
|
|
44
45
|
import { ListActionRow } from "@kerfjs/ui/list-action-row";
|
|
45
46
|
import { Toolbar } from "@kerfjs/ui/toolbar";
|
|
46
|
-
import { ToolbarControlGroup } from "@kerfjs/ui/toolbar-control-group";
|
|
47
47
|
import { ToolbarText } from "@kerfjs/ui/toolbar-text";
|
|
48
48
|
|
|
49
|
+
const root = document.getElementById("app")!;
|
|
50
|
+
|
|
49
51
|
mount(root, () => (
|
|
50
52
|
<>
|
|
51
53
|
<Toolbar
|
|
@@ -80,7 +82,7 @@ mount(root, () => (
|
|
|
80
82
|
label="src/main.ts"
|
|
81
83
|
trailingAction="open-file-actions"
|
|
82
84
|
trailingActionLabel="Actions for src/main.ts"
|
|
83
|
-
trailingActionIcon={
|
|
85
|
+
trailingActionIcon={<span aria-hidden="true">⋯</span>}
|
|
84
86
|
/>
|
|
85
87
|
<div id="workspace-actions" popover="auto">
|
|
86
88
|
Application-owned actions
|
|
@@ -226,13 +228,24 @@ interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
|
|
|
226
228
|
| `EmptyState` | `@kerfjs/ui/empty-state` | `@kerfjs/ui/empty-state.css` |
|
|
227
229
|
| `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
|
|
228
230
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
Application layouts are separate component subpaths. Browser-condition imports
|
|
232
|
+
include their reachable CSS; use the matching manual CSS export when your
|
|
233
|
+
bundler does not select the browser condition. Add a wire subpath when the
|
|
234
|
+
layout has interactive behavior. The catalog
|
|
232
235
|
entries for `nav-stack`, `split-view`, `tab-scaffold`, `workbench`, and
|
|
233
236
|
`collapsible-panel` document their selection rules, ownership boundaries,
|
|
234
237
|
public classes, tokens, and focused demos. See
|
|
235
238
|
[`docs/app-layouts.md`](./docs/app-layouts.md) for the layout decision matrix.
|
|
239
|
+
`NavStack` and `TabScaffold` expose `chromeDividers="scroll" | "always" |
|
|
240
|
+
"none"` for their chrome lines; `SplitView` forwards the setting to its
|
|
241
|
+
compact stack. A sole `Pane` in a view or scene fills it, keeping the Pane's
|
|
242
|
+
header in place while its own content scrolls.
|
|
243
|
+
|
|
244
|
+
For a `Workbench` or `CollapsiblePanel`, place panel toolbar groups in its
|
|
245
|
+
`leading`, `center`, and `trailing` zones. Add `relocateOnCollapse` to each
|
|
246
|
+
`ToolbarControlGroup` that should remain available in the work-area toolbar
|
|
247
|
+
while the panel is closed. The panel collects marked groups in zone order;
|
|
248
|
+
its toggle follows them. See [Workbench panel toolbars](./docs/workbench.md#panel-toolbars).
|
|
236
249
|
|
|
237
250
|
Compose panel, dialog, and page headings directly with `Toolbar`: put an optional
|
|
238
251
|
icon in a `ToolbarControlGroup`, use a direct extra-large `ToolbarText` for the
|
|
@@ -1498,7 +1498,8 @@
|
|
|
1498
1498
|
"Group related controls inside a toolbar with a supported visual treatment.",
|
|
1499
1499
|
"Use ToolbarActionLink for navigation or external resources that must retain native anchor semantics inside a group.",
|
|
1500
1500
|
"Fill it with plain <button> controls (the group styles > button fully); use wa-button only for a Web Awesome feature. A popup menu is a PopupMenu in a single group with nestedDropdown; it renders its own trigger, so never hand-write wa-dropdown markup. Nothing wraps inside a group: an icon sits beside its label on one row and no trigger gets a fixed width.",
|
|
1501
|
-
"For an avatar control, set content=avatar and avatarImage instead of inserting an img; one button paints the group and multiple buttons paint only the pressed highlight."
|
|
1501
|
+
"For an avatar control, set content=avatar and avatarImage instead of inserting an img; one button paints the group and multiple buttons paint only the pressed highlight.",
|
|
1502
|
+
"In a Workbench or CollapsiblePanel toolbar, mark a group relocateOnCollapse to keep it available in the work-area toolbar when the panel closes; place it directly or in an array in any toolbar zone."
|
|
1502
1503
|
],
|
|
1503
1504
|
"avoidWhen": [
|
|
1504
1505
|
"Do not use merely to align unrelated buttons or to imitate an exclusive choice.",
|
|
@@ -1535,6 +1536,7 @@
|
|
|
1535
1536
|
"standard, compact, or list-zero dropdown menu inset",
|
|
1536
1537
|
"visible or horizontally scrollable overflow",
|
|
1537
1538
|
"always visible or compact-only responsive visibility",
|
|
1539
|
+
"relocate on panel collapse",
|
|
1538
1540
|
"avatar scrim",
|
|
1539
1541
|
"contained avatar background on a single group or selected multi-button highlight"
|
|
1540
1542
|
],
|
|
@@ -14,6 +14,7 @@ Provide complete toolbar action geometry through configuration, including semant
|
|
|
14
14
|
- Use ToolbarActionLink for navigation or external resources that must retain native anchor semantics inside a group.
|
|
15
15
|
- Fill it with plain \<button> controls (the group styles > button fully); use wa-button only for a Web Awesome feature. A popup menu is a PopupMenu in a single group with nestedDropdown; it renders its own trigger, so never hand-write wa-dropdown markup. Nothing wraps inside a group: an icon sits beside its label on one row and no trigger gets a fixed width.
|
|
16
16
|
- For an avatar control, set content=avatar and avatarImage instead of inserting an img; one button paints the group and multiple buttons paint only the pressed highlight.
|
|
17
|
+
- In a Workbench or CollapsiblePanel toolbar, mark a group relocateOnCollapse to keep it available in the work-area toolbar when the panel closes; place it directly or in an array in any toolbar zone.
|
|
17
18
|
|
|
18
19
|
**Not when:**
|
|
19
20
|
|
|
@@ -50,6 +51,7 @@ Exact prop names and types: [`@kerfjs/ui/toolbar-control-group`](../public-api-s
|
|
|
50
51
|
- standard, compact, or list-zero dropdown menu inset
|
|
51
52
|
- visible or horizontally scrollable overflow
|
|
52
53
|
- always visible or compact-only responsive visibility
|
|
54
|
+
- relocate on panel collapse
|
|
53
55
|
- avatar scrim
|
|
54
56
|
- contained avatar background on a single group or selected multi-button highlight
|
|
55
57
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.58` and `kerfjs@5.0.0-beta.58`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/css-values`
|
|
6
6
|
|
|
@@ -315,6 +315,8 @@ interface ToolbarControlGroupProps {
|
|
|
315
315
|
overflow?: ToolbarControlGroupOverflow;
|
|
316
316
|
/** Responsive visibility owned by the enclosing Toolbar container. */
|
|
317
317
|
visibility?: ToolbarControlGroupVisibility;
|
|
318
|
+
/** Move this group into the work-area toolbar when its panel collapses. */
|
|
319
|
+
relocateOnCollapse?: boolean;
|
|
318
320
|
/** Add contrast behind photo-backed avatar content. */
|
|
319
321
|
scrim?: boolean;
|
|
320
322
|
/**
|
|
@@ -325,7 +327,7 @@ interface ToolbarControlGroupProps {
|
|
|
325
327
|
/** Native named-slot assignment when composed inside a web component. */
|
|
326
328
|
slot?: string;
|
|
327
329
|
}
|
|
328
|
-
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, scrim, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
|
|
330
|
+
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
|
|
329
331
|
|
|
330
332
|
export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
|
|
331
333
|
```
|
|
@@ -1414,7 +1416,7 @@ import { ListConfig } from './list.js';
|
|
|
1414
1416
|
import { PaneConfig } from './pane.js';
|
|
1415
1417
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
1416
1418
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1417
|
-
import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-
|
|
1419
|
+
import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-DqwtBxQL.js';
|
|
1418
1420
|
import { ToolbarConfig } from './toolbar.js';
|
|
1419
1421
|
import './css-values.js';
|
|
1420
1422
|
import './flex-alignment-4ms8ZbV8.js';
|
|
@@ -1427,7 +1429,7 @@ type WorkbenchPanelToggle = PanelToggle;
|
|
|
1427
1429
|
/**
|
|
1428
1430
|
* A Workbench panel's top toolbar, composed by the Workbench so its groups can
|
|
1429
1431
|
* follow the panel's open state (see {@link PanelToolbar} for the roles).
|
|
1430
|
-
* A collapsed rail's
|
|
1432
|
+
* A collapsed rail's marked groups and toggle go to the leading edge of
|
|
1431
1433
|
* `mainToolbar` (left rail) or its trailing edge (right rail); a collapsed
|
|
1432
1434
|
* drawer's go to the trailing edge of `mainBottomToolbar`, else to a
|
|
1433
1435
|
* `FloatingToolbar` in the work area's bottom-end corner.
|
|
@@ -1494,7 +1496,7 @@ interface WorkbenchPanelResizable {
|
|
|
1494
1496
|
interface WorkbenchPanel {
|
|
1495
1497
|
content: KerfUiContent;
|
|
1496
1498
|
/**
|
|
1497
|
-
* The panel's top toolbar, composed by the Workbench: its
|
|
1499
|
+
* The panel's top toolbar, composed by the Workbench: its marked groups
|
|
1498
1500
|
* and standard `toggle` move to the work area's toolbar while the panel is
|
|
1499
1501
|
* collapsed. With it, `content` renders in a `Pane` below the toolbar.
|
|
1500
1502
|
*/
|
|
@@ -1565,7 +1567,7 @@ interface WorkbenchProps {
|
|
|
1565
1567
|
/** The central work area. */
|
|
1566
1568
|
main: KerfUiContent;
|
|
1567
1569
|
/**
|
|
1568
|
-
* The work area's top toolbar. A collapsed left rail's
|
|
1570
|
+
* The work area's top toolbar. A collapsed left rail's marked groups
|
|
1569
1571
|
* and toggle lead it; a collapsed right rail's trail it. With it, `main`
|
|
1570
1572
|
* renders in a `Pane` below the toolbar.
|
|
1571
1573
|
*/
|
|
@@ -1581,7 +1583,7 @@ interface WorkbenchProps {
|
|
|
1581
1583
|
*/
|
|
1582
1584
|
mainFooter?: KerfUiContent;
|
|
1583
1585
|
/**
|
|
1584
|
-
* The work area's bottom toolbar. A collapsed drawer's
|
|
1586
|
+
* The work area's bottom toolbar. A collapsed drawer's marked groups and
|
|
1585
1587
|
* toggle trail it; without it they float in the work area's corner.
|
|
1586
1588
|
*/
|
|
1587
1589
|
mainBottomToolbar?: WorkbenchMainBottomToolbar;
|
|
@@ -1774,8 +1776,8 @@ export { type WireWorkbenchOptions, type WireWorkbenchPanel, type WorkbenchPanel
|
|
|
1774
1776
|
```ts
|
|
1775
1777
|
import { SafeHtml } from 'kerfjs';
|
|
1776
1778
|
import { PaneConfig } from './pane.js';
|
|
1777
|
-
import { P as PanelSide, a as PanelToolbar, b as PanelToggle } from './panel-toolbar-
|
|
1778
|
-
export { c as collapsiblePanelToggleIcon } from './panel-toolbar-
|
|
1779
|
+
import { P as PanelSide, a as PanelToolbar, b as PanelToggle } from './panel-toolbar-DqwtBxQL.js';
|
|
1780
|
+
export { c as collapsiblePanelToggleIcon } from './panel-toolbar-DqwtBxQL.js';
|
|
1779
1781
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
1780
1782
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1781
1783
|
import './lucide-icon.js';
|
|
@@ -1788,10 +1790,10 @@ type CollapsiblePanelSide = PanelSide;
|
|
|
1788
1790
|
/** The standard toggle a panel toolbar renders (see {@link CollapsiblePanelToolbar}). */
|
|
1789
1791
|
type CollapsiblePanelToolbarToggle = PanelToggle;
|
|
1790
1792
|
/**
|
|
1791
|
-
* A panel's composed top toolbar.
|
|
1792
|
-
*
|
|
1793
|
-
*
|
|
1794
|
-
*
|
|
1793
|
+
* A panel's composed top toolbar. Its groups occupy `leading`, `center`, and
|
|
1794
|
+
* `trailing` while open; groups marked `relocateOnCollapse` and the standard
|
|
1795
|
+
* toggle move to the work-area toolbar through
|
|
1796
|
+
* {@link CollapsiblePanelRelocated} while it is collapsed.
|
|
1795
1797
|
*/
|
|
1796
1798
|
type CollapsiblePanelToolbar = PanelToolbar;
|
|
1797
1799
|
interface CollapsiblePanelToggleProps {
|
|
@@ -1834,7 +1836,7 @@ interface CollapsiblePanelProps {
|
|
|
1834
1836
|
* The panel's top toolbar, composed so its groups follow the panel's open
|
|
1835
1837
|
* state. With it, `children` renders in a `Pane` below the toolbar; render
|
|
1836
1838
|
* {@link CollapsiblePanelRelocated} in the app's work-area toolbar so the
|
|
1837
|
-
*
|
|
1839
|
+
* marked groups and toggle stay reachable while the panel is collapsed.
|
|
1838
1840
|
*/
|
|
1839
1841
|
toolbar?: CollapsiblePanelToolbar;
|
|
1840
1842
|
/** Optional bottom toolbar under a `toolbar` panel's content. */
|
|
@@ -1883,7 +1885,7 @@ interface CollapsiblePanelRelocatedProps {
|
|
|
1883
1885
|
toolbar: CollapsiblePanelToolbar;
|
|
1884
1886
|
}
|
|
1885
1887
|
/**
|
|
1886
|
-
* A collapsed {@link CollapsiblePanel}'s
|
|
1888
|
+
* A collapsed {@link CollapsiblePanel}'s marked groups and standard
|
|
1887
1889
|
* toggle, for the app's work-area toolbar — nothing while the panel is open.
|
|
1888
1890
|
* Put it first in the leading zone for a left rail, last in the trailing zone
|
|
1889
1891
|
* for a right rail, and last in a bottom toolbar (or a `FloatingToolbar`
|
|
@@ -2217,7 +2219,7 @@ import './list.js';
|
|
|
2217
2219
|
import './css-values.js';
|
|
2218
2220
|
import './flex-alignment-4ms8ZbV8.js';
|
|
2219
2221
|
import './resizable-region.js';
|
|
2220
|
-
import './panel-toolbar-
|
|
2222
|
+
import './panel-toolbar-DqwtBxQL.js';
|
|
2221
2223
|
import './lucide-icon.js';
|
|
2222
2224
|
import 'lucide';
|
|
2223
2225
|
|
|
@@ -2310,7 +2312,7 @@ import './list.js';
|
|
|
2310
2312
|
import './css-values.js';
|
|
2311
2313
|
import './flex-alignment-4ms8ZbV8.js';
|
|
2312
2314
|
import './resizable-region.js';
|
|
2313
|
-
import './panel-toolbar-
|
|
2315
|
+
import './panel-toolbar-DqwtBxQL.js';
|
|
2314
2316
|
import './lucide-icon.js';
|
|
2315
2317
|
import 'lucide';
|
|
2316
2318
|
|
package/ai/skill.md
CHANGED
|
@@ -207,7 +207,7 @@ Hard rules:
|
|
|
207
207
|
19. Compose `ValueTable` from typed `ValueTableRow` entries instead of handwritten `dt`/`dd` wrappers. Pass `icon` for the optional 24px leading visual; the row owns 8px of root-scaled top and bottom padding, the 8px iconless or 40px icon-bearing separator start, and the common 8px right inset.
|
|
208
208
|
20. Use the standard direct `Toolbar` composition for a panel, dialog, or page heading, not a private wrapper or custom heading row. Put an optional icon in a `ToolbarControlGroup`, the title directly in the leading zone as extra-large `ToolbarText`, and actions in a trailing group. Set `headingLevel` for page/section landmarks. Supporting copy stays below the toolbar as app-owned content. The app owns modal behavior, focus, dismissal, command policy, ids, and action handling.
|
|
209
209
|
21. Space with the official five-step scale, picked by how connected two elements are — not by eye. `0` `--kui-space-none` = no separation (one unit); `4px` `--kui-space-2xs` = very minor air on a connected cluster; `8px` `--kui-space-xs` = standard, between elements within a group; `16px` `--kui-space-m` = minor, between homogeneous groups; `24px` `--kui-space-l` = major, between heterogeneous groups (the `.kui-content` rhythm). The 8px-vs-24px distinction is inside-a-group vs between-major-differing-regions. `--kui-space-s` (12px) and `--kui-space-xl` (32px) are off-scale exceptions. For `Row.gap`, `Grid.gap`, or `List.gap`, pass a finite shorthand such as `gap="xs"` or `gap="m"`; use `Spacer` for one intentional typed empty width/height or a flexible main-axis gap. When one token is insufficient, import typed builders from the CSS-free `@kerfjs/ui/css-values` subpath. Preserve property grammar: lengths for gap/Spacer/Skeleton geometry, `flex()` for Row/Grid/List flex, and a foreground color for choice icons: `uiColor()` with a `*-on-*` or text token (`success-on-quiet`, `text-quiet`) or `foregroundColorVar()`. Fill tokens (`*-fill-*`) are backgrounds, not foregrounds, and `SelectChoice.color` rejects them. Never cast between brands or emit raw row `style` declarations. `plus` is not standalone and must be wrapped in `calc`; `remify()` remains source-CSS syntax and is never a runtime prop value. See `docs/layout.md` "Spacing scale".
|
|
210
|
-
22. Pick a whole-screen layout from the opt-in, tree-shakeable subpaths by data + interaction + device, and derive responsiveness from `@kerfjs/ui/device-class`'s `deviceClass()` (`compact` = handset or portrait tablet = one pane at a time). Simple/flat → `NavStack` with one entry (single pane), plus `TabScaffold` (`@kerfjs/ui/tab-scaffold`, iOS bottom tabs, each tab its own `NavStack`) for 2–5 co-equal sections on `compact`; show an unread count on a tab with its `badge` (a number or short string, rendered as the top-trailing danger `Badge` on the icon) plus a localized `badgeLabel` ("3 unread", folded into the tab's name as "Inbox, 3 unread"), never by concatenating the count into `label` or restyling the badge; for new content without a count pass `badge: true` (the text-free dot) with its required `badgeLabel` ("New activity"). Drill-down → `NavStack` (`@kerfjs/ui/nav-stack`), upgrading to `SplitView` (`@kerfjs/ui/split-view`, list-detail) once both panes fit (`atLeast('tablet')` landscape); `SplitView` collapses to a `NavStack` on `compact`. Keep each stack's ordered views controlled; put view-specific bottom chrome on `NavStackView.bottomToolbar` (or use the component-level persistent fallback), then call `wireNavStack` so content slides while the active view's top and bottom chrome cross-fade and focus moves into the new top view/restores on pop. Mark a preferred initial heading or control with `data-nav-focus` when DOM order is not sufficient. The stack's top chrome is a real `Toolbar`: put a view's groups on `NavStackView.leading` / `center` / `toolbar` (trailing), and configure the bar through `toolbarConfig` (`ToolbarConfig` plus `label`, `titleSize`, `headingLevel`) and `backIcon` / `backText`, never with CSS. `SplitView` forwards both of its inner components: `resizable` takes the list `ResizableRegion`'s `separator`, `handleIcon`, `contentOverflow`, and collapse props (`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, `restorePosition`), and `compactStack` takes the compact stack's `toolbarConfig`, `backIcon`, `backText`, `hideToolbar`, `bottomToolbar`, plus `list` / `detail` view toolbars (`leading`, `center`, `toolbar`, `bottomToolbar`). Complex tool with peripheral panels → `Workbench` (`@kerfjs/ui/workbench`, collapsible rails + drawer) `atLeast('desktop')`, degrading to `NavStack`/overlays below. Workbench panels are fixed-size unless a panel opts in with `resizable` (`true` or `{ min, max }`); then render `size={sizeSignal.value}` and call `wireWorkbench(root, { id, panels: { leftRail: { size: sizeSignal, storageKey? } }, deviceClass })` from `@kerfjs/ui/wire-workbench` for pointer drags, arrow/Shift+arrow/Home/End on the separator, persistence, and no resizing on `compact` classes. Inline rails, fixed or resizable, leave the work area `mainMinSize` px of width (a `Workbench` prop, default 320, `0` off), and an inline bottom drawer leaves it `mainMinHeight` px of height (default 120, `0` off): resizable panels stop growing there, rails shrink in proportion when the Workbench narrows and the drawer when it gets shorter, so do not add your own main-area `min-width` / `min-height`. Rails present as overlays below the `narrow` Workbench container breakpoint (704px) by default — `responsiveOverlayAt: "compact"` moves that to 448px and `"never"` keeps a rail inline — and a bottom drawer opts in the same way; do not derive `presentation` from `deviceClass`, and overlays never resize. At compact widths an overlay rail fills the Workbench less a 44px dismiss strip (`--kui-workbench-overlay-dismiss-margin`) on the side away from its edge; `compactOverlay: "full"` makes one rail fill it. Pass each such panel's `collapsed` signal to `wireWorkbench` too (`panels: { leftRail: { collapsed: navCollapsed } }`, `size` optional) so the overlay is transient like `wireSidebar`'s compact overlay: it collapses when the breakpoint begins to apply (the inline state returns when it ends), takes focus on its first control and keeps Tab inside it while open, and closes on Escape or an outside press with focus returned to its toggle (give each toggle `aria-controls` naming its panel's derived id, `<workbench id>-left-rail` / `-right-rail` / `-bottom-drawer`, so a panel open at wire-up has a focus target too); opening one overlay closes the other open overlays, so they never cover each other's controls; do not hand-roll those listeners (`dismissOverlays: false` opts out of all of it, `exclusiveOverlays: false` of exclusivity only). Collapse stays the app's `collapsed` flag and keeps the size, so an expanded panel returns at its last size. Let the Workbench compose panel toolbars: give each panel `toolbar: { label, title?,
|
|
210
|
+
22. Pick a whole-screen layout from the opt-in, tree-shakeable subpaths by data + interaction + device, and derive responsiveness from `@kerfjs/ui/device-class`'s `deviceClass()` (`compact` = handset or portrait tablet = one pane at a time). Simple/flat → `NavStack` with one entry (single pane), plus `TabScaffold` (`@kerfjs/ui/tab-scaffold`, iOS bottom tabs, each tab its own `NavStack`) for 2–5 co-equal sections on `compact`; show an unread count on a tab with its `badge` (a number or short string, rendered as the top-trailing danger `Badge` on the icon) plus a localized `badgeLabel` ("3 unread", folded into the tab's name as "Inbox, 3 unread"), never by concatenating the count into `label` or restyling the badge; for new content without a count pass `badge: true` (the text-free dot) with its required `badgeLabel` ("New activity"). Drill-down → `NavStack` (`@kerfjs/ui/nav-stack`), upgrading to `SplitView` (`@kerfjs/ui/split-view`, list-detail) once both panes fit (`atLeast('tablet')` landscape); `SplitView` collapses to a `NavStack` on `compact`. Keep each stack's ordered views controlled; put view-specific bottom chrome on `NavStackView.bottomToolbar` (or use the component-level persistent fallback), then call `wireNavStack` so content slides while the active view's top and bottom chrome cross-fade and focus moves into the new top view/restores on pop. Mark a preferred initial heading or control with `data-nav-focus` when DOM order is not sufficient. The stack's top chrome is a real `Toolbar`: put a view's groups on `NavStackView.leading` / `center` / `toolbar` (trailing), and configure the bar through `toolbarConfig` (`ToolbarConfig` plus `label`, `titleSize`, `headingLevel`) and `backIcon` / `backText`, never with CSS. `SplitView` forwards both of its inner components: `resizable` takes the list `ResizableRegion`'s `separator`, `handleIcon`, `contentOverflow`, and collapse props (`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, `restorePosition`), and `compactStack` takes the compact stack's `toolbarConfig`, `backIcon`, `backText`, `hideToolbar`, `bottomToolbar`, plus `list` / `detail` view toolbars (`leading`, `center`, `toolbar`, `bottomToolbar`). Complex tool with peripheral panels → `Workbench` (`@kerfjs/ui/workbench`, collapsible rails + drawer) `atLeast('desktop')`, degrading to `NavStack`/overlays below. Workbench panels are fixed-size unless a panel opts in with `resizable` (`true` or `{ min, max }`); then render `size={sizeSignal.value}` and call `wireWorkbench(root, { id, panels: { leftRail: { size: sizeSignal, storageKey? } }, deviceClass })` from `@kerfjs/ui/wire-workbench` for pointer drags, arrow/Shift+arrow/Home/End on the separator, persistence, and no resizing on `compact` classes. Inline rails, fixed or resizable, leave the work area `mainMinSize` px of width (a `Workbench` prop, default 320, `0` off), and an inline bottom drawer leaves it `mainMinHeight` px of height (default 120, `0` off): resizable panels stop growing there, rails shrink in proportion when the Workbench narrows and the drawer when it gets shorter, so do not add your own main-area `min-width` / `min-height`. Rails present as overlays below the `narrow` Workbench container breakpoint (704px) by default — `responsiveOverlayAt: "compact"` moves that to 448px and `"never"` keeps a rail inline — and a bottom drawer opts in the same way; do not derive `presentation` from `deviceClass`, and overlays never resize. At compact widths an overlay rail fills the Workbench less a 44px dismiss strip (`--kui-workbench-overlay-dismiss-margin`) on the side away from its edge; `compactOverlay: "full"` makes one rail fill it. Pass each such panel's `collapsed` signal to `wireWorkbench` too (`panels: { leftRail: { collapsed: navCollapsed } }`, `size` optional) so the overlay is transient like `wireSidebar`'s compact overlay: it collapses when the breakpoint begins to apply (the inline state returns when it ends), takes focus on its first control and keeps Tab inside it while open, and closes on Escape or an outside press with focus returned to its toggle (give each toggle `aria-controls` naming its panel's derived id, `<workbench id>-left-rail` / `-right-rail` / `-bottom-drawer`, so a panel open at wire-up has a focus target too); opening one overlay closes the other open overlays, so they never cover each other's controls; do not hand-roll those listeners (`dismissOverlays: false` opts out of all of it, `exclusiveOverlays: false` of exclusivity only). Collapse stays the app's `collapsed` flag and keeps the size, so an expanded panel returns at its last size. Let the Workbench compose panel toolbars: give each panel `toolbar: { label, title?, leading?, center?, trailing?, toggle: { action, name, showLabel?, hideLabel? } }` and the work area `mainToolbar` (and `mainBottomToolbar` for a drawer). Each of these toolbars takes the `Toolbar`'s configuration (`ToolbarConfig`: `dividerSides`, `centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); configure a composed toolbar through those props (for example `dividerSides: ""` to drop its divider), never with CSS. Configure the composed panes and chrome lists the same way: a panel's `pane` (and `CollapsiblePanel`'s `pane`) and the Workbench's `mainPane` take `PaneConfig` (`contentElement`, `contentLabel`, `separators`, `safeAreaEdges` — for example `{ contentElement: "nav", contentLabel: "Files" }` for a navigator rail), and `mainHeaderList` / `mainFooterList` take `ListConfig` (`gap`, `hAlign`, `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Open, a panel's toolbar places groups in its leading, center, and trailing zones, with the toggle last; mark a ToolbarControlGroup relocateOnCollapse to keep it available when closed (pass marked groups directly or in arrays rather than JSX fragments); closed, marked groups follow zone order into the work area before the toggle — a left rail's lead `mainToolbar`, a right rail's end it, a drawer's trail `mainBottomToolbar` or float in a corner `FloatingToolbar` — and panel-only groups stay behind. A control sits near where its effect appears: a collapsed drawer's restore belongs in the bottom toolbar or a `FloatingToolbar` beside the drawer, not in a distant top toolbar. Do not hand-place panel toggles in the work-area toolbar or render a second copy, and handle only the toggle's `data-action`. A collapsed panel renders `inert` and `aria-hidden` by itself, on the rail/drawer and its content (its `restoreControl` stays outside and reachable), so do not add your own `tabindex`, `aria-hidden`, or `inert` to hide it. These are declarative (the app owns the stack/selection/collapsed/active state as signals) with disposer-returning `wire…` helpers; each stays out of the barrel, and its CSS-aware browser import loads the layout's CSS plus that of every component it renders (`Pane`, `Toolbar`, `List`, …), so do not hand-import `pane.css` or the other internal stylesheets; the companion `.css` subpath is only for pipelines without the `browser` condition. For a standalone collapsible rail or bottom drawer outside a full shell, use `CollapsiblePanel` + `CollapsiblePanelToggle` (`@kerfjs/ui/collapsible-panel`) with `wireSidebar` (`@kerfjs/ui/wire-sidebar`): the standard collapse animation and per-side icon convention (`PanelLeft*`/`PanelRight*`/`PanelBottom*`) plus toggle, focus, compact overlay, and persistence semantics. Give a standalone panel the same `toolbar` roles and render `CollapsiblePanelRelocated` in your work-area toolbar (first in leading for a left rail, last in trailing for a right rail, a bottom toolbar or a `FloatingToolbar` restoreControl for a drawer) instead of hand-placing a second toggle. A collapsed `CollapsiblePanel`, `ResizableRegion`, or Workbench panel renders `inert` and `aria-hidden` by itself, so do not hide collapsed content yourself either. Likewise an open side overlay (a Workbench rail overlay, a `wireSidebar` compact overlay, an overlay `CollapsiblePanel` or horizontal `ResizableRegion`) hides the covered work area's `FloatingToolbar`s and restore corners by itself until it closes, so do not hide them from overlay state. A compact overlay opens only on a user action: wire-up on a compact device and a wide-to-compact crossing collapse every panel, and a wide crossing restores the inline state. Seed the signal with `signal(device.value.compact)` and pass the panel's `inlineCollapsed` default so the first compact render has no overlay. Dialogs pick the same inner layout, then present per device class (full-screen modal on `compact`, inline on desktop). A list-detail dialog is a Workbench-shaped layout on roomy devices: a full-height list sidebar and a full-height main column, each a `Pane` with its own top `Toolbar`; the main column holds the primary xl title, the close control (`data-dialog="close"` in a `without-header` Web Awesome dialog), and the record actions, never a header spanning both columns. A top-level percentage-height shell needs a definite containing height: opt into `@kerfjs/ui/document.css` and put `.kui-app-root` on the one direct mount container, or provide equivalent application-owned geometry. The global baseline is deliberately absent from `styles.css` and component imports. See `docs/app-layouts.md`, `docs/document-baseline.md`, and `docs/collapsible-panel.md`.
|
|
211
211
|
23. Layouts and `Pane` are safe-area aware without configuration: backgrounds, separators, and dividers paint through a device's unsafe areas (a collapsible rail or drawer grows by the inset it docks to), content is padded only on the sides a region actually reaches, and block insets are scroll padding inside the scroller so first/last content can always be scrolled clear. Interior edges get nothing, and a collapsed rail hands its edge back to the center. Never add your own `env(safe-area-inset-*)` padding around a kerf layout or pane — that double-insets. In an app-owned arrangement of panes, pass `Pane.safeAreaEdges` (the sides that pane reaches; `[]` opts out); give an app bar or bottom bar that sits at a screen edge outside a Pane header or footer `Toolbar.safeAreaEdges` for the sides it reaches (for example `['block-start', 'inline-start', 'inline-end']`); the Workbench `mainToolbar` / `mainBottomToolbar` and panel `toolbar` configurations forward the same `safeAreaEdges` to their `Toolbar`. Do not set the internal `--kui-edge-inset-*` context yourself. The device insets are `--kui-safe-area-*` (defaulting to `env()`), overridable on `:root`. See `docs/app-layouts.md` "Safe areas".
|
|
212
212
|
|
|
213
213
|
Common mistakes:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.58` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
package/dist/catalog.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import './list.js';
|
|
|
11
11
|
import './css-values.js';
|
|
12
12
|
import './flex-alignment-4ms8ZbV8.js';
|
|
13
13
|
import './resizable-region.js';
|
|
14
|
-
import './panel-toolbar-
|
|
14
|
+
import './panel-toolbar-DqwtBxQL.js';
|
|
15
15
|
import './lucide-icon.js';
|
|
16
16
|
import 'lucide';
|
|
17
17
|
|
package/dist/catalog.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Workbench } from './chunk-
|
|
1
|
+
import { Workbench } from './chunk-2CCMJTVY.js';
|
|
2
2
|
|
|
3
3
|
import { PopupMenu } from './chunk-WLG6SSNT.js';
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@ import { Text } from './chunk-24PHKUR3.js';
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
import { ToolbarControlGroup, ToolbarActionLink } from './chunk-
|
|
20
|
+
import { ToolbarControlGroup, ToolbarActionLink } from './chunk-7JUBXOIV.js';
|
|
21
21
|
import { Toolbar } from './chunk-6YFHCLHG.js';
|
|
22
22
|
|
|
23
23
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
@@ -2,7 +2,7 @@ import { WORKBENCH_MAIN_MIN_SIZE, WORKBENCH_MAIN_MIN_HEIGHT, workbenchRegionId,
|
|
|
2
2
|
import { clampRegionSize, ResizeGrip } from './chunk-VHADGP3B.js';
|
|
3
3
|
import { List } from './chunk-NAPE7WUS.js';
|
|
4
4
|
import { FloatingToolbar } from './chunk-M7QV3IHH.js';
|
|
5
|
-
import { composedPanelBody, relocatedPanelGroups } from './chunk-
|
|
5
|
+
import { composedPanelBody, relocatedPanelGroups } from './chunk-QPUPLNNB.js';
|
|
6
6
|
import { Toolbar } from './chunk-6YFHCLHG.js';
|
|
7
7
|
import { Pane } from './chunk-EZVNC4J6.js';
|
|
8
8
|
import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
|
|
@@ -415,4 +415,4 @@ function Workbench({
|
|
|
415
415
|
|
|
416
416
|
export { Workbench };
|
|
417
417
|
|
|
418
|
-
//# sourceMappingURL=chunk-
|
|
418
|
+
//# sourceMappingURL=chunk-2CCMJTVY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workbench-toolbars.tsx","../src/workbench.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-2CCMJTVY.js","sourcesContent":["import {\n FloatingToolbar,\n type FloatingToolbarPosition,\n} from './floating-toolbar.js';\nimport { List, type ListConfig } from './list.js';\nimport { Pane, type PaneConfig } from './pane.js';\nimport {\n composedPanelBody,\n type PanelSide,\n type PanelToggle,\n type PanelToggleAttributes,\n type PanelToolbar,\n relocatedPanelGroups,\n} from './panel-toolbar.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport { Toolbar, type ToolbarConfig } from './toolbar.js';\nimport {\n type WorkbenchPanelKey,\n workbenchRegionId,\n} from './workbench-resize.js';\n\n/** The standard toggle a Workbench renders for a panel (see {@link PanelToggle}). */\nexport type WorkbenchPanelToggle = PanelToggle;\n\n/**\n * A Workbench panel's top toolbar, composed by the Workbench so its groups can\n * follow the panel's open state (see {@link PanelToolbar} for the roles).\n * A collapsed rail's marked groups and toggle go to the leading edge of\n * `mainToolbar` (left rail) or its trailing edge (right rail); a collapsed\n * drawer's go to the trailing edge of `mainBottomToolbar`, else to a\n * `FloatingToolbar` in the work area's bottom-end corner.\n */\nexport type WorkbenchPanelToolbar = PanelToolbar;\n\n/**\n * The work area's top toolbar; collapsed rails add their groups to it. Its\n * configuration forwards to its `Toolbar`. It draws no divider of its own by\n * default: the work area's `Pane` draws one under its header chrome, wherever\n * that chrome ends, while `main` is scrolled (`mainPane.chromeDividers`).\n */\nexport interface WorkbenchMainToolbar extends ToolbarConfig {\n label: string;\n /** The work area's title, usually an extra-large `ToolbarText`. */\n title?: KerfUiContent;\n /** Groups after the title. */\n leading?: KerfUiContent;\n center?: KerfUiContent;\n /** Groups at the trailing edge, before a collapsed right rail's groups. */\n trailing?: KerfUiContent;\n}\n\n/**\n * The work area's bottom toolbar; a collapsed drawer adds its groups to it.\n * Its configuration forwards to its `Toolbar`. It draws no divider of its own\n * by default: the work area's `Pane` draws one over its footer chrome while\n * more of `main` lies below (`mainPane.chromeDividers`).\n */\nexport interface WorkbenchMainBottomToolbar extends ToolbarConfig {\n label: string;\n leading?: KerfUiContent;\n center?: KerfUiContent;\n trailing?: KerfUiContent;\n}\n\nconst SIDES: Record<WorkbenchPanelKey, PanelSide> = {\n leftRail: 'left',\n rightRail: 'right',\n bottomDrawer: 'bottom',\n};\n\n/** A panel as far as its toolbar is concerned. */\nexport interface WorkbenchToolbarPanel {\n toolbar?: WorkbenchPanelToolbar;\n footer?: KerfUiContent;\n /** Configuration for the `Pane` a `toolbar` panel's content renders in. */\n pane?: PaneConfig;\n content: KerfUiContent;\n collapsed?: boolean;\n /** The corner a collapsed panel's restore controls float in. */\n restorePosition?: FloatingToolbarPosition;\n}\n\n/** A Workbench toggle's wiring hooks: its side, morph key, and panel. */\nconst toggleAttributes = (\n workbenchId: string,\n key: WorkbenchPanelKey,\n): PanelToggleAttributes => ({\n 'data-workbench-toggle': SIDES[key],\n // Keyed, so the morph removes a toggle that leaves a toolbar instead of\n // reusing its (possibly focused) button for a different control.\n 'data-key': `${workbenchRegionId(workbenchId, key)}-toggle`,\n 'aria-controls': workbenchRegionId(workbenchId, key),\n});\n\n/**\n * The groups a collapsed panel hands to the work area: its marked groups,\n * then its toggle. Empty while the panel is open or has no toolbar.\n */\nexport function relocatedGroups(\n workbenchId: string,\n key: WorkbenchPanelKey,\n panel: WorkbenchToolbarPanel | undefined,\n): KerfUiContent[] {\n return relocatedPanelGroups(\n panel?.toolbar,\n SIDES[key],\n Boolean(panel?.collapsed),\n toggleAttributes(workbenchId, key),\n );\n}\n\n/**\n * A panel's content, wrapped in a `Pane` under its composed toolbar when it\n * has one (with its optional `footer` below). Without a toolbar the content\n * renders as given.\n */\nexport function panelBody(\n workbenchId: string,\n key: WorkbenchPanelKey,\n panel: WorkbenchToolbarPanel,\n) {\n const toolbar = panel.toolbar;\n if (!toolbar) return panel.content;\n return composedPanelBody({\n toolbar,\n side: SIDES[key],\n collapsed: Boolean(panel.collapsed),\n attributes: toggleAttributes(workbenchId, key),\n pane: panel.pane,\n footer: panel.footer,\n content: panel.content,\n });\n}\n\n/**\n * The work area's `mainHeader` / `mainFooter` chrome in a `List` carrying the\n * app's configuration; an omitted or `undefined` field keeps the `List`\n * default (no divider: the work area's `Pane` draws its chrome dividers).\n */\nfunction chromeList(content: KerfUiContent, config: ListConfig | undefined) {\n return (\n <List\n dividerSides={config?.dividerSides}\n gap={config?.gap}\n hAlign={config?.hAlign}\n vAlign={config?.vAlign}\n textInsets={config?.textInsets}\n controlInsets={config?.controlInsets}\n >\n {content}\n </List>\n );\n}\n\n/**\n * Whether the work area's header or footer chrome stays pinned (`fixed`),\n * scrolls away with the content (`scroll`), or stays pinned while the work\n * area is tall enough and scrolls with the content when it is short (`auto`,\n * the Pane's `chromePlacement=\"auto\"`; it applies to the pinned header and\n * footer together).\n */\nexport type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';\n\n/**\n * The work area: the app's `main` in a `Pane` (configured by `mainPane`)\n * under `mainToolbar` and any `mainHeader` list, and above any `mainFooter`\n * list and `mainBottomToolbar` (the header and footer lists configured by\n * `mainHeaderList` / `mainFooterList`), with each collapsed panel's groups\n * added to the toolbar on its side. Without any of that chrome, `main`\n * renders as given and `mainPane` is ignored.\n */\nexport function mainBody({\n workbenchId,\n main,\n mainToolbar,\n mainHeader,\n mainFooter,\n mainBottomToolbar,\n mainHeaderPlacement = 'fixed',\n mainFooterPlacement = 'fixed',\n mainPane,\n mainHeaderList,\n mainFooterList,\n leftRail,\n rightRail,\n bottomDrawer,\n}: {\n workbenchId: string;\n main: KerfUiContent;\n mainToolbar?: WorkbenchMainToolbar;\n mainHeader?: KerfUiContent;\n mainFooter?: KerfUiContent;\n mainBottomToolbar?: WorkbenchMainBottomToolbar;\n mainHeaderPlacement?: WorkbenchChromePlacement;\n mainFooterPlacement?: WorkbenchChromePlacement;\n mainPane?: PaneConfig;\n mainHeaderList?: ListConfig;\n mainFooterList?: ListConfig;\n leftRail?: WorkbenchToolbarPanel;\n rightRail?: WorkbenchToolbarPanel;\n bottomDrawer?: WorkbenchToolbarPanel;\n}) {\n if (!mainToolbar && !mainBottomToolbar && !mainHeader && !mainFooter)\n return main;\n const left = relocatedGroups(workbenchId, 'leftRail', leftRail);\n const right = relocatedGroups(workbenchId, 'rightRail', rightRail);\n const drawer = mainBottomToolbar\n ? relocatedGroups(workbenchId, 'bottomDrawer', bottomDrawer)\n : [];\n // The Pane draws one divider under the header chrome and one over the\n // footer chrome, wherever that chrome ends, from the scroll state.\n const header =\n !mainToolbar && !mainHeader ? undefined : (\n <>\n {mainToolbar ? (\n <Toolbar\n label={mainToolbar.label}\n dividerSides={mainToolbar.dividerSides}\n centerAlign={mainToolbar.centerAlign}\n responsive={mainToolbar.responsive}\n responsiveAt={mainToolbar.responsiveAt}\n safeAreaEdges={mainToolbar.safeAreaEdges}\n leading={\n <>\n {left}\n {mainToolbar.title}\n {mainToolbar.leading}\n </>\n }\n center={mainToolbar.center}\n trailing={\n <>\n {mainToolbar.trailing}\n {right}\n </>\n }\n />\n ) : null}\n {mainHeader ? chromeList(mainHeader, mainHeaderList) : null}\n </>\n );\n const footer =\n !mainFooter && !mainBottomToolbar ? undefined : (\n <>\n {mainFooter ? chromeList(mainFooter, mainFooterList) : null}\n {mainBottomToolbar ? (\n <Toolbar\n label={mainBottomToolbar.label}\n dividerSides={mainBottomToolbar.dividerSides}\n centerAlign={mainBottomToolbar.centerAlign}\n responsive={mainBottomToolbar.responsive}\n responsiveAt={mainBottomToolbar.responsiveAt}\n safeAreaEdges={mainBottomToolbar.safeAreaEdges}\n leading={mainBottomToolbar.leading}\n center={mainBottomToolbar.center}\n trailing={\n <>\n {mainBottomToolbar.trailing}\n {drawer}\n </>\n }\n />\n ) : null}\n </>\n );\n const scrollHeader = mainHeaderPlacement === 'scroll';\n const scrollFooter = mainFooterPlacement === 'scroll';\n return (\n <Pane\n header={scrollHeader ? undefined : header}\n footer={scrollFooter ? undefined : footer}\n chromePlacement={\n mainHeaderPlacement === 'auto' || mainFooterPlacement === 'auto'\n ? 'auto'\n : 'fixed'\n }\n contentElement={mainPane?.contentElement}\n contentLabel={mainPane?.contentLabel}\n separators={mainPane?.separators}\n safeAreaEdges={mainPane?.safeAreaEdges}\n chromeDividers={mainPane?.chromeDividers}\n >\n {scrollHeader || scrollFooter ? (\n // Chrome that scrolls joins the content in one gapless column that\n // fills the scroller, so it scrolls away with the content.\n <List flex>\n {scrollHeader ? header : null}\n {main}\n {scrollFooter ? footer : null}\n </List>\n ) : (\n main\n )}\n </Pane>\n );\n}\n\n/**\n * A collapsed panel's groups when the work area has no toolbar on its side\n * to take them: a `FloatingToolbar` for the panel's restore corner, so the\n * panel can always be reopened.\n */\nexport function floatingRestore(\n workbenchId: string,\n key: WorkbenchPanelKey,\n panel: WorkbenchToolbarPanel | undefined,\n hasTargetToolbar: boolean,\n) {\n if (hasTargetToolbar) return undefined;\n const groups = relocatedGroups(workbenchId, key, panel);\n if (groups.length === 0) return undefined;\n return (\n <FloatingToolbar\n label={panel!.toolbar!.label}\n position={\n panel!.restorePosition ??\n (key === 'leftRail' ? 'bottom-start' : 'bottom-end')\n }\n >\n {groups}\n </FloatingToolbar>\n );\n}\n","import type { SafeHtml } from 'kerfjs';\n\nimport type { ListConfig } from './list.js';\nimport type { PaneConfig } from './pane.js';\nimport {\n clampRegionSize,\n type ResizableRegionAxis,\n type ResizableRegionCollapseMotion,\n type ResizableRegionContentOverflow,\n type ResizableRegionEdge,\n type ResizableRegionPresentation,\n type ResizableRegionRestorePosition,\n type ResizableRegionSeparator,\n} from './resizable-region.js';\nimport { ResizeGrip } from './resize-grip.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport {\n WORKBENCH_MAIN_MIN_HEIGHT,\n WORKBENCH_MAIN_MIN_SIZE,\n WORKBENCH_RESIZE_DEFAULTS,\n type WorkbenchPanelKey,\n workbenchRegionId,\n} from './workbench-resize.js';\nimport {\n floatingRestore,\n mainBody,\n panelBody,\n type WorkbenchChromePlacement,\n type WorkbenchMainBottomToolbar,\n type WorkbenchMainToolbar,\n type WorkbenchPanelToolbar,\n} from './workbench-toolbars.js';\n\nexport type {\n WorkbenchChromePlacement,\n WorkbenchMainBottomToolbar,\n WorkbenchMainToolbar,\n WorkbenchPanelToggle,\n WorkbenchPanelToolbar,\n} from './workbench-toolbars.js';\n\n/**\n * The Workbench container breakpoint below which a panel presents as an\n * overlay: `narrow` (704px or less) or `compact` (448px or less) — the same\n * breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep\n * it inline at every width.\n */\nexport type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';\n\n/**\n * How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`\n * fills the Workbench less a dismiss margin on the side away from the rail's\n * edge, so a press beside it closes it; `full` fills the Workbench.\n */\nexport type WorkbenchCompactOverlay = 'inset' | 'full';\n\n/** Drag-resize limits for a resizable Workbench panel, in px. */\nexport interface WorkbenchPanelResizable {\n /** Smallest size (default 180 for a rail, 120 for the drawer). */\n min?: number;\n /** Largest size (default 480). */\n max?: number;\n}\n\n/** A collapsible Workbench panel — a side rail or the bottom drawer. */\nexport interface WorkbenchPanel {\n content: KerfUiContent;\n /**\n * The panel's top toolbar, composed by the Workbench: its marked groups\n * and standard `toggle` move to the work area's toolbar while the panel is\n * collapsed. With it, `content` renders in a `Pane` below the toolbar.\n */\n toolbar?: WorkbenchPanelToolbar;\n /** Optional bottom toolbar under a `toolbar` panel's content. */\n footer?: KerfUiContent;\n /**\n * Configuration for a `toolbar` panel's `Pane` (`contentElement`,\n * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example\n * `{ contentElement: 'nav', contentLabel: 'Sections' }` for a navigation\n * rail. Omitted or `undefined` fields keep the `Pane` defaults. Ignored\n * without a `toolbar`, where `content` renders as given.\n */\n pane?: PaneConfig;\n /** Whether the panel is currently collapsed (the app owns this). */\n collapsed?: boolean;\n /**\n * Rail width, or drawer height, in px. Overrides the CSS default. For a\n * resizable panel it is the current size (default 280 for a rail, 220 for\n * the drawer), clamped to the limits; the app owns it and `wireWorkbench`\n * reports each resize.\n */\n size?: number;\n /**\n * Opt in to drag and keyboard resizing on the panel's inner separator:\n * `true` for the default limits, or `{ min, max }`. Off by default. Pair it\n * with `wireWorkbench` from `@kerfjs/ui/wire-workbench`.\n */\n resizable?: boolean | WorkbenchPanelResizable;\n /** Accessible name for the panel region. */\n label?: string;\n separator?: ResizableRegionSeparator;\n collapseMotion?: ResizableRegionCollapseMotion;\n contentOverflow?: ResizableRegionContentOverflow;\n presentation?: ResizableRegionPresentation;\n /**\n * Present the panel as an overlay, without a separator, below a Workbench\n * container breakpoint, and inline above it — the CSS decides, so the app\n * needs no device-class check. A rail overlays from its side at full\n * height, over the work area and an open drawer; the bottom drawer\n * overlays the bottom of the work-area column. Rails default to `narrow`\n * (pass `never` to keep one inline); the drawer defaults to inline.\n */\n responsiveOverlayAt?: WorkbenchResponsiveOverlayAt;\n /**\n * A rail's overlay width in a compact Workbench (default `inset`: the\n * Workbench less `--kui-workbench-overlay-dismiss-margin`, 44px). Ignored\n * by the drawer.\n */\n compactOverlay?: WorkbenchCompactOverlay;\n /**\n * Control shown while collapsed, in a safe-area-aware corner of the\n * Workbench (not the viewport); the bottom drawer's sits in the work-area\n * column. Prefer `toolbar.toggle`, which the Workbench relocates into the\n * work area's toolbar (or this corner when that toolbar is absent).\n */\n restoreControl?: SafeHtml;\n restorePosition?: ResizableRegionRestorePosition;\n}\n\nexport interface WorkbenchProps {\n /**\n * The Workbench's `id`. Each panel's `id` derives from it —\n * `<id>-left-rail`, `<id>-right-rail`, `<id>-bottom-drawer` — so a toggle\n * can name the panel it shows and hides with `aria-controls`.\n */\n id: string;\n label: string;\n /** The central work area. */\n main: KerfUiContent;\n /**\n * The work area's top toolbar. A collapsed left rail's marked groups\n * and toggle lead it; a collapsed right rail's trail it. With it, `main`\n * renders in a `Pane` below the toolbar.\n */\n mainToolbar?: WorkbenchMainToolbar;\n /**\n * Fixed content under `mainToolbar` — supporting copy such as a\n * description — divided from the scrolling `main` below it.\n */\n mainHeader?: KerfUiContent;\n /**\n * Fixed content over `mainBottomToolbar` — a status line or a resource\n * toolbar — divided from the scrolling `main` above it.\n */\n mainFooter?: KerfUiContent;\n /**\n * The work area's bottom toolbar. A collapsed drawer's marked groups and\n * toggle trail it; without it they float in the work area's corner.\n */\n mainBottomToolbar?: WorkbenchMainBottomToolbar;\n /**\n * Whether `mainToolbar` and `mainHeader` stay pinned (`fixed`, default),\n * scroll away with `main` (`scroll`) — useful where large text would leave\n * pinned chrome little room — or stay pinned while the work area is tall\n * enough and scroll with `main` when it is short (`auto`).\n */\n mainHeaderPlacement?: WorkbenchChromePlacement;\n /** The same for `mainFooter` and `mainBottomToolbar` (default `fixed`). */\n mainFooterPlacement?: WorkbenchChromePlacement;\n /**\n * Configuration for the work area's `Pane` (`contentElement`,\n * `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`), which it has whenever it\n * has a toolbar, `mainHeader`, or `mainFooter`; without that chrome, `main`\n * renders as given and this is ignored. Omitted or `undefined` fields keep\n * the `Pane` defaults.\n */\n mainPane?: PaneConfig;\n /**\n * Configuration for the `List` that holds `mainHeader` (`gap`, `hAlign`,\n * `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Omitted or\n * `undefined` fields keep the defaults (no divider: the work area's\n * `Pane` draws the line under its header chrome).\n */\n mainHeaderList?: ListConfig;\n /**\n * The same for the `List` that holds `mainFooter` (no divider by default:\n * the work area's `Pane` draws the line over its footer chrome).\n */\n mainFooterList?: ListConfig;\n leftRail?: WorkbenchPanel;\n rightRail?: WorkbenchPanel;\n bottomDrawer?: WorkbenchPanel;\n /**\n * Minimum width, in px, the work area keeps beside the inline rails, fixed\n * or `resizable` (default 320; `0` turns it off). Resizing a rail stops\n * where the work area would drop below it, and inline rails shrink\n * proportionally when the Workbench gets narrower. Workbenches without a\n * rail ignore it.\n */\n mainMinSize?: number;\n /**\n * Minimum height, in px, the work area keeps above an inline bottom drawer,\n * fixed or `resizable` (default 120; `0` turns it off) — the drawer's\n * counterpart of `mainMinSize`. Resizing the drawer stops where the work\n * area would drop below it, and the drawer shrinks when the Workbench gets\n * shorter. Workbenches without a drawer ignore it.\n */\n mainMinHeight?: number;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\ninterface ResolvedResize {\n regionId: string;\n axis: ResizableRegionAxis;\n edge: ResizableRegionEdge;\n size: number;\n min: number;\n max: number;\n}\n\n/**\n * Each panel's separator is its inner edge. Growing the left rail moves that\n * edge toward the inline end; growing the right rail or the drawer moves it\n * toward the start — the same edge vocabulary `ResizableRegion` uses.\n */\nconst EDGES: Record<WorkbenchPanelKey, ResizableRegionEdge> = {\n leftRail: 'end',\n rightRail: 'start',\n bottomDrawer: 'start',\n};\n\nconst DEFAULT_LABELS: Record<WorkbenchPanelKey, string> = {\n leftRail: 'left rail',\n rightRail: 'right rail',\n bottomDrawer: 'bottom drawer',\n};\n\nfunction resolveResize(\n id: string,\n key: WorkbenchPanelKey,\n panel: WorkbenchPanel,\n): ResolvedResize | undefined {\n if (!panel.resizable) return undefined;\n const defaults = WORKBENCH_RESIZE_DEFAULTS[key];\n const limits = panel.resizable === true ? {} : panel.resizable;\n const min = limits.min ?? defaults.min;\n const max = Math.max(min, limits.max ?? defaults.max);\n return {\n regionId: workbenchRegionId(id, key),\n axis: key === 'bottomDrawer' ? 'vertical' : 'horizontal',\n edge: EDGES[key],\n size: clampRegionSize(panel.size ?? defaults.size, min, max),\n min,\n max,\n };\n}\n\n/** The attributes a resizable panel adds for the resize wiring to read. */\nconst resizeAttributes = (resize: ResolvedResize | undefined) =>\n resize\n ? {\n 'data-resizable': 'true',\n 'data-region-id': resize.regionId,\n 'data-axis': resize.axis,\n 'data-edge': resize.edge,\n }\n : {};\n\n/**\n * A resizable panel's size lives in the resize wiring's track property, so a\n * drag or key press resizes the panel before the app re-renders; the CSS maps\n * it onto the rail width or drawer height.\n */\nfunction panelStyle(\n panel: WorkbenchPanel,\n resize: ResolvedResize | undefined,\n sizeProperty: string,\n) {\n if (resize) return `--kui-resizable-region-size:${resize.size}px`;\n return panel.size ? `${sizeProperty}: ${panel.size}px` : undefined;\n}\n\n/**\n * The separator a resizable panel owns: the same focusable `role=\"separator\"`\n * contract a `ResizableRegion` handle carries, so one resize wiring drives\n * both. It leaves the tab order while the panel is collapsed or not inline.\n */\nfunction PanelHandle({\n panel,\n resize,\n label,\n}: {\n panel: WorkbenchPanel;\n resize: ResolvedResize;\n label: string;\n}) {\n const inert =\n Boolean(panel.collapsed) || (panel.presentation ?? 'inline') !== 'inline';\n return (\n <div\n class=\"kui-workbench__handle\"\n role=\"separator\"\n tabindex={inert ? '-1' : '0'}\n aria-label={`Resize ${label}`}\n aria-orientation={\n resize.axis === 'horizontal' ? 'vertical' : 'horizontal'\n }\n aria-valuemin={resize.min}\n aria-valuemax={resize.max}\n aria-valuenow={resize.size}\n aria-hidden={inert ? 'true' : undefined}\n data-kui-resize-handle\n data-region-id={resize.regionId}\n >\n <span class=\"kui-workbench__handle-icon\" aria-hidden=\"true\">\n <ResizeGrip axis={resize.axis} />\n </span>\n </div>\n );\n}\n\n/**\n * A collapsed panel leaves the accessibility tree as a whole, like a collapsed\n * `CollapsiblePanel`: its content and separator are already inert or hidden,\n * so the labeled landmark would otherwise stay behind, empty, for a screen\n * reader to land on. Its restore control renders outside it and stays\n * reachable.\n */\nfunction hiddenFromAccessibility(panel: WorkbenchPanel) {\n return panel.collapsed || panel.presentation === 'hidden'\n ? ('true' as const)\n : undefined;\n}\n\n/** A breakpoint's attribute value; `never` (or none) renders no attribute. */\nconst responsiveAt = (at: WorkbenchResponsiveOverlayAt | undefined) =>\n at === 'never' ? undefined : at;\n\nfunction Rail({\n id,\n side,\n panel,\n}: {\n id: string;\n side: 'left' | 'right';\n panel: WorkbenchPanel;\n}) {\n const key: WorkbenchPanelKey = side === 'left' ? 'leftRail' : 'rightRail';\n const resize = resolveResize(id, key, panel);\n return (\n <aside\n id={workbenchRegionId(id, key)}\n class={`kui-workbench__rail kui-workbench__rail--${side}`}\n data-workbench-rail={side}\n data-collapsed={String(panel.collapsed ?? false)}\n data-separator={panel.separator ?? 'auto'}\n data-collapse-motion={panel.collapseMotion ?? 'slide'}\n data-content-overflow={panel.contentOverflow ?? 'clip'}\n data-presentation={panel.presentation ?? 'inline'}\n data-responsive-overlay-at={responsiveAt(\n panel.responsiveOverlayAt ?? 'narrow',\n )}\n data-compact-overlay={panel.compactOverlay ?? 'inset'}\n {...resizeAttributes(resize)}\n aria-label={panel.label || undefined}\n aria-hidden={hiddenFromAccessibility(panel)}\n inert={Boolean(panel.collapsed)}\n style={panelStyle(panel, resize, '--kui-workbench-rail-width')}\n >\n <div\n class=\"kui-workbench__panel-content\"\n data-workbench-panel-content\n inert={Boolean(panel.collapsed)}\n >\n {panelBody(id, key, panel)}\n </div>\n {resize && (\n <PanelHandle\n panel={panel}\n resize={resize}\n label={panel.label || DEFAULT_LABELS[key]}\n />\n )}\n </aside>\n );\n}\n\nfunction Drawer({ id, panel }: { id: string; panel: WorkbenchPanel }) {\n const resize = resolveResize(id, 'bottomDrawer', panel);\n return (\n <section\n id={workbenchRegionId(id, 'bottomDrawer')}\n class=\"kui-workbench__drawer\"\n data-workbench-drawer\n data-collapsed={String(panel.collapsed ?? false)}\n data-separator={panel.separator ?? 'auto'}\n data-collapse-motion={panel.collapseMotion ?? 'slide'}\n data-content-overflow={panel.contentOverflow ?? 'clip'}\n data-presentation={panel.presentation ?? 'inline'}\n data-responsive-overlay-at={responsiveAt(panel.responsiveOverlayAt)}\n {...resizeAttributes(resize)}\n aria-label={panel.label || undefined}\n aria-hidden={hiddenFromAccessibility(panel)}\n inert={Boolean(panel.collapsed)}\n style={panelStyle(panel, resize, '--kui-workbench-drawer-height')}\n >\n <div\n class=\"kui-workbench__panel-content\"\n data-workbench-panel-content\n inert={Boolean(panel.collapsed)}\n >\n {panelBody(id, 'bottomDrawer', panel)}\n </div>\n {resize && (\n <PanelHandle\n panel={panel}\n resize={resize}\n label={panel.label || DEFAULT_LABELS.bottomDrawer}\n />\n )}\n </section>\n );\n}\n\n/** A collapsed panel's restore control, outside the clipped panel. */\nfunction restore(\n panel: WorkbenchPanel | undefined,\n side: 'left' | 'right' | 'bottom',\n position: ResizableRegionRestorePosition,\n generated: SafeHtml | undefined,\n) {\n const control = panel?.restoreControl ?? generated;\n if (!panel?.collapsed || !control || panel.presentation === 'hidden')\n return '';\n return (\n <div\n class=\"kui-workbench__restore\"\n data-panel={side}\n data-position={panel.restorePosition ?? position}\n >\n {control}\n </div>\n );\n}\n\n/**\n * The Xcode-like multi-panel workspace: a collapsible left rail, right rail, and\n * bottom drawer around a central work area (any absent). Collapsing snaps the\n * panel's track to zero in one reflow while its fixed-size content slides out via\n * a composited transform — the instant-width / sliding-content technique, so the\n * work area relayouts once, not per frame. Bottom-drawer content stays anchored\n * to the shell's stable bottom edge throughout that transition. The app owns\n * each `collapsed` flag; the collapse is pure CSS. A collapsed panel renders\n * `inert` and `aria-hidden`, so neither Tab nor assistive technology reaches\n * controls that have slid out of view or an empty landmark (its restore control\n * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with\n * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.\n */\nexport function Workbench({\n id,\n label,\n main,\n leftRail,\n rightRail,\n bottomDrawer,\n mainToolbar,\n mainHeader,\n mainFooter,\n mainBottomToolbar,\n mainHeaderPlacement,\n mainFooterPlacement,\n mainPane,\n mainHeaderList,\n mainFooterList,\n mainMinSize = WORKBENCH_MAIN_MIN_SIZE,\n mainMinHeight = WORKBENCH_MAIN_MIN_HEIGHT,\n className = '',\n slot,\n}: WorkbenchProps) {\n // Each work-area minimum applies only on an axis a panel shares with it:\n // the width beside a rail, the height above the drawer.\n const px = (value: number) => Math.max(0, Math.round(value));\n const mainMin = leftRail || rightRail ? px(mainMinSize) : undefined;\n const mainMinBlock = bottomDrawer ? px(mainMinHeight) : undefined;\n const style = [\n mainMin === undefined ? '' : `--_kui-workbench-main-min-width:${mainMin}px`,\n mainMinBlock === undefined\n ? ''\n : `--_kui-workbench-main-min-height:${mainMinBlock}px`,\n ]\n .filter(Boolean)\n .join(';');\n return (\n <section\n class={`kui-workbench ${className}`.trim()}\n id={id}\n data-component=\"workbench\"\n data-main-min-size={mainMin === undefined ? undefined : String(mainMin)}\n data-main-min-height={\n mainMinBlock === undefined ? undefined : String(mainMinBlock)\n }\n style={style || undefined}\n aria-label={label}\n slot={slot}\n >\n {leftRail && <Rail id={id} side=\"left\" panel={leftRail} />}\n {restore(\n leftRail,\n 'left',\n 'bottom-start',\n floatingRestore(id, 'leftRail', leftRail, Boolean(mainToolbar)),\n )}\n <div class=\"kui-workbench__center\">\n <div class=\"kui-workbench__main\" data-workbench-main>\n {mainBody({\n workbenchId: id,\n main,\n mainToolbar,\n mainHeader,\n mainFooter,\n mainBottomToolbar,\n mainHeaderPlacement,\n mainFooterPlacement,\n mainPane,\n mainHeaderList,\n mainFooterList,\n leftRail,\n rightRail,\n bottomDrawer,\n })}\n </div>\n {bottomDrawer && <Drawer id={id} panel={bottomDrawer} />}\n {restore(\n bottomDrawer,\n 'bottom',\n 'bottom-end',\n floatingRestore(\n id,\n 'bottomDrawer',\n bottomDrawer,\n Boolean(mainBottomToolbar),\n ),\n )}\n </div>\n {rightRail && <Rail id={id} side=\"right\" panel={rightRail} />}\n {restore(\n rightRail,\n 'right',\n 'bottom-end',\n floatingRestore(id, 'rightRail', rightRail, Boolean(mainToolbar)),\n )}\n </section>\n );\n}\n"]}
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import { isSafeHtml } from 'kerfjs';
|
|
1
2
|
import { jsxs, jsx } from 'kerfjs/jsx-runtime';
|
|
2
3
|
|
|
3
|
-
// src/toolbar-
|
|
4
|
+
// src/panel-toolbar-group.ts
|
|
5
|
+
var RELOCATE_ON_COLLAPSE = /* @__PURE__ */ Symbol.for(
|
|
6
|
+
"@kerfjs/ui.ToolbarControlGroup.relocateOnCollapse"
|
|
7
|
+
);
|
|
8
|
+
function markRelocatableGroup(group) {
|
|
9
|
+
Object.defineProperty(group, RELOCATE_ON_COLLAPSE, { value: true });
|
|
10
|
+
return group;
|
|
11
|
+
}
|
|
12
|
+
function isRelocatableGroup(value) {
|
|
13
|
+
return isSafeHtml(value) && value[RELOCATE_ON_COLLAPSE] === true;
|
|
14
|
+
}
|
|
4
15
|
function ToolbarActionLink({
|
|
5
16
|
href,
|
|
6
17
|
label,
|
|
@@ -50,11 +61,12 @@ function ToolbarControlGroup({
|
|
|
50
61
|
menuInset = "standard",
|
|
51
62
|
overflow = "visible",
|
|
52
63
|
visibility = "always",
|
|
64
|
+
relocateOnCollapse = false,
|
|
53
65
|
scrim = false,
|
|
54
66
|
avatarImage,
|
|
55
67
|
slot
|
|
56
68
|
}) {
|
|
57
|
-
|
|
69
|
+
const group = /* @__PURE__ */ jsx(
|
|
58
70
|
"div",
|
|
59
71
|
{
|
|
60
72
|
class: `kui-toolbar-control-group ${className}`.trim(),
|
|
@@ -83,8 +95,9 @@ function ToolbarControlGroup({
|
|
|
83
95
|
children
|
|
84
96
|
}
|
|
85
97
|
);
|
|
98
|
+
return relocateOnCollapse ? markRelocatableGroup(group) : group;
|
|
86
99
|
}
|
|
87
100
|
|
|
88
|
-
export { ToolbarActionLink, ToolbarControlGroup };
|
|
101
|
+
export { ToolbarActionLink, ToolbarControlGroup, isRelocatableGroup };
|
|
89
102
|
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
103
|
+
//# sourceMappingURL=chunk-7JUBXOIV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/panel-toolbar-group.ts","../src/toolbar-control-group.tsx"],"names":[],"mappings":"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","file":"chunk-7JUBXOIV.js","sourcesContent":["import { isSafeHtml, type SafeHtml } from 'kerfjs';\n\n// A render-time annotation, shared across separately bundled UI subpaths.\n// It never appears in the DOM or changes the group's visual treatment.\nconst RELOCATE_ON_COLLAPSE = Symbol.for(\n '@kerfjs/ui.ToolbarControlGroup.relocateOnCollapse',\n);\n\nexport function markRelocatableGroup(group: SafeHtml): SafeHtml {\n Object.defineProperty(group, RELOCATE_ON_COLLAPSE, { value: true });\n return group;\n}\n\nexport function isRelocatableGroup(value: unknown): value is SafeHtml {\n return (\n isSafeHtml(value) &&\n (value as SafeHtml & { [RELOCATE_ON_COLLAPSE]?: boolean })[\n RELOCATE_ON_COLLAPSE\n ] === true\n );\n}\n","import { markRelocatableGroup } from './panel-toolbar-group.js';\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport type ToolbarControlGroupAppearance = 'contained' | 'borderless';\nexport type ToolbarControlGroupTone = 'default' | 'dark';\nexport type ToolbarControlGroupButtonAppearance = 'plain' | 'push';\nexport type ToolbarControlGroupShape = 'pill' | 'rounded';\nexport type ToolbarControlGroupSize = 'default' | 'compact';\nexport type ToolbarControlGroupDensity = 'comfortable' | 'tight';\nexport type ToolbarControlGroupContent =\n 'icon' | 'text' | 'mixed' | 'avatar' | 'search';\nexport type ToolbarControlGroupFocusRing = 'control' | 'outline' | 'halo';\nexport type ToolbarControlGroupSelectedChrome = 'raised' | 'filled' | 'outline';\nexport type ToolbarControlGroupSelectedTone = 'brand' | 'neutral' | 'pop';\nexport type ToolbarControlGroupOverflow = 'visible' | 'scroll';\nexport type ToolbarControlGroupMenuInset = 'standard' | 'compact' | 'list-zero';\nexport type ToolbarControlGroupVisibility = 'always' | 'compact-only';\n\nexport interface ToolbarActionLinkProps {\n href: string;\n label: string;\n icon?: KerfUiContent;\n /** Optional machine-readable detail hidden visually but included in the default accessible name. */\n detail?: string;\n /** Override the accessible name when surrounding context is needed. */\n ariaLabel?: string;\n /** Open in a new tab with a safe rel and announce that behavior. */\n external?: boolean;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/** A semantic anchor with ToolbarControlGroup-owned action geometry. */\nexport function ToolbarActionLink({\n href,\n label,\n icon,\n detail,\n ariaLabel,\n external = false,\n className = '',\n slot,\n}: ToolbarActionLinkProps) {\n const accessibleLabel =\n ariaLabel ??\n `${label}${detail ? `, ${detail}` : ''}${external ? ' (opens in new tab)' : ''}`;\n return (\n <a\n class={`kui-toolbar-action-link ${className}`.trim()}\n data-component=\"toolbar-action-link\"\n href={href}\n target={external ? '_blank' : undefined}\n rel={external ? 'noopener noreferrer' : undefined}\n aria-label={accessibleLabel}\n slot={slot}\n >\n {icon}\n <span>{label}</span>\n {detail ? <code aria-hidden=\"true\">{detail}</code> : null}\n </a>\n );\n}\n\nexport interface ToolbarControlGroupProps {\n children: KerfUiContent;\n label?: string;\n className?: string;\n expanded?: boolean;\n single?: boolean;\n appearance?: ToolbarControlGroupAppearance;\n tone?: ToolbarControlGroupTone;\n buttonAppearance?: ToolbarControlGroupButtonAppearance;\n /** Corner shape: fully round `pill` (default) or a softer `rounded` rectangle. */\n shape?: ToolbarControlGroupShape;\n size?: ToolbarControlGroupSize;\n density?: ToolbarControlGroupDensity;\n content?: ToolbarControlGroupContent;\n /** Whether controls paint focus individually or the group paints an outline/halo on focus-within. */\n focusRing?: ToolbarControlGroupFocusRing;\n selectedChrome?: ToolbarControlGroupSelectedChrome;\n selectedTone?: ToolbarControlGroupSelectedTone;\n /** Size a nested Web Awesome dropdown trigger as part of this group. */\n nestedDropdown?: boolean;\n /** Configure the nested dropdown menu inset without consumer ::part() CSS. */\n menuInset?: ToolbarControlGroupMenuInset;\n /** Keep an overlong row of actions inside the available width with horizontal scrolling. */\n overflow?: ToolbarControlGroupOverflow;\n /** Responsive visibility owned by the enclosing Toolbar container. */\n visibility?: ToolbarControlGroupVisibility;\n /** Move this group into the work-area toolbar when its panel collapses. */\n relocateOnCollapse?: boolean;\n /** Add contrast behind photo-backed avatar content. */\n scrim?: boolean;\n /**\n * Avatar image URL. A single-control group paints it on the group; a\n * multi-control group paints it only on the pressed selection highlight.\n */\n avatarImage?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\nexport function ToolbarControlGroup({\n children,\n label,\n className = '',\n expanded = false,\n single = false,\n appearance = 'contained',\n tone = 'default',\n buttonAppearance = 'plain',\n shape = 'pill',\n size = 'default',\n density = 'comfortable',\n content = 'icon',\n focusRing = 'control',\n selectedChrome = 'raised',\n selectedTone = 'brand',\n nestedDropdown = false,\n menuInset = 'standard',\n overflow = 'visible',\n visibility = 'always',\n relocateOnCollapse = false,\n scrim = false,\n avatarImage,\n slot,\n}: ToolbarControlGroupProps) {\n const group = (\n <div\n class={`kui-toolbar-control-group ${className}`.trim()}\n data-component=\"toolbar-control-group\"\n role={label ? 'group' : undefined}\n aria-label={label}\n data-appearance={appearance}\n data-tone={tone}\n data-button-appearance={buttonAppearance}\n data-expanded={String(expanded)}\n data-single={String(single)}\n data-shape={shape}\n data-size={size}\n data-density={density}\n data-content={content}\n data-focus-ring={focusRing}\n data-selected-chrome={selectedChrome}\n data-selected-tone={selectedTone}\n data-nested-dropdown={String(nestedDropdown)}\n data-menu-inset={menuInset}\n data-overflow={overflow}\n data-visibility={visibility}\n data-scrim={String(scrim)}\n style={\n avatarImage\n ? `--kui-toolbar-avatar-image:url(${JSON.stringify(avatarImage)})`\n : undefined\n }\n slot={slot}\n >\n {children}\n </div>\n );\n return relocateOnCollapse ? markRelocatableGroup(group) : group;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ToolbarControlGroup } from './chunk-
|
|
1
|
+
import { isRelocatableGroup, ToolbarControlGroup } from './chunk-7JUBXOIV.js';
|
|
2
2
|
import { Toolbar } from './chunk-6YFHCLHG.js';
|
|
3
3
|
import { Pane } from './chunk-EZVNC4J6.js';
|
|
4
4
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
@@ -39,10 +39,10 @@ function composedPanelToolbar(toolbar, side, collapsed, attributes) {
|
|
|
39
39
|
center: toolbar.center,
|
|
40
40
|
leading: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
41
|
toolbar.title,
|
|
42
|
-
toolbar.
|
|
42
|
+
toolbar.leading
|
|
43
43
|
] }),
|
|
44
44
|
trailing: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45
|
-
toolbar.
|
|
45
|
+
toolbar.trailing,
|
|
46
46
|
toolbar.toggle ? panelToggleGroup(side, toolbar.toggle, collapsed, attributes) : null
|
|
47
47
|
] })
|
|
48
48
|
}
|
|
@@ -73,12 +73,23 @@ function composedPanelBody({
|
|
|
73
73
|
}
|
|
74
74
|
function relocatedPanelGroups(toolbar, side, collapsed, attributes) {
|
|
75
75
|
if (!collapsed || !toolbar) return [];
|
|
76
|
+
const groups = [];
|
|
77
|
+
const collect = (content) => {
|
|
78
|
+
if (Array.isArray(content)) {
|
|
79
|
+
for (const item of content) collect(item);
|
|
80
|
+
} else if (isRelocatableGroup(content)) {
|
|
81
|
+
groups.push(content);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
collect(toolbar.leading);
|
|
85
|
+
collect(toolbar.center);
|
|
86
|
+
collect(toolbar.trailing);
|
|
76
87
|
return [
|
|
77
|
-
|
|
88
|
+
...groups,
|
|
78
89
|
toolbar.toggle ? panelToggleGroup(side, toolbar.toggle, true, attributes) : null
|
|
79
90
|
].filter((group) => group !== void 0 && group !== null && group !== false);
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
export { collapsiblePanelToggleIcon, composedPanelBody, relocatedPanelGroups };
|
|
83
94
|
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
95
|
+
//# sourceMappingURL=chunk-QPUPLNNB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/panel-toolbar.tsx"],"names":[],"mappings":"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","file":"chunk-QPUPLNNB.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\nimport {\n PanelBottomClose,\n PanelBottomOpen,\n PanelLeftClose,\n PanelLeftOpen,\n PanelRightClose,\n PanelRightOpen,\n} from 'lucide';\n\nimport { LucideIcon } from './lucide-icon.js';\nimport { Pane, type PaneConfig } from './pane.js';\nimport { isRelocatableGroup } from './panel-toolbar-group.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport { Toolbar, type ToolbarConfig } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\n\n/** Which edge a collapsible panel docks to. */\nexport type PanelSide = 'left' | 'right' | 'bottom';\n\n/**\n * The standard collapse/expand icon for a panel `side` and `collapsed` state,\n * so every app's sidebars and drawers use one recognizable convention:\n * `PanelLeft*` for a left rail, `PanelRight*` for a right rail, `PanelBottom*`\n * for a bottom drawer — the `Close` glyph while open, the `Open` glyph while\n * collapsed. Exposed so an app can render its own toggle affordance.\n */\nexport function collapsiblePanelToggleIcon(\n side: PanelSide,\n collapsed: boolean,\n): { icon: Parameters<typeof LucideIcon>[0]['icon']; name: string } {\n if (side === 'left')\n return collapsed\n ? { icon: PanelLeftOpen, name: 'panel-left-open' }\n : { icon: PanelLeftClose, name: 'panel-left-close' };\n if (side === 'right')\n return collapsed\n ? { icon: PanelRightOpen, name: 'panel-right-open' }\n : { icon: PanelRightClose, name: 'panel-right-close' };\n return collapsed\n ? { icon: PanelBottomOpen, name: 'panel-bottom-open' }\n : { icon: PanelBottomClose, name: 'panel-bottom-close' };\n}\n\n/**\n * The standard collapse toggle a panel toolbar renders. The app handles the\n * button's `data-action` and flips its own `collapsed` flag.\n */\nexport interface PanelToggle {\n /** The `data-action` the toggle button carries. */\n action: string;\n /** The panel's short name, for the accessible \"Show …\" / \"Hide …\" label. */\n name: string;\n /** Accessible label while the panel is collapsed. Defaults to `Show {name}`. */\n showLabel?: string;\n /** Accessible label while the panel is open. Defaults to `Hide {name}`. */\n hideLabel?: string;\n}\n\n/**\n * A collapsible panel's top toolbar, composed so its groups follow the\n * panel's open state.\n *\n * - `title` precedes the `leading` zone. Groups may appear in any of the\n * `leading`, `center`, and `trailing` zones while the panel is open.\n * - Groups marked `relocateOnCollapse` move to the work area's toolbar while\n * the panel is collapsed, preserving their order across the three zones.\n * - `toggle` is always the last group: in the panel's toolbar while it is\n * open, and right after the relocated groups in the work area's toolbar\n * while it is collapsed.\n *\n * Relocated content renders in both places while the panel is collapsed (the\n * panel's copy is inert), so give it no `id`s. Pass groups directly or in\n * arrays so their render-time annotation remains available to the panel.\n *\n * The toolbar's configuration (`dividerSides`, `centerAlign`, `responsive`,\n * `responsiveAt`, `safeAreaEdges`) forwards to its `Toolbar`. It draws no\n * divider of its own: the panel's `Pane` draws the line under it while the\n * content is scrolled (its `chromeDividers`, wired by `wireScrollDividers`).\n */\nexport interface PanelToolbar extends ToolbarConfig {\n /** Accessible name of the panel's toolbar. */\n label: string;\n title?: KerfUiContent;\n leading?: KerfUiContent;\n center?: KerfUiContent;\n trailing?: KerfUiContent;\n toggle?: PanelToggle;\n}\n\n/** Owner-specific attributes a toggle button carries (its wiring hooks). */\nexport type PanelToggleAttributes = Readonly<Record<string, string>>;\n\n/** The standard toggle, alone in a borderless group. */\nexport function panelToggleGroup(\n side: PanelSide,\n toggle: PanelToggle,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): SafeHtml {\n const glyph = collapsiblePanelToggleIcon(side, collapsed);\n return (\n <ToolbarControlGroup label={toggle.name} appearance=\"borderless\" single>\n <button\n type=\"button\"\n {...attributes}\n data-action={toggle.action}\n aria-expanded={String(!collapsed)}\n aria-label={\n collapsed\n ? (toggle.showLabel ?? `Show ${toggle.name}`)\n : (toggle.hideLabel ?? `Hide ${toggle.name}`)\n }\n >\n <LucideIcon icon={glyph.icon} name={glyph.name} />\n </button>\n </ToolbarControlGroup>\n );\n}\n\n/**\n * The panel's own toolbar: content keeps its chosen zones and the toggle trails.\n */\nexport function composedPanelToolbar(\n toolbar: PanelToolbar,\n side: PanelSide,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): SafeHtml {\n return (\n <Toolbar\n label={toolbar.label}\n dividerSides={toolbar.dividerSides}\n centerAlign={toolbar.centerAlign}\n responsive={toolbar.responsive}\n responsiveAt={toolbar.responsiveAt}\n safeAreaEdges={toolbar.safeAreaEdges}\n center={toolbar.center}\n leading={\n <>\n {toolbar.title}\n {toolbar.leading}\n </>\n }\n trailing={\n <>\n {toolbar.trailing}\n {toolbar.toggle\n ? panelToggleGroup(side, toolbar.toggle, collapsed, attributes)\n : null}\n </>\n }\n />\n );\n}\n\n/**\n * A toolbar panel's body: its content in a `Pane` under its composed toolbar,\n * with its optional `footer` below. The panel's `pane` configuration forwards\n * to that `Pane`; an omitted or `undefined` field keeps the `Pane` default.\n */\nexport function composedPanelBody({\n toolbar,\n side,\n collapsed,\n attributes,\n pane,\n footer,\n content,\n}: {\n toolbar: PanelToolbar;\n side: PanelSide;\n collapsed: boolean;\n attributes: PanelToggleAttributes;\n pane: PaneConfig | undefined;\n footer: KerfUiContent;\n content: KerfUiContent;\n}): SafeHtml {\n return (\n <Pane\n header={composedPanelToolbar(toolbar, side, collapsed, attributes)}\n footer={footer}\n contentElement={pane?.contentElement}\n contentLabel={pane?.contentLabel}\n separators={pane?.separators}\n safeAreaEdges={pane?.safeAreaEdges}\n chromeDividers={pane?.chromeDividers}\n >\n {content}\n </Pane>\n );\n}\n\n/**\n * The groups a collapsed panel hands to the work area, in zone order, then its\n * toggle. Empty while the panel is open or has no toolbar.\n */\nexport function relocatedPanelGroups(\n toolbar: PanelToolbar | undefined,\n side: PanelSide,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): KerfUiContent[] {\n if (!collapsed || !toolbar) return [];\n const groups: KerfUiContent[] = [];\n const collect = (content: KerfUiContent): void => {\n if (Array.isArray(content)) {\n for (const item of content) collect(item);\n } else if (isRelocatableGroup(content)) {\n groups.push(content);\n }\n };\n collect(toolbar.leading);\n collect(toolbar.center);\n collect(toolbar.trailing);\n return [\n ...groups,\n toolbar.toggle\n ? panelToggleGroup(side, toolbar.toggle, true, attributes)\n : null,\n ].filter((group) => group !== undefined && group !== null && group !== false);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ToolbarText } from './chunk-XDKAYSVD.js';
|
|
2
|
-
import { ToolbarControlGroup } from './chunk-
|
|
2
|
+
import { ToolbarControlGroup } from './chunk-7JUBXOIV.js';
|
|
3
3
|
import { Toolbar } from './chunk-6YFHCLHG.js';
|
|
4
4
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
5
5
|
import { ChevronLeft } from 'lucide';
|
|
@@ -112,4 +112,4 @@ function NavStack({
|
|
|
112
112
|
|
|
113
113
|
export { NavStack };
|
|
114
114
|
|
|
115
|
-
//# sourceMappingURL=chunk-
|
|
115
|
+
//# sourceMappingURL=chunk-W4XKTST6.js.map
|