grist-widget-sdk 0.4.0 → 0.5.1
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 +47 -0
- package/README.md +79 -208
- package/dist/app.cjs +186 -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-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/{chunk-P6VTEKWO.js → chunk-P5I5MRC6.js} +86 -10
- package/dist/chunk-P5I5MRC6.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 +2393 -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 +75 -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.d.cts
CHANGED
|
@@ -1,103 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
export { D as DeployChannel, a as DeployPath, G as GristWidgetApp, b as GristWidgetAppProps, c as GristWidgetEntry, M as MountGristWidgetConfig, d as MountedGristWidget, e as deployChannelLabel, f as entryProps, m as mountGristWidget, p as parseDeployPath } from './mount-grist-widget-Dtelqao_.cjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import './define-widget-B1FIvI-h.cjs';
|
|
4
4
|
import './types-DBStn0Dk.cjs';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Where a deployed build is being served from.
|
|
8
|
-
*
|
|
9
|
-
* A widget's deploy pipeline publishes the same build at its root and at
|
|
10
|
-
* `/latest/`, a preview at `/dev/`, and each release at `/v<version>/`, all
|
|
11
|
-
* under one base path (e.g. `/my-widget/` on GitHub Pages). Opened outside
|
|
12
|
-
* Grist, the page tells them apart from `window.location.pathname` alone.
|
|
13
|
-
*/
|
|
14
|
-
type DeployChannel = {
|
|
15
|
-
kind: "latest";
|
|
16
|
-
} | {
|
|
17
|
-
kind: "dev";
|
|
18
|
-
} | {
|
|
19
|
-
kind: "version";
|
|
20
|
-
version: string;
|
|
21
|
-
};
|
|
22
|
-
type DeployPath = {
|
|
23
|
-
channel: DeployChannel;
|
|
24
|
-
/**
|
|
25
|
-
* The path the channels live under, always ending in `/`: the current
|
|
26
|
-
* path without its channel segment. `"/my-widget/v1.2.0/"` gives
|
|
27
|
-
* `"/my-widget/"`.
|
|
28
|
-
*/
|
|
29
|
-
basePath: string;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Parse a pathname into its deploy channel and base path. A path without a
|
|
33
|
-
* channel segment (the deployed root, or a local dev server) is `latest`:
|
|
34
|
-
* the deploy places the latest release at the root too.
|
|
35
|
-
*/
|
|
36
|
-
declare function parseDeployPath(pathname: string): DeployPath;
|
|
37
|
-
/** `"latest"`, `"dev"` or `"v1.2.0"`. */
|
|
38
|
-
declare function deployChannelLabel(channel: DeployChannel): string;
|
|
39
|
-
|
|
40
|
-
type GristWidgetAppProps = {
|
|
41
|
-
/** The widget. A `React.lazy()` component works too: its code then loads only inside Grist. */
|
|
42
|
-
App: ComponentType;
|
|
43
|
-
/** The widget's `GRIST_OPTIONS`: access level, columns, and so on. */
|
|
44
|
-
options: UseGristOptions;
|
|
45
|
-
/**
|
|
46
|
-
* Whether this is the local dev server. Pass `import.meta.env.DEV`.
|
|
47
|
-
* Outside Grist it picks the local-dev page over the release page.
|
|
48
|
-
*/
|
|
49
|
-
dev?: boolean;
|
|
50
|
-
/**
|
|
51
|
-
* Wraps the widget inside Grist, under {@link GristBoundary}. The default
|
|
52
|
-
* lists what needs the user's attention (column mapping, access level,
|
|
53
|
-
* failed writes) above the widget; `null` renders the widget alone.
|
|
54
|
-
*/
|
|
55
|
-
Alerts?: ComponentType<{
|
|
56
|
-
children: ReactNode;
|
|
57
|
-
}> | null;
|
|
58
|
-
/** Shown outside Grist on the local dev server. Defaults to a page pointing at `pnpm test` and the `dev` loop. */
|
|
59
|
-
LocalDevPage?: ComponentType;
|
|
60
|
-
/**
|
|
61
|
-
* Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`).
|
|
62
|
-
* Defaults to a page linking every channel and version, with the URL to
|
|
63
|
-
* paste into Grist.
|
|
64
|
-
*/
|
|
65
|
-
ReleasePage?: ComponentType<{
|
|
66
|
-
channel: DeployChannel;
|
|
67
|
-
}>;
|
|
68
|
-
};
|
|
69
|
-
type MountGristWidgetConfig = GristWidgetAppProps & {
|
|
70
|
-
/** The element to render into, or its CSS selector. Defaults to `#root`. */
|
|
71
|
-
root?: Element | string;
|
|
72
|
-
};
|
|
73
|
-
type MountedGristWidget = {
|
|
74
|
-
unmount: () => void;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Render a widget into the page: everything `src/main.tsx` used to wire by
|
|
78
|
-
* hand.
|
|
79
|
-
*
|
|
80
|
-
* ```tsx
|
|
81
|
-
* import { mountGristWidget } from "grist-widget-sdk/app"
|
|
82
|
-
* import "./index.css"
|
|
83
|
-
* import App, { GRIST_OPTIONS } from "./App"
|
|
84
|
-
*
|
|
85
|
-
* mountGristWidget({ App, options: GRIST_OPTIONS, dev: import.meta.env.DEV })
|
|
86
|
-
* ```
|
|
87
|
-
*
|
|
88
|
-
* Inside Grist, the widget renders in {@link GristWidgetProvider} and
|
|
89
|
-
* {@link GristBoundary}, which gates on its mapped columns when it declares
|
|
90
|
-
* any, and follows Grist's light/dark theme. Outside Grist, where there is
|
|
91
|
-
* nothing to connect to, the page shows `LocalDevPage` on the dev server and
|
|
92
|
-
* `ReleasePage` on a deployed URL.
|
|
93
|
-
*/
|
|
94
|
-
declare function mountGristWidget(config: MountGristWidgetConfig): MountedGristWidget;
|
|
95
|
-
/**
|
|
96
|
-
* The tree {@link mountGristWidget} renders, as a component: for a test, or
|
|
97
|
-
* for a page that manages its own React root.
|
|
98
|
-
*/
|
|
99
|
-
declare function GristWidgetApp({ App, options, dev, Alerts, LocalDevPage, ReleasePage, }: GristWidgetAppProps): react.JSX.Element;
|
|
100
|
-
|
|
101
6
|
type WidgetTheme = "light" | "dark" | "system";
|
|
102
7
|
type ResolvedWidgetTheme = "light" | "dark";
|
|
103
8
|
type UseThemeResult = {
|
|
@@ -141,5 +46,5 @@ type UseReleasedVersionsResult = {
|
|
|
141
46
|
*/
|
|
142
47
|
declare function useReleasedVersions(pathname?: string): UseReleasedVersionsResult;
|
|
143
48
|
|
|
144
|
-
export {
|
|
145
|
-
export type {
|
|
49
|
+
export { useReleasedVersions, useTheme };
|
|
50
|
+
export type { ReleasedVersion, ResolvedWidgetTheme, UseReleasedVersionsResult, UseThemeResult, WidgetTheme };
|
package/dist/app.d.ts
CHANGED
|
@@ -1,103 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
export { D as DeployChannel, a as DeployPath, G as GristWidgetApp, b as GristWidgetAppProps, c as GristWidgetEntry, M as MountGristWidgetConfig, d as MountedGristWidget, e as deployChannelLabel, f as entryProps, m as mountGristWidget, p as parseDeployPath } from './mount-grist-widget-CkB-3iG_.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import './define-widget-B9gEtJP0.js';
|
|
4
4
|
import './types-DBStn0Dk.js';
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Where a deployed build is being served from.
|
|
8
|
-
*
|
|
9
|
-
* A widget's deploy pipeline publishes the same build at its root and at
|
|
10
|
-
* `/latest/`, a preview at `/dev/`, and each release at `/v<version>/`, all
|
|
11
|
-
* under one base path (e.g. `/my-widget/` on GitHub Pages). Opened outside
|
|
12
|
-
* Grist, the page tells them apart from `window.location.pathname` alone.
|
|
13
|
-
*/
|
|
14
|
-
type DeployChannel = {
|
|
15
|
-
kind: "latest";
|
|
16
|
-
} | {
|
|
17
|
-
kind: "dev";
|
|
18
|
-
} | {
|
|
19
|
-
kind: "version";
|
|
20
|
-
version: string;
|
|
21
|
-
};
|
|
22
|
-
type DeployPath = {
|
|
23
|
-
channel: DeployChannel;
|
|
24
|
-
/**
|
|
25
|
-
* The path the channels live under, always ending in `/`: the current
|
|
26
|
-
* path without its channel segment. `"/my-widget/v1.2.0/"` gives
|
|
27
|
-
* `"/my-widget/"`.
|
|
28
|
-
*/
|
|
29
|
-
basePath: string;
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Parse a pathname into its deploy channel and base path. A path without a
|
|
33
|
-
* channel segment (the deployed root, or a local dev server) is `latest`:
|
|
34
|
-
* the deploy places the latest release at the root too.
|
|
35
|
-
*/
|
|
36
|
-
declare function parseDeployPath(pathname: string): DeployPath;
|
|
37
|
-
/** `"latest"`, `"dev"` or `"v1.2.0"`. */
|
|
38
|
-
declare function deployChannelLabel(channel: DeployChannel): string;
|
|
39
|
-
|
|
40
|
-
type GristWidgetAppProps = {
|
|
41
|
-
/** The widget. A `React.lazy()` component works too: its code then loads only inside Grist. */
|
|
42
|
-
App: ComponentType;
|
|
43
|
-
/** The widget's `GRIST_OPTIONS`: access level, columns, and so on. */
|
|
44
|
-
options: UseGristOptions;
|
|
45
|
-
/**
|
|
46
|
-
* Whether this is the local dev server. Pass `import.meta.env.DEV`.
|
|
47
|
-
* Outside Grist it picks the local-dev page over the release page.
|
|
48
|
-
*/
|
|
49
|
-
dev?: boolean;
|
|
50
|
-
/**
|
|
51
|
-
* Wraps the widget inside Grist, under {@link GristBoundary}. The default
|
|
52
|
-
* lists what needs the user's attention (column mapping, access level,
|
|
53
|
-
* failed writes) above the widget; `null` renders the widget alone.
|
|
54
|
-
*/
|
|
55
|
-
Alerts?: ComponentType<{
|
|
56
|
-
children: ReactNode;
|
|
57
|
-
}> | null;
|
|
58
|
-
/** Shown outside Grist on the local dev server. Defaults to a page pointing at `pnpm test` and the `dev` loop. */
|
|
59
|
-
LocalDevPage?: ComponentType;
|
|
60
|
-
/**
|
|
61
|
-
* Shown outside Grist on a deployed URL (`/latest/`, `/dev/`, `/v<version>/`).
|
|
62
|
-
* Defaults to a page linking every channel and version, with the URL to
|
|
63
|
-
* paste into Grist.
|
|
64
|
-
*/
|
|
65
|
-
ReleasePage?: ComponentType<{
|
|
66
|
-
channel: DeployChannel;
|
|
67
|
-
}>;
|
|
68
|
-
};
|
|
69
|
-
type MountGristWidgetConfig = GristWidgetAppProps & {
|
|
70
|
-
/** The element to render into, or its CSS selector. Defaults to `#root`. */
|
|
71
|
-
root?: Element | string;
|
|
72
|
-
};
|
|
73
|
-
type MountedGristWidget = {
|
|
74
|
-
unmount: () => void;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Render a widget into the page: everything `src/main.tsx` used to wire by
|
|
78
|
-
* hand.
|
|
79
|
-
*
|
|
80
|
-
* ```tsx
|
|
81
|
-
* import { mountGristWidget } from "grist-widget-sdk/app"
|
|
82
|
-
* import "./index.css"
|
|
83
|
-
* import App, { GRIST_OPTIONS } from "./App"
|
|
84
|
-
*
|
|
85
|
-
* mountGristWidget({ App, options: GRIST_OPTIONS, dev: import.meta.env.DEV })
|
|
86
|
-
* ```
|
|
87
|
-
*
|
|
88
|
-
* Inside Grist, the widget renders in {@link GristWidgetProvider} and
|
|
89
|
-
* {@link GristBoundary}, which gates on its mapped columns when it declares
|
|
90
|
-
* any, and follows Grist's light/dark theme. Outside Grist, where there is
|
|
91
|
-
* nothing to connect to, the page shows `LocalDevPage` on the dev server and
|
|
92
|
-
* `ReleasePage` on a deployed URL.
|
|
93
|
-
*/
|
|
94
|
-
declare function mountGristWidget(config: MountGristWidgetConfig): MountedGristWidget;
|
|
95
|
-
/**
|
|
96
|
-
* The tree {@link mountGristWidget} renders, as a component: for a test, or
|
|
97
|
-
* for a page that manages its own React root.
|
|
98
|
-
*/
|
|
99
|
-
declare function GristWidgetApp({ App, options, dev, Alerts, LocalDevPage, ReleasePage, }: GristWidgetAppProps): react.JSX.Element;
|
|
100
|
-
|
|
101
6
|
type WidgetTheme = "light" | "dark" | "system";
|
|
102
7
|
type ResolvedWidgetTheme = "light" | "dark";
|
|
103
8
|
type UseThemeResult = {
|
|
@@ -141,5 +46,5 @@ type UseReleasedVersionsResult = {
|
|
|
141
46
|
*/
|
|
142
47
|
declare function useReleasedVersions(pathname?: string): UseReleasedVersionsResult;
|
|
143
48
|
|
|
144
|
-
export {
|
|
145
|
-
export type {
|
|
49
|
+
export { useReleasedVersions, useTheme };
|
|
50
|
+
export type { ReleasedVersion, ResolvedWidgetTheme, UseReleasedVersionsResult, UseThemeResult, WidgetTheme };
|
package/dist/app.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GristWidgetApp,
|
|
3
3
|
deployChannelLabel,
|
|
4
|
+
entryProps,
|
|
4
5
|
mountGristWidget,
|
|
5
6
|
parseDeployPath,
|
|
6
7
|
useReleasedVersions,
|
|
7
8
|
useTheme
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-P5I5MRC6.js";
|
|
10
|
+
import "./chunk-MAPAWVQC.js";
|
|
10
11
|
import "./chunk-4ZGVKGDF.js";
|
|
11
12
|
export {
|
|
12
13
|
GristWidgetApp,
|
|
13
14
|
deployChannelLabel,
|
|
15
|
+
entryProps,
|
|
14
16
|
mountGristWidget,
|
|
15
17
|
parseDeployPath,
|
|
16
18
|
useReleasedVersions,
|
|
@@ -528,10 +528,13 @@ function checkOne(base, value) {
|
|
|
528
528
|
return ok(value);
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
|
+
function basesOf(type) {
|
|
532
|
+
return (type ?? "Any").split(",").map((t) => t.trim().split(":")[0]).filter(Boolean);
|
|
533
|
+
}
|
|
531
534
|
function checkGristCell(type, value) {
|
|
532
535
|
const error = formulaError(value);
|
|
533
536
|
if (error) return bad(`formula error (${error})`);
|
|
534
|
-
const bases = (type
|
|
537
|
+
const bases = basesOf(type);
|
|
535
538
|
if (bases.length === 0 || bases.includes("Any")) return ok(value === void 0 ? null : value);
|
|
536
539
|
let first = null;
|
|
537
540
|
for (const base of bases) {
|
|
@@ -541,6 +544,19 @@ function checkGristCell(type, value) {
|
|
|
541
544
|
}
|
|
542
545
|
return first;
|
|
543
546
|
}
|
|
547
|
+
var LIST_BASES = ["ChoiceList", "RefList", "Attachments"];
|
|
548
|
+
function encodeGristCell(type, value) {
|
|
549
|
+
if (value === null || value === void 0) return value;
|
|
550
|
+
const bases = basesOf(type);
|
|
551
|
+
const accepts = (...names) => names.some((n) => bases.includes(n));
|
|
552
|
+
if (value instanceof Date) return accepts("Date", "DateTime") ? Math.floor(value.getTime() / 1e3) : value;
|
|
553
|
+
if (Array.isArray(value)) {
|
|
554
|
+
if (!accepts(...LIST_BASES) || value[0] === "L") return value;
|
|
555
|
+
return ["L", ...value.map((item) => rowIdOf(item) ?? item)];
|
|
556
|
+
}
|
|
557
|
+
if (accepts("Ref") && typeof value === "object") return rowIdOf(value) ?? value;
|
|
558
|
+
return value;
|
|
559
|
+
}
|
|
544
560
|
var nameOf = (c) => typeof c === "string" ? c : c.name;
|
|
545
561
|
var typeOf = (c) => typeof c === "string" ? void 0 : c.type;
|
|
546
562
|
var isOptional = (c) => typeof c === "object" && c.optional === true;
|
|
@@ -819,16 +835,24 @@ function createGristApi(runtime) {
|
|
|
819
835
|
throw err;
|
|
820
836
|
}
|
|
821
837
|
};
|
|
822
|
-
|
|
838
|
+
let running = 0;
|
|
839
|
+
let failure = null;
|
|
840
|
+
const write = (fn) => {
|
|
841
|
+
if (running++ === 0) failure = null;
|
|
823
842
|
runtime.update({ actionStatus: "running", actionError: null });
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
843
|
+
const done = (async () => {
|
|
844
|
+
try {
|
|
845
|
+
return await fn();
|
|
846
|
+
} catch (err) {
|
|
847
|
+
failure = message(err);
|
|
848
|
+
throw err;
|
|
849
|
+
} finally {
|
|
850
|
+
if (--running === 0) runtime.update(failure ? { actionStatus: "error", actionError: failure } : { actionStatus: "idle" });
|
|
851
|
+
}
|
|
852
|
+
})();
|
|
853
|
+
done.catch(() => {
|
|
854
|
+
});
|
|
855
|
+
return done;
|
|
832
856
|
};
|
|
833
857
|
const tableOps = (resolve) => ({
|
|
834
858
|
getTableId: () => resolve().getTableId(),
|
|
@@ -973,14 +997,18 @@ function deriveColumnMappingStatus(columns, mappings) {
|
|
|
973
997
|
if (mappings === null) return MAPPINGS_PENDING;
|
|
974
998
|
return validateColumnMappings(columns, mappings);
|
|
975
999
|
}
|
|
976
|
-
function mapBackPatch(patch, mappings) {
|
|
1000
|
+
function mapBackPatch(patch, mappings, columns) {
|
|
977
1001
|
const fields = {};
|
|
978
1002
|
const skipped = [];
|
|
979
1003
|
for (const [name, value] of Object.entries(patch)) {
|
|
980
1004
|
if (value === void 0) continue;
|
|
981
1005
|
const real = mappings[name];
|
|
982
|
-
if (Array.isArray(real))
|
|
983
|
-
|
|
1006
|
+
if (Array.isArray(real)) {
|
|
1007
|
+
skipped.push(name);
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
const declared = columns?.find((c) => nameOf(c) === name);
|
|
1011
|
+
fields[typeof real === "string" && real ? real : name] = declared ? encodeGristCell(typeOf(declared), value) : value;
|
|
984
1012
|
}
|
|
985
1013
|
return { fields, skipped };
|
|
986
1014
|
}
|
|
@@ -1340,7 +1368,27 @@ function useMapped(state, options) {
|
|
|
1340
1368
|
return { record: selected.value, records: mappedRecords, issues: issues.length ? issues : NO_ISSUES };
|
|
1341
1369
|
}, [record, records, mappings, columns, schema]);
|
|
1342
1370
|
}
|
|
1343
|
-
function
|
|
1371
|
+
function recordWrites(connection) {
|
|
1372
|
+
const { runtime, api } = connection;
|
|
1373
|
+
const fieldsOf = (patch) => {
|
|
1374
|
+
const { id: _id, ...rest } = patch;
|
|
1375
|
+
return mapBackPatch(rest, runtime.getState().mappings ?? EMPTY_MAPPINGS, runtime.options.columns).fields;
|
|
1376
|
+
};
|
|
1377
|
+
const updateRecord = ((a, b) => {
|
|
1378
|
+
const rowId = typeof a === "number" ? a : runtime.getState().record?.id;
|
|
1379
|
+
const patch = typeof a === "number" ? b ?? {} : a;
|
|
1380
|
+
if (typeof rowId !== "number") {
|
|
1381
|
+
return Promise.reject(new Error("updateRecord(): no row is selected. Pass the row id: updateRecord(rowId, patch)."));
|
|
1382
|
+
}
|
|
1383
|
+
return api.table.update({ id: rowId, fields: fieldsOf(patch) });
|
|
1384
|
+
});
|
|
1385
|
+
const addRecord = async (patch) => {
|
|
1386
|
+
const created = await api.table.create({ fields: fieldsOf(patch) });
|
|
1387
|
+
return (Array.isArray(created) ? created[0] : created).id;
|
|
1388
|
+
};
|
|
1389
|
+
return { updateRecord, addRecord };
|
|
1390
|
+
}
|
|
1391
|
+
function buildResult(state, mapped, connection, mapBack, resolveMappedColumnId, writes) {
|
|
1344
1392
|
const { runtime, api } = connection;
|
|
1345
1393
|
const status = deriveStatus(state);
|
|
1346
1394
|
const columns = runtime.options.columns;
|
|
@@ -1361,6 +1409,8 @@ function buildResult(state, mapped, connection, mapBack, resolveMappedColumnId)
|
|
|
1361
1409
|
mode: state.isNewRecord ? "new-row" : state.record ? "row" : "empty",
|
|
1362
1410
|
resolveMappedColumnId,
|
|
1363
1411
|
mapBack,
|
|
1412
|
+
updateRecord: writes.updateRecord,
|
|
1413
|
+
addRecord: writes.addRecord,
|
|
1364
1414
|
currentTableId: state.currentTableId,
|
|
1365
1415
|
actionStatus: state.actionStatus,
|
|
1366
1416
|
actionError: state.actionError,
|
|
@@ -1383,7 +1433,7 @@ function useGristResult(connection) {
|
|
|
1383
1433
|
);
|
|
1384
1434
|
const mapBack = useCallback(
|
|
1385
1435
|
(patch) => {
|
|
1386
|
-
const { fields, skipped } = mapBackPatch(patch, mappings);
|
|
1436
|
+
const { fields, skipped } = mapBackPatch(patch, mappings, runtime.options.columns);
|
|
1387
1437
|
const previous = runtime.getState().mapBackSkipped;
|
|
1388
1438
|
if (previous.join("\0") !== skipped.join("\0")) runtime.update({ mapBackSkipped: skipped });
|
|
1389
1439
|
return fields;
|
|
@@ -1391,9 +1441,10 @@ function useGristResult(connection) {
|
|
|
1391
1441
|
[mappings, runtime]
|
|
1392
1442
|
);
|
|
1393
1443
|
const mapped = useMapped(state, runtime.options);
|
|
1444
|
+
const writes = useMemo(() => recordWrites(connection), [connection]);
|
|
1394
1445
|
return useMemo(
|
|
1395
|
-
() => buildResult(state, mapped, connection, mapBack, resolveMappedColumnId),
|
|
1396
|
-
[state, mapped, connection, mapBack, resolveMappedColumnId]
|
|
1446
|
+
() => buildResult(state, mapped, connection, mapBack, resolveMappedColumnId, writes),
|
|
1447
|
+
[state, mapped, connection, mapBack, resolveMappedColumnId, writes]
|
|
1397
1448
|
);
|
|
1398
1449
|
}
|
|
1399
1450
|
function useGrist(options) {
|
|
@@ -1435,6 +1486,20 @@ function useNearestGristState() {
|
|
|
1435
1486
|
return { connection, state, cellIssues: issues };
|
|
1436
1487
|
}
|
|
1437
1488
|
|
|
1489
|
+
// src/sdk/define-widget.ts
|
|
1490
|
+
function defineGristWidget(definition) {
|
|
1491
|
+
const { title, description, ...options } = definition;
|
|
1492
|
+
return {
|
|
1493
|
+
definition,
|
|
1494
|
+
options,
|
|
1495
|
+
metadata: { title, description },
|
|
1496
|
+
useGrist: () => useGrist(options)
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function isGristWidget(value) {
|
|
1500
|
+
return typeof value === "object" && value !== null && "definition" in value && "useGrist" in value;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1438
1503
|
// src/sdk/components/grist-widget-provider.tsx
|
|
1439
1504
|
import { useState } from "react";
|
|
1440
1505
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -1641,9 +1706,9 @@ function useGristSchema(options) {
|
|
|
1641
1706
|
const [document2, setDocument] = useState3(null);
|
|
1642
1707
|
const [loading, setLoading] = useState3(false);
|
|
1643
1708
|
const [error, setError] = useState3(null);
|
|
1644
|
-
const includeRowsForBuild = replicaRowMode === "schema-only" ? false : replicaRowMode === "schema+data" ? "full" : "samples";
|
|
1645
1709
|
const load = useCallback3(async () => {
|
|
1646
1710
|
if (!docApi) return;
|
|
1711
|
+
const includeRowsForBuild = replicaRowMode === "schema-only" ? false : replicaRowMode === "schema+data" ? "full" : "samples";
|
|
1647
1712
|
setLoading(true);
|
|
1648
1713
|
setError(null);
|
|
1649
1714
|
try {
|
|
@@ -1813,18 +1878,21 @@ export {
|
|
|
1813
1878
|
gristAttachmentCellValue,
|
|
1814
1879
|
mergeGristAttachmentCellValue,
|
|
1815
1880
|
isAccessInsufficientError,
|
|
1881
|
+
checkGristCell,
|
|
1882
|
+
encodeGristCell,
|
|
1816
1883
|
deriveStatus,
|
|
1817
1884
|
deriveColumnMappingStatus,
|
|
1818
|
-
checkGristCell,
|
|
1819
1885
|
parseGristWidgetLinkingInfo,
|
|
1820
1886
|
resetGristForTests,
|
|
1821
1887
|
useGrist,
|
|
1822
1888
|
useGristOptional,
|
|
1823
1889
|
useGristContext,
|
|
1824
1890
|
useNearestGristState,
|
|
1891
|
+
defineGristWidget,
|
|
1892
|
+
isGristWidget,
|
|
1825
1893
|
GristWidgetProvider,
|
|
1826
1894
|
GristBoundary,
|
|
1827
1895
|
useGristSchema,
|
|
1828
1896
|
useWidgetMetadata
|
|
1829
1897
|
};
|
|
1830
|
-
//# sourceMappingURL=chunk-
|
|
1898
|
+
//# sourceMappingURL=chunk-MAPAWVQC.js.map
|