@f-ewald/components 1.21.1 → 1.22.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/custom-elements.json +21 -1
- package/dist/timeline-entry.d.ts +12 -3
- package/dist/timeline-entry.d.ts.map +1 -1
- package/dist/timeline-entry.js +62 -4
- package/dist/timeline-entry.js.map +1 -1
- package/docs/timeline-entry.md +7 -3
- package/llms.txt +7 -4
- package/package.json +1 -1
package/custom-elements.json
CHANGED
|
@@ -14343,7 +14343,7 @@
|
|
|
14343
14343
|
"declarations": [
|
|
14344
14344
|
{
|
|
14345
14345
|
"kind": "class",
|
|
14346
|
-
"description": "One event on a `timeline-container`: a dot on the vertical line, an optional\nheadline, a relative timestamp (\"3 hours ago\"), and freely nested content.\nThe connecting line is drawn here — its segment above the dot is hidden on\nthe first entry and the segment below is hidden on the last, so the line caps\nexactly at the first and last dots. Only meaningful inside a\n`timeline-container`; demonstrated through it.\n\n`datetime` is the entry's one timestamp. A nested element that has its own\ntimestamp prop (e.g. `chat-message`'s `timestamp`) should leave it unset —\nsetting both renders the same time twice.\n\nThe dot's `color` types the entry using the shared status-pill palette —\n`primary` by default, plus `neutral`, `info`, `success`, `warning`, and\n`danger`.\n\nSet `compact` for dense, one-line system-status entries
|
|
14346
|
+
"description": "One event on a `timeline-container`: a dot on the vertical line, an optional\nheadline, a relative timestamp (\"3 hours ago\"), and freely nested content.\nThe connecting line is drawn here — its segment above the dot is hidden on\nthe first entry and the segment below is hidden on the last, so the line caps\nexactly at the first and last dots. Only meaningful inside a\n`timeline-container`; demonstrated through it.\n\n`datetime` is the entry's one timestamp. A nested element that has its own\ntimestamp prop (e.g. `chat-message`'s `timestamp`) should leave it unset —\nsetting both renders the same time twice.\n\nThe dot's `color` types the entry using the shared status-pill palette —\n`primary` by default, plus `neutral`, `info`, `success`, `warning`, and\n`danger`.\n\nSet `compact` for dense, one-line system-status entries: it tightens the\nvertical spacing and renders the content smaller and muted.\n\nSet `running` to replace the dot with an animated gray ring spinner,\nindicating the entry represents in-progress work; `color` has no visible\neffect while `running` is set.",
|
|
14347
14347
|
"name": "TimelineEntry",
|
|
14348
14348
|
"slots": [
|
|
14349
14349
|
{
|
|
@@ -14387,6 +14387,17 @@
|
|
|
14387
14387
|
"attribute": "compact",
|
|
14388
14388
|
"reflects": true
|
|
14389
14389
|
},
|
|
14390
|
+
{
|
|
14391
|
+
"kind": "field",
|
|
14392
|
+
"name": "running",
|
|
14393
|
+
"type": {
|
|
14394
|
+
"text": "boolean"
|
|
14395
|
+
},
|
|
14396
|
+
"default": "false",
|
|
14397
|
+
"description": "Shows an animated ring spinner in place of the dot, indicating the entry\nrepresents in-progress work. Overrides `color` while set — the spinner\nalways uses the muted/gray palette.",
|
|
14398
|
+
"attribute": "running",
|
|
14399
|
+
"reflects": true
|
|
14400
|
+
},
|
|
14390
14401
|
{
|
|
14391
14402
|
"kind": "field",
|
|
14392
14403
|
"name": "_hasHeadline",
|
|
@@ -14444,6 +14455,15 @@
|
|
|
14444
14455
|
"default": "false",
|
|
14445
14456
|
"description": "Dense, one-line presentation for system-status entries: tighter vertical\nspacing and smaller, muted content.",
|
|
14446
14457
|
"fieldName": "compact"
|
|
14458
|
+
},
|
|
14459
|
+
{
|
|
14460
|
+
"name": "running",
|
|
14461
|
+
"type": {
|
|
14462
|
+
"text": "boolean"
|
|
14463
|
+
},
|
|
14464
|
+
"default": "false",
|
|
14465
|
+
"description": "Shows an animated ring spinner in place of the dot, indicating the entry\nrepresents in-progress work. Overrides `color` while set — the spinner\nalways uses the muted/gray palette.",
|
|
14466
|
+
"fieldName": "running"
|
|
14447
14467
|
}
|
|
14448
14468
|
],
|
|
14449
14469
|
"superclass": {
|
package/dist/timeline-entry.d.ts
CHANGED
|
@@ -17,9 +17,12 @@ import type { StatusPillColor } from "./status-pill.js";
|
|
|
17
17
|
* `primary` by default, plus `neutral`, `info`, `success`, `warning`, and
|
|
18
18
|
* `danger`.
|
|
19
19
|
*
|
|
20
|
-
* Set `compact` for dense, one-line system-status entries
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Set `compact` for dense, one-line system-status entries: it tightens the
|
|
21
|
+
* vertical spacing and renders the content smaller and muted.
|
|
22
|
+
*
|
|
23
|
+
* Set `running` to replace the dot with an animated gray ring spinner,
|
|
24
|
+
* indicating the entry represents in-progress work; `color` has no visible
|
|
25
|
+
* effect while `running` is set.
|
|
23
26
|
*
|
|
24
27
|
* @element timeline-entry
|
|
25
28
|
* @slot headline - Optional headline/title for the event.
|
|
@@ -38,6 +41,12 @@ export declare class TimelineEntry extends LitElement {
|
|
|
38
41
|
* spacing and smaller, muted content.
|
|
39
42
|
*/
|
|
40
43
|
compact: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Shows an animated ring spinner in place of the dot, indicating the entry
|
|
46
|
+
* represents in-progress work. Overrides `color` while set — the spinner
|
|
47
|
+
* always uses the muted/gray palette.
|
|
48
|
+
*/
|
|
49
|
+
running: boolean;
|
|
41
50
|
/** Whether the headline slot currently has assigned content. */
|
|
42
51
|
private _hasHeadline;
|
|
43
52
|
static styles: import("lit").CSSResult[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-entry.d.ts","sourceRoot":"","sources":["../src/timeline-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAErD,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"timeline-entry.d.ts","sourceRoot":"","sources":["../src/timeline-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAErD,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,uEAAuE;IAC3D,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3C;;;OAGG;IACS,KAAK,EAAE,eAAe,CAAa;IAE/C;;;OAGG;IACyC,OAAO,UAAS;IAE5D;;;;OAIG;IACyC,OAAO,UAAS;IAE5D,gEAAgE;IACvD,OAAO,CAAC,YAAY,CAAS;IAEtC,OAAgB,MAAM,4BAsKpB;IAEO,iBAAiB,IAAI,IAAI,CAGjC;IAED,6EAA6E;IAC7E,OAAO,CAAC,qBAAqB;IAIpB,MAAM,yCA4Bd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,aAAa,CAAC;KACjC;CACF"}
|
package/dist/timeline-entry.js
CHANGED
|
@@ -24,9 +24,12 @@ import { tokens } from "./tokens.js";
|
|
|
24
24
|
* `primary` by default, plus `neutral`, `info`, `success`, `warning`, and
|
|
25
25
|
* `danger`.
|
|
26
26
|
*
|
|
27
|
-
* Set `compact` for dense, one-line system-status entries
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* Set `compact` for dense, one-line system-status entries: it tightens the
|
|
28
|
+
* vertical spacing and renders the content smaller and muted.
|
|
29
|
+
*
|
|
30
|
+
* Set `running` to replace the dot with an animated gray ring spinner,
|
|
31
|
+
* indicating the entry represents in-progress work; `color` has no visible
|
|
32
|
+
* effect while `running` is set.
|
|
30
33
|
*
|
|
31
34
|
* @element timeline-entry
|
|
32
35
|
* @slot headline - Optional headline/title for the event.
|
|
@@ -47,6 +50,12 @@ let TimelineEntry = class TimelineEntry extends LitElement {
|
|
|
47
50
|
* spacing and smaller, muted content.
|
|
48
51
|
*/
|
|
49
52
|
this.compact = false;
|
|
53
|
+
/**
|
|
54
|
+
* Shows an animated ring spinner in place of the dot, indicating the entry
|
|
55
|
+
* represents in-progress work. Overrides `color` while set — the spinner
|
|
56
|
+
* always uses the muted/gray palette.
|
|
57
|
+
*/
|
|
58
|
+
this.running = false;
|
|
50
59
|
/** Whether the headline slot currently has assigned content. */
|
|
51
60
|
this._hasHeadline = false;
|
|
52
61
|
}
|
|
@@ -125,6 +134,45 @@ let TimelineEntry = class TimelineEntry extends LitElement {
|
|
|
125
134
|
.dot.danger {
|
|
126
135
|
--_dot: var(--ui-danger, #dc2626);
|
|
127
136
|
}
|
|
137
|
+
.spinner {
|
|
138
|
+
position: absolute;
|
|
139
|
+
top: 0.125rem;
|
|
140
|
+
left: 50%;
|
|
141
|
+
width: 0.75rem;
|
|
142
|
+
height: 0.75rem;
|
|
143
|
+
transform: translateX(-50%);
|
|
144
|
+
animation: spin 0.8s linear infinite;
|
|
145
|
+
}
|
|
146
|
+
.spinner-track {
|
|
147
|
+
fill: none;
|
|
148
|
+
stroke: color-mix(in srgb, var(--ui-text-muted, #64748b) 25%, transparent);
|
|
149
|
+
stroke-width: 3;
|
|
150
|
+
}
|
|
151
|
+
.spinner-arc {
|
|
152
|
+
fill: none;
|
|
153
|
+
stroke: var(--ui-text-muted, #64748b);
|
|
154
|
+
stroke-width: 3;
|
|
155
|
+
stroke-linecap: round;
|
|
156
|
+
stroke-dasharray: 42 100;
|
|
157
|
+
}
|
|
158
|
+
@keyframes spin {
|
|
159
|
+
to {
|
|
160
|
+
transform: rotate(360deg);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
@media (prefers-reduced-motion: reduce) {
|
|
164
|
+
.spinner {
|
|
165
|
+
animation: none;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
@media (forced-colors: active) {
|
|
169
|
+
.spinner-track {
|
|
170
|
+
stroke: GrayText;
|
|
171
|
+
}
|
|
172
|
+
.spinner-arc {
|
|
173
|
+
stroke: CanvasText;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
128
176
|
:host(:first-child) .line-top {
|
|
129
177
|
display: none;
|
|
130
178
|
}
|
|
@@ -193,7 +241,14 @@ let TimelineEntry = class TimelineEntry extends LitElement {
|
|
|
193
241
|
<div class="rail" aria-hidden="true">
|
|
194
242
|
<span class="line line-top"></span>
|
|
195
243
|
<span class="line line-bottom"></span>
|
|
196
|
-
|
|
244
|
+
${this.running
|
|
245
|
+
? html `
|
|
246
|
+
<svg class="spinner" viewBox="0 0 24 24">
|
|
247
|
+
<circle class="spinner-track" cx="12" cy="12" r="9"></circle>
|
|
248
|
+
<circle class="spinner-arc" cx="12" cy="12" r="9"></circle>
|
|
249
|
+
</svg>
|
|
250
|
+
`
|
|
251
|
+
: html `<span class="dot ${this.color}"></span>`}
|
|
197
252
|
</div>
|
|
198
253
|
<div class="body">
|
|
199
254
|
<div class="head">
|
|
@@ -219,6 +274,9 @@ __decorate([
|
|
|
219
274
|
__decorate([
|
|
220
275
|
property({ type: Boolean, reflect: true })
|
|
221
276
|
], TimelineEntry.prototype, "compact", void 0);
|
|
277
|
+
__decorate([
|
|
278
|
+
property({ type: Boolean, reflect: true })
|
|
279
|
+
], TimelineEntry.prototype, "running", void 0);
|
|
222
280
|
__decorate([
|
|
223
281
|
state()
|
|
224
282
|
], TimelineEntry.prototype, "_hasHeadline", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-entry.js","sourceRoot":"","sources":["../src/timeline-entry.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAAtC;;QACL,uEAAuE;QAC3D,aAAQ,GAAkB,IAAI,CAAC;QAE3C;;;WAGG;QACS,UAAK,GAAoB,SAAS,CAAC;QAE/C;;;WAGG;QACyC,YAAO,GAAG,KAAK,CAAC;QAE5D,gEAAgE;QAC/C,iBAAY,GAAG,KAAK,CAAC;IAmKxC,CAAC;aAjKiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA4HF;KACF,AA/HqB,CA+HpB;IAEO,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxE,CAAC;IAED,6EAA6E;IACrE,qBAAqB,CAAC,KAAY;QACxC,IAAI,CAAC,YAAY,GAAI,KAAK,CAAC,MAA0B,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACpG,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;;;;6BAKc,IAAI,CAAC,KAAK;;;;oCAIH,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;kDAClB,IAAI,CAAC,qBAAqB;;cAE9D,IAAI,CAAC,QAAQ;YACb,CAAC,CAAC,IAAI,CAAA,wCAAwC,IAAI,CAAC,QAAQ,mBAAmB;YAC9E,CAAC,CAAC,OAAO;;;;;KAKlB,CAAC;IACJ,CAAC;CACF,CAAA;AAlLa;IAAX,QAAQ,EAAE;+CAAgC;AAM/B;IAAX,QAAQ,EAAE;4CAAoC;AAMH;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAiB;AAG3C;IAAhB,KAAK,EAAE;mDAA8B;AAjB3B,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAoLzB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport \"./relative-time.js\";\nimport { tokens } from \"./tokens.js\";\nimport type { StatusPillColor } from \"./status-pill.js\";\n\n/**\n * One event on a `timeline-container`: a dot on the vertical line, an optional\n * headline, a relative timestamp (\"3 hours ago\"), and freely nested content.\n * The connecting line is drawn here — its segment above the dot is hidden on\n * the first entry and the segment below is hidden on the last, so the line caps\n * exactly at the first and last dots. Only meaningful inside a\n * `timeline-container`; demonstrated through it.\n *\n * `datetime` is the entry's one timestamp. A nested element that has its own\n * timestamp prop (e.g. `chat-message`'s `timestamp`) should leave it unset —\n * setting both renders the same time twice.\n *\n * The dot's `color` types the entry using the shared status-pill palette —\n * `primary` by default, plus `neutral`, `info`, `success`, `warning`, and\n * `danger`.\n *\n * Set `compact` for dense, one-line system-status entries (running spinners,\n * state changes): it tightens the vertical spacing and renders the content\n * smaller and muted.\n *\n * @element timeline-entry\n * @slot headline - Optional headline/title for the event.\n * @slot - The event content; nest any elements here.\n */\n@customElement(\"timeline-entry\")\nexport class TimelineEntry extends LitElement {\n /** ISO 8601 or SQLite datetime string, rendered as a relative time. */\n @property() datetime: string | null = null;\n\n /**\n * Visual type of the entry's dot, from the shared status-pill palette:\n * `primary` (default), `neutral`, `info`, `success`, `warning`, or `danger`.\n */\n @property() color: StatusPillColor = \"primary\";\n\n /**\n * Dense, one-line presentation for system-status entries: tighter vertical\n * spacing and smaller, muted content.\n */\n @property({ type: Boolean, reflect: true }) compact = false;\n\n /** Whether the headline slot currently has assigned content. */\n @state() private _hasHeadline = false;\n\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 }\n .entry {\n display: flex;\n gap: 0.75rem;\n }\n .rail {\n position: relative;\n flex: 0 0 auto;\n width: 0.75rem;\n }\n .line {\n position: absolute;\n left: 50%;\n width: 2px;\n transform: translateX(-50%);\n background: var(--ui-border, #e2e8f0);\n }\n .line-top {\n top: 0;\n height: 0.5rem;\n }\n .line-bottom {\n top: 0.5rem;\n bottom: 0;\n }\n .dot {\n position: absolute;\n top: 0.125rem;\n left: 50%;\n width: 0.75rem;\n height: 0.75rem;\n transform: translateX(-50%);\n border-radius: 9999px;\n /* Same lighter-on-top token gradient as map-circle/user-avatar; the\n base color is swapped per the color property via the private\n --_dot var. */\n background: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--_dot, var(--ui-primary, #4f46e5)) 70%, #ffffff) 0%,\n color-mix(in srgb, var(--_dot, var(--ui-primary, #4f46e5)) 70%, #000000) 100%\n );\n }\n .dot.neutral {\n --_dot: var(--ui-text-muted, #64748b);\n }\n .dot.info {\n --_dot: var(--ui-info, #0ea5e9);\n }\n .dot.primary {\n --_dot: var(--ui-primary, #4f46e5);\n }\n .dot.success {\n --_dot: var(--ui-success, #16a34a);\n }\n .dot.warning {\n --_dot: var(--ui-warning, #d97706);\n }\n .dot.danger {\n --_dot: var(--ui-danger, #dc2626);\n }\n :host(:first-child) .line-top {\n display: none;\n }\n :host(:last-child) .line-bottom {\n display: none;\n }\n .body {\n flex: 1 1 auto;\n min-width: 0;\n padding-bottom: 1.5rem;\n }\n :host(:last-child) .body {\n padding-bottom: 0;\n }\n .head {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n flex-wrap: wrap;\n }\n .headline {\n font-weight: var(--ui-font-weight-semibold, 600);\n font-size: var(--ui-font-size, 0.875rem);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text, #0f172a);\n }\n .headline.empty {\n display: none;\n }\n .time {\n font-size: var(--ui-font-size-sm, 0.75rem);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text-muted, #64748b);\n }\n .content {\n margin-top: 0.25rem;\n font-size: var(--ui-font-size, 0.875rem);\n line-height: var(--ui-line-height-normal, 1.5);\n color: var(--ui-text, #0f172a);\n }\n :host([compact]) .body {\n padding-bottom: 0.5rem;\n }\n :host([compact]:last-child) .body {\n padding-bottom: 0;\n }\n :host([compact]) .content {\n margin-top: 0.125rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n color: var(--ui-text-muted, #64748b);\n }\n `,\n ];\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (!this.hasAttribute(\"role\")) this.setAttribute(\"role\", \"listitem\");\n }\n\n /** Collapses the headline when nothing is slotted so the time sits alone. */\n private _onHeadlineSlotChange(event: Event): void {\n this._hasHeadline = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n }\n\n override render() {\n return html`\n <div class=\"entry\">\n <div class=\"rail\" aria-hidden=\"true\">\n <span class=\"line line-top\"></span>\n <span class=\"line line-bottom\"></span>\n <span class=\"dot ${this.color}\"></span>\n </div>\n <div class=\"body\">\n <div class=\"head\">\n <span class=\"headline ${this._hasHeadline ? \"\" : \"empty\"}\">\n <slot name=\"headline\" @slotchange=${this._onHeadlineSlotChange}></slot>\n </span>\n ${this.datetime\n ? html`<relative-time class=\"time\" datetime=${this.datetime}></relative-time>`\n : nothing}\n </div>\n <div class=\"content\"><slot></slot></div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"timeline-entry\": TimelineEntry;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"timeline-entry.js","sourceRoot":"","sources":["../src/timeline-entry.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAAtC;;QACL,uEAAuE;QAC3D,aAAQ,GAAkB,IAAI,CAAC;QAE3C;;;WAGG;QACS,UAAK,GAAoB,SAAS,CAAC;QAE/C;;;WAGG;QACyC,YAAO,GAAG,KAAK,CAAC;QAE5D;;;;WAIG;QACyC,YAAO,GAAG,KAAK,CAAC;QAE5D,gEAAgE;QAC/C,iBAAY,GAAG,KAAK,CAAC;IAiNxC,CAAC;aA/MiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmKF;KACF,AAtKqB,CAsKpB;IAEO,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxE,CAAC;IAED,6EAA6E;IACrE,qBAAqB,CAAC,KAAY;QACxC,IAAI,CAAC,YAAY,GAAI,KAAK,CAAC,MAA0B,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACpG,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;;;;YAKH,IAAI,CAAC,OAAO;YACZ,CAAC,CAAC,IAAI,CAAA;;;;;eAKH;YACH,CAAC,CAAC,IAAI,CAAA,oBAAoB,IAAI,CAAC,KAAK,WAAW;;;;oCAIvB,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;kDAClB,IAAI,CAAC,qBAAqB;;cAE9D,IAAI,CAAC,QAAQ;YACb,CAAC,CAAC,IAAI,CAAA,wCAAwC,IAAI,CAAC,QAAQ,mBAAmB;YAC9E,CAAC,CAAC,OAAO;;;;;KAKlB,CAAC;IACJ,CAAC;CACF,CAAA;AAvOa;IAAX,QAAQ,EAAE;+CAAgC;AAM/B;IAAX,QAAQ,EAAE;4CAAoC;AAMH;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAiB;AAOhB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAiB;AAG3C;IAAhB,KAAK,EAAE;mDAA8B;AAxB3B,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CAyOzB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport \"./relative-time.js\";\nimport { tokens } from \"./tokens.js\";\nimport type { StatusPillColor } from \"./status-pill.js\";\n\n/**\n * One event on a `timeline-container`: a dot on the vertical line, an optional\n * headline, a relative timestamp (\"3 hours ago\"), and freely nested content.\n * The connecting line is drawn here — its segment above the dot is hidden on\n * the first entry and the segment below is hidden on the last, so the line caps\n * exactly at the first and last dots. Only meaningful inside a\n * `timeline-container`; demonstrated through it.\n *\n * `datetime` is the entry's one timestamp. A nested element that has its own\n * timestamp prop (e.g. `chat-message`'s `timestamp`) should leave it unset —\n * setting both renders the same time twice.\n *\n * The dot's `color` types the entry using the shared status-pill palette —\n * `primary` by default, plus `neutral`, `info`, `success`, `warning`, and\n * `danger`.\n *\n * Set `compact` for dense, one-line system-status entries: it tightens the\n * vertical spacing and renders the content smaller and muted.\n *\n * Set `running` to replace the dot with an animated gray ring spinner,\n * indicating the entry represents in-progress work; `color` has no visible\n * effect while `running` is set.\n *\n * @element timeline-entry\n * @slot headline - Optional headline/title for the event.\n * @slot - The event content; nest any elements here.\n */\n@customElement(\"timeline-entry\")\nexport class TimelineEntry extends LitElement {\n /** ISO 8601 or SQLite datetime string, rendered as a relative time. */\n @property() datetime: string | null = null;\n\n /**\n * Visual type of the entry's dot, from the shared status-pill palette:\n * `primary` (default), `neutral`, `info`, `success`, `warning`, or `danger`.\n */\n @property() color: StatusPillColor = \"primary\";\n\n /**\n * Dense, one-line presentation for system-status entries: tighter vertical\n * spacing and smaller, muted content.\n */\n @property({ type: Boolean, reflect: true }) compact = false;\n\n /**\n * Shows an animated ring spinner in place of the dot, indicating the entry\n * represents in-progress work. Overrides `color` while set — the spinner\n * always uses the muted/gray palette.\n */\n @property({ type: Boolean, reflect: true }) running = false;\n\n /** Whether the headline slot currently has assigned content. */\n @state() private _hasHeadline = false;\n\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 }\n .entry {\n display: flex;\n gap: 0.75rem;\n }\n .rail {\n position: relative;\n flex: 0 0 auto;\n width: 0.75rem;\n }\n .line {\n position: absolute;\n left: 50%;\n width: 2px;\n transform: translateX(-50%);\n background: var(--ui-border, #e2e8f0);\n }\n .line-top {\n top: 0;\n height: 0.5rem;\n }\n .line-bottom {\n top: 0.5rem;\n bottom: 0;\n }\n .dot {\n position: absolute;\n top: 0.125rem;\n left: 50%;\n width: 0.75rem;\n height: 0.75rem;\n transform: translateX(-50%);\n border-radius: 9999px;\n /* Same lighter-on-top token gradient as map-circle/user-avatar; the\n base color is swapped per the color property via the private\n --_dot var. */\n background: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--_dot, var(--ui-primary, #4f46e5)) 70%, #ffffff) 0%,\n color-mix(in srgb, var(--_dot, var(--ui-primary, #4f46e5)) 70%, #000000) 100%\n );\n }\n .dot.neutral {\n --_dot: var(--ui-text-muted, #64748b);\n }\n .dot.info {\n --_dot: var(--ui-info, #0ea5e9);\n }\n .dot.primary {\n --_dot: var(--ui-primary, #4f46e5);\n }\n .dot.success {\n --_dot: var(--ui-success, #16a34a);\n }\n .dot.warning {\n --_dot: var(--ui-warning, #d97706);\n }\n .dot.danger {\n --_dot: var(--ui-danger, #dc2626);\n }\n .spinner {\n position: absolute;\n top: 0.125rem;\n left: 50%;\n width: 0.75rem;\n height: 0.75rem;\n transform: translateX(-50%);\n animation: spin 0.8s linear infinite;\n }\n .spinner-track {\n fill: none;\n stroke: color-mix(in srgb, var(--ui-text-muted, #64748b) 25%, transparent);\n stroke-width: 3;\n }\n .spinner-arc {\n fill: none;\n stroke: var(--ui-text-muted, #64748b);\n stroke-width: 3;\n stroke-linecap: round;\n stroke-dasharray: 42 100;\n }\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .spinner {\n animation: none;\n }\n }\n @media (forced-colors: active) {\n .spinner-track {\n stroke: GrayText;\n }\n .spinner-arc {\n stroke: CanvasText;\n }\n }\n :host(:first-child) .line-top {\n display: none;\n }\n :host(:last-child) .line-bottom {\n display: none;\n }\n .body {\n flex: 1 1 auto;\n min-width: 0;\n padding-bottom: 1.5rem;\n }\n :host(:last-child) .body {\n padding-bottom: 0;\n }\n .head {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n flex-wrap: wrap;\n }\n .headline {\n font-weight: var(--ui-font-weight-semibold, 600);\n font-size: var(--ui-font-size, 0.875rem);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text, #0f172a);\n }\n .headline.empty {\n display: none;\n }\n .time {\n font-size: var(--ui-font-size-sm, 0.75rem);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text-muted, #64748b);\n }\n .content {\n margin-top: 0.25rem;\n font-size: var(--ui-font-size, 0.875rem);\n line-height: var(--ui-line-height-normal, 1.5);\n color: var(--ui-text, #0f172a);\n }\n :host([compact]) .body {\n padding-bottom: 0.5rem;\n }\n :host([compact]:last-child) .body {\n padding-bottom: 0;\n }\n :host([compact]) .content {\n margin-top: 0.125rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n color: var(--ui-text-muted, #64748b);\n }\n `,\n ];\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (!this.hasAttribute(\"role\")) this.setAttribute(\"role\", \"listitem\");\n }\n\n /** Collapses the headline when nothing is slotted so the time sits alone. */\n private _onHeadlineSlotChange(event: Event): void {\n this._hasHeadline = (event.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;\n }\n\n override render() {\n return html`\n <div class=\"entry\">\n <div class=\"rail\" aria-hidden=\"true\">\n <span class=\"line line-top\"></span>\n <span class=\"line line-bottom\"></span>\n ${this.running\n ? html`\n <svg class=\"spinner\" viewBox=\"0 0 24 24\">\n <circle class=\"spinner-track\" cx=\"12\" cy=\"12\" r=\"9\"></circle>\n <circle class=\"spinner-arc\" cx=\"12\" cy=\"12\" r=\"9\"></circle>\n </svg>\n `\n : html`<span class=\"dot ${this.color}\"></span>`}\n </div>\n <div class=\"body\">\n <div class=\"head\">\n <span class=\"headline ${this._hasHeadline ? \"\" : \"empty\"}\">\n <slot name=\"headline\" @slotchange=${this._onHeadlineSlotChange}></slot>\n </span>\n ${this.datetime\n ? html`<relative-time class=\"time\" datetime=${this.datetime}></relative-time>`\n : nothing}\n </div>\n <div class=\"content\"><slot></slot></div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"timeline-entry\": TimelineEntry;\n }\n}\n"]}
|
package/docs/timeline-entry.md
CHANGED
|
@@ -15,9 +15,12 @@ The dot's `color` types the entry using the shared status-pill palette —
|
|
|
15
15
|
`primary` by default, plus `neutral`, `info`, `success`, `warning`, and
|
|
16
16
|
`danger`.
|
|
17
17
|
|
|
18
|
-
Set `compact` for dense, one-line system-status entries
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
Set `compact` for dense, one-line system-status entries: it tightens the
|
|
19
|
+
vertical spacing and renders the content smaller and muted.
|
|
20
|
+
|
|
21
|
+
Set `running` to replace the dot with an animated gray ring spinner,
|
|
22
|
+
indicating the entry represents in-progress work; `color` has no visible
|
|
23
|
+
effect while `running` is set.
|
|
21
24
|
|
|
22
25
|
## Install
|
|
23
26
|
|
|
@@ -41,6 +44,7 @@ import "@f-ewald/components/timeline-entry.js";
|
|
|
41
44
|
| `datetime` | `datetime` | `string | null` | `null` | ISO 8601 or SQLite datetime string, rendered as a relative time. |
|
|
42
45
|
| `color` | `color` | `StatusPillColor` | `"primary"` | Visual type of the entry's dot, from the shared status-pill palette: `primary` (default), `neutral`, `info`, `success`, `warning`, or `danger`. |
|
|
43
46
|
| `compact` | `compact` | `boolean` | `false` | Dense, one-line presentation for system-status entries: tighter vertical spacing and smaller, muted content. |
|
|
47
|
+
| `running` | `running` | `boolean` | `false` | Shows an animated ring spinner in place of the dot, indicating the entry represents in-progress work. Overrides `color` while set — the spinner always uses the muted/gray palette. |
|
|
44
48
|
|
|
45
49
|
## Events
|
|
46
50
|
|
package/llms.txt
CHANGED
|
@@ -1893,13 +1893,16 @@ The dot's `color` types the entry using the shared status-pill palette —
|
|
|
1893
1893
|
`primary` by default, plus `neutral`, `info`, `success`, `warning`, and
|
|
1894
1894
|
`danger`.
|
|
1895
1895
|
|
|
1896
|
-
Set `compact` for dense, one-line system-status entries
|
|
1897
|
-
|
|
1898
|
-
|
|
1896
|
+
Set `compact` for dense, one-line system-status entries: it tightens the
|
|
1897
|
+
vertical spacing and renders the content smaller and muted.
|
|
1898
|
+
|
|
1899
|
+
Set `running` to replace the dot with an animated gray ring spinner,
|
|
1900
|
+
indicating the entry represents in-progress work; `color` has no visible
|
|
1901
|
+
effect while `running` is set.
|
|
1899
1902
|
|
|
1900
1903
|
Import: `import "@f-ewald/components/timeline-entry.js";`
|
|
1901
1904
|
|
|
1902
|
-
Properties: `datetime` (attribute `datetime`) : string | null, default null; `color` (attribute `color`) : StatusPillColor, default "primary"; `compact` (attribute `compact`) : boolean, default false
|
|
1905
|
+
Properties: `datetime` (attribute `datetime`) : string | null, default null; `color` (attribute `color`) : StatusPillColor, default "primary"; `compact` (attribute `compact`) : boolean, default false; `running` (attribute `running`) : boolean, default false
|
|
1903
1906
|
Events: none
|
|
1904
1907
|
CSS custom properties: `--ui-border`, `--ui-danger`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-weight-semibold`, `--ui-info`, `--ui-line-height-normal`, `--ui-line-height-tight`, `--ui-primary`, `--ui-success`, `--ui-text`, `--ui-text-muted`, `--ui-warning`
|
|
1905
1908
|
|