diff --git a/README.md b/README.md index 37cc619..b1ec74c 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ This is a reference list of *all* possible props, divided into related sections. | ----------------------- | ----------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `theme` | `ThemeInput` | `defaultTheme` | Either one of the built-in themes (imported separately), or an object specifying some or all theme properties — see [Themes](#themes--styles). | | `icons` | `{[iconName]: JSX.Element, ... }` | `{ }` | Replace the built-in icons by specifying them here — see [Themes](#themes--styles). | | +| `showIconTooltips` | `boolean` | false | Display icon tooltips when hovering. | | | `indent` | `number` | `3` | Specify the amount of indentation for each level of nesting in the displayed data. | | `collapse` | `boolean\|number\|FilterFunction` | `false` | Defines which nodes of the JSON tree will be displayed "opened" in the UI on load — see [Collapse](#collapse). | | `collapseAnimationTime` | `number` | `300` | Time (in milliseconds) for the transition animation when collapsing collection nodes. | @@ -914,6 +915,11 @@ Localise your implementation (or just customise the default messages) by passing DEFAULT_NEW_KEY: 'key', SHOW_LESS: '(Show less)', EMPTY_STRING: '' // Displayed when property key is "" + // Tooltips only appear if `showIconTooltips` prop is enabled + TOOLTIP_COPY: 'Copy to clipboard', + TOOLTIP_EDIT: 'Edit', + TOOLTIP_DELETE: 'Delete', + TOOLTIP_ADD: 'Add', } ``` @@ -1115,11 +1121,14 @@ The `onEditEvent` callback is executed whenever the user starts or stops editing ```ts type OnEditEventFunction = - (path: CollectionKey[] | null, isKey: boolean) => void + (path: (CollectionKey | null)[] | null, isKey: boolean) => void ``` The `path` will be an array representing the path components when starting to edit, and `null` when ending the edit. The `isKey` indicates whether the edit is for the property `key` rather than `value`. +> [!NOTE] +> After clicking the "Add key" button, the `path` in the `onEditEvent` callback will end with a `null` value, indicating that the final path where this key will end up is not yet known. + The `onCollapse` callback is executed when user opens or collapses a node, and has the following signature: ```ts @@ -1229,6 +1238,9 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s ## Changelog +- **1.28.0**: + - (Optional) tooltips for icons ([#211](https://github.com/CarlosNZ/json-edit-react/pull/211)) + - Call `onEditEvent` when starting/stopping editing of a *new* key ([#208](https://github.com/CarlosNZ/json-edit-react/issues/208)) - **1.27.2**: - Bug fix for ":" not rendering when key is `0` - Slightly better detection of data type when copying value to clipboard text diff --git a/custom-component-library/README.md b/custom-component-library/README.md index ae83076..73e5c7a 100644 --- a/custom-component-library/README.md +++ b/custom-component-library/README.md @@ -30,7 +30,8 @@ These are the ones currently available: - [x] `BigInt` - [x] Markdown - [x] "Enhanced" link -- [ ] Image (to-do) +- [x] Image +- [ ] Colour picker (to-do) ## Development @@ -59,7 +60,7 @@ Custom components should consider the following: - `Tab`/`Shift-Tab` to navigate - `Enter` to submit - `Escape` to cancel -- Provide customisation options, particularly styles +- Provide customisation options, particularly styles (but make sure to specify defaults) - If the data contains non-JSON types, add a "stringify" and "reviver" function definition (see `BigInt`, `NaN` and `Symbol` components) If your custom component is "string-like", there are two helper components exported with the package: `StringDisplay` and `StringEdit` -- these are the same components used for the actual "string" elements in the main package. See the [Hyperlink](https://github.com/CarlosNZ/json-edit-react/blob/main/custom-component-library/components/Hyperlink/component.tsx) and [BigInt](https://github.com/CarlosNZ/json-edit-react/blob/main/custom-component-library/components/BigInt/component.tsx) components for examples of how to use them. diff --git a/custom-component-library/components/Image/component.tsx b/custom-component-library/components/Image/component.tsx new file mode 100644 index 0000000..fdabe32 --- /dev/null +++ b/custom-component-library/components/Image/component.tsx @@ -0,0 +1,24 @@ +/** + * An Image display Custom Component + */ + +import React from 'react' +import { type CustomNodeProps } from '@json-edit-react' + +export interface ImageProps { + imageStyles?: React.CSSProperties + altText?: string +} + +export const ImageComponent: React.FC> = (props) => { + const { value, customNodeProps = {} } = props + + const { imageStyles = { maxWidth: 200, maxHeight: 200 }, altText = value as string } = + customNodeProps + + return ( + + {altText} + + ) +} diff --git a/custom-component-library/components/Image/definition.ts b/custom-component-library/components/Image/definition.ts new file mode 100644 index 0000000..1c1903e --- /dev/null +++ b/custom-component-library/components/Image/definition.ts @@ -0,0 +1,13 @@ +import { type CustomNodeDefinition } from '@json-edit-react' +import { ImageComponent, ImageProps } from './component' + +const imageLinkRegex = /^https?:\/\/[^\s]+?\.(?:jpe?g|png|svg|gif)/i + +export const ImageNodeDefinition: CustomNodeDefinition = { + condition: ({ value }) => typeof value === 'string' && imageLinkRegex.test(value), + element: ImageComponent, + // customNodeProps: {}, + showOnView: true, + showOnEdit: false, + name: 'Image', +} diff --git a/custom-component-library/components/Image/index.ts b/custom-component-library/components/Image/index.ts new file mode 100644 index 0000000..75c618f --- /dev/null +++ b/custom-component-library/components/Image/index.ts @@ -0,0 +1 @@ +export * from './definition' diff --git a/custom-component-library/components/index.ts b/custom-component-library/components/index.ts index e1933a4..43f1381 100644 --- a/custom-component-library/components/index.ts +++ b/custom-component-library/components/index.ts @@ -8,3 +8,4 @@ export * from './NaN' export * from './Symbol' export * from './BigInt' export * from './Markdown' +export * from './Image' diff --git a/custom-component-library/package.json b/custom-component-library/package.json index e6dd388..0940157 100644 --- a/custom-component-library/package.json +++ b/custom-component-library/package.json @@ -12,7 +12,7 @@ "preview": "vite preview" }, "dependencies": { - "json-edit-react": "1.27.1", + "json-edit-react": "^1.27.2", "react": "^19.0.0", "react-datepicker": "^7.5.0", "react-dom": "^19.0.0", diff --git a/custom-component-library/src/App.tsx b/custom-component-library/src/App.tsx index fd85bc0..6159ed2 100644 --- a/custom-component-library/src/App.tsx +++ b/custom-component-library/src/App.tsx @@ -13,9 +13,10 @@ import { BigIntDefinition, MarkdownNodeDefinition, EnhancedLinkCustomNodeDefinition, + ImageNodeDefinition, } from '../components' import { testData } from './data' -import { JsonData, JsonEditor } from '@json-edit-react' +import { JsonEditor } from '@json-edit-react' if (testData?.['Date & Time']) { // @ts-expect-error redefine after initialisation @@ -33,25 +34,32 @@ if (testData?.['Date & Time']) { type TestData = typeof testData function App() { - const [data, setData] = useState(testData) + const [data, setData] = useState(testData) console.log('Current data', data) + // Properties that are conditional on some data property: + + // Display the time depending on whether or not the "Show time" toggle is + // checked + const showTime = data?.['Date & Time']?.['Show Time in Date?'] ?? false + + // Image sizing + const maxWidth = data?.Images?.['Image properties']?.maxWidth + const maxHeight = data?.Images?.['Image properties']?.maxHeight + return (
void} customNodeDefinitions={[ + { ...ImageNodeDefinition, customNodeProps: { imageStyles: { maxWidth, maxHeight } } }, LinkCustomNodeDefinition, { ...(STORE_DATE_AS_DATE_OBJECT ? DateObjectDefinition : DatePickerDefinition), - customNodeProps: { - // Display the time depending on whether or not the "Show time" - // toggle is checked - showTime: (data as TestData)?.['Date & Time']?.['Show Time in Date?'] ?? false, - }, + customNodeProps: { showTime }, }, EnhancedLinkCustomNodeDefinition, UndefinedDefinition, diff --git a/custom-component-library/src/data.ts b/custom-component-library/src/data.ts index 6531176..4dcca9b 100644 --- a/custom-component-library/src/data.ts +++ b/custom-component-library/src/data.ts @@ -19,6 +19,7 @@ export const testData = { - BooleanToggle - NaN - Symbol + - Image Click [here](https://github.com/CarlosNZ/json-edit-react/blob/main/custom-component-library/README.md) for more info `, @@ -40,7 +41,7 @@ export const testData = { }, 'Non-JSON types': { - undefined: undefined, + Undefined: undefined, 'Not a Number': NaN, Symbol1: Symbol('First one'), Symbol2: Symbol('Second one'), @@ -48,4 +49,13 @@ export const testData = { }, Markdown: 'Uses [react-markdown](https://www.npmjs.com/package/react-markdown) to render **Markdown** *text content*. ', + Images: { + JPG: 'https://film-grab.com/wp-content/uploads/2014/07/51.jpg', + PNG: 'https://github.com/CarlosNZ/json-edit-react/blob/main/image/logo192.png?raw=true', + GIF: 'https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExdnV0aHB0c2xiMHFmdGY3Z2NkenBkb3Rmd3hvdTlkaTlkNGYxOXFtOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/9E7kUhnT9eDok/giphy.gif', + 'Image properties': { + maxWidth: 200, + maxHeight: 100, + }, + }, } diff --git a/custom-component-library/yarn.lock b/custom-component-library/yarn.lock index a33c5e4..f5e533e 100644 --- a/custom-component-library/yarn.lock +++ b/custom-component-library/yarn.lock @@ -1439,10 +1439,10 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-edit-react@1.27.1: - version "1.27.1" - resolved "https://registry.yarnpkg.com/json-edit-react/-/json-edit-react-1.27.1.tgz#9fdd4feddca1a28c0c52a77d6741555b5a29c7d0" - integrity sha512-466o3bMUUOORicRHX4LSMZxdshTn2ezcGLuvcIThYimlNVKO5tkJ2Apc/H5cAdqvJHCE89vaMeRDEh9eMXZV6g== +json-edit-react@^1.27.2: + version "1.27.2" + resolved "https://registry.yarnpkg.com/json-edit-react/-/json-edit-react-1.27.2.tgz#3851e931eb61e4f90fbf771f01f40f9cf32236c8" + integrity sha512-UOtgBY65LAyoYdMxGhaAwjRmDAu9BRxeD8OFrul8iz2fZmQC46CjLkByPzB+egizztWvMvXzFY5+Ss9ejRDWUw== dependencies: object-property-assigner "^1.3.5" object-property-extractor "^1.0.13" diff --git a/demo/package.json b/demo/package.json index 91fab85..2a06774 100644 --- a/demo/package.json +++ b/demo/package.json @@ -33,7 +33,7 @@ "ajv": "^8.16.0", "firebase": "^10.13.0", "framer-motion": "^11.0.3", - "json-edit-react": "1.27.1", + "json-edit-react": "^1.27.2", "json5": "^2.2.3", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 0dcadd2..48c460f 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -46,8 +46,9 @@ import { ArrowBackIcon, ArrowForwardIcon, InfoIcon } from '@chakra-ui/icons' import { demoDataDefinitions } from './demoData' import { useDatabase } from './useDatabase' import './style.css' -import { getLineHeight, truncate } from './helpers' +import { getConditionalDefinitions, getLineHeight, truncate } from './helpers' import { Loading } from '../../custom-component-library/components/_common/Loading' +import { testData } from '../../custom-component-library/src/data' const CodeEditor = lazy(() => import('./CodeEditor')) const SourceIndicator = lazy(() => import('./SourceIndicator')) @@ -155,14 +156,11 @@ function App() { // }, []) const customNodeDefinitions = - selectedDataSet === 'customComponentLibrary' && - typeof data === 'object' && - (data as Record>)?.['Date & Time']?.['Show Time in Date?'] && - Array.isArray(dataDefinition.customNodeDefinitions) - ? [ - { ...dataDefinition.customNodeDefinitions[0], customNodeProps: { showTime: true } }, - ...dataDefinition.customNodeDefinitions.slice(1), - ] + selectedDataSet === 'customComponentLibrary' + ? getConditionalDefinitions( + data as typeof testData, + dataDefinition?.customNodeDefinitions ?? [] + ) : dataDefinition.customNodeDefinitions const updateState = (patch: Partial) => setState({ ...state, ...patch }) @@ -588,6 +586,7 @@ function App() { : undefined } // collapseClickZones={['property', 'header']} + // onEditEvent={(...args) => console.log('onEditEvent', ...args)} // onEditEvent={(path) => { // console.log(path) // setIsEditing(path ? true : false) @@ -602,6 +601,7 @@ function App() { // translations={{ // EMPTY_STRING: 'Nah', // }} + showIconTooltips /> diff --git a/demo/src/demoData/dataDefinitions.tsx b/demo/src/demoData/dataDefinitions.tsx index 69f386d..3499047 100644 --- a/demo/src/demoData/dataDefinitions.tsx +++ b/demo/src/demoData/dataDefinitions.tsx @@ -12,6 +12,7 @@ import { BigIntDefinition, MarkdownNodeDefinition, EnhancedLinkCustomNodeDefinition, + ImageNodeDefinition, } from '../../../custom-component-library/components' import { testData } from '../../../custom-component-library/src/data' import { @@ -115,7 +116,7 @@ export const demoDataDefinitions: Record = { if (key === 'enum') return [ ...standardDataTypes, - 'Date', + 'Date (ISO)', { enum: 'Custom Type', values: ['Option A 🍏', 'Option B 🍌', 'Option C 🍒'], @@ -831,7 +832,7 @@ export const demoDataDefinitions: Record = { ), rootName: 'components', - collapse: 2, + collapse: 3, data: testData, customNodeDefinitions: [ // Must keep this one first as we override it by index in App.tsx @@ -839,6 +840,7 @@ export const demoDataDefinitions: Record = { ...DateObjectDefinition, customNodeProps: { showTime: false }, }, + ImageNodeDefinition, LinkCustomNodeDefinition, EnhancedLinkCustomNodeDefinition, UndefinedDefinition, diff --git a/demo/src/helpers.ts b/demo/src/helpers.ts index 4c2ee46..a60ce3c 100644 --- a/demo/src/helpers.ts +++ b/demo/src/helpers.ts @@ -1,6 +1,50 @@ -import { JsonData } from '@json-edit-react' +import { JsonData, type CustomNodeDefinition } from '@json-edit-react' +import { testData } from '../../custom-component-library/src/data' export const truncate = (string: string, length = 200) => string.length < length ? string : `${string.slice(0, length - 2).trim()}...` -export const getLineHeight = (data: JsonData) => JSON.stringify(data, null, 2).split('\n').length +export const getLineHeight = (data: JsonData) => jsonStringify(data).split('\n').length + +// Special JSON.stringify with custom replacer functions for special types +const jsonStringify = (data: JsonData) => + JSON.stringify( + data, + (_, value) => { + if (typeof value === 'bigint') { + return value.toString() + } + if (typeof value === 'symbol') { + return value.toString() + } + return value + }, + 2 + ) + +// For the "CustomNodeLibrary" data, returns modified definitions dependent on +// the data +export const getConditionalDefinitions = ( + data: typeof testData, + customNodeDefinitions: CustomNodeDefinition[] +) => + customNodeDefinitions.map((definition) => { + if (definition?.name === 'Image') + return { + ...definition, + customNodeProps: { + imageStyles: { + maxHeight: data?.Images?.['Image properties']?.maxHeight, + maxWidth: data?.Images?.['Image properties']?.maxWidth, + }, + }, + } + + if (definition?.name === 'Date Object') + return { + ...definition, + customNodeProps: { showTime: data?.['Date & Time']?.['Show Time in Date?'] ?? false }, + } + + return definition + }) diff --git a/demo/yarn.lock b/demo/yarn.lock index 9a60413..998e15e 100644 --- a/demo/yarn.lock +++ b/demo/yarn.lock @@ -2534,10 +2534,10 @@ json-buffer@3.0.1: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== -json-edit-react@1.27.1: - version "1.27.1" - resolved "https://registry.yarnpkg.com/json-edit-react/-/json-edit-react-1.27.1.tgz#9fdd4feddca1a28c0c52a77d6741555b5a29c7d0" - integrity sha512-466o3bMUUOORicRHX4LSMZxdshTn2ezcGLuvcIThYimlNVKO5tkJ2Apc/H5cAdqvJHCE89vaMeRDEh9eMXZV6g== +json-edit-react@^1.27.2: + version "1.27.2" + resolved "https://registry.yarnpkg.com/json-edit-react/-/json-edit-react-1.27.2.tgz#3851e931eb61e4f90fbf771f01f40f9cf32236c8" + integrity sha512-UOtgBY65LAyoYdMxGhaAwjRmDAu9BRxeD8OFrul8iz2fZmQC46CjLkByPzB+egizztWvMvXzFY5+Ss9ejRDWUw== dependencies: object-property-assigner "^1.3.5" object-property-extractor "^1.0.13" diff --git a/package.json b/package.json index c67f645..6c9cbd1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "json-edit-react", - "version": "1.27.2", + "version": "1.28.0", "description": "React component for editing or viewing JSON/object data", "main": "build/index.cjs.js", "module": "build/index.esm.js", diff --git a/src/ButtonPanels.tsx b/src/ButtonPanels.tsx index 98e2c8f..48916ce 100644 --- a/src/ButtonPanels.tsx +++ b/src/ButtonPanels.tsx @@ -12,6 +12,7 @@ import { type CustomButtonDefinition, type KeyboardControlsFull, JsonData, + OnEditEventFunction, } from './types' import { getModifier } from './helpers' @@ -36,6 +37,8 @@ interface EditButtonProps { // eslint-disable-next-line replacer?: (this: any, key: string, value: unknown) => string ) => string + onEditEvent?: OnEditEventFunction + showIconTooltips: boolean } export const EditButtons: React.FC = ({ @@ -52,6 +55,8 @@ export const EditButtons: React.FC = ({ editConfirmRef, getNewKeyOptions, jsonStringify, + onEditEvent, + showIconTooltips, }) => { const { getStyles } = useTheme() const NEW_KEY_PROMPT = translate('KEY_NEW', nodeData) @@ -69,6 +74,12 @@ export const EditButtons: React.FC = ({ const hasKeyOptionsList = Array.isArray(addingKeyState) const updateAddingState = (active: boolean) => { + // Add 'null' to the path to indicate that the actual path of where the new + // key will go is not yet known. + // Also, "active" matches the second "isKey" parameter here, even though it + // describes a different thing. + if (onEditEvent) onEditEvent(active ? [...path, null] : null, active) + if (!active) { setAddingKeyState(false) return @@ -160,17 +171,27 @@ export const EditButtons: React.FC = ({ onClick={(e) => e.stopPropagation()} > {enableClipboard && ( -
+
)} {startEdit && ( -
+
)} {handleDelete && ( -
+
)} @@ -181,6 +202,7 @@ export const EditButtons: React.FC = ({ // For arrays, we don't need to add a key else handleAdd('') }} + title={showIconTooltips ? translate('TOOLTIP_ADD', nodeData) : ''} >
diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 02b01cb..3083a0d 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -47,6 +47,8 @@ export const CollectionNode: React.FC = (props) => { collapseAnimationTime, onMove, enableClipboard, + onEditEvent, + showIconTooltips, searchFilter, searchText, indent, @@ -432,6 +434,8 @@ export const CollectionNode: React.FC = (props) => { getNewKeyOptions={getNewKeyOptions} editConfirmRef={editConfirmRef} jsonStringify={jsonStringify} + onEditEvent={onEditEvent} + showIconTooltips={showIconTooltips} /> ) diff --git a/src/JsonEditor.tsx b/src/JsonEditor.tsx index 84a10cd..68bd73e 100644 --- a/src/JsonEditor.tsx +++ b/src/JsonEditor.tsx @@ -45,6 +45,7 @@ const Editor: React.FC = ({ onAdd: srcAdd = onUpdate, onChange, onError, + onEditEvent, showErrorMessages = true, enableClipboard = true, indent = 2, @@ -63,6 +64,7 @@ const Editor: React.FC = ({ keySort = false, showArrayIndices = true, showStringQuotes = true, + showIconTooltips = false, defaultValue = null, newKeyOptions, minWidth = 250, @@ -348,6 +350,7 @@ const Editor: React.FC = ({ onAdd, onChange, onError, + onEditEvent, showErrorMessages, onMove, showCollectionCount, @@ -366,6 +369,7 @@ const Editor: React.FC = ({ sort, showArrayIndices, showStringQuotes, + showIconTooltips, indent, defaultValue, newKeyOptions, diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 0926efe..ac6729c 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -49,6 +49,7 @@ export const ValueNodeWrapper: React.FC = (props) => { sort, editConfirmRef, jsonStringify, + showIconTooltips, } = props const { getStyles } = useTheme() const { @@ -388,6 +389,7 @@ export const ValueNodeWrapper: React.FC = (props) => { keyboardControls={keyboardControls} editConfirmRef={editConfirmRef} jsonStringify={jsonStringify} + showIconTooltips={showIconTooltips} /> ) )} diff --git a/src/contexts/TreeStateProvider.tsx b/src/contexts/TreeStateProvider.tsx index efcf2d8..736ce01 100644 --- a/src/contexts/TreeStateProvider.tsx +++ b/src/contexts/TreeStateProvider.tsx @@ -90,7 +90,8 @@ export const TreeStateProvider = ({ children, onEditEvent, onCollapse }: TreeSta cancelOp.current() } setCurrentlyEditingElement(pathString) - if (onEditEvent) onEditEvent(path, newCancelOrKey === 'key') + if (onEditEvent && (Array.isArray(path) || path === null)) + onEditEvent(path, newCancelOrKey === 'key') cancelOp.current = typeof newCancelOrKey === 'function' ? newCancelOrKey : null } diff --git a/src/localisation.ts b/src/localisation.ts index 9dc0c5d..ef21745 100644 --- a/src/localisation.ts +++ b/src/localisation.ts @@ -15,6 +15,10 @@ const localisedStrings = { DEFAULT_NEW_KEY: 'key', SHOW_LESS: '(Show less)', EMPTY_STRING: '', + TOOLTIP_COPY: 'Copy to clipboard', + TOOLTIP_EDIT: 'Edit', + TOOLTIP_DELETE: 'Delete', + TOOLTIP_ADD: 'Add', } export type LocalisedStrings = typeof localisedStrings diff --git a/src/types.ts b/src/types.ts index 27c423a..5ed8fdf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -38,6 +38,7 @@ export interface JsonEditorProps { keySort?: boolean | CompareFunction showArrayIndices?: boolean showStringQuotes?: boolean + showIconTooltips?: boolean defaultValue?: string | number | boolean | null | object | DefaultValueFunction newKeyOptions?: string[] | NewKeyOptionsFunction minWidth?: string | number @@ -177,7 +178,7 @@ export type CompareFunction = ( export type SortFunction = (arr: T[], nodeMap: (input: T) => [string | number, unknown]) => void -export type OnEditEventFunction = (path: CollectionKey[] | string | null, isKey: boolean) => void +export type OnEditEventFunction = (path: (CollectionKey | null)[] | null, isKey: boolean) => void // Definition to externally set Collapse state -- also passed to OnCollapse // function @@ -257,8 +258,10 @@ interface BaseNodeProps { onDelete: InternalUpdateFunction onError?: OnErrorFunction showErrorMessages: boolean + showIconTooltips: boolean onMove: InternalMoveFunction enableClipboard: boolean | CopyFunction + onEditEvent?: OnEditEventFunction restrictEditFilter: FilterFunction restrictDeleteFilter: FilterFunction restrictAddFilter: FilterFunction