@f-ewald/components 1.12.0 → 1.14.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 (62) hide show
  1. package/README.md +6 -0
  2. package/custom-elements.json +1376 -49
  3. package/dist/auto-scroll.d.ts +37 -0
  4. package/dist/auto-scroll.d.ts.map +1 -0
  5. package/dist/auto-scroll.js +100 -0
  6. package/dist/auto-scroll.js.map +1 -0
  7. package/dist/form-field.d.ts +39 -0
  8. package/dist/form-field.d.ts.map +1 -0
  9. package/dist/form-field.js +145 -0
  10. package/dist/form-field.js.map +1 -0
  11. package/dist/icons.d.ts +1 -0
  12. package/dist/icons.d.ts.map +1 -1
  13. package/dist/icons.js +1 -0
  14. package/dist/icons.js.map +1 -1
  15. package/dist/index.d.ts +6 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +6 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/load-more.d.ts +33 -0
  20. package/dist/load-more.d.ts.map +1 -0
  21. package/dist/load-more.js +82 -0
  22. package/dist/load-more.js.map +1 -0
  23. package/dist/map-circle.d.ts +12 -9
  24. package/dist/map-circle.d.ts.map +1 -1
  25. package/dist/map-circle.js +26 -12
  26. package/dist/map-circle.js.map +1 -1
  27. package/dist/map-pin.d.ts +7 -5
  28. package/dist/map-pin.d.ts.map +1 -1
  29. package/dist/map-pin.js +14 -8
  30. package/dist/map-pin.js.map +1 -1
  31. package/dist/percent-bar-chart.d.ts +32 -3
  32. package/dist/percent-bar-chart.d.ts.map +1 -1
  33. package/dist/percent-bar-chart.js +101 -36
  34. package/dist/percent-bar-chart.js.map +1 -1
  35. package/dist/scroll-to-bottom.d.ts +41 -0
  36. package/dist/scroll-to-bottom.d.ts.map +1 -0
  37. package/dist/scroll-to-bottom.js +189 -0
  38. package/dist/scroll-to-bottom.js.map +1 -0
  39. package/dist/scroll-to-top.d.ts +41 -0
  40. package/dist/scroll-to-top.d.ts.map +1 -0
  41. package/dist/scroll-to-top.js +189 -0
  42. package/dist/scroll-to-top.js.map +1 -0
  43. package/dist/ui-checkbox.d.ts +49 -0
  44. package/dist/ui-checkbox.d.ts.map +1 -0
  45. package/dist/ui-checkbox.js +228 -0
  46. package/dist/ui-checkbox.js.map +1 -0
  47. package/dist/utils/scroll.d.ts +9 -0
  48. package/dist/utils/scroll.d.ts.map +1 -0
  49. package/dist/utils/scroll.js +30 -0
  50. package/dist/utils/scroll.js.map +1 -0
  51. package/docs/auto-scroll.md +52 -0
  52. package/docs/form-field.md +63 -0
  53. package/docs/layouts/form-page.md +8 -4
  54. package/docs/load-more.md +43 -0
  55. package/docs/map-circle.md +11 -9
  56. package/docs/map-pin.md +6 -5
  57. package/docs/percent-bar-chart.md +19 -5
  58. package/docs/scroll-to-bottom.md +68 -0
  59. package/docs/scroll-to-top.md +59 -0
  60. package/docs/ui-checkbox.md +58 -0
  61. package/llms.txt +199 -20
  62. package/package.json +1 -1
@@ -9,14 +9,25 @@ import { customElement, property, state } from "lit/decorators.js";
9
9
  import { styleMap } from "lit/directives/style-map.js";
10
10
  import { scaleLinear } from "d3-scale";
11
11
  import { tokens } from "./tokens.js";
12
+ // Horizontal (row) layout.
12
13
  const ROW_H = 20;
13
14
  const LABEL_W = 56;
14
- const PCT_W = 36;
15
+ const VALUE_W = 36;
16
+ // Vertical (column) layout.
17
+ const COL_TRACK_H = 96;
18
+ const CAT_LABEL_H = 16;
19
+ const VALUE_LABEL_H = 14;
20
+ const MAX_BAR_W = 28;
21
+ const COL_GAP = 8;
15
22
  const PAD = { top: 4, right: 4, bottom: 4, left: 4 };
16
23
  let gradientIdCounter = 0;
17
24
  /**
18
- * Horizontal bar chart for labeled percentage rows, using D3's linear scale.
19
- * Each group gets its own labeled row; bars are proportional to percentage of 100.
25
+ * Bar chart for labeled rows, using D3's linear scale. Horizontal (default)
26
+ * renders stacked rows with bars growing rightward; `orientation="vertical"`
27
+ * renders side-by-side columns growing upward instead. `mode="percent"`
28
+ * (default) scales `value` against a fixed 0-100 domain and labels it with a
29
+ * `%` suffix; `mode="value"` scales it against `max` (or the largest `value`
30
+ * present) and formats it with `valueFormat`.
20
31
  *
21
32
  * @element percent-bar-chart
22
33
  */
@@ -25,6 +36,12 @@ let PercentBarChart = class PercentBarChart extends LitElement {
25
36
  super(...arguments);
26
37
  /** Rows to render, one per group. */
27
38
  this.groups = [];
39
+ /** Whether `value` is a 0-100 percentage (fixed domain) or an arbitrary number (domain from data/`max`). */
40
+ this.mode = "percent";
41
+ /** Bar direction: stacked rows growing rightward, or columns growing upward. */
42
+ this.orientation = "horizontal";
43
+ /** Formats a row's value for its label in `mode="value"`. Defaults to locale-formatted number. */
44
+ this.valueFormat = (value) => value.toLocaleString();
28
45
  this._width = 0;
29
46
  this._ro = null;
30
47
  this._gradIdBase = `percent-bar-grad-${gradientIdCounter++}`;
@@ -65,6 +82,18 @@ let PercentBarChart = class PercentBarChart extends LitElement {
65
82
  _gradId(index) {
66
83
  return `${this._gradIdBase}-${index}`;
67
84
  }
85
+ /** The row's value formatted for display, per the current `mode`. */
86
+ _labelFor(value) {
87
+ return this.mode === "percent" ? `${value.toFixed(1)}%` : this.valueFormat(value);
88
+ }
89
+ /** The scale domain's upper bound for the current `mode`. */
90
+ _domainMax() {
91
+ if (this.mode === "percent")
92
+ return 100;
93
+ if (this.max !== undefined)
94
+ return this.max;
95
+ return Math.max(0.000001, ...this.groups.map((g) => g.value));
96
+ }
68
97
  firstUpdated() {
69
98
  this._ro = new ResizeObserver((entries) => {
70
99
  const w = Math.floor(entries[0].contentRect.width);
@@ -78,59 +107,83 @@ let PercentBarChart = class PercentBarChart extends LitElement {
78
107
  this._ro?.disconnect();
79
108
  this._ro = null;
80
109
  }
81
- render() {
82
- if (this._width === 0 || this.groups.length === 0)
83
- return html ``;
84
- const innerW = this._width - PAD.left - PAD.right;
85
- const barMaxW = innerW - LABEL_W - PCT_W;
86
- const svgH = PAD.top + this.groups.length * ROW_H + PAD.bottom;
87
- const xScale = scaleLinear().domain([0, 100]).range([0, barMaxW]);
88
- // CSS stop styles preserve every valid CSS color format while matching
89
- // map-circle's 30% white/black vertical depth.
90
- const rowFills = this.groups.map((g, i) => {
110
+ _renderGradients() {
111
+ return this.groups.map((g, i) => {
91
112
  const color = g.color.trim();
92
113
  const gradId = this._gradId(i);
93
- return {
94
- fill: `url(#${gradId})`,
95
- gradient: svg `
96
- <linearGradient
97
- id=${gradId}
98
- x1="0"
99
- y1="0"
100
- x2="0"
101
- y2="1"
102
- style=${styleMap({ "--percent-bar-color": color })}
103
- >
104
- <stop class="gradient-start" offset="0%" />
105
- <stop class="gradient-end" offset="100%" />
106
- </linearGradient>
107
- `,
108
- };
114
+ return svg `
115
+ <linearGradient
116
+ id=${gradId}
117
+ x1="0"
118
+ y1="0"
119
+ x2="0"
120
+ y2="1"
121
+ style=${styleMap({ "--percent-bar-color": color })}
122
+ >
123
+ <stop class="gradient-start" offset="0%" />
124
+ <stop class="gradient-end" offset="100%" />
125
+ </linearGradient>
126
+ `;
109
127
  });
110
- const gradients = rowFills.map((row) => row.gradient);
128
+ }
129
+ _renderHorizontal() {
130
+ const innerW = this._width - PAD.left - PAD.right;
131
+ const barMaxW = innerW - LABEL_W - VALUE_W;
132
+ const svgH = PAD.top + this.groups.length * ROW_H + PAD.bottom;
133
+ const xScale = scaleLinear().domain([0, this._domainMax()]).range([0, barMaxW]);
111
134
  const rows = this.groups.map((g, i) => {
112
135
  const cy = PAD.top + i * ROW_H + ROW_H / 2;
113
- const bw = Math.max(0, xScale(g.pct));
136
+ const bw = Math.max(0, xScale(g.value));
114
137
  return svg `
115
138
  <text class="chart-label" x=${PAD.left} y=${cy} font-size="10"
116
139
  text-anchor="start" dominant-baseline="middle">${g.label}</text>
117
140
  <rect x=${PAD.left + LABEL_W} y=${cy - 5}
118
141
  width=${bw} height="10" rx="5"
119
- fill=${rowFills[i].fill} />
142
+ fill="url(#${this._gradId(i)})" />
120
143
  <text class="chart-label" x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size="10"
121
- text-anchor="start" dominant-baseline="middle">${g.pct.toFixed(1)}%</text>
144
+ text-anchor="start" dominant-baseline="middle">${this._labelFor(g.value)}</text>
145
+ `;
146
+ });
147
+ return { svgH, content: rows };
148
+ }
149
+ _renderVertical() {
150
+ const innerW = this._width - PAD.left - PAD.right;
151
+ const n = this.groups.length;
152
+ const colSlotW = n > 0 ? innerW / n : 0;
153
+ const barW = Math.max(4, Math.min(MAX_BAR_W, colSlotW - COL_GAP));
154
+ const svgH = PAD.top + VALUE_LABEL_H + COL_TRACK_H + CAT_LABEL_H + PAD.bottom;
155
+ const yScale = scaleLinear().domain([0, this._domainMax()]).range([0, COL_TRACK_H]);
156
+ const cols = this.groups.map((g, i) => {
157
+ const cx = PAD.left + i * colSlotW + colSlotW / 2;
158
+ const barH = Math.max(0, yScale(g.value));
159
+ const barTop = PAD.top + VALUE_LABEL_H + (COL_TRACK_H - barH);
160
+ const catLabelY = PAD.top + VALUE_LABEL_H + COL_TRACK_H + CAT_LABEL_H - 4;
161
+ return svg `
162
+ <rect x=${cx - barW / 2} y=${barTop} width=${barW} height=${barH} rx=${barW / 2}
163
+ fill="url(#${this._gradId(i)})" />
164
+ <text class="chart-label" x=${cx} y=${barTop - 4} font-size="10"
165
+ text-anchor="middle">${this._labelFor(g.value)}</text>
166
+ <text class="chart-label" x=${cx} y=${catLabelY} font-size="10"
167
+ text-anchor="middle">${g.label}</text>
122
168
  `;
123
169
  });
170
+ return { svgH, content: cols };
171
+ }
172
+ render() {
173
+ if (this._width === 0 || this.groups.length === 0)
174
+ return html ``;
175
+ const { svgH, content } = this.orientation === "vertical" ? this._renderVertical() : this._renderHorizontal();
176
+ const ariaPrefix = this.mode === "percent" ? "Percentages" : "Values";
124
177
  return html `
125
178
  <svg
126
179
  viewBox="0 0 ${this._width} ${svgH}"
127
180
  width=${this._width}
128
181
  height=${svgH}
129
182
  role="img"
130
- aria-label=${`Percentages: ${this.groups.map((group) => `${group.label} ${group.pct.toFixed(1)}%`).join(", ")}`}
183
+ aria-label=${`${ariaPrefix}: ${this.groups.map((g) => `${g.label} ${this._labelFor(g.value)}`).join(", ")}`}
131
184
  >
132
- <defs>${gradients}</defs>
133
- ${rows}
185
+ <defs>${this._renderGradients()}</defs>
186
+ ${content}
134
187
  </svg>
135
188
  `;
136
189
  }
@@ -138,6 +191,18 @@ let PercentBarChart = class PercentBarChart extends LitElement {
138
191
  __decorate([
139
192
  property({ attribute: false })
140
193
  ], PercentBarChart.prototype, "groups", void 0);
194
+ __decorate([
195
+ property()
196
+ ], PercentBarChart.prototype, "mode", void 0);
197
+ __decorate([
198
+ property()
199
+ ], PercentBarChart.prototype, "orientation", void 0);
200
+ __decorate([
201
+ property({ type: Number })
202
+ ], PercentBarChart.prototype, "max", void 0);
203
+ __decorate([
204
+ property({ attribute: false })
205
+ ], PercentBarChart.prototype, "valueFormat", void 0);
141
206
  __decorate([
142
207
  state()
143
208
  ], PercentBarChart.prototype, "_width", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"percent-bar-chart.js","sourceRoot":"","sources":["../src/percent-bar-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, svg } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { scaleLinear } from \"d3-scale\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface PercentBarGroup {\n key: string;\n label: string;\n pct: number;\n color: string;\n}\n\nconst ROW_H = 20;\nconst LABEL_W = 56;\nconst PCT_W = 36;\nconst PAD = { top: 4, right: 4, bottom: 4, left: 4 };\n\nlet gradientIdCounter = 0;\n\n/**\n * Horizontal bar chart for labeled percentage rows, using D3's linear scale.\n * Each group gets its own labeled row; bars are proportional to percentage of 100.\n *\n * @element percent-bar-chart\n */\n@customElement(\"percent-bar-chart\")\nexport class PercentBarChart extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n width: 100%;\n }\n svg {\n display: block;\n overflow: visible;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n .chart-label {\n fill: var(--ui-text-muted, #64748b);\n }\n .gradient-start {\n stop-color: color-mix(in srgb, var(--percent-bar-color) 70%, #ffffff);\n }\n .gradient-end {\n stop-color: color-mix(in srgb, var(--percent-bar-color) 70%, #000000);\n }\n `,\n ];\n\n /** Rows to render, one per group. */\n @property({ attribute: false }) groups: PercentBarGroup[] = [];\n @state() private _width = 0;\n\n private _ro: ResizeObserver | null = null;\n private readonly _gradIdBase = `percent-bar-grad-${gradientIdCounter++}`;\n\n /** Per-row gradient id, unique across instances and rows. */\n private _gradId(index: number): string {\n return `${this._gradIdBase}-${index}`;\n }\n\n override firstUpdated() {\n this._ro = new ResizeObserver((entries) => {\n const w = Math.floor(entries[0].contentRect.width);\n if (w > 0 && w !== this._width) this._width = w;\n });\n this._ro.observe(this);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._ro?.disconnect();\n this._ro = null;\n }\n\n override render() {\n if (this._width === 0 || this.groups.length === 0) return html``;\n\n const innerW = this._width - PAD.left - PAD.right;\n const barMaxW = innerW - LABEL_W - PCT_W;\n const svgH = PAD.top + this.groups.length * ROW_H + PAD.bottom;\n\n const xScale = scaleLinear().domain([0, 100]).range([0, barMaxW]);\n\n // CSS stop styles preserve every valid CSS color format while matching\n // map-circle's 30% white/black vertical depth.\n const rowFills = this.groups.map((g, i) => {\n const color = g.color.trim();\n const gradId = this._gradId(i);\n return {\n fill: `url(#${gradId})`,\n gradient: svg`\n <linearGradient\n id=${gradId}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n style=${styleMap({ \"--percent-bar-color\": color })}\n >\n <stop class=\"gradient-start\" offset=\"0%\" />\n <stop class=\"gradient-end\" offset=\"100%\" />\n </linearGradient>\n `,\n };\n });\n const gradients = rowFills.map((row) => row.gradient);\n\n const rows = this.groups.map((g, i) => {\n const cy = PAD.top + i * ROW_H + ROW_H / 2;\n const bw = Math.max(0, xScale(g.pct));\n return svg`\n <text class=\"chart-label\" x=${PAD.left} y=${cy} font-size=\"10\"\n text-anchor=\"start\" dominant-baseline=\"middle\">${g.label}</text>\n <rect x=${PAD.left + LABEL_W} y=${cy - 5}\n width=${bw} height=\"10\" rx=\"5\"\n fill=${rowFills[i].fill} />\n <text class=\"chart-label\" x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size=\"10\"\n text-anchor=\"start\" dominant-baseline=\"middle\">${g.pct.toFixed(1)}%</text>\n `;\n });\n\n return html`\n <svg\n viewBox=\"0 0 ${this._width} ${svgH}\"\n width=${this._width}\n height=${svgH}\n role=\"img\"\n aria-label=${`Percentages: ${this.groups.map((group) => `${group.label} ${group.pct.toFixed(1)}%`).join(\", \")}`}\n >\n <defs>${gradients}</defs>\n ${rows}\n </svg>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"percent-bar-chart\": PercentBarChart;\n }\n}\n"]}
1
+ {"version":3,"file":"percent-bar-chart.js","sourceRoot":"","sources":["../src/percent-bar-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, svg } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { scaleLinear } from \"d3-scale\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface PercentBarGroup {\n key: string;\n label: string;\n /**\n * The row's value. In `mode=\"percent\"` (default) this is a 0-100\n * percentage, scaled against a fixed domain. In `mode=\"value\"` this is an\n * arbitrary raw number, scaled against `max` (or the largest `value`\n * across `groups` when `max` is unset).\n */\n value: number;\n color: string;\n}\n\n/** Whether `PercentBarGroup.value` is a 0-100 percentage or an arbitrary raw number. */\nexport type PercentBarMode = \"percent\" | \"value\";\n/** Bars grow rightward as stacked rows, or upward as side-by-side columns. */\nexport type PercentBarOrientation = \"horizontal\" | \"vertical\";\n\n// Horizontal (row) layout.\nconst ROW_H = 20;\nconst LABEL_W = 56;\nconst VALUE_W = 36;\n\n// Vertical (column) layout.\nconst COL_TRACK_H = 96;\nconst CAT_LABEL_H = 16;\nconst VALUE_LABEL_H = 14;\nconst MAX_BAR_W = 28;\nconst COL_GAP = 8;\n\nconst PAD = { top: 4, right: 4, bottom: 4, left: 4 };\n\nlet gradientIdCounter = 0;\n\n/**\n * Bar chart for labeled rows, using D3's linear scale. Horizontal (default)\n * renders stacked rows with bars growing rightward; `orientation=\"vertical\"`\n * renders side-by-side columns growing upward instead. `mode=\"percent\"`\n * (default) scales `value` against a fixed 0-100 domain and labels it with a\n * `%` suffix; `mode=\"value\"` scales it against `max` (or the largest `value`\n * present) and formats it with `valueFormat`.\n *\n * @element percent-bar-chart\n */\n@customElement(\"percent-bar-chart\")\nexport class PercentBarChart extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n width: 100%;\n }\n svg {\n display: block;\n overflow: visible;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n .chart-label {\n fill: var(--ui-text-muted, #64748b);\n }\n .gradient-start {\n stop-color: color-mix(in srgb, var(--percent-bar-color) 70%, #ffffff);\n }\n .gradient-end {\n stop-color: color-mix(in srgb, var(--percent-bar-color) 70%, #000000);\n }\n `,\n ];\n\n /** Rows to render, one per group. */\n @property({ attribute: false }) groups: PercentBarGroup[] = [];\n /** Whether `value` is a 0-100 percentage (fixed domain) or an arbitrary number (domain from data/`max`). */\n @property() mode: PercentBarMode = \"percent\";\n /** Bar direction: stacked rows growing rightward, or columns growing upward. */\n @property() orientation: PercentBarOrientation = \"horizontal\";\n /** Explicit domain max for `mode=\"value\"`; auto-computed from `groups` when unset. Ignored in `mode=\"percent\"`. */\n @property({ type: Number }) max?: number;\n /** Formats a row's value for its label in `mode=\"value\"`. Defaults to locale-formatted number. */\n @property({ attribute: false }) valueFormat: (value: number) => string = (value) =>\n value.toLocaleString();\n\n @state() private _width = 0;\n\n private _ro: ResizeObserver | null = null;\n private readonly _gradIdBase = `percent-bar-grad-${gradientIdCounter++}`;\n\n /** Per-row gradient id, unique across instances and rows. */\n private _gradId(index: number): string {\n return `${this._gradIdBase}-${index}`;\n }\n\n /** The row's value formatted for display, per the current `mode`. */\n private _labelFor(value: number): string {\n return this.mode === \"percent\" ? `${value.toFixed(1)}%` : this.valueFormat(value);\n }\n\n /** The scale domain's upper bound for the current `mode`. */\n private _domainMax(): number {\n if (this.mode === \"percent\") return 100;\n if (this.max !== undefined) return this.max;\n return Math.max(0.000001, ...this.groups.map((g) => g.value));\n }\n\n override firstUpdated() {\n this._ro = new ResizeObserver((entries) => {\n const w = Math.floor(entries[0].contentRect.width);\n if (w > 0 && w !== this._width) this._width = w;\n });\n this._ro.observe(this);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._ro?.disconnect();\n this._ro = null;\n }\n\n private _renderGradients() {\n return this.groups.map((g, i) => {\n const color = g.color.trim();\n const gradId = this._gradId(i);\n return svg`\n <linearGradient\n id=${gradId}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n style=${styleMap({ \"--percent-bar-color\": color })}\n >\n <stop class=\"gradient-start\" offset=\"0%\" />\n <stop class=\"gradient-end\" offset=\"100%\" />\n </linearGradient>\n `;\n });\n }\n\n private _renderHorizontal() {\n const innerW = this._width - PAD.left - PAD.right;\n const barMaxW = innerW - LABEL_W - VALUE_W;\n const svgH = PAD.top + this.groups.length * ROW_H + PAD.bottom;\n const xScale = scaleLinear().domain([0, this._domainMax()]).range([0, barMaxW]);\n\n const rows = this.groups.map((g, i) => {\n const cy = PAD.top + i * ROW_H + ROW_H / 2;\n const bw = Math.max(0, xScale(g.value));\n return svg`\n <text class=\"chart-label\" x=${PAD.left} y=${cy} font-size=\"10\"\n text-anchor=\"start\" dominant-baseline=\"middle\">${g.label}</text>\n <rect x=${PAD.left + LABEL_W} y=${cy - 5}\n width=${bw} height=\"10\" rx=\"5\"\n fill=\"url(#${this._gradId(i)})\" />\n <text class=\"chart-label\" x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size=\"10\"\n text-anchor=\"start\" dominant-baseline=\"middle\">${this._labelFor(g.value)}</text>\n `;\n });\n\n return { svgH, content: rows };\n }\n\n private _renderVertical() {\n const innerW = this._width - PAD.left - PAD.right;\n const n = this.groups.length;\n const colSlotW = n > 0 ? innerW / n : 0;\n const barW = Math.max(4, Math.min(MAX_BAR_W, colSlotW - COL_GAP));\n const svgH = PAD.top + VALUE_LABEL_H + COL_TRACK_H + CAT_LABEL_H + PAD.bottom;\n const yScale = scaleLinear().domain([0, this._domainMax()]).range([0, COL_TRACK_H]);\n\n const cols = this.groups.map((g, i) => {\n const cx = PAD.left + i * colSlotW + colSlotW / 2;\n const barH = Math.max(0, yScale(g.value));\n const barTop = PAD.top + VALUE_LABEL_H + (COL_TRACK_H - barH);\n const catLabelY = PAD.top + VALUE_LABEL_H + COL_TRACK_H + CAT_LABEL_H - 4;\n return svg`\n <rect x=${cx - barW / 2} y=${barTop} width=${barW} height=${barH} rx=${barW / 2}\n fill=\"url(#${this._gradId(i)})\" />\n <text class=\"chart-label\" x=${cx} y=${barTop - 4} font-size=\"10\"\n text-anchor=\"middle\">${this._labelFor(g.value)}</text>\n <text class=\"chart-label\" x=${cx} y=${catLabelY} font-size=\"10\"\n text-anchor=\"middle\">${g.label}</text>\n `;\n });\n\n return { svgH, content: cols };\n }\n\n override render() {\n if (this._width === 0 || this.groups.length === 0) return html``;\n\n const { svgH, content } =\n this.orientation === \"vertical\" ? this._renderVertical() : this._renderHorizontal();\n const ariaPrefix = this.mode === \"percent\" ? \"Percentages\" : \"Values\";\n\n return html`\n <svg\n viewBox=\"0 0 ${this._width} ${svgH}\"\n width=${this._width}\n height=${svgH}\n role=\"img\"\n aria-label=${`${ariaPrefix}: ${this.groups.map((g) => `${g.label} ${this._labelFor(g.value)}`).join(\", \")}`}\n >\n <defs>${this._renderGradients()}</defs>\n ${content}\n </svg>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"percent-bar-chart\": PercentBarChart;\n }\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { LitElement, type PropertyValues } from "lit";
2
+ /**
3
+ * Overlay button that appears once the page (or a given `target` container)
4
+ * has scrolled more than `threshold` pixels away from the bottom edge, and
5
+ * scrolls back to the bottom on click.
6
+ *
7
+ * With no `target` (default), the button is `position: fixed` to the
8
+ * viewport. When `target` is set, the button switches to `position:
9
+ * absolute` and expects to be placed as a descendant of a `position:
10
+ * relative` (or otherwise positioned) ancestor that establishes the visual
11
+ * bounds to float within — typically `target` itself, given `overflow-y:
12
+ * auto; position: relative`, so the button stays pinned to that container's
13
+ * own visible corner as its content scrolls, rather than floating over the
14
+ * whole page.
15
+ *
16
+ * @element scroll-to-bottom
17
+ * @fires scroll-to-bottom-triggered - The button was clicked, just before
18
+ * scrolling; detail: `{ target }`.
19
+ */
20
+ export declare class ScrollToBottom extends LitElement {
21
+ #private;
22
+ static styles: import("lit").CSSResult[];
23
+ /** Scrollable container to control; `null` (default) scrolls `window`. */
24
+ target: HTMLElement | null;
25
+ /** Pixels scrolled away from the bottom before the button appears. */
26
+ threshold: number;
27
+ /** Visible button text, and its accessible name. */
28
+ label: string;
29
+ private _visible;
30
+ connectedCallback(): void;
31
+ disconnectedCallback(): void;
32
+ protected willUpdate(changed: PropertyValues): void;
33
+ protected updated(changed: PropertyValues): void;
34
+ render(): import("lit-html").TemplateResult<1>;
35
+ }
36
+ declare global {
37
+ interface HTMLElementTagNameMap {
38
+ "scroll-to-bottom": ScrollToBottom;
39
+ }
40
+ }
41
+ //# sourceMappingURL=scroll-to-bottom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-to-bottom.d.ts","sourceRoot":"","sources":["../src/scroll-to-bottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAMjE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,cAAe,SAAQ,UAAU;;IAC5C,OAAgB,MAAM,4BA6EpB;IAEF,0EAA0E;IAC1C,MAAM,EAAE,WAAW,GAAG,IAAI,CAAQ;IAClE,sEAAsE;IAC1C,SAAS,SAAO;IAC5C,oDAAoD;IACxC,KAAK,SAAsB;IAE9B,OAAO,CAAC,QAAQ,CAAS;IAIzB,iBAAiB,IAAI,IAAI,CAGjC;IAEQ,oBAAoB,IAAI,IAAI,CAGpC;IAED,UAAmB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAU3D;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAExD;IA0BQ,MAAM,yCAOd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
@@ -0,0 +1,189 @@
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, state } from "lit/decorators.js";
9
+ import { iconChevronDown } from "./icons.js";
10
+ import { distanceFromBottom, scrollToEdge } from "./utils/scroll.js";
11
+ import { tokens } from "./tokens.js";
12
+ /**
13
+ * Overlay button that appears once the page (or a given `target` container)
14
+ * has scrolled more than `threshold` pixels away from the bottom edge, and
15
+ * scrolls back to the bottom on click.
16
+ *
17
+ * With no `target` (default), the button is `position: fixed` to the
18
+ * viewport. When `target` is set, the button switches to `position:
19
+ * absolute` and expects to be placed as a descendant of a `position:
20
+ * relative` (or otherwise positioned) ancestor that establishes the visual
21
+ * bounds to float within — typically `target` itself, given `overflow-y:
22
+ * auto; position: relative`, so the button stays pinned to that container's
23
+ * own visible corner as its content scrolls, rather than floating over the
24
+ * whole page.
25
+ *
26
+ * @element scroll-to-bottom
27
+ * @fires scroll-to-bottom-triggered - The button was clicked, just before
28
+ * scrolling; detail: `{ target }`.
29
+ */
30
+ let ScrollToBottom = class ScrollToBottom extends LitElement {
31
+ constructor() {
32
+ super(...arguments);
33
+ /** Scrollable container to control; `null` (default) scrolls `window`. */
34
+ this.target = null;
35
+ /** Pixels scrolled away from the bottom before the button appears. */
36
+ this.threshold = 200;
37
+ /** Visible button text, and its accessible name. */
38
+ this.label = "Scroll to bottom";
39
+ this._visible = false;
40
+ this.#listenedTo = null;
41
+ this.#onScroll = () => {
42
+ this._visible = distanceFromBottom(this.target ?? window) > this.threshold;
43
+ };
44
+ }
45
+ static { this.styles = [
46
+ tokens,
47
+ css `
48
+ :host {
49
+ position: fixed;
50
+ bottom: 0.75rem;
51
+ right: 0.75rem;
52
+ z-index: 40;
53
+ pointer-events: none;
54
+ opacity: 0;
55
+ visibility: hidden;
56
+ transition:
57
+ opacity 150ms ease,
58
+ visibility 0s linear 150ms;
59
+ }
60
+ :host([contained]) {
61
+ position: absolute;
62
+ }
63
+ :host([visible]) {
64
+ opacity: 1;
65
+ visibility: visible;
66
+ transition:
67
+ opacity 150ms ease,
68
+ visibility 0s linear 0s;
69
+ }
70
+ button {
71
+ pointer-events: auto;
72
+ display: inline-flex;
73
+ align-items: center;
74
+ gap: 0.25rem;
75
+ height: 2rem;
76
+ box-sizing: border-box;
77
+ padding: 0 0.75rem;
78
+ color: var(--ui-text, #0f172a);
79
+ background: var(--ui-surface, #ffffff);
80
+ border: 1px solid var(--ui-border, #e2e8f0);
81
+ border-radius: 999px;
82
+ box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));
83
+ cursor: pointer;
84
+ font-family: var(
85
+ --ui-font,
86
+ ui-sans-serif,
87
+ system-ui,
88
+ sans-serif,
89
+ "Apple Color Emoji",
90
+ "Segoe UI Emoji",
91
+ "Segoe UI Symbol",
92
+ "Noto Color Emoji"
93
+ );
94
+ font-size: var(--ui-font-size-sm, 0.75rem);
95
+ font-weight: var(--ui-font-weight-medium, 500);
96
+ line-height: var(--ui-line-height-tight, 1.25);
97
+ white-space: nowrap;
98
+ }
99
+ button:hover {
100
+ background: var(--ui-surface-muted, #f8fafc);
101
+ }
102
+ button:focus-visible {
103
+ outline: none;
104
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
105
+ }
106
+ @media (prefers-reduced-motion: reduce) {
107
+ :host {
108
+ transition: none;
109
+ }
110
+ :host([visible]) {
111
+ transition: none;
112
+ }
113
+ }
114
+ @media (forced-colors: active) {
115
+ button:focus-visible {
116
+ outline: 2px solid CanvasText;
117
+ outline-offset: 2px;
118
+ box-shadow: none;
119
+ }
120
+ }
121
+ `,
122
+ ]; }
123
+ #listenedTo;
124
+ connectedCallback() {
125
+ super.connectedCallback();
126
+ this.#subscribe();
127
+ }
128
+ disconnectedCallback() {
129
+ super.disconnectedCallback();
130
+ this.#unsubscribe();
131
+ }
132
+ willUpdate(changed) {
133
+ if (changed.has("target")) {
134
+ this.toggleAttribute("contained", this.target !== null);
135
+ // Resubscribing here (not in `updated()`) lets `#onScroll()`'s
136
+ // `_visible` write fold into the update already in progress instead of
137
+ // scheduling a new one. Guarded against the initial update, where
138
+ // `target` is always in `changed` too, but `connectedCallback` already
139
+ // subscribed to it.
140
+ if (this.#listenedTo !== (this.target ?? window))
141
+ this.#subscribe();
142
+ }
143
+ }
144
+ updated(changed) {
145
+ if (changed.has("_visible"))
146
+ this.toggleAttribute("visible", this._visible);
147
+ }
148
+ #subscribe() {
149
+ this.#unsubscribe();
150
+ this.#listenedTo = this.target ?? window;
151
+ this.#listenedTo.addEventListener("scroll", this.#onScroll, { passive: true });
152
+ this.#onScroll();
153
+ }
154
+ #unsubscribe() {
155
+ this.#listenedTo?.removeEventListener("scroll", this.#onScroll);
156
+ this.#listenedTo = null;
157
+ }
158
+ #onScroll;
159
+ #onClick() {
160
+ const target = this.target ?? window;
161
+ this.dispatchEvent(new CustomEvent("scroll-to-bottom-triggered", { detail: { target }, bubbles: true, composed: true }));
162
+ scrollToEdge(target, "bottom");
163
+ }
164
+ render() {
165
+ return html `
166
+ <button type="button" @click=${() => this.#onClick()}>
167
+ ${iconChevronDown(14)}
168
+ <span>${this.label}</span>
169
+ </button>
170
+ `;
171
+ }
172
+ };
173
+ __decorate([
174
+ property({ attribute: false })
175
+ ], ScrollToBottom.prototype, "target", void 0);
176
+ __decorate([
177
+ property({ type: Number })
178
+ ], ScrollToBottom.prototype, "threshold", void 0);
179
+ __decorate([
180
+ property()
181
+ ], ScrollToBottom.prototype, "label", void 0);
182
+ __decorate([
183
+ state()
184
+ ], ScrollToBottom.prototype, "_visible", void 0);
185
+ ScrollToBottom = __decorate([
186
+ customElement("scroll-to-bottom")
187
+ ], ScrollToBottom);
188
+ export { ScrollToBottom };
189
+ //# sourceMappingURL=scroll-to-bottom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-to-bottom.js","sourceRoot":"","sources":["../src/scroll-to-bottom.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AAEI,IAAM,cAAc,GAApB,MAAM,cAAe,SAAQ,UAAU;IAAvC;;QAgFL,0EAA0E;QAC1C,WAAM,GAAuB,IAAI,CAAC;QAClE,sEAAsE;QAC1C,cAAS,GAAG,GAAG,CAAC;QAC5C,oDAAoD;QACxC,UAAK,GAAG,kBAAkB,CAAC;QAEtB,aAAQ,GAAG,KAAK,CAAC;QAElC,gBAAW,GAAgC,IAAI,CAAC;QAwChD,cAAS,GAAG,GAAS,EAAE;YACrB,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7E,CAAC,CAAC;IAkBJ,CAAC;aApJiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0EF;KACF,AA7EqB,CA6EpB;IAWF,WAAW,CAAqC;IAEvC,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEQ,oBAAoB;QAC3B,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAEkB,UAAU,CAAC,OAAuB;QACnD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;YACxD,+DAA+D;YAC/D,uEAAuE;YACvE,kEAAkE;YAClE,uEAAuE;YACvE,oBAAoB;YACpB,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;gBAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACtE,CAAC;IACH,CAAC;IAEkB,OAAO,CAAC,OAAuB;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9E,CAAC;IAED,UAAU;QACR,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;QACzC,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,YAAY;QACV,IAAI,CAAC,WAAW,EAAE,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAChE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,SAAS,CAEP;IAEF,QAAQ;QACN,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;QACrC,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,4BAA4B,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CACrG,CAAC;QACF,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;qCACsB,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE;UAChD,eAAe,CAAC,EAAE,CAAC;gBACb,IAAI,CAAC,KAAK;;KAErB,CAAC;IACJ,CAAC;CACF,CAAA;AApEiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;8CAAmC;AAEtC;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;iDAAiB;AAEhC;IAAX,QAAQ,EAAE;6CAA4B;AAEtB;IAAhB,KAAK,EAAE;gDAA0B;AAvFvB,cAAc;IAD1B,aAAa,CAAC,kBAAkB,CAAC;GACrB,cAAc,CAqJ1B","sourcesContent":["import { LitElement, css, html, type PropertyValues } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { iconChevronDown } from \"./icons.js\";\nimport { distanceFromBottom, scrollToEdge } from \"./utils/scroll.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Overlay button that appears once the page (or a given `target` container)\n * has scrolled more than `threshold` pixels away from the bottom edge, and\n * scrolls back to the bottom on click.\n *\n * With no `target` (default), the button is `position: fixed` to the\n * viewport. When `target` is set, the button switches to `position:\n * absolute` and expects to be placed as a descendant of a `position:\n * relative` (or otherwise positioned) ancestor that establishes the visual\n * bounds to float within — typically `target` itself, given `overflow-y:\n * auto; position: relative`, so the button stays pinned to that container's\n * own visible corner as its content scrolls, rather than floating over the\n * whole page.\n *\n * @element scroll-to-bottom\n * @fires scroll-to-bottom-triggered - The button was clicked, just before\n * scrolling; detail: `{ target }`.\n */\n@customElement(\"scroll-to-bottom\")\nexport class ScrollToBottom extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n position: fixed;\n bottom: 0.75rem;\n right: 0.75rem;\n z-index: 40;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition:\n opacity 150ms ease,\n visibility 0s linear 150ms;\n }\n :host([contained]) {\n position: absolute;\n }\n :host([visible]) {\n opacity: 1;\n visibility: visible;\n transition:\n opacity 150ms ease,\n visibility 0s linear 0s;\n }\n button {\n pointer-events: auto;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n height: 2rem;\n box-sizing: border-box;\n padding: 0 0.75rem;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: 999px;\n box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));\n cursor: pointer;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n white-space: nowrap;\n }\n button:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n button:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @media (prefers-reduced-motion: reduce) {\n :host {\n transition: none;\n }\n :host([visible]) {\n transition: none;\n }\n }\n @media (forced-colors: active) {\n button:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n /** Scrollable container to control; `null` (default) scrolls `window`. */\n @property({ attribute: false }) target: HTMLElement | null = null;\n /** Pixels scrolled away from the bottom before the button appears. */\n @property({ type: Number }) threshold = 200;\n /** Visible button text, and its accessible name. */\n @property() label = \"Scroll to bottom\";\n\n @state() private _visible = false;\n\n #listenedTo: HTMLElement | Window | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.#subscribe();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#unsubscribe();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n if (changed.has(\"target\")) {\n this.toggleAttribute(\"contained\", this.target !== null);\n // Resubscribing here (not in `updated()`) lets `#onScroll()`'s\n // `_visible` write fold into the update already in progress instead of\n // scheduling a new one. Guarded against the initial update, where\n // `target` is always in `changed` too, but `connectedCallback` already\n // subscribed to it.\n if (this.#listenedTo !== (this.target ?? window)) this.#subscribe();\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"_visible\")) this.toggleAttribute(\"visible\", this._visible);\n }\n\n #subscribe(): void {\n this.#unsubscribe();\n this.#listenedTo = this.target ?? window;\n this.#listenedTo.addEventListener(\"scroll\", this.#onScroll, { passive: true });\n this.#onScroll();\n }\n\n #unsubscribe(): void {\n this.#listenedTo?.removeEventListener(\"scroll\", this.#onScroll);\n this.#listenedTo = null;\n }\n\n #onScroll = (): void => {\n this._visible = distanceFromBottom(this.target ?? window) > this.threshold;\n };\n\n #onClick(): void {\n const target = this.target ?? window;\n this.dispatchEvent(\n new CustomEvent(\"scroll-to-bottom-triggered\", { detail: { target }, bubbles: true, composed: true }),\n );\n scrollToEdge(target, \"bottom\");\n }\n\n override render() {\n return html`\n <button type=\"button\" @click=${() => this.#onClick()}>\n ${iconChevronDown(14)}\n <span>${this.label}</span>\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"scroll-to-bottom\": ScrollToBottom;\n }\n}\n"]}
@@ -0,0 +1,41 @@
1
+ import { LitElement, type PropertyValues } from "lit";
2
+ /**
3
+ * Overlay button that appears once the page (or a given `target` container)
4
+ * has scrolled more than `threshold` pixels away from the top edge, and
5
+ * scrolls back to the top on click.
6
+ *
7
+ * With no `target` (default), the button is `position: fixed` to the
8
+ * viewport. When `target` is set, the button switches to `position:
9
+ * absolute` and expects to be placed as a descendant of a `position:
10
+ * relative` (or otherwise positioned) ancestor that establishes the visual
11
+ * bounds to float within — typically `target` itself, given `overflow-y:
12
+ * auto; position: relative`, so the button stays pinned to that container's
13
+ * own visible corner as its content scrolls, rather than floating over the
14
+ * whole page.
15
+ *
16
+ * @element scroll-to-top
17
+ * @fires scroll-to-top-triggered - The button was clicked, just before
18
+ * scrolling; detail: `{ target }`.
19
+ */
20
+ export declare class ScrollToTop extends LitElement {
21
+ #private;
22
+ static styles: import("lit").CSSResult[];
23
+ /** Scrollable container to control; `null` (default) scrolls `window`. */
24
+ target: HTMLElement | null;
25
+ /** Pixels scrolled away from the top before the button appears. */
26
+ threshold: number;
27
+ /** Visible button text, and its accessible name. */
28
+ label: string;
29
+ private _visible;
30
+ connectedCallback(): void;
31
+ disconnectedCallback(): void;
32
+ protected willUpdate(changed: PropertyValues): void;
33
+ protected updated(changed: PropertyValues): void;
34
+ render(): import("lit-html").TemplateResult<1>;
35
+ }
36
+ declare global {
37
+ interface HTMLElementTagNameMap {
38
+ "scroll-to-top": ScrollToTop;
39
+ }
40
+ }
41
+ //# sourceMappingURL=scroll-to-top.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-to-top.d.ts","sourceRoot":"","sources":["../src/scroll-to-top.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAMjE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,WAAY,SAAQ,UAAU;;IACzC,OAAgB,MAAM,4BA6EpB;IAEF,0EAA0E;IAC1C,MAAM,EAAE,WAAW,GAAG,IAAI,CAAQ;IAClE,mEAAmE;IACvC,SAAS,SAAO;IAC5C,oDAAoD;IACxC,KAAK,SAAmB;IAE3B,OAAO,CAAC,QAAQ,CAAS;IAIzB,iBAAiB,IAAI,IAAI,CAGjC;IAEQ,oBAAoB,IAAI,IAAI,CAGpC;IAED,UAAmB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAU3D;IAED,UAAmB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAExD;IA0BQ,MAAM,yCAOd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,WAAW,CAAC;KAC9B;CACF"}