@f-ewald/components 0.7.0 → 1.0.2

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 (193) hide show
  1. package/README.md +76 -47
  2. package/custom-elements.json +3049 -910
  3. package/dist/address-autocomplete.d.ts +8 -0
  4. package/dist/address-autocomplete.d.ts.map +1 -1
  5. package/dist/address-autocomplete.js +165 -15
  6. package/dist/address-autocomplete.js.map +1 -1
  7. package/dist/animate-confetti.d.ts +8 -5
  8. package/dist/animate-confetti.d.ts.map +1 -1
  9. package/dist/animate-confetti.js +46 -19
  10. package/dist/animate-confetti.js.map +1 -1
  11. package/dist/autocomplete-input.d.ts +8 -0
  12. package/dist/autocomplete-input.d.ts.map +1 -1
  13. package/dist/autocomplete-input.js +165 -15
  14. package/dist/autocomplete-input.js.map +1 -1
  15. package/dist/calendar-entry.d.ts +33 -0
  16. package/dist/calendar-entry.d.ts.map +1 -0
  17. package/dist/calendar-entry.js +64 -0
  18. package/dist/calendar-entry.js.map +1 -0
  19. package/dist/calendar-month.d.ts +67 -0
  20. package/dist/calendar-month.d.ts.map +1 -0
  21. package/dist/calendar-month.js +469 -0
  22. package/dist/calendar-month.js.map +1 -0
  23. package/dist/calendar-year.d.ts +43 -0
  24. package/dist/calendar-year.d.ts.map +1 -0
  25. package/dist/calendar-year.js +145 -0
  26. package/dist/calendar-year.js.map +1 -0
  27. package/dist/chat-message.d.ts.map +1 -1
  28. package/dist/chat-message.js +77 -24
  29. package/dist/chat-message.js.map +1 -1
  30. package/dist/confirm-dialog.d.ts +8 -1
  31. package/dist/confirm-dialog.d.ts.map +1 -1
  32. package/dist/confirm-dialog.js +130 -18
  33. package/dist/confirm-dialog.js.map +1 -1
  34. package/dist/copy-link-button.d.ts +2 -0
  35. package/dist/copy-link-button.d.ts.map +1 -1
  36. package/dist/copy-link-button.js +35 -3
  37. package/dist/copy-link-button.js.map +1 -1
  38. package/dist/data-table.d.ts +2 -0
  39. package/dist/data-table.d.ts.map +1 -1
  40. package/dist/data-table.js +83 -11
  41. package/dist/data-table.js.map +1 -1
  42. package/dist/distance-value.d.ts +0 -1
  43. package/dist/distance-value.d.ts.map +1 -1
  44. package/dist/distance-value.js +3 -8
  45. package/dist/distance-value.js.map +1 -1
  46. package/dist/distribution-chart.d.ts.map +1 -1
  47. package/dist/distribution-chart.js +54 -17
  48. package/dist/distribution-chart.js.map +1 -1
  49. package/dist/dropdown-button.d.ts.map +1 -1
  50. package/dist/dropdown-button.js +60 -11
  51. package/dist/dropdown-button.js.map +1 -1
  52. package/dist/editable-text.d.ts.map +1 -1
  53. package/dist/editable-text.js +46 -13
  54. package/dist/editable-text.js.map +1 -1
  55. package/dist/form-select.d.ts +21 -2
  56. package/dist/form-select.d.ts.map +1 -1
  57. package/dist/form-select.js +489 -37
  58. package/dist/form-select.js.map +1 -1
  59. package/dist/frame-box.d.ts.map +1 -1
  60. package/dist/frame-box.js +20 -12
  61. package/dist/frame-box.js.map +1 -1
  62. package/dist/icon-button.d.ts.map +1 -1
  63. package/dist/icon-button.js +11 -0
  64. package/dist/icon-button.js.map +1 -1
  65. package/dist/index.d.ts +4 -1
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +4 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/kbd-hint.d.ts +30 -0
  70. package/dist/kbd-hint.d.ts.map +1 -0
  71. package/dist/kbd-hint.js +184 -0
  72. package/dist/kbd-hint.js.map +1 -0
  73. package/dist/live-timer.d.ts +0 -1
  74. package/dist/live-timer.d.ts.map +1 -1
  75. package/dist/live-timer.js +1 -6
  76. package/dist/live-timer.js.map +1 -1
  77. package/dist/map-circle.d.ts +3 -0
  78. package/dist/map-circle.d.ts.map +1 -1
  79. package/dist/map-circle.js +19 -1
  80. package/dist/map-circle.js.map +1 -1
  81. package/dist/map-pin.d.ts.map +1 -1
  82. package/dist/map-pin.js +16 -1
  83. package/dist/map-pin.js.map +1 -1
  84. package/dist/percent-bar-chart.d.ts +3 -0
  85. package/dist/percent-bar-chart.d.ts.map +1 -1
  86. package/dist/percent-bar-chart.js +60 -4
  87. package/dist/percent-bar-chart.js.map +1 -1
  88. package/dist/photo-gallery.d.ts.map +1 -1
  89. package/dist/photo-gallery.js +12 -3
  90. package/dist/photo-gallery.js.map +1 -1
  91. package/dist/popover-panel.d.ts.map +1 -1
  92. package/dist/popover-panel.js +132 -23
  93. package/dist/popover-panel.js.map +1 -1
  94. package/dist/price-history-chart.d.ts.map +1 -1
  95. package/dist/price-history-chart.js +52 -18
  96. package/dist/price-history-chart.js.map +1 -1
  97. package/dist/radio-cards.d.ts +2 -0
  98. package/dist/radio-cards.d.ts.map +1 -1
  99. package/dist/radio-cards.js +51 -5
  100. package/dist/radio-cards.js.map +1 -1
  101. package/dist/radio-pills.d.ts +2 -0
  102. package/dist/radio-pills.d.ts.map +1 -1
  103. package/dist/radio-pills.js +46 -4
  104. package/dist/radio-pills.js.map +1 -1
  105. package/dist/relative-time.d.ts +0 -1
  106. package/dist/relative-time.d.ts.map +1 -1
  107. package/dist/relative-time.js +1 -6
  108. package/dist/relative-time.js.map +1 -1
  109. package/dist/reveal-button.d.ts +2 -0
  110. package/dist/reveal-button.d.ts.map +1 -1
  111. package/dist/reveal-button.js +42 -5
  112. package/dist/reveal-button.js.map +1 -1
  113. package/dist/roman-numeral.js +1 -1
  114. package/dist/roman-numeral.js.map +1 -1
  115. package/dist/slide-panel.d.ts +7 -3
  116. package/dist/slide-panel.d.ts.map +1 -1
  117. package/dist/slide-panel.js +95 -23
  118. package/dist/slide-panel.js.map +1 -1
  119. package/dist/stat-meter.d.ts.map +1 -1
  120. package/dist/stat-meter.js +17 -7
  121. package/dist/stat-meter.js.map +1 -1
  122. package/dist/status-pill.d.ts.map +1 -1
  123. package/dist/status-pill.js +26 -12
  124. package/dist/status-pill.js.map +1 -1
  125. package/dist/tile-grid.d.ts +8 -0
  126. package/dist/tile-grid.d.ts.map +1 -1
  127. package/dist/tile-grid.js +88 -12
  128. package/dist/tile-grid.js.map +1 -1
  129. package/dist/toast-notification.d.ts.map +1 -1
  130. package/dist/toast-notification.js +40 -11
  131. package/dist/toast-notification.js.map +1 -1
  132. package/dist/tokens.css +23 -0
  133. package/dist/tokens.d.ts.map +1 -1
  134. package/dist/tokens.js +16 -0
  135. package/dist/tokens.js.map +1 -1
  136. package/dist/ui-button.d.ts +2 -0
  137. package/dist/ui-button.d.ts.map +1 -1
  138. package/dist/ui-button.js +58 -9
  139. package/dist/ui-button.js.map +1 -1
  140. package/dist/user-avatar.d.ts.map +1 -1
  141. package/dist/user-avatar.js +18 -3
  142. package/dist/user-avatar.js.map +1 -1
  143. package/dist/utils/calendar.d.ts +77 -0
  144. package/dist/utils/calendar.d.ts.map +1 -0
  145. package/dist/utils/calendar.js +135 -0
  146. package/dist/utils/calendar.js.map +1 -0
  147. package/dist/utils/form.d.ts +3 -0
  148. package/dist/utils/form.d.ts.map +1 -0
  149. package/dist/utils/form.js +14 -0
  150. package/dist/utils/form.js.map +1 -0
  151. package/dist/utils/layer-stack.d.ts +9 -0
  152. package/dist/utils/layer-stack.d.ts.map +1 -0
  153. package/dist/utils/layer-stack.js +35 -0
  154. package/dist/utils/layer-stack.js.map +1 -0
  155. package/dist/weight-bar-chart.d.ts.map +1 -1
  156. package/dist/weight-bar-chart.js +27 -8
  157. package/dist/weight-bar-chart.js.map +1 -1
  158. package/docs/address-autocomplete.md +5 -0
  159. package/docs/autocomplete-input.md +5 -0
  160. package/docs/calendar-entry.md +53 -0
  161. package/docs/calendar-month.md +79 -0
  162. package/docs/calendar-year.md +53 -0
  163. package/docs/chat-message.md +4 -0
  164. package/docs/confirm-dialog.md +2 -0
  165. package/docs/copy-link-button.md +2 -0
  166. package/docs/data-table.md +2 -0
  167. package/docs/design-language.md +149 -0
  168. package/docs/distribution-chart.md +4 -0
  169. package/docs/dropdown-button.md +1 -0
  170. package/docs/form-select.md +15 -3
  171. package/docs/frame-box.md +2 -0
  172. package/docs/kbd-hint.md +42 -0
  173. package/docs/map-circle.md +4 -0
  174. package/docs/percent-bar-chart.md +4 -1
  175. package/docs/photo-gallery.md +1 -0
  176. package/docs/popover-panel.md +2 -0
  177. package/docs/price-history-chart.md +8 -1
  178. package/docs/radio-cards.md +2 -0
  179. package/docs/radio-pills.md +2 -0
  180. package/docs/reveal-button.md +3 -0
  181. package/docs/slide-panel.md +4 -2
  182. package/docs/status-pill.md +3 -0
  183. package/docs/tile-grid.md +10 -1
  184. package/docs/toast-notification.md +4 -1
  185. package/docs/ui-button.md +2 -0
  186. package/docs/user-avatar.md +1 -0
  187. package/llms.txt +175 -61
  188. package/package.json +14 -2
  189. package/dist/map-point.d.ts +0 -31
  190. package/dist/map-point.d.ts.map +0 -1
  191. package/dist/map-point.js +0 -83
  192. package/dist/map-point.js.map +0 -1
  193. package/docs/map-point.md +0 -44
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.js","sourceRoot":"","sources":["../../src/utils/calendar.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StatusPillColor } from \"../status-pill.js\";\nimport type { CalendarEntry } from \"../calendar-entry.js\";\n\n/** Plain data extracted from a `calendar-entry` element's properties. */\nexport interface CalendarEntryData {\n start: string;\n end: string;\n label: string;\n details?: string[];\n footer?: string;\n color: StatusPillColor;\n href?: string;\n}\n\n/** A `CalendarEntryData` with its date strings resolved to local `Date`s. */\nexport interface ResolvedCalendarEntry extends CalendarEntryData {\n startDate: Date;\n endDate: Date;\n}\n\n/** A `ResolvedCalendarEntry` assigned a stacking column by `assignLanes`. */\nexport interface LanedEntry extends ResolvedCalendarEntry {\n lane: number;\n}\n\nconst ISO_DATE_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** Attributes whose mutations can change a rendered calendar entry. */\nexport const CALENDAR_ENTRY_ATTRIBUTES = [\"start\", \"end\", \"label\", \"color\", \"href\", \"slot\"];\n\n/** Number of days in `month` (1-12) of `year`, leap years included. */\nexport function daysInMonth(year: number, month: number): number {\n return new Date(year, month, 0).getDate();\n}\n\n/**\n * Parses `\"YYYY-MM-DD\"` as a local-midnight `Date`. Returns `null` for\n * anything that doesn't match or doesn't round-trip (e.g. \"2026-02-30\") —\n * deliberately never uses `new Date(iso)`/`.toISOString()`, both of which\n * are UTC-based and would silently shift the date in negative-UTC-offset\n * timezones.\n */\nexport function parseIsoDate(iso: string): Date | null {\n const match = ISO_DATE_PATTERN.exec(iso);\n if (!match) return null;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {\n return null;\n }\n return date;\n}\n\n/** Formats a `Date`'s local year/month/day as `\"YYYY-MM-DD\"`. */\nexport function toIsoDate(date: Date): string {\n const year = String(date.getFullYear()).padStart(4, \"0\");\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\nconst monthNameFormatter = new Intl.DateTimeFormat(undefined, { month: \"long\" });\n\n/** Locale-aware full month name for `month` (1-12). */\nexport function monthName(month: number): string {\n return monthNameFormatter.format(new Date(2000, month - 1, 1));\n}\n\n/** Sunday-first weekday abbreviations, indexed by `Date.getDay()` (0 = Sunday). */\nexport const WEEKDAY_ABBR: readonly string[] = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\n/**\n * Whether `date` falls on a Saturday or Sunday, per JS's `Date.getDay()`\n * convention (Sunday = 0 .. Saturday = 6) — note this differs from Python's\n * `calendar` module (Monday = 0), which the original reference\n * implementation this component's layout is based on used.\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\n/** Reads normalized plain-text content from direct children assigned to a named slot. */\nfunction slottedText(el: CalendarEntry, slotName: string): string[] {\n return Array.from(el.querySelectorAll<HTMLElement>(`:scope > [slot=\"${slotName}\"]`))\n .map((node) => (node.textContent ?? \"\").replace(/\\s+/g, \" \").trim());\n}\n\n/** Reads a `calendar-entry` element's properties and named text slots into plain data. */\nexport function readCalendarEntryElement(el: CalendarEntry): CalendarEntryData {\n const title = slottedText(el, \"title\").find((line) => line.length > 0);\n const footer = slottedText(el, \"footer\").find((line) => line.length > 0);\n return {\n start: el.start,\n end: el.end,\n label: title ?? el.label,\n details: slottedText(el, \"detail\"),\n footer,\n color: el.color,\n href: el.href,\n };\n}\n\n/**\n * Resolves a `CalendarEntryData`'s date strings to `Date`s. Returns `null`\n * when `start` is missing or unparseable — such entries are dropped\n * silently rather than thrown, since this reads declarative markup a\n * consumer authored, not validated user input. A blank `end` defaults to\n * `start` (single-day entry); an `end` before `start` is clamped up to\n * `start` rather than treated as an error.\n */\nexport function resolveEntry(data: CalendarEntryData): ResolvedCalendarEntry | null {\n const startDate = parseIsoDate(data.start);\n if (!startDate) return null;\n\n const endDate = parseIsoDate(data.end) ?? startDate;\n return {\n ...data,\n details: data.details ?? [],\n startDate,\n endDate: endDate < startDate ? startDate : endDate,\n };\n}\n\n/** Whether `entry`'s inclusive date range intersects the inclusive `[rangeStart, rangeEnd]` range. */\nexport function overlapsRange(entry: ResolvedCalendarEntry, rangeStart: Date, rangeEnd: Date): boolean {\n return entry.startDate <= rangeEnd && entry.endDate >= rangeStart;\n}\n\n/**\n * Assigns each entry a 0-based stacking lane via greedy interval\n * partitioning (\"meeting rooms II\"): entries are sorted by start date, then\n * each is placed in the lowest-numbered lane whose current occupant ends\n * strictly before the entry starts. Because entry ranges are\n * inclusive-inclusive, an entry ending on day X and one starting on day X\n * both occupy day X and must not share a lane — hence the strict `<`.\n *\n * Lane assignment is meant to be computed independently per `calendar-month`\n * (from only the entries overlapping that month); an entry spanning a month\n * boundary may therefore land in a different lane in adjacent months. This\n * is an accepted v1 limitation, not a bug.\n */\nexport function assignLanes(entries: ResolvedCalendarEntry[]): {\n entries: LanedEntry[];\n laneCount: number;\n} {\n const sorted = entries\n .map((entry, index) => ({ entry, index }))\n .sort((a, b) => {\n const startDiff = a.entry.startDate.getTime() - b.entry.startDate.getTime();\n if (startDiff !== 0) return startDiff;\n const endDiff = a.entry.endDate.getTime() - b.entry.endDate.getTime();\n if (endDiff !== 0) return endDiff;\n return a.index - b.index;\n });\n\n const laneEnds: Date[] = [];\n const laned: LanedEntry[] = [];\n for (const { entry } of sorted) {\n let lane = laneEnds.findIndex((end) => end < entry.startDate);\n if (lane === -1) {\n lane = laneEnds.length;\n laneEnds.push(entry.endDate);\n } else {\n laneEnds[lane] = entry.endDate;\n }\n laned.push({ ...entry, lane });\n }\n\n return { entries: laned, laneCount: laneEnds.length };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Submits a form through its default enabled native submit control when present. */
2
+ export declare function submitWithDefaultButton(form: HTMLFormElement): void;
3
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/utils/form.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAWnE"}
@@ -0,0 +1,14 @@
1
+ /** Submits a form through its default enabled native submit control when present. */
2
+ export function submitWithDefaultButton(form) {
3
+ const submitter = Array.from(form.elements).find((element) => (element instanceof HTMLButtonElement ||
4
+ element instanceof HTMLInputElement) &&
5
+ (element.type === "submit" ||
6
+ (element instanceof HTMLInputElement && element.type === "image")));
7
+ if (submitter?.matches(":disabled"))
8
+ return;
9
+ if (submitter)
10
+ submitter.click();
11
+ else
12
+ form.requestSubmit();
13
+ }
14
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../../src/utils/form.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,UAAU,uBAAuB,CAAC,IAAqB;IAC3D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAC9C,CAAC,OAAO,EAAmD,EAAE,CAC3D,CAAC,OAAO,YAAY,iBAAiB;QACnC,OAAO,YAAY,gBAAgB,CAAC;QACtC,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ;YACxB,CAAC,OAAO,YAAY,gBAAgB,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CACvE,CAAC;IACF,IAAI,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC;QAAE,OAAO;IAC5C,IAAI,SAAS;QAAE,SAAS,CAAC,KAAK,EAAE,CAAC;;QAC5B,IAAI,CAAC,aAAa,EAAE,CAAC;AAC5B,CAAC","sourcesContent":["/** Submits a form through its default enabled native submit control when present. */\nexport function submitWithDefaultButton(form: HTMLFormElement): void {\n const submitter = Array.from(form.elements).find(\n (element): element is HTMLButtonElement | HTMLInputElement =>\n (element instanceof HTMLButtonElement ||\n element instanceof HTMLInputElement) &&\n (element.type === \"submit\" ||\n (element instanceof HTMLInputElement && element.type === \"image\")),\n );\n if (submitter?.matches(\":disabled\")) return;\n if (submitter) submitter.click();\n else form.requestSubmit();\n}\n"]}
@@ -0,0 +1,9 @@
1
+ /** Registers an open overlay as the current topmost interactive layer. */
2
+ export declare function activateLayer(layer: HTMLElement): void;
3
+ /** Removes a closed or disconnected overlay from the layer stack. */
4
+ export declare function deactivateLayer(layer: HTMLElement): void;
5
+ /** Whether this overlay currently owns global Escape/focus behavior. */
6
+ export declare function isTopLayer(layer: HTMLElement): boolean;
7
+ /** Claims Escape for the topmost layer and marks it handled for other listeners. */
8
+ export declare function claimEscape(layer: HTMLElement, event: KeyboardEvent): boolean;
9
+ //# sourceMappingURL=layer-stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-stack.d.ts","sourceRoot":"","sources":["../../src/utils/layer-stack.ts"],"names":[],"mappings":"AAUA,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAItD;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAKxD;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAEtD;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAM7E"}
@@ -0,0 +1,35 @@
1
+ const layers = [];
2
+ const baseZIndex = 100;
3
+ /** Keeps visual z-order synchronized with interaction-stack order. */
4
+ function syncLayerOrder() {
5
+ layers.forEach((layer, index) => {
6
+ layer.style.setProperty("--component-layer-z", String(baseZIndex + index));
7
+ });
8
+ }
9
+ /** Registers an open overlay as the current topmost interactive layer. */
10
+ export function activateLayer(layer) {
11
+ deactivateLayer(layer);
12
+ layers.push(layer);
13
+ syncLayerOrder();
14
+ }
15
+ /** Removes a closed or disconnected overlay from the layer stack. */
16
+ export function deactivateLayer(layer) {
17
+ const index = layers.indexOf(layer);
18
+ if (index >= 0)
19
+ layers.splice(index, 1);
20
+ layer.style.removeProperty("--component-layer-z");
21
+ syncLayerOrder();
22
+ }
23
+ /** Whether this overlay currently owns global Escape/focus behavior. */
24
+ export function isTopLayer(layer) {
25
+ return layers.at(-1) === layer;
26
+ }
27
+ /** Claims Escape for the topmost layer and marks it handled for other listeners. */
28
+ export function claimEscape(layer, event) {
29
+ if (event.key !== "Escape" || event.defaultPrevented || !isTopLayer(layer)) {
30
+ return false;
31
+ }
32
+ event.preventDefault();
33
+ return true;
34
+ }
35
+ //# sourceMappingURL=layer-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-stack.js","sourceRoot":"","sources":["../../src/utils/layer-stack.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAkB,EAAE,CAAC;AACjC,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,sEAAsE;AACtE,SAAS,cAAc;IACrB,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC9B,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,qBAAqB,EAAE,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,eAAe,CAAC,KAAK,CAAC,CAAC;IACvB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC;AACnB,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,qBAAqB,CAAC,CAAC;IAClD,cAAc,EAAE,CAAC;AACnB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,KAAkB;IAC3C,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;AACjC,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,WAAW,CAAC,KAAkB,EAAE,KAAoB;IAClE,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["const layers: HTMLElement[] = [];\nconst baseZIndex = 100;\n\n/** Keeps visual z-order synchronized with interaction-stack order. */\nfunction syncLayerOrder(): void {\n layers.forEach((layer, index) => {\n layer.style.setProperty(\"--component-layer-z\", String(baseZIndex + index));\n });\n}\n\n/** Registers an open overlay as the current topmost interactive layer. */\nexport function activateLayer(layer: HTMLElement): void {\n deactivateLayer(layer);\n layers.push(layer);\n syncLayerOrder();\n}\n\n/** Removes a closed or disconnected overlay from the layer stack. */\nexport function deactivateLayer(layer: HTMLElement): void {\n const index = layers.indexOf(layer);\n if (index >= 0) layers.splice(index, 1);\n layer.style.removeProperty(\"--component-layer-z\");\n syncLayerOrder();\n}\n\n/** Whether this overlay currently owns global Escape/focus behavior. */\nexport function isTopLayer(layer: HTMLElement): boolean {\n return layers.at(-1) === layer;\n}\n\n/** Claims Escape for the topmost layer and marks it handled for other listeners. */\nexport function claimEscape(layer: HTMLElement, event: KeyboardEvent): boolean {\n if (event.key !== \"Escape\" || event.defaultPrevented || !isTopLayer(layer)) {\n return false;\n }\n event.preventDefault();\n return true;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"weight-bar-chart.d.ts","sourceRoot":"","sources":["../src/weight-bar-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,oEAAoE;IACpC,KAAK,EAAE,aAAa,EAAE,CAAM;IAE5D,OAAgB,MAAM,4BAuCpB;IAEO,MAAM,gDAuBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
1
+ {"version":3,"file":"weight-bar-chart.d.ts","sourceRoot":"","sources":["../src/weight-bar-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;GASG;AACH,qBACa,cAAe,SAAQ,UAAU;IAC5C,oEAAoE;IACpC,KAAK,EAAE,aAAa,EAAE,CAAM;IAE5D,OAAgB,MAAM,4BA0DpB;IAEO,MAAM,gDAuBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
@@ -33,35 +33,54 @@ let WeightBarChart = class WeightBarChart extends LitElement {
33
33
  .row {
34
34
  display: flex;
35
35
  align-items: center;
36
- gap: 8px;
37
- margin: 6px 0;
36
+ gap: 0.5rem;
37
+ margin: 0.5rem 0;
38
38
  }
39
39
  .label {
40
- flex: 0 0 90px;
40
+ flex: 0 0 5.5rem;
41
41
  font-size: var(--ui-font-size-sm, 0.75rem);
42
- font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
42
+ font-family: var(
43
+ --ui-font,
44
+ ui-sans-serif,
45
+ system-ui,
46
+ sans-serif,
47
+ "Apple Color Emoji",
48
+ "Segoe UI Emoji",
49
+ "Segoe UI Symbol",
50
+ "Noto Color Emoji"
51
+ );
43
52
  color: var(--ui-text, #0f172a);
44
53
  }
45
54
  .track {
46
55
  flex: 1 1 auto;
47
- height: 12px;
56
+ height: 0.75rem;
48
57
  background: var(--ui-surface-muted, #f8fafc);
49
58
  border-radius: var(--ui-radius-sm, 0.25rem);
50
59
  overflow: hidden;
51
60
  }
52
61
  .bar {
53
62
  height: 100%;
54
- background: var(--ui-primary, #4f46e5);
63
+ /* Match map-circle's 30% white/black vertical depth while preserving token overrides. */
64
+ background: linear-gradient(
65
+ to bottom,
66
+ color-mix(in srgb, var(--ui-primary, #4f46e5) 70%, #ffffff) 0%,
67
+ color-mix(in srgb, var(--ui-primary, #4f46e5) 70%, #000000) 100%
68
+ );
55
69
  border-radius: 0 var(--ui-radius-sm, 0.25rem) var(--ui-radius-sm, 0.25rem) 0;
56
- transition: width 0.15s ease-out;
70
+ transition: width 150ms ease-out;
57
71
  }
58
72
  .pct {
59
- flex: 0 0 40px;
73
+ flex: 0 0 2.5rem;
60
74
  text-align: right;
61
75
  font-size: var(--ui-font-size-sm, 0.75rem);
62
76
  font-variant-numeric: tabular-nums;
63
77
  color: var(--ui-text-muted, #64748b);
64
78
  }
79
+ @media (prefers-reduced-motion: reduce) {
80
+ .bar {
81
+ transition: none;
82
+ }
83
+ }
65
84
  `,
66
85
  ]; }
67
86
  render() {
@@ -1 +1 @@
1
- {"version":3,"file":"weight-bar-chart.js","sourceRoot":"","sources":["../src/weight-bar-chart.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,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC;;;;;;;;;GASG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QACL,oEAAoE;QACpC,UAAK,GAAoB,EAAE,CAAC;IAmE9D,CAAC;aAjEiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoCF;KACF,AAvCqB,CAuCpB;IAEO,MAAM;QACb,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,+EAA+E;QAC/E,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClG,OAAO,IAAI,CAAA;6CAC8B,OAAO;UAC1C,MAAM,CACN,MAAM,EACN,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EACjB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;;oCAEY,IAAI,CAAC,KAAK;;iDAEG,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG;;kCAEvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;;WAEnD,CACF;;KAEJ,CAAC;IACJ,CAAC;CACF,CAAA;AAnEiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;6CAA6B;AAFjD,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CAqE1B","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface WeightBarItem {\n id: string;\n label: string;\n /** Normalized fraction (fractions across all items sum to ~1). */\n value: number;\n}\n\n/**\n * Sorted horizontal bar chart of labeled weights (normalized fractions\n * summing to ~1). Bars sort descending — the order IS the priority ranking.\n * Widths scale relative to the largest weight (which fills its track); the\n * percent labels carry the absolute values. Rows are keyed by item id\n * (repeat directive) so a re-render with new weights moves the existing\n * rows; bar widths animate via CSS, re-sorting is instant.\n *\n * @element weight-bar-chart\n */\n@customElement(\"weight-bar-chart\")\nexport class WeightBarChart extends LitElement {\n /** Items to render as weighted rows, sorted descending by value. */\n @property({ attribute: false }) items: WeightBarItem[] = [];\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .row {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 6px 0;\n }\n .label {\n flex: 0 0 90px;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n color: var(--ui-text, #0f172a);\n }\n .track {\n flex: 1 1 auto;\n height: 12px;\n background: var(--ui-surface-muted, #f8fafc);\n border-radius: var(--ui-radius-sm, 0.25rem);\n overflow: hidden;\n }\n .bar {\n height: 100%;\n background: var(--ui-primary, #4f46e5);\n border-radius: 0 var(--ui-radius-sm, 0.25rem) var(--ui-radius-sm, 0.25rem) 0;\n transition: width 0.15s ease-out;\n }\n .pct {\n flex: 0 0 40px;\n text-align: right;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-variant-numeric: tabular-nums;\n color: var(--ui-text-muted, #64748b);\n }\n `,\n ];\n\n override render() {\n if (this.items.length === 0) return null;\n // Stable sort: ties keep the incoming item order, so the chart never flickers.\n const sorted = [...this.items].sort((a, b) => b.value - a.value);\n const max = Math.max(0.01, ...sorted.map((item) => item.value));\n const summary = sorted.map((item) => `${item.label} ${Math.round(item.value * 100)}%`).join(\", \");\n return html`\n <div role=\"img\" aria-label=\"Weights: ${summary}\">\n ${repeat(\n sorted,\n (item) => item.id,\n (item) => html`\n <div class=\"row\">\n <span class=\"label\">${item.label}</span>\n <div class=\"track\">\n <div class=\"bar\" style=\"width: ${(item.value / max) * 100}%\"></div>\n </div>\n <span class=\"pct\">${Math.round(item.value * 100)}%</span>\n </div>\n `,\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"weight-bar-chart\": WeightBarChart;\n }\n}\n"]}
1
+ {"version":3,"file":"weight-bar-chart.js","sourceRoot":"","sources":["../src/weight-bar-chart.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,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC;;;;;;;;;GASG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QACL,oEAAoE;QACpC,UAAK,GAAoB,EAAE,CAAC;IAsF9D,CAAC;aApFiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuDF;KACF,AA1DqB,CA0DpB;IAEO,MAAM;QACb,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,+EAA+E;QAC/E,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClG,OAAO,IAAI,CAAA;6CAC8B,OAAO;UAC1C,MAAM,CACN,MAAM,EACN,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EACjB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;;oCAEY,IAAI,CAAC,KAAK;;iDAEG,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG;;kCAEvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;;WAEnD,CACF;;KAEJ,CAAC;IACJ,CAAC;CACF,CAAA;AAtFiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;6CAA6B;AAFjD,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CAwF1B","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface WeightBarItem {\n id: string;\n label: string;\n /** Normalized fraction (fractions across all items sum to ~1). */\n value: number;\n}\n\n/**\n * Sorted horizontal bar chart of labeled weights (normalized fractions\n * summing to ~1). Bars sort descending — the order IS the priority ranking.\n * Widths scale relative to the largest weight (which fills its track); the\n * percent labels carry the absolute values. Rows are keyed by item id\n * (repeat directive) so a re-render with new weights moves the existing\n * rows; bar widths animate via CSS, re-sorting is instant.\n *\n * @element weight-bar-chart\n */\n@customElement(\"weight-bar-chart\")\nexport class WeightBarChart extends LitElement {\n /** Items to render as weighted rows, sorted descending by value. */\n @property({ attribute: false }) items: WeightBarItem[] = [];\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .row {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin: 0.5rem 0;\n }\n .label {\n flex: 0 0 5.5rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\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 color: var(--ui-text, #0f172a);\n }\n .track {\n flex: 1 1 auto;\n height: 0.75rem;\n background: var(--ui-surface-muted, #f8fafc);\n border-radius: var(--ui-radius-sm, 0.25rem);\n overflow: hidden;\n }\n .bar {\n height: 100%;\n /* Match map-circle's 30% white/black vertical depth while preserving token overrides. */\n background: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--ui-primary, #4f46e5) 70%, #ffffff) 0%,\n color-mix(in srgb, var(--ui-primary, #4f46e5) 70%, #000000) 100%\n );\n border-radius: 0 var(--ui-radius-sm, 0.25rem) var(--ui-radius-sm, 0.25rem) 0;\n transition: width 150ms ease-out;\n }\n .pct {\n flex: 0 0 2.5rem;\n text-align: right;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-variant-numeric: tabular-nums;\n color: var(--ui-text-muted, #64748b);\n }\n @media (prefers-reduced-motion: reduce) {\n .bar {\n transition: none;\n }\n }\n `,\n ];\n\n override render() {\n if (this.items.length === 0) return null;\n // Stable sort: ties keep the incoming item order, so the chart never flickers.\n const sorted = [...this.items].sort((a, b) => b.value - a.value);\n const max = Math.max(0.01, ...sorted.map((item) => item.value));\n const summary = sorted.map((item) => `${item.label} ${Math.round(item.value * 100)}%`).join(\", \");\n return html`\n <div role=\"img\" aria-label=\"Weights: ${summary}\">\n ${repeat(\n sorted,\n (item) => item.id,\n (item) => html`\n <div class=\"row\">\n <span class=\"label\">${item.label}</span>\n <div class=\"track\">\n <div class=\"bar\" style=\"width: ${(item.value / max) * 100}%\"></div>\n </div>\n <span class=\"pct\">${Math.round(item.value * 100)}%</span>\n </div>\n `,\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"weight-bar-chart\": WeightBarChart;\n }\n}\n"]}
@@ -35,6 +35,7 @@ import "@f-ewald/components/address-autocomplete.js";
35
35
  | `value` | `value` | `string` | `""` | Current input value; also the form-associated value submitted with the form. |
36
36
  | `placeholder` | `placeholder` | `string` | `""` | Placeholder text shown when the input is empty. |
37
37
  | `required` | `required` | `boolean` | `false` | Marks the input as required for native form validation. |
38
+ | `disabled` | `disabled` | `boolean` | `false` | Disables the input and closes its suggestion popup. |
38
39
  | `types` | `types` | `string` | `"address"` | Mapbox `types` param, e.g. "address" or "address,poi". |
39
40
  | `endpoint` | `endpoint` | `string` | `"https://api.mapbox.com/search/geocode/v6/forward"` | Geocoding endpoint URL. Defaults to the Mapbox Geocoding v6 forward URL. |
40
41
  | `accessToken` | `access-token` | `string` | `""` | Mapbox access token. Required for requests to succeed. |
@@ -60,9 +61,13 @@ _None._
60
61
  | Custom property |
61
62
  | --- |
62
63
  | `--ui-border` |
64
+ | `--ui-focus-ring` |
63
65
  | `--ui-font` |
64
66
  | `--ui-font-size-sm` |
67
+ | `--ui-primary` |
65
68
  | `--ui-radius-sm` |
66
69
  | `--ui-shadow` |
67
70
  | `--ui-surface` |
68
71
  | `--ui-surface-muted` |
72
+ | `--ui-text` |
73
+ | `--ui-text-muted` |
@@ -49,6 +49,7 @@ import "@f-ewald/components/autocomplete-input.js";
49
49
  | `value` | `value` | `string` | `""` | Current input value; also the form-associated value submitted with the form. |
50
50
  | `placeholder` | `placeholder` | `string` | `""` | Placeholder text shown when the input is empty. |
51
51
  | `required` | `required` | `boolean` | `false` | Marks the input as required for native form validation. |
52
+ | `disabled` | `disabled` | `boolean` | `false` | Disables the input and closes its suggestion popup. |
52
53
  | `endpoint` | `endpoint` | `string` | `""` | API endpoint queried in API mode. Ignored when `options` is set. |
53
54
  | `queryParam` | `query-param` | `string` | `"q"` | Query string parameter name the current input text is sent under. |
54
55
  | `debounce` | `debounce` | `number` | `300` | Debounce delay (ms) before firing a request/filter after typing. |
@@ -71,9 +72,13 @@ _None._
71
72
  | Custom property |
72
73
  | --- |
73
74
  | `--ui-border` |
75
+ | `--ui-focus-ring` |
74
76
  | `--ui-font` |
75
77
  | `--ui-font-size-sm` |
78
+ | `--ui-primary` |
76
79
  | `--ui-radius-sm` |
77
80
  | `--ui-shadow` |
78
81
  | `--ui-surface` |
79
82
  | `--ui-surface-muted` |
83
+ | `--ui-text` |
84
+ | `--ui-text-muted` |
@@ -0,0 +1,53 @@
1
+ # `<calendar-entry>`
2
+
3
+ Declarative metadata for one calendar event, consumed by a parent
4
+ `calendar-month` or `calendar-year`. Read-only/non-interactive; renders
5
+ nothing itself.
6
+
7
+ ## Install
8
+
9
+ ```js
10
+ import "@f-ewald/components/calendar-entry.js";
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```html
16
+ <calendar-entry
17
+ start="2026-07-10"
18
+ end="2026-07-18"
19
+ label="Vacation"
20
+ color="success"
21
+ >
22
+ <span slot="title">Vacation</span>
23
+ <span slot="detail">Out of office</span>
24
+ <span slot="detail">Road trip along the California coast with several scenic stops</span>
25
+ <span slot="footer">Return July 19 at 6 PM</span>
26
+ </calendar-entry>
27
+ ```
28
+
29
+ ## Attributes / properties
30
+
31
+ | Property | Attribute | Type | Default | Description |
32
+ | --- | --- | --- | --- | --- |
33
+ | `start` | `start` | `string` | `""` | Inclusive start date, `"YYYY-MM-DD"`. |
34
+ | `end` | `end` | `string` | `""` | Inclusive end date, `"YYYY-MM-DD"`. Falls back to `start` when unset (single-day entry). |
35
+ | `label` | `label` | `string` | `""` | Fallback title used when no `title` slot is provided. |
36
+ | `color` | `color` | `StatusPillColor` | `"neutral"` | Color variant, reusing `status-pill`'s palette. |
37
+ | `href` | `href` | `string | undefined` | `—` | Optional link target; the parent renders the entry as an `<a>` when set. |
38
+
39
+ ## Events
40
+
41
+ _None._
42
+
43
+ ## Slots
44
+
45
+ | Slot | Description |
46
+ | --- | --- |
47
+ | `title` | Plain-text title shown instead of the `label` fallback. |
48
+ | `detail` | Repeatable plain-text details rendered inside the shared body spanning all remaining days. |
49
+ | `footer` | Plain-text ending note pinned to the bottom of the shared body. |
50
+
51
+ ## CSS custom properties
52
+
53
+ _None._
@@ -0,0 +1,79 @@
1
+ # `<calendar-month>`
2
+
3
+ One month rendered as a top-to-bottom list of days — weekends and today
4
+ highlighted, with declarative `calendar-entry` children shown as colored
5
+ bars spanning the days they cover. An entry's title uses its first visible
6
+ day; every remaining visible day becomes one shared body for wrapped
7
+ details and an optional ending footer. Overlapping entries stack into
8
+ side-by-side lanes rather than being layered/hidden. Read-only.
9
+
10
+ Lanes are computed independently per instance, from only the entries
11
+ overlapping this month — an entry spanning a month boundary may therefore
12
+ land in a different lane index in the adjacent month's `calendar-month`.
13
+ This is an accepted v1 limitation: cross-month lane continuity would
14
+ require a shared parent (`calendar-year`) to assign lanes globally.
15
+
16
+ Entry attributes and slotted title/detail text are observed, so a
17
+ standalone month re-renders when consumers update declarative metadata.
18
+
19
+ ## Install
20
+
21
+ ```js
22
+ import "@f-ewald/components/calendar-month.js";
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```html
28
+ <calendar-month year="2026" month="7">
29
+ <calendar-entry start="2026-07-10" end="2026-07-18" label="Vacation" color="success">
30
+ <span slot="title">Vacation</span>
31
+ <span slot="detail">Out of office</span>
32
+ <span slot="detail">Road trip along the California coast with several scenic stops</span>
33
+ <span slot="footer">Return July 19 at 6 PM</span>
34
+ </calendar-entry>
35
+ <calendar-entry start="2026-07-15" end="2026-07-20" label="Conference" color="warning" href="#conf">
36
+ <span slot="detail">Talks and workshops</span>
37
+ <span slot="footer">Closing keynote · July 20</span>
38
+ </calendar-entry>
39
+ </calendar-month>
40
+ ```
41
+
42
+ ## Attributes / properties
43
+
44
+ | Property | Attribute | Type | Default | Description |
45
+ | --- | --- | --- | --- | --- |
46
+ | `year` | `year` | `number` | `—` | Calendar year, e.g. `2026`. |
47
+ | `month` | `month` | `number` | `1` | Calendar month, 1-12 (January = 1). |
48
+
49
+ ## Events
50
+
51
+ _None._
52
+
53
+ ## Slots
54
+
55
+ | Slot | Description |
56
+ | --- | --- |
57
+ | `(default)` | Declarative `calendar-entry` elements to render for this month. |
58
+
59
+ ## CSS custom properties
60
+
61
+ | Custom property |
62
+ | --- |
63
+ | `--ui-border` |
64
+ | `--ui-danger` |
65
+ | `--ui-focus-ring` |
66
+ | `--ui-font` |
67
+ | `--ui-font-size` |
68
+ | `--ui-font-size-sm` |
69
+ | `--ui-font-size-xs` |
70
+ | `--ui-hover-overlay` |
71
+ | `--ui-info` |
72
+ | `--ui-primary` |
73
+ | `--ui-radius-sm` |
74
+ | `--ui-success` |
75
+ | `--ui-surface` |
76
+ | `--ui-surface-muted` |
77
+ | `--ui-text` |
78
+ | `--ui-text-muted` |
79
+ | `--ui-warning` |
@@ -0,0 +1,53 @@
1
+ # `<calendar-year>`
2
+
3
+ A full year of `calendar-month` blocks, generated from declarative
4
+ `calendar-entry` children. Each entry is re-projected into the
5
+ `calendar-month` blocks it overlaps as a freshly-created `calendar-entry`
6
+ element — the original elements stay slotted here and are never moved,
7
+ since a DOM node can only have one parent. Read-only.
8
+
9
+ ## Install
10
+
11
+ ```js
12
+ import "@f-ewald/components/calendar-year.js";
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```html
18
+ <calendar-year year="2026">
19
+ <calendar-entry start="2026-01-28" end="2026-02-03" label="Offsite" color="primary" href="#offsite">
20
+ <span slot="detail">New York</span>
21
+ <span slot="detail">Team workshops</span>
22
+ <span slot="footer">Closing dinner Friday</span>
23
+ </calendar-entry>
24
+ <calendar-entry start="2026-03-05" end="2026-03-18" label="Product launch" color="success" href="#launch">
25
+ <span slot="detail">Coordinate the release across engineering, design, support, and marketing.</span>
26
+ <span slot="detail">Monitor adoption and production health throughout the rollout.</span>
27
+ <span slot="footer">Public launch · March 18 at 9 AM</span>
28
+ </calendar-entry>
29
+ <calendar-entry start="2026-07-10" end="2026-07-18" label="Vacation" color="success"></calendar-entry>
30
+ </calendar-year>
31
+ ```
32
+
33
+ ## Attributes / properties
34
+
35
+ | Property | Attribute | Type | Default | Description |
36
+ | --- | --- | --- | --- | --- |
37
+ | `year` | `year` | `number` | `—` | Calendar year to render all 12 months for, e.g. `2026`. |
38
+
39
+ ## Events
40
+
41
+ _None._
42
+
43
+ ## Slots
44
+
45
+ | Slot | Description |
46
+ | --- | --- |
47
+ | `(default)` | Declarative `calendar-entry` elements spanning the displayed year, re-projected into each month. |
48
+
49
+ ## CSS custom properties
50
+
51
+ | Custom property |
52
+ | --- |
53
+ | `--ui-font` |
@@ -50,10 +50,14 @@ _None._
50
50
  | Custom property |
51
51
  | --- |
52
52
  | `--ui-border` |
53
+ | `--ui-focus-ring` |
53
54
  | `--ui-font` |
55
+ | `--ui-font-mono` |
54
56
  | `--ui-font-size` |
57
+ | `--ui-font-size-sm` |
55
58
  | `--ui-primary` |
56
59
  | `--ui-radius` |
60
+ | `--ui-radius-sm` |
57
61
  | `--ui-surface` |
58
62
  | `--ui-text` |
59
63
  | `--ui-text-muted` |
@@ -51,9 +51,11 @@ import "@f-ewald/components/confirm-dialog.js";
51
51
  | `--ui-border` |
52
52
  | `--ui-danger` |
53
53
  | `--ui-danger-hover` |
54
+ | `--ui-focus-ring` |
54
55
  | `--ui-font` |
55
56
  | `--ui-font-size` |
56
57
  | `--ui-font-size-sm` |
58
+ | `--ui-on-accent` |
57
59
  | `--ui-overlay` |
58
60
  | `--ui-primary` |
59
61
  | `--ui-primary-hover` |
@@ -24,6 +24,7 @@ import "@f-ewald/components/copy-link-button.js";
24
24
  | --- | --- | --- | --- | --- |
25
25
  | `value` | `value` | `string` | `""` | Text to copy. Defaults to `window.location.href` at click time. |
26
26
  | `label` | `label` | `string` | `"Copy link"` | Accessible label / tooltip text. |
27
+ | `disabled` | `disabled` | `boolean` | `false` | Disables clipboard copying. |
27
28
 
28
29
  ## Events
29
30
 
@@ -40,6 +41,7 @@ _None._
40
41
 
41
42
  | Custom property |
42
43
  | --- |
44
+ | `--ui-focus-ring` |
43
45
  | `--ui-radius-sm` |
44
46
  | `--ui-surface-muted` |
45
47
  | `--ui-text` |
@@ -42,6 +42,7 @@ import "@f-ewald/components/data-table.js";
42
42
  | `rowKey` | _(JS property only)_ | `(row: unknown, index: number) => string | number` | `—` | Stable identity for `rows[i]`, used as the repeat-directive key. Defaults to the row's index. |
43
43
  | `renderCell` | _(JS property only)_ | `(row: unknown, key: string) => unknown` | `—` | Produces a cell's rendered content for `row`/`column.key`. Default: `row[key]`. |
44
44
  | `rowHref` | _(JS property only)_ | `((row: unknown) => string | null) | null` | `null` | When set, clicking a row (outside any nested link/button) navigates to this hash. |
45
+ | `rowLabel` | _(JS property only)_ | `((row: unknown) => string) | null` | `null` | Accessible label for a row's keyboard link; defaults to primitive cell values. |
45
46
 
46
47
  ## Events
47
48
 
@@ -56,6 +57,7 @@ _None._
56
57
  | Custom property |
57
58
  | --- |
58
59
  | `--ui-border` |
60
+ | `--ui-focus-ring` |
59
61
  | `--ui-font` |
60
62
  | `--ui-font-size-sm` |
61
63
  | `--ui-surface-muted` |