@zjlab-fe/data-hub-ui 0.33.2 → 0.35.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.
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import './index.scss';
3
+ declare const Demo: React.FC;
4
+ export default Demo;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import './index.scss';
3
+ export interface JsonEditorProps {
4
+ /** 初始值 */
5
+ defaultValue?: string;
6
+ /** 是否只读, 默认可编辑 */
7
+ readOnly?: boolean;
8
+ }
9
+ export type JsonEditorPath = Array<string | number>;
10
+ export type JsonEditorErrorLevel = 'error' | 'warning' | 'info' | 'hint';
11
+ export interface JsonEditorError {
12
+ path: JsonEditorPath;
13
+ message: string;
14
+ level: JsonEditorErrorLevel;
15
+ }
16
+ export interface JsonEditorRef {
17
+ setValue: (value: string) => void;
18
+ getValue: () => string;
19
+ showError: (errors: JsonEditorError[]) => void;
20
+ }
21
+ declare const JsonEditor: React.ForwardRefExoticComponent<JsonEditorProps & React.RefAttributes<JsonEditorRef>>;
22
+ export default JsonEditor;
@@ -50,3 +50,5 @@ export type { IConfirmParam, IFieldOption, IDatasetBatchActionParams, } from './
50
50
  export { EDatasetBatchType } from './components/dataset-batch-action';
51
51
  export { DataHubProvider } from './locale';
52
52
  export type { DataHubProviderProps, DataHubAntdMode, DataHubTheme, DataHubThemeToken, DataHubLang, } from './locale';
53
+ export { default as JsonEditor } from './components/json-editor';
54
+ export type { JsonEditorProps, JsonEditorRef, JsonEditorError, JsonEditorErrorLevel, JsonEditorPath, } from './components/json-editor';
@@ -1,7 +1,7 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { useRef, useState, useEffect } from 'react';
4
- import ReactJson from 'react-json-view';
4
+ import JsonEditor from '../../json-editor/index.js';
5
5
  import { ErrorBoundary } from 'react-error-boundary';
6
6
  import DataTable from '../data-table/index.js';
7
7
  import { fetchFileWithAutoCode } from '../util.js';
@@ -150,11 +150,7 @@ function JsonPreview(props) {
150
150
  return (jsx("div", { style: { height: '100%', overflow: 'auto', wordBreak: 'break-all' }, ref: ref, children: (() => {
151
151
  var _a;
152
152
  if (json) {
153
- return (jsx(ErrorBoundary, { fallback: JSON.stringify(json), children: jsx(ReactJson, { name: false, src: json, iconStyle: "triangle", collapsed: 2, enableClipboard: false, displayObjectSize: false, displayDataTypes: false, collapseStringsAfterLength: 140, style: {
154
- fontFamily: 'Monaco, Menlo, Consolas, monospace',
155
- backgroundColor: 'rgba(0, 0, 0, 0)',
156
- color: 'rgb(155, 12, 121)',
157
- } }) }));
153
+ return (jsx(ErrorBoundary, { fallback: JSON.stringify(json), children: jsx(JsonEditor, { defaultValue: JSON.stringify(json), readOnly: true }) }));
158
154
  }
159
155
  else if (jsonLResult) {
160
156
  return (jsx(DataTable, { head: jsonLResult.head, data: jsonLResult.data, containerHeight: jsonLContainerHeight, containerWidth: jsonLContainerWidth, maxLines: (_a = props.tableConfig) === null || _a === void 0 ? void 0 : _a.maxLines }));
@@ -0,0 +1,317 @@
1
+ import { __awaiter } from 'tslib';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { forwardRef, useState, useRef, useImperativeHandle, useEffect } from 'react';
4
+ import { SearchOutlined } from '@ant-design/icons';
5
+ import { Button } from 'antd';
6
+ import useStyle from './index.scss.js';
7
+ import Editor, { loader } from '@monaco-editor/react';
8
+
9
+ useStyle();
10
+ loader.config({
11
+ paths: {
12
+ vs: 'https://haina-datahub.zero2x.org/ossRoute/frontend/resources/npm/monaco-editor/0.56.0/min/vs',
13
+ },
14
+ 'vs/nls': {
15
+ availableLanguages: {
16
+ '*': 'zh-cn',
17
+ },
18
+ },
19
+ });
20
+ const MARKER_OWNER = 'data-hub-ui-json-editor';
21
+ const isChangeInRange = (changeStart, changeLength, rangeStart, rangeEnd) => {
22
+ if (changeLength === 0) {
23
+ return changeStart >= rangeStart && changeStart <= rangeEnd;
24
+ }
25
+ const changeEnd = changeStart + changeLength;
26
+ return changeStart < rangeEnd && changeEnd > rangeStart;
27
+ };
28
+ const formatJson = (value) => {
29
+ if (value === undefined) {
30
+ return value;
31
+ }
32
+ try {
33
+ return JSON.stringify(JSON.parse(value), null, 2);
34
+ }
35
+ catch (_a) {
36
+ return value;
37
+ }
38
+ };
39
+ const compactJson = (value) => {
40
+ try {
41
+ return JSON.stringify(JSON.parse(value));
42
+ }
43
+ catch (_a) {
44
+ return value;
45
+ }
46
+ };
47
+ const findJsonNode = (value, path) => {
48
+ var _a, _b;
49
+ let offset = 0;
50
+ const skipWhitespace = () => {
51
+ var _a;
52
+ while (/\s/.test((_a = value[offset]) !== null && _a !== void 0 ? _a : '')) {
53
+ offset += 1;
54
+ }
55
+ };
56
+ const parseString = () => {
57
+ const start = offset;
58
+ offset += 1;
59
+ while (offset < value.length) {
60
+ if (value[offset] === '\\') {
61
+ offset += 2;
62
+ }
63
+ else if (value[offset] === '"') {
64
+ offset += 1;
65
+ return { start, end: offset };
66
+ }
67
+ else {
68
+ offset += 1;
69
+ }
70
+ }
71
+ throw new Error('Invalid JSON string');
72
+ };
73
+ const parseValue = () => {
74
+ skipWhitespace();
75
+ const start = offset;
76
+ const character = value[offset];
77
+ if (character === '{') {
78
+ offset += 1;
79
+ const properties = new Map();
80
+ skipWhitespace();
81
+ while (value[offset] !== '}') {
82
+ const key = parseString();
83
+ const propertyName = JSON.parse(value.slice(key.start, key.end));
84
+ if (typeof propertyName !== 'string') {
85
+ throw new Error('Invalid JSON object key');
86
+ }
87
+ skipWhitespace();
88
+ if (value[offset] !== ':') {
89
+ throw new Error('Invalid JSON object');
90
+ }
91
+ offset += 1;
92
+ const property = parseValue();
93
+ property.keyStart = key.start;
94
+ property.keyEnd = key.end;
95
+ properties.set(propertyName, property);
96
+ skipWhitespace();
97
+ if (value[offset] === ',') {
98
+ offset += 1;
99
+ skipWhitespace();
100
+ }
101
+ else if (value[offset] !== '}') {
102
+ throw new Error('Invalid JSON object');
103
+ }
104
+ }
105
+ offset += 1;
106
+ return { start, end: offset, properties };
107
+ }
108
+ if (character === '[') {
109
+ offset += 1;
110
+ const items = [];
111
+ skipWhitespace();
112
+ while (value[offset] !== ']') {
113
+ items.push(parseValue());
114
+ skipWhitespace();
115
+ if (value[offset] === ',') {
116
+ offset += 1;
117
+ skipWhitespace();
118
+ }
119
+ else if (value[offset] !== ']') {
120
+ throw new Error('Invalid JSON array');
121
+ }
122
+ }
123
+ offset += 1;
124
+ return { start, end: offset, items };
125
+ }
126
+ if (character === '"') {
127
+ const string = parseString();
128
+ return string;
129
+ }
130
+ while (offset < value.length && !/[\s,}\]]/.test(value[offset])) {
131
+ offset += 1;
132
+ }
133
+ if (start === offset) {
134
+ throw new Error('Invalid JSON value');
135
+ }
136
+ return { start, end: offset };
137
+ };
138
+ try {
139
+ let node = parseValue();
140
+ for (const [index, segment] of path.entries()) {
141
+ if (!node) {
142
+ return undefined;
143
+ }
144
+ const nextNode = typeof segment === 'number' ? (_a = node.items) === null || _a === void 0 ? void 0 : _a[segment] : (_b = node.properties) === null || _b === void 0 ? void 0 : _b.get(segment);
145
+ if (!nextNode) {
146
+ if (index === path.length - 1 && typeof segment === 'string' && node.properties) {
147
+ return { node, isMissingProperty: true };
148
+ }
149
+ return undefined;
150
+ }
151
+ node = nextNode;
152
+ }
153
+ return node ? { node, isMissingProperty: false } : undefined;
154
+ }
155
+ catch (_c) {
156
+ return undefined;
157
+ }
158
+ };
159
+ const JsonEditor = forwardRef((props, ref) => {
160
+ const { defaultValue, readOnly = false } = props;
161
+ const [mounted, setMounted] = useState(false);
162
+ const [containerHeight, setContainerHeight] = useState(0);
163
+ const [isFindWidgetVisible, setIsFindWidgetVisible] = useState(false);
164
+ const containerRef = useRef(null);
165
+ const editorRef = useRef(null);
166
+ const monacoRef = useRef(null);
167
+ const initialValueRef = useRef(formatJson(defaultValue));
168
+ const pendingValueRef = useRef(undefined);
169
+ const pendingErrorsRef = useRef(null);
170
+ const displayedErrorsRef = useRef([]);
171
+ const contentChangeDisposableRef = useRef(null);
172
+ const findWidgetObserverRef = useRef(null);
173
+ const applyErrors = (errors, shouldFocusFirstError = true) => {
174
+ const editor = editorRef.current;
175
+ const monaco = monacoRef.current;
176
+ if (!editor || !monaco) {
177
+ pendingErrorsRef.current = errors;
178
+ return;
179
+ }
180
+ const model = editor.getModel();
181
+ if (!model) {
182
+ return;
183
+ }
184
+ const errorsWithPositions = errors.flatMap((error) => {
185
+ var _a, _b, _c;
186
+ const location = findJsonNode(model.getValue(), error.path);
187
+ if (!location) {
188
+ return [];
189
+ }
190
+ const startOffset = location.isMissingProperty
191
+ ? location.node.start
192
+ : ((_a = location.node.keyStart) !== null && _a !== void 0 ? _a : location.node.start);
193
+ const endOffset = location.isMissingProperty
194
+ ? location.node.start + 1
195
+ : ((_b = location.node.keyEnd) !== null && _b !== void 0 ? _b : location.node.end);
196
+ const affectedStart = location.isMissingProperty
197
+ ? location.node.start
198
+ : Math.min((_c = location.node.keyStart) !== null && _c !== void 0 ? _c : location.node.start, location.node.start);
199
+ const affectedEnd = location.node.end;
200
+ const startPosition = model.getPositionAt(startOffset);
201
+ const endPosition = model.getPositionAt(Math.max(startOffset, endOffset));
202
+ const severity = {
203
+ error: monaco.MarkerSeverity.Error,
204
+ warning: monaco.MarkerSeverity.Warning,
205
+ info: monaco.MarkerSeverity.Info,
206
+ hint: monaco.MarkerSeverity.Hint,
207
+ }[error.level];
208
+ return [{ error, startPosition, endPosition, severity, affectedStart, affectedEnd }];
209
+ });
210
+ displayedErrorsRef.current = errorsWithPositions.map(({ error, affectedStart, affectedEnd }) => ({
211
+ error,
212
+ affectedStart,
213
+ affectedEnd,
214
+ }));
215
+ monaco.editor.setModelMarkers(model, MARKER_OWNER, errorsWithPositions.map(({ error, startPosition, endPosition, severity }) => ({
216
+ startLineNumber: startPosition.lineNumber,
217
+ startColumn: startPosition.column,
218
+ endLineNumber: endPosition.lineNumber,
219
+ endColumn: endPosition.column,
220
+ message: error.message,
221
+ severity,
222
+ })));
223
+ const firstError = errorsWithPositions[0];
224
+ if (!firstError || !shouldFocusFirstError) {
225
+ return;
226
+ }
227
+ void (() => __awaiter(void 0, void 0, void 0, function* () {
228
+ var _a, _b;
229
+ yield ((_a = editor.getAction('editor.unfold')) === null || _a === void 0 ? void 0 : _a.run({
230
+ levels: Number.MAX_SAFE_INTEGER,
231
+ direction: 'up',
232
+ selectionLines: [firstError.startPosition.lineNumber - 1],
233
+ }));
234
+ editor.setPosition(firstError.startPosition);
235
+ editor.revealPositionInCenterIfOutsideViewport(firstError.startPosition);
236
+ yield ((_b = editor.getAction('editor.action.marker.next')) === null || _b === void 0 ? void 0 : _b.run());
237
+ }))();
238
+ };
239
+ useImperativeHandle(ref, () => ({
240
+ setValue: (value) => {
241
+ var _a, _b;
242
+ const formattedValue = (_a = formatJson(value)) !== null && _a !== void 0 ? _a : value;
243
+ pendingValueRef.current = formattedValue;
244
+ (_b = editorRef.current) === null || _b === void 0 ? void 0 : _b.setValue(formattedValue);
245
+ },
246
+ getValue: () => {
247
+ var _a, _b, _c, _d;
248
+ return compactJson((_d = (_c = (_b = (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.getValue()) !== null && _b !== void 0 ? _b : pendingValueRef.current) !== null && _c !== void 0 ? _c : initialValueRef.current) !== null && _d !== void 0 ? _d : '');
249
+ },
250
+ showError: applyErrors,
251
+ }), []);
252
+ const handleMount = (editor, monaco) => {
253
+ editorRef.current = editor;
254
+ monacoRef.current = monaco;
255
+ contentChangeDisposableRef.current = editor.onDidChangeModelContent((event) => {
256
+ const remainingErrors = displayedErrorsRef.current.filter(({ affectedStart, affectedEnd }) => event.changes.every(({ rangeOffset, rangeLength }) => !isChangeInRange(rangeOffset, rangeLength, affectedStart, affectedEnd)));
257
+ if (remainingErrors.length !== displayedErrorsRef.current.length) {
258
+ editor.trigger('json-editor', 'closeMarkersNavigation', undefined);
259
+ applyErrors(remainingErrors.map(({ error }) => error), false);
260
+ }
261
+ });
262
+ const editorDomNode = editor.getDomNode();
263
+ if (editorDomNode) {
264
+ const updateFindWidgetVisibility = () => {
265
+ var _a, _b;
266
+ setIsFindWidgetVisible((_b = (_a = editorDomNode.querySelector('.find-widget')) === null || _a === void 0 ? void 0 : _a.classList.contains('visible')) !== null && _b !== void 0 ? _b : false);
267
+ };
268
+ findWidgetObserverRef.current = new MutationObserver(updateFindWidgetVisibility);
269
+ findWidgetObserverRef.current.observe(editorDomNode, {
270
+ attributes: true,
271
+ attributeFilter: ['class'],
272
+ subtree: true,
273
+ });
274
+ updateFindWidgetVisibility();
275
+ }
276
+ if (pendingValueRef.current !== undefined) {
277
+ editor.setValue(pendingValueRef.current);
278
+ }
279
+ if (pendingErrorsRef.current !== null) {
280
+ const pendingErrors = pendingErrorsRef.current;
281
+ pendingErrorsRef.current = null;
282
+ applyErrors(pendingErrors);
283
+ }
284
+ };
285
+ const handleOpenFindWidget = () => {
286
+ var _a, _b;
287
+ void ((_b = (_a = editorRef.current) === null || _a === void 0 ? void 0 : _a.getAction('actions.find')) === null || _b === void 0 ? void 0 : _b.run());
288
+ };
289
+ useEffect(() => {
290
+ setMounted(true);
291
+ setContainerHeight(containerRef.current.clientHeight);
292
+ return () => {
293
+ var _a, _b;
294
+ (_a = contentChangeDisposableRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
295
+ contentChangeDisposableRef.current = null;
296
+ (_b = findWidgetObserverRef.current) === null || _b === void 0 ? void 0 : _b.disconnect();
297
+ findWidgetObserverRef.current = null;
298
+ displayedErrorsRef.current = [];
299
+ editorRef.current = null;
300
+ monacoRef.current = null;
301
+ };
302
+ }, []);
303
+ console.log('++++ render');
304
+ return (jsxs("div", { className: "data-hub-ui-json-editor-container", ref: containerRef, children: [!isFindWidgetVisible && (jsx(Button, { "aria-label": "\u641C\u7D22", className: "data-hub-ui-json-editor-search-button", icon: jsx(SearchOutlined, {}), type: "text", onClick: handleOpenFindWidget })), mounted && (jsx(Editor, { height: containerHeight, language: "json", defaultValue: initialValueRef.current, onMount: handleMount, options: {
305
+ folding: true,
306
+ readOnly,
307
+ minimap: {
308
+ enabled: false,
309
+ },
310
+ stickyScroll: {
311
+ enabled: false,
312
+ },
313
+ } }))] }));
314
+ });
315
+ JsonEditor.displayName = 'JsonEditor';
316
+
317
+ export { JsonEditor as default };
@@ -0,0 +1,22 @@
1
+ function useStyle() {
2
+ var style = document.createElement('style');
3
+ style.textContent = `.data-hub-ui-json-editor-container {
4
+ position: relative;
5
+ height: 100%;
6
+ min-height: 100px;
7
+ }
8
+ .data-hub-ui-json-editor-container .data-hub-ui-json-editor-search-button {
9
+ position: absolute;
10
+ z-index: 1;
11
+ top: 8px;
12
+ right: 8px;
13
+ color: #87909e;
14
+ }
15
+ .data-hub-ui-json-editor-container .monaco-editor .find-widget.visible {
16
+ top: 20px !important;
17
+ right: 48px !important;
18
+ }`;
19
+ document.head.appendChild(style);
20
+ }
21
+
22
+ export { useStyle as default };
@@ -236,23 +236,27 @@ const NotionEditor = forwardRef(({ initContent, editable = false, className = ''
236
236
  useEffect(() => {
237
237
  const onHashChange = () => {
238
238
  if (editor) {
239
- if (window.location.hash) {
240
- const id = window.location.hash.split('#')[1];
241
- if (id) {
242
- setTimeout(() => {
243
- var _a;
239
+ setTimeout(() => {
240
+ var _a;
241
+ if (window.location.hash) {
242
+ const id = window.location.hash.slice(1);
243
+ if (id) {
244
244
  // 将 hash 中指定 id 对应的 block 滚动到可视范围内
245
245
  const target = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(`.data-hub-ui-blocknote-editor [data-id="${CSS.escape(id)}"]`);
246
246
  target === null || target === void 0 ? void 0 : target.scrollIntoView({ behavior: 'smooth', block: 'start' });
247
- }, 500);
247
+ }
248
248
  }
249
- }
249
+ }, 500);
250
250
  }
251
251
  };
252
252
  onHashChange();
253
- window.addEventListener('hashchange', onHashChange);
253
+ if (window.navigation) {
254
+ window.navigation.addEventListener('navigate', onHashChange);
255
+ }
254
256
  return () => {
255
- window.removeEventListener('hashchange', onHashChange);
257
+ if (window.navigation) {
258
+ window.navigation.removeEventListener('navigate', onHashChange);
259
+ }
256
260
  };
257
261
  }, [editor]);
258
262
  const handleChange = useCallback(() => {
package/es/index.js CHANGED
@@ -41,4 +41,5 @@ export { default as TagGroupFilter } from './components/tag-group-filter/index.j
41
41
  export { default as LimitCreditModal, useLimitCreditModal } from './components/limit-credit-modal/index.js';
42
42
  export { default as DatasetBatchAction, EDatasetBatchType } from './components/dataset-batch-action/index.js';
43
43
  export { DataHubProvider } from './locale/index.js';
44
+ export { default as JsonEditor } from './components/json-editor/index.js';
44
45
  export { default as UploadDrawerUploadStoreProvider } from './components/uploadDrawer/UploadStoreProvider.js';