From 04e2a58c7e5b23321fc9e62b53dd0669044c7ac1 Mon Sep 17 00:00:00 2001 From: Galen Date: Fri, 18 Jul 2025 11:21:44 -0500 Subject: [PATCH 1/3] chore: add onExpand callback --- examples/src/App.tsx | 359 ++++++++++++++++++++++++----------------- src/ItemRange.tsx | 13 +- src/JSONArrow.tsx | 11 +- src/JSONNestedNode.tsx | 20 ++- src/JSONNode.tsx | 1 + src/index.tsx | 17 ++ src/types.ts | 11 ++ 7 files changed, 267 insertions(+), 165 deletions(-) diff --git a/examples/src/App.tsx b/examples/src/App.tsx index 1a63294..ee96e7e 100644 --- a/examples/src/App.tsx +++ b/examples/src/App.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Map } from "immutable"; -import { JSONTree, KeyPath, areKeyPathsEqual } from "react-json-tree"; -import { ScrollToPath } from "../../src/types"; +import { JSONTree, KeyPath, areKeyPathsEqual, doesNodeContainNode, ScrollToPath } from "react-json-tree"; + const getItemString = (type: string) => ( @@ -31,6 +31,24 @@ const data: Record = { bool: true, date: new Date(), error: new Error(longString), + arrayOfObjects: [Array.from({ length: 1000 }).map(e => ({ + foo: { + bar: "baz", + nested: { + bar: "baz2", + moreNested: { + bar: "baz3", + evenMoreNested: { + veryNested: { + insanelyNested: { + ridiculouslyDeepValue: "Hello", + }, + }, + }, + }, + }, + }, + }))], object: { foo: { bar: "baz", @@ -88,160 +106,203 @@ const data: Record = { const key: KeyPath = []; const hugeArrayKeyPath: ScrollToPath = [101, "array", "hugeArray", "root"]; + const App = () => ( -
-

Basic Example

-
- -
-
- -

Scroll to on render example

-
- { - // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded - return !!areKeyPathsEqual( - keyPath, - hugeArrayKeyPath.slice(keyPath.length * -1), - ); - }} - scrollToPath={hugeArrayKeyPath} - /> -
-
- -

Scroll to on open example

-
- -
-
- -

Hide root node

-
- -
-
- -

Force root node open

-
- -
-
- -

No quotations around string values

-
- -
-
- -

Theming Example

-

- Styles are managed with css variables, override the default values to - customize. -

-
- -
- -

Theming Example - relative position arrows

-

- Styles are managed with css variables, override the default values to - customize. -

-
- -
- -

Style Customization

-
    -
  • - Label changes between uppercase/lowercase based on the expanded state. -
  • -
  • Array keys are styled based on their parity.
  • -
  • - The labels of objects, arrays, and iterables are customized as "// - type". -
  • -
  • See code for details.
  • -
-
- -
-

More Fine Grained Rendering

-

- Pass labelRenderer or valueRenderer. -

-
- (({raw})):} - valueRenderer={(raw) => ( - +
+

Basic Example

+
+ +
+
+ +

Scroll to on render example

+
+ { + // // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded + // return !!areKeyPathsEqual( + // keyPath, + // hugeArrayKeyPath.slice(keyPath.length * -1), + // ); + // }} + scrollToPath={hugeArrayKeyPath} + /> +
+
+ +

Scroll to on open example

+
+ +
+
+ +

Hide root node

+
+ +
+
+ +

Force root node open

+
+ +
+
+ +

No quotations around string values

+
+ +
+
+ +

Theming Example

+

+ Styles are managed with css variables, override the default values to + customize. +

+
+ +
+ +

Theming Example - relative position arrows

+

+ Styles are managed with css variables, override the default values to + customize. +

+
+ +
+ +

Style Customization

+
    +
  • + Label changes between uppercase/lowercase based on the expanded state. +
  • +
  • Array keys are styled based on their parity.
  • +
  • + The labels of objects, arrays, and iterables are customized as "// + type". +
  • +
  • See code for details.
  • +
+
+ +
+

More Fine Grained Rendering

+

+ Pass labelRenderer or valueRenderer. +

+
+ (({raw})):} + valueRenderer={(raw) => ( + 😐 {" "} - {raw as string}{" "} - + {raw as string}{" "} + 😐 - - )} - /> -
-

- Sort object keys with sortObjectKeys prop. -

-
- -
-

Collapsed root node

-
- false} /> -
- -

Collapsed top-level nodes

-
- ({ - name: `item #${i}`, - value: i, - }))} - /> -
+
+ )} + /> +
+

+ Sort object keys with sortObjectKeys prop. +

+
+ +
+

Collapsed root node

+
+ false}/> +
+ +

Collapsed top-level nodes

+
+ ({ + name: `item #${i}`, + value: i, + }))} + /> +
+ +

Shift + click to toggle visualizing all child nodes

+
+ +
+
+
); +function OnExpandExample() { + const [keyPathsToExpand, setKeyPathsToExpand] = React.useState([]) + return
+
+ KeyPaths that will be expanded: {JSON.stringify(keyPathsToExpand)} +
+ + { + for(let i = 0; i < keyPathsToExpand.length; i++) { + if(doesNodeContainNode(keyPathsToExpand[i], keyPath)) { + return true; + } + } + + return level < 1 + }} + data={data} + onExpand={(e, keyPath, expanded) => { + if ((e.ctrlKey || e.shiftKey || e.altKey)) { + if(expanded){ + setKeyPathsToExpand([...keyPathsToExpand.filter(existingKeyPath => !areKeyPathsEqual(existingKeyPath, keyPath)), keyPath]) + }else { + if(keyPathsToExpand.length) { + setKeyPathsToExpand(keyPathsToExpand.filter(k => !areKeyPathsEqual(k, keyPath))) + } + } + + } + }}/> +
; +} + + export default App; diff --git a/src/ItemRange.tsx b/src/ItemRange.tsx index b888364..298734c 100644 --- a/src/ItemRange.tsx +++ b/src/ItemRange.tsx @@ -3,7 +3,7 @@ import JSONArrow from "./JSONArrow.js"; import { CircularCache, CommonInternalProps, - KeyPath, + KeyPath, OnExpandEvent, ScrollToPath, } from "./types.js"; import styles from "./styles/itemRange.module.scss"; @@ -21,7 +21,7 @@ interface Props extends CommonInternalProps { } export default function ItemRange(props: Props) { - const { from, to, renderChildNodes, nodeType, scrollToPath, keyPath } = props; + const { from, to, renderChildNodes, nodeType, scrollToPath, keyPath, onExpand } = props; let initialExpanded = false; if (scrollToPath) { const [index] = scrollToPath; @@ -35,8 +35,13 @@ export default function ItemRange(props: Props) { } const [expanded, setExpanded] = useState(initialExpanded); - const handleClick = useCallback(() => { + const handleClick = useCallback((e: OnExpandEvent) => { setExpanded(!expanded); + + if(onExpand !== undefined) { + onExpand(e, keyPath, expanded) + } + }, [expanded]); return expanded ? ( @@ -48,7 +53,7 @@ export default function ItemRange(props: Props) { {`${from} ... ${to}`} diff --git a/src/JSONArrow.tsx b/src/JSONArrow.tsx index cc95cb0..5d4d49d 100644 --- a/src/JSONArrow.tsx +++ b/src/JSONArrow.tsx @@ -1,31 +1,32 @@ import React, { EventHandler } from "react"; import styles from "./styles/JSONArrow.module.scss"; +import {OnExpandEvent} from "./types.ts"; interface Props { arrowStyle?: "single" | "double"; expanded: boolean; nodeType: string; - onClick: () => void; + onNodeExpand: (e: OnExpandEvent) => void; } export default function JSONArrow({ arrowStyle = "single", expanded, - onClick, + onNodeExpand, }: Props) { return (
{ if (event.key === "Enter" || event.key === " ") { event.preventDefault(); - onClick(); + onNodeExpand(event); } }} - className={`${styles.arrow} ${expanded ? styles.arrowExpanded : ""} ${arrowStyle === "single" ? styles.arrowArrowStyleSingle : styles.arrowArrowStyleDouble}`} + className={`${styles.arrow} ${expanded ? styles.arrowExpanded : ""}`} > {/* @todo let implementer define custom arrow object */} {"\u25B6"} diff --git a/src/JSONNestedNode.tsx b/src/JSONNestedNode.tsx index b79394b..da8271a 100644 --- a/src/JSONNestedNode.tsx +++ b/src/JSONNestedNode.tsx @@ -1,9 +1,9 @@ -import React, { useCallback, useState } from "react"; +import React, {useCallback, useEffect, useState} from "react"; import JSONArrow from "./JSONArrow.js"; import getCollectionEntries from "./getCollectionEntries.js"; import JSONNode from "./JSONNode.js"; import ItemRange from "./ItemRange.js"; -import type { CircularCache, CommonInternalProps } from "./types.js"; +import {CircularCache, CommonInternalProps, KeyPath, OnExpandEvent, ShouldExpandNode} from "./types.js"; import styles from "./styles/JSONNestedNode.module.scss"; import { NodeListItem } from "./components/NodeListItem.tsx"; @@ -116,6 +116,7 @@ export default function JSONNestedNode(props: Props) { nodeTypeIndicator, shouldExpandNodeInitially, scrollToPath, + onExpand } = props; const isRoot = keyPath[0] === "root"; @@ -129,8 +130,13 @@ export default function JSONNestedNode(props: Props) { isCircular ? false : shouldExpandNodeInitially(keyPath, data, level), ); - const handleClick = useCallback(() => { - if (isNodeExpandable) setExpanded(!expanded); + const onNodeExpand = useCallback((e: OnExpandEvent) => { + if (isNodeExpandable) { + if(onExpand){ + onExpand(e, keyPath, !expanded) + } + setExpanded(!expanded); + } }, [isNodeExpandable, expanded]); const renderedChildren = @@ -179,18 +185,18 @@ export default function JSONNestedNode(props: Props) { )} {labelRenderer(...stylingArgs)} - + {renderedItemString} diff --git a/src/JSONNode.tsx b/src/JSONNode.tsx index 8639758..0ffee1f 100644 --- a/src/JSONNode.tsx +++ b/src/JSONNode.tsx @@ -17,6 +17,7 @@ export default function JSONNode({ valueRenderer, isCustomNode, valueWrap, + scrollToPath, ...rest }: Props) { diff --git a/src/index.tsx b/src/index.tsx index 5c3d617..f101c07 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -57,6 +57,7 @@ export function JSONTree({ sortObjectKeys = false, scrollToPath, valueWrap = '"', + onExpand = undefined, }: JSONTreeProps) { return (
); @@ -97,6 +100,19 @@ export const areKeyPathsEqual = (a: KeyPath, b: KeyPath) => { return true; }; +/** + * Returns true if source is a child node of target + * Remember child nodes have a longer key path + */ +export const doesNodeContainNode = (parent: KeyPath, child: KeyPath): boolean => { + for (let i = parent.length - 1; i >= 0; i--) { + if (parent[parent.length - i] !== child[child.length - i]) { + return false; + } + } + return true; +} + export type { Key, KeyPath, @@ -108,4 +124,5 @@ export type { IsCustomNode, SortObjectKeys, CommonExternalProps, + ScrollToPath } from "./types.js"; diff --git a/src/types.ts b/src/types.ts index 20cf9fb..0b2d871 100644 --- a/src/types.ts +++ b/src/types.ts @@ -40,6 +40,13 @@ export type ShouldExpandNodeInitially = ( level: number, ) => boolean; +export type ShouldExpandNode = ( + keyPath: KeyPath, + data: unknown, + level: number, +) => boolean | undefined; + + export type PostprocessValue = (value: unknown) => unknown; export type IsCustomNode = (value: unknown) => boolean; @@ -48,10 +55,13 @@ export type SortObjectKeys = ((a: unknown, b: unknown) => number) | boolean; export type CircularCache = unknown[]; +export type OnExpandEvent = React.MouseEvent | React.KeyboardEvent | React.MouseEvent + export interface CommonExternalProps { keyPath: KeyPath; labelRenderer: LabelRenderer; valueRenderer: ValueRenderer; + // Sets expanded state on initial render, will not update expanded state on subsequent renders to prevent changing nodes user has interacted with already shouldExpandNodeInitially: ShouldExpandNodeInitially; hideRoot: boolean; hideRootExpand: boolean; @@ -62,6 +72,7 @@ export interface CommonExternalProps { sortObjectKeys: SortObjectKeys; valueWrap: string; scrollToPath?: ScrollToPath; + onExpand?: (event: OnExpandEvent, keyPath: KeyPath, expand: boolean) => void } export interface CommonInternalProps extends CommonExternalProps { From 8a37694896b91258744da3e2705a5a0d6c1862ab Mon Sep 17 00:00:00 2001 From: Galen Date: Fri, 18 Jul 2025 11:21:56 -0500 Subject: [PATCH 2/3] chore: lint --- examples/src/App.tsx | 394 +++++++++++++++++++++-------------------- src/ItemRange.tsx | 29 ++- src/JSONArrow.tsx | 2 +- src/JSONNestedNode.tsx | 29 +-- src/index.tsx | 10 +- src/types.ts | 14 +- 6 files changed, 258 insertions(+), 220 deletions(-) diff --git a/examples/src/App.tsx b/examples/src/App.tsx index ee96e7e..23deeda 100644 --- a/examples/src/App.tsx +++ b/examples/src/App.tsx @@ -1,7 +1,12 @@ import React from "react"; import { Map } from "immutable"; -import { JSONTree, KeyPath, areKeyPathsEqual, doesNodeContainNode, ScrollToPath } from "react-json-tree"; - +import { + JSONTree, + KeyPath, + areKeyPathsEqual, + doesNodeContainNode, + ScrollToPath, +} from "react-json-tree"; const getItemString = (type: string) => ( @@ -31,24 +36,26 @@ const data: Record = { bool: true, date: new Date(), error: new Error(longString), - arrayOfObjects: [Array.from({ length: 1000 }).map(e => ({ + arrayOfObjects: [ + Array.from({ length: 1000 }).map((e) => ({ foo: { - bar: "baz", - nested: { - bar: "baz2", - moreNested: { - bar: "baz3", - evenMoreNested: { - veryNested: { - insanelyNested: { - ridiculouslyDeepValue: "Hello", - }, - }, - }, + bar: "baz", + nested: { + bar: "baz2", + moreNested: { + bar: "baz3", + evenMoreNested: { + veryNested: { + insanelyNested: { + ridiculouslyDeepValue: "Hello", + }, }, + }, }, + }, }, - }))], + })), + ], object: { foo: { bar: "baz", @@ -106,203 +113,210 @@ const data: Record = { const key: KeyPath = []; const hugeArrayKeyPath: ScrollToPath = [101, "array", "hugeArray", "root"]; - const App = () => ( -
-

Basic Example

-
- -
-
+
+

Basic Example

+
+ +
+
-

Scroll to on render example

-
- { - // // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded - // return !!areKeyPathsEqual( - // keyPath, - // hugeArrayKeyPath.slice(keyPath.length * -1), - // ); - // }} - scrollToPath={hugeArrayKeyPath} - /> -
-
+

Scroll to on render example

+
+ { + // // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded + // return !!areKeyPathsEqual( + // keyPath, + // hugeArrayKeyPath.slice(keyPath.length * -1), + // ); + // }} + scrollToPath={hugeArrayKeyPath} + /> +
+
-

Scroll to on open example

-
- -
-
+

Scroll to on open example

+
+ +
+
-

Hide root node

-
- -
-
+

Hide root node

+
+ +
+
-

Force root node open

-
- -
-
+

Force root node open

+
+ +
+
-

No quotations around string values

-
- -
-
+

No quotations around string values

+
+ +
+
-

Theming Example

-

- Styles are managed with css variables, override the default values to - customize. -

-
- -
+

Theming Example

+

+ Styles are managed with css variables, override the default values to + customize. +

+
+ +
-

Theming Example - relative position arrows

-

- Styles are managed with css variables, override the default values to - customize. -

-
- -
+

Theming Example - relative position arrows

+

+ Styles are managed with css variables, override the default values to + customize. +

+
+ +
-

Style Customization

-
    -
  • - Label changes between uppercase/lowercase based on the expanded state. -
  • -
  • Array keys are styled based on their parity.
  • -
  • - The labels of objects, arrays, and iterables are customized as "// - type". -
  • -
  • See code for details.
  • -
-
- -
-

More Fine Grained Rendering

-

- Pass labelRenderer or valueRenderer. -

-
- (({raw})):} - valueRenderer={(raw) => ( - +

Style Customization

+
    +
  • + Label changes between uppercase/lowercase based on the expanded state. +
  • +
  • Array keys are styled based on their parity.
  • +
  • + The labels of objects, arrays, and iterables are customized as "// + type". +
  • +
  • See code for details.
  • +
+
+ +
+

More Fine Grained Rendering

+

+ Pass labelRenderer or valueRenderer. +

+
+ (({raw})):} + valueRenderer={(raw) => ( + 😐 {" "} - {raw as string}{" "} - + {raw as string}{" "} + 😐 - - )} - /> -
-

- Sort object keys with sortObjectKeys prop. -

-
- -
-

Collapsed root node

-
- false}/> -
- -

Collapsed top-level nodes

-
- ({ - name: `item #${i}`, - value: i, - }))} - /> -
+
+ )} + /> +
+

+ Sort object keys with sortObjectKeys prop. +

+
+ +
+

Collapsed root node

+
+ false} /> +
-

Shift + click to toggle visualizing all child nodes

-
- -
-
+

Collapsed top-level nodes

+
+ ({ + name: `item #${i}`, + value: i, + }))} + /> +
+

Shift + click to toggle visualizing all child nodes

+
+ +
+
); function OnExpandExample() { - const [keyPathsToExpand, setKeyPathsToExpand] = React.useState([]) - return
-
- KeyPaths that will be expanded: {JSON.stringify(keyPathsToExpand)} -
- - { - for(let i = 0; i < keyPathsToExpand.length; i++) { - if(doesNodeContainNode(keyPathsToExpand[i], keyPath)) { - return true; - } - } + const [keyPathsToExpand, setKeyPathsToExpand] = React.useState([]); + return ( +
+
+ KeyPaths that will be expanded: {JSON.stringify(keyPathsToExpand)} +
- return level < 1 - }} - data={data} - onExpand={(e, keyPath, expanded) => { - if ((e.ctrlKey || e.shiftKey || e.altKey)) { - if(expanded){ - setKeyPathsToExpand([...keyPathsToExpand.filter(existingKeyPath => !areKeyPathsEqual(existingKeyPath, keyPath)), keyPath]) - }else { - if(keyPathsToExpand.length) { - setKeyPathsToExpand(keyPathsToExpand.filter(k => !areKeyPathsEqual(k, keyPath))) - } - } + { + for (let i = 0; i < keyPathsToExpand.length; i++) { + if (doesNodeContainNode(keyPathsToExpand[i], keyPath)) { + return true; + } + } + return level < 1; + }} + data={data} + onExpand={(e, keyPath, expanded) => { + if (e.ctrlKey || e.shiftKey || e.altKey) { + if (expanded) { + setKeyPathsToExpand([ + ...keyPathsToExpand.filter( + (existingKeyPath) => + !areKeyPathsEqual(existingKeyPath, keyPath), + ), + keyPath, + ]); + } else { + if (keyPathsToExpand.length) { + setKeyPathsToExpand( + keyPathsToExpand.filter((k) => !areKeyPathsEqual(k, keyPath)), + ); + } } - }}/> -
; + } + }} + /> +
+ ); } - export default App; diff --git a/src/ItemRange.tsx b/src/ItemRange.tsx index 298734c..d8229d9 100644 --- a/src/ItemRange.tsx +++ b/src/ItemRange.tsx @@ -3,7 +3,8 @@ import JSONArrow from "./JSONArrow.js"; import { CircularCache, CommonInternalProps, - KeyPath, OnExpandEvent, + KeyPath, + OnExpandEvent, ScrollToPath, } from "./types.js"; import styles from "./styles/itemRange.module.scss"; @@ -21,7 +22,15 @@ interface Props extends CommonInternalProps { } export default function ItemRange(props: Props) { - const { from, to, renderChildNodes, nodeType, scrollToPath, keyPath, onExpand } = props; + const { + from, + to, + renderChildNodes, + nodeType, + scrollToPath, + keyPath, + onExpand, + } = props; let initialExpanded = false; if (scrollToPath) { const [index] = scrollToPath; @@ -35,14 +44,16 @@ export default function ItemRange(props: Props) { } const [expanded, setExpanded] = useState(initialExpanded); - const handleClick = useCallback((e: OnExpandEvent) => { - setExpanded(!expanded); + const handleClick = useCallback( + (e: OnExpandEvent) => { + setExpanded(!expanded); - if(onExpand !== undefined) { - onExpand(e, keyPath, expanded) - } - - }, [expanded]); + if (onExpand !== undefined) { + onExpand(e, keyPath, expanded); + } + }, + [expanded], + ); return expanded ? (
diff --git a/src/JSONArrow.tsx b/src/JSONArrow.tsx index 5d4d49d..28805ae 100644 --- a/src/JSONArrow.tsx +++ b/src/JSONArrow.tsx @@ -1,6 +1,6 @@ import React, { EventHandler } from "react"; import styles from "./styles/JSONArrow.module.scss"; -import {OnExpandEvent} from "./types.ts"; +import { OnExpandEvent } from "./types.ts"; interface Props { arrowStyle?: "single" | "double"; diff --git a/src/JSONNestedNode.tsx b/src/JSONNestedNode.tsx index da8271a..db17325 100644 --- a/src/JSONNestedNode.tsx +++ b/src/JSONNestedNode.tsx @@ -1,9 +1,15 @@ -import React, {useCallback, useEffect, useState} from "react"; +import React, { useCallback, useEffect, useState } from "react"; import JSONArrow from "./JSONArrow.js"; import getCollectionEntries from "./getCollectionEntries.js"; import JSONNode from "./JSONNode.js"; import ItemRange from "./ItemRange.js"; -import {CircularCache, CommonInternalProps, KeyPath, OnExpandEvent, ShouldExpandNode} from "./types.js"; +import { + CircularCache, + CommonInternalProps, + KeyPath, + OnExpandEvent, + ShouldExpandNode, +} from "./types.js"; import styles from "./styles/JSONNestedNode.module.scss"; import { NodeListItem } from "./components/NodeListItem.tsx"; @@ -116,7 +122,7 @@ export default function JSONNestedNode(props: Props) { nodeTypeIndicator, shouldExpandNodeInitially, scrollToPath, - onExpand + onExpand, } = props; const isRoot = keyPath[0] === "root"; @@ -130,14 +136,17 @@ export default function JSONNestedNode(props: Props) { isCircular ? false : shouldExpandNodeInitially(keyPath, data, level), ); - const onNodeExpand = useCallback((e: OnExpandEvent) => { - if (isNodeExpandable) { - if(onExpand){ - onExpand(e, keyPath, !expanded) + const onNodeExpand = useCallback( + (e: OnExpandEvent) => { + if (isNodeExpandable) { + if (onExpand) { + onExpand(e, keyPath, !expanded); + } + setExpanded(!expanded); } - setExpanded(!expanded); - } - }, [isNodeExpandable, expanded]); + }, + [isNodeExpandable, expanded], + ); const renderedChildren = expanded || (hideRoot && level === 0) diff --git a/src/index.tsx b/src/index.tsx index f101c07..4d93f2c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -82,7 +82,6 @@ export function JSONTree({ sortObjectKeys={sortObjectKeys} valueWrap={valueWrap} onExpand={onExpand} - /> ); @@ -104,14 +103,17 @@ export const areKeyPathsEqual = (a: KeyPath, b: KeyPath) => { * Returns true if source is a child node of target * Remember child nodes have a longer key path */ -export const doesNodeContainNode = (parent: KeyPath, child: KeyPath): boolean => { +export const doesNodeContainNode = ( + parent: KeyPath, + child: KeyPath, +): boolean => { for (let i = parent.length - 1; i >= 0; i--) { if (parent[parent.length - i] !== child[child.length - i]) { return false; } } return true; -} +}; export type { Key, @@ -124,5 +126,5 @@ export type { IsCustomNode, SortObjectKeys, CommonExternalProps, - ScrollToPath + ScrollToPath, } from "./types.js"; diff --git a/src/types.ts b/src/types.ts index 0b2d871..2c1808d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -41,12 +41,11 @@ export type ShouldExpandNodeInitially = ( ) => boolean; export type ShouldExpandNode = ( - keyPath: KeyPath, - data: unknown, - level: number, + keyPath: KeyPath, + data: unknown, + level: number, ) => boolean | undefined; - export type PostprocessValue = (value: unknown) => unknown; export type IsCustomNode = (value: unknown) => boolean; @@ -55,7 +54,10 @@ export type SortObjectKeys = ((a: unknown, b: unknown) => number) | boolean; export type CircularCache = unknown[]; -export type OnExpandEvent = React.MouseEvent | React.KeyboardEvent | React.MouseEvent +export type OnExpandEvent = + | React.MouseEvent + | React.KeyboardEvent + | React.MouseEvent; export interface CommonExternalProps { keyPath: KeyPath; @@ -72,7 +74,7 @@ export interface CommonExternalProps { sortObjectKeys: SortObjectKeys; valueWrap: string; scrollToPath?: ScrollToPath; - onExpand?: (event: OnExpandEvent, keyPath: KeyPath, expand: boolean) => void + onExpand?: (event: OnExpandEvent, keyPath: KeyPath, expand: boolean) => void; } export interface CommonInternalProps extends CommonExternalProps { From 91fba761ded35b1125b4cc856884b76c465d7d48 Mon Sep 17 00:00:00 2001 From: Galen Date: Fri, 18 Jul 2025 11:27:38 -0500 Subject: [PATCH 3/3] chore: undo unintentional commit --- examples/src/App.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/src/App.tsx b/examples/src/App.tsx index 23deeda..96f2b32 100644 --- a/examples/src/App.tsx +++ b/examples/src/App.tsx @@ -132,14 +132,13 @@ const App = () => ( > { - // // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded - // return !!areKeyPathsEqual( - // keyPath, - // hugeArrayKeyPath.slice(keyPath.length * -1), - // ); - // }} + shouldExpandNodeInitially={(keyPath: KeyPath) => { + // Caller needs to ensure that parent node of scrollToPath is expanded for scrollTo to work on initial render, otherwise it will scroll to when the parent node/collection is expanded + return !!areKeyPathsEqual( + keyPath, + hugeArrayKeyPath.slice(keyPath.length * -1), + ); + }} scrollToPath={hugeArrayKeyPath} />