json-edit-react 0.9.4 → 1.0.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.
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var jsxRuntime = require('react/jsx-runtime');
6
4
  var react = require('react');
7
5
  var assign = require('object-property-assigner');
@@ -28,7 +26,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
28
26
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
29
27
  PERFORMANCE OF THIS SOFTWARE.
30
28
  ***************************************************************************** */
31
- /* global Reflect, Promise */
29
+ /* global Reflect, Promise, SuppressedError, Symbol */
32
30
 
33
31
 
34
32
  function __rest(s, e) {
@@ -51,11 +49,16 @@ function __awaiter(thisArg, _arguments, P, generator) {
51
49
  function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
52
50
  step((generator = generator.apply(thisArg, _arguments || [])).next());
53
51
  });
54
- }
52
+ }
53
+
54
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
55
+ var e = new Error(message);
56
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
57
+ };
55
58
 
56
59
  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}}
57
60
 
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.2s;\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-icon-wrapper {\n height: 1.4em;\n opacity: 1;\n transition: 0.2s;\n}\n\n.jer-icon-wrapper:active {\n position: relative;\n top: 0.07em;\n}\n\n.jer-icon-wrapper:hover {\n opacity: 0.85;\n transition: 0.2s;\n transform: scale(1.2);\n}\n\n.jer-copy-pulse {\n position: relative;\n}\n\n.jer-copy-pulse:hover {\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-icon {\n /* font-size: '2em'; */\n}\n\n.jer-icon:hover {\n opacity: 0.85;\n transition: 0.3s;\n transform: scale(1.2);\n}\n";
61
+ 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";
59
62
  n(css,{});
60
63
 
61
64
  const defaultTheme$1 = {
@@ -314,7 +317,7 @@ const ThemeProvider = ({ children }) => {
314
317
  const [styles, setStyles] = react.useState(emptyStyleObject);
315
318
  const [icons, setIcons] = react.useState({});
316
319
  const setTheme = (theme) => setStyles(compileStyles(theme));
317
- return (jsxRuntime.jsx(ThemeProviderContext.Provider, Object.assign({ value: { styles, setTheme, icons, setIcons } }, { children: children })));
320
+ return (jsxRuntime.jsx(ThemeProviderContext.Provider, { value: { styles, setTheme, icons, setIcons }, children: children }));
318
321
  };
319
322
  const useTheme = () => react.useContext(ThemeProviderContext);
320
323
  const compileStyles = (themeInput) => {
@@ -388,12 +391,13 @@ const defaultStyleProperties = {
388
391
  const AutogrowTextArea = ({ className, name, value, setValue, handleKeyPress, }) => {
389
392
  const { styles } = useTheme();
390
393
  const dummyValue = value.slice(-1) === '\n' ? value + '.' : value;
391
- return (jsxRuntime.jsxs("div", Object.assign({ style: { display: 'grid' } }, { children: [jsxRuntime.jsx("textarea", { style: Object.assign({ height: 'auto', gridArea: '1 / 1 / 2 / 2', overflowY: 'auto' }, styles.input), rows: 1, className: className, name: name, value: value, onChange: (e) => setValue(e.target.value), autoFocus: true, onFocus: (e) => {
394
+ return (jsxRuntime.jsxs("div", { style: { display: 'grid' }, children: [jsxRuntime.jsx("textarea", { style: Object.assign({ height: 'auto', gridArea: '1 / 1 / 2 / 2', overflowY: 'auto' }, styles.input), rows: 1, className: className, name: name, value: value, onChange: (e) => setValue(e.target.value), autoFocus: true, onFocus: (e) => {
392
395
  if (value.length < 40)
393
396
  e.target.select();
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 }))] })));
397
+ }, onKeyDown: handleKeyPress }), jsxRuntime.jsx("span", { 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 })] }));
395
398
  };
396
399
 
400
+ const INVALID_FUNCTION_STRING = '**INVALID_FUNCTION**';
397
401
  const truncate = (string, length = 200) => string.length < length ? string : `${string.slice(0, length - 2).trim()}...`;
398
402
  const StringValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdit, handleCancel, stringTruncate, }) => {
399
403
  const { styles } = useTheme();
@@ -404,10 +408,10 @@ const StringValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdi
404
408
  handleCancel();
405
409
  };
406
410
  const breakString = (text) => text.split('\n').map((line, index, arr) => (jsxRuntime.jsxs("span", { children: [line, index < arr.length - 1 ? jsxRuntime.jsx("br", {}) : null] }, index)));
407
- return isEditing ? (jsxRuntime.jsx(AutogrowTextArea, { className: "jer-input-text", name: path.join('.'), value: value, setValue: setValue, isEditing: isEditing, handleKeyPress: handleKeyPress })) : (jsxRuntime.jsxs("div", Object.assign({ onDoubleClick: () => setIsEditing(true), onClick: (e) => {
411
+ return isEditing ? (jsxRuntime.jsx(AutogrowTextArea, { className: "jer-input-text", name: path.join('.'), value: value, setValue: setValue, isEditing: isEditing, handleKeyPress: handleKeyPress })) : (jsxRuntime.jsxs("div", { onDoubleClick: () => setIsEditing(true), onClick: (e) => {
408
412
  if (e.getModifierState('Control') || e.getModifierState('Meta'))
409
413
  setIsEditing(true);
410
- }, className: "jer-value-string", style: styles.string }, { children: ["\"", breakString(truncate(value, stringTruncate)), "\""] })));
414
+ }, className: "jer-value-string", style: styles.string, children: ["\"", breakString(truncate(value, stringTruncate)), "\""] }));
411
415
  };
412
416
  const NumberValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdit, handleCancel, }) => {
413
417
  const { styles } = useTheme();
@@ -420,24 +424,85 @@ const NumberValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdi
420
424
  const validateNumber = (input) => {
421
425
  return input.replace(/[^0-9.-]/g, '');
422
426
  };
423
- 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 })));
427
+ 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", { onDoubleClick: () => setIsEditing(true), className: "jer-value-number", style: styles.number, children: value }));
424
428
  };
425
- const BooleanValue = ({ value, setValue, isEditing, path, setIsEditing, }) => {
429
+ const BooleanValue = ({ value, setValue, isEditing, path, setIsEditing, handleEdit, handleCancel, }) => {
426
430
  const { styles } = useTheme();
427
- return isEditing ? (jsxRuntime.jsx("input", { className: "jer-input-boolean", type: "checkbox", name: path.join('.'), checked: value, onChange: () => setValue(!value) })) : (jsxRuntime.jsx("span", Object.assign({ onDoubleClick: () => setIsEditing(true), className: "jer-value-boolean", style: styles.boolean }, { children: String(value) })));
431
+ react.useEffect(() => {
432
+ if (isEditing)
433
+ document.addEventListener('keydown', listenForSubmit);
434
+ return () => document.removeEventListener('keydown', listenForSubmit);
435
+ }, [isEditing]);
436
+ const listenForSubmit = (event) => {
437
+ if (event.key === 'Enter') {
438
+ handleEdit();
439
+ }
440
+ else if (event.key === 'Escape')
441
+ handleCancel();
442
+ };
443
+ return isEditing ? (jsxRuntime.jsx("input", { className: "jer-input-boolean", type: "checkbox", name: path.join('.'), checked: value, onChange: () => setValue(!value) })) : (jsxRuntime.jsx("span", { onDoubleClick: () => setIsEditing(true), className: "jer-value-boolean", style: styles.boolean, children: String(value) }));
428
444
  };
429
- const NullValue = ({ value, isEditing, setIsEditing }) => {
445
+ const NullValue = ({ value, isEditing, setIsEditing, handleEdit, handleCancel, }) => {
430
446
  const { styles } = useTheme();
431
- 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) })));
447
+ react.useEffect(() => {
448
+ if (isEditing)
449
+ document.addEventListener('keydown', listenForSubmit);
450
+ return () => document.removeEventListener('keydown', listenForSubmit);
451
+ }, [isEditing]);
452
+ const listenForSubmit = (event) => {
453
+ if (event.key === 'Enter') {
454
+ handleEdit();
455
+ }
456
+ else if (event.key === 'Escape')
457
+ handleCancel();
458
+ };
459
+ return isEditing ? (jsxRuntime.jsx("div", { className: "jer-input-null", children: "null" })) : (jsxRuntime.jsx("div", { onDoubleClick: () => setIsEditing(true), className: "jer-value-null", style: styles.null, children: String(value) }));
432
460
  };
433
- const ObjectValue = () => {
434
- return jsxRuntime.jsx("span", Object.assign({ className: "jer-value-object" }, { children: '{ }' }));
461
+ const ObjectValue = ({ value, translate, isEditing, handleEdit, handleCancel, }) => {
462
+ react.useEffect(() => {
463
+ if (isEditing)
464
+ document.addEventListener('keydown', listenForSubmit);
465
+ return () => document.removeEventListener('keydown', listenForSubmit);
466
+ }, []);
467
+ const listenForSubmit = (event) => {
468
+ if (event.key === 'Enter') {
469
+ handleEdit();
470
+ }
471
+ else if (event.key === 'Escape')
472
+ handleCancel();
473
+ };
474
+ return (jsxRuntime.jsx("span", { className: "jer-value-object", children: `{${translate('DEFAULT_NEW_KEY')}: "${value}" }` }));
435
475
  };
436
- const ArrayValue = ({ value }) => {
437
- return jsxRuntime.jsx("span", Object.assign({ className: "jer-value-array" }, { children: `[${value === null ? '' : value}]` }));
476
+ const ArrayValue = ({ value, isEditing, handleEdit, handleCancel, }) => {
477
+ react.useEffect(() => {
478
+ if (isEditing)
479
+ document.addEventListener('keydown', listenForSubmit);
480
+ return () => document.removeEventListener('keydown', listenForSubmit);
481
+ }, []);
482
+ const listenForSubmit = (event) => {
483
+ if (event.key === 'Enter') {
484
+ handleEdit();
485
+ }
486
+ else if (event.key === 'Escape')
487
+ handleCancel();
488
+ };
489
+ return jsxRuntime.jsx("span", { className: "jer-value-array", children: `[${value === null ? '' : value}]` });
438
490
  };
439
- const InvalidValue = () => {
440
- return jsxRuntime.jsx("span", Object.assign({ className: "jer-value-invalid" }, { children: "Invalid value" }));
491
+ const InvalidValue = ({ value }) => {
492
+ let message = 'Error!';
493
+ switch (typeof value) {
494
+ case 'string':
495
+ if (value === INVALID_FUNCTION_STRING)
496
+ message = 'Function';
497
+ break;
498
+ case 'undefined':
499
+ message = 'Undefined';
500
+ break;
501
+ case 'symbol':
502
+ message = 'Symbol';
503
+ break;
504
+ }
505
+ return jsxRuntime.jsx("span", { className: "jer-value-invalid", children: message });
441
506
  };
442
507
 
443
508
  const Icon = ({ name, rotate }) => {
@@ -458,7 +523,7 @@ const Icon = ({ name, rotate }) => {
458
523
  case 'cancel':
459
524
  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) }))));
460
525
  case 'chevron':
461
- return ((_g = icons === null || icons === void 0 ? void 0 : icons.chevron) !== null && _g !== void 0 ? _g : (jsxRuntime.jsx(fa.FaChevronDown, { className: `${rotate ? ' jer-rotate-90' : ''}`, style: styles.iconCollection })));
526
+ 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 })));
462
527
  default:
463
528
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
464
529
  }
@@ -482,38 +547,41 @@ const EditButtons = ({ startEdit, handleDelete, handleAdd, enableClipboard, type
482
547
  setIsAdding(false);
483
548
  };
484
549
  const handleCopy = (e) => {
485
- let type = 'value';
486
- let value = '';
550
+ let copyType = 'value';
551
+ let value;
552
+ let stringValue = '';
487
553
  if (enableClipboard) {
488
554
  switch (e.ctrlKey || e.metaKey) {
489
555
  case true:
490
556
  value = stringifyPath(path);
491
- type = 'path';
557
+ stringValue = value;
558
+ copyType = 'path';
492
559
  break;
493
560
  default:
494
- value = JSON.stringify(data, null, 2);
561
+ value = data;
562
+ stringValue = type ? JSON.stringify(data, null, 2) : String(value);
495
563
  }
496
- navigator.clipboard.writeText(value);
564
+ navigator.clipboard.writeText(stringValue);
497
565
  }
498
566
  if (typeof enableClipboard === 'function')
499
- enableClipboard({ value, path, key: name, type });
567
+ enableClipboard({ value, stringValue, path, key: name, type: copyType });
500
568
  };
501
- 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: () => {
569
+ return (jsxRuntime.jsxs("div", { className: "jer-edit-buttons", style: isAdding ? { opacity: 1 } : undefined, children: [enableClipboard && (jsxRuntime.jsx("div", { onClick: handleCopy, className: "jer-copy-pulse", children: jsxRuntime.jsx(Icon, { name: "copy" }) })), startEdit && (jsxRuntime.jsx("div", { onClick: startEdit, children: jsxRuntime.jsx(Icon, { name: "edit" }) })), handleDelete && (jsxRuntime.jsx("div", { onClick: handleDelete, children: jsxRuntime.jsx(Icon, { name: "delete" }) })), handleAdd && (jsxRuntime.jsx("div", { onClick: () => {
502
570
  if (type === 'object')
503
571
  setIsAdding(true);
504
572
  else
505
573
  handleAdd('');
506
- } }, { children: jsxRuntime.jsx(Icon, { name: "add" }) }))), isAdding && handleAdd && type === 'object' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { className: "jer-input-new-key", type: "text", name: "new-object-key", value: newKey, onChange: (e) => setNewKey(e.target.value), autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPress, style: Object.assign({}, styles.input) }), jsxRuntime.jsx(InputButtons, { onOk: () => {
574
+ }, children: jsxRuntime.jsx(Icon, { name: "add" }) })), isAdding && handleAdd && type === 'object' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { className: "jer-input-new-key", type: "text", name: "new-object-key", value: newKey, onChange: (e) => setNewKey(e.target.value), autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPress, style: Object.assign({}, styles.input) }), jsxRuntime.jsx(InputButtons, { onOk: () => {
507
575
  if (!!newKey) {
508
576
  setIsAdding(false);
509
577
  handleAdd(newKey);
510
578
  }
511
579
  }, onCancel: () => {
512
580
  setIsAdding(false);
513
- } })] }))] })));
581
+ } })] }))] }));
514
582
  };
515
583
  const InputButtons = ({ onOk, onCancel }) => {
516
- return (jsxRuntime.jsxs("div", Object.assign({ className: "jer-confirm-buttons" }, { children: [jsxRuntime.jsx("div", Object.assign({ onClick: onOk }, { children: jsxRuntime.jsx(Icon, { name: "ok" }) })), jsxRuntime.jsx("div", Object.assign({ onClick: onCancel }, { children: jsxRuntime.jsx(Icon, { name: "cancel" }) }))] })));
584
+ return (jsxRuntime.jsxs("div", { className: "jer-confirm-buttons", children: [jsxRuntime.jsx("div", { onClick: onOk, children: jsxRuntime.jsx(Icon, { name: "ok" }) }), jsxRuntime.jsx("div", { onClick: onCancel, children: jsxRuntime.jsx(Icon, { name: "cancel" }) })] }));
517
585
  };
518
586
  const stringifyPath = (path) => path.reduce((str, part) => {
519
587
  if (typeof part === 'number')
@@ -527,19 +595,43 @@ const ValueDataTypes = ['string', 'number', 'boolean', 'null'];
527
595
  const CollectionDataTypes = ['object', 'array'];
528
596
  const DataTypes = [...ValueDataTypes, ...CollectionDataTypes];
529
597
 
530
- const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard, restrictEditFilter, restrictDeleteFilter, showArrayIndices, stringTruncate, indent, translate, }) => {
598
+ const getCustomNode = (customNodeDefinitions = [], filterProps) => {
599
+ const matchingDefinitions = customNodeDefinitions.filter(({ condition }) => condition(filterProps));
600
+ if (matchingDefinitions.length === 0)
601
+ return {};
602
+ const { element, props, hideKey = false } = matchingDefinitions[0];
603
+ return { CustomNode: element, customNodeProps: props, hideKey };
604
+ };
605
+
606
+ const CustomNodeWrapper = ({ name, hideKey, children, indent, }) => {
607
+ const { styles } = useTheme();
608
+ const indentStyle = indent ? { marginLeft: `${indent / 2}em` } : {};
609
+ return (jsxRuntime.jsx("div", { className: "jer-component jer-value-component", style: indentStyle, children: jsxRuntime.jsxs("div", { className: "jer-value-main-row", style: {
610
+ flexWrap: name.length > 10 ? 'wrap' : 'nowrap',
611
+ }, children: [!hideKey && (jsxRuntime.jsxs("label", { htmlFor: name, 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.jsx("div", { className: "jer-value-and-buttons", style: { paddingLeft: hideKey ? 0 : undefined }, children: children })] }) }));
612
+ };
613
+
614
+ const ValueNodeWrapper = (props) => {
615
+ const { data, parentData, name, path, onEdit, onDelete, enableClipboard, restrictEditFilter, restrictDeleteFilter, restrictTypeSelection, showLabel, stringTruncate, indent, translate, customNodeDefinitions, } = props;
531
616
  const { styles } = useTheme();
532
617
  const [isEditing, setIsEditing] = react.useState(false);
533
- const [value, setValue] = react.useState(typeof data === 'function' ? 'INVALID_FUNCTION' : data);
618
+ const [isEditingKey, setIsEditingKey] = react.useState(false);
619
+ const [value, setValue] = react.useState(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
534
620
  const [error, setError] = react.useState(null);
535
621
  const [dataType, setDataType] = react.useState(getDataType(data));
536
622
  react.useEffect(() => {
537
- setValue(typeof data === 'function' ? 'INVALID_FUNCTION' : data);
623
+ setValue(typeof data === 'function' ? INVALID_FUNCTION_STRING : data);
538
624
  setDataType(getDataType(data));
539
625
  }, [data, error]);
540
626
  const handleChangeDataType = (type) => {
541
- setValue(convertValue(value, type));
542
- setDataType(type);
627
+ const customNode = customNodeDefinitions.find((customNode) => customNode.name === type);
628
+ if (customNode) {
629
+ onEdit(customNode.defaultValue, path);
630
+ }
631
+ else {
632
+ setValue(convertValue(value, type));
633
+ setDataType(type);
634
+ }
543
635
  };
544
636
  const logError = (errorString) => {
545
637
  setError(errorString);
@@ -551,10 +643,10 @@ const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard,
551
643
  let newValue;
552
644
  switch (dataType) {
553
645
  case 'object':
554
- newValue = {};
646
+ newValue = { [translate('DEFAULT_NEW_KEY')]: value };
555
647
  break;
556
648
  case 'array':
557
- newValue = value !== null ? [value] : [];
649
+ newValue = value !== null ? value : [];
558
650
  break;
559
651
  case 'number':
560
652
  const n = Number(value);
@@ -571,9 +663,27 @@ const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard,
571
663
  logError(error);
572
664
  });
573
665
  };
666
+ const handleEditKey = (newKey) => {
667
+ setIsEditingKey(false);
668
+ if (!parentData)
669
+ return;
670
+ const parentPath = path.slice(0, -1);
671
+ if (!newKey)
672
+ return;
673
+ const newData = Object.fromEntries(Object.entries(parentData).map(([key, val]) => (key === name ? [newKey, val] : [key, val])));
674
+ onEdit(newData, parentPath);
675
+ };
676
+ const handleKeyPress = (e) => {
677
+ if (e.key === 'Enter')
678
+ handleEditKey(e.target.value);
679
+ else if (e.key === 'Escape')
680
+ handleCancel();
681
+ };
574
682
  const handleCancel = () => {
575
683
  setIsEditing(false);
684
+ setIsEditingKey(false);
576
685
  setValue(data);
686
+ setDataType(getDataType(data));
577
687
  };
578
688
  const handleDelete = () => {
579
689
  onDelete(value, path).then((error) => {
@@ -584,20 +694,47 @@ const ValueNodeWrapper = ({ data, name, path, onEdit, onDelete, enableClipboard,
584
694
  const filterProps = { key: name, path, level: path.length, value: data, size: null };
585
695
  const canEdit = react.useMemo(() => !restrictEditFilter(filterProps), [filterProps]);
586
696
  const canDelete = react.useMemo(() => !restrictDeleteFilter(filterProps), [filterProps]);
697
+ const isArray = typeof path.slice(-1)[0] === 'number';
698
+ const canEditKey = !isArray && canEdit && canDelete;
587
699
  const inputProps = {
588
700
  value,
701
+ parentData,
589
702
  setValue,
590
703
  isEditing,
591
- setIsEditing,
704
+ setIsEditing: canEdit ? () => setIsEditing(true) : () => { },
592
705
  handleEdit,
593
706
  handleCancel,
594
707
  path,
595
708
  stringTruncate,
709
+ translate,
596
710
  };
597
- 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: {
711
+ const { CustomNode, customNodeProps, hideKey } = getCustomNode(customNodeDefinitions, {
712
+ key: name,
713
+ path,
714
+ level: path.length,
715
+ value: data,
716
+ size: 0,
717
+ });
718
+ const allDataTypes = [
719
+ ...customNodeDefinitions
720
+ .filter(({ showInTypesSelector = false }) => showInTypesSelector)
721
+ .map(({ name }) => name),
722
+ ...DataTypes,
723
+ ];
724
+ const allowedDataTypes = react.useMemo(() => {
725
+ if (typeof restrictTypeSelection === 'boolean')
726
+ return restrictTypeSelection ? [] : allDataTypes;
727
+ if (Array.isArray(restrictTypeSelection))
728
+ return restrictTypeSelection;
729
+ const result = restrictTypeSelection(filterProps);
730
+ if (typeof result === 'boolean')
731
+ return result ? [] : allDataTypes;
732
+ return result;
733
+ }, [filterProps, restrictTypeSelection]);
734
+ return CustomNode ? (jsxRuntime.jsx(CustomNodeWrapper, { name: name, hideKey: hideKey, indent: indent, children: jsxRuntime.jsx(CustomNode, Object.assign({ customProps: customNodeProps }, props)) })) : (jsxRuntime.jsx("div", { className: "jer-component jer-value-component", style: { marginLeft: `${indent / 2}em` }, children: jsxRuntime.jsxs("div", { className: "jer-value-main-row", style: {
598
735
  flexWrap: name.length > 10 ? 'wrap' : 'nowrap',
599
- } }, { 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' &&
600
- !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 })))] }))] })) })));
736
+ }, children: [showLabel && !isEditingKey && (jsxRuntime.jsxs("label", { 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 }), onDoubleClick: () => canEditKey && setIsEditingKey(true), children: [name, ":", ' '] })), showLabel && isEditingKey && (jsxRuntime.jsx("input", { className: "jer-object-key", type: "text", name: path.join('.'), defaultValue: name, autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPress, style: { width: `${String(name).length / 1.5 + 0.5}em` } })), jsxRuntime.jsxs("div", { className: "jer-value-and-buttons", children: [jsxRuntime.jsx("div", { className: "jer-input-component", children: getInputComponent(dataType, inputProps) }), isEditing ? (jsxRuntime.jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel })) : (dataType !== 'invalid' &&
737
+ !error && (jsxRuntime.jsx(EditButtons, { startEdit: canEdit ? () => setIsEditing(true) : undefined, handleDelete: canDelete ? handleDelete : undefined, data: data, enableClipboard: enableClipboard, name: name, path: path, translate: translate }))), isEditing && allowedDataTypes.length > 0 && (jsxRuntime.jsxs("div", { className: "jer-select", children: [jsxRuntime.jsx("select", { name: `${name}-type-select`, className: "jer-type-select", onChange: (e) => handleChangeDataType(e.target.value), value: dataType, children: allowedDataTypes.map((type) => (jsxRuntime.jsx("option", { value: type, children: type }, type))) }), jsxRuntime.jsx("span", { className: "focus" })] })), !isEditing && error && (jsxRuntime.jsx("span", { className: "jer-error-slug", style: styles.error, children: error }))] })] }) }));
601
738
  };
602
739
  const getDataType = (value) => {
603
740
  if (typeof value === 'string')
@@ -622,7 +759,7 @@ const getInputComponent = (dataType, inputProps) => {
622
759
  case 'null':
623
760
  return jsxRuntime.jsx(NullValue, Object.assign({}, inputProps));
624
761
  case 'object':
625
- return jsxRuntime.jsx(ObjectValue, Object.assign({}, inputProps));
762
+ return jsxRuntime.jsx(ObjectValue, Object.assign({}, inputProps, { value: value }));
626
763
  case 'array':
627
764
  return jsxRuntime.jsx(ArrayValue, Object.assign({}, inputProps));
628
765
  default:
@@ -641,7 +778,7 @@ const convertValue = (value, type) => {
641
778
  case 'null':
642
779
  return null;
643
780
  case 'object':
644
- return {};
781
+ return value;
645
782
  case 'array':
646
783
  return [value];
647
784
  default:
@@ -651,15 +788,19 @@ const convertValue = (value, type) => {
651
788
 
652
789
  const isCollection = (value) => value !== null && typeof value == 'object';
653
790
  const CollectionNode = (_a) => {
654
- var { data, path, name } = _a, props = __rest(_a, ["data", "path", "name"]);
791
+ var { data, path, name, parentData, showCollectionCount } = _a, props = __rest(_a, ["data", "path", "name", "parentData", "showCollectionCount"]);
655
792
  const { styles } = useTheme();
656
- const { onEdit, onAdd, onDelete, restrictEditFilter, restrictDeleteFilter, restrictAddFilter, collapseFilter, enableClipboard, indent, keySort, showArrayIndices, defaultValue, translate, } = props;
793
+ const { onEdit, onAdd, onDelete, restrictEditFilter, restrictDeleteFilter, restrictAddFilter, collapseFilter, enableClipboard, indent, keySort, showArrayIndices, defaultValue, translate, customNodeDefinitions, } = props;
657
794
  const [isEditing, setIsEditing] = react.useState(false);
795
+ const [isEditingKey, setIsEditingKey] = react.useState(false);
658
796
  const [stringifiedValue, setStringifiedValue] = react.useState(JSON.stringify(data, null, 2));
659
797
  const [error, setError] = react.useState(null);
660
798
  const collectionSize = Object.keys(data).length;
661
799
  const filterProps = { key: name, path, level: path.length, value: data, size: collectionSize };
662
- const [collapsed, setCollapsed] = react.useState(collapseFilter(filterProps));
800
+ const startCollapsed = collapseFilter(filterProps);
801
+ const [collapsed, setCollapsed] = react.useState(startCollapsed);
802
+ const hasBeenOpened = react.useRef(!startCollapsed);
803
+ const [isAnimating, setIsAnimating] = react.useState(false);
663
804
  react.useEffect(() => {
664
805
  setStringifiedValue(JSON.stringify(data, null, 2));
665
806
  }, [data]);
@@ -675,6 +816,14 @@ const CollectionNode = (_a) => {
675
816
  else if (e.key === 'Escape')
676
817
  handleCancel();
677
818
  };
819
+ const handleCollapse = () => {
820
+ if (!isEditing) {
821
+ setIsAnimating(true);
822
+ hasBeenOpened.current = true;
823
+ setCollapsed(!collapsed);
824
+ setTimeout(() => setIsAnimating(false), 500);
825
+ }
826
+ };
678
827
  const showError = (errorString) => {
679
828
  setError(errorString);
680
829
  setTimeout(() => setError(null), ERROR_DISPLAY_TIME);
@@ -697,6 +846,22 @@ const CollectionNode = (_a) => {
697
846
  return;
698
847
  }
699
848
  };
849
+ const handleEditKey = (newKey) => {
850
+ setIsEditingKey(false);
851
+ if (!parentData)
852
+ return;
853
+ const parentPath = path.slice(0, -1);
854
+ if (!newKey)
855
+ return;
856
+ const newData = Object.fromEntries(Object.entries(parentData).map(([key, val]) => (key === name ? [newKey, val] : [key, val])));
857
+ onEdit(newData, parentPath);
858
+ };
859
+ const handleKeyPressKeyEdit = (e) => {
860
+ if (e.key === 'Enter')
861
+ handleEditKey(e.target.value);
862
+ else if (e.key === 'Escape')
863
+ handleCancel();
864
+ };
700
865
  const handleAdd = (key) => {
701
866
  setCollapsed(false);
702
867
  if (collectionType === 'array') {
@@ -731,7 +896,10 @@ const CollectionNode = (_a) => {
731
896
  const canEdit = react.useMemo(() => !restrictEditFilter(filterProps), [filterProps]);
732
897
  const canDelete = react.useMemo(() => !restrictDeleteFilter(filterProps), [filterProps]);
733
898
  const canAdd = react.useMemo(() => !restrictAddFilter(filterProps), [filterProps]);
734
- const showLabel = showArrayIndices || !(typeof path.slice(-1)[0] === 'number');
899
+ const canEditKey = parentData !== null && canEdit && canAdd && canDelete;
900
+ const isArray = typeof path.slice(-1)[0] === 'number';
901
+ const showLabel = showArrayIndices || !isArray;
902
+ const showCount = showCollectionCount === 'when-closed' ? collapsed : showCollectionCount;
735
903
  const keyValueArray = Object.entries(data).map(([key, value]) => [
736
904
  collectionType === 'array' ? Number(key) : key,
737
905
  value,
@@ -739,21 +907,27 @@ const CollectionNode = (_a) => {
739
907
  if (keySort && collectionType === 'object')
740
908
  keyValueArray.sort(typeof keySort === 'function' ? (a, b) => keySort(a[0], b[0]) : undefined);
741
909
  const numOfLines = JSON.stringify(data, null, 2).split('\n').length;
742
- 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: () => {
743
- if (!isEditing)
744
- setCollapsed(!collapsed);
745
- } }, { 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
746
- ? translate('ITEM_SINGLE', 1)
747
- : 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
748
- ? () => {
749
- setIsEditing(true);
750
- setCollapsed(false);
751
- }
752
- : 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: {
753
- maxHeight: collapsed ? 0 : !isEditing ? `${numOfLines * 4}em` : undefined,
754
- overflowY: collapsed ? 'hidden' : 'visible',
755
- transition: `max-height ${transitionTime}`,
756
- } }, { 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: 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 }))) }))] })), !collapsed && !isEditing && (jsxRuntime.jsx("div", Object.assign({ className: "jer-brackets", style: styles.bracket }, { children: brackets.close })))] })));
910
+ const { CustomNode, customNodeProps, hideKey } = getCustomNode(customNodeDefinitions, {
911
+ key: name,
912
+ path,
913
+ level: path.length,
914
+ value: data,
915
+ size: Object.keys(data).length,
916
+ });
917
+ return (jsxRuntime.jsx("div", { className: "jer-component fb-collection-component", style: { marginLeft: `${path.length === 0 ? 0 : indent / 2}em` }, children: CustomNode ? (jsxRuntime.jsx(CustomNodeWrapper, { name: name, hideKey: hideKey, children: jsxRuntime.jsx(CustomNode, Object.assign({ data: data, path: path, name: name, parentData: parentData, customProps: customNodeProps }, props)) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "jer-collection-header-row", children: [jsxRuntime.jsx("div", { onClick: handleCollapse, children: jsxRuntime.jsx(Icon, { name: "chevron", rotate: collapsed }) }), jsxRuntime.jsxs("div", { className: "jer-collection-name", children: [!isEditingKey && (jsxRuntime.jsx("span", { style: styles.property, onDoubleClick: () => canEditKey && setIsEditingKey(true), children: showLabel && name !== '' && name !== undefined ? `${name}:` : null })), isEditingKey && (jsxRuntime.jsx("input", { className: "jer-collection-name", type: "text", name: path.join('.'), defaultValue: name, autoFocus: true, onFocus: (e) => e.target.select(), onKeyDown: handleKeyPressKeyEdit, style: { width: `${String(name).length / 1.5 + 0.5}em` } })), !isEditing && (jsxRuntime.jsx("span", { className: "jer-brackets", style: styles.bracket, children: brackets.open }))] }), !isEditing && showCollectionCount && (jsxRuntime.jsx("div", { className: `jer-collection-item-count${showCount ? ' jer-visible' : ' jer-hidden'}`, style: styles.itemCount, children: collectionSize === 1
918
+ ? translate('ITEM_SINGLE', 1)
919
+ : translate('ITEMS_MULTIPLE', collectionSize) })), jsxRuntime.jsx("div", { className: `jer-brackets${collapsed ? ' jer-visible' : ' jer-hidden'}`, style: styles.bracket, children: brackets.close }), !isEditing && (jsxRuntime.jsx(EditButtons, { startEdit: canEdit
920
+ ? () => {
921
+ setIsEditing(true);
922
+ setCollapsed(false);
923
+ }
924
+ : undefined, handleAdd: canAdd ? handleAdd : undefined, handleDelete: canDelete ? handleDelete : undefined, enableClipboard: enableClipboard, type: collectionType, data: data, name: name, path: path, translate: translate }))] }), jsxRuntime.jsxs("div", { className: 'jer-collection-inner', style: {
925
+ maxHeight: collapsed ? 0 : !isEditing ? `${numOfLines * 3}em` : undefined,
926
+ overflowY: collapsed || isAnimating ? 'hidden' : 'visible',
927
+ transition: `max-height ${transitionTime}`,
928
+ }, children: [isEditing ? (jsxRuntime.jsx("div", { 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", { className: "jer-collection-input-button-row", children: jsxRuntime.jsx(InputButtons, { onOk: handleEdit, onCancel: handleCancel, isCollection: true }) })] }) })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !hasBeenOpened.current
929
+ ? null
930
+ : keyValueArray.map(([key, value]) => (jsxRuntime.jsx("div", { className: "jer-collection-element", children: isCollection(value) ? (jsxRuntime.jsx(CollectionNode, Object.assign({ data: value, parentData: data, path: [...path, key], name: key, showCollectionCount: showCollectionCount }, props), key)) : (jsxRuntime.jsx(ValueNodeWrapper, Object.assign({ data: value, parentData: data, path: [...path, key], name: key }, props, { showLabel: collectionType === 'object' ? true : showArrayIndices }), key)) }, key))) })), jsxRuntime.jsx("div", { className: isEditing ? 'jer-collection-error-row' : 'jer-collection-error-row-edit', children: error && (jsxRuntime.jsx("span", { className: "jer-error-slug", style: styles.error, children: error })) }), jsxRuntime.jsx("div", { className: "jer-brackets", style: styles.bracket, children: brackets.close })] })] })) }));
757
931
  };
758
932
 
759
933
  const localisedStrings = {
@@ -765,6 +939,8 @@ const localisedStrings = {
765
939
  ERROR_UPDATE: 'Update unsuccessful',
766
940
  ERROR_DELETE: 'Delete unsuccessful',
767
941
  ERROR_ADD: 'Adding node unsuccessful',
942
+ DEFAULT_STRING: 'New data!',
943
+ DEFAULT_NEW_KEY: 'key',
768
944
  };
769
945
  const translate = (translations, key, count) => {
770
946
  const string = key in translations ? translations[key] : localisedStrings[key];
@@ -772,7 +948,7 @@ const translate = (translations, key, count) => {
772
948
  };
773
949
  const getTranslateFunction = (translations) => (key, count) => translate(translations, key, count);
774
950
 
775
- 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 = 600, stringTruncate = 250, translations = {}, className, }) => {
951
+ 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, showCollectionCount = true, restrictEdit = false, restrictDelete = false, restrictAdd = false, restrictTypeSelection = false, keySort = false, showArrayIndices = true, defaultValue = null, minWidth = 250, maxWidth = 'min(600px, 90vw)', stringTruncate = 250, translations = {}, className, customNodeDefinitions = [], }) => {
776
952
  const [data, setData] = react.useState(srcData);
777
953
  const { styles, setTheme, setIcons } = useTheme();
778
954
  const collapseFilter = react.useCallback(getFilterFunction(collapse), [collapse]);
@@ -854,10 +1030,12 @@ const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit =
854
1030
  onEdit,
855
1031
  onDelete,
856
1032
  onAdd,
1033
+ showCollectionCount,
857
1034
  collapseFilter,
858
1035
  restrictEditFilter,
859
1036
  restrictDeleteFilter,
860
1037
  restrictAddFilter,
1038
+ restrictTypeSelection,
861
1039
  enableClipboard,
862
1040
  keySort,
863
1041
  showArrayIndices,
@@ -865,10 +1043,12 @@ const Editor = ({ data: srcData, rootName = 'root', onUpdate, onEdit: srcEdit =
865
1043
  defaultValue,
866
1044
  stringTruncate,
867
1045
  translate,
1046
+ customNodeDefinitions,
1047
+ parentData: null,
868
1048
  };
869
1049
  if (!styles)
870
1050
  return null;
871
- return (jsxRuntime.jsx("div", Object.assign({ className: 'jer-editor-container ' + className, style: Object.assign(Object.assign({}, styles.container), { minWidth, maxWidth }) }, { children: isCollection(data) && jsxRuntime.jsx(CollectionNode, Object.assign({ data: data, path: [] }, otherProps)) })));
1051
+ return (jsxRuntime.jsx("div", { className: 'jer-editor-container ' + className, style: Object.assign(Object.assign({}, styles.container), { minWidth, maxWidth }), children: isCollection(data) ? (jsxRuntime.jsx(CollectionNode, Object.assign({ data: data, path: [] }, otherProps))) : (jsxRuntime.jsx(ValueNodeWrapper, Object.assign({ data: data, path: [], showLabel: true }, otherProps))) }));
872
1052
  };
873
1053
  const JsonEditor = (props) => (jsxRuntime.jsx(ThemeProvider, { children: jsxRuntime.jsx(Editor, Object.assign({}, props)) }));
874
1054
  const updateDataObject = (data, path, newValue, action) => {
@@ -898,5 +1078,4 @@ const getFilterFunction = (propValue) => {
898
1078
  };
899
1079
 
900
1080
  exports.JsonEditor = JsonEditor;
901
- exports.default = JsonEditor;
902
1081
  exports.themes = themes;