@f-ewald/components 1.2.1 → 1.3.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 +15 -2
- package/custom-elements.json +1019 -93
- package/dist/action-bar.d.ts +24 -0
- package/dist/action-bar.d.ts.map +1 -0
- package/dist/action-bar.js +67 -0
- package/dist/action-bar.js.map +1 -0
- package/dist/app-shell.d.ts +86 -0
- package/dist/app-shell.d.ts.map +1 -0
- package/dist/app-shell.js +460 -0
- package/dist/app-shell.js.map +1 -0
- package/dist/app-sidebar.d.ts +44 -0
- package/dist/app-sidebar.d.ts.map +1 -0
- package/dist/app-sidebar.js +211 -0
- package/dist/app-sidebar.js.map +1 -0
- package/dist/form-actions.d.ts +27 -0
- package/dist/form-actions.d.ts.map +1 -0
- package/dist/form-actions.js +65 -0
- package/dist/form-actions.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +82 -5
- package/dist/mcp-server.js.map +1 -1
- package/dist/page-header.d.ts +27 -0
- package/dist/page-header.d.ts.map +1 -0
- package/dist/page-header.js +106 -0
- package/dist/page-header.js.map +1 -0
- package/dist/pagination-nav.d.ts +34 -0
- package/dist/pagination-nav.d.ts.map +1 -0
- package/dist/pagination-nav.js +144 -0
- package/dist/pagination-nav.js.map +1 -0
- package/dist/timeline-container.d.ts +22 -0
- package/dist/timeline-container.d.ts.map +1 -0
- package/dist/timeline-container.js +42 -0
- package/dist/timeline-container.js.map +1 -0
- package/dist/timeline-entry.d.ts +31 -0
- package/dist/timeline-entry.d.ts.map +1 -0
- package/dist/timeline-entry.js +170 -0
- package/dist/timeline-entry.js.map +1 -0
- package/docs/action-bar.md +41 -0
- package/docs/app-shell.md +85 -0
- package/docs/app-sidebar.md +69 -0
- package/docs/design-language.md +74 -1
- package/docs/form-actions.md +43 -0
- package/docs/layouts/detail-only.md +52 -0
- package/docs/layouts/form-page.md +52 -0
- package/docs/layouts/list-detail.md +52 -0
- package/docs/layouts/list-only.md +50 -0
- package/docs/layouts/record-detail.md +88 -0
- package/docs/mcp-evaluation.md +21 -0
- package/docs/page-header.md +47 -0
- package/docs/pagination-nav.md +54 -0
- package/docs/timeline-container.md +44 -0
- package/docs/timeline-entry.md +52 -0
- package/llms.txt +229 -0
- package/package.json +1 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# List-only page
|
|
2
|
+
|
|
3
|
+
A full-width list/table view: a collapsible sidebar, a top bar, an action row,
|
|
4
|
+
the list, and pagination. The default internal-dashboard "index" screen.
|
|
5
|
+
|
|
6
|
+
**When to use:** browsing or managing a collection of records where a row does
|
|
7
|
+
not need a side-by-side detail pane (rows link to their own detail page). If you
|
|
8
|
+
want an inline detail pane, use the list + detail template instead.
|
|
9
|
+
|
|
10
|
+
## Shell slots
|
|
11
|
+
|
|
12
|
+
- `sidebar` → `app-sidebar` with the app's navigation.
|
|
13
|
+
- `topbar` → `page-header` with the collection title (and optional actions).
|
|
14
|
+
- default (`main`) → an `action-bar` above a `data-table`.
|
|
15
|
+
- `footer` → `pagination-nav`.
|
|
16
|
+
|
|
17
|
+
## Markup
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<app-shell style="height: 100vh">
|
|
21
|
+
<app-sidebar slot="sidebar"><!-- nav items --></app-sidebar>
|
|
22
|
+
|
|
23
|
+
<page-header slot="topbar" heading="Members"></page-header>
|
|
24
|
+
|
|
25
|
+
<div>
|
|
26
|
+
<action-bar>
|
|
27
|
+
<autocomplete-input slot="start" placeholder="Search…"></autocomplete-input>
|
|
28
|
+
<ui-button slot="end" variant="secondary">Filter</ui-button>
|
|
29
|
+
<ui-button slot="end" variant="primary">Create</ui-button>
|
|
30
|
+
</action-bar>
|
|
31
|
+
<data-table style="margin-top: 1rem; display: block;"></data-table>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<pagination-nav slot="footer" current-page="1" total-pages="6"></pagination-nav>
|
|
35
|
+
</app-shell>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Notes
|
|
39
|
+
|
|
40
|
+
- Give `app-shell` a height (e.g. `100vh`) so the sidebar and main can size and
|
|
41
|
+
scroll independently.
|
|
42
|
+
- `pagination-nav` is controlled: set `current-page`/`total-pages` and re-render
|
|
43
|
+
in response to its `page-change` event, the same way `data-table` leaves the
|
|
44
|
+
rows to you.
|
|
45
|
+
- Put search and filters in the action bar's `start` slot and record actions
|
|
46
|
+
(create, delete) in `end`.
|
|
47
|
+
|
|
48
|
+
**Live demo:** `demo/layouts/list-only.html`
|
|
49
|
+
|
|
50
|
+
**Components:** app-shell, app-sidebar, page-header, action-bar, data-table, pagination-nav
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Record + metadata rail page
|
|
2
|
+
|
|
3
|
+
A record's read view with the main content on the left and a persistent
|
|
4
|
+
metadata/detail rail on the right — the Jira/Linear issue layout (description +
|
|
5
|
+
status, assignee, labels, priority).
|
|
6
|
+
|
|
7
|
+
**When to use:** viewing one rich record whose metadata (status, owner, labels,
|
|
8
|
+
progress) should stay visible alongside the content, and where that metadata is
|
|
9
|
+
mostly a static display of components rather than a transient selection.
|
|
10
|
+
|
|
11
|
+
## Layout
|
|
12
|
+
|
|
13
|
+
The rail is a **two-column CSS grid inside the `main` slot**, not the shell's
|
|
14
|
+
`detail` slot:
|
|
15
|
+
|
|
16
|
+
- `sidebar` → `app-sidebar`.
|
|
17
|
+
- `topbar` → `page-header` with a linked `breadcrumb` and record `actions`
|
|
18
|
+
(primary Edit rightmost).
|
|
19
|
+
- default (`main`) → a grid: the body (description, activity) on the left, an
|
|
20
|
+
`<aside>` metadata rail on the right. It collapses to one column at the shared
|
|
21
|
+
48rem breakpoint so the metadata **stacks below** the content on narrow
|
|
22
|
+
screens instead of hiding.
|
|
23
|
+
|
|
24
|
+
The metadata rail is composed from existing components: `frame-box` to group,
|
|
25
|
+
`status-pill` for status/priority/labels, `user-avatar` for people, and
|
|
26
|
+
`stat-meter` for progress. Activity uses `chat-message`.
|
|
27
|
+
|
|
28
|
+
## Markup
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<app-shell style="height: 100vh">
|
|
32
|
+
<app-sidebar slot="sidebar"><!-- nav items --></app-sidebar>
|
|
33
|
+
|
|
34
|
+
<page-header slot="topbar" heading="Fix flaky login redirect">
|
|
35
|
+
<nav slot="breadcrumb" aria-label="Breadcrumb"><a href="/board">Board</a> / PROJ-142</nav>
|
|
36
|
+
<ui-button slot="actions" variant="primary">Edit</ui-button>
|
|
37
|
+
</page-header>
|
|
38
|
+
|
|
39
|
+
<div class="ticket">
|
|
40
|
+
<div class="ticket-body">
|
|
41
|
+
<h3>Description</h3>
|
|
42
|
+
<p>…</p>
|
|
43
|
+
<frame-box label="Activity">
|
|
44
|
+
<chat-message role="user" author="Ada Lovelace">…</chat-message>
|
|
45
|
+
</frame-box>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<aside class="ticket-meta" aria-label="Issue details">
|
|
49
|
+
<frame-box label="Details">
|
|
50
|
+
<dl class="meta">
|
|
51
|
+
<div class="meta-row"><dt>Status</dt><dd><status-pill label="In Progress" color="info"></status-pill></dd></div>
|
|
52
|
+
<div class="meta-row"><dt>Assignee</dt><dd><user-avatar name="Ada Lovelace" size="24"></user-avatar> Ada Lovelace</dd></div>
|
|
53
|
+
<div class="meta-row"><dt>Priority</dt><dd><status-pill label="High" color="warning"></status-pill></dd></div>
|
|
54
|
+
</dl>
|
|
55
|
+
<stat-meter label="Progress" percent="60"></stat-meter>
|
|
56
|
+
</frame-box>
|
|
57
|
+
</aside>
|
|
58
|
+
</div>
|
|
59
|
+
</app-shell>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```css
|
|
63
|
+
.ticket {
|
|
64
|
+
display: grid;
|
|
65
|
+
grid-template-columns: minmax(0, 1fr) 18rem;
|
|
66
|
+
gap: 1.5rem;
|
|
67
|
+
align-items: start;
|
|
68
|
+
}
|
|
69
|
+
@media (max-width: 48rem) {
|
|
70
|
+
.ticket { grid-template-columns: minmax(0, 1fr); }
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Notes
|
|
75
|
+
|
|
76
|
+
- Use the two-column grid inside `main` (not the shell `detail` slot) when the
|
|
77
|
+
metadata is **persistent** and should stack on mobile. The shell's `detail`
|
|
78
|
+
slot is for a **transient master-detail selection** (list + selected item): on
|
|
79
|
+
mobile it becomes a dismissible overlay, which hides persistent record
|
|
80
|
+
metadata. Reach for it in the list + detail template, not here.
|
|
81
|
+
- Editable metadata is a drop-in swap: replace a `status-pill` with a
|
|
82
|
+
`form-select`, or the label pills with a `multi-select`.
|
|
83
|
+
- Keep the record actions in the header (primary Edit); there is no
|
|
84
|
+
`form-actions` footer on a read view.
|
|
85
|
+
|
|
86
|
+
**Live demo:** `demo/layouts/record-detail.html`
|
|
87
|
+
|
|
88
|
+
**Components:** app-shell, app-sidebar, page-header, frame-box, status-pill, user-avatar, stat-meter, chat-message
|
package/docs/mcp-evaluation.md
CHANGED
|
@@ -36,3 +36,24 @@ A thin stdio MCP server exposing two tools — `list_components` and
|
|
|
36
36
|
`get_component_docs(tag)` — backed by the same `custom-elements.json` this
|
|
37
37
|
package already generates and ships. No new data source was needed; the
|
|
38
38
|
server is just a different transport over data that already existed.
|
|
39
|
+
|
|
40
|
+
## Update (layout system): added `list_layouts` / `get_layout`
|
|
41
|
+
|
|
42
|
+
The dashboard layout system introduced cross-component knowledge — which
|
|
43
|
+
components compose into which page templates, the slot recipes, and the
|
|
44
|
+
button-placement rule — that no single component's generated doc captures. Two
|
|
45
|
+
thin tools, `list_layouts` and `get_layout(name)`, expose it.
|
|
46
|
+
|
|
47
|
+
This stays true to the server's founding principle: **no new data source.** The
|
|
48
|
+
tools read the authored `docs/layouts/*.md` recipes (which also ship in the npm
|
|
49
|
+
package and render on the docs site), not a bespoke structure invented for MCP.
|
|
50
|
+
The individual layout components still flow through `list_components` /
|
|
51
|
+
`get_component_docs` automatically.
|
|
52
|
+
|
|
53
|
+
**Is MCP the right fit here?** It's a reasonable, not slam-dunk, fit. The
|
|
54
|
+
justification is discoverability and targeted retrieval — an agent can list the
|
|
55
|
+
templates and pull just the one it needs, rather than loading everything. If the
|
|
56
|
+
guidance stayed tiny, `llms.txt` alone could carry it; the tools earn their keep
|
|
57
|
+
by making the "preferred layout" explicitly enumerable and by matching the
|
|
58
|
+
per-component tools consumers already call. The cost to watch is keeping the
|
|
59
|
+
recipes, the `demo/layouts/` demos, and the tool output in sync.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# `<page-header>`
|
|
2
|
+
|
|
3
|
+
Page title block for the top of a dashboard view: an optional breadcrumb
|
|
4
|
+
trail, the page heading, and a right-aligned cluster of page-level actions.
|
|
5
|
+
It only lays these out — the breadcrumb links and action buttons are entirely
|
|
6
|
+
the consumer's, so it stays framework- and router-agnostic.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import "@f-ewald/components/page-header.js";
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<page-header heading="Team members">
|
|
18
|
+
<nav slot="breadcrumb" aria-label="Breadcrumb">Home / Settings / Members</nav>
|
|
19
|
+
<ui-button slot="actions" variant="primary">Invite</ui-button>
|
|
20
|
+
</page-header>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Attributes / properties
|
|
24
|
+
|
|
25
|
+
| Property | Attribute | Type | Default | Description |
|
|
26
|
+
| --- | --- | --- | --- | --- |
|
|
27
|
+
| `heading` | `heading` | `string` | `""` | The page heading text. |
|
|
28
|
+
|
|
29
|
+
## Events
|
|
30
|
+
|
|
31
|
+
_None._
|
|
32
|
+
|
|
33
|
+
## Slots
|
|
34
|
+
|
|
35
|
+
_None._
|
|
36
|
+
|
|
37
|
+
## CSS custom properties
|
|
38
|
+
|
|
39
|
+
| Custom property |
|
|
40
|
+
| --- |
|
|
41
|
+
| `--ui-font` |
|
|
42
|
+
| `--ui-font-size-lg` |
|
|
43
|
+
| `--ui-font-size-sm` |
|
|
44
|
+
| `--ui-font-weight-semibold` |
|
|
45
|
+
| `--ui-line-height-tight` |
|
|
46
|
+
| `--ui-text` |
|
|
47
|
+
| `--ui-text-muted` |
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# `<pagination-nav>`
|
|
2
|
+
|
|
3
|
+
Minimal, controlled pager for list/table views: a previous/next control pair
|
|
4
|
+
around a "Page N of M" status. It owns no data — the consumer sets
|
|
5
|
+
`current-page` / `total-pages` and moves the page in response to the
|
|
6
|
+
`page-change` event (typically alongside its own data fetch), exactly like
|
|
7
|
+
`data-table` leaves the row data to the caller.
|
|
8
|
+
|
|
9
|
+
Previous is disabled on the first page and next on the last; neither fires an
|
|
10
|
+
event when there is nowhere to go.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import "@f-ewald/components/pagination-nav.js";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<pagination-nav current-page="1" total-pages="5"></pagination-nav>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Attributes / properties
|
|
25
|
+
|
|
26
|
+
| Property | Attribute | Type | Default | Description |
|
|
27
|
+
| --- | --- | --- | --- | --- |
|
|
28
|
+
| `currentPage` | `current-page` | `number` | `1` | The 1-based current page. |
|
|
29
|
+
| `totalPages` | `total-pages` | `number` | `1` | The total number of pages (minimum 1). |
|
|
30
|
+
|
|
31
|
+
## Events
|
|
32
|
+
|
|
33
|
+
| Event | Description |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `page-change` | The user picked a new page (`detail: { page }`). |
|
|
36
|
+
|
|
37
|
+
## Slots
|
|
38
|
+
|
|
39
|
+
_None._
|
|
40
|
+
|
|
41
|
+
## CSS custom properties
|
|
42
|
+
|
|
43
|
+
| Custom property |
|
|
44
|
+
| --- |
|
|
45
|
+
| `--ui-border` |
|
|
46
|
+
| `--ui-focus-ring` |
|
|
47
|
+
| `--ui-font` |
|
|
48
|
+
| `--ui-font-size-sm` |
|
|
49
|
+
| `--ui-font-weight-medium` |
|
|
50
|
+
| `--ui-line-height-tight` |
|
|
51
|
+
| `--ui-radius-sm` |
|
|
52
|
+
| `--ui-surface-muted` |
|
|
53
|
+
| `--ui-text` |
|
|
54
|
+
| `--ui-text-muted` |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# `<timeline-container>`
|
|
2
|
+
|
|
3
|
+
Vertical timeline: a single connecting line runs down the left edge and each
|
|
4
|
+
slotted `timeline-entry` places a dot on it. This is a thin layout and
|
|
5
|
+
semantics wrapper — the entries draw the line segments and dots themselves,
|
|
6
|
+
so the container adds no gap between them (a gap would break the line).
|
|
7
|
+
Exposed to assistive technology as a list of events.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import "@f-ewald/components/timeline-container.js";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<timeline-container>
|
|
19
|
+
<timeline-entry datetime="2026-07-23T09:00:00Z">
|
|
20
|
+
<span slot="headline">Deployment started</span>
|
|
21
|
+
Release v1.4.0 is rolling out.
|
|
22
|
+
</timeline-entry>
|
|
23
|
+
<timeline-entry datetime="2026-07-23T08:45:00Z">
|
|
24
|
+
<span slot="headline">Review approved</span>
|
|
25
|
+
<status-pill label="In Review" color="info"></status-pill>
|
|
26
|
+
</timeline-entry>
|
|
27
|
+
</timeline-container>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Attributes / properties
|
|
31
|
+
|
|
32
|
+
_None._
|
|
33
|
+
|
|
34
|
+
## Events
|
|
35
|
+
|
|
36
|
+
_None._
|
|
37
|
+
|
|
38
|
+
## Slots
|
|
39
|
+
|
|
40
|
+
_None._
|
|
41
|
+
|
|
42
|
+
## CSS custom properties
|
|
43
|
+
|
|
44
|
+
_None._
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# `<timeline-entry>`
|
|
2
|
+
|
|
3
|
+
One event on a `timeline-container`: a dot on the vertical line, an optional
|
|
4
|
+
headline, a relative timestamp ("3 hours ago"), and freely nested content.
|
|
5
|
+
The connecting line is drawn here — its segment above the dot is hidden on
|
|
6
|
+
the first entry and the segment below is hidden on the last, so the line caps
|
|
7
|
+
exactly at the first and last dots. Only meaningful inside a
|
|
8
|
+
`timeline-container`; demonstrated through it.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import "@f-ewald/components/timeline-entry.js";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<timeline-entry datetime="2026-07-23T09:00:00Z">
|
|
20
|
+
<span slot="headline">Deployment started</span>
|
|
21
|
+
Release v1.4.0 is rolling out to production.
|
|
22
|
+
</timeline-entry>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Attributes / properties
|
|
26
|
+
|
|
27
|
+
| Property | Attribute | Type | Default | Description |
|
|
28
|
+
| --- | --- | --- | --- | --- |
|
|
29
|
+
| `datetime` | `datetime` | `string | null` | `null` | ISO 8601 or SQLite datetime string, rendered as a relative time. |
|
|
30
|
+
|
|
31
|
+
## Events
|
|
32
|
+
|
|
33
|
+
_None._
|
|
34
|
+
|
|
35
|
+
## Slots
|
|
36
|
+
|
|
37
|
+
_None._
|
|
38
|
+
|
|
39
|
+
## CSS custom properties
|
|
40
|
+
|
|
41
|
+
| Custom property |
|
|
42
|
+
| --- |
|
|
43
|
+
| `--ui-border` |
|
|
44
|
+
| `--ui-font` |
|
|
45
|
+
| `--ui-font-size` |
|
|
46
|
+
| `--ui-font-size-sm` |
|
|
47
|
+
| `--ui-font-weight-semibold` |
|
|
48
|
+
| `--ui-line-height-normal` |
|
|
49
|
+
| `--ui-line-height-tight` |
|
|
50
|
+
| `--ui-primary` |
|
|
51
|
+
| `--ui-text` |
|
|
52
|
+
| `--ui-text-muted` |
|
package/llms.txt
CHANGED
|
@@ -16,6 +16,31 @@ render correctly with zero external CSS. Override any `--ui-*` property on
|
|
|
16
16
|
`:root` (or an ancestor) to retheme, or import the optional
|
|
17
17
|
`@f-ewald/components/tokens.css` stylesheet as a starting point.
|
|
18
18
|
|
|
19
|
+
## <action-bar>
|
|
20
|
+
|
|
21
|
+
Toolbar that sits directly above a list or table: a left cluster for
|
|
22
|
+
search and filters and a right cluster for record actions (create, delete,
|
|
23
|
+
bulk actions). It's a presentational layout container only — drop any
|
|
24
|
+
controls (`autocomplete-input`, `multi-select`, `ui-button`, …) into the
|
|
25
|
+
`start` and `end` slots; the bar owns none of their behavior and adds no
|
|
26
|
+
search field of its own. The two clusters wrap onto separate rows when the
|
|
27
|
+
bar is too narrow.
|
|
28
|
+
|
|
29
|
+
Import: `import "@f-ewald/components/action-bar.js";`
|
|
30
|
+
|
|
31
|
+
Properties: none
|
|
32
|
+
Events: none
|
|
33
|
+
CSS custom properties: none
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
```html
|
|
37
|
+
<action-bar>
|
|
38
|
+
<autocomplete-input slot="start" placeholder="Search…"></autocomplete-input>
|
|
39
|
+
<ui-button slot="end" variant="secondary">Delete</ui-button>
|
|
40
|
+
<ui-button slot="end" variant="primary">Create</ui-button>
|
|
41
|
+
</action-bar>
|
|
42
|
+
```
|
|
43
|
+
|
|
19
44
|
## <address-autocomplete>
|
|
20
45
|
|
|
21
46
|
Form-associated text input with a suggestion dropdown. Works as a
|
|
@@ -61,6 +86,89 @@ Example:
|
|
|
61
86
|
<animate-confetti duration="6000"></animate-confetti>
|
|
62
87
|
```
|
|
63
88
|
|
|
89
|
+
## <app-shell>
|
|
90
|
+
|
|
91
|
+
The dashboard page shell: a slot-based CSS-grid backbone that arranges a
|
|
92
|
+
full-height sidebar, a top bar, the main content, an optional right-hand
|
|
93
|
+
detail column, and an optional footer. It owns the responsive behavior so
|
|
94
|
+
consumers don't re-implement it — above the shared 48rem breakpoint the
|
|
95
|
+
sidebar collapses to an icon rail and the detail region is an inline column;
|
|
96
|
+
at or below it the sidebar becomes an off-canvas drawer and the detail region
|
|
97
|
+
an overlay, both dismissed by a scrim or Escape.
|
|
98
|
+
|
|
99
|
+
Widths are tunable per instance via `--component-sidebar-width` (16rem),
|
|
100
|
+
`--component-sidebar-rail-width` (3.5rem), and `--component-topbar-height`
|
|
101
|
+
(3rem); the detail column reuses the 20rem/25rem panel widths. The main
|
|
102
|
+
content area is white by default — override it with
|
|
103
|
+
`--component-main-background`. Give the shell a height (e.g. `height: 100vh`)
|
|
104
|
+
so the sidebar and main can size and scroll.
|
|
105
|
+
|
|
106
|
+
The built-in top-bar button toggles the sidebar, and so does pressing `[`
|
|
107
|
+
anywhere on the page (ignored while typing in a text field or with a
|
|
108
|
+
modifier held). Hovering or keyboard-focusing the toggle reveals a tooltip
|
|
109
|
+
naming the action and its `[` shortcut — the shortcut is not shown as
|
|
110
|
+
permanent chrome.
|
|
111
|
+
|
|
112
|
+
Import: `import "@f-ewald/components/app-shell.js";`
|
|
113
|
+
|
|
114
|
+
Properties: `sidebarCollapsed` (attribute `sidebar-collapsed`) : boolean, default false; `detailOpen` (attribute `detail-open`) : boolean, default false; `detailWidth` (attribute `detail-width`) : "compact" | "comfortable", default "compact"
|
|
115
|
+
Events: `sidebar-toggle`, `detail-close`
|
|
116
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font-size-sm`, `--ui-line-height-tight`, `--ui-on-accent`, `--ui-overlay`, `--ui-radius-sm`, `--ui-shadow`, `--ui-shadow-lg`, `--ui-surface`, `--ui-surface-muted`, `--ui-text-muted`, `--ui-tooltip`
|
|
117
|
+
|
|
118
|
+
Example:
|
|
119
|
+
```html
|
|
120
|
+
<app-shell detail-open style="height: 100vh">
|
|
121
|
+
<app-sidebar slot="sidebar">
|
|
122
|
+
<a href="/dashboard" aria-current="page" aria-label="Dashboard">
|
|
123
|
+
<!-- icon --><span style="display: var(--app-sidebar-label, inline)">Dashboard</span>
|
|
124
|
+
</a>
|
|
125
|
+
</app-sidebar>
|
|
126
|
+
<page-header slot="topbar" heading="Members"></page-header>
|
|
127
|
+
<action-bar>
|
|
128
|
+
<autocomplete-input slot="start" placeholder="Search…"></autocomplete-input>
|
|
129
|
+
<ui-button slot="end" variant="primary">Create</ui-button>
|
|
130
|
+
</action-bar>
|
|
131
|
+
<data-table></data-table>
|
|
132
|
+
<div slot="detail">Selected record…</div>
|
|
133
|
+
<pagination-nav slot="footer" total-pages="5"></pagination-nav>
|
|
134
|
+
</app-shell>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## <app-sidebar>
|
|
138
|
+
|
|
139
|
+
Collapsible navigation sidebar for the `app-shell` sidebar slot. It is
|
|
140
|
+
deliberately presentational and router-agnostic: the consumer supplies the
|
|
141
|
+
nav items as plain `<a>`/`<button>` elements (each an icon followed by a
|
|
142
|
+
label), optional `<p>` group headings, and marks the active item with
|
|
143
|
+
`aria-current="page"`. The sidebar styles them, tracks hover/active/focus,
|
|
144
|
+
and — in collapsed "rail" mode — centers the icons and hides the labels.
|
|
145
|
+
|
|
146
|
+
Rail mode is driven by the `collapsed` attribute (the parent `app-shell`
|
|
147
|
+
toggles it). Labels are hidden by the inherited `--app-sidebar-label` custom
|
|
148
|
+
property, so each label element should read it, e.g.
|
|
149
|
+
`<span style="display: var(--app-sidebar-label, inline)">Reports</span>`;
|
|
150
|
+
keep an `aria-label` on the item so its accessible name survives collapse.
|
|
151
|
+
The sidebar fills the width and height of its container — `app-shell` owns
|
|
152
|
+
the actual rail/expanded width.
|
|
153
|
+
|
|
154
|
+
Import: `import "@f-ewald/components/app-sidebar.js";`
|
|
155
|
+
|
|
156
|
+
Properties: `collapsed` (attribute `collapsed`) : boolean, default false
|
|
157
|
+
Events: none
|
|
158
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-size-xs`, `--ui-font-weight-medium`, `--ui-font-weight-semibold`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`, `--ui-tracking-wide`
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
```html
|
|
162
|
+
<app-sidebar>
|
|
163
|
+
<a href="/dashboard" aria-current="page" aria-label="Dashboard">
|
|
164
|
+
<!-- icon --><span style="display: var(--app-sidebar-label, inline)">Dashboard</span>
|
|
165
|
+
</a>
|
|
166
|
+
<a href="/members" aria-label="Members">
|
|
167
|
+
<!-- icon --><span style="display: var(--app-sidebar-label, inline)">Members</span>
|
|
168
|
+
</a>
|
|
169
|
+
</app-sidebar>
|
|
170
|
+
```
|
|
171
|
+
|
|
64
172
|
## <autocomplete-input>
|
|
65
173
|
|
|
66
174
|
Generic form-associated text input with a suggestion dropdown, for any
|
|
@@ -390,6 +498,33 @@ Example:
|
|
|
390
498
|
<editable-text multiline placeholder="Add a description…" label="Description"></editable-text>
|
|
391
499
|
```
|
|
392
500
|
|
|
501
|
+
## <form-actions>
|
|
502
|
+
|
|
503
|
+
Form footer button bar with a fixed action order for internal apps: the
|
|
504
|
+
primary (submit) button is always rightmost, the secondary (cancel) button
|
|
505
|
+
sits to its immediate left, and an optional tertiary/destructive action is
|
|
506
|
+
pinned to the far left. The order is enforced by the component regardless of
|
|
507
|
+
the source order the buttons are authored in, so every form in a product
|
|
508
|
+
reads the same way.
|
|
509
|
+
|
|
510
|
+
Purely presentational: it lays out whatever controls (usually `ui-button`)
|
|
511
|
+
are slotted and never intercepts their clicks, `type="submit"`, or events.
|
|
512
|
+
|
|
513
|
+
Import: `import "@f-ewald/components/form-actions.js";`
|
|
514
|
+
|
|
515
|
+
Properties: none
|
|
516
|
+
Events: none
|
|
517
|
+
CSS custom properties: none
|
|
518
|
+
|
|
519
|
+
Example:
|
|
520
|
+
```html
|
|
521
|
+
<form-actions>
|
|
522
|
+
<ui-button slot="start" variant="danger">Delete</ui-button>
|
|
523
|
+
<ui-button slot="secondary" variant="secondary">Cancel</ui-button>
|
|
524
|
+
<ui-button slot="primary" type="submit" variant="primary">Save</ui-button>
|
|
525
|
+
</form-actions>
|
|
526
|
+
```
|
|
527
|
+
|
|
393
528
|
## <form-select>
|
|
394
529
|
|
|
395
530
|
A styled dropdown select: a trigger button showing the current option's
|
|
@@ -780,6 +915,49 @@ Example:
|
|
|
780
915
|
</script>
|
|
781
916
|
```
|
|
782
917
|
|
|
918
|
+
## <page-header>
|
|
919
|
+
|
|
920
|
+
Page title block for the top of a dashboard view: an optional breadcrumb
|
|
921
|
+
trail, the page heading, and a right-aligned cluster of page-level actions.
|
|
922
|
+
It only lays these out — the breadcrumb links and action buttons are entirely
|
|
923
|
+
the consumer's, so it stays framework- and router-agnostic.
|
|
924
|
+
|
|
925
|
+
Import: `import "@f-ewald/components/page-header.js";`
|
|
926
|
+
|
|
927
|
+
Properties: `heading` (attribute `heading`) : string, default ""
|
|
928
|
+
Events: none
|
|
929
|
+
CSS custom properties: `--ui-font`, `--ui-font-size-lg`, `--ui-font-size-sm`, `--ui-font-weight-semibold`, `--ui-line-height-tight`, `--ui-text`, `--ui-text-muted`
|
|
930
|
+
|
|
931
|
+
Example:
|
|
932
|
+
```html
|
|
933
|
+
<page-header heading="Team members">
|
|
934
|
+
<nav slot="breadcrumb" aria-label="Breadcrumb">Home / Settings / Members</nav>
|
|
935
|
+
<ui-button slot="actions" variant="primary">Invite</ui-button>
|
|
936
|
+
</page-header>
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
## <pagination-nav>
|
|
940
|
+
|
|
941
|
+
Minimal, controlled pager for list/table views: a previous/next control pair
|
|
942
|
+
around a "Page N of M" status. It owns no data — the consumer sets
|
|
943
|
+
`current-page` / `total-pages` and moves the page in response to the
|
|
944
|
+
`page-change` event (typically alongside its own data fetch), exactly like
|
|
945
|
+
`data-table` leaves the row data to the caller.
|
|
946
|
+
|
|
947
|
+
Previous is disabled on the first page and next on the last; neither fires an
|
|
948
|
+
event when there is nowhere to go.
|
|
949
|
+
|
|
950
|
+
Import: `import "@f-ewald/components/pagination-nav.js";`
|
|
951
|
+
|
|
952
|
+
Properties: `currentPage` (attribute `current-page`) : number, default 1; `totalPages` (attribute `total-pages`) : number, default 1
|
|
953
|
+
Events: `page-change`
|
|
954
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-line-height-tight`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
|
|
955
|
+
|
|
956
|
+
Example:
|
|
957
|
+
```html
|
|
958
|
+
<pagination-nav current-page="1" total-pages="5"></pagination-nav>
|
|
959
|
+
```
|
|
960
|
+
|
|
783
961
|
## <percent-bar-chart>
|
|
784
962
|
|
|
785
963
|
Horizontal bar chart for labeled percentage rows, using D3's linear scale.
|
|
@@ -1095,6 +1273,57 @@ Example:
|
|
|
1095
1273
|
</script>
|
|
1096
1274
|
```
|
|
1097
1275
|
|
|
1276
|
+
## <timeline-container>
|
|
1277
|
+
|
|
1278
|
+
Vertical timeline: a single connecting line runs down the left edge and each
|
|
1279
|
+
slotted `timeline-entry` places a dot on it. This is a thin layout and
|
|
1280
|
+
semantics wrapper — the entries draw the line segments and dots themselves,
|
|
1281
|
+
so the container adds no gap between them (a gap would break the line).
|
|
1282
|
+
Exposed to assistive technology as a list of events.
|
|
1283
|
+
|
|
1284
|
+
Import: `import "@f-ewald/components/timeline-container.js";`
|
|
1285
|
+
|
|
1286
|
+
Properties: none
|
|
1287
|
+
Events: none
|
|
1288
|
+
CSS custom properties: none
|
|
1289
|
+
|
|
1290
|
+
Example:
|
|
1291
|
+
```html
|
|
1292
|
+
<timeline-container>
|
|
1293
|
+
<timeline-entry datetime="2026-07-23T09:00:00Z">
|
|
1294
|
+
<span slot="headline">Deployment started</span>
|
|
1295
|
+
Release v1.4.0 is rolling out.
|
|
1296
|
+
</timeline-entry>
|
|
1297
|
+
<timeline-entry datetime="2026-07-23T08:45:00Z">
|
|
1298
|
+
<span slot="headline">Review approved</span>
|
|
1299
|
+
<status-pill label="In Review" color="info"></status-pill>
|
|
1300
|
+
</timeline-entry>
|
|
1301
|
+
</timeline-container>
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
## <timeline-entry>
|
|
1305
|
+
|
|
1306
|
+
One event on a `timeline-container`: a dot on the vertical line, an optional
|
|
1307
|
+
headline, a relative timestamp ("3 hours ago"), and freely nested content.
|
|
1308
|
+
The connecting line is drawn here — its segment above the dot is hidden on
|
|
1309
|
+
the first entry and the segment below is hidden on the last, so the line caps
|
|
1310
|
+
exactly at the first and last dots. Only meaningful inside a
|
|
1311
|
+
`timeline-container`; demonstrated through it.
|
|
1312
|
+
|
|
1313
|
+
Import: `import "@f-ewald/components/timeline-entry.js";`
|
|
1314
|
+
|
|
1315
|
+
Properties: `datetime` (attribute `datetime`) : string | null, default null
|
|
1316
|
+
Events: none
|
|
1317
|
+
CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-weight-semibold`, `--ui-line-height-normal`, `--ui-line-height-tight`, `--ui-primary`, `--ui-text`, `--ui-text-muted`
|
|
1318
|
+
|
|
1319
|
+
Example:
|
|
1320
|
+
```html
|
|
1321
|
+
<timeline-entry datetime="2026-07-23T09:00:00Z">
|
|
1322
|
+
<span slot="headline">Deployment started</span>
|
|
1323
|
+
Release v1.4.0 is rolling out to production.
|
|
1324
|
+
</timeline-entry>
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1098
1327
|
## <toast-notification>
|
|
1099
1328
|
|
|
1100
1329
|
Fixed-position stack of dismissible notifications, anchored top-right
|