json-edit-react 0.9.3 → 0.9.6
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/README.md +11 -5
- package/build/index.cjs.js +63 -32
- package/build/index.d.ts +3 -2
- package/build/index.esm.js +62 -34
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Features include:
|
|
|
9
9
|
- edit individual values, or whole objects as JSON text
|
|
10
10
|
- fine-grained control over which elements can be edited, deleted, or added to
|
|
11
11
|
- customisable UI, through simple, pre-defined [themes](#themes), or specific CSS overrides
|
|
12
|
-
- self-contained —
|
|
12
|
+
- self-contained — rendered with plain HTML/CSS, so no dependance on external UI libraries
|
|
13
13
|
|
|
14
14
|
**[Explore the Demo](https://carlosnz.github.io/json-edit-react/)**
|
|
15
15
|
|
|
@@ -119,10 +119,12 @@ The function needn't return anything, but if it returns `false`, it will be cons
|
|
|
119
119
|
A similar callback is executed whenever an item is copied to the clipboard (if passed to the `enableClipboard` prop), but with a different input parameter:
|
|
120
120
|
|
|
121
121
|
```js
|
|
122
|
-
key
|
|
123
|
-
path
|
|
124
|
-
value
|
|
125
|
-
type
|
|
122
|
+
key // name of the property being copied
|
|
123
|
+
path // path to the property
|
|
124
|
+
value // the value copied to the clipboard
|
|
125
|
+
type // Either "path" or "value" depending on whether "Cmd/Ctrl" was pressed
|
|
126
|
+
stringValue // A nicely stringified version of `value`
|
|
127
|
+
// (i.e. what the clipboard actually receives)
|
|
126
128
|
```
|
|
127
129
|
|
|
128
130
|
Since there is very little user feedback when clicking "Copy", a good idea would be to present some kind of notification in this callback.
|
|
@@ -335,6 +337,10 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s
|
|
|
335
337
|
|
|
336
338
|
## Changelog
|
|
337
339
|
|
|
340
|
+
- **0.9.6**: Performance improvement by not processing child elements if not visible
|
|
341
|
+
- **0.9.4**:
|
|
342
|
+
- Layout improvements
|
|
343
|
+
- Better internal handling of functions in data
|
|
338
344
|
- **0.9.3**: Bundle as ES6 module
|
|
339
345
|
- **0.9.1**: Export more Types from the package
|
|
340
346
|
- **0.9.0**: Initial release
|
package/build/index.cjs.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
6
|
var react = require('react');
|
|
5
7
|
var assign = require('object-property-assigner');
|
|
@@ -53,7 +55,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
53
55
|
|
|
54
56
|
var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}
|
|
55
57
|
|
|
56
|
-
var css = ":root {\n --jer-form-border: 1px solid #ededf0;\n --jer-form-border-focus: 1px solid #e2e2e2;\n --jer-expand-transition-time: 0.
|
|
58
|
+
var css = ":root {\n --jer-select-border: #b6b6b6;\n --jer-select-focus: #777;\n --jer-select-arrow: #777;\n --jer-form-border: 1px solid #ededf0;\n --jer-form-border-focus: 1px solid #e2e2e2;\n --jer-expand-transition-time: 0.5s;\n --jer-highlight-color: #b3d8ff;\n}\n\n.jer-visible {\n opacity: 1;\n transition: var(--jer-expand-transition-time);\n}\n\n.jer-hidden {\n opacity: 0;\n transition: var(--jer-expand-transition-time);\n}\n\n/* Select styled as per:\nhttps://moderncss.dev/custom-select-styles-with-pure-css/\n*/\n\n.jer-select select {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: transparent;\n border: none;\n padding: 0 1em 0 0;\n margin: 0;\n /* width: 100%; */\n font-family: inherit;\n font-size: inherit;\n color: black;\n cursor: inherit;\n line-height: inherit;\n z-index: 1;\n outline: none;\n}\nselect::-ms-expand {\n display: none;\n}\n\n.jer-select {\n display: grid;\n grid-template-areas: 'select';\n align-items: center;\n position: relative;\n min-width: 12ch;\n max-width: 15ch;\n border: 1px solid var(--jer-select-border);\n border-radius: 0.25em;\n padding: 0.25em 0.5em;\n font-size: 1em;\n cursor: pointer;\n line-height: 1.1;\n background-color: #fff;\n background-image: linear-gradient(to top, #f9f9f9, #fff 33%);\n}\n.jer-select select,\n.jer-select::after {\n grid-area: select;\n}\n.jer-select:not(.jer-select--multiple)::after {\n content: '';\n justify-self: end;\n width: 0.8em;\n height: 0.5em;\n background-color: var(--jer-select-arrow);\n -webkit-clip-path: polygon(100% 0%, 0 0%, 50% 100%);\n clip-path: polygon(100% 0%, 0 0%, 50% 100%);\n}\n\nselect:focus + .focus {\n position: absolute;\n top: -1px;\n left: -1px;\n right: -1px;\n bottom: -1px;\n border: 1px solid var(--jer-select-focus);\n border-radius: inherit;\n}\n\n.jer-editor-container {\n font-size: 1.1em;\n /* font-size: 20px; */\n padding: 1em;\n margin-top: 1em;\n margin-bottom: 1em;\n border-radius: 0.5em;\n}\n\n.jer-editor-container textarea {\n /* width: 90%; */\n color: var(--jer-input-color);\n border: var(--jer-form-border);\n border-radius: 0.3em;\n outline: none;\n}\n\n.jer-editor-container textarea:focus {\n border: var(--jer-form-border-focus);\n}\n\n.jer-editor-container input {\n border: var(--jer-form-border);\n border-radius: 0.3em;\n outline: none;\n}\n\n.jer-editor-container input:focus {\n border: var(--jer-form-border-focus);\n}\n\n/* Input highlighted text */\n.jer-editor-container ::selection {\n background-color: var(--jer-highlight-color);\n}\n\n.jer-editor-container select {\n /* color: red; */\n}\n\n.jer-component {\n}\n\n.jer-collection-header-row,\n.jer-value-main-row {\n display: flex;\n min-height: 1.7em;\n gap: 0.3em;\n align-items: center;\n}\n\n.jer-collection-header-row {\n display: flex;\n flex-wrap: wrap;\n}\n\n.jer-brackets {\n}\n\n.jer-collection-item-count {\n}\n\n.jer-collection-inner {\n position: relative;\n}\n\n.jer-collection-text-edit {\n display: flex;\n flex-direction: column;\n gap: 0.3em;\n align-items: flex-start;\n}\n\n.jer-collection-text-area {\n resize: both;\n padding-top: 0.2em;\n padding-left: 0.5em;\n padding-right: 0.5em;\n padding-bottom: 0;\n overflow: hidden;\n max-height: 40em;\n}\n\n.jer-collection-input-button-row {\n display: flex;\n justify-content: flex-end;\n font-size: 150%;\n}\n\n.jer-collection-element {\n}\n\n.jer-collection-error-row {\n position: absolute;\n bottom: 0;\n}\n\n.jer-collection-error-row-edit {\n}\n\n.jer-error-slug {\n margin-left: 1em;\n}\n\n.jer-value-component {\n position: relative;\n}\n\n.jer-value-main-row {\n display: flex;\n gap: 0;\n}\n\n.jer-value-and-buttons {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n padding-left: 0.5em;\n}\n\n.jer-value-error-row {\n position: absolute;\n}\n\n.jer-value-string {\n line-height: 1.3em;\n}\n\n.jer-input-text {\n resize: none;\n margin: 0;\n height: 1.4em;\n padding-left: 0.5em;\n padding-right: 0.5em;\n padding-bottom: 0;\n min-width: 6em;\n overflow: hidden;\n max-height: 30em;\n}\n\n.jer-value-number {\n}\n\n.jer-value-boolean {\n}\n\n.jer-input-boolean {\n transform: scale(1.5);\n margin-left: 0.3em;\n margin-right: 0.3em;\n}\n\n.jer-value-null {\n}\n\n.jer-value-object {\n}\n\n.jer-object-key {\n word-break: break-word;\n line-height: 1.1em;\n}\n\n.jer-value-array {\n}\n\n.jer-value-invalid {\n opacity: 0.5;\n font-style: italic;\n}\n\n/* .jer-input-text, */\n.jer-input-number {\n height: 1.6em;\n}\n\n.jer-input-number {\n min-width: 3em;\n}\n\n.jer-input-component {\n}\n\n.jer-edit-buttons,\n.jer-confirm-buttons {\n display: flex;\n align-items: center;\n cursor: pointer;\n}\n\n.jer-input-buttons {\n gap: 0.4em;\n}\n\n.jer-edit-buttons {\n gap: 0.4em;\n margin-left: 0.5em;\n opacity: 0;\n}\n\n.jer-confirm-buttons {\n gap: 0.2em;\n margin-left: 0.4em;\n}\n\n.jer-edit-buttons:hover {\n opacity: 1;\n position: relative;\n}\n\n.jer-collection-header-row:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-value-main-row:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-value-and-buttons:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-input-buttons {\n}\n\n.jer-copy-pulse {\n position: relative;\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-copy-pulse:hover {\n opacity: 0.85;\n transition: 0.3s;\n transform: scale(1.2);\n}\n\n.jer-copy-pulse:after {\n content: '';\n display: block;\n position: absolute;\n border-radius: 50%;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n opacity: 0;\n transition: all 0.5s;\n box-shadow: 0 0 15px 5px var(--jer-icon-copy-color);\n}\n\n.jer-copy-pulse:active:after {\n box-shadow: 0 0 0 0 var(--jer-icon-copy-color);\n position: absolute;\n border-radius: 4em;\n left: 0;\n top: 0;\n opacity: 1;\n transition: 0s;\n}\n\n.jer-copy-pulse:active {\n top: 0.07em;\n}\n\n.jer-rotate-90 {\n transform: rotate(-90deg);\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-accordion-icon {\n /* font-size: '2em'; */\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-icon:hover {\n opacity: 0.85;\n transition: 0.3s;\n transform: scale(1.2);\n}\n";
|
|
57
59
|
n(css,{});
|
|
58
60
|
|
|
59
61
|
const defaultTheme$1 = {
|
|
@@ -392,6 +394,7 @@ const AutogrowTextArea = ({ className, name, value, setValue, handleKeyPress, })
|
|
|
392
394
|
}, onKeyDown: handleKeyPress }), jsxRuntime.jsx("span", Object.assign({ className: className, style: Object.assign({ visibility: 'hidden', height: 'auto', gridArea: '1 / 1 / 2 / 2', color: 'red', opacity: 0.9, whiteSpace: 'pre-wrap', overflow: 'clip', border: '1px solid transparent' }, styles.input) }, { children: dummyValue }))] })));
|
|
393
395
|
};
|
|
394
396
|
|
|
397
|
+
const INVALID_FUNCTION_STRING = '**INVALID_FUNCTION**';
|
|
395
398
|
const truncate = (string, length = 200) => string.length < length ? string : `${string.slice(0, length - 2).trim()}...`;
|
|
396
399
|
const StringValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdit, handleCancel, stringTruncate, }) => {
|
|
397
400
|
const { styles } = useTheme();
|
|
@@ -415,7 +418,10 @@ const NumberValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdi
|
|
|
415
418
|
else if (e.key === 'Escape')
|
|
416
419
|
handleCancel();
|
|
417
420
|
};
|
|
418
|
-
|
|
421
|
+
const validateNumber = (input) => {
|
|
422
|
+
return input.replace(/[^0-9.-]/g, '');
|
|
423
|
+
};
|
|
424
|
+
return isEditing ? (jsxRuntime.jsx("input", { className: "jer-input-number", type: "text", name: path.join('.'), value: value, onChange: (e) => setValue(validateNumber(e.target.value)), autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPress, style: { width: `${String(value).length / 1.5 + 2}em` } })) : (jsxRuntime.jsx("span", Object.assign({ onDoubleClick: () => setIsEditing(true), className: "jer-value-number", style: styles.number }, { children: value })));
|
|
419
425
|
};
|
|
420
426
|
const BooleanValue = ({ value, setValue, isEditing, path, setIsEditing, }) => {
|
|
421
427
|
const { styles } = useTheme();
|
|
@@ -425,14 +431,23 @@ const NullValue = ({ value, isEditing, setIsEditing }) => {
|
|
|
425
431
|
const { styles } = useTheme();
|
|
426
432
|
return isEditing ? (jsxRuntime.jsx("div", Object.assign({ className: "jer-input-null" }, { children: "null" }))) : (jsxRuntime.jsx("div", Object.assign({ onDoubleClick: () => setIsEditing(true), className: "jer-value-null", style: styles.null }, { children: String(value) })));
|
|
427
433
|
};
|
|
428
|
-
const ObjectValue = () => {
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
434
|
+
const ObjectValue = () => (jsxRuntime.jsx("span", Object.assign({ className: "jer-value-object" }, { children: '{ }' })));
|
|
435
|
+
const ArrayValue = ({ value }) => (jsxRuntime.jsx("span", Object.assign({ className: "jer-value-array" }, { children: `[${value === null ? '' : value}]` })));
|
|
436
|
+
const InvalidValue = ({ value }) => {
|
|
437
|
+
let message = 'Error!';
|
|
438
|
+
switch (typeof value) {
|
|
439
|
+
case 'string':
|
|
440
|
+
if (value === INVALID_FUNCTION_STRING)
|
|
441
|
+
message = 'Function';
|
|
442
|
+
break;
|
|
443
|
+
case 'undefined':
|
|
444
|
+
message = 'Undefined';
|
|
445
|
+
break;
|
|
446
|
+
case 'symbol':
|
|
447
|
+
message = 'Symbol';
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
return jsxRuntime.jsx("span", Object.assign({ className: "jer-value-invalid" }, { children: message }));
|
|
436
451
|
};
|
|
437
452
|
|
|
438
453
|
const Icon = ({ name, rotate }) => {
|
|
@@ -453,7 +468,7 @@ const Icon = ({ name, rotate }) => {
|
|
|
453
468
|
case 'cancel':
|
|
454
469
|
return ((_f = icons === null || icons === void 0 ? void 0 : icons.cancel) !== null && _f !== void 0 ? _f : (jsxRuntime.jsx(ti.TiCancel, Object.assign({}, commonProps, { style: Object.assign({ fontSize: '130%' }, styles.iconCancel) }))));
|
|
455
470
|
case 'chevron':
|
|
456
|
-
return ((_g = icons === null || icons === void 0 ? void 0 : icons.chevron) !== null && _g !== void 0 ? _g : (jsxRuntime.jsx(fa.FaChevronDown, { className:
|
|
471
|
+
return ((_g = icons === null || icons === void 0 ? void 0 : icons.chevron) !== null && _g !== void 0 ? _g : (jsxRuntime.jsx(fa.FaChevronDown, { className: `jer-accordion-icon${rotate ? ' jer-rotate-90' : ''}`, style: styles.iconCollection })));
|
|
457
472
|
default:
|
|
458
473
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
459
474
|
}
|
|
@@ -477,21 +492,24 @@ const EditButtons = ({ startEdit, handleDelete, handleAdd, enableClipboard, type
|
|
|
477
492
|
setIsAdding(false);
|
|
478
493
|
};
|
|
479
494
|
const handleCopy = (e) => {
|
|
480
|
-
let
|
|
495
|
+
let copyType = 'value';
|
|
481
496
|
let value;
|
|
497
|
+
let stringValue = '';
|
|
482
498
|
if (enableClipboard) {
|
|
483
499
|
switch (e.ctrlKey || e.metaKey) {
|
|
484
500
|
case true:
|
|
485
501
|
value = stringifyPath(path);
|
|
486
|
-
|
|
502
|
+
stringValue = value;
|
|
503
|
+
copyType = 'path';
|
|
487
504
|
break;
|
|
488
|
-
|
|
489
|
-
value =
|
|
505
|
+
default:
|
|
506
|
+
value = data;
|
|
507
|
+
stringValue = type ? JSON.stringify(data, null, 2) : String(value);
|
|
490
508
|
}
|
|
491
|
-
navigator.clipboard.writeText(
|
|
509
|
+
navigator.clipboard.writeText(stringValue);
|
|
492
510
|
}
|
|
493
511
|
if (typeof enableClipboard === 'function')
|
|
494
|
-
enableClipboard({ value, path, key: name, type });
|
|
512
|
+
enableClipboard({ value, stringValue, path, key: name, type: copyType });
|
|
495
513
|
};
|
|
496
514
|
return (jsxRuntime.jsxs("div", Object.assign({ className: "jer-edit-buttons", style: isAdding ? { opacity: 1 } : undefined }, { children: [enableClipboard && (jsxRuntime.jsx("div", Object.assign({ onClick: handleCopy, className: "jer-copy-pulse" }, { children: jsxRuntime.jsx(Icon, { name: "copy" }) }))), startEdit && (jsxRuntime.jsx("div", Object.assign({ onClick: startEdit }, { children: jsxRuntime.jsx(Icon, { name: "edit" }) }))), handleDelete && (jsxRuntime.jsx("div", Object.assign({ onClick: handleDelete }, { children: jsxRuntime.jsx(Icon, { name: "delete" }) }))), handleAdd && (jsxRuntime.jsx("div", Object.assign({ onClick: () => {
|
|
497
515
|
if (type === 'object')
|
|
@@ -525,11 +543,11 @@ const DataTypes = [...ValueDataTypes, ...CollectionDataTypes];
|
|
|
525
543
|
const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard, restrictEditFilter, restrictDeleteFilter, showArrayIndices, stringTruncate, indent, translate, }) => {
|
|
526
544
|
const { styles } = useTheme();
|
|
527
545
|
const [isEditing, setIsEditing] = react.useState(false);
|
|
528
|
-
const [value, setValue] = react.useState(data);
|
|
546
|
+
const [value, setValue] = react.useState(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
|
|
529
547
|
const [error, setError] = react.useState(null);
|
|
530
548
|
const [dataType, setDataType] = react.useState(getDataType(data));
|
|
531
549
|
react.useEffect(() => {
|
|
532
|
-
setValue(data);
|
|
550
|
+
setValue(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
|
|
533
551
|
setDataType(getDataType(data));
|
|
534
552
|
}, [data, error]);
|
|
535
553
|
const handleChangeDataType = (type) => {
|
|
@@ -583,14 +601,16 @@ const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard,
|
|
|
583
601
|
value,
|
|
584
602
|
setValue,
|
|
585
603
|
isEditing,
|
|
586
|
-
setIsEditing,
|
|
604
|
+
setIsEditing: canEdit ? () => setIsEditing(true) : () => { },
|
|
587
605
|
handleEdit,
|
|
588
606
|
handleCancel,
|
|
589
607
|
path,
|
|
590
608
|
stringTruncate,
|
|
591
609
|
};
|
|
592
|
-
return (jsxRuntime.jsx("div", Object.assign({ className: "jer-component jer-value-component", style: { marginLeft: `${indent / 2}em` } }, { children: jsxRuntime.jsxs("div", Object.assign({ className: "jer-value-main-row"
|
|
593
|
-
|
|
610
|
+
return (jsxRuntime.jsx("div", Object.assign({ className: "jer-component jer-value-component", style: { marginLeft: `${indent / 2}em` } }, { children: jsxRuntime.jsxs("div", Object.assign({ className: "jer-value-main-row", style: {
|
|
611
|
+
flexWrap: name.length > 10 ? 'wrap' : 'nowrap',
|
|
612
|
+
} }, { children: [showArrayIndices && (jsxRuntime.jsxs("label", Object.assign({ htmlFor: path.join('.'), className: "jer-object-key", style: Object.assign(Object.assign({}, styles.property), { minWidth: `${Math.min(String(name).length + 1, 5)}ch`, flexShrink: name.length > 10 ? 1 : 0 }) }, { children: [name, ":", ' '] }))), jsxRuntime.jsxs("div", Object.assign({ className: "jer-value-and-buttons" }, { children: [jsxRuntime.jsx("div", Object.assign({ className: "jer-input-component" }, { children: getInputComponent(dataType, inputProps) })), isEditing ? (jsxRuntime.jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel })) : (dataType !== 'invalid' &&
|
|
613
|
+
!error && (jsxRuntime.jsx(EditButtons, { startEdit: canEdit ? () => setIsEditing(true) : undefined, handleDelete: canDelete ? handleDelete : undefined, data: data, enableClipboard: enableClipboard, name: name, path: path, translate: translate }))), isEditing && (jsxRuntime.jsxs("div", Object.assign({ className: "jer-select" }, { children: [jsxRuntime.jsx("select", Object.assign({ name: `${name}-type-select`, className: "jer-type-select", onChange: (e) => handleChangeDataType(e.target.value), value: dataType }, { children: DataTypes.map((type) => (jsxRuntime.jsx("option", Object.assign({ value: type }, { children: type }), type))) })), jsxRuntime.jsx("span", { className: "focus" })] }))), !isEditing && error && (jsxRuntime.jsx("span", Object.assign({ className: "jer-error-slug", style: styles.error }, { children: error })))] }))] })) })));
|
|
594
614
|
};
|
|
595
615
|
const getDataType = (value) => {
|
|
596
616
|
if (typeof value === 'string')
|
|
@@ -652,7 +672,10 @@ const CollectionNode = (_a) => {
|
|
|
652
672
|
const [error, setError] = react.useState(null);
|
|
653
673
|
const collectionSize = Object.keys(data).length;
|
|
654
674
|
const filterProps = { key: name, path, level: path.length, value: data, size: collectionSize };
|
|
655
|
-
const
|
|
675
|
+
const startCollapsed = collapseFilter(filterProps);
|
|
676
|
+
const [collapsed, setCollapsed] = react.useState(startCollapsed);
|
|
677
|
+
const hasBeenOpened = react.useRef(!startCollapsed);
|
|
678
|
+
const [isAnimating, setIsAnimating] = react.useState(false);
|
|
656
679
|
react.useEffect(() => {
|
|
657
680
|
setStringifiedValue(JSON.stringify(data, null, 2));
|
|
658
681
|
}, [data]);
|
|
@@ -668,6 +691,14 @@ const CollectionNode = (_a) => {
|
|
|
668
691
|
else if (e.key === 'Escape')
|
|
669
692
|
handleCancel();
|
|
670
693
|
};
|
|
694
|
+
const handleCollapse = () => {
|
|
695
|
+
if (!isEditing) {
|
|
696
|
+
setIsAnimating(true);
|
|
697
|
+
hasBeenOpened.current = true;
|
|
698
|
+
setCollapsed(!collapsed);
|
|
699
|
+
setTimeout(() => setIsAnimating(false), 500);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
671
702
|
const showError = (errorString) => {
|
|
672
703
|
setError(errorString);
|
|
673
704
|
setTimeout(() => setError(null), ERROR_DISPLAY_TIME);
|
|
@@ -732,21 +763,20 @@ const CollectionNode = (_a) => {
|
|
|
732
763
|
if (keySort && collectionType === 'object')
|
|
733
764
|
keyValueArray.sort(typeof keySort === 'function' ? (a, b) => keySort(a[0], b[0]) : undefined);
|
|
734
765
|
const numOfLines = JSON.stringify(data, null, 2).split('\n').length;
|
|
735
|
-
return (jsxRuntime.jsxs("div", Object.assign({ className: "jer-component fb-collection-component", style: { marginLeft: `${path.length === 0 ? 0 : indent / 2}em` } }, { children: [jsxRuntime.jsxs("div", Object.assign({ className: "jer-collection-header-row" }, { children: [jsxRuntime.jsx("div", Object.assign({ onClick: ()
|
|
736
|
-
if (!isEditing)
|
|
737
|
-
setCollapsed(!collapsed);
|
|
738
|
-
} }, { children: jsxRuntime.jsx(Icon, { name: "chevron", rotate: collapsed }) })), jsxRuntime.jsxs("div", Object.assign({ className: "jer-collection-name" }, { children: [jsxRuntime.jsx("span", Object.assign({ style: styles.property }, { children: showLabel ? `${name}:` : null })), jsxRuntime.jsx("span", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.open }))] })), jsxRuntime.jsx("div", Object.assign({ className: "jer-collection-item-count", style: styles.itemCount }, { children: collectionSize === 1
|
|
766
|
+
return (jsxRuntime.jsxs("div", Object.assign({ className: "jer-component fb-collection-component", style: { marginLeft: `${path.length === 0 ? 0 : indent / 2}em` } }, { children: [jsxRuntime.jsxs("div", Object.assign({ className: "jer-collection-header-row" }, { children: [jsxRuntime.jsx("div", Object.assign({ onClick: handleCollapse }, { children: jsxRuntime.jsx(Icon, { name: "chevron", rotate: collapsed }) })), jsxRuntime.jsxs("div", Object.assign({ className: "jer-collection-name" }, { children: [jsxRuntime.jsx("span", Object.assign({ style: styles.property }, { children: showLabel ? `${name}:` : null })), !isEditing && (jsxRuntime.jsx("span", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.open })))] })), !isEditing && (jsxRuntime.jsx("div", Object.assign({ className: "jer-collection-item-count", style: styles.itemCount }, { children: collectionSize === 1
|
|
739
767
|
? translate('ITEM_SINGLE', 1)
|
|
740
|
-
: translate('ITEMS_MULTIPLE', collectionSize) })),
|
|
768
|
+
: translate('ITEMS_MULTIPLE', collectionSize) }))), jsxRuntime.jsx("div", Object.assign({ className: `jer-brackets${collapsed ? ' jer-visible' : ' jer-hidden'}`, style: styles.bracket }, { children: brackets.close })), !isEditing && (jsxRuntime.jsx(EditButtons, { startEdit: canEdit
|
|
741
769
|
? () => {
|
|
742
770
|
setIsEditing(true);
|
|
743
771
|
setCollapsed(false);
|
|
744
772
|
}
|
|
745
773
|
: undefined, handleAdd: canAdd ? handleAdd : undefined, handleDelete: canDelete ? handleDelete : undefined, enableClipboard: enableClipboard, type: collectionType, data: data, name: name, path: path, translate: translate }))] })), jsxRuntime.jsxs("div", Object.assign({ className: 'jer-collection-inner', style: {
|
|
746
|
-
maxHeight: collapsed ? 0 : `${numOfLines *
|
|
747
|
-
overflowY: collapsed ? 'hidden' : 'visible',
|
|
774
|
+
maxHeight: collapsed ? 0 : !isEditing ? `${numOfLines * 3}em` : undefined,
|
|
775
|
+
overflowY: collapsed || isAnimating ? 'hidden' : 'visible',
|
|
748
776
|
transition: `max-height ${transitionTime}`,
|
|
749
|
-
} }, { children: [isEditing ? (jsxRuntime.
|
|
777
|
+
} }, { children: [isEditing ? (jsxRuntime.jsx("div", Object.assign({ className: "jer-collection-text-edit" }, { children: jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(AutogrowTextArea, { className: "jer-collection-text-area", name: path.join('.'), value: stringifiedValue, setValue: setStringifiedValue, isEditing: isEditing, handleKeyPress: handleKeyPress }), jsxRuntime.jsx("div", Object.assign({ className: "jer-collection-input-button-row" }, { children: jsxRuntime.jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel, isCollection: true }) }))] }) }))) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !hasBeenOpened.current
|
|
778
|
+
? null
|
|
779
|
+
: keyValueArray.map(([key, value]) => (jsxRuntime.jsx("div", Object.assign({ className: "jer-collection-element" }, { children: isCollection(value) ? (jsxRuntime.jsx(CollectionNode, Object.assign({ data: value, path: [...path, key], name: key }, props), key)) : (jsxRuntime.jsx(ValueNodeWrapper, Object.assign({ data: value, path: [...path, key], name: key }, props, { showArrayIndices: collectionType === 'object' ? true : showArrayIndices }), key)) }), key))) })), jsxRuntime.jsx("div", Object.assign({ className: isEditing ? 'jer-collection-error-row' : 'jer-collection-error-row-edit' }, { children: error && (jsxRuntime.jsx("span", Object.assign({ className: "jer-error-slug", style: styles.error }, { children: error }))) })), jsxRuntime.jsx("div", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.close }))] }))] })));
|
|
750
780
|
};
|
|
751
781
|
|
|
752
782
|
const localisedStrings = {
|
|
@@ -765,7 +795,7 @@ const translate = (translations, key, count) => {
|
|
|
765
795
|
};
|
|
766
796
|
const getTranslateFunction = (translations) => (key, count) => translate(translations, key, count);
|
|
767
797
|
|
|
768
|
-
const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit = onUpdate, onDelete: srcDelete = onUpdate, onAdd: srcAdd = onUpdate, enableClipboard = true, theme = 'default', icons, indent = 4, collapse = false, restrictEdit = false, restrictDelete = false, restrictAdd = false, keySort = false, showArrayIndices = true, defaultValue = null, minWidth = 250, maxWidth =
|
|
798
|
+
const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit = onUpdate, onDelete: srcDelete = onUpdate, onAdd: srcAdd = onUpdate, enableClipboard = true, theme = 'default', icons, indent = 4, collapse = false, restrictEdit = false, restrictDelete = false, restrictAdd = false, keySort = false, showArrayIndices = true, defaultValue = null, minWidth = 250, maxWidth = 'min(600px, 90vw)', stringTruncate = 250, translations = {}, className, }) => {
|
|
769
799
|
const [data, setData] = react.useState(srcData);
|
|
770
800
|
const { styles, setTheme, setIcons } = useTheme();
|
|
771
801
|
const collapseFilter = react.useCallback(getFilterFunction(collapse), [collapse]);
|
|
@@ -891,4 +921,5 @@ const getFilterFunction = (propValue) => {
|
|
|
891
921
|
};
|
|
892
922
|
|
|
893
923
|
exports.JsonEditor = JsonEditor;
|
|
924
|
+
exports.default = JsonEditor;
|
|
894
925
|
exports.themes = themes;
|
package/build/index.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ interface JsonEditorProps {
|
|
|
55
55
|
showArrayIndices?: boolean;
|
|
56
56
|
defaultValue?: unknown;
|
|
57
57
|
minWidth?: string | number;
|
|
58
|
-
maxWidth?: number;
|
|
58
|
+
maxWidth?: string | number;
|
|
59
59
|
stringTruncate?: number;
|
|
60
60
|
translations?: Partial<LocalisedStrings>;
|
|
61
61
|
}
|
|
@@ -90,10 +90,11 @@ type CopyFunction = (input: {
|
|
|
90
90
|
key: CollectionKey;
|
|
91
91
|
path: CollectionKey[];
|
|
92
92
|
value: unknown;
|
|
93
|
+
stringValue: string;
|
|
93
94
|
type: CopyType;
|
|
94
95
|
}) => void;
|
|
95
96
|
type CompareFunction = (a: string, b: string) => number;
|
|
96
97
|
|
|
97
98
|
declare const JsonEditor: React$1.FC<JsonEditorProps>;
|
|
98
99
|
|
|
99
|
-
export { CompareFunction, CopyFunction, FilterFunction, IconReplacements, JsonEditor, JsonEditorProps, LocalisedStrings, Theme, ThemeInput, ThemeName, TranslateFunction, UpdateFunction, themes };
|
|
100
|
+
export { CompareFunction, CopyFunction, FilterFunction, IconReplacements, JsonEditor, JsonEditorProps, LocalisedStrings, Theme, ThemeInput, ThemeName, TranslateFunction, UpdateFunction, JsonEditor as default, themes };
|
package/build/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext, useState, useContext, useEffect, useMemo, useCallback } from 'react';
|
|
2
|
+
import { createContext, useState, useContext, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
3
3
|
import assign from 'object-property-assigner';
|
|
4
4
|
import extract from 'object-property-extractor';
|
|
5
5
|
import clone from 'just-clone';
|
|
@@ -51,7 +51,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
51
51
|
|
|
52
52
|
var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}
|
|
53
53
|
|
|
54
|
-
var css = ":root {\n --jer-form-border: 1px solid #ededf0;\n --jer-form-border-focus: 1px solid #e2e2e2;\n --jer-expand-transition-time: 0.
|
|
54
|
+
var css = ":root {\n --jer-select-border: #b6b6b6;\n --jer-select-focus: #777;\n --jer-select-arrow: #777;\n --jer-form-border: 1px solid #ededf0;\n --jer-form-border-focus: 1px solid #e2e2e2;\n --jer-expand-transition-time: 0.5s;\n --jer-highlight-color: #b3d8ff;\n}\n\n.jer-visible {\n opacity: 1;\n transition: var(--jer-expand-transition-time);\n}\n\n.jer-hidden {\n opacity: 0;\n transition: var(--jer-expand-transition-time);\n}\n\n/* Select styled as per:\nhttps://moderncss.dev/custom-select-styles-with-pure-css/\n*/\n\n.jer-select select {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n background-color: transparent;\n border: none;\n padding: 0 1em 0 0;\n margin: 0;\n /* width: 100%; */\n font-family: inherit;\n font-size: inherit;\n color: black;\n cursor: inherit;\n line-height: inherit;\n z-index: 1;\n outline: none;\n}\nselect::-ms-expand {\n display: none;\n}\n\n.jer-select {\n display: grid;\n grid-template-areas: 'select';\n align-items: center;\n position: relative;\n min-width: 12ch;\n max-width: 15ch;\n border: 1px solid var(--jer-select-border);\n border-radius: 0.25em;\n padding: 0.25em 0.5em;\n font-size: 1em;\n cursor: pointer;\n line-height: 1.1;\n background-color: #fff;\n background-image: linear-gradient(to top, #f9f9f9, #fff 33%);\n}\n.jer-select select,\n.jer-select::after {\n grid-area: select;\n}\n.jer-select:not(.jer-select--multiple)::after {\n content: '';\n justify-self: end;\n width: 0.8em;\n height: 0.5em;\n background-color: var(--jer-select-arrow);\n -webkit-clip-path: polygon(100% 0%, 0 0%, 50% 100%);\n clip-path: polygon(100% 0%, 0 0%, 50% 100%);\n}\n\nselect:focus + .focus {\n position: absolute;\n top: -1px;\n left: -1px;\n right: -1px;\n bottom: -1px;\n border: 1px solid var(--jer-select-focus);\n border-radius: inherit;\n}\n\n.jer-editor-container {\n font-size: 1.1em;\n /* font-size: 20px; */\n padding: 1em;\n margin-top: 1em;\n margin-bottom: 1em;\n border-radius: 0.5em;\n}\n\n.jer-editor-container textarea {\n /* width: 90%; */\n color: var(--jer-input-color);\n border: var(--jer-form-border);\n border-radius: 0.3em;\n outline: none;\n}\n\n.jer-editor-container textarea:focus {\n border: var(--jer-form-border-focus);\n}\n\n.jer-editor-container input {\n border: var(--jer-form-border);\n border-radius: 0.3em;\n outline: none;\n}\n\n.jer-editor-container input:focus {\n border: var(--jer-form-border-focus);\n}\n\n/* Input highlighted text */\n.jer-editor-container ::selection {\n background-color: var(--jer-highlight-color);\n}\n\n.jer-editor-container select {\n /* color: red; */\n}\n\n.jer-component {\n}\n\n.jer-collection-header-row,\n.jer-value-main-row {\n display: flex;\n min-height: 1.7em;\n gap: 0.3em;\n align-items: center;\n}\n\n.jer-collection-header-row {\n display: flex;\n flex-wrap: wrap;\n}\n\n.jer-brackets {\n}\n\n.jer-collection-item-count {\n}\n\n.jer-collection-inner {\n position: relative;\n}\n\n.jer-collection-text-edit {\n display: flex;\n flex-direction: column;\n gap: 0.3em;\n align-items: flex-start;\n}\n\n.jer-collection-text-area {\n resize: both;\n padding-top: 0.2em;\n padding-left: 0.5em;\n padding-right: 0.5em;\n padding-bottom: 0;\n overflow: hidden;\n max-height: 40em;\n}\n\n.jer-collection-input-button-row {\n display: flex;\n justify-content: flex-end;\n font-size: 150%;\n}\n\n.jer-collection-element {\n}\n\n.jer-collection-error-row {\n position: absolute;\n bottom: 0;\n}\n\n.jer-collection-error-row-edit {\n}\n\n.jer-error-slug {\n margin-left: 1em;\n}\n\n.jer-value-component {\n position: relative;\n}\n\n.jer-value-main-row {\n display: flex;\n gap: 0;\n}\n\n.jer-value-and-buttons {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n padding-left: 0.5em;\n}\n\n.jer-value-error-row {\n position: absolute;\n}\n\n.jer-value-string {\n line-height: 1.3em;\n}\n\n.jer-input-text {\n resize: none;\n margin: 0;\n height: 1.4em;\n padding-left: 0.5em;\n padding-right: 0.5em;\n padding-bottom: 0;\n min-width: 6em;\n overflow: hidden;\n max-height: 30em;\n}\n\n.jer-value-number {\n}\n\n.jer-value-boolean {\n}\n\n.jer-input-boolean {\n transform: scale(1.5);\n margin-left: 0.3em;\n margin-right: 0.3em;\n}\n\n.jer-value-null {\n}\n\n.jer-value-object {\n}\n\n.jer-object-key {\n word-break: break-word;\n line-height: 1.1em;\n}\n\n.jer-value-array {\n}\n\n.jer-value-invalid {\n opacity: 0.5;\n font-style: italic;\n}\n\n/* .jer-input-text, */\n.jer-input-number {\n height: 1.6em;\n}\n\n.jer-input-number {\n min-width: 3em;\n}\n\n.jer-input-component {\n}\n\n.jer-edit-buttons,\n.jer-confirm-buttons {\n display: flex;\n align-items: center;\n cursor: pointer;\n}\n\n.jer-input-buttons {\n gap: 0.4em;\n}\n\n.jer-edit-buttons {\n gap: 0.4em;\n margin-left: 0.5em;\n opacity: 0;\n}\n\n.jer-confirm-buttons {\n gap: 0.2em;\n margin-left: 0.4em;\n}\n\n.jer-edit-buttons:hover {\n opacity: 1;\n position: relative;\n}\n\n.jer-collection-header-row:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-value-main-row:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-value-and-buttons:hover > .jer-edit-buttons {\n opacity: 1;\n}\n\n.jer-input-buttons {\n}\n\n.jer-copy-pulse {\n position: relative;\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-copy-pulse:hover {\n opacity: 0.85;\n transition: 0.3s;\n transform: scale(1.2);\n}\n\n.jer-copy-pulse:after {\n content: '';\n display: block;\n position: absolute;\n border-radius: 50%;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n opacity: 0;\n transition: all 0.5s;\n box-shadow: 0 0 15px 5px var(--jer-icon-copy-color);\n}\n\n.jer-copy-pulse:active:after {\n box-shadow: 0 0 0 0 var(--jer-icon-copy-color);\n position: absolute;\n border-radius: 4em;\n left: 0;\n top: 0;\n opacity: 1;\n transition: 0s;\n}\n\n.jer-copy-pulse:active {\n top: 0.07em;\n}\n\n.jer-rotate-90 {\n transform: rotate(-90deg);\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-accordion-icon {\n /* font-size: '2em'; */\n transition: transform var(--jer-expand-transition-time);\n}\n\n.jer-icon:hover {\n opacity: 0.85;\n transition: 0.3s;\n transform: scale(1.2);\n}\n";
|
|
55
55
|
n(css,{});
|
|
56
56
|
|
|
57
57
|
const defaultTheme$1 = {
|
|
@@ -390,6 +390,7 @@ const AutogrowTextArea = ({ className, name, value, setValue, handleKeyPress, })
|
|
|
390
390
|
}, onKeyDown: handleKeyPress }), jsx("span", Object.assign({ className: className, style: Object.assign({ visibility: 'hidden', height: 'auto', gridArea: '1 / 1 / 2 / 2', color: 'red', opacity: 0.9, whiteSpace: 'pre-wrap', overflow: 'clip', border: '1px solid transparent' }, styles.input) }, { children: dummyValue }))] })));
|
|
391
391
|
};
|
|
392
392
|
|
|
393
|
+
const INVALID_FUNCTION_STRING = '**INVALID_FUNCTION**';
|
|
393
394
|
const truncate = (string, length = 200) => string.length < length ? string : `${string.slice(0, length - 2).trim()}...`;
|
|
394
395
|
const StringValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdit, handleCancel, stringTruncate, }) => {
|
|
395
396
|
const { styles } = useTheme();
|
|
@@ -413,7 +414,10 @@ const NumberValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdi
|
|
|
413
414
|
else if (e.key === 'Escape')
|
|
414
415
|
handleCancel();
|
|
415
416
|
};
|
|
416
|
-
|
|
417
|
+
const validateNumber = (input) => {
|
|
418
|
+
return input.replace(/[^0-9.-]/g, '');
|
|
419
|
+
};
|
|
420
|
+
return isEditing ? (jsx("input", { className: "jer-input-number", type: "text", name: path.join('.'), value: value, onChange: (e) => setValue(validateNumber(e.target.value)), autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPress, style: { width: `${String(value).length / 1.5 + 2}em` } })) : (jsx("span", Object.assign({ onDoubleClick: () => setIsEditing(true), className: "jer-value-number", style: styles.number }, { children: value })));
|
|
417
421
|
};
|
|
418
422
|
const BooleanValue = ({ value, setValue, isEditing, path, setIsEditing, }) => {
|
|
419
423
|
const { styles } = useTheme();
|
|
@@ -423,14 +427,23 @@ const NullValue = ({ value, isEditing, setIsEditing }) => {
|
|
|
423
427
|
const { styles } = useTheme();
|
|
424
428
|
return isEditing ? (jsx("div", Object.assign({ className: "jer-input-null" }, { children: "null" }))) : (jsx("div", Object.assign({ onDoubleClick: () => setIsEditing(true), className: "jer-value-null", style: styles.null }, { children: String(value) })));
|
|
425
429
|
};
|
|
426
|
-
const ObjectValue = () => {
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
430
|
+
const ObjectValue = () => (jsx("span", Object.assign({ className: "jer-value-object" }, { children: '{ }' })));
|
|
431
|
+
const ArrayValue = ({ value }) => (jsx("span", Object.assign({ className: "jer-value-array" }, { children: `[${value === null ? '' : value}]` })));
|
|
432
|
+
const InvalidValue = ({ value }) => {
|
|
433
|
+
let message = 'Error!';
|
|
434
|
+
switch (typeof value) {
|
|
435
|
+
case 'string':
|
|
436
|
+
if (value === INVALID_FUNCTION_STRING)
|
|
437
|
+
message = 'Function';
|
|
438
|
+
break;
|
|
439
|
+
case 'undefined':
|
|
440
|
+
message = 'Undefined';
|
|
441
|
+
break;
|
|
442
|
+
case 'symbol':
|
|
443
|
+
message = 'Symbol';
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
return jsx("span", Object.assign({ className: "jer-value-invalid" }, { children: message }));
|
|
434
447
|
};
|
|
435
448
|
|
|
436
449
|
const Icon = ({ name, rotate }) => {
|
|
@@ -451,7 +464,7 @@ const Icon = ({ name, rotate }) => {
|
|
|
451
464
|
case 'cancel':
|
|
452
465
|
return ((_f = icons === null || icons === void 0 ? void 0 : icons.cancel) !== null && _f !== void 0 ? _f : (jsx(TiCancel, Object.assign({}, commonProps, { style: Object.assign({ fontSize: '130%' }, styles.iconCancel) }))));
|
|
453
466
|
case 'chevron':
|
|
454
|
-
return ((_g = icons === null || icons === void 0 ? void 0 : icons.chevron) !== null && _g !== void 0 ? _g : (jsx(FaChevronDown, { className:
|
|
467
|
+
return ((_g = icons === null || icons === void 0 ? void 0 : icons.chevron) !== null && _g !== void 0 ? _g : (jsx(FaChevronDown, { className: `jer-accordion-icon${rotate ? ' jer-rotate-90' : ''}`, style: styles.iconCollection })));
|
|
455
468
|
default:
|
|
456
469
|
return jsx(Fragment, {});
|
|
457
470
|
}
|
|
@@ -475,21 +488,24 @@ const EditButtons = ({ startEdit, handleDelete, handleAdd, enableClipboard, type
|
|
|
475
488
|
setIsAdding(false);
|
|
476
489
|
};
|
|
477
490
|
const handleCopy = (e) => {
|
|
478
|
-
let
|
|
491
|
+
let copyType = 'value';
|
|
479
492
|
let value;
|
|
493
|
+
let stringValue = '';
|
|
480
494
|
if (enableClipboard) {
|
|
481
495
|
switch (e.ctrlKey || e.metaKey) {
|
|
482
496
|
case true:
|
|
483
497
|
value = stringifyPath(path);
|
|
484
|
-
|
|
498
|
+
stringValue = value;
|
|
499
|
+
copyType = 'path';
|
|
485
500
|
break;
|
|
486
|
-
|
|
487
|
-
value =
|
|
501
|
+
default:
|
|
502
|
+
value = data;
|
|
503
|
+
stringValue = type ? JSON.stringify(data, null, 2) : String(value);
|
|
488
504
|
}
|
|
489
|
-
navigator.clipboard.writeText(
|
|
505
|
+
navigator.clipboard.writeText(stringValue);
|
|
490
506
|
}
|
|
491
507
|
if (typeof enableClipboard === 'function')
|
|
492
|
-
enableClipboard({ value, path, key: name, type });
|
|
508
|
+
enableClipboard({ value, stringValue, path, key: name, type: copyType });
|
|
493
509
|
};
|
|
494
510
|
return (jsxs("div", Object.assign({ className: "jer-edit-buttons", style: isAdding ? { opacity: 1 } : undefined }, { children: [enableClipboard && (jsx("div", Object.assign({ onClick: handleCopy, className: "jer-copy-pulse" }, { children: jsx(Icon, { name: "copy" }) }))), startEdit && (jsx("div", Object.assign({ onClick: startEdit }, { children: jsx(Icon, { name: "edit" }) }))), handleDelete && (jsx("div", Object.assign({ onClick: handleDelete }, { children: jsx(Icon, { name: "delete" }) }))), handleAdd && (jsx("div", Object.assign({ onClick: () => {
|
|
495
511
|
if (type === 'object')
|
|
@@ -523,11 +539,11 @@ const DataTypes = [...ValueDataTypes, ...CollectionDataTypes];
|
|
|
523
539
|
const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard, restrictEditFilter, restrictDeleteFilter, showArrayIndices, stringTruncate, indent, translate, }) => {
|
|
524
540
|
const { styles } = useTheme();
|
|
525
541
|
const [isEditing, setIsEditing] = useState(false);
|
|
526
|
-
const [value, setValue] = useState(data);
|
|
542
|
+
const [value, setValue] = useState(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
|
|
527
543
|
const [error, setError] = useState(null);
|
|
528
544
|
const [dataType, setDataType] = useState(getDataType(data));
|
|
529
545
|
useEffect(() => {
|
|
530
|
-
setValue(data);
|
|
546
|
+
setValue(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
|
|
531
547
|
setDataType(getDataType(data));
|
|
532
548
|
}, [data, error]);
|
|
533
549
|
const handleChangeDataType = (type) => {
|
|
@@ -581,14 +597,16 @@ const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard,
|
|
|
581
597
|
value,
|
|
582
598
|
setValue,
|
|
583
599
|
isEditing,
|
|
584
|
-
setIsEditing,
|
|
600
|
+
setIsEditing: canEdit ? () => setIsEditing(true) : () => { },
|
|
585
601
|
handleEdit,
|
|
586
602
|
handleCancel,
|
|
587
603
|
path,
|
|
588
604
|
stringTruncate,
|
|
589
605
|
};
|
|
590
|
-
return (jsx("div", Object.assign({ className: "jer-component jer-value-component", style: { marginLeft: `${indent / 2}em` } }, { children: jsxs("div", Object.assign({ className: "jer-value-main-row"
|
|
591
|
-
|
|
606
|
+
return (jsx("div", Object.assign({ className: "jer-component jer-value-component", style: { marginLeft: `${indent / 2}em` } }, { children: jsxs("div", Object.assign({ className: "jer-value-main-row", style: {
|
|
607
|
+
flexWrap: name.length > 10 ? 'wrap' : 'nowrap',
|
|
608
|
+
} }, { children: [showArrayIndices && (jsxs("label", Object.assign({ htmlFor: path.join('.'), className: "jer-object-key", style: Object.assign(Object.assign({}, styles.property), { minWidth: `${Math.min(String(name).length + 1, 5)}ch`, flexShrink: name.length > 10 ? 1 : 0 }) }, { children: [name, ":", ' '] }))), jsxs("div", Object.assign({ className: "jer-value-and-buttons" }, { children: [jsx("div", Object.assign({ className: "jer-input-component" }, { children: getInputComponent(dataType, inputProps) })), isEditing ? (jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel })) : (dataType !== 'invalid' &&
|
|
609
|
+
!error && (jsx(EditButtons, { startEdit: canEdit ? () => setIsEditing(true) : undefined, handleDelete: canDelete ? handleDelete : undefined, data: data, enableClipboard: enableClipboard, name: name, path: path, translate: translate }))), isEditing && (jsxs("div", Object.assign({ className: "jer-select" }, { children: [jsx("select", Object.assign({ name: `${name}-type-select`, className: "jer-type-select", onChange: (e) => handleChangeDataType(e.target.value), value: dataType }, { children: DataTypes.map((type) => (jsx("option", Object.assign({ value: type }, { children: type }), type))) })), jsx("span", { className: "focus" })] }))), !isEditing && error && (jsx("span", Object.assign({ className: "jer-error-slug", style: styles.error }, { children: error })))] }))] })) })));
|
|
592
610
|
};
|
|
593
611
|
const getDataType = (value) => {
|
|
594
612
|
if (typeof value === 'string')
|
|
@@ -650,7 +668,10 @@ const CollectionNode = (_a) => {
|
|
|
650
668
|
const [error, setError] = useState(null);
|
|
651
669
|
const collectionSize = Object.keys(data).length;
|
|
652
670
|
const filterProps = { key: name, path, level: path.length, value: data, size: collectionSize };
|
|
653
|
-
const
|
|
671
|
+
const startCollapsed = collapseFilter(filterProps);
|
|
672
|
+
const [collapsed, setCollapsed] = useState(startCollapsed);
|
|
673
|
+
const hasBeenOpened = useRef(!startCollapsed);
|
|
674
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
654
675
|
useEffect(() => {
|
|
655
676
|
setStringifiedValue(JSON.stringify(data, null, 2));
|
|
656
677
|
}, [data]);
|
|
@@ -666,6 +687,14 @@ const CollectionNode = (_a) => {
|
|
|
666
687
|
else if (e.key === 'Escape')
|
|
667
688
|
handleCancel();
|
|
668
689
|
};
|
|
690
|
+
const handleCollapse = () => {
|
|
691
|
+
if (!isEditing) {
|
|
692
|
+
setIsAnimating(true);
|
|
693
|
+
hasBeenOpened.current = true;
|
|
694
|
+
setCollapsed(!collapsed);
|
|
695
|
+
setTimeout(() => setIsAnimating(false), 500);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
669
698
|
const showError = (errorString) => {
|
|
670
699
|
setError(errorString);
|
|
671
700
|
setTimeout(() => setError(null), ERROR_DISPLAY_TIME);
|
|
@@ -730,21 +759,20 @@ const CollectionNode = (_a) => {
|
|
|
730
759
|
if (keySort && collectionType === 'object')
|
|
731
760
|
keyValueArray.sort(typeof keySort === 'function' ? (a, b) => keySort(a[0], b[0]) : undefined);
|
|
732
761
|
const numOfLines = JSON.stringify(data, null, 2).split('\n').length;
|
|
733
|
-
return (jsxs("div", Object.assign({ className: "jer-component fb-collection-component", style: { marginLeft: `${path.length === 0 ? 0 : indent / 2}em` } }, { children: [jsxs("div", Object.assign({ className: "jer-collection-header-row" }, { children: [jsx("div", Object.assign({ onClick: ()
|
|
734
|
-
if (!isEditing)
|
|
735
|
-
setCollapsed(!collapsed);
|
|
736
|
-
} }, { children: jsx(Icon, { name: "chevron", rotate: collapsed }) })), jsxs("div", Object.assign({ className: "jer-collection-name" }, { children: [jsx("span", Object.assign({ style: styles.property }, { children: showLabel ? `${name}:` : null })), jsx("span", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.open }))] })), jsx("div", Object.assign({ className: "jer-collection-item-count", style: styles.itemCount }, { children: collectionSize === 1
|
|
762
|
+
return (jsxs("div", Object.assign({ className: "jer-component fb-collection-component", style: { marginLeft: `${path.length === 0 ? 0 : indent / 2}em` } }, { children: [jsxs("div", Object.assign({ className: "jer-collection-header-row" }, { children: [jsx("div", Object.assign({ onClick: handleCollapse }, { children: jsx(Icon, { name: "chevron", rotate: collapsed }) })), jsxs("div", Object.assign({ className: "jer-collection-name" }, { children: [jsx("span", Object.assign({ style: styles.property }, { children: showLabel ? `${name}:` : null })), !isEditing && (jsx("span", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.open })))] })), !isEditing && (jsx("div", Object.assign({ className: "jer-collection-item-count", style: styles.itemCount }, { children: collectionSize === 1
|
|
737
763
|
? translate('ITEM_SINGLE', 1)
|
|
738
|
-
: translate('ITEMS_MULTIPLE', collectionSize) })),
|
|
764
|
+
: translate('ITEMS_MULTIPLE', collectionSize) }))), jsx("div", Object.assign({ className: `jer-brackets${collapsed ? ' jer-visible' : ' jer-hidden'}`, style: styles.bracket }, { children: brackets.close })), !isEditing && (jsx(EditButtons, { startEdit: canEdit
|
|
739
765
|
? () => {
|
|
740
766
|
setIsEditing(true);
|
|
741
767
|
setCollapsed(false);
|
|
742
768
|
}
|
|
743
769
|
: undefined, handleAdd: canAdd ? handleAdd : undefined, handleDelete: canDelete ? handleDelete : undefined, enableClipboard: enableClipboard, type: collectionType, data: data, name: name, path: path, translate: translate }))] })), jsxs("div", Object.assign({ className: 'jer-collection-inner', style: {
|
|
744
|
-
maxHeight: collapsed ? 0 : `${numOfLines *
|
|
745
|
-
overflowY: collapsed ? 'hidden' : 'visible',
|
|
770
|
+
maxHeight: collapsed ? 0 : !isEditing ? `${numOfLines * 3}em` : undefined,
|
|
771
|
+
overflowY: collapsed || isAnimating ? 'hidden' : 'visible',
|
|
746
772
|
transition: `max-height ${transitionTime}`,
|
|
747
|
-
} }, { children: [isEditing ? (
|
|
773
|
+
} }, { children: [isEditing ? (jsx("div", Object.assign({ className: "jer-collection-text-edit" }, { children: jsxs("div", { children: [jsx(AutogrowTextArea, { className: "jer-collection-text-area", name: path.join('.'), value: stringifiedValue, setValue: setStringifiedValue, isEditing: isEditing, handleKeyPress: handleKeyPress }), jsx("div", Object.assign({ className: "jer-collection-input-button-row" }, { children: jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel, isCollection: true }) }))] }) }))) : (jsx(Fragment, { children: !hasBeenOpened.current
|
|
774
|
+
? null
|
|
775
|
+
: keyValueArray.map(([key, value]) => (jsx("div", Object.assign({ className: "jer-collection-element" }, { children: isCollection(value) ? (jsx(CollectionNode, Object.assign({ data: value, path: [...path, key], name: key }, props), key)) : (jsx(ValueNodeWrapper, Object.assign({ data: value, path: [...path, key], name: key }, props, { showArrayIndices: collectionType === 'object' ? true : showArrayIndices }), key)) }), key))) })), jsx("div", Object.assign({ className: isEditing ? 'jer-collection-error-row' : 'jer-collection-error-row-edit' }, { children: error && (jsx("span", Object.assign({ className: "jer-error-slug", style: styles.error }, { children: error }))) })), jsx("div", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.close }))] }))] })));
|
|
748
776
|
};
|
|
749
777
|
|
|
750
778
|
const localisedStrings = {
|
|
@@ -763,7 +791,7 @@ const translate = (translations, key, count) => {
|
|
|
763
791
|
};
|
|
764
792
|
const getTranslateFunction = (translations) => (key, count) => translate(translations, key, count);
|
|
765
793
|
|
|
766
|
-
const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit = onUpdate, onDelete: srcDelete = onUpdate, onAdd: srcAdd = onUpdate, enableClipboard = true, theme = 'default', icons, indent = 4, collapse = false, restrictEdit = false, restrictDelete = false, restrictAdd = false, keySort = false, showArrayIndices = true, defaultValue = null, minWidth = 250, maxWidth =
|
|
794
|
+
const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit = onUpdate, onDelete: srcDelete = onUpdate, onAdd: srcAdd = onUpdate, enableClipboard = true, theme = 'default', icons, indent = 4, collapse = false, restrictEdit = false, restrictDelete = false, restrictAdd = false, keySort = false, showArrayIndices = true, defaultValue = null, minWidth = 250, maxWidth = 'min(600px, 90vw)', stringTruncate = 250, translations = {}, className, }) => {
|
|
767
795
|
const [data, setData] = useState(srcData);
|
|
768
796
|
const { styles, setTheme, setIcons } = useTheme();
|
|
769
797
|
const collapseFilter = useCallback(getFilterFunction(collapse), [collapse]);
|
|
@@ -888,4 +916,4 @@ const getFilterFunction = (propValue) => {
|
|
|
888
916
|
return propValue;
|
|
889
917
|
};
|
|
890
918
|
|
|
891
|
-
export { JsonEditor, themes };
|
|
919
|
+
export { JsonEditor, JsonEditor as default, themes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-edit-react",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6",
|
|
4
4
|
"description": "React component for editing or viewing JSON/object data",
|
|
5
5
|
"main": "build/index.cjs.js",
|
|
6
6
|
"module": "build/index.esm.js",
|
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"setup": "yarn install && cd demo && yarn install",
|
|
16
|
-
"demo": "cd demo && yarn start",
|
|
16
|
+
"demo": "cd demo && node ./scripts/getVersion.js && yarn start",
|
|
17
17
|
"build": "rimraf ./build && rollup -c && rimraf ./build/dts",
|
|
18
|
-
"compile": "rimraf ./build && tsc"
|
|
18
|
+
"compile": "rimraf ./build && tsc",
|
|
19
|
+
"release": "yarn build && yarn publish",
|
|
20
|
+
"release-demo": "cd demo && yarn deploy"
|
|
19
21
|
},
|
|
20
22
|
"peerDependencies": {
|
|
21
23
|
"@types/react": "^18.2.6",
|