@f-ewald/components 0.6.0 → 1.0.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 (75) hide show
  1. package/README.md +101 -44
  2. package/custom-elements.json +2570 -877
  3. package/dist/calendar-entry.d.ts +33 -0
  4. package/dist/calendar-entry.d.ts.map +1 -0
  5. package/dist/calendar-entry.js +64 -0
  6. package/dist/calendar-entry.js.map +1 -0
  7. package/dist/calendar-month.d.ts +67 -0
  8. package/dist/calendar-month.d.ts.map +1 -0
  9. package/dist/calendar-month.js +455 -0
  10. package/dist/calendar-month.js.map +1 -0
  11. package/dist/calendar-year.d.ts +43 -0
  12. package/dist/calendar-year.d.ts.map +1 -0
  13. package/dist/calendar-year.js +136 -0
  14. package/dist/calendar-year.js.map +1 -0
  15. package/dist/dropdown-button.d.ts +37 -0
  16. package/dist/dropdown-button.d.ts.map +1 -0
  17. package/dist/dropdown-button.js +219 -0
  18. package/dist/dropdown-button.js.map +1 -0
  19. package/dist/form-select.d.ts +27 -2
  20. package/dist/form-select.d.ts.map +1 -1
  21. package/dist/form-select.js +440 -27
  22. package/dist/form-select.js.map +1 -1
  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/icon-button.d.ts +27 -0
  28. package/dist/icon-button.d.ts.map +1 -0
  29. package/dist/icon-button.js +83 -0
  30. package/dist/icon-button.js.map +1 -0
  31. package/dist/icons.d.ts +1 -0
  32. package/dist/icons.d.ts.map +1 -1
  33. package/dist/icons.js +1 -0
  34. package/dist/icons.js.map +1 -1
  35. package/dist/index.d.ts +6 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +6 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/map-circle.d.ts +3 -0
  40. package/dist/map-circle.d.ts.map +1 -1
  41. package/dist/map-circle.js +3 -0
  42. package/dist/map-circle.js.map +1 -1
  43. package/dist/mcp-server.d.ts +3 -0
  44. package/dist/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp-server.js +82 -0
  46. package/dist/mcp-server.js.map +1 -0
  47. package/dist/popover-panel.d.ts +3 -0
  48. package/dist/popover-panel.d.ts.map +1 -1
  49. package/dist/popover-panel.js +11 -0
  50. package/dist/popover-panel.js.map +1 -1
  51. package/dist/tokens.css +4 -0
  52. package/dist/tokens.d.ts.map +1 -1
  53. package/dist/tokens.js +3 -0
  54. package/dist/tokens.js.map +1 -1
  55. package/dist/utils/calendar.d.ts +77 -0
  56. package/dist/utils/calendar.d.ts.map +1 -0
  57. package/dist/utils/calendar.js +135 -0
  58. package/dist/utils/calendar.js.map +1 -0
  59. package/docs/calendar-entry.md +53 -0
  60. package/docs/calendar-month.md +77 -0
  61. package/docs/calendar-year.md +53 -0
  62. package/docs/dropdown-button.md +61 -0
  63. package/docs/form-select.md +21 -3
  64. package/docs/frame-box.md +43 -0
  65. package/docs/icon-button.md +52 -0
  66. package/docs/map-circle.md +4 -0
  67. package/docs/mcp-evaluation.md +18 -11
  68. package/docs/popover-panel.md +5 -1
  69. package/llms.txt +194 -28
  70. package/package.json +19 -4
  71. package/dist/map-point.d.ts +0 -31
  72. package/dist/map-point.d.ts.map +0 -1
  73. package/dist/map-point.js +0 -83
  74. package/dist/map-point.js.map +0 -1
  75. package/docs/map-point.md +0 -44
package/llms.txt CHANGED
@@ -104,6 +104,104 @@ Example:
104
104
  </script>
105
105
  ```
106
106
 
107
+ ## <calendar-entry>
108
+
109
+ Declarative metadata for one calendar event, consumed by a parent
110
+ `calendar-month` or `calendar-year`. Read-only/non-interactive; renders
111
+ nothing itself.
112
+
113
+ Import: `import "@f-ewald/components/calendar-entry.js";`
114
+
115
+ Properties: `start` (attribute `start`) : string, default ""; `end` (attribute `end`) : string, default ""; `label` (attribute `label`) : string, default ""; `color` (attribute `color`) : StatusPillColor, default "neutral"; `href` (attribute `href`) : string | undefined, default —
116
+ Events: none
117
+ CSS custom properties: none
118
+
119
+ Example:
120
+ ```html
121
+ <calendar-entry
122
+ start="2026-07-10"
123
+ end="2026-07-18"
124
+ label="Vacation"
125
+ color="success"
126
+ >
127
+ <span slot="title">Vacation</span>
128
+ <span slot="detail">Out of office</span>
129
+ <span slot="detail">Road trip along the California coast with several scenic stops</span>
130
+ <span slot="footer">Return July 19 at 6 PM</span>
131
+ </calendar-entry>
132
+ ```
133
+
134
+ ## <calendar-month>
135
+
136
+ One month rendered as a top-to-bottom list of days — weekends and today
137
+ highlighted, with declarative `calendar-entry` children shown as colored
138
+ bars spanning the days they cover. An entry's title uses its first visible
139
+ day; every remaining visible day becomes one shared body for wrapped
140
+ details and an optional ending footer. Overlapping entries stack into
141
+ side-by-side lanes rather than being layered/hidden. Read-only.
142
+
143
+ Lanes are computed independently per instance, from only the entries
144
+ overlapping this month — an entry spanning a month boundary may therefore
145
+ land in a different lane index in the adjacent month's `calendar-month`.
146
+ This is an accepted v1 limitation: cross-month lane continuity would
147
+ require a shared parent (`calendar-year`) to assign lanes globally.
148
+
149
+ Entry attributes and slotted title/detail text are observed, so a
150
+ standalone month re-renders when consumers update declarative metadata.
151
+
152
+ Import: `import "@f-ewald/components/calendar-month.js";`
153
+
154
+ Properties: `year` (attribute `year`) : number, default —; `month` (attribute `month`) : number, default 1
155
+ Events: none
156
+ CSS custom properties: `--ui-border`, `--ui-danger`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-size-xs`, `--ui-hover-overlay`, `--ui-primary`, `--ui-radius-sm`, `--ui-success`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
157
+
158
+ Example:
159
+ ```html
160
+ <calendar-month year="2026" month="7">
161
+ <calendar-entry start="2026-07-10" end="2026-07-18" label="Vacation" color="success">
162
+ <span slot="title">Vacation</span>
163
+ <span slot="detail">Out of office</span>
164
+ <span slot="detail">Road trip along the California coast with several scenic stops</span>
165
+ <span slot="footer">Return July 19 at 6 PM</span>
166
+ </calendar-entry>
167
+ <calendar-entry start="2026-07-15" end="2026-07-20" label="Conference" color="warning" href="#conf">
168
+ <span slot="detail">Talks and workshops</span>
169
+ <span slot="footer">Closing keynote · July 20</span>
170
+ </calendar-entry>
171
+ </calendar-month>
172
+ ```
173
+
174
+ ## <calendar-year>
175
+
176
+ A full year of `calendar-month` blocks, generated from declarative
177
+ `calendar-entry` children. Each entry is re-projected into the
178
+ `calendar-month` blocks it overlaps as a freshly-created `calendar-entry`
179
+ element — the original elements stay slotted here and are never moved,
180
+ since a DOM node can only have one parent. Read-only.
181
+
182
+ Import: `import "@f-ewald/components/calendar-year.js";`
183
+
184
+ Properties: `year` (attribute `year`) : number, default —
185
+ Events: none
186
+ CSS custom properties: `--ui-font`
187
+
188
+ Example:
189
+ ```html
190
+ <calendar-year year="2026">
191
+ <calendar-entry start="2026-01-28" end="2026-02-03" label="Offsite" color="primary" href="#offsite">
192
+ <span slot="detail">New York</span>
193
+ <span slot="detail">Team workshops</span>
194
+ <span slot="footer">Closing dinner Friday</span>
195
+ </calendar-entry>
196
+ <calendar-entry start="2026-03-05" end="2026-03-18" label="Product launch" color="success" href="#launch">
197
+ <span slot="detail">Coordinate the release across engineering, design, support, and marketing.</span>
198
+ <span slot="detail">Monitor adoption and production health throughout the rollout.</span>
199
+ <span slot="footer">Public launch · March 18 at 9 AM</span>
200
+ </calendar-entry>
201
+ <calendar-entry start="2026-07-10" end="2026-07-18" label="Vacation" color="success"></calendar-entry>
202
+ </calendar-year>
203
+ ```
204
+
107
205
  ## <chat-message>
108
206
 
109
207
  One conversation entry in a chat-style activity feed. Tool calls and
@@ -246,6 +344,33 @@ Example:
246
344
  </script>
247
345
  ```
248
346
 
347
+ ## <dropdown-button>
348
+
349
+ A primary-styled button with a label and chevron that opens an anchored
350
+ menu of actions — essentially `form-select` minus "current value"
351
+ semantics: a menu, not a select. Use for a set of mutually exclusive
352
+ next-step actions (e.g. a failed task's Retry / Close / Backlog).
353
+
354
+ Import: `import "@f-ewald/components/dropdown-button.js";`
355
+
356
+ Properties: `label` (attribute `label`) : string, default ""; `options` (JS property only) : DropdownOption[], default []; `disabled` (attribute `disabled`) : boolean, default false
357
+ Events: `select`
358
+ 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`
359
+
360
+ Example:
361
+ ```html
362
+ <dropdown-button label="Resolve…"></dropdown-button>
363
+ <script type="module">
364
+ const dropdown = document.querySelector("dropdown-button");
365
+ dropdown.options = [
366
+ { value: "retry", label: "Retry" },
367
+ { value: "close", label: "Close" },
368
+ { value: "backlog", label: "Backlog" },
369
+ ];
370
+ dropdown.addEventListener("select", (e) => console.log(e.detail.value));
371
+ </script>
372
+ ```
373
+
249
374
  ## <editable-text>
250
375
 
251
376
  Jira/GitHub-style click-to-edit text: a display span that turns into an
@@ -273,27 +398,64 @@ a native `<select>` wherever consistent cross-browser styling and a
273
398
  `change` event carrying `{ value }` are wanted (e.g. a task's status
274
399
  picker).
275
400
 
401
+ The trigger fills its host's width (`justify-content: space-between`
402
+ pushes the chevron to the far edge), but the host itself stays
403
+ `display: inline-block` — so usages that never size the host (a filter
404
+ bar, a status picker) keep shrink-to-fit auto-width unchanged. To make an
405
+ instance full-width, size the host itself: `form-select { width: 100%; }`.
406
+
407
+ Set `searchable` to replace the button trigger with an editable combobox
408
+ that filters the predefined options by case-insensitive label infix. Typed
409
+ text is only a query: `value` changes exclusively when an actual option is
410
+ selected, and an uncommitted query is discarded when the list closes.
411
+ Each option may also provide a pre-rendered `icon` and square `iconSize`;
412
+ iconless options reserve no leading space.
413
+
276
414
  Import: `import "@f-ewald/components/form-select.js";`
277
415
 
278
- Properties: `options` (JS property only) : SelectOption[], default []; `value` (attribute `value`) : string, default ""; `label` (attribute `label`) : string, default ""; `disabled` (attribute `disabled`) : boolean, default false
416
+ Properties: `options` (JS property only) : SelectOption[], default []; `value` (attribute `value`) : string, default ""; `label` (attribute `label`) : string, default ""; `disabled` (attribute `disabled`) : boolean, default false; `searchable` (attribute `searchable`) : boolean, default false
279
417
  Events: `change`
280
418
  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`
281
419
 
282
420
  Example:
283
421
  ```html
284
- <form-select label="Task state"></form-select>
422
+ <form-select label="Task state" searchable></form-select>
285
423
  <script type="module">
424
+ import { iconArrowPath, iconCheckCircle, iconListBullet } from "@f-ewald/components/icons.js";
425
+
286
426
  const select = document.querySelector("form-select");
287
427
  select.options = [
428
+ { value: "backlog", label: "Backlog", icon: iconListBullet(14), iconSize: 14 },
288
429
  { value: "open", label: "Open" },
289
- { value: "in_progress", label: "In progress" },
290
- { value: "done", label: "Done" },
430
+ { value: "in_progress", label: "In progress", icon: iconArrowPath(16), iconSize: 16 },
431
+ { value: "review", label: "Needs review" },
432
+ { value: "done", label: "Done", icon: iconCheckCircle(16), iconSize: 16 },
291
433
  ];
292
434
  select.value = "open";
293
435
  select.addEventListener("change", (e) => console.log(e.detail.value));
294
436
  </script>
295
437
  ```
296
438
 
439
+ ## <frame-box>
440
+
441
+ A titled frame around a slot: a gray border with a small uppercase,
442
+ muted label overlapping the top edge (fieldset/legend-style). Generic —
443
+ the label text is entirely up to the consumer (e.g. "Debug" to visually
444
+ fence off dev-only chrome from the product UI).
445
+
446
+ Import: `import "@f-ewald/components/frame-box.js";`
447
+
448
+ Properties: `label` (attribute `label`) : string, default ""
449
+ Events: none
450
+ CSS custom properties: `--ui-border`, `--ui-radius-sm`, `--ui-surface`, `--ui-text-muted`
451
+
452
+ Example:
453
+ ```html
454
+ <frame-box label="Debug">
455
+ Framed content goes here.
456
+ </frame-box>
457
+ ```
458
+
297
459
  ## <gallery-item>
298
460
 
299
461
  Declarative image metadata consumed by a parent `photo-gallery`.
@@ -336,6 +498,30 @@ Example:
336
498
  ></gallery-item-variant>
337
499
  ```
338
500
 
501
+ ## <icon-button>
502
+
503
+ A borderless button wrapping a passed-in icon, with a rounded
504
+ hover-highlight background. Use for a low-emphasis affordance next to
505
+ content it acts on (e.g. an "Edit" pencil at the end of a table row)
506
+ where a bordered `ui-button` would be too heavy.
507
+
508
+ Import: `import "@f-ewald/components/icon-button.js";`
509
+
510
+ Properties: `icon` (JS property only) : TemplateResult | null, default null; `label` (attribute `label`) : string, default ""; `disabled` (attribute `disabled`) : boolean, default false
511
+ Events: `click`
512
+ CSS custom properties: `--ui-focus-ring`, `--ui-radius-sm`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
513
+
514
+ Example:
515
+ ```html
516
+ <icon-button label="Edit"></icon-button>
517
+ <script type="module">
518
+ import { iconPencil } from "@f-ewald/components/icons.js";
519
+ const btn = document.querySelector("icon-button");
520
+ btn.icon = iconPencil(16);
521
+ btn.addEventListener("click", () => console.log("edit clicked"));
522
+ </script>
523
+ ```
524
+
339
525
  ## <live-timer>
340
526
 
341
527
  Per-second ticking count-up timer, e.g. a live "running for 12s" or
@@ -361,6 +547,9 @@ outer ring, no point/tail (unlike `<map-pin>`) — for markers that don't
361
547
  need to visually "point" at their exact coordinate. Purely a visual
362
548
  primitive — it has no `mapbox-gl` (or any mapping library) dependency;
363
549
  the consumer positions it, e.g. via `new mapboxgl.Marker({ element: el })`.
550
+ It can also replace the former `<map-point>` dense-layer primitive: use
551
+ `size="14" ring-width="3"`, leave the slot empty, and rasterize one marker
552
+ per color for use as a map `icon-image`.
364
553
 
365
554
  Import: `import "@f-ewald/components/map-circle.js";`
366
555
 
@@ -371,6 +560,7 @@ CSS custom properties: `--ui-font`
371
560
  Example:
372
561
  ```html
373
562
  <map-circle color="#6b7280"></map-circle>
563
+ <map-circle color="#0099D8" size="14" ring-width="3"></map-circle>
374
564
  <map-circle color="#1a73e8" size="24" ring-width="5" highlighted>1</map-circle>
375
565
  ```
376
566
 
@@ -393,30 +583,6 @@ Example:
393
583
  <map-pin color="#22c55e" size="26" highlighted>🏠</map-pin>
394
584
  ```
395
585
 
396
- ## <map-point>
397
-
398
- A small plain-colored map marker for dense point layers (transit stops,
399
- amenities, hazard points, etc.): a light-to-dark gradient fill with a thin
400
- white ring, no badge/content slot — every instance on a given layer shares
401
- the same look, so there's nothing to render per-feature (unlike
402
- `<map-pin>`/`<map-circle>`, which carry per-marker slotted content).
403
- Purely a visual primitive — it has no `mapbox-gl` (or any mapping library)
404
- dependency; typically rasterized once per color and used as a Mapbox
405
- `icon-image` on a `symbol` layer rather than mounted as individual DOM
406
- markers, so a whole layer's worth of points shares one icon image.
407
-
408
- Import: `import "@f-ewald/components/map-point.js";`
409
-
410
- Properties: `color` (attribute `color`) : string, default "#4f46e5"; `size` (attribute `size`) : number, default 14; `ringWidth` (attribute `ring-width`) : number, default 3
411
- Events: none
412
- CSS custom properties: none
413
-
414
- Example:
415
- ```html
416
- <map-point color="#0099D8"></map-point>
417
- <map-point color="#fb8072" size="10" ring-width="2"></map-point>
418
- ```
419
-
420
586
  ## <percent-bar-chart>
421
587
 
422
588
  Horizontal bar chart for labeled percentage rows, using D3's linear scale.
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "@f-ewald/components",
3
3
  "private": false,
4
- "version": "0.6.0",
4
+ "version": "1.0.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",
@@ -27,16 +30,21 @@
27
30
  "docs"
28
31
  ],
29
32
  "sideEffects": [
30
- "./dist/**/*.js"
33
+ "./dist/**/*.js",
34
+ "./src/**/*.ts"
31
35
  ],
32
36
  "scripts": {
33
37
  "dev": "vite",
34
- "build": "rm -rf dist && tsc && node scripts/generate-tokens-css.mjs",
38
+ "build": "rm -rf dist && tsc && node scripts/generate-tokens-css.mjs && chmod +x dist/mcp-server.js",
35
39
  "build:demo": "vite build",
40
+ "build:site": "node scripts/generate-docs.mjs --site && vite build --base=./ --outDir=pages-dist/playground",
41
+ "preview:site": "vite preview --outDir=pages-dist",
36
42
  "analyze": "cem analyze --litelement --globs \"src/**/*.ts\"",
37
43
  "docs": "npm run analyze && node scripts/generate-docs.mjs",
38
44
  "icons": "node scripts/generate-icons.mjs",
45
+ "mcp": "node dist/mcp-server.js",
39
46
  "test": "playwright test",
47
+ "test:site": "playwright test --config playwright.site.config.ts",
40
48
  "prepublishOnly": "npm run build && npm run docs && npm run test"
41
49
  },
42
50
  "keywords": [
@@ -44,11 +52,17 @@
44
52
  ],
45
53
  "author": "Friedrich Ewald",
46
54
  "license": "BSD-3-Clause",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/f-ewald/components.git"
58
+ },
47
59
  "dependencies": {
60
+ "@modelcontextprotocol/sdk": "^1.29.0",
48
61
  "d3-array": "^3.2.4",
49
62
  "d3-scale": "^4.0.2",
50
63
  "d3-shape": "^3.2.0",
51
- "lit": "^3.3.3"
64
+ "lit": "^3.3.3",
65
+ "zod": "^4.4.3"
52
66
  },
53
67
  "publishConfig": {
54
68
  "access": "public"
@@ -61,6 +75,7 @@
61
75
  "@types/d3-array": "^3.2.2",
62
76
  "@types/d3-scale": "^4.0.9",
63
77
  "@types/d3-shape": "^3.1.8",
78
+ "@types/node": "^26.1.1",
64
79
  "heroicons": "^2.2.0",
65
80
  "tailwindcss": "^4.3.3",
66
81
  "typescript": "^7.0.2",
@@ -1,31 +0,0 @@
1
- import { LitElement } from "lit";
2
- /**
3
- * A small plain-colored map marker for dense point layers (transit stops,
4
- * amenities, hazard points, etc.): a light-to-dark gradient fill with a thin
5
- * white ring, no badge/content slot — every instance on a given layer shares
6
- * the same look, so there's nothing to render per-feature (unlike
7
- * `<map-pin>`/`<map-circle>`, which carry per-marker slotted content).
8
- * Purely a visual primitive — it has no `mapbox-gl` (or any mapping library)
9
- * dependency; typically rasterized once per color and used as a Mapbox
10
- * `icon-image` on a `symbol` layer rather than mounted as individual DOM
11
- * markers, so a whole layer's worth of points shares one icon image.
12
- *
13
- * @element map-point
14
- */
15
- export declare class MapPoint extends LitElement {
16
- static styles: import("lit").CSSResult[];
17
- /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */
18
- color: string;
19
- /** Diameter, in CSS pixels. */
20
- size: number;
21
- /** White outer ring thickness, in the same viewBox units as `size` (scales with it). */
22
- ringWidth: number;
23
- private readonly _gradId;
24
- render(): import("lit-html").TemplateResult<1>;
25
- }
26
- declare global {
27
- interface HTMLElementTagNameMap {
28
- "map-point": MapPoint;
29
- }
30
- }
31
- //# sourceMappingURL=map-point.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"map-point.d.ts","sourceRoot":"","sources":["../src/map-point.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAO5C;;;;;;;;;;;;GAYG;AACH,qBACa,QAAS,SAAQ,UAAU;IACtC,OAAgB,MAAM,4BAWpB;IAEF,4FAA4F;IAChF,KAAK,SAAa;IAC9B,+BAA+B;IACH,IAAI,SAAM;IACtC,wFAAwF;IACnC,SAAS,SAAK;IAEnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IAE1D,MAAM,yCAoBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
package/dist/map-point.js DELETED
@@ -1,83 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { LitElement, css, html } from "lit";
8
- import { customElement, property } from "lit/decorators.js";
9
- import { tokens } from "./tokens.js";
10
- import { mixHex } from "./utils/color.js";
11
- let gradientIdCounter = 0;
12
- /**
13
- * A small plain-colored map marker for dense point layers (transit stops,
14
- * amenities, hazard points, etc.): a light-to-dark gradient fill with a thin
15
- * white ring, no badge/content slot — every instance on a given layer shares
16
- * the same look, so there's nothing to render per-feature (unlike
17
- * `<map-pin>`/`<map-circle>`, which carry per-marker slotted content).
18
- * Purely a visual primitive — it has no `mapbox-gl` (or any mapping library)
19
- * dependency; typically rasterized once per color and used as a Mapbox
20
- * `icon-image` on a `symbol` layer rather than mounted as individual DOM
21
- * markers, so a whole layer's worth of points shares one icon image.
22
- *
23
- * @element map-point
24
- */
25
- let MapPoint = class MapPoint extends LitElement {
26
- constructor() {
27
- super(...arguments);
28
- /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */
29
- this.color = "#4f46e5";
30
- /** Diameter, in CSS pixels. */
31
- this.size = 14;
32
- /** White outer ring thickness, in the same viewBox units as `size` (scales with it). */
33
- this.ringWidth = 3;
34
- this._gradId = `map-point-grad-${gradientIdCounter++}`;
35
- }
36
- static { this.styles = [
37
- tokens,
38
- css `
39
- :host {
40
- display: inline-block;
41
- line-height: 0;
42
- }
43
- svg {
44
- display: block;
45
- }
46
- `,
47
- ]; }
48
- render() {
49
- const light = mixHex(this.color, "#ffffff", 30);
50
- const dark = mixHex(this.color, "#000000", 30);
51
- return html `
52
- <svg
53
- width=${this.size}
54
- height=${this.size}
55
- viewBox="0 0 32 32"
56
- fill="none"
57
- xmlns="http://www.w3.org/2000/svg"
58
- >
59
- <defs>
60
- <linearGradient id=${this._gradId} x1="0" y1="0" x2="0" y2="1">
61
- <stop offset="0%" stop-color=${light} />
62
- <stop offset="100%" stop-color=${dark} />
63
- </linearGradient>
64
- </defs>
65
- <circle cx="16" cy="16" r="13" fill="url(#${this._gradId})" stroke="#ffffff" stroke-width=${this.ringWidth} />
66
- </svg>
67
- `;
68
- }
69
- };
70
- __decorate([
71
- property()
72
- ], MapPoint.prototype, "color", void 0);
73
- __decorate([
74
- property({ type: Number })
75
- ], MapPoint.prototype, "size", void 0);
76
- __decorate([
77
- property({ type: Number, attribute: "ring-width" })
78
- ], MapPoint.prototype, "ringWidth", void 0);
79
- MapPoint = __decorate([
80
- customElement("map-point")
81
- ], MapPoint);
82
- export { MapPoint };
83
- //# sourceMappingURL=map-point.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"map-point.js","sourceRoot":"","sources":["../src/map-point.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;;;;GAYG;AAEI,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,UAAU;IAAjC;;QAcL,4FAA4F;QAChF,UAAK,GAAG,SAAS,CAAC;QAC9B,+BAA+B;QACH,SAAI,GAAG,EAAE,CAAC;QACtC,wFAAwF;QACnC,cAAS,GAAG,CAAC,CAAC;QAElD,YAAO,GAAG,kBAAkB,iBAAiB,EAAE,EAAE,CAAC;IAuBrE,CAAC;aA3CiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;KAQF;KACF,AAXqB,CAWpB;IAWO,MAAM;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAA;;gBAEC,IAAI,CAAC,IAAI;iBACR,IAAI,CAAC,IAAI;;;;;;+BAMK,IAAI,CAAC,OAAO;2CACA,KAAK;6CACH,IAAI;;;oDAGG,IAAI,CAAC,OAAO,oCAAoC,IAAI,CAAC,SAAS;;KAE7G,CAAC;IACJ,CAAC;CACF,CAAA;AA7Ba;IAAX,QAAQ,EAAE;uCAAmB;AAEF;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sCAAW;AAEe;IAApD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;2CAAe;AAnBxD,QAAQ;IADpB,aAAa,CAAC,WAAW,CAAC;GACd,QAAQ,CA4CpB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\nimport { mixHex } from \"./utils/color.js\";\n\nlet gradientIdCounter = 0;\n\n/**\n * A small plain-colored map marker for dense point layers (transit stops,\n * amenities, hazard points, etc.): a light-to-dark gradient fill with a thin\n * white ring, no badge/content slot — every instance on a given layer shares\n * the same look, so there's nothing to render per-feature (unlike\n * `<map-pin>`/`<map-circle>`, which carry per-marker slotted content).\n * Purely a visual primitive — it has no `mapbox-gl` (or any mapping library)\n * dependency; typically rasterized once per color and used as a Mapbox\n * `icon-image` on a `symbol` layer rather than mounted as individual DOM\n * markers, so a whole layer's worth of points shares one icon image.\n *\n * @element map-point\n */\n@customElement(\"map-point\")\nexport class MapPoint extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: inline-block;\n line-height: 0;\n }\n svg {\n display: block;\n }\n `,\n ];\n\n /** Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. */\n @property() color = \"#4f46e5\";\n /** Diameter, in CSS pixels. */\n @property({ type: Number }) size = 14;\n /** White outer ring thickness, in the same viewBox units as `size` (scales with it). */\n @property({ type: Number, attribute: \"ring-width\" }) ringWidth = 3;\n\n private readonly _gradId = `map-point-grad-${gradientIdCounter++}`;\n\n override render() {\n const light = mixHex(this.color, \"#ffffff\", 30);\n const dark = mixHex(this.color, \"#000000\", 30);\n return html`\n <svg\n width=${this.size}\n height=${this.size}\n viewBox=\"0 0 32 32\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <linearGradient id=${this._gradId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=${light} />\n <stop offset=\"100%\" stop-color=${dark} />\n </linearGradient>\n </defs>\n <circle cx=\"16\" cy=\"16\" r=\"13\" fill=\"url(#${this._gradId})\" stroke=\"#ffffff\" stroke-width=${this.ringWidth} />\n </svg>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"map-point\": MapPoint;\n }\n}\n"]}
package/docs/map-point.md DELETED
@@ -1,44 +0,0 @@
1
- # `<map-point>`
2
-
3
- A small plain-colored map marker for dense point layers (transit stops,
4
- amenities, hazard points, etc.): a light-to-dark gradient fill with a thin
5
- white ring, no badge/content slot — every instance on a given layer shares
6
- the same look, so there's nothing to render per-feature (unlike
7
- `<map-pin>`/`<map-circle>`, which carry per-marker slotted content).
8
- Purely a visual primitive — it has no `mapbox-gl` (or any mapping library)
9
- dependency; typically rasterized once per color and used as a Mapbox
10
- `icon-image` on a `symbol` layer rather than mounted as individual DOM
11
- markers, so a whole layer's worth of points shares one icon image.
12
-
13
- ## Install
14
-
15
- ```js
16
- import "@f-ewald/components/map-point.js";
17
- ```
18
-
19
- ## Usage
20
-
21
- ```html
22
- <map-point color="#0099D8"></map-point>
23
- <map-point color="#fb8072" size="10" ring-width="2"></map-point>
24
- ```
25
-
26
- ## Attributes / properties
27
-
28
- | Property | Attribute | Type | Default | Description |
29
- | --- | --- | --- | --- | --- |
30
- | `color` | `color` | `string` | `"#4f46e5"` | Fill color; the gradient's light (top) and dark (bottom) stops are derived from this. |
31
- | `size` | `size` | `number` | `14` | Diameter, in CSS pixels. |
32
- | `ringWidth` | `ring-width` | `number` | `3` | White outer ring thickness, in the same viewBox units as `size` (scales with it). |
33
-
34
- ## Events
35
-
36
- _None._
37
-
38
- ## Slots
39
-
40
- _None._
41
-
42
- ## CSS custom properties
43
-
44
- _None._