@f-ewald/components 1.12.0 → 1.14.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.
Files changed (62) hide show
  1. package/README.md +6 -0
  2. package/custom-elements.json +1376 -49
  3. package/dist/auto-scroll.d.ts +37 -0
  4. package/dist/auto-scroll.d.ts.map +1 -0
  5. package/dist/auto-scroll.js +100 -0
  6. package/dist/auto-scroll.js.map +1 -0
  7. package/dist/form-field.d.ts +39 -0
  8. package/dist/form-field.d.ts.map +1 -0
  9. package/dist/form-field.js +145 -0
  10. package/dist/form-field.js.map +1 -0
  11. package/dist/icons.d.ts +1 -0
  12. package/dist/icons.d.ts.map +1 -1
  13. package/dist/icons.js +1 -0
  14. package/dist/icons.js.map +1 -1
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +6 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/load-more.d.ts +33 -0
  20. package/dist/load-more.d.ts.map +1 -0
  21. package/dist/load-more.js +82 -0
  22. package/dist/load-more.js.map +1 -0
  23. package/dist/map-circle.d.ts +12 -9
  24. package/dist/map-circle.d.ts.map +1 -1
  25. package/dist/map-circle.js +26 -12
  26. package/dist/map-circle.js.map +1 -1
  27. package/dist/map-pin.d.ts +7 -5
  28. package/dist/map-pin.d.ts.map +1 -1
  29. package/dist/map-pin.js +14 -8
  30. package/dist/map-pin.js.map +1 -1
  31. package/dist/percent-bar-chart.d.ts +32 -3
  32. package/dist/percent-bar-chart.d.ts.map +1 -1
  33. package/dist/percent-bar-chart.js +101 -36
  34. package/dist/percent-bar-chart.js.map +1 -1
  35. package/dist/scroll-to-bottom.d.ts +41 -0
  36. package/dist/scroll-to-bottom.d.ts.map +1 -0
  37. package/dist/scroll-to-bottom.js +189 -0
  38. package/dist/scroll-to-bottom.js.map +1 -0
  39. package/dist/scroll-to-top.d.ts +41 -0
  40. package/dist/scroll-to-top.d.ts.map +1 -0
  41. package/dist/scroll-to-top.js +189 -0
  42. package/dist/scroll-to-top.js.map +1 -0
  43. package/dist/ui-checkbox.d.ts +49 -0
  44. package/dist/ui-checkbox.d.ts.map +1 -0
  45. package/dist/ui-checkbox.js +228 -0
  46. package/dist/ui-checkbox.js.map +1 -0
  47. package/dist/utils/scroll.d.ts +9 -0
  48. package/dist/utils/scroll.d.ts.map +1 -0
  49. package/dist/utils/scroll.js +30 -0
  50. package/dist/utils/scroll.js.map +1 -0
  51. package/docs/auto-scroll.md +52 -0
  52. package/docs/form-field.md +63 -0
  53. package/docs/layouts/form-page.md +8 -4
  54. package/docs/load-more.md +43 -0
  55. package/docs/map-circle.md +11 -9
  56. package/docs/map-pin.md +6 -5
  57. package/docs/percent-bar-chart.md +19 -5
  58. package/docs/scroll-to-bottom.md +68 -0
  59. package/docs/scroll-to-top.md +59 -0
  60. package/docs/ui-checkbox.md +58 -0
  61. package/llms.txt +199 -20
  62. package/package.json +1 -1
@@ -0,0 +1,63 @@
1
+ # `<form-field>`
2
+
3
+ Per-field wrapper for a form control: label, slotted control, and an
4
+ optional hint or error message, in one consistent unit repeated across a
5
+ form. Purely presentational — composes whatever control is slotted
6
+ (`form-select`, `multi-select`, `autocomplete-input`, `ui-checkbox`, etc.)
7
+ without intercepting its events or value.
8
+
9
+ The label wraps the default slot for a best-effort visual/click
10
+ association only: every existing value-entry control encapsulates its
11
+ real `<input>` inside its own shadow DOM, so there is no light-DOM `id` a
12
+ `for` attribute could target from outside, and this component cannot set
13
+ `aria-describedby`/`aria-invalid` on an arbitrary slotted control's
14
+ shadow-encapsulated input for the same reason. The error message uses
15
+ `role="alert"` as the practical accessibility mitigation instead of true
16
+ `aria-describedby` association.
17
+
18
+ ## Install
19
+
20
+ ```js
21
+ import "@f-ewald/components/form-field.js";
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```html
27
+ <form-field label="Task state" hint="Only affects your own view">
28
+ <form-select></form-select>
29
+ </form-field>
30
+ <form-field label="Terms" required error="You must accept to continue">
31
+ <ui-checkbox label="I agree to the terms"></ui-checkbox>
32
+ </form-field>
33
+ ```
34
+
35
+ ## Attributes / properties
36
+
37
+ | Property | Attribute | Type | Default | Description |
38
+ | --- | --- | --- | --- | --- |
39
+ | `label` | `label` | `string` | `""` | Field label text. |
40
+ | `hint` | `hint` | `string` | `""` | Optional helper text shown below the control when there's no `error`. |
41
+ | `error` | `error` | `string` | `""` | Optional error text; replaces the `hint` display when non-empty. |
42
+ | `required` | `required` | `boolean` | `false` | Shows a required indicator next to the label. |
43
+
44
+ ## Events
45
+
46
+ _None._
47
+
48
+ ## Slots
49
+
50
+ _None._
51
+
52
+ ## CSS custom properties
53
+
54
+ | Custom property |
55
+ | --- |
56
+ | `--ui-danger` |
57
+ | `--ui-font` |
58
+ | `--ui-font-size-sm` |
59
+ | `--ui-font-size-xs` |
60
+ | `--ui-font-weight-medium` |
61
+ | `--ui-line-height-tight` |
62
+ | `--ui-text` |
63
+ | `--ui-text-muted` |
@@ -24,8 +24,11 @@ column so the eye tracks one field to the next.
24
24
  </page-header>
25
25
 
26
26
  <form style="max-width: 40rem;">
27
- <frame-box label="Details"><!-- name, email fields --></frame-box>
28
- <frame-box label="Role"><!-- role field --></frame-box>
27
+ <frame-box label="Details">
28
+ <form-field label="Name"><autocomplete-input name="name"></autocomplete-input></form-field>
29
+ <form-field label="Email" hint="Work email preferred"><autocomplete-input name="email"></autocomplete-input></form-field>
30
+ </frame-box>
31
+ <frame-box label="Role"><!-- role field, also wrapped in form-field --></frame-box>
29
32
 
30
33
  <form-actions>
31
34
  <ui-button slot="secondary" variant="secondary">Cancel</ui-button>
@@ -43,10 +46,11 @@ column so the eye tracks one field to the next.
43
46
  - Constrain the form with a `max-width` (about `40rem`); a full-width form on a
44
47
  wide dashboard is hard to scan.
45
48
  - Group related fields with `frame-box`; keep one field per row in a single
46
- column.
49
+ column. Wrap each individual field in `form-field` for a consistent
50
+ label/hint/error layout.
47
51
  - `ui-button type="submit"` associates with the ancestor `<form>` even from
48
52
  inside `form-actions`.
49
53
 
50
54
  **Live demo:** `demo/layouts/form-page.html`
51
55
 
52
- **Components:** app-shell, app-sidebar, page-header, frame-box, form-actions, ui-button
56
+ **Components:** app-shell, app-sidebar, page-header, frame-box, form-field, form-actions, ui-button
@@ -0,0 +1,43 @@
1
+ # `<load-more>`
2
+
3
+ Click-to-load button for either end of a list. Fully property-driven: the
4
+ consumer sets `loading` while a fetch is in flight and `exhausted` once
5
+ there's nothing left to load; this component never fetches or manages
6
+ state itself.
7
+
8
+ ## Install
9
+
10
+ ```js
11
+ import "@f-ewald/components/load-more.js";
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```html
17
+ <load-more direction="top" label="Load older"></load-more>
18
+ <load-more></load-more>
19
+ ```
20
+
21
+ ## Attributes / properties
22
+
23
+ | Property | Attribute | Type | Default | Description |
24
+ | --- | --- | --- | --- | --- |
25
+ | `direction` | `direction` | `"top" | "bottom"` | `"bottom"` | Which end of a list this instance loads more content for. |
26
+ | `loading` | `loading` | `boolean` | `false` | Consumer-managed busy flag, forwarded to the internal `ui-button`'s `busy`. |
27
+ | `exhausted` | `exhausted` | `boolean` | `false` | Terminal "no more content" state: disables the button and swaps its label. |
28
+ | `label` | `label` | `string` | `"Load more"` | Button text in the normal (loadable) state. |
29
+ | `exhaustedLabel` | `exhausted-label` | `string` | `"No more results"` | Button text shown once `exhausted` is true. |
30
+
31
+ ## Events
32
+
33
+ | Event | Description |
34
+ | --- | --- |
35
+ | `load-more` | The button was clicked while not `loading`/`exhausted`; detail: `{ direction }`. |
36
+
37
+ ## Slots
38
+
39
+ _None._
40
+
41
+ ## CSS custom properties
42
+
43
+ _None._
@@ -1,13 +1,14 @@
1
1
  # `<map-circle>`
2
2
 
3
- A plain circular map marker: a light-to-dark gradient fill with a white
4
- outer ring, no point/tail (unlike `<map-pin>`) — for markers that don't
5
- need to visually "point" at their exact coordinate. Purely a visual
6
- primitive — it has no `mapbox-gl` (or any mapping library) dependency;
7
- the consumer positions it, e.g. via `new mapboxgl.Marker({ element: el })`.
8
- It can also replace the former `<map-point>` dense-layer primitive: use
9
- `size="14" ring-width="3"`, leave the slot empty, and rasterize one marker
10
- per color for use as a map `icon-image`.
3
+ A plain circular map marker: a radial-gradient fill with a soft highlight
4
+ and a translucent white outer ring, no point/tail (unlike `<map-pin>`) —
5
+ for markers that don't need to visually "point" at their exact
6
+ coordinate. Purely a visual primitive — it has no `mapbox-gl` (or any
7
+ mapping library) dependency; the consumer positions it, e.g. via
8
+ `new mapboxgl.Marker({ element: el })`. It can also replace the former
9
+ `<map-point>` dense-layer primitive: use `size="14" ring-width="3"`, leave
10
+ the slot empty, and rasterize one marker per color for use as a map
11
+ `icon-image`.
11
12
 
12
13
  ## Install
13
14
 
@@ -27,9 +28,10 @@ import "@f-ewald/components/map-circle.js";
27
28
 
28
29
  | Property | Attribute | Type | Default | Description |
29
30
  | --- | --- | --- | --- | --- |
30
- | `color` | `color` | `string` | `"#4f46e5"` | Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. |
31
+ | `color` | `color` | `string` | `"#4f46e5"` | Fill color; the gradient's light (highlight) and dark (edge) stops are derived from this. |
31
32
  | `size` | `size` | `number` | `18` | Diameter, in CSS pixels. |
32
33
  | `ringWidth` | `ring-width` | `number` | `4` | White outer ring thickness, in the same viewBox units as `size` (scales with it). |
34
+ | `ringOpacity` | `ring-opacity` | `number` | `0.6` | Outer ring opacity, 0-1 (Apple Maps-style rings are translucent, not solid white). |
33
35
  | `highlighted` | `highlighted` | `boolean` | `false` | Scales and glows the circle — a generic emphasis state (e.g. hover, selection). |
34
36
 
35
37
  ## Events
package/docs/map-pin.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # `<map-pin>`
2
2
 
3
- A circular "Apple Maps"-style map pin: a light-to-dark gradient fill with
4
- a slight point at the bottom. Purely a visual primitive — it has no
5
- `mapbox-gl` (or any mapping library) dependency; the consumer positions
6
- it, e.g. via `new mapboxgl.Marker({ element: pinEl })`.
3
+ A circular "Apple Maps"-style map pin: a radial-gradient fill with a soft
4
+ highlight and a slight point at the bottom. Purely a visual primitive —
5
+ it has no `mapbox-gl` (or any mapping library) dependency; the consumer
6
+ positions it, e.g. via `new mapboxgl.Marker({ element: pinEl })`.
7
7
 
8
8
  ## Install
9
9
 
@@ -22,8 +22,9 @@ import "@f-ewald/components/map-pin.js";
22
22
 
23
23
  | Property | Attribute | Type | Default | Description |
24
24
  | --- | --- | --- | --- | --- |
25
- | `color` | `color` | `string` | `"#4f46e5"` | Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. |
25
+ | `color` | `color` | `string` | `"#4f46e5"` | Fill color; the gradient's light (highlight) and dark (edge) stops are derived from this. |
26
26
  | `size` | `size` | `number` | `32` | Diameter of the circular head, in CSS pixels. |
27
+ | `ringOpacity` | `ring-opacity` | `number` | `0.6` | Outer ring opacity, 0-1 (Apple Maps-style rings are translucent, not solid white). |
27
28
  | `highlighted` | `highlighted` | `boolean` | `false` | Scales and glows the pin — a generic emphasis state (e.g. hover, selection). |
28
29
 
29
30
  ## Events
@@ -1,7 +1,11 @@
1
1
  # `<percent-bar-chart>`
2
2
 
3
- Horizontal bar chart for labeled percentage rows, using D3's linear scale.
4
- Each group gets its own labeled row; bars are proportional to percentage of 100.
3
+ Bar chart for labeled rows, using D3's linear scale. Horizontal (default)
4
+ renders stacked rows with bars growing rightward; `orientation="vertical"`
5
+ renders side-by-side columns growing upward instead. `mode="percent"`
6
+ (default) scales `value` against a fixed 0-100 domain and labels it with a
7
+ `%` suffix; `mode="value"` scales it against `max` (or the largest `value`
8
+ present) and formats it with `valueFormat`.
5
9
 
6
10
  ## Install
7
11
 
@@ -14,10 +18,16 @@ import "@f-ewald/components/percent-bar-chart.js";
14
18
  ```html
15
19
  <percent-bar-chart></percent-bar-chart>
16
20
  <script type="module">
17
- document.querySelector("percent-bar-chart").groups = [
18
- { key: "a", label: "White", pct: 45.2, color: "#4f46e5" },
19
- { key: "b", label: "Asian", pct: 28.1, color: "#0d9488" },
21
+ const chart = document.querySelector("percent-bar-chart");
22
+ chart.groups = [
23
+ { key: "a", label: "White", value: 45.2, color: "#4f46e5" },
24
+ { key: "b", label: "Asian", value: 28.1, color: "#0d9488" },
20
25
  ];
26
+
27
+ // Absolute values instead of percentages, as vertical columns:
28
+ chart.mode = "value";
29
+ chart.orientation = "vertical";
30
+ chart.valueFormat = (value) => `$${value.toLocaleString()}`;
21
31
  </script>
22
32
  ```
23
33
 
@@ -26,6 +36,10 @@ import "@f-ewald/components/percent-bar-chart.js";
26
36
  | Property | Attribute | Type | Default | Description |
27
37
  | --- | --- | --- | --- | --- |
28
38
  | `groups` | _(JS property only)_ | `PercentBarGroup[]` | `[]` | Rows to render, one per group. |
39
+ | `mode` | `mode` | `PercentBarMode` | `"percent"` | Whether `value` is a 0-100 percentage (fixed domain) or an arbitrary number (domain from data/`max`). |
40
+ | `orientation` | `orientation` | `PercentBarOrientation` | `"horizontal"` | Bar direction: stacked rows growing rightward, or columns growing upward. |
41
+ | `max` | `max` | `number | undefined` | `—` | Explicit domain max for `mode="value"`; auto-computed from `groups` when unset. Ignored in `mode="percent"`. |
42
+ | `valueFormat` | _(JS property only)_ | `(value: number) => string` | `—` | Formats a row's value for its label in `mode="value"`. Defaults to locale-formatted number. |
29
43
 
30
44
  ## Events
31
45
 
@@ -0,0 +1,68 @@
1
+ # `<scroll-to-bottom>`
2
+
3
+ Overlay button that appears once the page (or a given `target` container)
4
+ has scrolled more than `threshold` pixels away from the bottom edge, and
5
+ scrolls back to the bottom on click.
6
+
7
+ With no `target` (default), the button is `position: fixed` to the
8
+ viewport. When `target` is set, the button switches to `position:
9
+ absolute` and expects to be placed as a descendant of a `position:
10
+ relative` (or otherwise positioned) ancestor that establishes the visual
11
+ bounds to float within — typically `target` itself, given `overflow-y:
12
+ auto; position: relative`, so the button stays pinned to that container's
13
+ own visible corner as its content scrolls, rather than floating over the
14
+ whole page.
15
+
16
+ ## Install
17
+
18
+ ```js
19
+ import "@f-ewald/components/scroll-to-bottom.js";
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```html
25
+ <scroll-to-bottom></scroll-to-bottom>
26
+
27
+ <!-- Floats inside its own scrollport instead of the whole page: -->
28
+ <div id="log" style="position: relative; overflow-y: auto; height: 10rem">
29
+ ...
30
+ <scroll-to-bottom threshold="20"></scroll-to-bottom>
31
+ </div>
32
+ <script type="module">
33
+ document.querySelector('scroll-to-bottom').target = document.querySelector('#log');
34
+ </script>
35
+ ```
36
+
37
+ ## Attributes / properties
38
+
39
+ | Property | Attribute | Type | Default | Description |
40
+ | --- | --- | --- | --- | --- |
41
+ | `target` | _(JS property only)_ | `HTMLElement | null` | `null` | Scrollable container to control; `null` (default) scrolls `window`. |
42
+ | `threshold` | `threshold` | `number` | `200` | Pixels scrolled away from the bottom before the button appears. |
43
+ | `label` | `label` | `string` | `"Scroll to bottom"` | Visible button text, and its accessible name. |
44
+
45
+ ## Events
46
+
47
+ | Event | Description |
48
+ | --- | --- |
49
+ | `scroll-to-bottom-triggered` | The button was clicked, just before scrolling; detail: `{ target }`. |
50
+
51
+ ## Slots
52
+
53
+ _None._
54
+
55
+ ## CSS custom properties
56
+
57
+ | Custom property |
58
+ | --- |
59
+ | `--ui-border` |
60
+ | `--ui-focus-ring` |
61
+ | `--ui-font` |
62
+ | `--ui-font-size-sm` |
63
+ | `--ui-font-weight-medium` |
64
+ | `--ui-line-height-tight` |
65
+ | `--ui-shadow` |
66
+ | `--ui-surface` |
67
+ | `--ui-surface-muted` |
68
+ | `--ui-text` |
@@ -0,0 +1,59 @@
1
+ # `<scroll-to-top>`
2
+
3
+ Overlay button that appears once the page (or a given `target` container)
4
+ has scrolled more than `threshold` pixels away from the top edge, and
5
+ scrolls back to the top on click.
6
+
7
+ With no `target` (default), the button is `position: fixed` to the
8
+ viewport. When `target` is set, the button switches to `position:
9
+ absolute` and expects to be placed as a descendant of a `position:
10
+ relative` (or otherwise positioned) ancestor that establishes the visual
11
+ bounds to float within — typically `target` itself, given `overflow-y:
12
+ auto; position: relative`, so the button stays pinned to that container's
13
+ own visible corner as its content scrolls, rather than floating over the
14
+ whole page.
15
+
16
+ ## Install
17
+
18
+ ```js
19
+ import "@f-ewald/components/scroll-to-top.js";
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```html
25
+ <scroll-to-top></scroll-to-top>
26
+ ```
27
+
28
+ ## Attributes / properties
29
+
30
+ | Property | Attribute | Type | Default | Description |
31
+ | --- | --- | --- | --- | --- |
32
+ | `target` | _(JS property only)_ | `HTMLElement | null` | `null` | Scrollable container to control; `null` (default) scrolls `window`. |
33
+ | `threshold` | `threshold` | `number` | `200` | Pixels scrolled away from the top before the button appears. |
34
+ | `label` | `label` | `string` | `"Scroll to top"` | Visible button text, and its accessible name. |
35
+
36
+ ## Events
37
+
38
+ | Event | Description |
39
+ | --- | --- |
40
+ | `scroll-to-top-triggered` | The button was clicked, just before scrolling; detail: `{ target }`. |
41
+
42
+ ## Slots
43
+
44
+ _None._
45
+
46
+ ## CSS custom properties
47
+
48
+ | Custom property |
49
+ | --- |
50
+ | `--ui-border` |
51
+ | `--ui-focus-ring` |
52
+ | `--ui-font` |
53
+ | `--ui-font-size-sm` |
54
+ | `--ui-font-weight-medium` |
55
+ | `--ui-line-height-tight` |
56
+ | `--ui-shadow` |
57
+ | `--ui-surface` |
58
+ | `--ui-surface-muted` |
59
+ | `--ui-text` |
@@ -0,0 +1,58 @@
1
+ # `<ui-checkbox>`
2
+
3
+ A form-associated boolean checkbox, usable standalone or inside a native
4
+ `<form>`. Submits `name=on` when checked (matching native
5
+ `<input type="checkbox">` semantics) and participates fully in form
6
+ `reset()`, ancestor `<fieldset disabled>`, and `required` validity.
7
+
8
+ Renders a native `<input type="checkbox">` wrapped in a `<label>`, styled
9
+ via `:has()` on the wrapping label (matching `radio-pills`/`radio-cards`)
10
+ rather than styling the native input directly; the checkbox itself renders
11
+ at `1rem`, matching the existing radio-input convention.
12
+
13
+ ## Install
14
+
15
+ ```js
16
+ import "@f-ewald/components/ui-checkbox.js";
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```html
22
+ <ui-checkbox label="Subscribe to updates"></ui-checkbox>
23
+ <ui-checkbox name="terms" label="I agree to the terms" required></ui-checkbox>
24
+ ```
25
+
26
+ ## Attributes / properties
27
+
28
+ | Property | Attribute | Type | Default | Description |
29
+ | --- | --- | --- | --- | --- |
30
+ | `checked` | `checked` | `boolean` | `false` | Whether the box is checked. |
31
+ | `indeterminate` | `indeterminate` | `boolean` | `false` | Visual "partial selection" state; cleared on the next user interaction. |
32
+ | `disabled` | `disabled` | `boolean` | `false` | Disables interaction; merged with an ancestor `<fieldset disabled>`. |
33
+ | `required` | `required` | `boolean` | `false` | Marks the control invalid via `ElementInternals` while unchecked. |
34
+ | `name` | `name` | `string` | `""` | Form field name; submitted as `name=on` only while checked. |
35
+ | `label` | `label` | `string` | `""` | Visible label text rendered next to the box. |
36
+
37
+ ## Events
38
+
39
+ | Event | Description |
40
+ | --- | --- |
41
+ | `change` | The checkbox was toggled by the user, in either direction; detail: `{ checked }`. Programmatic `checked` assignments do not fire it. |
42
+
43
+ ## Slots
44
+
45
+ _None._
46
+
47
+ ## CSS custom properties
48
+
49
+ | Custom property |
50
+ | --- |
51
+ | `--ui-danger` |
52
+ | `--ui-focus-ring` |
53
+ | `--ui-font` |
54
+ | `--ui-font-size-sm` |
55
+ | `--ui-line-height-tight` |
56
+ | `--ui-primary` |
57
+ | `--ui-radius-sm` |
58
+ | `--ui-text` |