grist-widget-sdk 0.4.0 → 0.5.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.
- package/CHANGELOG.md +39 -0
- package/README.md +79 -208
- package/dist/app.cjs +183 -65
- package/dist/app.cjs.map +1 -1
- package/dist/app.d.cts +5 -100
- package/dist/app.d.ts +5 -100
- package/dist/app.js +4 -2
- package/dist/{chunk-P6VTEKWO.js → chunk-LSALXIGM.js} +82 -10
- package/dist/chunk-LSALXIGM.js.map +1 -0
- package/dist/{chunk-O7NY46QY.js → chunk-MAPAWVQC.js} +88 -20
- package/dist/chunk-MAPAWVQC.js.map +1 -0
- package/dist/{chunk-B5ZZNLVS.js → chunk-OXA2VITC.js} +5 -1
- package/dist/chunk-OXA2VITC.js.map +1 -0
- package/dist/{use-grist-BK0eke9K.d.cts → define-widget-B1FIvI-h.d.cts} +179 -104
- package/dist/{use-grist-C5DMZ3wU.d.ts → define-widget-B9gEtJP0.d.ts} +179 -104
- package/dist/emulator/testing.cjs +2390 -2243
- package/dist/emulator/testing.cjs.map +1 -1
- package/dist/emulator/testing.d.cts +27 -9
- package/dist/emulator/testing.d.ts +27 -9
- package/dist/emulator/testing.js +74 -55
- package/dist/emulator/testing.js.map +1 -1
- package/dist/emulator.cjs +4 -0
- package/dist/emulator.cjs.map +1 -1
- package/dist/emulator.d.cts +3 -3
- package/dist/emulator.d.ts +3 -3
- package/dist/emulator.js +1 -1
- package/dist/index.cjs +133 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -1
- package/dist/mount-grist-widget-CkB-3iG_.d.ts +137 -0
- package/dist/mount-grist-widget-Dtelqao_.d.cts +137 -0
- package/package.json +1 -1
- package/dist/chunk-B5ZZNLVS.js.map +0 -1
- package/dist/chunk-O7NY46QY.js.map +0 -1
- package/dist/chunk-P6VTEKWO.js.map +0 -1
package/dist/app.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var app_exports = {};
|
|
|
22
22
|
__export(app_exports, {
|
|
23
23
|
GristWidgetApp: () => GristWidgetApp,
|
|
24
24
|
deployChannelLabel: () => deployChannelLabel,
|
|
25
|
+
entryProps: () => entryProps,
|
|
25
26
|
mountGristWidget: () => mountGristWidget,
|
|
26
27
|
parseDeployPath: () => parseDeployPath,
|
|
27
28
|
useReleasedVersions: () => useReleasedVersions,
|
|
@@ -30,7 +31,7 @@ __export(app_exports, {
|
|
|
30
31
|
module.exports = __toCommonJS(app_exports);
|
|
31
32
|
|
|
32
33
|
// src/app/mount-grist-widget.tsx
|
|
33
|
-
var
|
|
34
|
+
var import_react9 = require("react");
|
|
34
35
|
var import_client = require("react-dom/client");
|
|
35
36
|
|
|
36
37
|
// src/sdk/use-grist.ts
|
|
@@ -579,16 +580,24 @@ function createGristApi(runtime) {
|
|
|
579
580
|
throw err;
|
|
580
581
|
}
|
|
581
582
|
};
|
|
582
|
-
|
|
583
|
+
let running = 0;
|
|
584
|
+
let failure = null;
|
|
585
|
+
const write = (fn) => {
|
|
586
|
+
if (running++ === 0) failure = null;
|
|
583
587
|
runtime.update({ actionStatus: "running", actionError: null });
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
588
|
+
const done = (async () => {
|
|
589
|
+
try {
|
|
590
|
+
return await fn();
|
|
591
|
+
} catch (err) {
|
|
592
|
+
failure = message(err);
|
|
593
|
+
throw err;
|
|
594
|
+
} finally {
|
|
595
|
+
if (--running === 0) runtime.update(failure ? { actionStatus: "error", actionError: failure } : { actionStatus: "idle" });
|
|
596
|
+
}
|
|
597
|
+
})();
|
|
598
|
+
done.catch(() => {
|
|
599
|
+
});
|
|
600
|
+
return done;
|
|
592
601
|
};
|
|
593
602
|
const tableOps = (resolve) => ({
|
|
594
603
|
getTableId: () => resolve().getTableId(),
|
|
@@ -693,38 +702,6 @@ function validateColumnMappings(spec, mappings) {
|
|
|
693
702
|
};
|
|
694
703
|
}
|
|
695
704
|
|
|
696
|
-
// src/sdk/runtime/derive.ts
|
|
697
|
-
var ACCESS_RANK = { none: 0, "read table": 1, full: 2 };
|
|
698
|
-
function parseAccess(raw) {
|
|
699
|
-
return raw === "none" || raw === "read table" || raw === "full" ? raw : null;
|
|
700
|
-
}
|
|
701
|
-
function accessLabel(level) {
|
|
702
|
-
return level === "full" ? "Full document access" : level === "read table" ? "Read selected table" : "No document access";
|
|
703
|
-
}
|
|
704
|
-
function accessDenied(state) {
|
|
705
|
-
return state.grantedAccess !== null && ACCESS_RANK[state.grantedAccess] < ACCESS_RANK[state.declaredAccess];
|
|
706
|
-
}
|
|
707
|
-
function deriveStatus(state) {
|
|
708
|
-
switch (state.connection) {
|
|
709
|
-
case "connecting":
|
|
710
|
-
return "booting";
|
|
711
|
-
case "not-embedded":
|
|
712
|
-
case "unavailable":
|
|
713
|
-
return "unavailable";
|
|
714
|
-
case "error":
|
|
715
|
-
return "error";
|
|
716
|
-
case "ready":
|
|
717
|
-
return accessDenied(state) ? "error" : "ready";
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
var MAPPINGS_OK = Object.freeze({ ok: true, pending: false, missing: [], emptyMultiples: [] });
|
|
721
|
-
var MAPPINGS_PENDING = Object.freeze({ ok: true, pending: true, missing: [], emptyMultiples: [] });
|
|
722
|
-
function deriveColumnMappingStatus(columns, mappings) {
|
|
723
|
-
if (!columns?.length) return MAPPINGS_OK;
|
|
724
|
-
if (mappings === null) return MAPPINGS_PENDING;
|
|
725
|
-
return validateColumnMappings(columns, mappings);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
705
|
// src/sdk/runtime/cells.ts
|
|
729
706
|
var ok = (value) => ({ ok: true, value });
|
|
730
707
|
var bad = (message2) => ({ ok: false, message: message2 });
|
|
@@ -788,10 +765,13 @@ function checkOne(base, value) {
|
|
|
788
765
|
return ok(value);
|
|
789
766
|
}
|
|
790
767
|
}
|
|
768
|
+
function basesOf(type) {
|
|
769
|
+
return (type ?? "Any").split(",").map((t) => t.trim().split(":")[0]).filter(Boolean);
|
|
770
|
+
}
|
|
791
771
|
function checkGristCell(type, value) {
|
|
792
772
|
const error = formulaError(value);
|
|
793
773
|
if (error) return bad(`formula error (${error})`);
|
|
794
|
-
const bases = (type
|
|
774
|
+
const bases = basesOf(type);
|
|
795
775
|
if (bases.length === 0 || bases.includes("Any")) return ok(value === void 0 ? null : value);
|
|
796
776
|
let first = null;
|
|
797
777
|
for (const base of bases) {
|
|
@@ -841,6 +821,38 @@ function mapAndCheck(record, columns, mappings, schema) {
|
|
|
841
821
|
return { value: out, issues };
|
|
842
822
|
}
|
|
843
823
|
|
|
824
|
+
// src/sdk/runtime/derive.ts
|
|
825
|
+
var ACCESS_RANK = { none: 0, "read table": 1, full: 2 };
|
|
826
|
+
function parseAccess(raw) {
|
|
827
|
+
return raw === "none" || raw === "read table" || raw === "full" ? raw : null;
|
|
828
|
+
}
|
|
829
|
+
function accessLabel(level) {
|
|
830
|
+
return level === "full" ? "Full document access" : level === "read table" ? "Read selected table" : "No document access";
|
|
831
|
+
}
|
|
832
|
+
function accessDenied(state) {
|
|
833
|
+
return state.grantedAccess !== null && ACCESS_RANK[state.grantedAccess] < ACCESS_RANK[state.declaredAccess];
|
|
834
|
+
}
|
|
835
|
+
function deriveStatus(state) {
|
|
836
|
+
switch (state.connection) {
|
|
837
|
+
case "connecting":
|
|
838
|
+
return "booting";
|
|
839
|
+
case "not-embedded":
|
|
840
|
+
case "unavailable":
|
|
841
|
+
return "unavailable";
|
|
842
|
+
case "error":
|
|
843
|
+
return "error";
|
|
844
|
+
case "ready":
|
|
845
|
+
return accessDenied(state) ? "error" : "ready";
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
var MAPPINGS_OK = Object.freeze({ ok: true, pending: false, missing: [], emptyMultiples: [] });
|
|
849
|
+
var MAPPINGS_PENDING = Object.freeze({ ok: true, pending: true, missing: [], emptyMultiples: [] });
|
|
850
|
+
function deriveColumnMappingStatus(columns, mappings) {
|
|
851
|
+
if (!columns?.length) return MAPPINGS_OK;
|
|
852
|
+
if (mappings === null) return MAPPINGS_PENDING;
|
|
853
|
+
return validateColumnMappings(columns, mappings);
|
|
854
|
+
}
|
|
855
|
+
|
|
844
856
|
// src/sdk/helpers/grist-widget-interaction.ts
|
|
845
857
|
function parseGristWidgetLinkingInfo(raw) {
|
|
846
858
|
if (!raw || typeof raw !== "object" || !("asTarget" in raw)) return void 0;
|
|
@@ -1213,6 +1225,11 @@ function useNearestGristState() {
|
|
|
1213
1225
|
return { connection, state, cellIssues: issues };
|
|
1214
1226
|
}
|
|
1215
1227
|
|
|
1228
|
+
// src/sdk/define-widget.ts
|
|
1229
|
+
function isGristWidget(value) {
|
|
1230
|
+
return typeof value === "object" && value !== null && "definition" in value && "useGrist" in value;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1216
1233
|
// src/sdk/components/grist-widget-provider.tsx
|
|
1217
1234
|
var import_react2 = require("react");
|
|
1218
1235
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -1371,6 +1388,40 @@ function GristBoundary({ children }) {
|
|
|
1371
1388
|
);
|
|
1372
1389
|
}
|
|
1373
1390
|
|
|
1391
|
+
// src/sdk/use-widget-metadata.ts
|
|
1392
|
+
var import_react4 = require("react");
|
|
1393
|
+
function useWidgetMetadata(input) {
|
|
1394
|
+
(0, import_react4.useEffect)(() => {
|
|
1395
|
+
if (!input) return;
|
|
1396
|
+
const { title, description } = input;
|
|
1397
|
+
const canonicalUrl = window.location.href;
|
|
1398
|
+
document.title = title;
|
|
1399
|
+
setMetaTag("name", "title", title);
|
|
1400
|
+
setMetaTag("name", "description", description);
|
|
1401
|
+
setMetaTag("property", "og:title", title);
|
|
1402
|
+
setMetaTag("property", "og:description", description);
|
|
1403
|
+
setMetaTag("property", "og:type", "website");
|
|
1404
|
+
setMetaTag("property", "og:url", canonicalUrl);
|
|
1405
|
+
setMetaTag("name", "twitter:card", "summary");
|
|
1406
|
+
setMetaTag("name", "twitter:title", title);
|
|
1407
|
+
setMetaTag("name", "twitter:description", description);
|
|
1408
|
+
}, [input]);
|
|
1409
|
+
}
|
|
1410
|
+
function setMetaTag(key, value, content) {
|
|
1411
|
+
let meta = document.head.querySelector(
|
|
1412
|
+
`meta[${key}="${value}"]`
|
|
1413
|
+
);
|
|
1414
|
+
if (!meta) {
|
|
1415
|
+
meta = document.createElement("meta");
|
|
1416
|
+
meta.setAttribute(key, value);
|
|
1417
|
+
document.head.appendChild(meta);
|
|
1418
|
+
}
|
|
1419
|
+
meta.setAttribute("content", content);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
// src/app/chrome/local-dev-page.tsx
|
|
1423
|
+
var import_react5 = require("react");
|
|
1424
|
+
|
|
1374
1425
|
// src/app/chrome/tokens.ts
|
|
1375
1426
|
var token = (name, fallback) => `var(--${name}, ${fallback})`;
|
|
1376
1427
|
var tokens = {
|
|
@@ -1451,7 +1502,20 @@ function widgetTitle() {
|
|
|
1451
1502
|
|
|
1452
1503
|
// src/app/chrome/local-dev-page.tsx
|
|
1453
1504
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1505
|
+
function useHasDemo() {
|
|
1506
|
+
const [has, setHas] = (0, import_react5.useState)(null);
|
|
1507
|
+
(0, import_react5.useEffect)(() => {
|
|
1508
|
+
if (typeof fetch !== "function") return;
|
|
1509
|
+
let live = true;
|
|
1510
|
+
fetch("demo/demo.grist", { method: "HEAD" }).then((res) => live && setHas(res.ok)).catch(() => live && setHas(false));
|
|
1511
|
+
return () => {
|
|
1512
|
+
live = false;
|
|
1513
|
+
};
|
|
1514
|
+
}, []);
|
|
1515
|
+
return has;
|
|
1516
|
+
}
|
|
1454
1517
|
function LocalDevPage() {
|
|
1518
|
+
const hasDemo = useHasDemo();
|
|
1455
1519
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("main", { style: pageStyle, children: [
|
|
1456
1520
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: eyebrowStyle, children: [
|
|
1457
1521
|
widgetTitle(),
|
|
@@ -1459,6 +1523,29 @@ function LocalDevPage() {
|
|
|
1459
1523
|
] }),
|
|
1460
1524
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { style: headingStyle, children: "Not embedded in Grist" }),
|
|
1461
1525
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: leadStyle, children: "This is the local dev server: there's no Grist here to render the widget against." }),
|
|
1526
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { style: cardStyle2, children: [
|
|
1527
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: cardTitleStyle, children: "Open it in Grist, in this browser" }),
|
|
1528
|
+
hasDemo === false ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: cardTextStyle, children: [
|
|
1529
|
+
"Run ",
|
|
1530
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { style: codeStyle, children: "pnpm demo --save" }),
|
|
1531
|
+
" once (it needs Docker): it writes",
|
|
1532
|
+
" ",
|
|
1533
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { style: codeStyle, children: "public/demo/" }),
|
|
1534
|
+
", a document for this widget. Then",
|
|
1535
|
+
" ",
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: "demo/index.html", children: "demo/index.html" }),
|
|
1537
|
+
" opens it in real Grist, running in the browser, on this dev server's widget: edits reload in place."
|
|
1538
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: cardTextStyle, children: [
|
|
1539
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: "demo/index.html", children: "Open demo/index.html" }),
|
|
1540
|
+
": real Grist running in the browser (no server, nothing saved), with this dev server's widget, so edits reload in place. Its document is",
|
|
1541
|
+
" ",
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { style: codeStyle, children: "public/demo/demo.grist" }),
|
|
1543
|
+
": after changing the declared columns, run",
|
|
1544
|
+
" ",
|
|
1545
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { style: codeStyle, children: "pnpm demo --save" }),
|
|
1546
|
+
" (Docker) to regenerate it."
|
|
1547
|
+
] })
|
|
1548
|
+
] }),
|
|
1462
1549
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { style: cardStyle2, children: [
|
|
1463
1550
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: cardTitleStyle, children: "Check it against real Grist" }),
|
|
1464
1551
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: cardTextStyle, children: [
|
|
@@ -1486,7 +1573,7 @@ function LocalDevPage() {
|
|
|
1486
1573
|
}
|
|
1487
1574
|
|
|
1488
1575
|
// src/app/chrome/release-page.tsx
|
|
1489
|
-
var
|
|
1576
|
+
var import_react7 = require("react");
|
|
1490
1577
|
|
|
1491
1578
|
// src/app/deploy-path.ts
|
|
1492
1579
|
var VERSION_SEGMENT = /^v(\d+\.\d+\.\d+(?:-[\w.]+)?)$/;
|
|
@@ -1511,11 +1598,11 @@ function withTrailingSlash(path) {
|
|
|
1511
1598
|
}
|
|
1512
1599
|
|
|
1513
1600
|
// src/app/released-versions.ts
|
|
1514
|
-
var
|
|
1601
|
+
var import_react6 = require("react");
|
|
1515
1602
|
function useReleasedVersions(pathname = typeof window === "undefined" ? "/" : window.location.pathname) {
|
|
1516
1603
|
const url = `${parseDeployPath(pathname).basePath}versions.json`;
|
|
1517
|
-
const [result, setResult] = (0,
|
|
1518
|
-
(0,
|
|
1604
|
+
const [result, setResult] = (0, import_react6.useState)({ versions: null, error: false });
|
|
1605
|
+
(0, import_react6.useEffect)(() => {
|
|
1519
1606
|
let cancelled = false;
|
|
1520
1607
|
fetch(url, { cache: "no-store" }).then((res) => res.ok ? res.json() : Promise.reject(new Error(`HTTP ${res.status}`))).then((data) => {
|
|
1521
1608
|
if (cancelled) return;
|
|
@@ -1590,7 +1677,7 @@ function ChannelLink({
|
|
|
1590
1677
|
}
|
|
1591
1678
|
function InstallUrl() {
|
|
1592
1679
|
const url = window.location.href;
|
|
1593
|
-
const [copied, setCopied] = (0,
|
|
1680
|
+
const [copied, setCopied] = (0, import_react7.useState)(false);
|
|
1594
1681
|
function copy() {
|
|
1595
1682
|
void navigator.clipboard?.writeText(url).then(() => {
|
|
1596
1683
|
setCopied(true);
|
|
@@ -1809,14 +1896,14 @@ function LinkIcon() {
|
|
|
1809
1896
|
}
|
|
1810
1897
|
|
|
1811
1898
|
// src/app/widget-theme.tsx
|
|
1812
|
-
var
|
|
1899
|
+
var import_react8 = require("react");
|
|
1813
1900
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1814
1901
|
var STORAGE_KEY = "theme";
|
|
1815
1902
|
var DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
1816
1903
|
var THEMES = ["light", "dark", "system"];
|
|
1817
|
-
var ThemeContext = (0,
|
|
1904
|
+
var ThemeContext = (0, import_react8.createContext)(null);
|
|
1818
1905
|
function useTheme() {
|
|
1819
|
-
const value = (0,
|
|
1906
|
+
const value = (0, import_react8.useContext)(ThemeContext);
|
|
1820
1907
|
return value ?? { theme: "system", resolvedTheme: systemTheme(), setTheme: noop };
|
|
1821
1908
|
}
|
|
1822
1909
|
function EmbeddedThemeProvider({ children }) {
|
|
@@ -1824,22 +1911,22 @@ function EmbeddedThemeProvider({ children }) {
|
|
|
1824
1911
|
const system = useSystemTheme(gristTheme === null);
|
|
1825
1912
|
const resolvedTheme = gristTheme ?? system;
|
|
1826
1913
|
useApplyTheme(resolvedTheme);
|
|
1827
|
-
const value = (0,
|
|
1914
|
+
const value = (0, import_react8.useMemo)(
|
|
1828
1915
|
() => ({ theme: gristTheme ?? "system", resolvedTheme, setTheme: noop }),
|
|
1829
1916
|
[gristTheme, resolvedTheme]
|
|
1830
1917
|
);
|
|
1831
1918
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThemeContext.Provider, { value, children });
|
|
1832
1919
|
}
|
|
1833
1920
|
function StandaloneThemeProvider({ children }) {
|
|
1834
|
-
const [theme, setThemeState] = (0,
|
|
1921
|
+
const [theme, setThemeState] = (0, import_react8.useState)(() => readStoredTheme() ?? "system");
|
|
1835
1922
|
const system = useSystemTheme(theme === "system");
|
|
1836
1923
|
const resolvedTheme = theme === "system" ? system : theme;
|
|
1837
1924
|
useApplyTheme(resolvedTheme);
|
|
1838
|
-
const setTheme = (0,
|
|
1925
|
+
const setTheme = (0, import_react8.useCallback)((next) => {
|
|
1839
1926
|
writeStoredTheme(next);
|
|
1840
1927
|
setThemeState(next);
|
|
1841
1928
|
}, []);
|
|
1842
|
-
(0,
|
|
1929
|
+
(0, import_react8.useEffect)(() => {
|
|
1843
1930
|
const onKeyDown = (event) => {
|
|
1844
1931
|
if (event.repeat || event.metaKey || event.ctrlKey || event.altKey) return;
|
|
1845
1932
|
if (event.key.toLowerCase() !== "d" || isEditableTarget(event.target)) return;
|
|
@@ -1853,7 +1940,7 @@ function StandaloneThemeProvider({ children }) {
|
|
|
1853
1940
|
window.addEventListener("keydown", onKeyDown);
|
|
1854
1941
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
1855
1942
|
}, []);
|
|
1856
|
-
(0,
|
|
1943
|
+
(0, import_react8.useEffect)(() => {
|
|
1857
1944
|
const onStorage = (event) => {
|
|
1858
1945
|
if (event.key !== STORAGE_KEY) return;
|
|
1859
1946
|
setThemeState(isTheme(event.newValue) ? event.newValue : "system");
|
|
@@ -1861,15 +1948,15 @@ function StandaloneThemeProvider({ children }) {
|
|
|
1861
1948
|
window.addEventListener("storage", onStorage);
|
|
1862
1949
|
return () => window.removeEventListener("storage", onStorage);
|
|
1863
1950
|
}, []);
|
|
1864
|
-
const value = (0,
|
|
1951
|
+
const value = (0, import_react8.useMemo)(
|
|
1865
1952
|
() => ({ theme, resolvedTheme, setTheme }),
|
|
1866
1953
|
[theme, resolvedTheme, setTheme]
|
|
1867
1954
|
);
|
|
1868
1955
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ThemeContext.Provider, { value, children });
|
|
1869
1956
|
}
|
|
1870
1957
|
function useSystemTheme(active) {
|
|
1871
|
-
const [theme, setTheme] = (0,
|
|
1872
|
-
(0,
|
|
1958
|
+
const [theme, setTheme] = (0, import_react8.useState)(systemTheme);
|
|
1959
|
+
(0, import_react8.useEffect)(() => {
|
|
1873
1960
|
if (!active || typeof window.matchMedia !== "function") return;
|
|
1874
1961
|
const query = window.matchMedia(DARK_QUERY);
|
|
1875
1962
|
const onChange = () => setTheme(query.matches ? "dark" : "light");
|
|
@@ -1880,7 +1967,7 @@ function useSystemTheme(active) {
|
|
|
1880
1967
|
return theme;
|
|
1881
1968
|
}
|
|
1882
1969
|
function useApplyTheme(theme) {
|
|
1883
|
-
(0,
|
|
1970
|
+
(0, import_react8.useEffect)(() => {
|
|
1884
1971
|
const root = document.documentElement;
|
|
1885
1972
|
if (root.classList.contains(theme) && !root.classList.contains(other(theme))) return;
|
|
1886
1973
|
const restoreTransitions = suspendTransitions();
|
|
@@ -1933,21 +2020,41 @@ function noop() {
|
|
|
1933
2020
|
|
|
1934
2021
|
// src/app/mount-grist-widget.tsx
|
|
1935
2022
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1936
|
-
function
|
|
1937
|
-
const
|
|
2023
|
+
function entryProps(entry, dev = false) {
|
|
2024
|
+
const widget = isGristWidget(entry.widget) ? entry.widget : void 0;
|
|
2025
|
+
const options = widget?.options ?? entry.GRIST_OPTIONS;
|
|
2026
|
+
if (!options) {
|
|
2027
|
+
throw new Error(
|
|
2028
|
+
"mountGristWidget: src/app/App.tsx exports neither `widget` (defineGristWidget) nor `GRIST_OPTIONS`."
|
|
2029
|
+
);
|
|
2030
|
+
}
|
|
2031
|
+
const props = {
|
|
2032
|
+
App: entry.default,
|
|
2033
|
+
options,
|
|
2034
|
+
metadata: widget?.metadata ?? entry.WIDGET_METADATA,
|
|
2035
|
+
dev
|
|
2036
|
+
};
|
|
2037
|
+
if ("Alerts" in entry) props.Alerts = entry.Alerts;
|
|
2038
|
+
if (entry.LocalDevPage) props.LocalDevPage = entry.LocalDevPage;
|
|
2039
|
+
if (entry.ReleasePage) props.ReleasePage = entry.ReleasePage;
|
|
2040
|
+
return props;
|
|
2041
|
+
}
|
|
2042
|
+
function mountGristWidget(config, entryOptions = {}) {
|
|
2043
|
+
const { root = "#root", ...props } = "App" in config ? config : { ...entryProps(config, entryOptions.dev), root: entryOptions.root };
|
|
1938
2044
|
const container = typeof root === "string" ? document.querySelector(root) : root;
|
|
1939
2045
|
if (!container) {
|
|
1940
2046
|
throw new Error(`mountGristWidget: no element matches "${String(root)}" to render the widget into.`);
|
|
1941
2047
|
}
|
|
1942
2048
|
const reactRoot = (0, import_client.createRoot)(container);
|
|
1943
2049
|
reactRoot.render(
|
|
1944
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2050
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react9.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GristWidgetApp, { ...props }) })
|
|
1945
2051
|
);
|
|
1946
2052
|
return { unmount: () => reactRoot.unmount() };
|
|
1947
2053
|
}
|
|
1948
2054
|
function GristWidgetApp({
|
|
1949
2055
|
App,
|
|
1950
2056
|
options,
|
|
2057
|
+
metadata,
|
|
1951
2058
|
dev = false,
|
|
1952
2059
|
Alerts = WidgetAlerts,
|
|
1953
2060
|
LocalDevPage: LocalDevPage2 = LocalDevPage,
|
|
@@ -1955,15 +2062,25 @@ function GristWidgetApp({
|
|
|
1955
2062
|
}) {
|
|
1956
2063
|
const Wrap = Alerts ?? PassThrough;
|
|
1957
2064
|
if (isEmbedded2()) {
|
|
1958
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.
|
|
2065
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(GristWidgetProvider, { options, children: [
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PageMetadata, { metadata }),
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(EmbeddedThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GristBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: FILL, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Wrap, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react9.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(App, {}) }) }) }) }) })
|
|
2068
|
+
] });
|
|
1959
2069
|
}
|
|
1960
2070
|
const channel = parseDeployPath(window.location.pathname).channel;
|
|
1961
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.
|
|
2071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(StandaloneThemeProvider, { children: [
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PageMetadata, { metadata }),
|
|
2073
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: FILL, children: dev ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LocalDevPage2, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ReleasePage2, { channel }) })
|
|
2074
|
+
] });
|
|
1962
2075
|
}
|
|
1963
2076
|
var FILL = { minHeight: "100%", width: "100%" };
|
|
1964
2077
|
function isEmbedded2() {
|
|
1965
2078
|
return typeof window !== "undefined" && window.self !== window.top;
|
|
1966
2079
|
}
|
|
2080
|
+
function PageMetadata({ metadata }) {
|
|
2081
|
+
useWidgetMetadata(metadata?.title ? { title: metadata.title, description: metadata.description ?? "" } : null);
|
|
2082
|
+
return null;
|
|
2083
|
+
}
|
|
1967
2084
|
function PassThrough({ children }) {
|
|
1968
2085
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children });
|
|
1969
2086
|
}
|
|
@@ -1971,6 +2088,7 @@ function PassThrough({ children }) {
|
|
|
1971
2088
|
0 && (module.exports = {
|
|
1972
2089
|
GristWidgetApp,
|
|
1973
2090
|
deployChannelLabel,
|
|
2091
|
+
entryProps,
|
|
1974
2092
|
mountGristWidget,
|
|
1975
2093
|
parseDeployPath,
|
|
1976
2094
|
useReleasedVersions,
|