queria 0.0.0 → 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 (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -1
  3. package/dist/boot.d.ts +24 -0
  4. package/dist/boot.js +137 -0
  5. package/dist/boot.js.map +1 -0
  6. package/dist/client.d.ts +56 -0
  7. package/dist/client.js +194 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/elements/define.d.ts +1 -0
  10. package/dist/elements/define.js +4 -0
  11. package/dist/elements/define.js.map +1 -0
  12. package/dist/elements/index.d.ts +40 -0
  13. package/dist/elements/index.js +144 -0
  14. package/dist/elements/index.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.js +4 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/react/Chart.d.ts +12 -0
  19. package/dist/react/Chart.js +42 -0
  20. package/dist/react/Chart.js.map +1 -0
  21. package/dist/react/DataMap.d.ts +12 -0
  22. package/dist/react/DataMap.js +44 -0
  23. package/dist/react/DataMap.js.map +1 -0
  24. package/dist/react/MapView.d.ts +13 -0
  25. package/dist/react/MapView.js +31 -0
  26. package/dist/react/MapView.js.map +1 -0
  27. package/dist/react/PoweredBy.d.ts +2 -0
  28. package/dist/react/PoweredBy.js +5 -0
  29. package/dist/react/PoweredBy.js.map +1 -0
  30. package/dist/react/index.d.ts +5 -0
  31. package/dist/react/index.js +6 -0
  32. package/dist/react/index.js.map +1 -0
  33. package/dist/react/query.d.ts +20 -0
  34. package/dist/react/query.js +50 -0
  35. package/dist/react/query.js.map +1 -0
  36. package/dist/render/attribution.d.ts +6 -0
  37. package/dist/render/attribution.js +17 -0
  38. package/dist/render/attribution.js.map +1 -0
  39. package/dist/render/chart.d.ts +27 -0
  40. package/dist/render/chart.js +50 -0
  41. package/dist/render/chart.js.map +1 -0
  42. package/dist/render/data-map.d.ts +61 -0
  43. package/dist/render/data-map.js +200 -0
  44. package/dist/render/data-map.js.map +1 -0
  45. package/dist/render/escape.d.ts +2 -0
  46. package/dist/render/escape.js +4 -0
  47. package/dist/render/escape.js.map +1 -0
  48. package/dist/render/index.d.ts +5 -0
  49. package/dist/render/index.js +6 -0
  50. package/dist/render/index.js.map +1 -0
  51. package/dist/render/map.d.ts +7 -0
  52. package/dist/render/map.js +9 -0
  53. package/dist/render/map.js.map +1 -0
  54. package/dist/render/poweredBy.d.ts +2 -0
  55. package/dist/render/poweredBy.js +5 -0
  56. package/dist/render/poweredBy.js.map +1 -0
  57. package/dist/sql.d.ts +10 -0
  58. package/dist/sql.js +13 -0
  59. package/dist/sql.js.map +1 -0
  60. package/package.json +93 -1
  61. package/src/boot.test.ts +65 -0
  62. package/src/boot.ts +141 -0
  63. package/src/client.test.ts +77 -0
  64. package/src/client.ts +247 -0
  65. package/src/elements/define.ts +4 -0
  66. package/src/elements/index.ts +151 -0
  67. package/src/index.ts +12 -0
  68. package/src/react/Chart.tsx +49 -0
  69. package/src/react/DataMap.tsx +52 -0
  70. package/src/react/MapView.tsx +45 -0
  71. package/src/react/PoweredBy.tsx +4 -0
  72. package/src/react/index.ts +5 -0
  73. package/src/react/query.tsx +64 -0
  74. package/src/render/attribution.test.ts +22 -0
  75. package/src/render/attribution.ts +21 -0
  76. package/src/render/chart.test.ts +23 -0
  77. package/src/render/chart.ts +80 -0
  78. package/src/render/data-map.test.ts +40 -0
  79. package/src/render/data-map.ts +230 -0
  80. package/src/render/escape.ts +4 -0
  81. package/src/render/index.ts +12 -0
  82. package/src/render/map.ts +18 -0
  83. package/src/render/poweredBy.ts +6 -0
  84. package/src/sql.test.ts +21 -0
  85. package/src/sql.ts +19 -0
@@ -0,0 +1,144 @@
1
+ import { connect, parseDatasets } from "../client.js";
2
+ import { attributionHtml } from "../render/attribution.js";
3
+ import { renderChart } from "../render/chart.js";
4
+ import { renderMap } from "../render/data-map.js";
5
+ import { esc } from "../render/escape.js";
6
+ import { poweredByHtml } from "../render/poweredBy.js";
7
+ /**
8
+ * <queria-chart datasets="queria/e_stat" sql="..." spec='{"mark": "line", ...}'>
9
+ * Runs the SQL and draws the rows with the Vega-Lite spec, followed by the sources of the datasets.
10
+ * Instead of sql, `rows` takes the rows as JSON, for pages that run the SQL at build time. Declare the datasets the
11
+ * rows came from in `datasets` so their sources are shown.
12
+ * `api-url` replaces the Queria API, for example with a staging host.
13
+ */
14
+ export class QueriaChart extends HTMLElement {
15
+ static observedAttributes = ["datasets", "sql", "spec", "rows", "api-url"];
16
+ #run = 0;
17
+ #pending = false;
18
+ #finalize = null;
19
+ connectedCallback() {
20
+ this.#schedule();
21
+ }
22
+ attributeChangedCallback() {
23
+ if (this.isConnected)
24
+ this.#schedule();
25
+ }
26
+ disconnectedCallback() {
27
+ this.#run++;
28
+ this.#clear();
29
+ }
30
+ /** Draw once per task: an upgrade calls attributeChangedCallback for every attribute, then connectedCallback. */
31
+ #schedule() {
32
+ if (this.#pending)
33
+ return;
34
+ this.#pending = true;
35
+ queueMicrotask(() => {
36
+ this.#pending = false;
37
+ if (this.isConnected)
38
+ this.#draw();
39
+ });
40
+ }
41
+ #clear() {
42
+ this.#finalize?.();
43
+ this.#finalize = null;
44
+ }
45
+ async #draw() {
46
+ const [datasets, sql, spec, rows] = ["datasets", "sql", "spec", "rows"].map((a) => this.getAttribute(a));
47
+ if (!spec || (!rows && !sql))
48
+ return;
49
+ const run = ++this.#run;
50
+ this.#clear();
51
+ this.innerHTML = '<p class="queria-note">Loading…</p>';
52
+ try {
53
+ const conn = connect({ datasets: parseDatasets(datasets ?? ""), apiUrl: this.getAttribute("api-url") ?? undefined });
54
+ // With rows, the page ran the SQL itself; show every declared dataset as a source.
55
+ const [data, sources] = await Promise.all([sql ? conn.sql(sql) : JSON.parse(rows ?? "[]"), conn.sources(sql ?? undefined)]);
56
+ if (run !== this.#run)
57
+ return;
58
+ this.innerHTML = `<div></div>${attributionHtml(sources)}`;
59
+ const { finalize } = await renderChart(this.firstElementChild, JSON.parse(spec), data);
60
+ if (run === this.#run)
61
+ this.#finalize = finalize;
62
+ else
63
+ finalize();
64
+ }
65
+ catch (e) {
66
+ if (run === this.#run)
67
+ this.innerHTML = `<p class="queria-note">${esc(String(e))}</p>`;
68
+ }
69
+ }
70
+ }
71
+ /**
72
+ * <queria-map datasets="queria/e_stat" sql="..." layer='{"area": "city", "code": "lg_code", "color": "population"}'>
73
+ * Runs the SQL and puts the rows on a map by area code or by lng/lat, followed by the sources of the datasets.
74
+ * `rows`, `api-url` work as on <queria-chart>. `theme` is light or dark; `map-style` takes another MapLibre style URL.
75
+ * Include maplibre-gl's CSS in the page. The map height is the CSS variable --queria-map-height (400px by default).
76
+ */
77
+ export class QueriaMap extends HTMLElement {
78
+ static observedAttributes = ["datasets", "sql", "layer", "rows", "api-url", "theme", "map-style"];
79
+ #run = 0;
80
+ #pending = false;
81
+ #finalize = null;
82
+ connectedCallback() {
83
+ this.#schedule();
84
+ }
85
+ attributeChangedCallback() {
86
+ if (this.isConnected)
87
+ this.#schedule();
88
+ }
89
+ disconnectedCallback() {
90
+ this.#run++;
91
+ this.#clear();
92
+ }
93
+ #schedule() {
94
+ if (this.#pending)
95
+ return;
96
+ this.#pending = true;
97
+ queueMicrotask(() => {
98
+ this.#pending = false;
99
+ if (this.isConnected)
100
+ this.#draw();
101
+ });
102
+ }
103
+ #clear() {
104
+ this.#finalize?.();
105
+ this.#finalize = null;
106
+ }
107
+ async #draw() {
108
+ const [datasets, sql, layer, rows, theme, style] = ["datasets", "sql", "layer", "rows", "theme", "map-style"].map((a) => this.getAttribute(a));
109
+ if (!layer || (!rows && !sql))
110
+ return;
111
+ const run = ++this.#run;
112
+ this.#clear();
113
+ this.innerHTML = '<p class="queria-note">Loading…</p>';
114
+ try {
115
+ const conn = connect({ datasets: parseDatasets(datasets ?? ""), apiUrl: this.getAttribute("api-url") ?? undefined });
116
+ const [data, sources] = await Promise.all([sql ? conn.sql(sql) : JSON.parse(rows ?? "[]"), conn.sources(sql ?? undefined)]);
117
+ if (run !== this.#run)
118
+ return;
119
+ this.innerHTML = `<div style="height:var(--queria-map-height,400px)"></div>${attributionHtml(sources)}`;
120
+ const { finalize } = await renderMap(this.firstElementChild, JSON.parse(layer), data, {
121
+ theme: theme === "dark" ? "dark" : "light",
122
+ ...(style ? { style } : {}),
123
+ });
124
+ if (run === this.#run)
125
+ this.#finalize = finalize;
126
+ else
127
+ finalize();
128
+ }
129
+ catch (e) {
130
+ if (run === this.#run)
131
+ this.innerHTML = `<p class="queria-note">${esc(String(e))}</p>`;
132
+ }
133
+ }
134
+ }
135
+ /** <queria-powered-by> */
136
+ export class QueriaPoweredBy extends HTMLElement {
137
+ connectedCallback() {
138
+ this.innerHTML = poweredByHtml();
139
+ }
140
+ }
141
+ const elements = { "queria-chart": QueriaChart, "queria-map": QueriaMap, "queria-powered-by": QueriaPoweredBy };
142
+ /** Register the custom elements. Safe to call more than once. */
143
+ export const defineElements = () => Object.entries(elements).forEach(([name, cls]) => customElements.get(name) ?? customElements.define(name, cls));
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/elements/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { closeAll, connect, plain, type Connection, type ConnectOptions, type Dataset, type Declared, type License, } from "./client.js";
2
+ export { lit } from "./sql.js";
3
+ export * from "./render/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { closeAll, connect, plain, } from "./client.js";
2
+ export { lit } from "./sql.js";
3
+ export * from "./render/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,OAAO,EACP,KAAK,GAMN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type ChartSpec } from "../render/chart.js";
2
+ type Props = {
3
+ spec: ChartSpec;
4
+ className?: string;
5
+ } & ({
6
+ sql: string;
7
+ } | {
8
+ rows: readonly Record<string, unknown>[];
9
+ });
10
+ /** A Vega-Lite chart of the SQL result (or of `rows`), followed by the sources of the datasets. */
11
+ export declare const Chart: ({ spec, className, ...data }: Props) => import("react").JSX.Element;
12
+ export {};
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { attributionHtml } from "../render/attribution.js";
4
+ import { renderChart } from "../render/chart.js";
5
+ import { useQueria } from "./query.js";
6
+ /** A Vega-Lite chart of the SQL result (or of `rows`), followed by the sources of the datasets. */
7
+ export const Chart = ({ spec, className = "queria-chart", ...data }) => {
8
+ const conn = useQueria();
9
+ const el = useRef(null);
10
+ const [state, setState] = useState({ sources: [] });
11
+ const sql = "sql" in data ? data.sql : null;
12
+ const rows = "rows" in data ? data.rows : null;
13
+ // Compare the spec by content: a spec written inline is a new object on every render of the parent.
14
+ const specKey = JSON.stringify(spec);
15
+ useEffect(() => {
16
+ let alive = true;
17
+ let finalize;
18
+ const load = sql === null ? Promise.all([rows ?? [], conn.sources()]) : Promise.all([conn.sql(sql), conn.sources(sql)]);
19
+ load
20
+ .then(async ([values, sources]) => {
21
+ if (!alive || !el.current)
22
+ return;
23
+ setState({ sources });
24
+ ({ finalize } = await renderChart(el.current, spec, values));
25
+ if (!alive)
26
+ finalize();
27
+ })
28
+ .catch((error) => {
29
+ if (!alive)
30
+ return;
31
+ // finalize stops the previous chart but leaves its drawing in the element.
32
+ el.current?.replaceChildren();
33
+ setState({ sources: [], error });
34
+ });
35
+ return () => {
36
+ alive = false;
37
+ finalize?.();
38
+ };
39
+ }, [conn, sql, rows, specKey]);
40
+ return (_jsxs("div", { className: className, children: [state.error ? _jsx("p", { className: "queria-note", children: String(state.error) }) : null, _jsx("div", { ref: el }), _jsx("div", { dangerouslySetInnerHTML: { __html: attributionHtml(state.sources) } })] }));
41
+ };
42
+ //# sourceMappingURL=Chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chart.js","sourceRoot":"","sources":["../../src/react/Chart.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type MapLayer, type MapRenderOptions } from "../render/data-map.js";
2
+ type Props = {
3
+ layer: MapLayer;
4
+ className?: string;
5
+ } & MapRenderOptions & ({
6
+ sql: string;
7
+ } | {
8
+ rows: readonly Record<string, unknown>[];
9
+ });
10
+ /** The SQL result (or `rows`) on a map by area code or by lng/lat, followed by the sources. Its height is the CSS variable --queria-map-height (400px by default). */
11
+ export declare const DataMap: ({ layer, className, style, theme, ...data }: Props) => import("react").JSX.Element;
12
+ export {};
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { attributionHtml } from "../render/attribution.js";
4
+ import { renderMap } from "../render/data-map.js";
5
+ import { useQueria } from "./query.js";
6
+ /** The SQL result (or `rows`) on a map by area code or by lng/lat, followed by the sources. Its height is the CSS variable --queria-map-height (400px by default). */
7
+ export const DataMap = ({ layer, className = "queria-map", style, theme, ...data }) => {
8
+ const conn = useQueria();
9
+ const el = useRef(null);
10
+ const [state, setState] = useState({ sources: [] });
11
+ const sql = "sql" in data ? data.sql : null;
12
+ const rows = "rows" in data ? data.rows : null;
13
+ // Inline objects are new on every render of the parent, so compare them by content.
14
+ const key = JSON.stringify([layer, style, theme]);
15
+ useEffect(() => {
16
+ let alive = true;
17
+ let finalize;
18
+ // Each map gets its own element: a map removed after the next one started takes its class off its element.
19
+ const box = document.createElement("div");
20
+ box.style.height = "100%";
21
+ el.current?.append(box);
22
+ const load = sql === null ? Promise.all([rows ?? [], conn.sources()]) : Promise.all([conn.sql(sql), conn.sources(sql)]);
23
+ load
24
+ .then(async ([values, sources]) => {
25
+ if (!alive)
26
+ return;
27
+ setState({ sources });
28
+ ({ finalize } = await renderMap(box, layer, values, { style, theme }));
29
+ if (!alive)
30
+ finalize();
31
+ })
32
+ .catch((error) => {
33
+ if (alive)
34
+ setState({ sources: [], error });
35
+ });
36
+ return () => {
37
+ alive = false;
38
+ finalize?.();
39
+ box.remove();
40
+ };
41
+ }, [conn, sql, rows, key]);
42
+ return (_jsxs("div", { className: className, children: [state.error ? _jsx("p", { className: "queria-note", children: String(state.error) }) : null, _jsx("div", { ref: el, style: { height: "var(--queria-map-height, 400px)" } }), _jsx("div", { dangerouslySetInnerHTML: { __html: attributionHtml(state.sources) } })] }));
43
+ };
44
+ //# sourceMappingURL=DataMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataMap.js","sourceRoot":"","sources":["../../src/react/DataMap.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Map, MapOptions, StyleSpecification } from "maplibre-gl";
2
+ import { type ReactNode } from "react";
3
+ type Props = {
4
+ style: StyleSpecification | string;
5
+ /** Called once when the map is created. Attach handlers here and return a cleanup. */
6
+ onReady?: (map: Map) => void | (() => void);
7
+ options?: Omit<MapOptions, "container" | "style">;
8
+ className?: string;
9
+ children?: ReactNode;
10
+ };
11
+ /** A MapLibre map. Passing a new style applies only the diff. */
12
+ export declare const MapView: ({ style, onReady, options, className, children }: Props) => import("react").JSX.Element;
13
+ export {};
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ import { mountMap } from "../render/map.js";
4
+ /** A MapLibre map. Passing a new style applies only the diff. */
5
+ export const MapView = ({ style, onReady, options, className = "queria-map", children }) => {
6
+ const container = useRef(null);
7
+ const handle = useRef(null);
8
+ useEffect(() => {
9
+ if (!container.current)
10
+ return;
11
+ const h = mountMap(container.current, style, options);
12
+ handle.current = h;
13
+ const cleanup = h.map.then((m) => onReady?.(m));
14
+ return () => {
15
+ cleanup.then((f) => f?.(), console.error);
16
+ h.destroy();
17
+ handle.current = null;
18
+ };
19
+ // Create the map once; style changes are applied below.
20
+ }, []);
21
+ // The map is created with the first style; apply only later changes.
22
+ const applied = useRef(style);
23
+ useEffect(() => {
24
+ if (applied.current === style)
25
+ return;
26
+ applied.current = style;
27
+ handle.current?.map.then((m) => m.setStyle(style), console.error);
28
+ }, [style]);
29
+ return (_jsx("div", { className: className, ref: container, children: children }));
30
+ };
31
+ //# sourceMappingURL=MapView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapView.js","sourceRoot":"","sources":["../../src/react/MapView.tsx"],"names":[],"mappings":";AACA,OAAO,EAAkB,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAkB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAW5D,iEAAiE;AACjE,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,GAAG,YAAY,EAAE,QAAQ,EAAS,EAAE,EAAE;IAChG,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAE9C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,CAAC,OAAO;YAAE,OAAO;QAC/B,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QACtD,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;QACnB,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,GAAG,EAAE;YACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC,CAAC,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,CAAC,CAAC;QACF,wDAAwD;IAC1D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,qEAAqE;IACrE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK;YAAE,OAAO;QACtC,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,YACtC,QAAQ,GACL,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** A link that shows the app is built on Queria. */
2
+ export declare const PoweredBy: () => import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { poweredByHtml } from "../render/poweredBy.js";
3
+ /** A link that shows the app is built on Queria. */
4
+ export const PoweredBy = () => _jsx("span", { dangerouslySetInnerHTML: { __html: poweredByHtml() } });
5
+ //# sourceMappingURL=PoweredBy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PoweredBy.js","sourceRoot":"","sources":["../../src/react/PoweredBy.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,oDAAoD;AACpD,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,eAAM,uBAAuB,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,GAAI,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { QueriaProvider, useQueria, useQuery, type QueryState } from "./query.js";
2
+ export { Chart } from "./Chart.js";
3
+ export { DataMap } from "./DataMap.js";
4
+ export { MapView } from "./MapView.js";
5
+ export { PoweredBy } from "./PoweredBy.js";
@@ -0,0 +1,6 @@
1
+ export { QueriaProvider, useQueria, useQuery } from "./query.js";
2
+ export { Chart } from "./Chart.js";
3
+ export { DataMap } from "./DataMap.js";
4
+ export { MapView } from "./MapView.js";
5
+ export { PoweredBy } from "./PoweredBy.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type ReactNode } from "react";
2
+ import { type Connection, type ConnectOptions } from "../client.js";
3
+ /** Declare the datasets for the components below: <QueriaProvider datasets={["queria/e_stat"]}>. */
4
+ export declare const QueriaProvider: ({ children, ...options }: ConnectOptions & {
5
+ children: ReactNode;
6
+ }) => import("react").JSX.Element;
7
+ export declare const useQueria: () => Connection;
8
+ export type QueryState<T> = {
9
+ status: "idle";
10
+ } | {
11
+ status: "loading";
12
+ } | {
13
+ status: "done";
14
+ rows: T[];
15
+ } | {
16
+ status: "error";
17
+ error: unknown;
18
+ };
19
+ /** Run SQL and re-run it when the SQL changes. Pass null to skip; the state is then idle. */
20
+ export declare const useQuery: <T = Record<string, unknown>>(sql: string | null) => QueryState<T>;
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
3
+ import { connect } from "../client.js";
4
+ const Context = createContext(null);
5
+ /** Declare the datasets for the components below: <QueriaProvider datasets={["queria/e_stat"]}>. */
6
+ export const QueriaProvider = ({ children, ...options }) => {
7
+ // JSON drops functions, so a token function is keyed by its presence and called through a ref:
8
+ // a new function on each render keeps the connection, and the latest one is called.
9
+ const { token } = options;
10
+ const latest = useRef(token);
11
+ latest.current = token;
12
+ const key = JSON.stringify({ ...options, token: typeof token === "function" ? "function" : token });
13
+ const conn = useMemo(() => connect({
14
+ ...options,
15
+ token: typeof token === "function"
16
+ ? async () => {
17
+ const t = latest.current;
18
+ if (t === undefined)
19
+ throw new Error("The token was removed");
20
+ return typeof t === "function" ? t() : t;
21
+ }
22
+ : token,
23
+ }), [key]);
24
+ return _jsx(Context.Provider, { value: conn, children: children });
25
+ };
26
+ export const useQueria = () => {
27
+ const conn = useContext(Context);
28
+ if (!conn)
29
+ throw new Error("Wrap the component in <QueriaProvider datasets={[...]}>");
30
+ return conn;
31
+ };
32
+ /** Run SQL and re-run it when the SQL changes. Pass null to skip; the state is then idle. */
33
+ export const useQuery = (sql) => {
34
+ const conn = useQueria();
35
+ const [state, setState] = useState(sql === null ? { status: "idle" } : { status: "loading" });
36
+ useEffect(() => {
37
+ if (sql === null) {
38
+ setState({ status: "idle" });
39
+ return;
40
+ }
41
+ let alive = true;
42
+ setState({ status: "loading" });
43
+ conn.sql(sql).then((rows) => alive && setState({ status: "done", rows }), (error) => alive && setState({ status: "error", error }));
44
+ return () => {
45
+ alive = false;
46
+ };
47
+ }, [conn, sql]);
48
+ return state;
49
+ };
50
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/react/query.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Dataset } from "../client.js";
2
+ /**
3
+ * Markup of the sources and licenses of the datasets, for display under a chart or map.
4
+ * Licenses such as CC BY require it wherever the data is shown.
5
+ */
6
+ export declare const attributionHtml: (datasets: readonly Dataset[]) => string;
@@ -0,0 +1,17 @@
1
+ import { esc } from "./escape.js";
2
+ const link = (url, text) => url && /^https?:\/\//.test(url) ? `<a href="${esc(url)}" target="_blank" rel="noopener">${esc(text)}</a>` : esc(text);
3
+ /**
4
+ * Markup of the sources and licenses of the datasets, for display under a chart or map.
5
+ * Licenses such as CC BY require it wherever the data is shown.
6
+ */
7
+ export const attributionHtml = (datasets) => datasets.length === 0
8
+ ? ""
9
+ : '<p class="queria-attribution">Source: ' +
10
+ datasets
11
+ .map((d) => {
12
+ const licenses = (d.licenses ?? []).map((l) => link(l.url, l.title ?? l.id ?? "")).filter(Boolean);
13
+ return link(d.page_url, d.title ?? d.qualified_name) + (licenses.length ? ` (${licenses.join(", ")})` : "");
14
+ })
15
+ .join("; ") +
16
+ "</p>";
17
+ //# sourceMappingURL=attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/render/attribution.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,IAAI,GAAG,CAAC,GAAuB,EAAE,IAAY,EAAU,EAAE,CAC7D,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,oCAAoC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAExH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAA4B,EAAU,EAAE,CACtE,QAAQ,CAAC,MAAM,KAAK,CAAC;IACnB,CAAC,CAAC,EAAE;IACJ,CAAC,CAAC,wCAAwC;QACxC,QAAQ;aACL,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACnG,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9G,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC;QACb,MAAM,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { EmbedOptions, Result, VisualizationSpec } from "vega-embed";
2
+ /** A Vega-Lite spec. Its data is put in by the package. */
3
+ export type ChartSpec = VisualizationSpec | Record<string, unknown>;
4
+ export type Rows = readonly Record<string, unknown>[];
5
+ /**
6
+ * Put the data into the spec. With rows, they become the data of a spec that has none.
7
+ * With named rows, the spec (or its layers) picks them with data: { name }; rows named "" are the default data.
8
+ */
9
+ export declare const withData: (spec: ChartSpec, data: Rows | Readonly<Record<string, Rows>>) => Record<string, unknown>;
10
+ export type ChartOptions = {
11
+ /** Vega-Lite config, such as a theme. The spec's own config is merged over it. */
12
+ config?: Record<string, unknown>;
13
+ /** Export and source menu. Hidden by default. */
14
+ actions?: EmbedOptions["actions"];
15
+ /** Labels of the menu. */
16
+ i18n?: EmbedOptions["i18n"];
17
+ tooltipTheme?: "light" | "dark";
18
+ /** By default svg, and canvas when there are more than 5,000 rows in all. */
19
+ renderer?: "svg" | "canvas";
20
+ };
21
+ /**
22
+ * Draw a Vega-Lite chart. vega-embed and vega-interpreter are loaded on first use. Expressions are run by the
23
+ * interpreter, so charts draw on pages whose Content Security Policy has no unsafe-eval.
24
+ * Returns the Vega view and a function that removes the chart.
25
+ * Sources and licenses are not drawn here; the elements and React components add them under the chart.
26
+ */
27
+ export declare const renderChart: (el: HTMLElement, spec: ChartSpec, data: Rows | Readonly<Record<string, Rows>>, { config, actions, i18n, tooltipTheme, renderer }?: ChartOptions) => Promise<Pick<Result, "view" | "finalize">>;
@@ -0,0 +1,50 @@
1
+ // Vega writes an id into every row it reads, so hand it copies: the caller's rows may be frozen or shared.
2
+ const copy = (rows) => rows.map((r) => ({ ...r }));
3
+ const isRows = (d) => Array.isArray(d);
4
+ const ownDatasets = (spec) => {
5
+ const d = "datasets" in spec ? spec.datasets : undefined;
6
+ return typeof d === "object" && d !== null ? d : {};
7
+ };
8
+ /**
9
+ * Put the data into the spec. With rows, they become the data of a spec that has none.
10
+ * With named rows, the spec (or its layers) picks them with data: { name }; rows named "" are the default data.
11
+ */
12
+ export const withData = (spec, data) => {
13
+ const named = isRows(data) ? { "": data } : data;
14
+ const { "": main, ...rest } = named;
15
+ // Vega-Lite takes width "container" only for single and layered views, and warns on the others.
16
+ const composite = ["facet", "repeat", "concat", "hconcat", "vconcat"].some((k) => k in spec);
17
+ return {
18
+ ...(composite ? {} : { width: "container" }),
19
+ ...spec,
20
+ ...(main && !("data" in spec) ? { data: { values: copy(main) } } : {}),
21
+ // The spec's own datasets stay; named rows are laid over them.
22
+ ...(Object.keys(rest).length
23
+ ? { datasets: { ...ownDatasets(spec), ...Object.fromEntries(Object.entries(rest).map(([k, v]) => [k, copy(v)])) } }
24
+ : {}),
25
+ };
26
+ };
27
+ const CANVAS_ABOVE = 5000;
28
+ const rowCount = (data) => isRows(data) ? data.length : Object.values(data).reduce((n, rows) => n + rows.length, 0);
29
+ /**
30
+ * Draw a Vega-Lite chart. vega-embed and vega-interpreter are loaded on first use. Expressions are run by the
31
+ * interpreter, so charts draw on pages whose Content Security Policy has no unsafe-eval.
32
+ * Returns the Vega view and a function that removes the chart.
33
+ * Sources and licenses are not drawn here; the elements and React components add them under the chart.
34
+ */
35
+ export const renderChart = async (el, spec, data, { config, actions = false, i18n, tooltipTheme, renderer } = {}) => {
36
+ const [{ default: embed }, { expressionInterpreter }] = await Promise.all([import("vega-embed"), import("vega-interpreter")]);
37
+ const { view, finalize } = await embed(el, withData(spec, data), {
38
+ // Read the spec as Vega-Lite even when its $schema says Vega
39
+ mode: "vega-lite",
40
+ ast: true,
41
+ expr: expressionInterpreter,
42
+ renderer: renderer ?? (rowCount(data) > CANVAS_ABOVE ? "canvas" : "svg"),
43
+ actions,
44
+ ...(i18n ? { i18n } : {}),
45
+ ...(config ? { config } : {}),
46
+ ...(tooltipTheme ? { tooltip: { theme: tooltipTheme } } : {}),
47
+ });
48
+ return { view, finalize };
49
+ };
50
+ //# sourceMappingURL=chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart.js","sourceRoot":"","sources":["../../src/render/chart.ts"],"names":[],"mappings":"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"}