@react-fabric/data 1.0.0-beta.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/LICENSE +21 -0
- package/README.md +10 -0
- package/dist/cjs/histogram/Histogram.js +89 -0
- package/dist/cjs/histogram/Histogram.module.css +1 -0
- package/dist/cjs/hooks/useFilteredList.js +56 -0
- package/dist/cjs/hooks/usePagination.js +85 -0
- package/dist/cjs/i18n/ar.json.js +56 -0
- package/dist/cjs/i18n/en.json.js +56 -0
- package/dist/cjs/i18n/index.js +33 -0
- package/dist/cjs/index.js +24 -0
- package/dist/cjs/json/JsonViewer.js +246 -0
- package/dist/cjs/pagination/Pagination.js +100 -0
- package/dist/cjs/table/BodyCell.js +47 -0
- package/dist/cjs/table/HeaderCell.js +79 -0
- package/dist/cjs/table/Table.js +133 -0
- package/dist/cjs/table/useTableColumns.js +26 -0
- package/dist/cjs/table/useVirtualTable.js +56 -0
- package/dist/cjs/tree/TreeNode.js +107 -0
- package/dist/cjs/tree/TreePanel.js +136 -0
- package/dist/cjs/tree/types.js +30 -0
- package/dist/cjs/tree/useTree.js +181 -0
- package/dist/cjs/tree/utils.js +145 -0
- package/dist/cjs/virtual/Gallery.js +229 -0
- package/dist/cjs/virtual/List.js +218 -0
- package/dist/cjs/virtual/Scroller.js +77 -0
- package/dist/esm/histogram/Histogram.js +89 -0
- package/dist/esm/histogram/Histogram.module.css +1 -0
- package/dist/esm/hooks/useFilteredList.js +56 -0
- package/dist/esm/hooks/usePagination.js +85 -0
- package/dist/esm/i18n/ar.json.js +47 -0
- package/dist/esm/i18n/en.json.js +47 -0
- package/dist/esm/i18n/index.js +33 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/json/JsonViewer.js +246 -0
- package/dist/esm/pagination/Pagination.js +100 -0
- package/dist/esm/table/BodyCell.js +47 -0
- package/dist/esm/table/HeaderCell.js +79 -0
- package/dist/esm/table/Table.js +133 -0
- package/dist/esm/table/useTableColumns.js +26 -0
- package/dist/esm/table/useVirtualTable.js +56 -0
- package/dist/esm/tree/TreeNode.js +107 -0
- package/dist/esm/tree/TreePanel.js +136 -0
- package/dist/esm/tree/types.js +29 -0
- package/dist/esm/tree/useTree.js +181 -0
- package/dist/esm/tree/utils.js +140 -0
- package/dist/esm/virtual/Gallery.js +229 -0
- package/dist/esm/virtual/List.js +218 -0
- package/dist/esm/virtual/Scroller.js +77 -0
- package/dist/types/histogram/Histogram.d.ts +41 -0
- package/dist/types/hooks/useFilteredList.d.ts +7 -0
- package/dist/types/hooks/usePagination.d.ts +25 -0
- package/dist/types/i18n/index.d.ts +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/json/JsonViewer.d.ts +59 -0
- package/dist/types/pagination/Pagination.d.ts +24 -0
- package/dist/types/table/BodyCell.d.ts +5 -0
- package/dist/types/table/HeaderCell.d.ts +2 -0
- package/dist/types/table/Table.d.ts +2 -0
- package/dist/types/table/types.d.ts +26 -0
- package/dist/types/table/useTableColumns.d.ts +8 -0
- package/dist/types/table/useVirtualTable.d.ts +8 -0
- package/dist/types/tree/TreeNode.d.ts +2 -0
- package/dist/types/tree/TreePanel.d.ts +2 -0
- package/dist/types/tree/types.d.ts +138 -0
- package/dist/types/tree/useTree.d.ts +20 -0
- package/dist/types/tree/utils.d.ts +10 -0
- package/dist/types/virtual/Gallery.d.ts +55 -0
- package/dist/types/virtual/List.d.ts +59 -0
- package/dist/types/virtual/Scroller.d.ts +8 -0
- package/package.json +55 -0
- package/src/histogram/Histogram.module.css +57 -0
- package/src/histogram/Histogram.tsx +176 -0
- package/src/hooks/useFilteredList.tsx +78 -0
- package/src/hooks/usePagination.tsx +135 -0
- package/src/i18n/ar.json +36 -0
- package/src/i18n/en.json +36 -0
- package/src/i18n/index.ts +28 -0
- package/src/index.ts +35 -0
- package/src/json/JsonViewer.tsx +381 -0
- package/src/pagination/Pagination.tsx +157 -0
- package/src/table/BodyCell.tsx +54 -0
- package/src/table/HeaderCell.tsx +70 -0
- package/src/table/Table.tsx +143 -0
- package/src/table/types.ts +65 -0
- package/src/table/useTableColumns.ts +52 -0
- package/src/table/useVirtualTable.ts +54 -0
- package/src/tree/TreeNode.tsx +163 -0
- package/src/tree/TreePanel.tsx +157 -0
- package/src/tree/types.ts +181 -0
- package/src/tree/useTree.ts +227 -0
- package/src/tree/utils.ts +185 -0
- package/src/virtual/Gallery.tsx +349 -0
- package/src/virtual/List.tsx +351 -0
- package/src/virtual/Scroller.tsx +81 -0
package/src/i18n/en.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"label": {
|
|
3
|
+
"noRecords": "No Records"
|
|
4
|
+
},
|
|
5
|
+
"tree": {
|
|
6
|
+
"noItems": "No items",
|
|
7
|
+
"error": "Error loading items",
|
|
8
|
+
"loading": "Loading items..."
|
|
9
|
+
},
|
|
10
|
+
"datagrid": {
|
|
11
|
+
"empty": "No records available"
|
|
12
|
+
},
|
|
13
|
+
"json": {
|
|
14
|
+
"empty": "No data properties",
|
|
15
|
+
"true": "Yes",
|
|
16
|
+
"false": "No"
|
|
17
|
+
},
|
|
18
|
+
"checkList": {
|
|
19
|
+
"empty": "No list items"
|
|
20
|
+
},
|
|
21
|
+
"histogram": {
|
|
22
|
+
"empty": "No histograms"
|
|
23
|
+
},
|
|
24
|
+
"action": {
|
|
25
|
+
"find": "Find...",
|
|
26
|
+
"copy": "Copy Value",
|
|
27
|
+
"filter": "Filter...",
|
|
28
|
+
"showShortcuts": "Keyboard shortcuts...",
|
|
29
|
+
"collapseAll": "Collapse All",
|
|
30
|
+
"expandAll": "Expand All",
|
|
31
|
+
"checkAll": "Check All",
|
|
32
|
+
"uncheckAll": "Uncheck All",
|
|
33
|
+
"addFilter": "Add Filter",
|
|
34
|
+
"addFilterNot": "Add not Filter"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2024 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { addTranslationBundle } from "@react-fabric/core";
|
|
25
|
+
import ar from "./ar.json";
|
|
26
|
+
import en from "./en.json";
|
|
27
|
+
|
|
28
|
+
addTranslationBundle("data", { en, ar });
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2024 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import "./i18n";
|
|
25
|
+
|
|
26
|
+
export { Histogram } from "./histogram/Histogram";
|
|
27
|
+
export { JsonViewer } from "./json/JsonViewer";
|
|
28
|
+
export { Pagination } from "./pagination/Pagination";
|
|
29
|
+
export { Table } from "./table/Table";
|
|
30
|
+
export { TreePanel } from "./tree/TreePanel";
|
|
31
|
+
export { VirtualGallery, type VirtualGalleryRef } from "./virtual/Gallery";
|
|
32
|
+
export { VirtualList, type VirtualListRef } from "./virtual/List";
|
|
33
|
+
|
|
34
|
+
export * from "./hooks/useFilteredList";
|
|
35
|
+
export * from "./hooks/usePagination";
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2024 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
ActionLabel,
|
|
26
|
+
Button,
|
|
27
|
+
Copy,
|
|
28
|
+
CoreIcons,
|
|
29
|
+
EmptyContent,
|
|
30
|
+
Icon,
|
|
31
|
+
Meter,
|
|
32
|
+
Text,
|
|
33
|
+
} from "@react-fabric/core";
|
|
34
|
+
import { type CssProp } from "@react-fabric/core/dist/types/types";
|
|
35
|
+
import {
|
|
36
|
+
Format,
|
|
37
|
+
isArray,
|
|
38
|
+
isBoolean,
|
|
39
|
+
isEmpty,
|
|
40
|
+
isNil,
|
|
41
|
+
isObject,
|
|
42
|
+
isTrue,
|
|
43
|
+
} from "@react-fabric/utilities";
|
|
44
|
+
import classNames from "classnames";
|
|
45
|
+
import { Fragment, useMemo, useState } from "react";
|
|
46
|
+
import { useTranslation } from "react-i18next";
|
|
47
|
+
|
|
48
|
+
export interface JsonViewProps<T> extends CssProp {
|
|
49
|
+
/**
|
|
50
|
+
* json value
|
|
51
|
+
*/
|
|
52
|
+
json: T;
|
|
53
|
+
/**
|
|
54
|
+
* display inline
|
|
55
|
+
*/
|
|
56
|
+
inline?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* label fixed width when using inline
|
|
59
|
+
*/
|
|
60
|
+
labelWidth?: number | string;
|
|
61
|
+
/**
|
|
62
|
+
* display object properties as tree
|
|
63
|
+
* @default true
|
|
64
|
+
*/
|
|
65
|
+
showPropertyTree?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* properties to format as dates
|
|
68
|
+
* (default format applied to property name containing `date` | `time`)
|
|
69
|
+
*/
|
|
70
|
+
propertyScheme?: {
|
|
71
|
+
boolean?: string[];
|
|
72
|
+
date?: string[];
|
|
73
|
+
time?: string[];
|
|
74
|
+
number?: string[];
|
|
75
|
+
bytes?: string[];
|
|
76
|
+
percent?: string[];
|
|
77
|
+
phone?: string[];
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* enable value copy
|
|
81
|
+
*/
|
|
82
|
+
copy?: true | string[];
|
|
83
|
+
/**
|
|
84
|
+
* enable filter callbacks
|
|
85
|
+
*/
|
|
86
|
+
filters?: true | string[];
|
|
87
|
+
/**
|
|
88
|
+
* message for empty json
|
|
89
|
+
*/
|
|
90
|
+
emptyMessage?: string;
|
|
91
|
+
/**
|
|
92
|
+
* on filter callback
|
|
93
|
+
*/
|
|
94
|
+
onFilter?: (path: string, value: AnyObject, negate: boolean) => void;
|
|
95
|
+
/**
|
|
96
|
+
* render function for custom label display
|
|
97
|
+
*/
|
|
98
|
+
labeler?: (path: string) => string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* render function for custom value display
|
|
101
|
+
*/
|
|
102
|
+
formatter?: (
|
|
103
|
+
path?: string,
|
|
104
|
+
value?: AnyObject,
|
|
105
|
+
) => string | JSX.Element | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const reduceObject = (json: AnyObject, keys: string[] = [], prefix = "") => {
|
|
109
|
+
const ret: AnyObject[] = [];
|
|
110
|
+
Object.entries(json).forEach(([key, value]) => {
|
|
111
|
+
if (isArray(value) && isObject(value[0])) {
|
|
112
|
+
ret.push(...reduceObject(value, [...keys, key], key));
|
|
113
|
+
} else {
|
|
114
|
+
const obj: KeyValue = {
|
|
115
|
+
field: prefix ? `${prefix}.${key}` : key,
|
|
116
|
+
value,
|
|
117
|
+
path: [...keys, key].join("."),
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (isObject(value) && !isEmpty(value) && !("_score_" in value)) {
|
|
121
|
+
obj.children = reduceObject(value, [...keys, key]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
ret.push(obj);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return ret.flat(99);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const JsonEntry = ({
|
|
132
|
+
value,
|
|
133
|
+
path,
|
|
134
|
+
field,
|
|
135
|
+
children,
|
|
136
|
+
copy,
|
|
137
|
+
filters,
|
|
138
|
+
labeler,
|
|
139
|
+
formatter,
|
|
140
|
+
propertyScheme,
|
|
141
|
+
showPropertyTree,
|
|
142
|
+
onFilter,
|
|
143
|
+
inline,
|
|
144
|
+
labelWidth = "30%",
|
|
145
|
+
level = 0,
|
|
146
|
+
}: KeyValue) => {
|
|
147
|
+
const { t } = useTranslation("data");
|
|
148
|
+
|
|
149
|
+
const [expanded, setExpanded] = useState(true);
|
|
150
|
+
|
|
151
|
+
const canExpand = useMemo(() => !!children, [children]);
|
|
152
|
+
|
|
153
|
+
const actualValue = useMemo(() => value?._label_ ?? value ?? "", [value]);
|
|
154
|
+
|
|
155
|
+
const display = useMemo(() => {
|
|
156
|
+
if (children) return null;
|
|
157
|
+
if (isNil(value)) return <span className="text-muted">null</span>;
|
|
158
|
+
if (isEmpty(value)) return <span className="text-muted">empty</span>;
|
|
159
|
+
|
|
160
|
+
let ret = actualValue;
|
|
161
|
+
if (formatter) {
|
|
162
|
+
const formatted = formatter?.(path, actualValue);
|
|
163
|
+
if (!isNil(formatted)) ret = formatted;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (isArray(actualValue)) {
|
|
167
|
+
ret = `[${actualValue.join(", ")}]`;
|
|
168
|
+
}
|
|
169
|
+
if (propertyScheme?.date?.includes(path)) {
|
|
170
|
+
// return <DateDisplay date={value} />;
|
|
171
|
+
}
|
|
172
|
+
if (propertyScheme?.time?.includes(path))
|
|
173
|
+
ret = Format.date(actualValue, "pp");
|
|
174
|
+
if (propertyScheme?.number?.phone(path)) ret = Format.phone(actualValue);
|
|
175
|
+
if (propertyScheme?.bytes?.includes(path)) ret = Format.bytes(actualValue);
|
|
176
|
+
if (propertyScheme?.percent?.includes(path))
|
|
177
|
+
ret = Format.percent(actualValue);
|
|
178
|
+
if (propertyScheme?.number?.includes(path))
|
|
179
|
+
ret = Format.number(actualValue);
|
|
180
|
+
if (propertyScheme?.boolean?.includes(path) || isBoolean(actualValue))
|
|
181
|
+
ret = actualValue ? t("json.true") : t("json.false");
|
|
182
|
+
if (ret?.length > 128) {
|
|
183
|
+
ret = <Text clamp={3}>{ret}</Text>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<Fragment>
|
|
188
|
+
{ret}
|
|
189
|
+
{isObject(value) && value._score_ > 0 && (
|
|
190
|
+
<Meter className="text-xs" value={value._score_} />
|
|
191
|
+
)}
|
|
192
|
+
</Fragment>
|
|
193
|
+
);
|
|
194
|
+
}, [value, path, formatter, propertyScheme, actualValue]);
|
|
195
|
+
|
|
196
|
+
const pathWithoutOrdinal = useMemo(
|
|
197
|
+
() => path.replace(/\.\d*\./, "."),
|
|
198
|
+
[path],
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const canCopy = useMemo(
|
|
202
|
+
() =>
|
|
203
|
+
!isEmpty(value) &&
|
|
204
|
+
(isTrue(copy) ||
|
|
205
|
+
copy?.includes?.(path) ||
|
|
206
|
+
copy?.includes?.(pathWithoutOrdinal)),
|
|
207
|
+
[copy, value, path, pathWithoutOrdinal],
|
|
208
|
+
);
|
|
209
|
+
const canFilter = useMemo(
|
|
210
|
+
() =>
|
|
211
|
+
isTrue(filters) ||
|
|
212
|
+
filters?.includes?.(path) ||
|
|
213
|
+
filters?.includes?.(pathWithoutOrdinal),
|
|
214
|
+
[filters, path, pathWithoutOrdinal],
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const labelDisplay = useMemo(
|
|
218
|
+
() => (
|
|
219
|
+
<ActionLabel
|
|
220
|
+
className="text-dimmed text-sm px-2 flex-1 truncate"
|
|
221
|
+
actions={
|
|
222
|
+
!canExpand && canFilter
|
|
223
|
+
? [
|
|
224
|
+
<Button
|
|
225
|
+
key="negative"
|
|
226
|
+
color="danger"
|
|
227
|
+
size="sm"
|
|
228
|
+
variant="link"
|
|
229
|
+
icon={CoreIcons.funnelMinus}
|
|
230
|
+
aria-label="Filter Negative"
|
|
231
|
+
onClick={() =>
|
|
232
|
+
onFilter?.(pathWithoutOrdinal, actualValue, true)
|
|
233
|
+
}
|
|
234
|
+
/>,
|
|
235
|
+
<Button
|
|
236
|
+
key="positive"
|
|
237
|
+
color="primary"
|
|
238
|
+
size="sm"
|
|
239
|
+
variant="link"
|
|
240
|
+
icon={CoreIcons.funnelPlus}
|
|
241
|
+
aria-label="Filter"
|
|
242
|
+
onClick={() => onFilter?.(pathWithoutOrdinal, actualValue)}
|
|
243
|
+
/>,
|
|
244
|
+
]
|
|
245
|
+
: []
|
|
246
|
+
}
|
|
247
|
+
>
|
|
248
|
+
{labeler?.(path) ?? field}
|
|
249
|
+
</ActionLabel>
|
|
250
|
+
),
|
|
251
|
+
[field, labeler, pathWithoutOrdinal, actualValue, canExpand, canFilter],
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<Fragment>
|
|
256
|
+
{showPropertyTree && (
|
|
257
|
+
<div
|
|
258
|
+
className={classNames(
|
|
259
|
+
"py-2",
|
|
260
|
+
inline && "flex flex-nowrap items-center",
|
|
261
|
+
)}
|
|
262
|
+
style={{
|
|
263
|
+
paddingInlineStart: level * 8,
|
|
264
|
+
}}
|
|
265
|
+
>
|
|
266
|
+
<div
|
|
267
|
+
role="none"
|
|
268
|
+
className={classNames(
|
|
269
|
+
"flex overflow-hidden items-center",
|
|
270
|
+
inline && "flex-content",
|
|
271
|
+
)}
|
|
272
|
+
style={{
|
|
273
|
+
flexBasis: labelWidth,
|
|
274
|
+
}}
|
|
275
|
+
onClick={() => canExpand && setExpanded(!expanded)}
|
|
276
|
+
>
|
|
277
|
+
{canExpand && (
|
|
278
|
+
<Icon
|
|
279
|
+
rtlFlip
|
|
280
|
+
icon={expanded ? CoreIcons.chevronDown : CoreIcons.chevronRight}
|
|
281
|
+
/>
|
|
282
|
+
)}
|
|
283
|
+
{labelDisplay}
|
|
284
|
+
</div>
|
|
285
|
+
{display && (
|
|
286
|
+
<div className={classNames("px-2", inline && "flex-1")}>
|
|
287
|
+
{canCopy && <Copy size="xs" text={actualValue} />}
|
|
288
|
+
{display}
|
|
289
|
+
</div>
|
|
290
|
+
)}
|
|
291
|
+
</div>
|
|
292
|
+
)}
|
|
293
|
+
{!showPropertyTree && !children && (
|
|
294
|
+
<div
|
|
295
|
+
className={classNames(
|
|
296
|
+
"py-2",
|
|
297
|
+
inline && "flex flex-nowrap items-center",
|
|
298
|
+
)}
|
|
299
|
+
>
|
|
300
|
+
<div
|
|
301
|
+
role="none"
|
|
302
|
+
className={classNames(
|
|
303
|
+
"flex overflow-hidden items-center",
|
|
304
|
+
inline && "flex-content",
|
|
305
|
+
)}
|
|
306
|
+
style={{
|
|
307
|
+
flexBasis: labelWidth,
|
|
308
|
+
}}
|
|
309
|
+
>
|
|
310
|
+
{labelDisplay}
|
|
311
|
+
</div>
|
|
312
|
+
<div className={classNames("px-2", inline && "flex-1")}>
|
|
313
|
+
{canCopy && <Copy size="xs" text={value} />}
|
|
314
|
+
{display}
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
)}
|
|
318
|
+
{expanded &&
|
|
319
|
+
children?.map((item: KeyValue) => (
|
|
320
|
+
<JsonEntry
|
|
321
|
+
key={item.path}
|
|
322
|
+
{...item}
|
|
323
|
+
level={level + 1}
|
|
324
|
+
copy={copy}
|
|
325
|
+
inline={inline}
|
|
326
|
+
showPropertyTree={showPropertyTree}
|
|
327
|
+
propertyScheme={propertyScheme}
|
|
328
|
+
filters={filters}
|
|
329
|
+
labelWidth={labelWidth}
|
|
330
|
+
formatter={formatter}
|
|
331
|
+
labeler={labeler}
|
|
332
|
+
onFilter={onFilter}
|
|
333
|
+
/>
|
|
334
|
+
))}
|
|
335
|
+
</Fragment>
|
|
336
|
+
);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
export const JsonViewer = <T extends KeyValue = KeyValue>({
|
|
340
|
+
className,
|
|
341
|
+
json,
|
|
342
|
+
copy,
|
|
343
|
+
propertyScheme,
|
|
344
|
+
filters,
|
|
345
|
+
inline,
|
|
346
|
+
labelWidth,
|
|
347
|
+
formatter,
|
|
348
|
+
labeler,
|
|
349
|
+
onFilter,
|
|
350
|
+
emptyMessage,
|
|
351
|
+
showPropertyTree = true,
|
|
352
|
+
...rest
|
|
353
|
+
}: JsonViewProps<T>) => {
|
|
354
|
+
const { t } = useTranslation("data");
|
|
355
|
+
|
|
356
|
+
const list = useMemo(() => reduceObject(json), [json]);
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
<div {...rest} className={classNames(className, "p-4 bg-alternate")}>
|
|
360
|
+
{!isEmpty(json) ? (
|
|
361
|
+
list.map((item) => (
|
|
362
|
+
<JsonEntry
|
|
363
|
+
key={item.path}
|
|
364
|
+
{...item}
|
|
365
|
+
copy={copy}
|
|
366
|
+
inline={inline}
|
|
367
|
+
showPropertyTree={showPropertyTree}
|
|
368
|
+
propertyScheme={propertyScheme}
|
|
369
|
+
filters={filters}
|
|
370
|
+
labelWidth={labelWidth}
|
|
371
|
+
formatter={formatter}
|
|
372
|
+
labeler={labeler}
|
|
373
|
+
onFilter={onFilter}
|
|
374
|
+
/>
|
|
375
|
+
))
|
|
376
|
+
) : (
|
|
377
|
+
<EmptyContent size="sm" message={emptyMessage ?? t("json.empty")} />
|
|
378
|
+
)}
|
|
379
|
+
</div>
|
|
380
|
+
);
|
|
381
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2024 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { CoreIcons, Icon } from "@react-fabric/core";
|
|
25
|
+
import classNames from "classnames";
|
|
26
|
+
import { Fragment, memo, useMemo } from "react";
|
|
27
|
+
|
|
28
|
+
export interface PaginationProps {
|
|
29
|
+
/**
|
|
30
|
+
* currrent page number
|
|
31
|
+
*/
|
|
32
|
+
page: number;
|
|
33
|
+
/**
|
|
34
|
+
* total page count
|
|
35
|
+
*/
|
|
36
|
+
totalPages: number;
|
|
37
|
+
/**
|
|
38
|
+
* pagination sections [start, mid, end]
|
|
39
|
+
*/
|
|
40
|
+
ranges: number[][];
|
|
41
|
+
/**
|
|
42
|
+
* minimal view
|
|
43
|
+
*/
|
|
44
|
+
minimal?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* page change handler
|
|
47
|
+
*/
|
|
48
|
+
onPageChange: (page: number) => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const Pagination = memo(
|
|
52
|
+
({ page, ranges, totalPages, minimal, onPageChange }: PaginationProps) => {
|
|
53
|
+
const [start, mid, last] = ranges;
|
|
54
|
+
|
|
55
|
+
const pageBody = useMemo(
|
|
56
|
+
() => (
|
|
57
|
+
<Fragment>
|
|
58
|
+
{start?.map((pg) => (
|
|
59
|
+
<button
|
|
60
|
+
key={pg}
|
|
61
|
+
onClick={() => onPageChange(pg)}
|
|
62
|
+
className={classNames(
|
|
63
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
64
|
+
page === pg && "bg-primary-500 text-white pointer-events-none",
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
{pg + 1}
|
|
68
|
+
</button>
|
|
69
|
+
))}
|
|
70
|
+
{mid && (
|
|
71
|
+
<span className="leading-none inline-block w-8 text-center text-dimmed">
|
|
72
|
+
...
|
|
73
|
+
</span>
|
|
74
|
+
)}
|
|
75
|
+
{mid?.map((pg) => (
|
|
76
|
+
<button
|
|
77
|
+
key={pg}
|
|
78
|
+
onClick={() => onPageChange(pg)}
|
|
79
|
+
className={classNames(
|
|
80
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
81
|
+
page === pg && "bg-primary-500 text-white pointer-events-none",
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
{pg + 1}
|
|
85
|
+
</button>
|
|
86
|
+
))}
|
|
87
|
+
{last && (
|
|
88
|
+
<span className="leading-none inline-block w-8 text-center text-dimmed">
|
|
89
|
+
...
|
|
90
|
+
</span>
|
|
91
|
+
)}
|
|
92
|
+
{last?.map((pg) => (
|
|
93
|
+
<button
|
|
94
|
+
key={pg}
|
|
95
|
+
onClick={() => onPageChange(pg)}
|
|
96
|
+
className={classNames(
|
|
97
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
98
|
+
page === pg && "bg-primary-500 text-white pointer-events-none",
|
|
99
|
+
)}
|
|
100
|
+
>
|
|
101
|
+
{pg + 1}
|
|
102
|
+
</button>
|
|
103
|
+
))}
|
|
104
|
+
</Fragment>
|
|
105
|
+
),
|
|
106
|
+
[start, mid, last, page],
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<div className="inline-flex items-center">
|
|
111
|
+
<button
|
|
112
|
+
onClick={() => onPageChange(0)}
|
|
113
|
+
className={classNames(
|
|
114
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
115
|
+
page === 0 && "pointer-events-none text-tint-300",
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
<Icon icon={CoreIcons.chevronsLeft} rtlFlip />
|
|
119
|
+
</button>
|
|
120
|
+
<button
|
|
121
|
+
onClick={() => onPageChange(page - 1)}
|
|
122
|
+
className={classNames(
|
|
123
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
124
|
+
page === 0 && "pointer-events-none text-tint-300",
|
|
125
|
+
)}
|
|
126
|
+
>
|
|
127
|
+
<Icon icon={CoreIcons.chevronLeft} rtlFlip />
|
|
128
|
+
</button>
|
|
129
|
+
{!minimal && pageBody}
|
|
130
|
+
{minimal && (
|
|
131
|
+
<label className="leading-none inline-block px-1 text-center text-sm select-none fixed-numbers">
|
|
132
|
+
{page + 1}/{totalPages}
|
|
133
|
+
</label>
|
|
134
|
+
)}
|
|
135
|
+
<button
|
|
136
|
+
onClick={() => onPageChange(page + 1)}
|
|
137
|
+
className={classNames(
|
|
138
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
139
|
+
page + 1 >= totalPages && "pointer-events-none text-tint-300",
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
<Icon icon={CoreIcons.chevronRight} rtlFlip />
|
|
143
|
+
</button>
|
|
144
|
+
<button
|
|
145
|
+
onClick={() => onPageChange(totalPages - 1)}
|
|
146
|
+
className={classNames(
|
|
147
|
+
"leading-none text-sm hover:bg-primary-200 w-8 h-6 rounded-full",
|
|
148
|
+
page + 1 >= totalPages && "pointer-events-none text-tint-300",
|
|
149
|
+
)}
|
|
150
|
+
>
|
|
151
|
+
<Icon icon={CoreIcons.chevronsRight} rtlFlip />
|
|
152
|
+
</button>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
Pagination.displayName = "Pagination";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* React Fabric
|
|
3
|
+
* @version: 1.0.0
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* The MIT License (MIT)
|
|
7
|
+
* Copyright (c) 2024 Adarsh Pastakia
|
|
8
|
+
*
|
|
9
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
10
|
+
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
11
|
+
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
12
|
+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
13
|
+
* subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
16
|
+
* portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
19
|
+
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
20
|
+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import classNames from "classnames";
|
|
25
|
+
import { type ColumnType } from "./types";
|
|
26
|
+
|
|
27
|
+
export const BodyCell = ({
|
|
28
|
+
column,
|
|
29
|
+
item,
|
|
30
|
+
}: {
|
|
31
|
+
column: ColumnType;
|
|
32
|
+
item: KeyValue;
|
|
33
|
+
}) => {
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
className="overflow-hidden bg-inherit start-0"
|
|
37
|
+
style={{
|
|
38
|
+
width: column.width ?? "12rem",
|
|
39
|
+
minWidth: column.minWidth ?? "2rem",
|
|
40
|
+
maxWidth: column.maxWidth ?? "32rem",
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<div
|
|
44
|
+
className={classNames(
|
|
45
|
+
"px-2 py-1 border-e truncate",
|
|
46
|
+
column.align === "center" && "text-center",
|
|
47
|
+
column.align === "end" && "text-end",
|
|
48
|
+
)}
|
|
49
|
+
>
|
|
50
|
+
{column.renderer?.(item[column.id], item) ?? item[column.id]}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
};
|