@instantdb/components 0.22.89 → 0.22.90-experimental.drewh-usd-default.20285674543.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/.turbo/turbo-build.log +5 -5
- package/app/App.tsx +4 -2
- package/dist/components/explorer/index.d.ts.map +1 -1
- package/dist/components/explorer/inner-explorer.d.ts.map +1 -1
- package/dist/components/explorer/view-settings.d.ts.map +1 -1
- package/dist/components/ui.d.ts +3 -2
- package/dist/components/ui.d.ts.map +1 -1
- package/dist/index.cjs +7 -7
- package/dist/index.js +2123 -2034
- package/package.json +9 -8
- package/src/components/explorer/explorer-layout.tsx +2 -2
- package/src/components/explorer/index.tsx +9 -1
- package/src/components/explorer/inner-explorer.tsx +168 -18
- package/src/components/explorer/view-settings.tsx +1 -0
- package/src/components/ui.tsx +9 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instantdb/components",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.22.
|
|
4
|
+
"version": "0.22.90-experimental.drewh-usd-default.20285674543.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Instant's UI components",
|
|
7
7
|
"homepage": "https://github.com/instantdb/instant/tree/main/client/packages/components",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"vitest": "^1.6.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"react": "^18.3.1",
|
|
58
|
-
"react-dom": "^18.3.1"
|
|
57
|
+
"react": "^18.3.1 || ^19.0.0",
|
|
58
|
+
"react-dom": "^18.3.1 || ^19.0.0"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@babel/parser": "^8.0.0-beta.0",
|
|
@@ -74,6 +74,7 @@
|
|
|
74
74
|
"@radix-ui/react-switch": "^1.2.6",
|
|
75
75
|
"@radix-ui/react-toggle-group": "^1.0.4",
|
|
76
76
|
"@radix-ui/react-tooltip": "^1.1.7",
|
|
77
|
+
"@radix-ui/react-visually-hidden": "^1.2.4",
|
|
77
78
|
"@tanstack/react-table": "^8.21.3",
|
|
78
79
|
"clsx": "^2.1.0",
|
|
79
80
|
"copy-to-clipboard": "^3.3.3",
|
|
@@ -92,11 +93,11 @@
|
|
|
92
93
|
"swr": "^2.2.4",
|
|
93
94
|
"tailwind-merge": "^2.2.1",
|
|
94
95
|
"uuid": "^11.1.0",
|
|
95
|
-
"@instantdb/admin": "0.22.
|
|
96
|
-
"@instantdb/
|
|
97
|
-
"@instantdb/
|
|
98
|
-
"@instantdb/
|
|
99
|
-
"@instantdb/platform": "0.22.
|
|
96
|
+
"@instantdb/admin": "0.22.90-experimental.drewh-usd-default.20285674543.1",
|
|
97
|
+
"@instantdb/react": "0.22.90-experimental.drewh-usd-default.20285674543.1",
|
|
98
|
+
"@instantdb/version": "0.22.90-experimental.drewh-usd-default.20285674543.1",
|
|
99
|
+
"@instantdb/core": "0.22.90-experimental.drewh-usd-default.20285674543.1",
|
|
100
|
+
"@instantdb/platform": "0.22.90-experimental.drewh-usd-default.20285674543.1"
|
|
100
101
|
},
|
|
101
102
|
"scripts": {
|
|
102
103
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -55,10 +55,10 @@ export const ExplorerLayout = ({
|
|
|
55
55
|
props.className,
|
|
56
56
|
)}
|
|
57
57
|
>
|
|
58
|
-
<Dialog {...recentlyDeletedNsDialog}>
|
|
58
|
+
<Dialog title="Recently Deleted Namespaces" {...recentlyDeletedNsDialog}>
|
|
59
59
|
<RecentlyDeletedNamespaces appId={props.appId} db={db} />
|
|
60
60
|
</Dialog>
|
|
61
|
-
<Dialog {...newNsDialog}>
|
|
61
|
+
<Dialog title="New Namespace" {...newNsDialog}>
|
|
62
62
|
<NewNamespaceDialog
|
|
63
63
|
db={db}
|
|
64
64
|
onClose={(p) => {
|
|
@@ -91,7 +91,7 @@ const fillPropsWithDefaults = (
|
|
|
91
91
|
// In uncontrolled mode, use the internal state
|
|
92
92
|
explorerState: controlled ? (input.explorerState ?? null) : _explorerState,
|
|
93
93
|
setExplorerState: input.setExplorerState || setExplorerState,
|
|
94
|
-
useShadowDOM: input.useShadowDOM
|
|
94
|
+
useShadowDOM: input.useShadowDOM === undefined ? true : input.useShadowDOM,
|
|
95
95
|
};
|
|
96
96
|
};
|
|
97
97
|
|
|
@@ -120,12 +120,20 @@ export const Explorer = (_props: WithOptional<ExplorerProps>) => {
|
|
|
120
120
|
const [_explorerState, _setExplorerState] = useState<ExplorerNav | null>(
|
|
121
121
|
null,
|
|
122
122
|
);
|
|
123
|
+
|
|
123
124
|
const props: WithDefaults<ExplorerProps> = fillPropsWithDefaults(
|
|
124
125
|
_props,
|
|
125
126
|
_explorerState,
|
|
126
127
|
_setExplorerState,
|
|
127
128
|
);
|
|
128
129
|
|
|
130
|
+
if (!props.adminToken) {
|
|
131
|
+
throw new Error('adminToken is required for explorer');
|
|
132
|
+
}
|
|
133
|
+
if (!props.appId) {
|
|
134
|
+
throw new Error('appId is required for explorer');
|
|
135
|
+
}
|
|
136
|
+
|
|
129
137
|
// inside the component avoid setting explorer state directly
|
|
130
138
|
// if change could be useful for history
|
|
131
139
|
const { explorerState, setExplorerState } = props;
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
useSensor,
|
|
9
9
|
useSensors,
|
|
10
10
|
} from '@dnd-kit/core';
|
|
11
|
+
import { markdownTable } from 'markdown-table';
|
|
12
|
+
|
|
13
|
+
import { mkConfig, generateCsv, download } from 'export-to-csv';
|
|
14
|
+
|
|
11
15
|
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
|
|
12
16
|
import {
|
|
13
17
|
arrayMove,
|
|
@@ -77,6 +81,7 @@ import { ViewSettings } from './view-settings';
|
|
|
77
81
|
import { isObject } from 'lodash';
|
|
78
82
|
import { EditNamespaceDialog } from './edit-namespace-dialog';
|
|
79
83
|
import { EditRowDialog } from './edit-row-dialog';
|
|
84
|
+
import copy from 'copy-to-clipboard';
|
|
80
85
|
|
|
81
86
|
const fallbackItems: any[] = [];
|
|
82
87
|
|
|
@@ -88,6 +93,147 @@ export type TableColMeta = {
|
|
|
88
93
|
copyable?: boolean;
|
|
89
94
|
};
|
|
90
95
|
|
|
96
|
+
function exportToCSV(
|
|
97
|
+
rows: any[],
|
|
98
|
+
columns: ColumnDef<any>[],
|
|
99
|
+
namespace: string,
|
|
100
|
+
downloadFile: boolean = false,
|
|
101
|
+
) {
|
|
102
|
+
if (rows.length === 0) return;
|
|
103
|
+
|
|
104
|
+
const visibleColumns = columns.filter(
|
|
105
|
+
(col) =>
|
|
106
|
+
col.id !== 'select-col' &&
|
|
107
|
+
col.header !== undefined &&
|
|
108
|
+
!(col.meta as TableColMeta | undefined)?.isLink,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const data = rows.map((row) => {
|
|
112
|
+
const rowData: Record<string, any> = {};
|
|
113
|
+
visibleColumns.forEach((col: any) => {
|
|
114
|
+
const value = row[col.header];
|
|
115
|
+
// Handle different data types
|
|
116
|
+
if (value === null || value === undefined) {
|
|
117
|
+
rowData[col.header] = '';
|
|
118
|
+
} else if (typeof value === 'object') {
|
|
119
|
+
rowData[col.header] = JSON.stringify(value);
|
|
120
|
+
} else {
|
|
121
|
+
rowData[col.header] = value;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return rowData;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const csvConfig = mkConfig({
|
|
128
|
+
fieldSeparator: ',',
|
|
129
|
+
filename: `${namespace}_export`,
|
|
130
|
+
decimalSeparator: '.',
|
|
131
|
+
useKeysAsHeaders: true,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const csv = generateCsv(csvConfig)(data);
|
|
135
|
+
|
|
136
|
+
if (downloadFile) {
|
|
137
|
+
download(csvConfig)(csv);
|
|
138
|
+
successToast('CSV file downloaded');
|
|
139
|
+
} else {
|
|
140
|
+
copy(csv.toString());
|
|
141
|
+
successToast('CSV copied to clipboard');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function exportToMarkdown(
|
|
146
|
+
rows: any[],
|
|
147
|
+
columns: any[],
|
|
148
|
+
namespace: string,
|
|
149
|
+
downloadFile: boolean = false,
|
|
150
|
+
) {
|
|
151
|
+
if (rows.length === 0) return;
|
|
152
|
+
|
|
153
|
+
const visibleColumns = columns.filter(
|
|
154
|
+
(col) =>
|
|
155
|
+
col.id !== 'select-col' &&
|
|
156
|
+
col.header !== undefined &&
|
|
157
|
+
!(col.meta as TableColMeta | undefined)?.isLink,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const headers = visibleColumns.map((col: any) => col.header as string);
|
|
161
|
+
|
|
162
|
+
const data = rows.map((row) => {
|
|
163
|
+
return visibleColumns.map((col: any) => {
|
|
164
|
+
const value = row[col.header];
|
|
165
|
+
if (value === null || value === undefined) {
|
|
166
|
+
return ' ';
|
|
167
|
+
} else if (typeof value === 'object') {
|
|
168
|
+
return JSON.stringify(value);
|
|
169
|
+
} else {
|
|
170
|
+
return String(value);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const markdown = markdownTable([headers, ...data]);
|
|
176
|
+
|
|
177
|
+
if (downloadFile) {
|
|
178
|
+
const blob = new Blob([markdown], { type: 'text/markdown' });
|
|
179
|
+
const url = URL.createObjectURL(blob);
|
|
180
|
+
const a = document.createElement('a');
|
|
181
|
+
a.href = url;
|
|
182
|
+
a.download = `${namespace}_export.md`;
|
|
183
|
+
document.body.appendChild(a);
|
|
184
|
+
a.click();
|
|
185
|
+
document.body.removeChild(a);
|
|
186
|
+
URL.revokeObjectURL(url);
|
|
187
|
+
successToast('Markdown file downloaded');
|
|
188
|
+
} else {
|
|
189
|
+
copy(markdown);
|
|
190
|
+
successToast('Markdown copied to clipboard');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function exportToJSON(
|
|
195
|
+
rows: any[],
|
|
196
|
+
columns: any[],
|
|
197
|
+
namespace: string,
|
|
198
|
+
downloadFile: boolean = false,
|
|
199
|
+
) {
|
|
200
|
+
if (rows.length === 0) return;
|
|
201
|
+
|
|
202
|
+
const visibleColumns = columns.filter(
|
|
203
|
+
(col) =>
|
|
204
|
+
col.id !== 'select-col' &&
|
|
205
|
+
col.header !== undefined &&
|
|
206
|
+
!(col.meta as TableColMeta | undefined)?.isLink,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const data = rows.map((row) => {
|
|
210
|
+
const rowData: Record<string, any> = {};
|
|
211
|
+
visibleColumns.forEach((col: any) => {
|
|
212
|
+
const value = row[col.header];
|
|
213
|
+
rowData[col.header] = value;
|
|
214
|
+
});
|
|
215
|
+
return rowData;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const json = JSON.stringify(data, null, 2);
|
|
219
|
+
|
|
220
|
+
if (downloadFile) {
|
|
221
|
+
const blob = new Blob([json], { type: 'application/json' });
|
|
222
|
+
const url = URL.createObjectURL(blob);
|
|
223
|
+
const a = document.createElement('a');
|
|
224
|
+
a.href = url;
|
|
225
|
+
a.download = `${namespace}_export.json`;
|
|
226
|
+
document.body.appendChild(a);
|
|
227
|
+
a.click();
|
|
228
|
+
document.body.removeChild(a);
|
|
229
|
+
URL.revokeObjectURL(url);
|
|
230
|
+
successToast('JSON file downloaded');
|
|
231
|
+
} else {
|
|
232
|
+
copy(json);
|
|
233
|
+
successToast('JSON copied to clipboard');
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
91
237
|
export const InnerExplorer: React.FC<{
|
|
92
238
|
db: InstantReactAbstractDatabase<any, any>;
|
|
93
239
|
namespaces: SchemaNamespace[];
|
|
@@ -684,6 +830,7 @@ export const InnerExplorer: React.FC<{
|
|
|
684
830
|
return (
|
|
685
831
|
<>
|
|
686
832
|
<Dialog
|
|
833
|
+
title="Delete Rows"
|
|
687
834
|
open={deleteDataConfirmationOpen}
|
|
688
835
|
onClose={() => setDeleteDataConfirmationOpen(false)}
|
|
689
836
|
>
|
|
@@ -754,6 +901,7 @@ export const InnerExplorer: React.FC<{
|
|
|
754
901
|
) : null}
|
|
755
902
|
</Dialog>
|
|
756
903
|
<Dialog
|
|
904
|
+
title="Edit Row"
|
|
757
905
|
open={addItemDialogOpen}
|
|
758
906
|
onClose={() => setAddItemDialogOpen(false)}
|
|
759
907
|
>
|
|
@@ -767,6 +915,7 @@ export const InnerExplorer: React.FC<{
|
|
|
767
915
|
) : null}
|
|
768
916
|
</Dialog>
|
|
769
917
|
<Dialog
|
|
918
|
+
title="Edit Row"
|
|
770
919
|
open={!!selectedEditableItem}
|
|
771
920
|
onClose={() => setEditableRowId(null)}
|
|
772
921
|
>
|
|
@@ -780,6 +929,7 @@ export const InnerExplorer: React.FC<{
|
|
|
780
929
|
) : null}
|
|
781
930
|
</Dialog>
|
|
782
931
|
<Dialog
|
|
932
|
+
title="Edit Namespace"
|
|
783
933
|
stopFocusPropagation={true}
|
|
784
934
|
open={Boolean(editNs)}
|
|
785
935
|
onClose={() => setEditNs(null)}
|
|
@@ -1086,12 +1236,12 @@ export const InnerExplorer: React.FC<{
|
|
|
1086
1236
|
allItems,
|
|
1087
1237
|
checkedIds,
|
|
1088
1238
|
);
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1239
|
+
exportToCSV(
|
|
1240
|
+
selectedRows,
|
|
1241
|
+
columns,
|
|
1242
|
+
selectedNamespace.name,
|
|
1243
|
+
isShiftPressed,
|
|
1244
|
+
);
|
|
1095
1245
|
setDropdownOpen(false);
|
|
1096
1246
|
}}
|
|
1097
1247
|
className="flex items-center gap-2"
|
|
@@ -1106,12 +1256,12 @@ export const InnerExplorer: React.FC<{
|
|
|
1106
1256
|
allItems,
|
|
1107
1257
|
checkedIds,
|
|
1108
1258
|
);
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1259
|
+
exportToMarkdown(
|
|
1260
|
+
selectedRows,
|
|
1261
|
+
columns,
|
|
1262
|
+
selectedNamespace.name,
|
|
1263
|
+
isShiftPressed,
|
|
1264
|
+
);
|
|
1115
1265
|
setDropdownOpen(false);
|
|
1116
1266
|
}}
|
|
1117
1267
|
className="flex items-center gap-2"
|
|
@@ -1128,12 +1278,12 @@ export const InnerExplorer: React.FC<{
|
|
|
1128
1278
|
allItems,
|
|
1129
1279
|
checkedIds,
|
|
1130
1280
|
);
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1281
|
+
exportToJSON(
|
|
1282
|
+
selectedRows,
|
|
1283
|
+
columns,
|
|
1284
|
+
selectedNamespace.name,
|
|
1285
|
+
isShiftPressed,
|
|
1286
|
+
);
|
|
1137
1287
|
setDropdownOpen(false);
|
|
1138
1288
|
}}
|
|
1139
1289
|
className="flex items-center gap-2"
|
package/src/components/ui.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { Toaster, toast } from 'sonner';
|
|
3
|
+
import { VisuallyHidden } from '@radix-ui/react-visually-hidden';
|
|
3
4
|
import { Editor, Monaco, OnMount } from '@monaco-editor/react';
|
|
4
5
|
import type { ClassValue } from 'clsx';
|
|
5
6
|
import clsx from 'clsx';
|
|
@@ -635,6 +636,7 @@ function DialogContent({
|
|
|
635
636
|
className,
|
|
636
637
|
children,
|
|
637
638
|
showCloseButton = false,
|
|
639
|
+
title,
|
|
638
640
|
...props
|
|
639
641
|
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
640
642
|
showCloseButton?: boolean;
|
|
@@ -654,6 +656,9 @@ function DialogContent({
|
|
|
654
656
|
)}
|
|
655
657
|
{...props}
|
|
656
658
|
>
|
|
659
|
+
<VisuallyHidden>
|
|
660
|
+
<DialogTitle>{title}</DialogTitle>
|
|
661
|
+
</VisuallyHidden>
|
|
657
662
|
{children}
|
|
658
663
|
{showCloseButton && (
|
|
659
664
|
<DialogPrimitive.Close
|
|
@@ -677,11 +682,13 @@ export function Dialog({
|
|
|
677
682
|
children,
|
|
678
683
|
onClose,
|
|
679
684
|
className,
|
|
685
|
+
title,
|
|
680
686
|
stopFocusPropagation = false,
|
|
681
687
|
hideCloseButton = false,
|
|
682
688
|
}: {
|
|
683
689
|
open: boolean;
|
|
684
690
|
children: React.ReactNode;
|
|
691
|
+
title: string;
|
|
685
692
|
onClose: () => void;
|
|
686
693
|
className?: string;
|
|
687
694
|
stopFocusPropagation?: boolean;
|
|
@@ -697,6 +704,7 @@ export function Dialog({
|
|
|
697
704
|
open={open}
|
|
698
705
|
>
|
|
699
706
|
<DialogContent
|
|
707
|
+
title={title}
|
|
700
708
|
onFocusCapture={(e) => {
|
|
701
709
|
if (stopFocusPropagation) {
|
|
702
710
|
e.stopPropagation();
|
|
@@ -1533,6 +1541,7 @@ export function Fence({
|
|
|
1533
1541
|
import * as SwitchPrimitive from '@radix-ui/react-switch';
|
|
1534
1542
|
import { rosePineDawnTheme } from './rosePineDawnTheme';
|
|
1535
1543
|
import { useShadowRoot, useShadowDarkMode } from './StyleMe';
|
|
1544
|
+
import { DialogTitle } from '@radix-ui/react-dialog';
|
|
1536
1545
|
function Switch({
|
|
1537
1546
|
className,
|
|
1538
1547
|
...props
|