@f-ewald/components 1.14.1 → 1.16.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.
@@ -1 +1 @@
1
- {"version":3,"file":"tree-view.js","sourceRoot":"","sources":["../src/tree-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type TemplateResult } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { iconChevronDown, iconChevronRight } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** One tree node: a folder when `children` is set (even `[]`), a leaf otherwise. */\nexport interface TreeNode {\n id: string;\n label: string;\n children?: TreeNode[];\n data?: unknown;\n}\n\n/**\n * A generic, presentational tree shell: renders `nodes` recursively, one row\n * per node, with each row's content produced by `renderNode` (default: plain\n * label). Modeled on `data-table`'s headless pattern — knows nothing about\n * what a node's `data` means beyond what `renderNode` does with it.\n *\n * A node with a `children` array (even empty) is a folder: clicking or\n * activating its row toggles expand/collapse instead of firing `node-click`.\n * A node with no `children` is a leaf: clicking or activating its row fires\n * `node-click`. Folders start collapsed; set `default-expanded` to start\n * every folder expanded instead. Expansion state is otherwise managed\n * internally and untouched by later `nodes` updates, so a user's manual\n * toggles survive a data refresh.\n *\n * @element tree-view\n * @fires node-click - A leaf row was activated; detail is `{ id, data }`.\n */\n@customElement(\"tree-view\")\nexport class TreeView extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n .row {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n border-radius: var(--ui-radius-sm, 0.25rem);\n color: var(--ui-text, #0f172a);\n cursor: pointer;\n }\n .row:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .row:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .toggle {\n display: inline-flex;\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n color: var(--ui-text-muted, #64748b);\n }\n .content {\n min-width: 0;\n flex: 1;\n }\n @media (forced-colors: active) {\n .row:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: -2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n /** Tree data; opaque to this component beyond what `renderNode` does with it. */\n @property({ attribute: false }) nodes: TreeNode[] = [];\n /** Produces a row's rendered content for `node`. Default: plain label text. */\n @property({ attribute: false }) renderNode: (node: TreeNode) => unknown = (node) => node.label;\n /** Start every folder expanded instead of the default all-collapsed. */\n @property({ type: Boolean, attribute: \"default-expanded\" }) defaultExpanded = false;\n\n @state() private expanded = new Set<string>();\n #initializedExpansion = false;\n\n override willUpdate(changed: Map<string, unknown>): void {\n if (!changed.has(\"nodes\") || this.#initializedExpansion) return;\n this.#initializedExpansion = true;\n if (!this.defaultExpanded) return;\n const all = new Set<string>();\n const collect = (list: TreeNode[]) => {\n for (const node of list) {\n if (!node.children) continue;\n all.add(node.id);\n collect(node.children);\n }\n };\n collect(this.nodes);\n this.expanded = all;\n }\n\n #toggle(id: string): void {\n const next = new Set(this.expanded);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n this.expanded = next;\n }\n\n #activate(node: TreeNode): void {\n if (node.children) {\n this.#toggle(node.id);\n return;\n }\n this.dispatchEvent(\n new CustomEvent(\"node-click\", {\n detail: { id: node.id, data: node.data },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n #onKeydown(node: TreeNode, e: KeyboardEvent): void {\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n if (e.target !== e.currentTarget) return;\n e.preventDefault();\n this.#activate(node);\n }\n\n #onRowClick(node: TreeNode, e: MouseEvent): void {\n if (this.#isNestedInteractive(e.composedPath(), e.currentTarget)) return;\n this.#activate(node);\n }\n\n #isNestedInteractive(path: EventTarget[], row: EventTarget | null): boolean {\n const selector =\n \"a, button, input, select, textarea, summary, [contenteditable], [role='button'], [role='link'], [tabindex]\";\n for (const target of path) {\n if (target === row) return false;\n if (target instanceof HTMLElement && target.matches(selector)) return true;\n }\n return false;\n }\n\n #renderNode(node: TreeNode, depth: number): TemplateResult {\n const isFolder = !!node.children;\n const isOpen = isFolder && this.expanded.has(node.id);\n return html`\n <div\n class=\"row\"\n role=${isFolder ? \"button\" : \"link\"}\n aria-expanded=${isFolder ? String(isOpen) : nothing}\n tabindex=\"0\"\n style=\"padding-left: ${depth * 1.25}rem\"\n @click=${(e: MouseEvent) => this.#onRowClick(node, e)}\n @keydown=${(e: KeyboardEvent) => this.#onKeydown(node, e)}\n >\n <span class=\"toggle\" aria-hidden=\"true\">\n ${isFolder ? (isOpen ? iconChevronDown(14) : iconChevronRight(14)) : nothing}\n </span>\n <span class=\"content\">${this.renderNode(node)}</span>\n </div>\n ${isFolder && isOpen\n ? repeat(\n node.children!,\n (child) => child.id,\n (child) => this.#renderNode(child, depth + 1),\n )\n : nothing}\n `;\n }\n\n override render() {\n return repeat(\n this.nodes,\n (node) => node.id,\n (node) => this.#renderNode(node, 0),\n );\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"tree-view\": TreeView;\n }\n}\n"]}
1
+ {"version":3,"file":"tree-view.js","sourceRoot":"","sources":["../src/tree-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type TemplateResult } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { iconChevronDown, iconChevronRight } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/** One tree node: a folder when `children` is set (even `[]`), a leaf otherwise. */\nexport interface TreeNode {\n id: string;\n label: string;\n children?: TreeNode[];\n data?: unknown;\n}\n\n/**\n * A generic, presentational tree shell: renders `nodes` recursively, one row\n * per node, with each row's content produced by `renderNode` (default: plain\n * label). Modeled on `data-table`'s headless pattern — knows nothing about\n * what a node's `data` means beyond what `renderNode` does with it.\n *\n * A node with a `children` array (even empty) is a folder: clicking or\n * activating its row toggles expand/collapse instead of firing `node-click`.\n * A node with no `children` is a leaf: clicking or activating its row fires\n * `node-click`. Folders start collapsed; set `default-expanded` to start\n * every folder expanded instead. Expansion state is otherwise managed\n * internally and untouched by later `nodes` updates, so a user's manual\n * toggles survive a data refresh.\n *\n * Set the `lines` boolean to draw classic file-tree connector guides: a\n * vertical line per continuing ancestor level and a branch elbow (`└`) or\n * tee (`├`) linking each node to its parent. Off by default (indentation only).\n *\n * @element tree-view\n * @fires node-click - A leaf row was activated; detail is `{ id, data }`.\n */\n@customElement(\"tree-view\")\nexport class TreeView extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n .row {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n border-radius: var(--ui-radius-sm, 0.25rem);\n color: var(--ui-text, #0f172a);\n cursor: pointer;\n }\n .row:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .row:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .toggle {\n display: inline-flex;\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n color: var(--ui-text-muted, #64748b);\n }\n .content {\n min-width: 0;\n flex: 1;\n }\n :host([lines]) .row {\n padding-top: 0;\n padding-bottom: 0;\n min-height: 1.5rem;\n }\n .guides {\n display: flex;\n align-self: stretch;\n flex-shrink: 0;\n }\n .guide {\n position: relative;\n flex: 0 0 auto;\n width: 1rem;\n }\n .guide.v::before,\n .guide.connector::before {\n content: \"\";\n position: absolute;\n left: 50%;\n top: 0;\n bottom: 0;\n border-left: 1px solid var(--ui-border, #e2e8f0);\n }\n .guide.connector.last::before {\n bottom: 50%;\n }\n .guide.connector::after {\n content: \"\";\n position: absolute;\n left: 50%;\n right: 0;\n top: 50%;\n border-top: 1px solid var(--ui-border, #e2e8f0);\n }\n @media (forced-colors: active) {\n .row:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: -2px;\n box-shadow: none;\n }\n .guide.v::before,\n .guide.connector::before,\n .guide.connector::after {\n border-color: CanvasText;\n }\n }\n `,\n ];\n\n /** Tree data; opaque to this component beyond what `renderNode` does with it. */\n @property({ attribute: false }) nodes: TreeNode[] = [];\n /** Produces a row's rendered content for `node`. Default: plain label text. */\n @property({ attribute: false }) renderNode: (node: TreeNode) => unknown = (node) => node.label;\n /** Start every folder expanded instead of the default all-collapsed. */\n @property({ type: Boolean, attribute: \"default-expanded\" }) defaultExpanded = false;\n /**\n * Draw classic file-tree connector guides (vertical ancestor lines plus a\n * branch elbow/tee per row) instead of indentation alone. Off by default.\n */\n @property({ type: Boolean, reflect: true }) lines = false;\n\n @state() private expanded = new Set<string>();\n #initializedExpansion = false;\n\n override willUpdate(changed: Map<string, unknown>): void {\n if (!changed.has(\"nodes\") || this.#initializedExpansion) return;\n this.#initializedExpansion = true;\n if (!this.defaultExpanded) return;\n const all = new Set<string>();\n const collect = (list: TreeNode[]) => {\n for (const node of list) {\n if (!node.children) continue;\n all.add(node.id);\n collect(node.children);\n }\n };\n collect(this.nodes);\n this.expanded = all;\n }\n\n #toggle(id: string): void {\n const next = new Set(this.expanded);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n this.expanded = next;\n }\n\n #activate(node: TreeNode): void {\n if (node.children) {\n this.#toggle(node.id);\n return;\n }\n this.dispatchEvent(\n new CustomEvent(\"node-click\", {\n detail: { id: node.id, data: node.data },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n #onKeydown(node: TreeNode, e: KeyboardEvent): void {\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n if (e.target !== e.currentTarget) return;\n e.preventDefault();\n this.#activate(node);\n }\n\n #onRowClick(node: TreeNode, e: MouseEvent): void {\n if (this.#isNestedInteractive(e.composedPath(), e.currentTarget)) return;\n this.#activate(node);\n }\n\n #isNestedInteractive(path: EventTarget[], row: EventTarget | null): boolean {\n const selector =\n \"a, button, input, select, textarea, summary, [contenteditable], [role='button'], [role='link'], [tabindex]\";\n for (const target of path) {\n if (target === row) return false;\n if (target instanceof HTMLElement && target.matches(selector)) return true;\n }\n return false;\n }\n\n #renderNode(\n node: TreeNode,\n depth: number,\n isLast: boolean,\n ancestorHasNext: boolean[],\n ): TemplateResult {\n const isFolder = !!node.children;\n const isOpen = isFolder && this.expanded.has(node.id);\n const guides = this.lines\n ? html`<span class=\"guides\" aria-hidden=\"true\">\n ${ancestorHasNext.map(\n (hasNext) => html`<span class=\"guide ${hasNext ? \"v\" : \"\"}\"></span>`,\n )}\n <span class=\"guide connector ${isLast ? \"last\" : \"\"}\"></span>\n </span>`\n : nothing;\n return html`\n <div\n class=\"row\"\n role=${isFolder ? \"button\" : \"link\"}\n aria-expanded=${isFolder ? String(isOpen) : nothing}\n tabindex=\"0\"\n style=${this.lines ? nothing : `padding-left: ${depth * 1.25}rem`}\n @click=${(e: MouseEvent) => this.#onRowClick(node, e)}\n @keydown=${(e: KeyboardEvent) => this.#onKeydown(node, e)}\n >\n ${guides}\n <span class=\"toggle\" aria-hidden=\"true\">\n ${isFolder ? (isOpen ? iconChevronDown(14) : iconChevronRight(14)) : nothing}\n </span>\n <span class=\"content\">${this.renderNode(node)}</span>\n </div>\n ${isFolder && isOpen\n ? repeat(\n node.children!,\n (child) => child.id,\n (child, i) =>\n this.#renderNode(child, depth + 1, i === node.children!.length - 1, [\n ...ancestorHasNext,\n !isLast,\n ]),\n )\n : nothing}\n `;\n }\n\n override render() {\n return repeat(\n this.nodes,\n (node) => node.id,\n (node, i) => this.#renderNode(node, 0, i === this.nodes.length - 1, []),\n );\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"tree-view\": TreeView;\n }\n}\n"]}
@@ -0,0 +1,45 @@
1
+ # `<loading-dots>`
2
+
3
+ Three dots that bounce one after another as a lightweight, indeterminate
4
+ "working" / "typing" indicator. Purely presentational and property-driven —
5
+ show it while a short operation is pending and remove it when done.
6
+
7
+ Exposes an accessible `role="status"` with `label` as its name, so assistive
8
+ technology announces the loading state; the dots themselves are decorative.
9
+ Under `prefers-reduced-motion` the bounce is removed and the dots rest.
10
+
11
+ ## Install
12
+
13
+ ```js
14
+ import "@f-ewald/components/loading-dots.js";
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```html
20
+ <loading-dots></loading-dots>
21
+ <loading-dots size="sm"></loading-dots>
22
+ <loading-dots size="lg" label="Sending message"></loading-dots>
23
+ ```
24
+
25
+ ## Attributes / properties
26
+
27
+ | Property | Attribute | Type | Default | Description |
28
+ | --- | --- | --- | --- | --- |
29
+ | `size` | `size` | `"sm" | "md" | "lg"` | `"md"` | Dot-size step — `sm`, `md` (default), or `lg`. |
30
+ | `label` | `label` | `string` | `"Loading"` | Accessible name announced by the `role="status"` live region. |
31
+
32
+ ## Events
33
+
34
+ _None._
35
+
36
+ ## Slots
37
+
38
+ _None._
39
+
40
+ ## CSS custom properties
41
+
42
+ | Custom property |
43
+ | --- |
44
+ | `--ui-line-height-glyph` |
45
+ | `--ui-primary` |
@@ -0,0 +1,46 @@
1
+ # `<loading-spinner>`
2
+
3
+ Indeterminate circular loading spinner: a rotating arc over a faint track,
4
+ in the style of a browser page-load indicator. Purely presentational and
5
+ property-driven — show it while work is in flight and remove it when done.
6
+
7
+ Exposes an accessible `role="status"` with `label` as its name, so assistive
8
+ technology announces the loading state; the arc itself is decorative. Under
9
+ `prefers-reduced-motion` it stops rotating and stays a static ring.
10
+
11
+ ## Install
12
+
13
+ ```js
14
+ import "@f-ewald/components/loading-spinner.js";
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```html
20
+ <loading-spinner></loading-spinner>
21
+ <loading-spinner size="sm"></loading-spinner>
22
+ <loading-spinner size="lg" label="Loading results"></loading-spinner>
23
+ ```
24
+
25
+ ## Attributes / properties
26
+
27
+ | Property | Attribute | Type | Default | Description |
28
+ | --- | --- | --- | --- | --- |
29
+ | `size` | `size` | `"sm" | "md" | "lg"` | `"md"` | Diameter step — `sm` ≈ 1rem, `md` ≈ 1.5rem (default), `lg` ≈ 2rem. |
30
+ | `label` | `label` | `string` | `"Loading"` | Accessible name announced by the `role="status"` live region. |
31
+
32
+ ## Events
33
+
34
+ _None._
35
+
36
+ ## Slots
37
+
38
+ _None._
39
+
40
+ ## CSS custom properties
41
+
42
+ | Custom property |
43
+ | --- |
44
+ | `--ui-border` |
45
+ | `--ui-line-height-glyph` |
46
+ | `--ui-primary` |
@@ -3,6 +3,10 @@
3
3
  Responsive, accessible image carousel composed from declarative
4
4
  `gallery-item` children.
5
5
 
6
+ The image viewport keeps a fixed `aspect-ratio`, and the caption row is
7
+ reserved for every slide whenever any slide has a caption, so the carousel's
8
+ total height stays constant as it cycles — it never shifts the page below it.
9
+
6
10
  ## Install
7
11
 
8
12
  ```js
@@ -67,6 +71,7 @@ import "@f-ewald/components/photo-gallery.js";
67
71
  | `--ui-font` |
68
72
  | `--ui-font-size` |
69
73
  | `--ui-font-size-sm` |
74
+ | `--ui-line-height-normal` |
70
75
  | `--ui-line-height-tight` |
71
76
  | `--ui-on-accent` |
72
77
  | `--ui-overlay` |
@@ -1,13 +1,18 @@
1
1
  # `<toast-notification>`
2
2
 
3
3
  Fixed-position stack of dismissible notifications, anchored top-right
4
- (top-full-width on mobile). Not wired to any app state yet — callers add
5
- toasts imperatively via the `show()` method on a live element reference,
4
+ (top-full-width on mobile). Every toast shares one fixed width so entries
5
+ never appear narrower or wider than one another. Not wired to any app state
6
+ yet — callers add toasts imperatively via the `show()` method on a live
7
+ element reference,
6
8
  e.g. `document.querySelector('toast-notification')?.show('Offline', { variant: 'error' })`,
7
9
  or via the `notifySuccess`/`notifyError`/`notifyInfo` module-level helpers
8
- exported from this file. Each toast auto-dismisses after `duration` ms and
9
- can also be dismissed via its button. Appears/disappears instantly — no
10
- slide/fade transitions.
10
+ exported from this file. The first argument is the required bold headline; an
11
+ optional `description` renders a smaller, non-bold second line. Each variant
12
+ leads with a matching status icon (success → check, error → exclamation
13
+ circle, info → information circle, warning → exclamation triangle). Each toast
14
+ auto-dismisses after `duration` ms and can also be dismissed via its ✕
15
+ button. Appears/disappears instantly — no slide/fade transitions.
11
16
 
12
17
  ## Install
13
18
 
@@ -21,7 +26,7 @@ import "@f-ewald/components/toast-notification.js";
21
26
  <toast-notification></toast-notification>
22
27
  <script type="module">
23
28
  import { notifySuccess } from "@f-ewald/components/toast-notification.js";
24
- notifySuccess("Saved!");
29
+ notifySuccess("Saved!", "Your changes are now live.");
25
30
  </script>
26
31
  ```
27
32
 
@@ -45,6 +50,9 @@ _None._
45
50
  | `--ui-focus-ring` |
46
51
  | `--ui-font` |
47
52
  | `--ui-font-size` |
53
+ | `--ui-font-size-sm` |
54
+ | `--ui-font-weight-regular` |
55
+ | `--ui-font-weight-semibold` |
48
56
  | `--ui-hover-overlay` |
49
57
  | `--ui-info` |
50
58
  | `--ui-line-height-glyph` |
@@ -55,3 +63,4 @@ _None._
55
63
  | `--ui-shadow-lg` |
56
64
  | `--ui-success` |
57
65
  | `--ui-text` |
66
+ | `--ui-warning` |
package/docs/tree-view.md CHANGED
@@ -13,6 +13,10 @@ every folder expanded instead. Expansion state is otherwise managed
13
13
  internally and untouched by later `nodes` updates, so a user's manual
14
14
  toggles survive a data refresh.
15
15
 
16
+ Set the `lines` boolean to draw classic file-tree connector guides: a
17
+ vertical line per continuing ancestor level and a branch elbow (`└`) or
18
+ tee (`├`) linking each node to its parent. Off by default (indentation only).
19
+
16
20
  ## Install
17
21
 
18
22
  ```js
@@ -22,7 +26,7 @@ import "@f-ewald/components/tree-view.js";
22
26
  ## Usage
23
27
 
24
28
  ```html
25
- <tree-view></tree-view>
29
+ <tree-view lines></tree-view>
26
30
  <script type="module">
27
31
  const tree = document.querySelector("tree-view");
28
32
  tree.nodes = [
@@ -45,6 +49,7 @@ import "@f-ewald/components/tree-view.js";
45
49
  | `nodes` | _(JS property only)_ | `TreeNode[]` | `[]` | Tree data; opaque to this component beyond what `renderNode` does with it. |
46
50
  | `renderNode` | _(JS property only)_ | `(node: TreeNode) => unknown` | `—` | Produces a row's rendered content for `node`. Default: plain label text. |
47
51
  | `defaultExpanded` | `default-expanded` | `boolean` | `false` | Start every folder expanded instead of the default all-collapsed. |
52
+ | `lines` | `lines` | `boolean` | `false` | Draw classic file-tree connector guides (vertical ancestor lines plus a branch elbow/tee per row) instead of indentation alone. Off by default. |
48
53
 
49
54
  ## Events
50
55
 
@@ -60,6 +65,7 @@ _None._
60
65
 
61
66
  | Custom property |
62
67
  | --- |
68
+ | `--ui-border` |
63
69
  | `--ui-focus-ring` |
64
70
  | `--ui-font` |
65
71
  | `--ui-font-size-sm` |
package/llms.txt CHANGED
@@ -992,6 +992,52 @@ Example:
992
992
  <load-more></load-more>
993
993
  ```
994
994
 
995
+ ## <loading-dots>
996
+
997
+ Three dots that bounce one after another as a lightweight, indeterminate
998
+ "working" / "typing" indicator. Purely presentational and property-driven —
999
+ show it while a short operation is pending and remove it when done.
1000
+
1001
+ Exposes an accessible `role="status"` with `label` as its name, so assistive
1002
+ technology announces the loading state; the dots themselves are decorative.
1003
+ Under `prefers-reduced-motion` the bounce is removed and the dots rest.
1004
+
1005
+ Import: `import "@f-ewald/components/loading-dots.js";`
1006
+
1007
+ Properties: `size` (attribute `size`) : "sm" | "md" | "lg", default "md"; `label` (attribute `label`) : string, default "Loading"
1008
+ Events: none
1009
+ CSS custom properties: `--ui-line-height-glyph`, `--ui-primary`
1010
+
1011
+ Example:
1012
+ ```html
1013
+ <loading-dots></loading-dots>
1014
+ <loading-dots size="sm"></loading-dots>
1015
+ <loading-dots size="lg" label="Sending message"></loading-dots>
1016
+ ```
1017
+
1018
+ ## <loading-spinner>
1019
+
1020
+ Indeterminate circular loading spinner: a rotating arc over a faint track,
1021
+ in the style of a browser page-load indicator. Purely presentational and
1022
+ property-driven — show it while work is in flight and remove it when done.
1023
+
1024
+ Exposes an accessible `role="status"` with `label` as its name, so assistive
1025
+ technology announces the loading state; the arc itself is decorative. Under
1026
+ `prefers-reduced-motion` it stops rotating and stays a static ring.
1027
+
1028
+ Import: `import "@f-ewald/components/loading-spinner.js";`
1029
+
1030
+ Properties: `size` (attribute `size`) : "sm" | "md" | "lg", default "md"; `label` (attribute `label`) : string, default "Loading"
1031
+ Events: none
1032
+ CSS custom properties: `--ui-border`, `--ui-line-height-glyph`, `--ui-primary`
1033
+
1034
+ Example:
1035
+ ```html
1036
+ <loading-spinner></loading-spinner>
1037
+ <loading-spinner size="sm"></loading-spinner>
1038
+ <loading-spinner size="lg" label="Loading results"></loading-spinner>
1039
+ ```
1040
+
995
1041
  ## <map-circle>
996
1042
 
997
1043
  A plain circular map marker: a radial-gradient fill with a soft highlight
@@ -1227,11 +1273,15 @@ Example:
1227
1273
  Responsive, accessible image carousel composed from declarative
1228
1274
  `gallery-item` children.
1229
1275
 
1276
+ The image viewport keeps a fixed `aspect-ratio`, and the caption row is
1277
+ reserved for every slide whenever any slide has a caption, so the carousel's
1278
+ total height stays constant as it cycles — it never shifts the page below it.
1279
+
1230
1280
  Import: `import "@f-ewald/components/photo-gallery.js";`
1231
1281
 
1232
1282
  Properties: `currentIndex` (attribute `current-index`) : number, default 0; `delay` (attribute `delay`) : number, default 0; `showControls` (attribute `show-controls`) : boolean, default true; `showCounter` (attribute `show-counter`) : boolean, default false; `showIndicators` (attribute `show-indicators`) : boolean, default false; `showAutoplayControl` (attribute `show-autoplay-control`) : boolean, default true; `paused` (attribute `paused`) : boolean, default false; `aspectRatio` (attribute `aspect-ratio`) : string, default "16 / 9"; `objectFit` (attribute `object-fit`) : PhotoGalleryObjectFit, default "cover"
1233
1283
  Events: `slide-change`
1234
- CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-line-height-tight`, `--ui-on-accent`, `--ui-overlay`, `--ui-primary`, `--ui-radius`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
1284
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-line-height-normal`, `--ui-line-height-tight`, `--ui-on-accent`, `--ui-overlay`, `--ui-primary`, `--ui-radius`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
1235
1285
 
1236
1286
  Example:
1237
1287
  ```html
@@ -1666,26 +1716,31 @@ Example:
1666
1716
  ## <toast-notification>
1667
1717
 
1668
1718
  Fixed-position stack of dismissible notifications, anchored top-right
1669
- (top-full-width on mobile). Not wired to any app state yet — callers add
1670
- toasts imperatively via the `show()` method on a live element reference,
1719
+ (top-full-width on mobile). Every toast shares one fixed width so entries
1720
+ never appear narrower or wider than one another. Not wired to any app state
1721
+ yet — callers add toasts imperatively via the `show()` method on a live
1722
+ element reference,
1671
1723
  e.g. `document.querySelector('toast-notification')?.show('Offline', { variant: 'error' })`,
1672
1724
  or via the `notifySuccess`/`notifyError`/`notifyInfo` module-level helpers
1673
- exported from this file. Each toast auto-dismisses after `duration` ms and
1674
- can also be dismissed via its button. Appears/disappears instantly — no
1675
- slide/fade transitions.
1725
+ exported from this file. The first argument is the required bold headline; an
1726
+ optional `description` renders a smaller, non-bold second line. Each variant
1727
+ leads with a matching status icon (success → check, error → exclamation
1728
+ circle, info → information circle, warning → exclamation triangle). Each toast
1729
+ auto-dismisses after `duration` ms and can also be dismissed via its ✕
1730
+ button. Appears/disappears instantly — no slide/fade transitions.
1676
1731
 
1677
1732
  Import: `import "@f-ewald/components/toast-notification.js";`
1678
1733
 
1679
1734
  Properties: none
1680
1735
  Events: none
1681
- CSS custom properties: `--ui-danger`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-hover-overlay`, `--ui-info`, `--ui-line-height-glyph`, `--ui-line-height-normal`, `--ui-on-accent`, `--ui-radius`, `--ui-radius-sm`, `--ui-shadow-lg`, `--ui-success`, `--ui-text`
1736
+ CSS custom properties: `--ui-danger`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-weight-regular`, `--ui-font-weight-semibold`, `--ui-hover-overlay`, `--ui-info`, `--ui-line-height-glyph`, `--ui-line-height-normal`, `--ui-on-accent`, `--ui-radius`, `--ui-radius-sm`, `--ui-shadow-lg`, `--ui-success`, `--ui-text`, `--ui-warning`
1682
1737
 
1683
1738
  Example:
1684
1739
  ```html
1685
1740
  <toast-notification></toast-notification>
1686
1741
  <script type="module">
1687
1742
  import { notifySuccess } from "@f-ewald/components/toast-notification.js";
1688
- notifySuccess("Saved!");
1743
+ notifySuccess("Saved!", "Your changes are now live.");
1689
1744
  </script>
1690
1745
  ```
1691
1746
 
@@ -1704,15 +1759,19 @@ every folder expanded instead. Expansion state is otherwise managed
1704
1759
  internally and untouched by later `nodes` updates, so a user's manual
1705
1760
  toggles survive a data refresh.
1706
1761
 
1762
+ Set the `lines` boolean to draw classic file-tree connector guides: a
1763
+ vertical line per continuing ancestor level and a branch elbow (`└`) or
1764
+ tee (`├`) linking each node to its parent. Off by default (indentation only).
1765
+
1707
1766
  Import: `import "@f-ewald/components/tree-view.js";`
1708
1767
 
1709
- Properties: `nodes` (JS property only) : TreeNode[], default []; `renderNode` (JS property only) : (node: TreeNode) => unknown, default —; `defaultExpanded` (attribute `default-expanded`) : boolean, default false
1768
+ Properties: `nodes` (JS property only) : TreeNode[], default []; `renderNode` (JS property only) : (node: TreeNode) => unknown, default —; `defaultExpanded` (attribute `default-expanded`) : boolean, default false; `lines` (attribute `lines`) : boolean, default false
1710
1769
  Events: `node-click`
1711
- CSS custom properties: `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
1770
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
1712
1771
 
1713
1772
  Example:
1714
1773
  ```html
1715
- <tree-view></tree-view>
1774
+ <tree-view lines></tree-view>
1716
1775
  <script type="module">
1717
1776
  const tree = document.querySelector("tree-view");
1718
1777
  tree.nodes = [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@f-ewald/components",
3
3
  "private": false,
4
- "version": "1.14.1",
4
+ "version": "1.16.0",
5
5
  "description": "A collection of universally usable web components for various tasks.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",