@f-ewald/components 0.1.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 (102) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +147 -0
  3. package/custom-elements.json +3398 -0
  4. package/dist/address-autocomplete.d.ts +75 -0
  5. package/dist/address-autocomplete.d.ts.map +1 -0
  6. package/dist/address-autocomplete.js +342 -0
  7. package/dist/address-autocomplete.js.map +1 -0
  8. package/dist/animate-confetti.d.ts +53 -0
  9. package/dist/animate-confetti.d.ts.map +1 -0
  10. package/dist/animate-confetti.js +180 -0
  11. package/dist/animate-confetti.js.map +1 -0
  12. package/dist/autocomplete-input.d.ts +73 -0
  13. package/dist/autocomplete-input.d.ts.map +1 -0
  14. package/dist/autocomplete-input.js +309 -0
  15. package/dist/autocomplete-input.js.map +1 -0
  16. package/dist/confirm-dialog.d.ts +36 -0
  17. package/dist/confirm-dialog.d.ts.map +1 -0
  18. package/dist/confirm-dialog.js +191 -0
  19. package/dist/confirm-dialog.js.map +1 -0
  20. package/dist/copy-link-button.d.ts +27 -0
  21. package/dist/copy-link-button.d.ts.map +1 -0
  22. package/dist/copy-link-button.js +84 -0
  23. package/dist/copy-link-button.js.map +1 -0
  24. package/dist/distance-value.d.ts +24 -0
  25. package/dist/distance-value.d.ts.map +1 -0
  26. package/dist/distance-value.js +50 -0
  27. package/dist/distance-value.js.map +1 -0
  28. package/dist/distribution-chart.d.ts +52 -0
  29. package/dist/distribution-chart.d.ts.map +1 -0
  30. package/dist/distribution-chart.js +299 -0
  31. package/dist/distribution-chart.js.map +1 -0
  32. package/dist/icons.d.ts +32 -0
  33. package/dist/icons.d.ts.map +1 -0
  34. package/dist/icons.js +35 -0
  35. package/dist/icons.js.map +1 -0
  36. package/dist/index.d.ts +18 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +18 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/percent-bar-chart.d.ts +29 -0
  41. package/dist/percent-bar-chart.d.ts.map +1 -0
  42. package/dist/percent-bar-chart.js +92 -0
  43. package/dist/percent-bar-chart.js.map +1 -0
  44. package/dist/price-history-chart.d.ts +39 -0
  45. package/dist/price-history-chart.d.ts.map +1 -0
  46. package/dist/price-history-chart.js +217 -0
  47. package/dist/price-history-chart.js.map +1 -0
  48. package/dist/relative-time.d.ts +26 -0
  49. package/dist/relative-time.d.ts.map +1 -0
  50. package/dist/relative-time.js +64 -0
  51. package/dist/relative-time.js.map +1 -0
  52. package/dist/reveal-button.d.ts +19 -0
  53. package/dist/reveal-button.d.ts.map +1 -0
  54. package/dist/reveal-button.js +62 -0
  55. package/dist/reveal-button.js.map +1 -0
  56. package/dist/roman-numeral.d.ts +18 -0
  57. package/dist/roman-numeral.d.ts.map +1 -0
  58. package/dist/roman-numeral.js +54 -0
  59. package/dist/roman-numeral.js.map +1 -0
  60. package/dist/slide-panel.d.ts +27 -0
  61. package/dist/slide-panel.d.ts.map +1 -0
  62. package/dist/slide-panel.js +149 -0
  63. package/dist/slide-panel.js.map +1 -0
  64. package/dist/toast-notification.d.ts +53 -0
  65. package/dist/toast-notification.d.ts.map +1 -0
  66. package/dist/toast-notification.js +173 -0
  67. package/dist/toast-notification.js.map +1 -0
  68. package/dist/tokens.css +21 -0
  69. package/dist/tokens.d.ts +16 -0
  70. package/dist/tokens.d.ts.map +1 -0
  71. package/dist/tokens.js +79 -0
  72. package/dist/tokens.js.map +1 -0
  73. package/dist/utils/distance.d.ts +11 -0
  74. package/dist/utils/distance.d.ts.map +1 -0
  75. package/dist/utils/distance.js +25 -0
  76. package/dist/utils/distance.js.map +1 -0
  77. package/dist/utils/time.d.ts +10 -0
  78. package/dist/utils/time.d.ts.map +1 -0
  79. package/dist/utils/time.js +33 -0
  80. package/dist/utils/time.js.map +1 -0
  81. package/dist/weight-bar-chart.d.ts +29 -0
  82. package/dist/weight-bar-chart.d.ts.map +1 -0
  83. package/dist/weight-bar-chart.js +96 -0
  84. package/dist/weight-bar-chart.js.map +1 -0
  85. package/docs/address-autocomplete.md +68 -0
  86. package/docs/animate-confetti.md +34 -0
  87. package/docs/autocomplete-input.md +79 -0
  88. package/docs/confirm-dialog.md +65 -0
  89. package/docs/copy-link-button.md +46 -0
  90. package/docs/distance-value.md +38 -0
  91. package/docs/distribution-chart.md +51 -0
  92. package/docs/mcp-evaluation.md +31 -0
  93. package/docs/percent-bar-chart.md +40 -0
  94. package/docs/price-history-chart.md +44 -0
  95. package/docs/relative-time.md +37 -0
  96. package/docs/reveal-button.md +43 -0
  97. package/docs/roman-numeral.md +33 -0
  98. package/docs/slide-panel.md +56 -0
  99. package/docs/toast-notification.md +52 -0
  100. package/docs/weight-bar-chart.md +53 -0
  101. package/llms.txt +361 -0
  102. package/package.json +69 -0
@@ -0,0 +1,92 @@
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, svg } from "lit";
8
+ import { customElement, property, state } from "lit/decorators.js";
9
+ import { scaleLinear } from "d3-scale";
10
+ import { tokens } from "./tokens.js";
11
+ const ROW_H = 20;
12
+ const LABEL_W = 56;
13
+ const PCT_W = 36;
14
+ const PAD = { top: 4, right: 4, bottom: 4, left: 4 };
15
+ /**
16
+ * Horizontal bar chart for labeled percentage rows, using D3's linear scale.
17
+ * Each group gets its own labeled row; bars are proportional to percentage of 100.
18
+ *
19
+ * @element percent-bar-chart
20
+ */
21
+ let PercentBarChart = class PercentBarChart extends LitElement {
22
+ constructor() {
23
+ super(...arguments);
24
+ /** Rows to render, one per group. */
25
+ this.groups = [];
26
+ this._width = 0;
27
+ this._ro = null;
28
+ }
29
+ static { this.styles = [
30
+ tokens,
31
+ css `
32
+ :host {
33
+ display: block;
34
+ width: 100%;
35
+ }
36
+ svg {
37
+ display: block;
38
+ overflow: visible;
39
+ }
40
+ `,
41
+ ]; }
42
+ firstUpdated() {
43
+ this._ro = new ResizeObserver((entries) => {
44
+ const w = Math.floor(entries[0].contentRect.width);
45
+ if (w > 0 && w !== this._width)
46
+ this._width = w;
47
+ });
48
+ this._ro.observe(this);
49
+ }
50
+ disconnectedCallback() {
51
+ super.disconnectedCallback();
52
+ this._ro?.disconnect();
53
+ this._ro = null;
54
+ }
55
+ render() {
56
+ if (this._width === 0 || this.groups.length === 0)
57
+ return html ``;
58
+ const innerW = this._width - PAD.left - PAD.right;
59
+ const barMaxW = innerW - LABEL_W - PCT_W;
60
+ const svgH = PAD.top + this.groups.length * ROW_H + PAD.bottom;
61
+ const xScale = scaleLinear().domain([0, 100]).range([0, barMaxW]);
62
+ const rows = this.groups.map((g, i) => {
63
+ const cy = PAD.top + i * ROW_H + ROW_H / 2;
64
+ const bw = Math.max(0, xScale(g.pct));
65
+ return svg `
66
+ <text x=${PAD.left} y=${cy} font-size="10" fill="#64748b"
67
+ text-anchor="start" dominant-baseline="middle">${g.label}</text>
68
+ <rect x=${PAD.left + LABEL_W} y=${cy - 5}
69
+ width=${bw} height="10" rx="2"
70
+ fill=${g.color} fill-opacity="0.82" />
71
+ <text x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size="10" fill="#64748b"
72
+ text-anchor="start" dominant-baseline="middle">${g.pct.toFixed(1)}%</text>
73
+ `;
74
+ });
75
+ return html `
76
+ <svg viewBox="0 0 ${this._width} ${svgH}" width=${this._width} height=${svgH}>
77
+ ${rows}
78
+ </svg>
79
+ `;
80
+ }
81
+ };
82
+ __decorate([
83
+ property({ attribute: false })
84
+ ], PercentBarChart.prototype, "groups", void 0);
85
+ __decorate([
86
+ state()
87
+ ], PercentBarChart.prototype, "_width", void 0);
88
+ PercentBarChart = __decorate([
89
+ customElement("percent-bar-chart")
90
+ ], PercentBarChart);
91
+ export { PercentBarChart };
92
+ //# sourceMappingURL=percent-bar-chart.js.map
@@ -0,0 +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 { 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\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 }\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\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 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 x=${PAD.left} y=${cy} font-size=\"10\" fill=\"#64748b\"\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=\"2\"\n fill=${g.color} fill-opacity=\"0.82\" />\n <text x=${PAD.left + LABEL_W + barMaxW + 4} y=${cy} font-size=\"10\" fill=\"#64748b\"\n text-anchor=\"start\" dominant-baseline=\"middle\">${g.pct.toFixed(1)}%</text>\n `;\n });\n\n return html`\n <svg viewBox=\"0 0 ${this._width} ${svgH}\" width=${this._width} height=${svgH}>\n ${rows}\n </svg>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"percent-bar-chart\": PercentBarChart;\n }\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { LitElement } from "lit";
2
+ export interface PricePoint {
3
+ date: string | null;
4
+ price: number | null;
5
+ eventType: string;
6
+ source?: string | null;
7
+ }
8
+ /**
9
+ * D3-powered SVG line chart for property price history.
10
+ *
11
+ * Uses scaleTime (X) + scaleLinear (Y) from d3-scale and line/area path
12
+ * generators from d3-shape. Adapts to container width via ResizeObserver.
13
+ *
14
+ * @element price-history-chart
15
+ * @prop history - Array of price points (points with null price/date are skipped).
16
+ * @prop yLabels - "auto" (default) | "always" | "never"
17
+ * @prop maxXLabels - Max X-axis date ticks (default 3).
18
+ */
19
+ export declare class PriceHistoryChart extends LitElement {
20
+ history: PricePoint[];
21
+ yLabels: "auto" | "always" | "never";
22
+ maxXLabels: number;
23
+ private _width;
24
+ private _hoveredIdx;
25
+ private _ro;
26
+ connectedCallback(): void;
27
+ disconnectedCallback(): void;
28
+ private get validPoints();
29
+ private get showY();
30
+ static styles: import("lit").CSSResult[];
31
+ private computeLayout;
32
+ render(): import("lit-html").TemplateResult<1>;
33
+ }
34
+ declare global {
35
+ interface HTMLElementTagNameMap {
36
+ "price-history-chart": PriceHistoryChart;
37
+ }
38
+ }
39
+ //# sourceMappingURL=price-history-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"price-history-chart.d.ts","sourceRoot":"","sources":["../src/price-history-chart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AAOjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAiBD;;;;;;;;;;GAUG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IACpB,OAAO,EAAE,UAAU,EAAE,CAAM;IACjB,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAU;IAC5B,UAAU,SAAK;IAE7D,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,WAAW,CAAuB;IAEnD,OAAO,CAAC,GAAG,CAA+B;IAEjC,iBAAiB,SAOzB;IAEQ,oBAAoB,SAI5B;IAED,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAgB,MAAM,4BAgBpB;IAEF,OAAO,CAAC,aAAa;IA8CZ,MAAM,yCAgFd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
@@ -0,0 +1,217 @@
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, svg } from "lit";
8
+ import { customElement, property, state } from "lit/decorators.js";
9
+ import { scaleTime, scaleLinear } from "d3-scale";
10
+ import { line, area } from "d3-shape";
11
+ import { min, max } from "d3-array";
12
+ import { tokens } from "./tokens.js";
13
+ function fmtMoney(n) {
14
+ return `$${n.toLocaleString("en-US")}`;
15
+ }
16
+ function fmtMoneyShort(n) {
17
+ if (n >= 1_000_000)
18
+ return `$${(n / 1_000_000).toFixed(1)}M`;
19
+ if (n >= 1_000)
20
+ return `$${Math.round(n / 1_000)}K`;
21
+ return `$${n.toLocaleString("en-US")}`;
22
+ }
23
+ /**
24
+ * D3-powered SVG line chart for property price history.
25
+ *
26
+ * Uses scaleTime (X) + scaleLinear (Y) from d3-scale and line/area path
27
+ * generators from d3-shape. Adapts to container width via ResizeObserver.
28
+ *
29
+ * @element price-history-chart
30
+ * @prop history - Array of price points (points with null price/date are skipped).
31
+ * @prop yLabels - "auto" (default) | "always" | "never"
32
+ * @prop maxXLabels - Max X-axis date ticks (default 3).
33
+ */
34
+ let PriceHistoryChart = class PriceHistoryChart extends LitElement {
35
+ constructor() {
36
+ super(...arguments);
37
+ this.history = [];
38
+ this.yLabels = "auto";
39
+ this.maxXLabels = 3;
40
+ this._width = 0;
41
+ this._hoveredIdx = null;
42
+ this._ro = null;
43
+ }
44
+ connectedCallback() {
45
+ super.connectedCallback();
46
+ this._ro = new ResizeObserver((entries) => {
47
+ const entry = entries[0];
48
+ if (entry)
49
+ this._width = entry.contentRect.width;
50
+ });
51
+ this._ro.observe(this);
52
+ }
53
+ disconnectedCallback() {
54
+ super.disconnectedCallback();
55
+ this._ro?.disconnect();
56
+ this._ro = null;
57
+ }
58
+ get validPoints() {
59
+ return this.history
60
+ .filter((h) => h.price != null && h.date != null)
61
+ .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
62
+ }
63
+ get showY() {
64
+ return this.yLabels === "always" || (this.yLabels === "auto" && this._width >= 260);
65
+ }
66
+ static { this.styles = [
67
+ tokens,
68
+ css `
69
+ :host {
70
+ display: block;
71
+ width: 100%;
72
+ }
73
+ .wrap {
74
+ position: relative;
75
+ width: 100%;
76
+ }
77
+ svg {
78
+ display: block;
79
+ overflow: visible;
80
+ }
81
+ `,
82
+ ]; }
83
+ computeLayout() {
84
+ if (this._width < 10)
85
+ return null;
86
+ const points = this.validPoints;
87
+ if (points.length < 2)
88
+ return null;
89
+ const H = 180;
90
+ const MT = 20;
91
+ const MB = 30;
92
+ const MR = 12;
93
+ const ML = this.showY ? 56 : 12;
94
+ const plotW = Math.max(this._width - ML - MR, 1);
95
+ const plotH = Math.max(H - MT - MB, 1);
96
+ const bottomY = MT + plotH;
97
+ const prices = points.map((p) => p.price);
98
+ const dates = points.map((p) => new Date(p.date));
99
+ const minPrice = min(prices);
100
+ const maxPrice = max(prices);
101
+ const pad = (maxPrice - minPrice) * 0.05 || maxPrice * 0.05;
102
+ const xScale = scaleTime()
103
+ .domain([min(dates), max(dates)])
104
+ .range([ML, ML + plotW]);
105
+ const yScale = scaleLinear()
106
+ .domain([minPrice - pad, maxPrice + pad])
107
+ .range([bottomY, MT]);
108
+ const lineFn = line()
109
+ .x((p) => xScale(new Date(p.date)))
110
+ .y((p) => yScale(p.price));
111
+ const areaFn = area()
112
+ .x((p) => xScale(new Date(p.date)))
113
+ .y0(bottomY)
114
+ .y1((p) => yScale(p.price));
115
+ const plotted = points.map((p) => ({
116
+ ...p,
117
+ x: xScale(new Date(p.date)),
118
+ y: yScale(p.price),
119
+ }));
120
+ return { points, plotted, H, MT, ML, MR, plotW, plotH, bottomY, minPrice, maxPrice, xScale, yScale, lineFn, areaFn };
121
+ }
122
+ render() {
123
+ const layout = this.computeLayout();
124
+ if (!layout)
125
+ return html ``;
126
+ const { points, plotted, H, MT, ML, MR, plotW, plotH, xScale, yScale, lineFn, areaFn } = layout;
127
+ const lineD = lineFn(points) ?? "";
128
+ const areaD = areaFn(points) ?? "";
129
+ const hIdx = this._hoveredIdx;
130
+ const hovPt = hIdx !== null ? plotted[hIdx] : null;
131
+ const tooltipEl = hovPt ? (() => {
132
+ const tipText = `${fmtMoney(hovPt.price)} · ${hovPt.date ? new Date(hovPt.date).toLocaleDateString("en-US", { month: "short", year: "numeric" }) : ""} · ${hovPt.eventType}`;
133
+ const tipW = Math.min(tipText.length * 6.5 + 16, this._width - ML - MR);
134
+ const tipH = 24;
135
+ const tipGap = 8;
136
+ const above = hovPt.y > plotH / 2 + MT;
137
+ const tipRectY = above ? hovPt.y - tipGap - tipH : hovPt.y + tipGap;
138
+ const tipX = Math.min(Math.max(hovPt.x - tipW / 2, ML), this._width - MR - tipW);
139
+ return svg `
140
+ <g pointer-events="none">
141
+ <rect x="${tipX}" y="${tipRectY}" width="${tipW}" height="${tipH}"
142
+ rx="4" fill="rgba(15,23,42,0.88)" />
143
+ <text x="${tipX + tipW / 2}" y="${tipRectY + 15.5}"
144
+ text-anchor="middle" fill="white" font-size="11"
145
+ font-family="ui-sans-serif,system-ui,sans-serif">${tipText}</text>
146
+ </g>
147
+ `;
148
+ })() : "";
149
+ const xTicks = xScale.ticks(this.maxXLabels).map((d, i, arr) => {
150
+ const x = xScale(d);
151
+ const label = d.toLocaleDateString("en-US", { month: "short", year: "numeric" });
152
+ const anchor = i === 0 ? "start" : i === arr.length - 1 ? "end" : "middle";
153
+ return svg `
154
+ <text x="${x}" y="${H - 6}" text-anchor="${anchor}" font-size="10" fill="#64748b"
155
+ font-family="ui-sans-serif,system-ui,sans-serif">${label}</text>
156
+ `;
157
+ });
158
+ const yTicks = this.showY ? yScale.ticks(3).map((v, i, arr) => {
159
+ const y = yScale(v);
160
+ const isFirst = i === 0;
161
+ const isLast = i === arr.length - 1;
162
+ return svg `
163
+ <line x1="${ML - 4}" y1="${y}" x2="${ML + plotW}" y2="${y}"
164
+ stroke="#e2e8f0" stroke-width="1" />
165
+ ${isFirst || isLast ? svg `
166
+ <text x="${ML - 6}" y="${y + 4}" text-anchor="end" font-size="10" fill="#64748b"
167
+ font-family="ui-sans-serif,system-ui,sans-serif">${fmtMoneyShort(v)}</text>
168
+ ` : ""}
169
+ `;
170
+ }) : [];
171
+ return html `
172
+ <div class="wrap">
173
+ <svg width="${this._width}" height="${H}">
174
+ <defs>
175
+ <linearGradient id="phg" x1="0" y1="0" x2="0" y2="1">
176
+ <stop offset="0%" stop-color="#4f46e5" stop-opacity="0.25" />
177
+ <stop offset="100%" stop-color="#4f46e5" stop-opacity="0" />
178
+ </linearGradient>
179
+ </defs>
180
+ ${yTicks}
181
+ <path d="${areaD}" fill="url(#phg)" />
182
+ <path d="${lineD}" fill="none" stroke="#4f46e5" stroke-width="2.5"
183
+ stroke-linejoin="round" stroke-linecap="round" />
184
+ ${plotted.map((p, i) => svg `
185
+ <circle cx="${p.x}" cy="${p.y}" r="${i === hIdx ? 7 : 5}"
186
+ fill="#4f46e5" stroke="#fff" stroke-width="2"
187
+ style="cursor:pointer"
188
+ @pointerenter=${() => { this._hoveredIdx = i; }}
189
+ @pointerleave=${() => { this._hoveredIdx = null; }} />
190
+ `)}
191
+ ${xTicks}
192
+ ${tooltipEl}
193
+ </svg>
194
+ </div>
195
+ `;
196
+ }
197
+ };
198
+ __decorate([
199
+ property({ type: Array })
200
+ ], PriceHistoryChart.prototype, "history", void 0);
201
+ __decorate([
202
+ property({ attribute: "y-labels" })
203
+ ], PriceHistoryChart.prototype, "yLabels", void 0);
204
+ __decorate([
205
+ property({ type: Number, attribute: "max-x-labels" })
206
+ ], PriceHistoryChart.prototype, "maxXLabels", void 0);
207
+ __decorate([
208
+ state()
209
+ ], PriceHistoryChart.prototype, "_width", void 0);
210
+ __decorate([
211
+ state()
212
+ ], PriceHistoryChart.prototype, "_hoveredIdx", void 0);
213
+ PriceHistoryChart = __decorate([
214
+ customElement("price-history-chart")
215
+ ], PriceHistoryChart);
216
+ export { PriceHistoryChart };
217
+ //# sourceMappingURL=price-history-chart.js.map
@@ -0,0 +1 @@
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 }\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"]}
@@ -0,0 +1,26 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Inline relative-time display (e.g. "3 hours ago"). Accepts either a
4
+ * standard ISO 8601 string or a SQLite `datetime('now')` string
5
+ * ("YYYY-MM-DD HH:MM:SS", UTC, no zone marker) via `datetime`. Shows the
6
+ * full date/time in the viewer's local timezone as a hover tooltip, and
7
+ * re-renders on an interval so the text stays current while visible.
8
+ *
9
+ * @element relative-time
10
+ */
11
+ export declare class RelativeTime extends LitElement {
12
+ static styles: import("lit").CSSResult;
13
+ /** Timestamp to render, relative to now. */
14
+ datetime: string | null;
15
+ private _now;
16
+ private _timer;
17
+ connectedCallback(): void;
18
+ disconnectedCallback(): void;
19
+ render(): import("lit-html").TemplateResult<1>;
20
+ }
21
+ declare global {
22
+ interface HTMLElementTagNameMap {
23
+ "relative-time": RelativeTime;
24
+ }
25
+ }
26
+ //# sourceMappingURL=relative-time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relative-time.d.ts","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAM5C;;;;;;;;GAQG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,OAAgB,MAAM,0BAIpB;IAEF,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"}
@@ -0,0 +1,64 @@
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 { parseTimestamp, formatRelativeTime } from "./utils/time.js";
10
+ const REFRESH_INTERVAL_MS = 60_000;
11
+ /**
12
+ * Inline relative-time display (e.g. "3 hours ago"). Accepts either a
13
+ * standard ISO 8601 string or a SQLite `datetime('now')` string
14
+ * ("YYYY-MM-DD HH:MM:SS", UTC, no zone marker) via `datetime`. Shows the
15
+ * full date/time in the viewer's local timezone as a hover tooltip, and
16
+ * re-renders on an interval so the text stays current while visible.
17
+ *
18
+ * @element relative-time
19
+ */
20
+ let RelativeTime = class RelativeTime extends LitElement {
21
+ constructor() {
22
+ super(...arguments);
23
+ /** Timestamp to render, relative to now. */
24
+ this.datetime = null;
25
+ this._now = Date.now();
26
+ this._timer = null;
27
+ }
28
+ static { this.styles = css `
29
+ :host {
30
+ display: inline;
31
+ }
32
+ `; }
33
+ connectedCallback() {
34
+ super.connectedCallback();
35
+ this._timer = setInterval(() => {
36
+ this._now = Date.now();
37
+ }, REFRESH_INTERVAL_MS);
38
+ }
39
+ disconnectedCallback() {
40
+ super.disconnectedCallback();
41
+ if (this._timer != null)
42
+ clearInterval(this._timer);
43
+ this._timer = null;
44
+ }
45
+ render() {
46
+ if (!this.datetime)
47
+ return html ``;
48
+ const date = parseTimestamp(this.datetime);
49
+ if (Number.isNaN(date.getTime()))
50
+ return html `${this.datetime}`;
51
+ return html `<span title=${date.toLocaleString()}>${formatRelativeTime(date, this._now)}</span>`;
52
+ }
53
+ };
54
+ __decorate([
55
+ property()
56
+ ], RelativeTime.prototype, "datetime", void 0);
57
+ __decorate([
58
+ state()
59
+ ], RelativeTime.prototype, "_now", void 0);
60
+ RelativeTime = __decorate([
61
+ customElement("relative-time")
62
+ ], RelativeTime);
63
+ export { RelativeTime };
64
+ //# sourceMappingURL=relative-time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relative-time.js","sourceRoot":"","sources":["../src/relative-time.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,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;;QAOL,4CAA4C;QAChC,aAAQ,GAAkB,IAAI,CAAC;QAE1B,SAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE3B,WAAM,GAA0C,IAAI,CAAC;IAqB/D,CAAC;aAhCiB,WAAM,GAAG,GAAG,CAAA;;;;GAI3B,AAJqB,CAIpB;IASO,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;AAVxB,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAiCxB","sourcesContent":["import { LitElement, css, 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 static override styles = css`\n :host {\n display: inline;\n }\n `;\n\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"]}
@@ -0,0 +1,19 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Button that reveals hidden slotted content when clicked.
4
+ *
5
+ * @element reveal-button
6
+ */
7
+ export declare class RevealButton extends LitElement {
8
+ static styles: import("lit").CSSResult[];
9
+ /** Label shown on the button before it's clicked. */
10
+ label: string;
11
+ private _reveal;
12
+ protected render(): import("lit-html").TemplateResult<1>;
13
+ }
14
+ declare global {
15
+ interface HTMLElementTagNameMap {
16
+ "reveal-button": RevealButton;
17
+ }
18
+ }
19
+ //# sourceMappingURL=reveal-button.d.ts.map
@@ -0,0 +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,4BAoBpB;IAEF,qDAAqD;IAErD,KAAK,EAAE,MAAM,CAA2B;IAExC,OAAO,CAAC,OAAO;IAOf,UAAmB,MAAM,yCAKxB;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
@@ -0,0 +1,62 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, css, html } from "lit";
8
+ import { customElement, property } from "lit/decorators.js";
9
+ import { tokens } from "./tokens.js";
10
+ /**
11
+ * Button that reveals hidden slotted content when clicked.
12
+ *
13
+ * @element reveal-button
14
+ */
15
+ let RevealButton = class RevealButton extends LitElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ /** Label shown on the button before it's clicked. */
19
+ this.label = "Reveal hidden content";
20
+ }
21
+ static { this.styles = [
22
+ tokens,
23
+ css `
24
+ .hidden {
25
+ display: none;
26
+ }
27
+ button {
28
+ font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);
29
+ font-size: var(--ui-font-size, 0.875rem);
30
+ background: var(--ui-primary, #4f46e5);
31
+ color: #fff;
32
+ border: none;
33
+ border-radius: var(--ui-radius-sm, 0.25rem);
34
+ padding: 0.5rem 0.9rem;
35
+ cursor: pointer;
36
+ }
37
+ button:hover {
38
+ background: var(--ui-primary-hover, #4338ca);
39
+ }
40
+ `,
41
+ ]; }
42
+ _reveal() {
43
+ const div = this.shadowRoot.querySelector("div");
44
+ const button = this.shadowRoot.querySelector("button");
45
+ div?.classList.toggle("hidden");
46
+ button?.classList.toggle("hidden");
47
+ }
48
+ render() {
49
+ return html `
50
+ <div class="hidden"><slot></slot></div>
51
+ <button @click="${this._reveal}">${this.label}</button>
52
+ `;
53
+ }
54
+ };
55
+ __decorate([
56
+ property({ type: String })
57
+ ], RevealButton.prototype, "label", void 0);
58
+ RevealButton = __decorate([
59
+ customElement("reveal-button")
60
+ ], RevealButton);
61
+ export { RevealButton };
62
+ //# sourceMappingURL=reveal-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reveal-button.js","sourceRoot":"","sources":["../src/reveal-button.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;GAIG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAArC;;QAuBL,qDAAqD;QAErD,UAAK,GAAW,uBAAuB,CAAC;IAe1C,CAAC;aAvCiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;KAiBF;KACF,AApBqB,CAoBpB;IAMM,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,UAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxD,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAEkB,MAAM;QACvB,OAAO,IAAI,CAAA;;wBAES,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,KAAK;KAC9C,CAAC;IACJ,CAAC;CACF,CAAA;AAfC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CACa;AAzB7B,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CAwCxB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * Button that reveals hidden slotted content when clicked.\n *\n * @element reveal-button\n */\n@customElement(\"reveal-button\")\nexport class RevealButton extends LitElement {\n static override styles = [\n tokens,\n css`\n .hidden {\n display: none;\n }\n button {\n font-family: var(--ui-font, ui-sans-serif, system-ui, sans-serif);\n font-size: var(--ui-font-size, 0.875rem);\n background: var(--ui-primary, #4f46e5);\n color: #fff;\n border: none;\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 0.9rem;\n cursor: pointer;\n }\n button:hover {\n background: var(--ui-primary-hover, #4338ca);\n }\n `,\n ];\n\n /** Label shown on the button before it's clicked. */\n @property({ type: String })\n label: string = \"Reveal hidden content\";\n\n private _reveal() {\n const div = this.shadowRoot!.querySelector(\"div\");\n const button = this.shadowRoot!.querySelector(\"button\");\n div?.classList.toggle(\"hidden\");\n button?.classList.toggle(\"hidden\");\n }\n\n protected override render() {\n return html`\n <div class=\"hidden\"><slot></slot></div>\n <button @click=\"${this._reveal}\">${this.label}</button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"reveal-button\": RevealButton;\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * Converts an integer to a roman numeral inline.
4
+ *
5
+ * @element roman-numeral
6
+ */
7
+ export declare class RomanNumeral extends LitElement {
8
+ /** Integer value to render as a roman numeral. */
9
+ value?: number;
10
+ protected render(): import("lit-html").TemplateResult<1>;
11
+ private _convertToRoman;
12
+ }
13
+ declare global {
14
+ interface HTMLElementTagNameMap {
15
+ "roman-numeral": RomanNumeral;
16
+ }
17
+ }
18
+ //# sourceMappingURL=roman-numeral.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roman-numeral.d.ts","sourceRoot":"","sources":["../src/roman-numeral.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAC;AAmBvC;;;;GAIG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,kDAAkD;IAElD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,UAAmB,MAAM,yCAExB;IAED,OAAO,CAAC,eAAe;CAgBxB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}