@react-hive/honey-utils 3.21.0 → 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ import type { KeysWithArrayValues, KeysWithNonArrayValues } from '~/types';
2
+ import type { HoneyTreeFlatNode } from '~/tree';
3
+ /**
4
+ * Flattens a hierarchical tree into a single preorder array.
5
+ *
6
+ * Each node in the returned list is stripped of its nested children property
7
+ * (`childrenKey`) and enriched with hierarchy metadata:
8
+ *
9
+ * - `parentId` — identifier of the parent node (`undefined` for roots)
10
+ * - `depthLevel` — nesting depth starting at `0`
11
+ * - `childCount` — number of direct child nodes
12
+ *
13
+ * The flattening order is **preorder**, meaning parents always appear before
14
+ * their descendants. This representation is especially useful for rendering
15
+ * tree-based UIs such as TreeSelect components, nested menus, and folder pickers.
16
+ *
17
+ * @template OriginItem - Original node shape of the hierarchical structure.
18
+ *
19
+ * @param items - Root-level nodes to flatten. If undefined, an empty array is returned.
20
+ * @param nodeIdKey - Key that uniquely identifies each node.
21
+ * @param childrenKey - Key containing the nested child node array.
22
+ *
23
+ * @param flatTree - Internal accumulator used during recursion.
24
+ * @param parentId - Parent identifier for the current recursion level.
25
+ * @param depthLevel - Current depth level, where `0` represents the root.
26
+ *
27
+ * @returns A flat preorder list of tree nodes with hierarchy metadata attached,
28
+ * excluding the original children property.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const tree = [
33
+ * {
34
+ * id: 1,
35
+ * name: 'Root',
36
+ * children: [{ id: 2, name: 'Child', children: [] }],
37
+ * },
38
+ * ];
39
+ *
40
+ * const flatTree = flattenTree(tree, 'id', 'children');
41
+ *
42
+ * // [
43
+ * // { id: 1, name: 'Root', parentId: undefined, depthLevel: 0, childCount: 1 },
44
+ * // { id: 2, name: 'Child', parentId: 1, depthLevel: 1, childCount: 0 }
45
+ * // ]
46
+ * ```
47
+ */
48
+ export declare const flattenTree: <OriginItem extends object>(items: OriginItem[] | undefined, nodeIdKey: KeysWithNonArrayValues<OriginItem>, childrenKey: KeysWithArrayValues<OriginItem>, flatTree?: HoneyTreeFlatNode<OriginItem, typeof childrenKey>[], parentId?: OriginItem[KeysWithNonArrayValues<OriginItem>] | undefined, depthLevel?: number) => HoneyTreeFlatNode<OriginItem, typeof childrenKey>[];
@@ -0,0 +1,41 @@
1
+ import type { KeysWithNonArrayValues } from '~/types';
2
+ import type { HoneyTreeFlatNode } from '~/tree';
3
+ /**
4
+ * Returns the direct children of a given parent node from a flattened tree.
5
+ *
6
+ * This helper filters a flat tree representation (`HoneyTreeFlatNode`) and
7
+ * selects only nodes whose `parentId` matches the provided identifier.
8
+ *
9
+ * ⚠️ Only direct children are returned - descendants at deeper levels are not included.
10
+ *
11
+ * An optional predicate may be provided to further narrow the result set
12
+ * (e.g. filtering by depth, type, or custom node flags).
13
+ *
14
+ * @template OriginItem - Original node shape of the hierarchical structure.
15
+ * @template ChildrenKey - Key of the removed nested children property.
16
+ *
17
+ * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.
18
+ * @param parentId - Identifier of the parent node whose direct children should be returned.
19
+ * @param predicate - Optional additional filter applied to each matched child node.
20
+ *
21
+ * @returns An array of nodes that are direct children of the specified parent.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const children = getTreeChildren(flatTree, 1);
26
+ *
27
+ * // Returns all nodes where parentId === 1
28
+ * ```
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const shallowChildren = getTreeChildren(
33
+ * flatTree,
34
+ * 1,
35
+ * node => node.depthLevel <= 2,
36
+ * );
37
+ *
38
+ * // Returns only children of node 1 that satisfy the predicate.
39
+ * ```
40
+ */
41
+ export declare const getTreeChildren: <OriginItem extends object, ChildrenKey extends string>(flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[], parentId: OriginItem[KeysWithNonArrayValues<OriginItem>], predicate?: (node: HoneyTreeFlatNode<OriginItem, ChildrenKey>) => boolean) => HoneyTreeFlatNode<OriginItem, ChildrenKey>[];
@@ -0,0 +1,4 @@
1
+ export * from './tree.types';
2
+ export * from './flatten-tree';
3
+ export * from './get-tree-children';
4
+ export * from './search-tree';
@@ -0,0 +1,54 @@
1
+ import type { KeysWithNonArrayValues, KeysWithStringValues } from '~/types';
2
+ import type { HoneyTreeFlatNode } from '~/tree';
3
+ /**
4
+ * Performs a context-aware search over a flattened tree.
5
+ *
6
+ * Matching is applied to the provided string field (`nodeValueKey`) using
7
+ * **case-insensitive, word-prefix comparison**:
8
+ *
9
+ * - The query is split into words
10
+ * - Each query word must match the start of at least one word in the node value
11
+ *
12
+ * Unlike a simple filter, this function preserves hierarchical context:
13
+ *
14
+ * - When a nested node matches, all of its ancestor nodes are included, so the
15
+ * result remains navigable.
16
+ * - When a root node matches, its full descendant subtree is included so the
17
+ * hierarchy stays intact.
18
+ *
19
+ * This makes the utility ideal for searchable tree-based UIs such as
20
+ * TreeSelect components, folder pickers, nested menus, and grouped lists.
21
+ *
22
+ * @template OriginItem - Original node shape of the hierarchical structure.
23
+ * @template ChildrenKey - Key of the removed nested children property.
24
+ *
25
+ * @param flatTree - Flat preorder list of tree nodes containing hierarchy metadata.
26
+ * @param nodeIdKey - Key that uniquely identifies each node.
27
+ * @param nodeValueKey - Key containing the searchable string value (e.g. `"name"`).
28
+ * @param searchQuery - User input query. Split into words and matched by prefix.
29
+ *
30
+ * @returns A filtered flat list containing:
31
+ * - all matching nodes
32
+ * - their ancestor chain (for nested matches)
33
+ * - full descendant subtrees (for root-level matches)
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const results = searchTree(flatTree, 'id', 'label', 'kit che');
38
+ *
39
+ * // Matches nodes where words start with "kit" and "che"
40
+ * // (e.g. "Kitchen Chair"), including their parents.
41
+ * ```
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // If a deep child matches, ancestors are included:
46
+ * //
47
+ * // Root
48
+ * // └─ Category
49
+ * // └─ Item ← matches
50
+ * //
51
+ * // Result includes: Root, Category, Item
52
+ * ```
53
+ */
54
+ export declare const searchTree: <OriginItem extends object, ChildrenKey extends string>(flatTree: HoneyTreeFlatNode<OriginItem, ChildrenKey>[], nodeIdKey: KeysWithNonArrayValues<OriginItem>, nodeValueKey: KeysWithStringValues<OriginItem>, searchQuery: string) => HoneyTreeFlatNode<OriginItem, ChildrenKey>[];
@@ -0,0 +1,40 @@
1
+ import type { KeysWithNonArrayValues } from '~/types';
2
+ /**
3
+ * A flattened representation of a node from a hierarchical tree structure.
4
+ *
5
+ * This type is produced when converting nested data (e.g. folders, categories,
6
+ * grouped lists) into a flat array while preserving hierarchy metadata.
7
+ *
8
+ * The original nested children property (`ChildrenKey`) is removed, and each node is augmented with:
9
+ * - `parentId` — reference to the parent node (undefined for root nodes).
10
+ * - `depthLevel` — nesting depth, starting at `0`.
11
+ * - `childCount` — number of direct child nodes.
12
+ *
13
+ * This structure is ideal for rendering tree-based UIs (TreeSelect, menus, expandable lists)
14
+ * and for performing operations such as searching, filtering, or reconstructing parent-child relationships.
15
+ *
16
+ * @template OriginItem - The original node shape from the hierarchical structure.
17
+ * @template ChildrenKey - Key of the property that contains nested child nodes.
18
+ */
19
+ export type HoneyTreeFlatNode<OriginItem extends object, ChildrenKey extends string> = Omit<OriginItem, ChildrenKey> & {
20
+ /**
21
+ * Identifier of the parent node in the flattened structure.
22
+ *
23
+ * Root-level nodes have `parentId` set to `undefined`.
24
+ */
25
+ parentId: OriginItem[KeysWithNonArrayValues<OriginItem>] | undefined;
26
+ /**
27
+ * Depth of the node within the hierarchy.
28
+ *
29
+ * - `0` → root level
30
+ * - `1` → direct child
31
+ * - `2+` → deeper descendants
32
+ */
33
+ depthLevel: number;
34
+ /**
35
+ * Number of direct nested child nodes contained within this node.
36
+ *
37
+ * This value is `0` for leaf nodes.
38
+ */
39
+ childCount: number;
40
+ };
package/dist/types.d.ts CHANGED
@@ -1,2 +1,69 @@
1
1
  export type Nullable<T> = T | null;
2
2
  export type TimeoutId = ReturnType<typeof setTimeout>;
3
+ /**
4
+ * Extracts the keys from a given type `T` whose values match the specified `Condition`.
5
+ *
6
+ * @template T - The object type from which to extract keys.
7
+ * @template Condition - The condition that the type of the values must satisfy to be included.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * type Example = { a: string; b: number; c: boolean };
12
+ * type StringKeys = ExtractKeys<Example, string>; // "a"
13
+ * ```
14
+ */
15
+ type ExtractKeys<T, Condition> = {
16
+ [K in keyof T]: T[K] extends Condition ? K : never;
17
+ }[keyof T];
18
+ /**
19
+ * Excludes the keys from a given type `T` whose values match the specified `Condition`.
20
+ *
21
+ * @template T - The object type from which to exclude keys.
22
+ * @template Condition - The condition that the type of the values must satisfy to be excluded.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * type Example = { a: string; b: number; c: boolean };
27
+ * type NonNumberKeys = ExcludeKeys<Example, number>; // "a" | "c"
28
+ * ```
29
+ */
30
+ type ExcludeKeys<T, Condition> = {
31
+ [K in keyof T]: T[K] extends Condition ? never : K;
32
+ }[keyof T];
33
+ /**
34
+ * Extracts the keys from a given type `T` where the values are `string`, `null`, or `undefined`.
35
+ *
36
+ * @template T - The object type from which to extract string-related keys.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * type Example = { a: string; b: number; c: string | null };
41
+ * type StringKeys = KeysWithStringValues<Example>; // "a" | "c"
42
+ * ```
43
+ */
44
+ export type KeysWithStringValues<T> = Extract<ExtractKeys<T, string | null | undefined>, string>;
45
+ /**
46
+ * Extracts the keys from a given type `T` where the values are arrays (`unknown[]`), `null`, or `undefined`.
47
+ *
48
+ * @template T - The object type from which to extract array-related keys.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * type Example = { a: string[]; b: number; c: number[] | null };
53
+ * type ArrayKeys = KeysWithArrayValues<Example>; // "a" | "c"
54
+ * ```
55
+ */
56
+ export type KeysWithArrayValues<T> = Extract<ExtractKeys<T, unknown[] | null | undefined>, string>;
57
+ /**
58
+ * Extracts the keys from a given type `T` where the values are **not** arrays (`unknown[]`), `null`, or `undefined`.
59
+ *
60
+ * @template T - The object type from which to extract non-array keys.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * type Example = { a: string; b: number; c: string[]; d: null };
65
+ * type NonArrayKeys = KeysWithNonArrayValues<Example>; // "a" | "b"
66
+ * ```
67
+ */
68
+ export type KeysWithNonArrayValues<T> = Extract<ExcludeKeys<T, unknown[] | null | undefined>, string>;
69
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-hive/honey-utils",
3
- "version": "3.21.0",
3
+ "version": "3.23.0",
4
4
  "description": "A lightweight TypeScript utility library providing a collection of helper functions for common programming tasks",
5
5
  "keywords": [
6
6
  "utils",
@@ -22,7 +22,7 @@
22
22
  "type": "git",
23
23
  "url": "git+ssh://git@github.com/React-Hive/honey-utils.git"
24
24
  },
25
- "author": "Mykhailo Aliinyk <m.aliynik@gmail.com>",
25
+ "author": "Mike Aliinyk <m.aliynik@gmail.com>",
26
26
  "license": "MIT",
27
27
  "scripts": {
28
28
  "build": "webpack --config webpack.config.mjs",