@f-ewald/components 1.0.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.
- package/README.md +6 -0
- package/custom-elements.json +891 -22
- package/dist/address-autocomplete.d.ts +8 -0
- package/dist/address-autocomplete.d.ts.map +1 -1
- package/dist/address-autocomplete.js +165 -15
- package/dist/address-autocomplete.js.map +1 -1
- package/dist/animate-confetti.d.ts +8 -5
- package/dist/animate-confetti.d.ts.map +1 -1
- package/dist/animate-confetti.js +46 -19
- package/dist/animate-confetti.js.map +1 -1
- package/dist/autocomplete-input.d.ts +8 -0
- package/dist/autocomplete-input.d.ts.map +1 -1
- package/dist/autocomplete-input.js +165 -15
- package/dist/autocomplete-input.js.map +1 -1
- package/dist/calendar-month.d.ts.map +1 -1
- package/dist/calendar-month.js +27 -13
- package/dist/calendar-month.js.map +1 -1
- package/dist/calendar-year.d.ts.map +1 -1
- package/dist/calendar-year.js +11 -2
- package/dist/calendar-year.js.map +1 -1
- package/dist/chat-message.d.ts.map +1 -1
- package/dist/chat-message.js +77 -24
- package/dist/chat-message.js.map +1 -1
- package/dist/confirm-dialog.d.ts +8 -1
- package/dist/confirm-dialog.d.ts.map +1 -1
- package/dist/confirm-dialog.js +130 -18
- package/dist/confirm-dialog.js.map +1 -1
- package/dist/copy-link-button.d.ts +2 -0
- package/dist/copy-link-button.d.ts.map +1 -1
- package/dist/copy-link-button.js +35 -3
- package/dist/copy-link-button.js.map +1 -1
- package/dist/data-table.d.ts +2 -0
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +83 -11
- package/dist/data-table.js.map +1 -1
- package/dist/distance-value.d.ts +0 -1
- package/dist/distance-value.d.ts.map +1 -1
- package/dist/distance-value.js +3 -8
- package/dist/distance-value.js.map +1 -1
- package/dist/distribution-chart.d.ts.map +1 -1
- package/dist/distribution-chart.js +54 -17
- package/dist/distribution-chart.js.map +1 -1
- package/dist/dropdown-button.d.ts.map +1 -1
- package/dist/dropdown-button.js +60 -11
- package/dist/dropdown-button.js.map +1 -1
- package/dist/editable-text.d.ts.map +1 -1
- package/dist/editable-text.js +46 -13
- package/dist/editable-text.js.map +1 -1
- package/dist/form-select.d.ts.map +1 -1
- package/dist/form-select.js +70 -22
- package/dist/form-select.js.map +1 -1
- package/dist/frame-box.d.ts.map +1 -1
- package/dist/frame-box.js +20 -12
- package/dist/frame-box.js.map +1 -1
- package/dist/icon-button.d.ts.map +1 -1
- package/dist/icon-button.js +11 -0
- package/dist/icon-button.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/kbd-hint.d.ts +30 -0
- package/dist/kbd-hint.d.ts.map +1 -0
- package/dist/kbd-hint.js +184 -0
- package/dist/kbd-hint.js.map +1 -0
- package/dist/live-timer.d.ts +0 -1
- package/dist/live-timer.d.ts.map +1 -1
- package/dist/live-timer.js +1 -6
- package/dist/live-timer.js.map +1 -1
- package/dist/map-circle.d.ts.map +1 -1
- package/dist/map-circle.js +16 -1
- package/dist/map-circle.js.map +1 -1
- package/dist/map-pin.d.ts.map +1 -1
- package/dist/map-pin.js +16 -1
- package/dist/map-pin.js.map +1 -1
- package/dist/percent-bar-chart.d.ts +3 -0
- package/dist/percent-bar-chart.d.ts.map +1 -1
- package/dist/percent-bar-chart.js +60 -4
- package/dist/percent-bar-chart.js.map +1 -1
- package/dist/photo-gallery.d.ts.map +1 -1
- package/dist/photo-gallery.js +12 -3
- package/dist/photo-gallery.js.map +1 -1
- package/dist/popover-panel.d.ts.map +1 -1
- package/dist/popover-panel.js +132 -23
- package/dist/popover-panel.js.map +1 -1
- package/dist/price-history-chart.d.ts.map +1 -1
- package/dist/price-history-chart.js +52 -18
- package/dist/price-history-chart.js.map +1 -1
- package/dist/radio-cards.d.ts +2 -0
- package/dist/radio-cards.d.ts.map +1 -1
- package/dist/radio-cards.js +51 -5
- package/dist/radio-cards.js.map +1 -1
- package/dist/radio-pills.d.ts +2 -0
- package/dist/radio-pills.d.ts.map +1 -1
- package/dist/radio-pills.js +46 -4
- package/dist/radio-pills.js.map +1 -1
- package/dist/relative-time.d.ts +0 -1
- package/dist/relative-time.d.ts.map +1 -1
- package/dist/relative-time.js +1 -6
- package/dist/relative-time.js.map +1 -1
- package/dist/reveal-button.d.ts +2 -0
- package/dist/reveal-button.d.ts.map +1 -1
- package/dist/reveal-button.js +42 -5
- package/dist/reveal-button.js.map +1 -1
- package/dist/roman-numeral.js +1 -1
- package/dist/roman-numeral.js.map +1 -1
- package/dist/slide-panel.d.ts +7 -3
- package/dist/slide-panel.d.ts.map +1 -1
- package/dist/slide-panel.js +95 -23
- package/dist/slide-panel.js.map +1 -1
- package/dist/stat-meter.d.ts.map +1 -1
- package/dist/stat-meter.js +17 -7
- package/dist/stat-meter.js.map +1 -1
- package/dist/status-pill.d.ts.map +1 -1
- package/dist/status-pill.js +26 -12
- package/dist/status-pill.js.map +1 -1
- package/dist/tile-grid.d.ts +8 -0
- package/dist/tile-grid.d.ts.map +1 -1
- package/dist/tile-grid.js +88 -12
- package/dist/tile-grid.js.map +1 -1
- package/dist/toast-notification.d.ts.map +1 -1
- package/dist/toast-notification.js +40 -11
- package/dist/toast-notification.js.map +1 -1
- package/dist/tokens.css +19 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +13 -0
- package/dist/tokens.js.map +1 -1
- package/dist/ui-button.d.ts +2 -0
- package/dist/ui-button.d.ts.map +1 -1
- package/dist/ui-button.js +58 -9
- package/dist/ui-button.js.map +1 -1
- package/dist/user-avatar.d.ts.map +1 -1
- package/dist/user-avatar.js +18 -3
- package/dist/user-avatar.js.map +1 -1
- package/dist/utils/form.d.ts +3 -0
- package/dist/utils/form.d.ts.map +1 -0
- package/dist/utils/form.js +14 -0
- package/dist/utils/form.js.map +1 -0
- package/dist/utils/layer-stack.d.ts +9 -0
- package/dist/utils/layer-stack.d.ts.map +1 -0
- package/dist/utils/layer-stack.js +35 -0
- package/dist/utils/layer-stack.js.map +1 -0
- package/dist/weight-bar-chart.d.ts.map +1 -1
- package/dist/weight-bar-chart.js +27 -8
- package/dist/weight-bar-chart.js.map +1 -1
- package/docs/address-autocomplete.md +5 -0
- package/docs/autocomplete-input.md +5 -0
- package/docs/calendar-month.md +2 -0
- package/docs/chat-message.md +4 -0
- package/docs/confirm-dialog.md +2 -0
- package/docs/copy-link-button.md +2 -0
- package/docs/data-table.md +2 -0
- package/docs/design-language.md +149 -0
- package/docs/distribution-chart.md +4 -0
- package/docs/dropdown-button.md +1 -0
- package/docs/frame-box.md +2 -0
- package/docs/kbd-hint.md +42 -0
- package/docs/percent-bar-chart.md +4 -1
- package/docs/photo-gallery.md +1 -0
- package/docs/popover-panel.md +2 -0
- package/docs/price-history-chart.md +8 -1
- package/docs/radio-cards.md +2 -0
- package/docs/radio-pills.md +2 -0
- package/docs/reveal-button.md +3 -0
- package/docs/slide-panel.md +4 -2
- package/docs/status-pill.md +3 -0
- package/docs/tile-grid.md +10 -1
- package/docs/toast-notification.md +4 -1
- package/docs/ui-button.md +2 -0
- package/docs/user-avatar.md +1 -0
- package/llms.txt +59 -34
- package/package.json +5 -1
|
@@ -77,6 +77,39 @@ let PriceHistoryChart = class PriceHistoryChart extends LitElement {
|
|
|
77
77
|
svg {
|
|
78
78
|
display: block;
|
|
79
79
|
overflow: visible;
|
|
80
|
+
font-family: var(
|
|
81
|
+
--ui-font,
|
|
82
|
+
ui-sans-serif,
|
|
83
|
+
system-ui,
|
|
84
|
+
sans-serif,
|
|
85
|
+
"Apple Color Emoji",
|
|
86
|
+
"Segoe UI Emoji",
|
|
87
|
+
"Segoe UI Symbol",
|
|
88
|
+
"Noto Color Emoji"
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
.axis-label {
|
|
92
|
+
fill: var(--ui-text-muted, #64748b);
|
|
93
|
+
}
|
|
94
|
+
.grid-line {
|
|
95
|
+
stroke: var(--ui-border, #e2e8f0);
|
|
96
|
+
}
|
|
97
|
+
.series-line {
|
|
98
|
+
stroke: var(--ui-primary, #4f46e5);
|
|
99
|
+
}
|
|
100
|
+
.series-gradient {
|
|
101
|
+
stop-color: var(--ui-primary, #4f46e5);
|
|
102
|
+
}
|
|
103
|
+
.series-point {
|
|
104
|
+
fill: var(--ui-primary, #4f46e5);
|
|
105
|
+
stroke: var(--ui-on-accent, #ffffff);
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
}
|
|
108
|
+
.tooltip {
|
|
109
|
+
fill: var(--ui-tooltip, #0f172a);
|
|
110
|
+
}
|
|
111
|
+
.tooltip-label {
|
|
112
|
+
fill: var(--ui-on-accent, #ffffff);
|
|
80
113
|
}
|
|
81
114
|
`,
|
|
82
115
|
]; }
|
|
@@ -138,11 +171,10 @@ let PriceHistoryChart = class PriceHistoryChart extends LitElement {
|
|
|
138
171
|
const tipX = Math.min(Math.max(hovPt.x - tipW / 2, ML), this._width - MR - tipW);
|
|
139
172
|
return svg `
|
|
140
173
|
<g pointer-events="none">
|
|
141
|
-
<rect x="${tipX}" y="${tipRectY}" width="${tipW}" height="${tipH}"
|
|
142
|
-
rx="4"
|
|
143
|
-
<text x="${tipX + tipW / 2}" y="${tipRectY + 15.5}"
|
|
144
|
-
text-anchor="middle"
|
|
145
|
-
font-family="ui-sans-serif,system-ui,sans-serif">${tipText}</text>
|
|
174
|
+
<rect class="tooltip" x="${tipX}" y="${tipRectY}" width="${tipW}" height="${tipH}"
|
|
175
|
+
rx="4" />
|
|
176
|
+
<text class="tooltip-label" x="${tipX + tipW / 2}" y="${tipRectY + 15.5}"
|
|
177
|
+
text-anchor="middle" font-size="11">${tipText}</text>
|
|
146
178
|
</g>
|
|
147
179
|
`;
|
|
148
180
|
})() : "";
|
|
@@ -151,8 +183,7 @@ let PriceHistoryChart = class PriceHistoryChart extends LitElement {
|
|
|
151
183
|
const label = d.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
152
184
|
const anchor = i === 0 ? "start" : i === arr.length - 1 ? "end" : "middle";
|
|
153
185
|
return svg `
|
|
154
|
-
<text x="${x}" y="${H - 6}" text-anchor="${anchor}" font-size="10"
|
|
155
|
-
font-family="ui-sans-serif,system-ui,sans-serif">${label}</text>
|
|
186
|
+
<text class="axis-label" x="${x}" y="${H - 6}" text-anchor="${anchor}" font-size="10">${label}</text>
|
|
156
187
|
`;
|
|
157
188
|
});
|
|
158
189
|
const yTicks = this.showY ? yScale.ticks(3).map((v, i, arr) => {
|
|
@@ -160,31 +191,34 @@ let PriceHistoryChart = class PriceHistoryChart extends LitElement {
|
|
|
160
191
|
const isFirst = i === 0;
|
|
161
192
|
const isLast = i === arr.length - 1;
|
|
162
193
|
return svg `
|
|
163
|
-
<line x1="${ML - 4}" y1="${y}" x2="${ML + plotW}" y2="${y}"
|
|
164
|
-
stroke
|
|
194
|
+
<line class="grid-line" x1="${ML - 4}" y1="${y}" x2="${ML + plotW}" y2="${y}"
|
|
195
|
+
stroke-width="1" />
|
|
165
196
|
${isFirst || isLast ? svg `
|
|
166
|
-
<text x="${ML - 6}" y="${y + 4}" text-anchor="end" font-size="10"
|
|
167
|
-
font-family="ui-sans-serif,system-ui,sans-serif">${fmtMoneyShort(v)}</text>
|
|
197
|
+
<text class="axis-label" x="${ML - 6}" y="${y + 4}" text-anchor="end" font-size="10">${fmtMoneyShort(v)}</text>
|
|
168
198
|
` : ""}
|
|
169
199
|
`;
|
|
170
200
|
}) : [];
|
|
201
|
+
const firstPoint = points[0];
|
|
202
|
+
const lastPoint = points[points.length - 1];
|
|
203
|
+
const formatDate = (date) => new Date(date).toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
204
|
+
const summary = `${points.length} price points from ${formatDate(firstPoint.date)} at ${fmtMoney(firstPoint.price)} ` +
|
|
205
|
+
`to ${formatDate(lastPoint.date)} at ${fmtMoney(lastPoint.price)}.`;
|
|
171
206
|
return html `
|
|
172
207
|
<div class="wrap">
|
|
173
|
-
<svg width="${this._width}" height="${H}">
|
|
208
|
+
<svg width="${this._width}" height="${H}" role="img" aria-label=${summary}>
|
|
174
209
|
<defs>
|
|
175
210
|
<linearGradient id="phg" x1="0" y1="0" x2="0" y2="1">
|
|
176
|
-
<stop
|
|
177
|
-
<stop
|
|
211
|
+
<stop class="series-gradient" offset="0%" stop-opacity="0.25" />
|
|
212
|
+
<stop class="series-gradient" offset="100%" stop-opacity="0" />
|
|
178
213
|
</linearGradient>
|
|
179
214
|
</defs>
|
|
180
215
|
${yTicks}
|
|
181
216
|
<path d="${areaD}" fill="url(#phg)" />
|
|
182
|
-
<path d="${lineD}" fill="none" stroke
|
|
217
|
+
<path class="series-line" d="${lineD}" fill="none" stroke-width="2.5"
|
|
183
218
|
stroke-linejoin="round" stroke-linecap="round" />
|
|
184
219
|
${plotted.map((p, i) => svg `
|
|
185
|
-
<circle cx="${p.x}" cy="${p.y}" r="${i === hIdx ? 7 : 5}"
|
|
186
|
-
|
|
187
|
-
style="cursor:pointer"
|
|
220
|
+
<circle class="series-point" cx="${p.x}" cy="${p.y}" r="${i === hIdx ? 7 : 5}"
|
|
221
|
+
stroke-width="2"
|
|
188
222
|
@pointerenter=${() => { this._hoveredIdx = i; }}
|
|
189
223
|
@pointerleave=${() => { this._hoveredIdx = null; }} />
|
|
190
224
|
`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"price-history-chart.js","sourceRoot":"","sources":["../src/price-history-chart.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAcrC,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,IAAI,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC7D,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;IACpD,OAAO,IAAI,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;;;;;GAUG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,UAAU;IAA1C;;QACsB,YAAO,GAAiB,EAAE,CAAC;QACjB,YAAO,GAAgC,MAAM,CAAC;QAC5B,eAAU,GAAG,CAAC,CAAC;QAErD,WAAM,GAAG,CAAC,CAAC;QACX,gBAAW,GAAkB,IAAI,CAAC;QAE3C,QAAG,GAA0B,IAAI,CAAC;IA4K5C,CAAC;IA1KU,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG,GAAG,IAAI,cAAc,CAAC,CAAC,OAAO,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,KAAK;gBAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAEQ,oBAAoB;QAC3B,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,OAAO;aAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC;aAChD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,IAAY,KAAK;QACf,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;IACtF,CAAC;aAEe,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;KAaF;KACF,AAhBqB,CAgBpB;IAEM,aAAa;QACnB,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAEnC,MAAM,CAAC,GAAG,GAAG,CAAC;QACd,MAAM,EAAE,GAAG,EAAE,CAAC;QACd,MAAM,EAAE,GAAG,EAAE,CAAC;QACd,MAAM,EAAE,GAAG,EAAE,CAAC;QACd,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3B,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC,GAAG,IAAI,IAAI,QAAQ,GAAG,IAAI,CAAC;QAE5D,MAAM,MAAM,GAAG,SAAS,EAAE;aACvB,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAE,EAAE,GAAG,CAAC,KAAK,CAAE,CAAC,CAAC;aAClC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;QAE3B,MAAM,MAAM,GAAG,WAAW,EAAE;aACzB,MAAM,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,QAAQ,GAAG,GAAG,CAAC,CAAC;aACxC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAExB,MAAM,MAAM,GAAG,IAAI,EAAc;aAC9B,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC,CAAC;aACnC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC;QAE9B,MAAM,MAAM,GAAG,IAAI,EAAc;aAC9B,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC,CAAC;aACnC,EAAE,CAAC,OAAO,CAAC;aACX,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC;QAE/B,MAAM,OAAO,GAAmB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjD,GAAG,CAAC;YACJ,CAAC,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAK,CAAC,CAAC;YAC5B,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,KAAM,CAAC;SACpB,CAAC,CAAC,CAAC;QAEJ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACvH,CAAC;IAEQ,MAAM;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA,EAAE,CAAC;QAE3B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QAEhG,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAEnC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAEnD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;YAC9B,MAAM,OAAO,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC;YAC9K,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACxE,MAAM,IAAI,GAAG,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,CAAC,CAAC;YACjB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC;YACpE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YACjF,OAAO,GAAG,CAAA;;qBAEK,IAAI,QAAQ,QAAQ,YAAY,IAAI,aAAa,IAAI;;qBAErD,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,QAAQ,GAAG,IAAI;;mEAEQ,OAAO;;OAEnE,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEV,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;YAC7D,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,KAAK,GAAG,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YACjF,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC3E,OAAO,GAAG,CAAA;mBACG,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,MAAM;iEACQ,KAAK;OAC/D,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;YAC5D,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,MAAM,MAAM,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YACpC,OAAO,GAAG,CAAA;oBACI,EAAE,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,GAAG,KAAK,SAAS,CAAC;;UAEvD,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAA;qBACZ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;mEAC2B,aAAa,CAAC,CAAC,CAAC;SAC1E,CAAC,CAAC,CAAC,EAAE;OACP,CAAC;QACJ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAER,OAAO,IAAI,CAAA;;sBAEO,IAAI,CAAC,MAAM,aAAa,CAAC;;;;;;;YAOnC,MAAM;qBACG,KAAK;qBACL,KAAK;;YAEd,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAA;0BACX,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;;oCAG/B,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC;oCAC/B,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC;WAC3D,CAAC;YACA,MAAM;YACN,SAAS;;;KAGhB,CAAC;IACJ,CAAC;CACF,CAAA;AAnL4B;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;kDAA4B;AACjB;IAApC,QAAQ,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;kDAA+C;AAC5B;IAAtD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;qDAAgB;AAErD;IAAhB,KAAK,EAAE;iDAAoB;AACX;IAAhB,KAAK,EAAE;sDAA2C;AANxC,iBAAiB;IAD7B,aAAa,CAAC,qBAAqB,CAAC;GACxB,iBAAiB,CAoL7B","sourcesContent":["import { LitElement, css, html, svg } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { scaleTime, scaleLinear } from \"d3-scale\";\nimport { line, area } from \"d3-shape\";\nimport { min, max } from \"d3-array\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface PricePoint {\n date: string | null;\n price: number | null;\n eventType: string;\n source?: string | null;\n}\n\ninterface PlottedPoint extends PricePoint {\n x: number;\n y: number;\n}\n\nfunction fmtMoney(n: number): string {\n return `$${n.toLocaleString(\"en-US\")}`;\n}\n\nfunction fmtMoneyShort(n: number): string {\n if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `$${Math.round(n / 1_000)}K`;\n return `$${n.toLocaleString(\"en-US\")}`;\n}\n\n/**\n * D3-powered SVG line chart for property price history.\n *\n * Uses scaleTime (X) + scaleLinear (Y) from d3-scale and line/area path\n * generators from d3-shape. Adapts to container width via ResizeObserver.\n *\n * @element price-history-chart\n * @prop history - Array of price points (points with null price/date are skipped).\n * @prop yLabels - \"auto\" (default) | \"always\" | \"never\"\n * @prop maxXLabels - Max X-axis date ticks (default 3).\n */\n@customElement(\"price-history-chart\")\nexport class PriceHistoryChart extends LitElement {\n @property({ type: Array }) history: PricePoint[] = [];\n @property({ attribute: \"y-labels\" }) yLabels: \"auto\" | \"always\" | \"never\" = \"auto\";\n @property({ type: Number, attribute: \"max-x-labels\" }) maxXLabels = 3;\n\n @state() private _width = 0;\n @state() private _hoveredIdx: number | null = null;\n\n private _ro: ResizeObserver | null = null;\n\n override connectedCallback() {\n super.connectedCallback();\n this._ro = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) this._width = entry.contentRect.width;\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 get validPoints(): PricePoint[] {\n return this.history\n .filter((h) => h.price != null && h.date != null)\n .sort((a, b) => new Date(a.date!).getTime() - new Date(b.date!).getTime());\n }\n\n private get showY(): boolean {\n return this.yLabels === \"always\" || (this.yLabels === \"auto\" && this._width >= 260);\n }\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n width: 100%;\n }\n .wrap {\n position: relative;\n width: 100%;\n }\n svg {\n display: block;\n overflow: visible;\n }\n `,\n ];\n\n private computeLayout() {\n if (this._width < 10) return null;\n const points = this.validPoints;\n if (points.length < 2) return null;\n\n const H = 180;\n const MT = 20;\n const MB = 30;\n const MR = 12;\n const ML = this.showY ? 56 : 12;\n const plotW = Math.max(this._width - ML - MR, 1);\n const plotH = Math.max(H - MT - MB, 1);\n const bottomY = MT + plotH;\n\n const prices = points.map((p) => p.price!);\n const dates = points.map((p) => new Date(p.date!));\n const minPrice = min(prices)!;\n const maxPrice = max(prices)!;\n const pad = (maxPrice - minPrice) * 0.05 || maxPrice * 0.05;\n\n const xScale = scaleTime()\n .domain([min(dates)!, max(dates)!])\n .range([ML, ML + plotW]);\n\n const yScale = scaleLinear()\n .domain([minPrice - pad, maxPrice + pad])\n .range([bottomY, MT]);\n\n const lineFn = line<PricePoint>()\n .x((p) => xScale(new Date(p.date!)))\n .y((p) => yScale(p.price!));\n\n const areaFn = area<PricePoint>()\n .x((p) => xScale(new Date(p.date!)))\n .y0(bottomY)\n .y1((p) => yScale(p.price!));\n\n const plotted: PlottedPoint[] = points.map((p) => ({\n ...p,\n x: xScale(new Date(p.date!)),\n y: yScale(p.price!),\n }));\n\n return { points, plotted, H, MT, ML, MR, plotW, plotH, bottomY, minPrice, maxPrice, xScale, yScale, lineFn, areaFn };\n }\n\n override render() {\n const layout = this.computeLayout();\n if (!layout) return html``;\n\n const { points, plotted, H, MT, ML, MR, plotW, plotH, xScale, yScale, lineFn, areaFn } = layout;\n\n const lineD = lineFn(points) ?? \"\";\n const areaD = areaFn(points) ?? \"\";\n\n const hIdx = this._hoveredIdx;\n const hovPt = hIdx !== null ? plotted[hIdx] : null;\n\n const tooltipEl = hovPt ? (() => {\n const tipText = `${fmtMoney(hovPt.price!)} · ${hovPt.date ? new Date(hovPt.date).toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" }) : \"\"} · ${hovPt.eventType}`;\n const tipW = Math.min(tipText.length * 6.5 + 16, this._width - ML - MR);\n const tipH = 24;\n const tipGap = 8;\n const above = hovPt.y > plotH / 2 + MT;\n const tipRectY = above ? hovPt.y - tipGap - tipH : hovPt.y + tipGap;\n const tipX = Math.min(Math.max(hovPt.x - tipW / 2, ML), this._width - MR - tipW);\n return svg`\n <g pointer-events=\"none\">\n <rect x=\"${tipX}\" y=\"${tipRectY}\" width=\"${tipW}\" height=\"${tipH}\"\n rx=\"4\" fill=\"rgba(15,23,42,0.88)\" />\n <text x=\"${tipX + tipW / 2}\" y=\"${tipRectY + 15.5}\"\n text-anchor=\"middle\" fill=\"white\" font-size=\"11\"\n font-family=\"ui-sans-serif,system-ui,sans-serif\">${tipText}</text>\n </g>\n `;\n })() : \"\";\n\n const xTicks = xScale.ticks(this.maxXLabels).map((d, i, arr) => {\n const x = xScale(d);\n const label = d.toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" });\n const anchor = i === 0 ? \"start\" : i === arr.length - 1 ? \"end\" : \"middle\";\n return svg`\n <text x=\"${x}\" y=\"${H - 6}\" text-anchor=\"${anchor}\" font-size=\"10\" fill=\"#64748b\"\n font-family=\"ui-sans-serif,system-ui,sans-serif\">${label}</text>\n `;\n });\n\n const yTicks = this.showY ? yScale.ticks(3).map((v, i, arr) => {\n const y = yScale(v);\n const isFirst = i === 0;\n const isLast = i === arr.length - 1;\n return svg`\n <line x1=\"${ML - 4}\" y1=\"${y}\" x2=\"${ML + plotW}\" y2=\"${y}\"\n stroke=\"#e2e8f0\" stroke-width=\"1\" />\n ${isFirst || isLast ? svg`\n <text x=\"${ML - 6}\" y=\"${y + 4}\" text-anchor=\"end\" font-size=\"10\" fill=\"#64748b\"\n font-family=\"ui-sans-serif,system-ui,sans-serif\">${fmtMoneyShort(v)}</text>\n ` : \"\"}\n `;\n }) : [];\n\n return html`\n <div class=\"wrap\">\n <svg width=\"${this._width}\" height=\"${H}\">\n <defs>\n <linearGradient id=\"phg\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=\"#4f46e5\" stop-opacity=\"0.25\" />\n <stop offset=\"100%\" stop-color=\"#4f46e5\" stop-opacity=\"0\" />\n </linearGradient>\n </defs>\n ${yTicks}\n <path d=\"${areaD}\" fill=\"url(#phg)\" />\n <path d=\"${lineD}\" fill=\"none\" stroke=\"#4f46e5\" stroke-width=\"2.5\"\n stroke-linejoin=\"round\" stroke-linecap=\"round\" />\n ${plotted.map((p, i) => svg`\n <circle cx=\"${p.x}\" cy=\"${p.y}\" r=\"${i === hIdx ? 7 : 5}\"\n fill=\"#4f46e5\" stroke=\"#fff\" stroke-width=\"2\"\n style=\"cursor:pointer\"\n @pointerenter=${() => { this._hoveredIdx = i; }}\n @pointerleave=${() => { this._hoveredIdx = null; }} />\n `)}\n ${xTicks}\n ${tooltipEl}\n </svg>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"price-history-chart\": PriceHistoryChart;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"price-history-chart.js","sourceRoot":"","sources":["../src/price-history-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 { scaleTime, scaleLinear } from \"d3-scale\";\nimport { line, area } from \"d3-shape\";\nimport { min, max } from \"d3-array\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface PricePoint {\n date: string | null;\n price: number | null;\n eventType: string;\n source?: string | null;\n}\n\ninterface PlottedPoint extends PricePoint {\n x: number;\n y: number;\n}\n\nfunction fmtMoney(n: number): string {\n return `$${n.toLocaleString(\"en-US\")}`;\n}\n\nfunction fmtMoneyShort(n: number): string {\n if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `$${Math.round(n / 1_000)}K`;\n return `$${n.toLocaleString(\"en-US\")}`;\n}\n\n/**\n * D3-powered SVG line chart for property price history.\n *\n * Uses scaleTime (X) + scaleLinear (Y) from d3-scale and line/area path\n * generators from d3-shape. Adapts to container width via ResizeObserver.\n *\n * @element price-history-chart\n * @prop history - Array of price points (points with null price/date are skipped).\n * @prop yLabels - \"auto\" (default) | \"always\" | \"never\"\n * @prop maxXLabels - Max X-axis date ticks (default 3).\n */\n@customElement(\"price-history-chart\")\nexport class PriceHistoryChart extends LitElement {\n @property({ type: Array }) history: PricePoint[] = [];\n @property({ attribute: \"y-labels\" }) yLabels: \"auto\" | \"always\" | \"never\" = \"auto\";\n @property({ type: Number, attribute: \"max-x-labels\" }) maxXLabels = 3;\n\n @state() private _width = 0;\n @state() private _hoveredIdx: number | null = null;\n\n private _ro: ResizeObserver | null = null;\n\n override connectedCallback() {\n super.connectedCallback();\n this._ro = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) this._width = entry.contentRect.width;\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 get validPoints(): PricePoint[] {\n return this.history\n .filter((h) => h.price != null && h.date != null)\n .sort((a, b) => new Date(a.date!).getTime() - new Date(b.date!).getTime());\n }\n\n private get showY(): boolean {\n return this.yLabels === \"always\" || (this.yLabels === \"auto\" && this._width >= 260);\n }\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n width: 100%;\n }\n .wrap {\n position: relative;\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 .axis-label {\n fill: var(--ui-text-muted, #64748b);\n }\n .grid-line {\n stroke: var(--ui-border, #e2e8f0);\n }\n .series-line {\n stroke: var(--ui-primary, #4f46e5);\n }\n .series-gradient {\n stop-color: var(--ui-primary, #4f46e5);\n }\n .series-point {\n fill: var(--ui-primary, #4f46e5);\n stroke: var(--ui-on-accent, #ffffff);\n cursor: pointer;\n }\n .tooltip {\n fill: var(--ui-tooltip, #0f172a);\n }\n .tooltip-label {\n fill: var(--ui-on-accent, #ffffff);\n }\n `,\n ];\n\n private computeLayout() {\n if (this._width < 10) return null;\n const points = this.validPoints;\n if (points.length < 2) return null;\n\n const H = 180;\n const MT = 20;\n const MB = 30;\n const MR = 12;\n const ML = this.showY ? 56 : 12;\n const plotW = Math.max(this._width - ML - MR, 1);\n const plotH = Math.max(H - MT - MB, 1);\n const bottomY = MT + plotH;\n\n const prices = points.map((p) => p.price!);\n const dates = points.map((p) => new Date(p.date!));\n const minPrice = min(prices)!;\n const maxPrice = max(prices)!;\n const pad = (maxPrice - minPrice) * 0.05 || maxPrice * 0.05;\n\n const xScale = scaleTime()\n .domain([min(dates)!, max(dates)!])\n .range([ML, ML + plotW]);\n\n const yScale = scaleLinear()\n .domain([minPrice - pad, maxPrice + pad])\n .range([bottomY, MT]);\n\n const lineFn = line<PricePoint>()\n .x((p) => xScale(new Date(p.date!)))\n .y((p) => yScale(p.price!));\n\n const areaFn = area<PricePoint>()\n .x((p) => xScale(new Date(p.date!)))\n .y0(bottomY)\n .y1((p) => yScale(p.price!));\n\n const plotted: PlottedPoint[] = points.map((p) => ({\n ...p,\n x: xScale(new Date(p.date!)),\n y: yScale(p.price!),\n }));\n\n return { points, plotted, H, MT, ML, MR, plotW, plotH, bottomY, minPrice, maxPrice, xScale, yScale, lineFn, areaFn };\n }\n\n override render() {\n const layout = this.computeLayout();\n if (!layout) return html``;\n\n const { points, plotted, H, MT, ML, MR, plotW, plotH, xScale, yScale, lineFn, areaFn } = layout;\n\n const lineD = lineFn(points) ?? \"\";\n const areaD = areaFn(points) ?? \"\";\n\n const hIdx = this._hoveredIdx;\n const hovPt = hIdx !== null ? plotted[hIdx] : null;\n\n const tooltipEl = hovPt ? (() => {\n const tipText = `${fmtMoney(hovPt.price!)} · ${hovPt.date ? new Date(hovPt.date).toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" }) : \"\"} · ${hovPt.eventType}`;\n const tipW = Math.min(tipText.length * 6.5 + 16, this._width - ML - MR);\n const tipH = 24;\n const tipGap = 8;\n const above = hovPt.y > plotH / 2 + MT;\n const tipRectY = above ? hovPt.y - tipGap - tipH : hovPt.y + tipGap;\n const tipX = Math.min(Math.max(hovPt.x - tipW / 2, ML), this._width - MR - tipW);\n return svg`\n <g pointer-events=\"none\">\n <rect class=\"tooltip\" x=\"${tipX}\" y=\"${tipRectY}\" width=\"${tipW}\" height=\"${tipH}\"\n rx=\"4\" />\n <text class=\"tooltip-label\" x=\"${tipX + tipW / 2}\" y=\"${tipRectY + 15.5}\"\n text-anchor=\"middle\" font-size=\"11\">${tipText}</text>\n </g>\n `;\n })() : \"\";\n\n const xTicks = xScale.ticks(this.maxXLabels).map((d, i, arr) => {\n const x = xScale(d);\n const label = d.toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" });\n const anchor = i === 0 ? \"start\" : i === arr.length - 1 ? \"end\" : \"middle\";\n return svg`\n <text class=\"axis-label\" x=\"${x}\" y=\"${H - 6}\" text-anchor=\"${anchor}\" font-size=\"10\">${label}</text>\n `;\n });\n\n const yTicks = this.showY ? yScale.ticks(3).map((v, i, arr) => {\n const y = yScale(v);\n const isFirst = i === 0;\n const isLast = i === arr.length - 1;\n return svg`\n <line class=\"grid-line\" x1=\"${ML - 4}\" y1=\"${y}\" x2=\"${ML + plotW}\" y2=\"${y}\"\n stroke-width=\"1\" />\n ${isFirst || isLast ? svg`\n <text class=\"axis-label\" x=\"${ML - 6}\" y=\"${y + 4}\" text-anchor=\"end\" font-size=\"10\">${fmtMoneyShort(v)}</text>\n ` : \"\"}\n `;\n }) : [];\n\n const firstPoint = points[0];\n const lastPoint = points[points.length - 1];\n const formatDate = (date: string | null) =>\n new Date(date!).toLocaleDateString(\"en-US\", { month: \"short\", year: \"numeric\" });\n const summary =\n `${points.length} price points from ${formatDate(firstPoint.date)} at ${fmtMoney(firstPoint.price!)} ` +\n `to ${formatDate(lastPoint.date)} at ${fmtMoney(lastPoint.price!)}.`;\n\n return html`\n <div class=\"wrap\">\n <svg width=\"${this._width}\" height=\"${H}\" role=\"img\" aria-label=${summary}>\n <defs>\n <linearGradient id=\"phg\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop class=\"series-gradient\" offset=\"0%\" stop-opacity=\"0.25\" />\n <stop class=\"series-gradient\" offset=\"100%\" stop-opacity=\"0\" />\n </linearGradient>\n </defs>\n ${yTicks}\n <path d=\"${areaD}\" fill=\"url(#phg)\" />\n <path class=\"series-line\" d=\"${lineD}\" fill=\"none\" stroke-width=\"2.5\"\n stroke-linejoin=\"round\" stroke-linecap=\"round\" />\n ${plotted.map((p, i) => svg`\n <circle class=\"series-point\" cx=\"${p.x}\" cy=\"${p.y}\" r=\"${i === hIdx ? 7 : 5}\"\n stroke-width=\"2\"\n @pointerenter=${() => { this._hoveredIdx = i; }}\n @pointerleave=${() => { this._hoveredIdx = null; }} />\n `)}\n ${xTicks}\n ${tooltipEl}\n </svg>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"price-history-chart\": PriceHistoryChart;\n }\n}\n"]}
|
package/dist/radio-cards.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export declare class RadioCards extends LitElement {
|
|
|
21
21
|
options: RadioCardOption[];
|
|
22
22
|
/** Currently selected value. */
|
|
23
23
|
value: string;
|
|
24
|
+
/** Disables every native radio in the group. */
|
|
25
|
+
disabled: boolean;
|
|
24
26
|
private _onChange;
|
|
25
27
|
render(): import("lit-html").TemplateResult<1>;
|
|
26
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-cards.d.ts","sourceRoot":"","sources":["../src/radio-cards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"radio-cards.d.ts","sourceRoot":"","sources":["../src/radio-cards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAKrD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,4BAiFpB;IAEF,wCAAwC;IACR,OAAO,EAAE,eAAe,EAAE,CAAM;IAChE,gCAAgC;IACpB,KAAK,SAAM;IACvB,gDAAgD;IACnB,QAAQ,UAAS;IAI9C,OAAO,CAAC,SAAS;IAMR,MAAM,yCAwBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
|
package/dist/radio-cards.js
CHANGED
|
@@ -26,6 +26,8 @@ let RadioCards = class RadioCards extends LitElement {
|
|
|
26
26
|
this.options = [];
|
|
27
27
|
/** Currently selected value. */
|
|
28
28
|
this.value = "";
|
|
29
|
+
/** Disables every native radio in the group. */
|
|
30
|
+
this.disabled = false;
|
|
29
31
|
this.#name = `radio-cards-${++instanceCount}`;
|
|
30
32
|
}
|
|
31
33
|
static { this.styles = [
|
|
@@ -36,19 +38,28 @@ let RadioCards = class RadioCards extends LitElement {
|
|
|
36
38
|
}
|
|
37
39
|
.options {
|
|
38
40
|
display: flex;
|
|
39
|
-
gap: 0.
|
|
41
|
+
gap: 0.5rem;
|
|
40
42
|
flex-wrap: wrap;
|
|
41
43
|
}
|
|
42
44
|
.card {
|
|
43
|
-
flex: 1 1
|
|
45
|
+
flex: 1 1 11.25rem;
|
|
44
46
|
display: flex;
|
|
45
47
|
align-items: flex-start;
|
|
46
48
|
gap: 0.5rem;
|
|
47
49
|
border: 1px solid var(--ui-border, #e2e8f0);
|
|
48
50
|
border-radius: var(--ui-radius-sm, 0.25rem);
|
|
49
|
-
padding: 0.
|
|
51
|
+
padding: 0.5rem 0.75rem;
|
|
50
52
|
cursor: pointer;
|
|
51
|
-
font-family: var(
|
|
53
|
+
font-family: var(
|
|
54
|
+
--ui-font,
|
|
55
|
+
ui-sans-serif,
|
|
56
|
+
system-ui,
|
|
57
|
+
sans-serif,
|
|
58
|
+
"Apple Color Emoji",
|
|
59
|
+
"Segoe UI Emoji",
|
|
60
|
+
"Segoe UI Symbol",
|
|
61
|
+
"Noto Color Emoji"
|
|
62
|
+
);
|
|
52
63
|
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
53
64
|
}
|
|
54
65
|
.card:has(input:checked) {
|
|
@@ -57,7 +68,7 @@ let RadioCards = class RadioCards extends LitElement {
|
|
|
57
68
|
}
|
|
58
69
|
.card input {
|
|
59
70
|
width: auto;
|
|
60
|
-
margin-top: 0.
|
|
71
|
+
margin-top: 0.25rem;
|
|
61
72
|
accent-color: var(--ui-primary, #4f46e5);
|
|
62
73
|
cursor: pointer;
|
|
63
74
|
}
|
|
@@ -70,10 +81,41 @@ let RadioCards = class RadioCards extends LitElement {
|
|
|
70
81
|
color: var(--ui-text-muted, #64748b);
|
|
71
82
|
font-weight: 400;
|
|
72
83
|
}
|
|
84
|
+
.card:has(input:focus-visible) {
|
|
85
|
+
outline: none;
|
|
86
|
+
box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
|
|
87
|
+
}
|
|
88
|
+
.card:has(input:disabled) {
|
|
89
|
+
cursor: not-allowed;
|
|
90
|
+
opacity: 0.6;
|
|
91
|
+
}
|
|
92
|
+
.card:has(input:disabled) input {
|
|
93
|
+
cursor: not-allowed;
|
|
94
|
+
}
|
|
95
|
+
@media (forced-colors: active) {
|
|
96
|
+
.card:has(input:focus-visible) {
|
|
97
|
+
outline: 2px solid CanvasText;
|
|
98
|
+
outline-offset: 2px;
|
|
99
|
+
box-shadow: none;
|
|
100
|
+
}
|
|
101
|
+
.card:has(input:checked) {
|
|
102
|
+
border-color: Highlight;
|
|
103
|
+
}
|
|
104
|
+
.card:has(input:disabled) {
|
|
105
|
+
color: GrayText;
|
|
106
|
+
opacity: 1;
|
|
107
|
+
}
|
|
108
|
+
.card:has(input:disabled) .card-label,
|
|
109
|
+
.card:has(input:disabled) .card-description {
|
|
110
|
+
color: GrayText;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
73
113
|
`,
|
|
74
114
|
]; }
|
|
75
115
|
#name;
|
|
76
116
|
_onChange(value) {
|
|
117
|
+
if (this.disabled)
|
|
118
|
+
return;
|
|
77
119
|
this.value = value;
|
|
78
120
|
this.dispatchEvent(new CustomEvent("change", { detail: { value }, bubbles: true, composed: true }));
|
|
79
121
|
}
|
|
@@ -86,6 +128,7 @@ let RadioCards = class RadioCards extends LitElement {
|
|
|
86
128
|
type="radio"
|
|
87
129
|
name=${this.#name}
|
|
88
130
|
?checked=${this.value === opt.value}
|
|
131
|
+
?disabled=${this.disabled}
|
|
89
132
|
@change=${() => this._onChange(opt.value)}
|
|
90
133
|
/>
|
|
91
134
|
<span>
|
|
@@ -104,6 +147,9 @@ __decorate([
|
|
|
104
147
|
__decorate([
|
|
105
148
|
property()
|
|
106
149
|
], RadioCards.prototype, "value", void 0);
|
|
150
|
+
__decorate([
|
|
151
|
+
property({ type: Boolean })
|
|
152
|
+
], RadioCards.prototype, "disabled", void 0);
|
|
107
153
|
RadioCards = __decorate([
|
|
108
154
|
customElement("radio-cards")
|
|
109
155
|
], RadioCards);
|
package/dist/radio-cards.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-cards.js","sourceRoot":"","sources":["../src/radio-cards.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,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;AAQrC,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;;;;;;;GASG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;
|
|
1
|
+
{"version":3,"file":"radio-cards.js","sourceRoot":"","sources":["../src/radio-cards.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,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;AAQrC,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;;;;;;;GASG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QAoFL,wCAAwC;QACR,YAAO,GAAsB,EAAE,CAAC;QAChE,gCAAgC;QACpB,UAAK,GAAG,EAAE,CAAC;QACvB,gDAAgD;QACnB,aAAQ,GAAG,KAAK,CAAC;QAErC,UAAK,GAAG,eAAe,EAAE,aAAa,EAAE,CAAC;IAiCpD,CAAC;aA3HiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA8EF;KACF,AAjFqB,CAiFpB;IASO,KAAK,CAAoC;IAE1C,SAAS,CAAC,KAAa;QAC7B,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtG,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;UAEL,MAAM,CACN,IAAI,CAAC,OAAO,EACZ,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAClB,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAA;;;;uBAIA,IAAI,CAAC,KAAK;2BACN,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;4BACvB,IAAI,CAAC,QAAQ;0BACf,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;;;2CAGd,GAAG,CAAC,KAAK;kBAClC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA,kCAAkC,GAAG,CAAC,WAAW,SAAS,CAAC,CAAC,CAAC,OAAO;;;WAGjG,CACF;;KAEJ,CAAC;IACJ,CAAC;CACF,CAAA;AAvCiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;2CAAiC;AAEpD;IAAX,QAAQ,EAAE;yCAAY;AAEM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAkB;AAzFnC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CA4HtB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { tokens } from \"./tokens.js\";\n\nexport interface RadioCardOption {\n value: string;\n label: string;\n description?: string;\n}\n\nlet instanceCount = 0;\n\n/**\n * Single-select group of full-width cards, each with a label and optional\n * description — for a handful of meaningfully different choices where the\n * description matters. For many short, same-shaped options (a color swatch,\n * a basemap style), use `radio-pills` instead. Wraps native radio inputs for\n * keyboard/a11y and fires `change` rather than relying on form submission.\n *\n * @element radio-cards\n * @fires change - A card was selected; detail: { value }.\n */\n@customElement(\"radio-cards\")\nexport class RadioCards extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .options {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n }\n .card {\n flex: 1 1 11.25rem;\n display: flex;\n align-items: flex-start;\n gap: 0.5rem;\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 0.75rem;\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 }\n .card:has(input:checked) {\n border-color: var(--ui-primary, #4f46e5);\n background: var(--ui-surface-muted, #f8fafc);\n }\n .card input {\n width: auto;\n margin-top: 0.25rem;\n accent-color: var(--ui-primary, #4f46e5);\n cursor: pointer;\n }\n .card-label {\n font-weight: 600;\n color: var(--ui-text, #0f172a);\n }\n .card-description {\n display: block;\n color: var(--ui-text-muted, #64748b);\n font-weight: 400;\n }\n .card:has(input:focus-visible) {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .card:has(input:disabled) {\n cursor: not-allowed;\n opacity: 0.6;\n }\n .card:has(input:disabled) input {\n cursor: not-allowed;\n }\n @media (forced-colors: active) {\n .card:has(input:focus-visible) {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n .card:has(input:checked) {\n border-color: Highlight;\n }\n .card:has(input:disabled) {\n color: GrayText;\n opacity: 1;\n }\n .card:has(input:disabled) .card-label,\n .card:has(input:disabled) .card-description {\n color: GrayText;\n }\n }\n `,\n ];\n\n /** Options to render, one card each. */\n @property({ attribute: false }) options: RadioCardOption[] = [];\n /** Currently selected value. */\n @property() value = \"\";\n /** Disables every native radio in the group. */\n @property({ type: Boolean }) disabled = false;\n\n readonly #name = `radio-cards-${++instanceCount}`;\n\n private _onChange(value: string) {\n if (this.disabled) return;\n this.value = value;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value }, bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <div class=\"options\">\n ${repeat(\n this.options,\n (opt) => opt.value,\n (opt) => html`\n <label class=\"card\">\n <input\n type=\"radio\"\n name=${this.#name}\n ?checked=${this.value === opt.value}\n ?disabled=${this.disabled}\n @change=${() => this._onChange(opt.value)}\n />\n <span>\n <span class=\"card-label\">${opt.label}</span>\n ${opt.description ? html`<span class=\"card-description\">${opt.description}</span>` : nothing}\n </span>\n </label>\n `,\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"radio-cards\": RadioCards;\n }\n}\n"]}
|
package/dist/radio-pills.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare class RadioPills extends LitElement {
|
|
|
20
20
|
options: RadioPillOption[];
|
|
21
21
|
/** Currently selected value. */
|
|
22
22
|
value: string;
|
|
23
|
+
/** Disables every native radio in the group. */
|
|
24
|
+
disabled: boolean;
|
|
23
25
|
private _onChange;
|
|
24
26
|
render(): import("lit-html").TemplateResult<1>;
|
|
25
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-pills.d.ts","sourceRoot":"","sources":["../src/radio-pills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"radio-pills.d.ts","sourceRoot":"","sources":["../src/radio-pills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAID;;;;;;;;;GASG;AACH,qBACa,UAAW,SAAQ,UAAU;;IACxC,OAAgB,MAAM,4BAqEpB;IAEF,wCAAwC;IACR,OAAO,EAAE,eAAe,EAAE,CAAM;IAChE,gCAAgC;IACpB,KAAK,SAAM;IACvB,gDAAgD;IACnB,QAAQ,UAAS;IAI9C,OAAO,CAAC,SAAS;IAMR,MAAM,yCAqBd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
|
package/dist/radio-pills.js
CHANGED
|
@@ -26,6 +26,8 @@ let RadioPills = class RadioPills extends LitElement {
|
|
|
26
26
|
this.options = [];
|
|
27
27
|
/** Currently selected value. */
|
|
28
28
|
this.value = "";
|
|
29
|
+
/** Disables every native radio in the group. */
|
|
30
|
+
this.disabled = false;
|
|
29
31
|
this.#name = `radio-pills-${++instanceCount}`;
|
|
30
32
|
}
|
|
31
33
|
static { this.styles = [
|
|
@@ -37,17 +39,26 @@ let RadioPills = class RadioPills extends LitElement {
|
|
|
37
39
|
.options {
|
|
38
40
|
display: flex;
|
|
39
41
|
flex-wrap: wrap;
|
|
40
|
-
gap: 0.
|
|
42
|
+
gap: 0.5rem;
|
|
41
43
|
}
|
|
42
44
|
.pill {
|
|
43
45
|
display: flex;
|
|
44
46
|
align-items: center;
|
|
45
|
-
gap: 0.
|
|
46
|
-
padding: 0.
|
|
47
|
+
gap: 0.25rem;
|
|
48
|
+
padding: 0.25rem 0.75rem;
|
|
47
49
|
border: 1px solid var(--ui-border, #e2e8f0);
|
|
48
50
|
border-radius: 999px;
|
|
49
51
|
cursor: pointer;
|
|
50
|
-
font-family: var(
|
|
52
|
+
font-family: var(
|
|
53
|
+
--ui-font,
|
|
54
|
+
ui-sans-serif,
|
|
55
|
+
system-ui,
|
|
56
|
+
sans-serif,
|
|
57
|
+
"Apple Color Emoji",
|
|
58
|
+
"Segoe UI Emoji",
|
|
59
|
+
"Segoe UI Symbol",
|
|
60
|
+
"Noto Color Emoji"
|
|
61
|
+
);
|
|
51
62
|
font-size: var(--ui-font-size-sm, 0.75rem);
|
|
52
63
|
color: var(--ui-text, #0f172a);
|
|
53
64
|
}
|
|
@@ -62,10 +73,37 @@ let RadioPills = class RadioPills extends LitElement {
|
|
|
62
73
|
cursor: pointer;
|
|
63
74
|
margin: 0;
|
|
64
75
|
}
|
|
76
|
+
.pill:has(input:focus-visible) {
|
|
77
|
+
outline: none;
|
|
78
|
+
box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
|
|
79
|
+
}
|
|
80
|
+
.pill:has(input:disabled) {
|
|
81
|
+
cursor: not-allowed;
|
|
82
|
+
opacity: 0.6;
|
|
83
|
+
}
|
|
84
|
+
.pill:has(input:disabled) input {
|
|
85
|
+
cursor: not-allowed;
|
|
86
|
+
}
|
|
87
|
+
@media (forced-colors: active) {
|
|
88
|
+
.pill:has(input:focus-visible) {
|
|
89
|
+
outline: 2px solid CanvasText;
|
|
90
|
+
outline-offset: 2px;
|
|
91
|
+
box-shadow: none;
|
|
92
|
+
}
|
|
93
|
+
.pill:has(input:checked) {
|
|
94
|
+
border-color: Highlight;
|
|
95
|
+
}
|
|
96
|
+
.pill:has(input:disabled) {
|
|
97
|
+
color: GrayText;
|
|
98
|
+
opacity: 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
65
101
|
`,
|
|
66
102
|
]; }
|
|
67
103
|
#name;
|
|
68
104
|
_onChange(value) {
|
|
105
|
+
if (this.disabled)
|
|
106
|
+
return;
|
|
69
107
|
this.value = value;
|
|
70
108
|
this.dispatchEvent(new CustomEvent("change", { detail: { value }, bubbles: true, composed: true }));
|
|
71
109
|
}
|
|
@@ -78,6 +116,7 @@ let RadioPills = class RadioPills extends LitElement {
|
|
|
78
116
|
type="radio"
|
|
79
117
|
name=${this.#name}
|
|
80
118
|
?checked=${this.value === opt.value}
|
|
119
|
+
?disabled=${this.disabled}
|
|
81
120
|
@change=${() => this._onChange(opt.value)}
|
|
82
121
|
/>
|
|
83
122
|
<span>${opt.label}</span>
|
|
@@ -93,6 +132,9 @@ __decorate([
|
|
|
93
132
|
__decorate([
|
|
94
133
|
property()
|
|
95
134
|
], RadioPills.prototype, "value", void 0);
|
|
135
|
+
__decorate([
|
|
136
|
+
property({ type: Boolean })
|
|
137
|
+
], RadioPills.prototype, "disabled", void 0);
|
|
96
138
|
RadioPills = __decorate([
|
|
97
139
|
customElement("radio-pills")
|
|
98
140
|
], RadioPills);
|
package/dist/radio-pills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radio-pills.js","sourceRoot":"","sources":["../src/radio-pills.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;AAOrC,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;;;;;;;GASG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;
|
|
1
|
+
{"version":3,"file":"radio-pills.js","sourceRoot":"","sources":["../src/radio-pills.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;AAOrC,IAAI,aAAa,GAAG,CAAC,CAAC;AAEtB;;;;;;;;;GASG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QAwEL,wCAAwC;QACR,YAAO,GAAsB,EAAE,CAAC;QAChE,gCAAgC;QACpB,UAAK,GAAG,EAAE,CAAC;QACvB,gDAAgD;QACnB,aAAQ,GAAG,KAAK,CAAC;QAErC,UAAK,GAAG,eAAe,EAAE,aAAa,EAAE,CAAC;IA8BpD,CAAC;aA5GiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkEF;KACF,AArEqB,CAqEpB;IASO,KAAK,CAAoC;IAE1C,SAAS,CAAC,KAAa;QAC7B,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtG,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;;UAEL,MAAM,CACN,IAAI,CAAC,OAAO,EACZ,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAClB,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAA;;;;uBAIA,IAAI,CAAC,KAAK;2BACN,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;4BACvB,IAAI,CAAC,QAAQ;0BACf,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;;sBAEnC,GAAG,CAAC,KAAK;;WAEpB,CACF;;KAEJ,CAAC;IACJ,CAAC;CACF,CAAA;AApCiC;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;2CAAiC;AAEpD;IAAX,QAAQ,EAAE;yCAAY;AAEM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;4CAAkB;AA7EnC,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CA6GtB","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 RadioPillOption {\n value: string;\n label: string;\n}\n\nlet instanceCount = 0;\n\n/**\n * Single-select group of compact pill-shaped options — for many short,\n * same-shaped choices (a basemap style, a unit toggle). For a handful of\n * choices where a description matters, use `radio-cards` instead. Wraps\n * native radio inputs for keyboard/a11y and fires `change` rather than\n * relying on form submission.\n *\n * @element radio-pills\n * @fires change - A pill was selected; detail: { value }.\n */\n@customElement(\"radio-pills\")\nexport class RadioPills extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .options {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n .pill {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.75rem;\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: 999px;\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 color: var(--ui-text, #0f172a);\n }\n .pill:has(input:checked) {\n border-color: var(--ui-primary, #4f46e5);\n background: var(--ui-surface-muted, #f8fafc);\n }\n .pill input {\n width: 0.85rem;\n height: 0.85rem;\n accent-color: var(--ui-primary, #4f46e5);\n cursor: pointer;\n margin: 0;\n }\n .pill:has(input:focus-visible) {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .pill:has(input:disabled) {\n cursor: not-allowed;\n opacity: 0.6;\n }\n .pill:has(input:disabled) input {\n cursor: not-allowed;\n }\n @media (forced-colors: active) {\n .pill:has(input:focus-visible) {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n .pill:has(input:checked) {\n border-color: Highlight;\n }\n .pill:has(input:disabled) {\n color: GrayText;\n opacity: 1;\n }\n }\n `,\n ];\n\n /** Options to render, one pill each. */\n @property({ attribute: false }) options: RadioPillOption[] = [];\n /** Currently selected value. */\n @property() value = \"\";\n /** Disables every native radio in the group. */\n @property({ type: Boolean }) disabled = false;\n\n readonly #name = `radio-pills-${++instanceCount}`;\n\n private _onChange(value: string) {\n if (this.disabled) return;\n this.value = value;\n this.dispatchEvent(new CustomEvent(\"change\", { detail: { value }, bubbles: true, composed: true }));\n }\n\n override render() {\n return html`\n <div class=\"options\">\n ${repeat(\n this.options,\n (opt) => opt.value,\n (opt) => html`\n <label class=\"pill\">\n <input\n type=\"radio\"\n name=${this.#name}\n ?checked=${this.value === opt.value}\n ?disabled=${this.disabled}\n @change=${() => this._onChange(opt.value)}\n />\n <span>${opt.label}</span>\n </label>\n `,\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"radio-pills\": RadioPills;\n }\n}\n"]}
|
package/dist/relative-time.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relative-time.d.ts","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"relative-time.d.ts","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAC;AAMvC;;;;;;;;GAQG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,4CAA4C;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAElC,OAAO,CAAC,IAAI,CAAc;IAEnC,OAAO,CAAC,MAAM,CAA+C;IAEpD,iBAAiB,SAKzB;IAEQ,oBAAoB,SAI5B;IAEQ,MAAM,yCAKd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
|
package/dist/relative-time.js
CHANGED
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { LitElement,
|
|
7
|
+
import { LitElement, html } from "lit";
|
|
8
8
|
import { customElement, property, state } from "lit/decorators.js";
|
|
9
9
|
import { parseTimestamp, formatRelativeTime } from "./utils/time.js";
|
|
10
10
|
const REFRESH_INTERVAL_MS = 60_000;
|
|
@@ -25,11 +25,6 @@ let RelativeTime = class RelativeTime extends LitElement {
|
|
|
25
25
|
this._now = Date.now();
|
|
26
26
|
this._timer = null;
|
|
27
27
|
}
|
|
28
|
-
static { this.styles = css `
|
|
29
|
-
:host {
|
|
30
|
-
display: inline;
|
|
31
|
-
}
|
|
32
|
-
`; }
|
|
33
28
|
connectedCallback() {
|
|
34
29
|
super.connectedCallback();
|
|
35
30
|
this._timer = setInterval(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relative-time.js","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"relative-time.js","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErE,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEnC;;;;;;;;GAQG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAArC;;QACL,4CAA4C;QAChC,aAAQ,GAAkB,IAAI,CAAC;QAE1B,SAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE3B,WAAM,GAA0C,IAAI,CAAC;IAqB/D,CAAC;IAnBU,iBAAiB;QACxB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,CAAC,EAAE,mBAAmB,CAAC,CAAC;IAC1B,CAAC;IAEQ,oBAAoB;QAC3B,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAEQ,MAAM;QACb,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAA,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAAE,OAAO,IAAI,CAAA,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChE,OAAO,IAAI,CAAA,eAAe,IAAI,CAAC,cAAc,EAAE,IAAI,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;IAClG,CAAC;CACF,CAAA;AAzBa;IAAX,QAAQ,EAAE;8CAAgC;AAE1B;IAAhB,KAAK,EAAE;0CAA2B;AAJxB,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CA2BxB","sourcesContent":["import { LitElement, html } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { parseTimestamp, formatRelativeTime } from \"./utils/time.js\";\n\nconst REFRESH_INTERVAL_MS = 60_000;\n\n/**\n * Inline relative-time display (e.g. \"3 hours ago\"). Accepts either a\n * standard ISO 8601 string or a SQLite `datetime('now')` string\n * (\"YYYY-MM-DD HH:MM:SS\", UTC, no zone marker) via `datetime`. Shows the\n * full date/time in the viewer's local timezone as a hover tooltip, and\n * re-renders on an interval so the text stays current while visible.\n *\n * @element relative-time\n */\n@customElement(\"relative-time\")\nexport class RelativeTime extends LitElement {\n /** Timestamp to render, relative to now. */\n @property() datetime: string | null = null;\n\n @state() private _now = Date.now();\n\n private _timer: ReturnType<typeof setInterval> | null = null;\n\n override connectedCallback() {\n super.connectedCallback();\n this._timer = setInterval(() => {\n this._now = Date.now();\n }, REFRESH_INTERVAL_MS);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n if (this._timer != null) clearInterval(this._timer);\n this._timer = null;\n }\n\n override render() {\n if (!this.datetime) return html``;\n const date = parseTimestamp(this.datetime);\n if (Number.isNaN(date.getTime())) return html`${this.datetime}`;\n return html`<span title=${date.toLocaleString()}>${formatRelativeTime(date, this._now)}</span>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"relative-time\": RelativeTime;\n }\n}\n"]}
|
package/dist/reveal-button.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare class RevealButton extends LitElement {
|
|
|
8
8
|
static styles: import("lit").CSSResult[];
|
|
9
9
|
/** Label shown on the button before it's clicked. */
|
|
10
10
|
label: string;
|
|
11
|
+
/** Disables revealing the slotted content. */
|
|
12
|
+
disabled: boolean;
|
|
11
13
|
private _reveal;
|
|
12
14
|
protected render(): import("lit-html").TemplateResult<1>;
|
|
13
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reveal-button.d.ts","sourceRoot":"","sources":["../src/reveal-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;GAIG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,OAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"reveal-button.d.ts","sourceRoot":"","sources":["../src/reveal-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAI5C;;;;GAIG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,OAAgB,MAAM,4BAgDpB;IAEF,qDAAqD;IAErD,KAAK,EAAE,MAAM,CAA2B;IACxC,8CAA8C;IACjB,QAAQ,UAAS;IAE9C,OAAO,CAAC,OAAO;IAQf,UAAmB,MAAM,yCAOxB;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
|