@f-ewald/components 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +61 -0
  2. package/custom-elements.json +3808 -930
  3. package/dist/chat-message.d.ts +39 -0
  4. package/dist/chat-message.d.ts.map +1 -0
  5. package/dist/chat-message.js +155 -0
  6. package/dist/chat-message.js.map +1 -0
  7. package/dist/data-table.d.ts +39 -0
  8. package/dist/data-table.d.ts.map +1 -0
  9. package/dist/data-table.js +119 -0
  10. package/dist/data-table.js.map +1 -0
  11. package/dist/dropdown-button.d.ts +37 -0
  12. package/dist/dropdown-button.d.ts.map +1 -0
  13. package/dist/dropdown-button.js +219 -0
  14. package/dist/dropdown-button.js.map +1 -0
  15. package/dist/editable-text.d.ts +52 -0
  16. package/dist/editable-text.d.ts.map +1 -0
  17. package/dist/editable-text.js +224 -0
  18. package/dist/editable-text.js.map +1 -0
  19. package/dist/form-select.d.ts +46 -0
  20. package/dist/form-select.d.ts.map +1 -0
  21. package/dist/form-select.js +245 -0
  22. package/dist/form-select.js.map +1 -0
  23. package/dist/frame-box.d.ts +22 -0
  24. package/dist/frame-box.d.ts.map +1 -0
  25. package/dist/frame-box.js +68 -0
  26. package/dist/frame-box.js.map +1 -0
  27. package/dist/gallery-item-variant.d.ts +21 -0
  28. package/dist/gallery-item-variant.d.ts.map +1 -0
  29. package/dist/gallery-item-variant.js +44 -0
  30. package/dist/gallery-item-variant.js.map +1 -0
  31. package/dist/gallery-item.d.ts +28 -0
  32. package/dist/gallery-item.d.ts.map +1 -0
  33. package/dist/gallery-item.js +54 -0
  34. package/dist/gallery-item.js.map +1 -0
  35. package/dist/icon-button.d.ts +27 -0
  36. package/dist/icon-button.d.ts.map +1 -0
  37. package/dist/icon-button.js +83 -0
  38. package/dist/icon-button.js.map +1 -0
  39. package/dist/icons.d.ts +8 -0
  40. package/dist/icons.d.ts.map +1 -1
  41. package/dist/icons.js +8 -0
  42. package/dist/icons.js.map +1 -1
  43. package/dist/index.d.ts +16 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +16 -1
  46. package/dist/index.js.map +1 -1
  47. package/dist/live-timer.d.ts +31 -0
  48. package/dist/live-timer.d.ts.map +1 -0
  49. package/dist/live-timer.js +78 -0
  50. package/dist/live-timer.js.map +1 -0
  51. package/dist/mcp-server.d.ts +3 -0
  52. package/dist/mcp-server.d.ts.map +1 -0
  53. package/dist/mcp-server.js +82 -0
  54. package/dist/mcp-server.js.map +1 -0
  55. package/dist/photo-gallery.d.ts +117 -0
  56. package/dist/photo-gallery.d.ts.map +1 -0
  57. package/dist/photo-gallery.js +620 -0
  58. package/dist/photo-gallery.js.map +1 -0
  59. package/dist/popover-panel.d.ts +37 -0
  60. package/dist/popover-panel.d.ts.map +1 -0
  61. package/dist/popover-panel.js +184 -0
  62. package/dist/popover-panel.js.map +1 -0
  63. package/dist/status-pill.d.ts +24 -0
  64. package/dist/status-pill.d.ts.map +1 -0
  65. package/dist/status-pill.js +101 -0
  66. package/dist/status-pill.js.map +1 -0
  67. package/dist/tile-grid.d.ts +32 -0
  68. package/dist/tile-grid.d.ts.map +1 -0
  69. package/dist/tile-grid.js +102 -0
  70. package/dist/tile-grid.js.map +1 -0
  71. package/dist/tokens.css +39 -0
  72. package/dist/tokens.d.ts +28 -3
  73. package/dist/tokens.d.ts.map +1 -1
  74. package/dist/tokens.js +42 -43
  75. package/dist/tokens.js.map +1 -1
  76. package/dist/user-avatar.d.ts +5 -2
  77. package/dist/user-avatar.d.ts.map +1 -1
  78. package/dist/user-avatar.js +22 -6
  79. package/dist/user-avatar.js.map +1 -1
  80. package/dist/utils/duration.d.ts +12 -0
  81. package/dist/utils/duration.d.ts.map +1 -0
  82. package/dist/utils/duration.js +27 -0
  83. package/dist/utils/duration.js.map +1 -0
  84. package/docs/chat-message.md +59 -0
  85. package/docs/data-table.md +63 -0
  86. package/docs/dropdown-button.md +61 -0
  87. package/docs/editable-text.md +51 -0
  88. package/docs/form-select.md +70 -0
  89. package/docs/frame-box.md +43 -0
  90. package/docs/gallery-item-variant.md +37 -0
  91. package/docs/gallery-item.md +47 -0
  92. package/docs/icon-button.md +52 -0
  93. package/docs/live-timer.md +39 -0
  94. package/docs/mcp-evaluation.md +18 -11
  95. package/docs/photo-gallery.md +77 -0
  96. package/docs/popover-panel.md +70 -0
  97. package/docs/status-pill.md +43 -0
  98. package/docs/tile-grid.md +58 -0
  99. package/docs/user-avatar.md +1 -1
  100. package/llms.txt +357 -1
  101. package/package.json +10 -3
package/llms.txt CHANGED
@@ -104,6 +104,30 @@ Example:
104
104
  </script>
105
105
  ```
106
106
 
107
+ ## <chat-message>
108
+
109
+ One conversation entry in a chat-style activity feed. Tool calls and
110
+ "thinking" traces are variants of this component rather than separate
111
+ ones — they share the same header, collapse behavior, and body card as a
112
+ normal message, just dimmed and collapsible with an always-visible summary.
113
+
114
+ Import: `import "@f-ewald/components/chat-message.js";`
115
+
116
+ Properties: `role` (attribute `role`) : ChatMessageRole, default "agent"; `variant` (attribute `variant`) : ChatMessageVariant, default "normal"; `author` (attribute `author`) : string, default ""; `timestamp` (attribute `timestamp`) : string | null, default null; `summary` (attribute `summary`) : string, default ""; `collapsible` (attribute `collapsible`) : boolean, default false; `collapsed` (attribute `collapsed`) : boolean, default false
117
+ Events: `toggle`
118
+ CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size`, `--ui-primary`, `--ui-radius`, `--ui-surface`, `--ui-text`, `--ui-text-muted`
119
+
120
+ Example:
121
+ ```html
122
+ <chat-message role="user" author="Freddy" timestamp="2026-07-19T12:00:00Z">
123
+ Write notes.md containing a haiku.
124
+ </chat-message>
125
+ <chat-message role="agent" variant="tool" collapsible collapsed summary='file_write · {"filename": "notes.md"}'>
126
+ directory: .
127
+ filename: notes.md
128
+ </chat-message>
129
+ ```
130
+
107
131
  ## <confirm-dialog>
108
132
 
109
133
  Reusable confirmation dialog: overlay + centered card with a slotted body,
@@ -144,6 +168,40 @@ Example:
144
168
  <copy-link-button value="https://example.com/listing/42" label="Copy listing link"></copy-link-button>
145
169
  ```
146
170
 
171
+ ## <data-table>
172
+
173
+ A generic, presentational table shell: renders a `<thead>` from `columns`
174
+ and one `<tr>` per entry in `rows`, with each cell's content produced by
175
+ `renderCell` (default: plain property lookup on the row object). Knows
176
+ nothing about what a "row" means — callers own the data shape entirely.
177
+
178
+ Optional `rowHref` makes whole rows clickable (navigating via `location.hash`),
179
+ without hijacking clicks on nested interactive elements (links/buttons) a
180
+ cell's rendered content might contain.
181
+
182
+ Import: `import "@f-ewald/components/data-table.js";`
183
+
184
+ Properties: `columns` (JS property only) : DataTableColumn[], default []; `rows` (JS property only) : unknown[], default []; `rowKey` (JS property only) : (row: unknown, index: number) => string | number, default —; `renderCell` (JS property only) : (row: unknown, key: string) => unknown, default —; `rowHref` (JS property only) : ((row: unknown) => string | null) | null, default null
185
+ Events: none
186
+ CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
187
+
188
+ Example:
189
+ ```html
190
+ <data-table></data-table>
191
+ <script type="module">
192
+ const table = document.querySelector("data-table");
193
+ table.columns = [
194
+ { key: "title", label: "Title" },
195
+ { key: "state", label: "State" },
196
+ ];
197
+ table.rows = [
198
+ { id: "tsk_1", title: "Write onboarding docs", state: "Backlog" },
199
+ { id: "tsk_2", title: "Fix the login bug", state: "Done" },
200
+ ];
201
+ table.rowHref = (row) => `#/tasks/${row.id}`;
202
+ </script>
203
+ ```
204
+
147
205
  ## <distance-value>
148
206
 
149
207
  Inline distance display. Renders miles/feet or km/m, switching units at
@@ -188,6 +246,191 @@ Example:
188
246
  </script>
189
247
  ```
190
248
 
249
+ ## <dropdown-button>
250
+
251
+ A primary-styled button with a label and chevron that opens an anchored
252
+ menu of actions — essentially `form-select` minus "current value"
253
+ semantics: a menu, not a select. Use for a set of mutually exclusive
254
+ next-step actions (e.g. a failed task's Retry / Close / Backlog).
255
+
256
+ Import: `import "@f-ewald/components/dropdown-button.js";`
257
+
258
+ Properties: `label` (attribute `label`) : string, default ""; `options` (JS property only) : DropdownOption[], default []; `disabled` (attribute `disabled`) : boolean, default false
259
+ Events: `select`
260
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-primary`, `--ui-primary-hover`, `--ui-radius-sm`, `--ui-shadow`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`
261
+
262
+ Example:
263
+ ```html
264
+ <dropdown-button label="Resolve…"></dropdown-button>
265
+ <script type="module">
266
+ const dropdown = document.querySelector("dropdown-button");
267
+ dropdown.options = [
268
+ { value: "retry", label: "Retry" },
269
+ { value: "close", label: "Close" },
270
+ { value: "backlog", label: "Backlog" },
271
+ ];
272
+ dropdown.addEventListener("select", (e) => console.log(e.detail.value));
273
+ </script>
274
+ ```
275
+
276
+ ## <editable-text>
277
+
278
+ Jira/GitHub-style click-to-edit text: a display span that turns into an
279
+ `<input>` (or auto-growing `<textarea>` when `multiline`) on click. The
280
+ input/textarea inherits the host's font, so a title wrapped in an `<h1>`
281
+ edits at title size.
282
+
283
+ Import: `import "@f-ewald/components/editable-text.js";`
284
+
285
+ Properties: `value` (attribute `value`) : string, default ""; `multiline` (attribute `multiline`) : boolean, default false; `placeholder` (attribute `placeholder`) : string, default ""; `readonly` (attribute `readonly`) : boolean, default false; `label` (attribute `label`) : string, default ""
286
+ Events: `change`
287
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-primary`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text-muted`
288
+
289
+ Example:
290
+ ```html
291
+ <editable-text value="Write the quarterly report" label="Title"></editable-text>
292
+ <editable-text multiline placeholder="Add a description…" label="Description"></editable-text>
293
+ ```
294
+
295
+ ## <form-select>
296
+
297
+ A styled dropdown select: a trigger button showing the current option's
298
+ label, opening a listbox popover on click. Drop-in generic replacement for
299
+ a native `<select>` wherever consistent cross-browser styling and a
300
+ `change` event carrying `{ value }` are wanted (e.g. a task's status
301
+ picker).
302
+
303
+ The trigger fills its host's width (`justify-content: space-between`
304
+ pushes the chevron to the far edge), but the host itself stays
305
+ `display: inline-block` — so usages that never size the host (a filter
306
+ bar, a status picker) keep shrink-to-fit auto-width unchanged. To make an
307
+ instance full-width, size the host itself: `form-select { width: 100%; }`.
308
+
309
+ Import: `import "@f-ewald/components/form-select.js";`
310
+
311
+ Properties: `options` (JS property only) : SelectOption[], default []; `value` (attribute `value`) : string, default ""; `label` (attribute `label`) : string, default ""; `disabled` (attribute `disabled`) : boolean, default false
312
+ Events: `change`
313
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-primary`, `--ui-radius-sm`, `--ui-shadow`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
314
+
315
+ Example:
316
+ ```html
317
+ <form-select label="Task state"></form-select>
318
+ <script type="module">
319
+ const select = document.querySelector("form-select");
320
+ select.options = [
321
+ { value: "open", label: "Open" },
322
+ { value: "in_progress", label: "In progress" },
323
+ { value: "done", label: "Done" },
324
+ ];
325
+ select.value = "open";
326
+ select.addEventListener("change", (e) => console.log(e.detail.value));
327
+ </script>
328
+ ```
329
+
330
+ ## <frame-box>
331
+
332
+ A titled frame around a slot: a gray border with a small uppercase,
333
+ muted label overlapping the top edge (fieldset/legend-style). Generic —
334
+ the label text is entirely up to the consumer (e.g. "Debug" to visually
335
+ fence off dev-only chrome from the product UI).
336
+
337
+ Import: `import "@f-ewald/components/frame-box.js";`
338
+
339
+ Properties: `label` (attribute `label`) : string, default ""
340
+ Events: none
341
+ CSS custom properties: `--ui-border`, `--ui-radius-sm`, `--ui-surface`, `--ui-text-muted`
342
+
343
+ Example:
344
+ ```html
345
+ <frame-box label="Debug">
346
+ Framed content goes here.
347
+ </frame-box>
348
+ ```
349
+
350
+ ## <gallery-item>
351
+
352
+ Declarative image metadata consumed by a parent `photo-gallery`.
353
+
354
+ Import: `import "@f-ewald/components/gallery-item.js";`
355
+
356
+ Properties: `src` (attribute `src`) : string, default ""; `alt` (attribute `alt`) : string, default ""; `caption` (attribute `caption`) : string | undefined, default —; `variants` (JS property only) : GalleryItemVariant[], default —
357
+ Events: none
358
+ CSS custom properties: none
359
+
360
+ Example:
361
+ ```html
362
+ <gallery-item
363
+ src="/photos/coast.jpg"
364
+ alt="Rocky California coastline"
365
+ caption="California coast"
366
+ >
367
+ <gallery-item-variant
368
+ media="(max-width: 640px)"
369
+ srcset="/photos/coast-portrait.jpg"
370
+ ></gallery-item-variant>
371
+ </gallery-item>
372
+ ```
373
+
374
+ ## <gallery-item-variant>
375
+
376
+ Responsive image source metadata for a parent `gallery-item`.
377
+
378
+ Import: `import "@f-ewald/components/gallery-item-variant.js";`
379
+
380
+ Properties: `media` (attribute `media`) : string | undefined, default —; `srcset` (attribute `srcset`) : string, default ""
381
+ Events: none
382
+ CSS custom properties: none
383
+
384
+ Example:
385
+ ```html
386
+ <gallery-item-variant
387
+ media="(max-width: 640px)"
388
+ srcset="/photos/coast-portrait.jpg"
389
+ ></gallery-item-variant>
390
+ ```
391
+
392
+ ## <icon-button>
393
+
394
+ A borderless button wrapping a passed-in icon, with a rounded
395
+ hover-highlight background. Use for a low-emphasis affordance next to
396
+ content it acts on (e.g. an "Edit" pencil at the end of a table row)
397
+ where a bordered `ui-button` would be too heavy.
398
+
399
+ Import: `import "@f-ewald/components/icon-button.js";`
400
+
401
+ Properties: `icon` (JS property only) : TemplateResult | null, default null; `label` (attribute `label`) : string, default ""; `disabled` (attribute `disabled`) : boolean, default false
402
+ Events: `click`
403
+ CSS custom properties: `--ui-focus-ring`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
404
+
405
+ Example:
406
+ ```html
407
+ <icon-button label="Edit"></icon-button>
408
+ <script type="module">
409
+ import { iconPencil } from "@f-ewald/components/icons.js";
410
+ const btn = document.querySelector("icon-button");
411
+ btn.icon = iconPencil(16);
412
+ btn.addEventListener("click", () => console.log("edit clicked"));
413
+ </script>
414
+ ```
415
+
416
+ ## <live-timer>
417
+
418
+ Per-second ticking count-up timer, e.g. a live "running for 12s" or
419
+ "Sleeping for 3 seconds" indicator. Renders nothing while `since` is unset
420
+ or unparseable.
421
+
422
+ Import: `import "@f-ewald/components/live-timer.js";`
423
+
424
+ Properties: `since` (attribute `since`) : string | null, default null; `format` (attribute `format`) : DurationFormat, default "seconds"; `prefix` (attribute `prefix`) : string, default ""; `suffix` (attribute `suffix`) : string, default ""
425
+ Events: none
426
+ CSS custom properties: none
427
+
428
+ Example:
429
+ ```html
430
+ <live-timer since="2026-07-19T12:00:00Z" prefix="Sleeping for "></live-timer>
431
+ <live-timer since="2026-07-19T12:00:00Z" format="compact" prefix="running for "></live-timer>
432
+ ```
433
+
191
434
  ## <map-circle>
192
435
 
193
436
  A plain circular map marker: a light-to-dark gradient fill with a white
@@ -273,6 +516,72 @@ Example:
273
516
  </script>
274
517
  ```
275
518
 
519
+ ## <photo-gallery>
520
+
521
+ Responsive, accessible image carousel composed from declarative
522
+ `gallery-item` children.
523
+
524
+ Import: `import "@f-ewald/components/photo-gallery.js";`
525
+
526
+ 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"
527
+ Events: `slide-change`
528
+ CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-overlay`, `--ui-primary`, `--ui-radius`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
529
+
530
+ Example:
531
+ ```html
532
+ <photo-gallery delay="5000" show-counter show-indicators>
533
+ <gallery-item
534
+ src="/photos/coast.jpg"
535
+ alt="Rocky California coastline"
536
+ caption="California coast"
537
+ >
538
+ <gallery-item-variant
539
+ media="(max-width: 640px)"
540
+ srcset="/photos/coast-portrait.jpg"
541
+ ></gallery-item-variant>
542
+ </gallery-item>
543
+ <gallery-item src="/photos/bridge.jpg" alt="Golden Gate Bridge"></gallery-item>
544
+ </photo-gallery>
545
+ <script type="module">
546
+ document.querySelector("photo-gallery").addEventListener("slide-change", (event) => {
547
+ console.log(event.detail.currentIndex);
548
+ });
549
+ </script>
550
+ ```
551
+
552
+ ## <popover-panel>
553
+
554
+ Generic anchored popover shell: a floating card positioned relative to its
555
+ nearest `position: relative` ancestor (place it next to its trigger button
556
+ inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge
557
+ drawer. Closes on outside click or Escape. Header chrome and close button
558
+ match `slide-panel`'s API (`heading`, `panel-close`) so either can be
559
+ swapped in for the other with no consumer-side changes beyond the wrapper.
560
+
561
+ Set `centered` to render as a screen-centered modal with a translucent
562
+ backdrop instead of the default anchored placement.
563
+
564
+ Import: `import "@f-ewald/components/popover-panel.js";`
565
+
566
+ Properties: `open` (attribute `open`) : boolean, default false; `heading` (attribute `heading`) : string, default ""; `centered` (attribute `centered`) : boolean, default false
567
+ Events: `panel-close`
568
+ CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size`, `--ui-radius`, `--ui-radius-sm`, `--ui-shadow-lg`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
569
+
570
+ Example:
571
+ ```html
572
+ <div style="position: relative; display: inline-block;">
573
+ <button id="new-task-btn">New task</button>
574
+ <popover-panel heading="New task">
575
+ Popover body content goes here.
576
+ </popover-panel>
577
+ </div>
578
+ <script type="module">
579
+ const popover = document.querySelector("popover-panel");
580
+ document.querySelector("#new-task-btn").addEventListener("click", () => (popover.open = true));
581
+ popover.addEventListener("panel-close", () => (popover.open = false));
582
+ </script>
583
+ ```
584
+
276
585
  ## <price-history-chart>
277
586
 
278
587
  D3-powered SVG line chart for property price history.
@@ -447,6 +756,53 @@ Example:
447
756
  <stat-meter label="GPU" percent="88" color="#dc2626"></stat-meter>
448
757
  ```
449
758
 
759
+ ## <status-pill>
760
+
761
+ Small colored status pill, optionally with a spinning icon — for task/run
762
+ states ("Open", "Blocked", "Done") and live-activity indicators ("Running").
763
+
764
+ Import: `import "@f-ewald/components/status-pill.js";`
765
+
766
+ Properties: `label` (attribute `label`) : string, default ""; `color` (attribute `color`) : StatusPillColor, default "neutral"; `spinner` (attribute `spinner`) : boolean, default false
767
+ Events: none
768
+ CSS custom properties: `--ui-danger`, `--ui-font`, `--ui-primary`, `--ui-success`, `--ui-text-muted`
769
+
770
+ Example:
771
+ ```html
772
+ <status-pill label="Running" color="primary" spinner></status-pill>
773
+ <status-pill label="Blocked" color="danger"></status-pill>
774
+ ```
775
+
776
+ ## <tile-grid>
777
+
778
+ A generic, presentational grid shell: renders one bordered card per entry
779
+ in `items`, with each tile's content produced by `renderTile` (default:
780
+ stringify). Knows nothing about what an "item" means — callers own the
781
+ data shape entirely. Modeled directly on `data-table`'s headless pattern.
782
+
783
+ Optional `itemHref` makes whole tiles clickable (navigating via
784
+ `location.hash`), without hijacking clicks on nested interactive elements
785
+ (links/buttons) a tile's rendered content might contain.
786
+
787
+ Import: `import "@f-ewald/components/tile-grid.js";`
788
+
789
+ Properties: `items` (JS property only) : unknown[], default []; `itemKey` (JS property only) : (item: unknown, index: number) => string | number, default —; `renderTile` (JS property only) : (item: unknown) => unknown, default —; `itemHref` (JS property only) : ((item: unknown) => string | null) | null, default null
790
+ Events: none
791
+ CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size-sm`, `--ui-radius`, `--ui-surface-muted`, `--ui-text`
792
+
793
+ Example:
794
+ ```html
795
+ <tile-grid></tile-grid>
796
+ <script type="module">
797
+ const grid = document.querySelector("tile-grid");
798
+ grid.items = [
799
+ { name: "notes.txt" },
800
+ { name: "photo.jpg" },
801
+ ];
802
+ grid.renderTile = (item) => item.name;
803
+ </script>
804
+ ```
805
+
450
806
  ## <toast-notification>
451
807
 
452
808
  Fixed-position stack of dismissible notifications, anchored top-right
@@ -514,7 +870,7 @@ circle.
514
870
 
515
871
  Import: `import "@f-ewald/components/user-avatar.js";`
516
872
 
517
- Properties: `src` (attribute `src`) : string | null, default null; `name` (attribute `name`) : string | null, default null; `size` (attribute `size`) : number, default 32
873
+ Properties: `src` (attribute `src`) : string | null, default null; `name` (attribute `name`) : string | null, default null; `size` (attribute `size`) : string | number, default 32
518
874
  Events: none
519
875
  CSS custom properties: `--ui-font`, `--ui-primary`
520
876
 
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@f-ewald/components",
3
3
  "private": false,
4
- "version": "0.5.0",
4
+ "version": "0.7.0",
5
5
  "description": "A collection of universally usable web components for various tasks.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "f-ewald-components-mcp": "dist/mcp-server.js"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
15
  "types": "./dist/index.d.ts",
@@ -31,11 +34,12 @@
31
34
  ],
32
35
  "scripts": {
33
36
  "dev": "vite",
34
- "build": "rm -rf dist && tsc && node scripts/generate-tokens-css.mjs",
37
+ "build": "rm -rf dist && tsc && node scripts/generate-tokens-css.mjs && chmod +x dist/mcp-server.js",
35
38
  "build:demo": "vite build",
36
39
  "analyze": "cem analyze --litelement --globs \"src/**/*.ts\"",
37
40
  "docs": "npm run analyze && node scripts/generate-docs.mjs",
38
41
  "icons": "node scripts/generate-icons.mjs",
42
+ "mcp": "node dist/mcp-server.js",
39
43
  "test": "playwright test",
40
44
  "prepublishOnly": "npm run build && npm run docs && npm run test"
41
45
  },
@@ -45,10 +49,12 @@
45
49
  "author": "Friedrich Ewald",
46
50
  "license": "BSD-3-Clause",
47
51
  "dependencies": {
52
+ "@modelcontextprotocol/sdk": "^1.29.0",
48
53
  "d3-array": "^3.2.4",
49
54
  "d3-scale": "^4.0.2",
50
55
  "d3-shape": "^3.2.0",
51
- "lit": "^3.3.3"
56
+ "lit": "^3.3.3",
57
+ "zod": "^4.4.3"
52
58
  },
53
59
  "publishConfig": {
54
60
  "access": "public"
@@ -61,6 +67,7 @@
61
67
  "@types/d3-array": "^3.2.2",
62
68
  "@types/d3-scale": "^4.0.9",
63
69
  "@types/d3-shape": "^3.1.8",
70
+ "@types/node": "^26.1.1",
64
71
  "heroicons": "^2.2.0",
65
72
  "tailwindcss": "^4.3.3",
66
73
  "typescript": "^7.0.2",