@f-ewald/components 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/custom-elements.json +1651 -115
- package/dist/auto-scroll.d.ts +37 -0
- package/dist/auto-scroll.d.ts.map +1 -0
- package/dist/auto-scroll.js +100 -0
- package/dist/auto-scroll.js.map +1 -0
- package/dist/form-field.d.ts +39 -0
- package/dist/form-field.d.ts.map +1 -0
- package/dist/form-field.js +145 -0
- package/dist/form-field.js.map +1 -0
- package/dist/icons.d.ts +1 -0
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +1 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/load-more.d.ts +33 -0
- package/dist/load-more.d.ts.map +1 -0
- package/dist/load-more.js +82 -0
- package/dist/load-more.js.map +1 -0
- package/dist/percent-bar-chart.d.ts +32 -3
- package/dist/percent-bar-chart.d.ts.map +1 -1
- package/dist/percent-bar-chart.js +101 -36
- package/dist/percent-bar-chart.js.map +1 -1
- package/dist/scroll-to-bottom.d.ts +41 -0
- package/dist/scroll-to-bottom.d.ts.map +1 -0
- package/dist/scroll-to-bottom.js +189 -0
- package/dist/scroll-to-bottom.js.map +1 -0
- package/dist/scroll-to-top.d.ts +41 -0
- package/dist/scroll-to-top.d.ts.map +1 -0
- package/dist/scroll-to-top.js +189 -0
- package/dist/scroll-to-top.js.map +1 -0
- package/dist/tree-view.d.ts +44 -0
- package/dist/tree-view.d.ts.map +1 -0
- package/dist/tree-view.js +200 -0
- package/dist/tree-view.js.map +1 -0
- package/dist/ui-checkbox.d.ts +49 -0
- package/dist/ui-checkbox.d.ts.map +1 -0
- package/dist/ui-checkbox.js +228 -0
- package/dist/ui-checkbox.js.map +1 -0
- package/dist/utils/scroll.d.ts +9 -0
- package/dist/utils/scroll.d.ts.map +1 -0
- package/dist/utils/scroll.js +30 -0
- package/dist/utils/scroll.js.map +1 -0
- package/docs/auto-scroll.md +52 -0
- package/docs/form-field.md +63 -0
- package/docs/layouts/form-page.md +8 -4
- package/docs/load-more.md +43 -0
- package/docs/percent-bar-chart.md +19 -5
- package/docs/scroll-to-bottom.md +68 -0
- package/docs/scroll-to-top.md +59 -0
- package/docs/tree-view.md +69 -0
- package/docs/ui-checkbox.md +58 -0
- package/llms.txt +223 -6
- package/package.json +1 -1
package/llms.txt
CHANGED
|
@@ -169,6 +169,37 @@ Example:
|
|
|
169
169
|
</app-sidebar>
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
## <auto-scroll>
|
|
173
|
+
|
|
174
|
+
Wraps arbitrary slotted content (e.g. `timeline-container`) and keeps it
|
|
175
|
+
scrolled to the bottom as new children are appended — but only while the
|
|
176
|
+
user is already scrolled near the bottom ("stick to bottom", a chat/log-
|
|
177
|
+
viewer convention). If the user has scrolled up to read earlier content,
|
|
178
|
+
new content does not yank the scroll position back down.
|
|
179
|
+
|
|
180
|
+
New content is detected via a `MutationObserver`, so no cooperation from
|
|
181
|
+
whatever is slotted in is required. The host itself is the scrollable
|
|
182
|
+
region (`overflow-y: auto`) and needs a consumer-supplied bounded height to
|
|
183
|
+
have anything to scroll, e.g. `auto-scroll { height: 24rem; }`.
|
|
184
|
+
|
|
185
|
+
Import: `import "@f-ewald/components/auto-scroll.js";`
|
|
186
|
+
|
|
187
|
+
Properties: `threshold` (attribute `threshold`) : number, default 24; `pinned` (JS property only) : boolean, default —
|
|
188
|
+
Events: `pinned-change`
|
|
189
|
+
CSS custom properties: none
|
|
190
|
+
|
|
191
|
+
Example:
|
|
192
|
+
```html
|
|
193
|
+
<auto-scroll style="height: 24rem">
|
|
194
|
+
<timeline-container>
|
|
195
|
+
<timeline-entry datetime="2026-07-23T09:00:00Z">
|
|
196
|
+
<span slot="headline">Deployment started</span>
|
|
197
|
+
Release v1.4.0 is rolling out.
|
|
198
|
+
</timeline-entry>
|
|
199
|
+
</timeline-container>
|
|
200
|
+
</auto-scroll>
|
|
201
|
+
```
|
|
202
|
+
|
|
172
203
|
## <autocomplete-input>
|
|
173
204
|
|
|
174
205
|
Generic form-associated text input with a suggestion dropdown, for any
|
|
@@ -608,6 +639,39 @@ Example:
|
|
|
608
639
|
</form-actions>
|
|
609
640
|
```
|
|
610
641
|
|
|
642
|
+
## <form-field>
|
|
643
|
+
|
|
644
|
+
Per-field wrapper for a form control: label, slotted control, and an
|
|
645
|
+
optional hint or error message, in one consistent unit repeated across a
|
|
646
|
+
form. Purely presentational — composes whatever control is slotted
|
|
647
|
+
(`form-select`, `multi-select`, `autocomplete-input`, `ui-checkbox`, etc.)
|
|
648
|
+
without intercepting its events or value.
|
|
649
|
+
|
|
650
|
+
The label wraps the default slot for a best-effort visual/click
|
|
651
|
+
association only: every existing value-entry control encapsulates its
|
|
652
|
+
real `<input>` inside its own shadow DOM, so there is no light-DOM `id` a
|
|
653
|
+
`for` attribute could target from outside, and this component cannot set
|
|
654
|
+
`aria-describedby`/`aria-invalid` on an arbitrary slotted control's
|
|
655
|
+
shadow-encapsulated input for the same reason. The error message uses
|
|
656
|
+
`role="alert"` as the practical accessibility mitigation instead of true
|
|
657
|
+
`aria-describedby` association.
|
|
658
|
+
|
|
659
|
+
Import: `import "@f-ewald/components/form-field.js";`
|
|
660
|
+
|
|
661
|
+
Properties: `label` (attribute `label`) : string, default ""; `hint` (attribute `hint`) : string, default ""; `error` (attribute `error`) : string, default ""; `required` (attribute `required`) : boolean, default false
|
|
662
|
+
Events: none
|
|
663
|
+
CSS custom properties: `--ui-danger`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-size-xs`, `--ui-font-weight-medium`, `--ui-line-height-tight`, `--ui-text`, `--ui-text-muted`
|
|
664
|
+
|
|
665
|
+
Example:
|
|
666
|
+
```html
|
|
667
|
+
<form-field label="Task state" hint="Only affects your own view">
|
|
668
|
+
<form-select></form-select>
|
|
669
|
+
</form-field>
|
|
670
|
+
<form-field label="Terms" required error="You must accept to continue">
|
|
671
|
+
<ui-checkbox label="I agree to the terms"></ui-checkbox>
|
|
672
|
+
</form-field>
|
|
673
|
+
```
|
|
674
|
+
|
|
611
675
|
## <form-select>
|
|
612
676
|
|
|
613
677
|
A styled dropdown select: a trigger button showing the current option's
|
|
@@ -909,6 +973,25 @@ Example:
|
|
|
909
973
|
<live-timer since="2026-07-19T12:00:00Z" format="compact" prefix="running for "></live-timer>
|
|
910
974
|
```
|
|
911
975
|
|
|
976
|
+
## <load-more>
|
|
977
|
+
|
|
978
|
+
Click-to-load button for either end of a list. Fully property-driven: the
|
|
979
|
+
consumer sets `loading` while a fetch is in flight and `exhausted` once
|
|
980
|
+
there's nothing left to load; this component never fetches or manages
|
|
981
|
+
state itself.
|
|
982
|
+
|
|
983
|
+
Import: `import "@f-ewald/components/load-more.js";`
|
|
984
|
+
|
|
985
|
+
Properties: `direction` (attribute `direction`) : "top" | "bottom", default "bottom"; `loading` (attribute `loading`) : boolean, default false; `exhausted` (attribute `exhausted`) : boolean, default false; `label` (attribute `label`) : string, default "Load more"; `exhaustedLabel` (attribute `exhausted-label`) : string, default "No more results"
|
|
986
|
+
Events: `load-more`
|
|
987
|
+
CSS custom properties: none
|
|
988
|
+
|
|
989
|
+
Example:
|
|
990
|
+
```html
|
|
991
|
+
<load-more direction="top" label="Load older"></load-more>
|
|
992
|
+
<load-more></load-more>
|
|
993
|
+
```
|
|
994
|
+
|
|
912
995
|
## <map-circle>
|
|
913
996
|
|
|
914
997
|
A plain circular map marker: a light-to-dark gradient fill with a white
|
|
@@ -1108,12 +1191,16 @@ Example:
|
|
|
1108
1191
|
|
|
1109
1192
|
## <percent-bar-chart>
|
|
1110
1193
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1194
|
+
Bar chart for labeled rows, using D3's linear scale. Horizontal (default)
|
|
1195
|
+
renders stacked rows with bars growing rightward; `orientation="vertical"`
|
|
1196
|
+
renders side-by-side columns growing upward instead. `mode="percent"`
|
|
1197
|
+
(default) scales `value` against a fixed 0-100 domain and labels it with a
|
|
1198
|
+
`%` suffix; `mode="value"` scales it against `max` (or the largest `value`
|
|
1199
|
+
present) and formats it with `valueFormat`.
|
|
1113
1200
|
|
|
1114
1201
|
Import: `import "@f-ewald/components/percent-bar-chart.js";`
|
|
1115
1202
|
|
|
1116
|
-
Properties: `groups` (JS property only) : PercentBarGroup[], default []
|
|
1203
|
+
Properties: `groups` (JS property only) : PercentBarGroup[], default []; `mode` (attribute `mode`) : PercentBarMode, default "percent"; `orientation` (attribute `orientation`) : PercentBarOrientation, default "horizontal"; `max` (attribute `max`) : number | undefined, default —; `valueFormat` (JS property only) : (value: number) => string, default —
|
|
1117
1204
|
Events: none
|
|
1118
1205
|
CSS custom properties: `--ui-font`, `--ui-text-muted`
|
|
1119
1206
|
|
|
@@ -1121,10 +1208,16 @@ Example:
|
|
|
1121
1208
|
```html
|
|
1122
1209
|
<percent-bar-chart></percent-bar-chart>
|
|
1123
1210
|
<script type="module">
|
|
1124
|
-
document.querySelector("percent-bar-chart")
|
|
1125
|
-
|
|
1126
|
-
{ key: "
|
|
1211
|
+
const chart = document.querySelector("percent-bar-chart");
|
|
1212
|
+
chart.groups = [
|
|
1213
|
+
{ key: "a", label: "White", value: 45.2, color: "#4f46e5" },
|
|
1214
|
+
{ key: "b", label: "Asian", value: 28.1, color: "#0d9488" },
|
|
1127
1215
|
];
|
|
1216
|
+
|
|
1217
|
+
// Absolute values instead of percentages, as vertical columns:
|
|
1218
|
+
chart.mode = "value";
|
|
1219
|
+
chart.orientation = "vertical";
|
|
1220
|
+
chart.valueFormat = (value) => `$${value.toLocaleString()}`;
|
|
1128
1221
|
</script>
|
|
1129
1222
|
```
|
|
1130
1223
|
|
|
@@ -1325,6 +1418,67 @@ Example:
|
|
|
1325
1418
|
<roman-numeral value="2004"></roman-numeral>
|
|
1326
1419
|
```
|
|
1327
1420
|
|
|
1421
|
+
## <scroll-to-bottom>
|
|
1422
|
+
|
|
1423
|
+
Overlay button that appears once the page (or a given `target` container)
|
|
1424
|
+
has scrolled more than `threshold` pixels away from the bottom edge, and
|
|
1425
|
+
scrolls back to the bottom on click.
|
|
1426
|
+
|
|
1427
|
+
With no `target` (default), the button is `position: fixed` to the
|
|
1428
|
+
viewport. When `target` is set, the button switches to `position:
|
|
1429
|
+
absolute` and expects to be placed as a descendant of a `position:
|
|
1430
|
+
relative` (or otherwise positioned) ancestor that establishes the visual
|
|
1431
|
+
bounds to float within — typically `target` itself, given `overflow-y:
|
|
1432
|
+
auto; position: relative`, so the button stays pinned to that container's
|
|
1433
|
+
own visible corner as its content scrolls, rather than floating over the
|
|
1434
|
+
whole page.
|
|
1435
|
+
|
|
1436
|
+
Import: `import "@f-ewald/components/scroll-to-bottom.js";`
|
|
1437
|
+
|
|
1438
|
+
Properties: `target` (JS property only) : HTMLElement | null, default null; `threshold` (attribute `threshold`) : number, default 200; `label` (attribute `label`) : string, default "Scroll to bottom"
|
|
1439
|
+
Events: `scroll-to-bottom-triggered`
|
|
1440
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-line-height-tight`, `--ui-shadow`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`
|
|
1441
|
+
|
|
1442
|
+
Example:
|
|
1443
|
+
```html
|
|
1444
|
+
<scroll-to-bottom></scroll-to-bottom>
|
|
1445
|
+
|
|
1446
|
+
<!-- Floats inside its own scrollport instead of the whole page: -->
|
|
1447
|
+
<div id="log" style="position: relative; overflow-y: auto; height: 10rem">
|
|
1448
|
+
...
|
|
1449
|
+
<scroll-to-bottom threshold="20"></scroll-to-bottom>
|
|
1450
|
+
</div>
|
|
1451
|
+
<script type="module">
|
|
1452
|
+
document.querySelector('scroll-to-bottom').target = document.querySelector('#log');
|
|
1453
|
+
</script>
|
|
1454
|
+
```
|
|
1455
|
+
|
|
1456
|
+
## <scroll-to-top>
|
|
1457
|
+
|
|
1458
|
+
Overlay button that appears once the page (or a given `target` container)
|
|
1459
|
+
has scrolled more than `threshold` pixels away from the top edge, and
|
|
1460
|
+
scrolls back to the top on click.
|
|
1461
|
+
|
|
1462
|
+
With no `target` (default), the button is `position: fixed` to the
|
|
1463
|
+
viewport. When `target` is set, the button switches to `position:
|
|
1464
|
+
absolute` and expects to be placed as a descendant of a `position:
|
|
1465
|
+
relative` (or otherwise positioned) ancestor that establishes the visual
|
|
1466
|
+
bounds to float within — typically `target` itself, given `overflow-y:
|
|
1467
|
+
auto; position: relative`, so the button stays pinned to that container's
|
|
1468
|
+
own visible corner as its content scrolls, rather than floating over the
|
|
1469
|
+
whole page.
|
|
1470
|
+
|
|
1471
|
+
Import: `import "@f-ewald/components/scroll-to-top.js";`
|
|
1472
|
+
|
|
1473
|
+
Properties: `target` (JS property only) : HTMLElement | null, default null; `threshold` (attribute `threshold`) : number, default 200; `label` (attribute `label`) : string, default "Scroll to top"
|
|
1474
|
+
Events: `scroll-to-top-triggered`
|
|
1475
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-line-height-tight`, `--ui-shadow`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`
|
|
1476
|
+
|
|
1477
|
+
Example:
|
|
1478
|
+
```html
|
|
1479
|
+
<scroll-to-top></scroll-to-top>
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1328
1482
|
## <slide-panel>
|
|
1329
1483
|
|
|
1330
1484
|
Generic sliding panel shell. Handles positioning, open/close animation,
|
|
@@ -1534,6 +1688,45 @@ Example:
|
|
|
1534
1688
|
</script>
|
|
1535
1689
|
```
|
|
1536
1690
|
|
|
1691
|
+
## <tree-view>
|
|
1692
|
+
|
|
1693
|
+
A generic, presentational tree shell: renders `nodes` recursively, one row
|
|
1694
|
+
per node, with each row's content produced by `renderNode` (default: plain
|
|
1695
|
+
label). Modeled on `data-table`'s headless pattern — knows nothing about
|
|
1696
|
+
what a node's `data` means beyond what `renderNode` does with it.
|
|
1697
|
+
|
|
1698
|
+
A node with a `children` array (even empty) is a folder: clicking or
|
|
1699
|
+
activating its row toggles expand/collapse instead of firing `node-click`.
|
|
1700
|
+
A node with no `children` is a leaf: clicking or activating its row fires
|
|
1701
|
+
`node-click`. Folders start collapsed; set `default-expanded` to start
|
|
1702
|
+
every folder expanded instead. Expansion state is otherwise managed
|
|
1703
|
+
internally and untouched by later `nodes` updates, so a user's manual
|
|
1704
|
+
toggles survive a data refresh.
|
|
1705
|
+
|
|
1706
|
+
Import: `import "@f-ewald/components/tree-view.js";`
|
|
1707
|
+
|
|
1708
|
+
Properties: `nodes` (JS property only) : TreeNode[], default []; `renderNode` (JS property only) : (node: TreeNode) => unknown, default —; `defaultExpanded` (attribute `default-expanded`) : boolean, default false
|
|
1709
|
+
Events: `node-click`
|
|
1710
|
+
CSS custom properties: `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
|
|
1711
|
+
|
|
1712
|
+
Example:
|
|
1713
|
+
```html
|
|
1714
|
+
<tree-view></tree-view>
|
|
1715
|
+
<script type="module">
|
|
1716
|
+
const tree = document.querySelector("tree-view");
|
|
1717
|
+
tree.nodes = [
|
|
1718
|
+
{
|
|
1719
|
+
id: "docs",
|
|
1720
|
+
label: "docs",
|
|
1721
|
+
children: [{ id: "fil_1", label: "notes.txt", data: { id: "fil_1" } }],
|
|
1722
|
+
},
|
|
1723
|
+
{ id: "fil_2", label: "readme.md", data: { id: "fil_2" } },
|
|
1724
|
+
];
|
|
1725
|
+
tree.renderNode = (node) => node.label;
|
|
1726
|
+
tree.addEventListener("node-click", (e) => console.log(e.detail));
|
|
1727
|
+
</script>
|
|
1728
|
+
```
|
|
1729
|
+
|
|
1537
1730
|
## <ui-button>
|
|
1538
1731
|
|
|
1539
1732
|
Button (or link styled as one) with an optional leading icon, in three
|
|
@@ -1565,6 +1758,30 @@ Example:
|
|
|
1565
1758
|
<ui-button variant="secondary" href="/properties?edit=42">Edit</ui-button>
|
|
1566
1759
|
```
|
|
1567
1760
|
|
|
1761
|
+
## <ui-checkbox>
|
|
1762
|
+
|
|
1763
|
+
A form-associated boolean checkbox, usable standalone or inside a native
|
|
1764
|
+
`<form>`. Submits `name=on` when checked (matching native
|
|
1765
|
+
`<input type="checkbox">` semantics) and participates fully in form
|
|
1766
|
+
`reset()`, ancestor `<fieldset disabled>`, and `required` validity.
|
|
1767
|
+
|
|
1768
|
+
Renders a native `<input type="checkbox">` wrapped in a `<label>`, styled
|
|
1769
|
+
via `:has()` on the wrapping label (matching `radio-pills`/`radio-cards`)
|
|
1770
|
+
rather than styling the native input directly; the checkbox itself renders
|
|
1771
|
+
at `1rem`, matching the existing radio-input convention.
|
|
1772
|
+
|
|
1773
|
+
Import: `import "@f-ewald/components/ui-checkbox.js";`
|
|
1774
|
+
|
|
1775
|
+
Properties: `checked` (attribute `checked`) : boolean, default false; `indeterminate` (attribute `indeterminate`) : boolean, default false; `disabled` (attribute `disabled`) : boolean, default false; `required` (attribute `required`) : boolean, default false; `name` (attribute `name`) : string, default ""; `label` (attribute `label`) : string, default ""
|
|
1776
|
+
Events: `change`
|
|
1777
|
+
CSS custom properties: `--ui-danger`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius-sm`, `--ui-text`
|
|
1778
|
+
|
|
1779
|
+
Example:
|
|
1780
|
+
```html
|
|
1781
|
+
<ui-checkbox label="Subscribe to updates"></ui-checkbox>
|
|
1782
|
+
<ui-checkbox name="terms" label="I agree to the terms" required></ui-checkbox>
|
|
1783
|
+
```
|
|
1784
|
+
|
|
1568
1785
|
## <user-avatar>
|
|
1569
1786
|
|
|
1570
1787
|
Circular avatar. Shows `src` when it loads successfully; falls back to the
|