@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.
- package/README.md +2 -0
- package/custom-elements.json +295 -3
- 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 +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/loading-dots.d.ts +28 -0
- package/dist/loading-dots.d.ts.map +1 -0
- package/dist/loading-dots.js +116 -0
- package/dist/loading-dots.js.map +1 -0
- package/dist/loading-spinner.d.ts +28 -0
- package/dist/loading-spinner.d.ts.map +1 -0
- package/dist/loading-spinner.js +109 -0
- package/dist/loading-spinner.js.map +1 -0
- package/dist/photo-gallery.d.ts +4 -0
- package/dist/photo-gallery.d.ts.map +1 -1
- package/dist/photo-gallery.js +14 -1
- package/dist/photo-gallery.js.map +1 -1
- package/dist/toast-notification.d.ts +27 -9
- package/dist/toast-notification.d.ts.map +1 -1
- package/dist/toast-notification.js +68 -17
- package/dist/toast-notification.js.map +1 -1
- package/dist/tree-view.d.ts +9 -0
- package/dist/tree-view.d.ts.map +1 -1
- package/dist/tree-view.js +66 -4
- package/dist/tree-view.js.map +1 -1
- package/docs/loading-dots.md +45 -0
- package/docs/loading-spinner.md +46 -0
- package/docs/photo-gallery.md +5 -0
- package/docs/toast-notification.md +15 -6
- package/docs/tree-view.md +7 -1
- package/llms.txt +70 -11
- package/package.json +1 -1
package/dist/tree-view.js.map
CHANGED
|
@@ -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` |
|
package/docs/photo-gallery.md
CHANGED
|
@@ -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).
|
|
5
|
-
|
|
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.
|
|
9
|
-
|
|
10
|
-
|
|
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).
|
|
1670
|
-
|
|
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.
|
|
1674
|
-
|
|
1675
|
-
|
|
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 = [
|