@himanshu-sorathiya/react-kit 1.0.32 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +557 -24
- package/dist/index.js +4 -4
- package/dist/state.d.ts +557 -24
- package/dist/state.js +2 -2
- package/dist/state2.js +509 -112
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2844,30 +2844,238 @@ export declare function useGrouping<T = unknown>(options?: {
|
|
|
2844
2844
|
initialGroupBy?: string;
|
|
2845
2845
|
}): UseGroupingReturn<T>;
|
|
2846
2846
|
export type SelectionId = string | number;
|
|
2847
|
-
export
|
|
2848
|
-
|
|
2847
|
+
export type Primitive = string | number | boolean | bigint | symbol | null | undefined;
|
|
2848
|
+
export type PathImpl<K extends string | number, V> = V extends Primitive ? `${K}` : V extends readonly unknown[] ? `${K}` | `${K}.${number}` | (V[number] extends Primitive ? never : `${K}.${number}.${Path<V[number]>}`) : `${K}` | `${K}.${Path<V>}`;
|
|
2849
|
+
export type Path<T> = T extends object ? {
|
|
2850
|
+
[K in keyof T & (string | number)]: PathImpl<K, T[K]>;
|
|
2851
|
+
}[keyof T & (string | number)] : never;
|
|
2852
|
+
export type PathValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<T[K], Rest> : unknown : P extends keyof T ? T[P] : unknown;
|
|
2853
|
+
/**
|
|
2854
|
+
* All dot-notation paths of `T` whose resolved value is assignable to `TId`.
|
|
2855
|
+
*
|
|
2856
|
+
* @remarks
|
|
2857
|
+
* This is what makes `field` type-safe: a path pointing at a boolean, an
|
|
2858
|
+
* object, or a non-existent property simply isn't a member of this type, so
|
|
2859
|
+
* passing it is a compile-time error rather than a silent `undefined` at
|
|
2860
|
+
* runtime. Built on top of the `Path`/`PathValue` machinery already exported
|
|
2861
|
+
* by `getValue`'s module.
|
|
2862
|
+
*
|
|
2863
|
+
* @template T The item shape.
|
|
2864
|
+
* @template TId The id type the resolved value must be assignable to.
|
|
2865
|
+
*/
|
|
2866
|
+
export type SelectionIdPath<T, TId extends SelectionId> = {
|
|
2867
|
+
[P in Path<T> & string]: PathValue<T, P> extends TId ? P : never;
|
|
2868
|
+
}[Path<T> & string];
|
|
2869
|
+
/**
|
|
2870
|
+
* The options every {@link useMultipleSelection} call accepts regardless of
|
|
2871
|
+
* whether `T` is a raw id type or an object type.
|
|
2872
|
+
*
|
|
2873
|
+
* @typeParam T - The item shape (or `TId` itself, for id-only mode).
|
|
2874
|
+
* @typeParam TId - The id type used internally for `Set`/comparison purposes.
|
|
2875
|
+
*/
|
|
2876
|
+
export interface UseMultipleSelectionBaseOptions<T, TId extends SelectionId> {
|
|
2877
|
+
/**
|
|
2878
|
+
* The items this selection is over. Determines `selectedItems`, and is
|
|
2879
|
+
* what `selectAll`/`toggleAll`/`invertSelection` operate against.
|
|
2880
|
+
*
|
|
2881
|
+
* @remarks
|
|
2882
|
+
* Pass a stable/memoized array. An inline `items={data.filter(...)}` gets
|
|
2883
|
+
* a new reference every render, which cascades into every memoized value
|
|
2884
|
+
* derived from `items` recomputing every render too — this hook can't
|
|
2885
|
+
* cheaply detect "same contents, different reference" for you.
|
|
2886
|
+
*/
|
|
2887
|
+
items?: readonly T[];
|
|
2888
|
+
/**
|
|
2889
|
+
* The ids selected on mount, and what {@link UseMultipleSelectionReturn.reset}
|
|
2890
|
+
* returns the selection to.
|
|
2891
|
+
*
|
|
2892
|
+
* @remarks
|
|
2893
|
+
* Only the value present on the **first render** seeds state (standard
|
|
2894
|
+
* `useState` initializer semantics). `reset()` always reads the **latest**
|
|
2895
|
+
* `defaultSelectedIds` at call time, so if this changes across renders,
|
|
2896
|
+
* `reset()` restores to the newest default, not the original mount-time one.
|
|
2897
|
+
*/
|
|
2898
|
+
defaultSelectedIds?: readonly TId[];
|
|
2899
|
+
/**
|
|
2900
|
+
* Predicate that marks certain ids as non-selectable.
|
|
2901
|
+
*
|
|
2902
|
+
* @remarks
|
|
2903
|
+
* Enforced on every operation that **adds** to the selection (`select`,
|
|
2904
|
+
* `toggle`'s select-direction, `selectMultiple`, `selectAll`, `toggleAll`,
|
|
2905
|
+
* `invertSelection`, `replaceSelection`). It never blocks **removal**
|
|
2906
|
+
* (`deselect`, `deselectMultiple`, `retainOnly`, `toggle`'s deselect-direction,
|
|
2907
|
+
* `deselectAll`) — if an already-selected id becomes disabled later, you can
|
|
2908
|
+
* always deselect it, just not re-select it.
|
|
2909
|
+
*
|
|
2910
|
+
* @param id - The id being checked.
|
|
2911
|
+
* @returns `true` if the id must not be added to the selection.
|
|
2912
|
+
*/
|
|
2913
|
+
isDisabled?: (id: TId) => boolean;
|
|
2914
|
+
}
|
|
2915
|
+
/**
|
|
2916
|
+
* The `field` requirement, resolved conditionally on whether `T` is already
|
|
2917
|
+
* an id (`[T] extends [TId]`) or a full object.
|
|
2918
|
+
*
|
|
2919
|
+
* @remarks
|
|
2920
|
+
* - id-only mode (`T` is assignable to `TId`, e.g. the default `T = SelectionId`):
|
|
2921
|
+
* `field` is forbidden — there's nothing to extract a path from.
|
|
2922
|
+
* - object mode: `field` is **required**, and restricted to
|
|
2923
|
+
* {@link SelectionIdPath} — a path that doesn't exist on `T`, or whose
|
|
2924
|
+
* resolved value isn't assignable to `TId`, is a compile-time error rather
|
|
2925
|
+
* than a silent `undefined` id at runtime.
|
|
2926
|
+
*/
|
|
2927
|
+
export type UseMultipleSelectionFieldOptions<T, TId extends SelectionId> = [
|
|
2928
|
+
T
|
|
2929
|
+
] extends [
|
|
2930
|
+
TId
|
|
2931
|
+
] ? {
|
|
2932
|
+
field?: never;
|
|
2933
|
+
} : {
|
|
2934
|
+
field: SelectionIdPath<T, TId>;
|
|
2935
|
+
};
|
|
2936
|
+
/**
|
|
2937
|
+
* Combined options for {@link useMultipleSelection}. See
|
|
2938
|
+
* {@link UseMultipleSelectionBaseOptions} and {@link UseMultipleSelectionFieldOptions}.
|
|
2939
|
+
*
|
|
2940
|
+
* @typeParam T - The item shape. Defaults to `SelectionId` (id-only mode: pass
|
|
2941
|
+
* raw ids as "items", no `field` needed).
|
|
2942
|
+
* @typeParam TId - The id type. Defaults to `SelectionId`; narrow it (e.g. to a
|
|
2943
|
+
* branded `UserId`) for stronger inference.
|
|
2944
|
+
*/
|
|
2945
|
+
export type UseMultipleSelectionOptions<T = SelectionId, TId extends SelectionId = SelectionId> = UseMultipleSelectionBaseOptions<T, TId> & UseMultipleSelectionFieldOptions<T, TId>;
|
|
2946
|
+
/**
|
|
2947
|
+
* Return shape of {@link useMultipleSelection}.
|
|
2948
|
+
*
|
|
2949
|
+
* @typeParam T - The item shape.
|
|
2950
|
+
* @typeParam TId - The id type.
|
|
2951
|
+
*/
|
|
2952
|
+
export interface UseMultipleSelectionReturn<T = SelectionId, TId extends SelectionId = SelectionId> {
|
|
2953
|
+
/**
|
|
2954
|
+
* The currently selected ids.
|
|
2955
|
+
*
|
|
2956
|
+
* @remarks
|
|
2957
|
+
* Ordered to match `items`' order whenever every selected id is present in
|
|
2958
|
+
* `items`. If some selected ids aren't in the current `items` array (e.g.
|
|
2959
|
+
* a previously-selected item that's since been filtered out, or an id
|
|
2960
|
+
* selected directly without ever appearing in `items`), those "orphaned"
|
|
2961
|
+
* ids are preserved and appended at the end, rather than silently dropped —
|
|
2962
|
+
* this hook never discards selection state you didn't ask it to discard.
|
|
2963
|
+
*/
|
|
2964
|
+
selectedIds: readonly TId[];
|
|
2965
|
+
/** The number of currently selected ids (including any orphaned ones — see {@link UseMultipleSelectionReturn.selectedIds}). */
|
|
2849
2966
|
selectedCount: number;
|
|
2850
|
-
|
|
2967
|
+
/** The subset of `items` that are currently selected, in `items`' order. */
|
|
2968
|
+
selectedItems: readonly T[];
|
|
2969
|
+
/** Whether nothing at all is selected. */
|
|
2851
2970
|
isEmpty: boolean;
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2971
|
+
/**
|
|
2972
|
+
* Whether every *selectable* (non-disabled) item in `items` is currently
|
|
2973
|
+
* selected. `false` when `items` is empty. Intended for a "select all"
|
|
2974
|
+
* checkbox's checked state.
|
|
2975
|
+
*/
|
|
2976
|
+
isAllSelected: boolean;
|
|
2977
|
+
/**
|
|
2978
|
+
* Whether some, but not all, selectable items in `items` are selected.
|
|
2979
|
+
* Intended for a "select all" checkbox's indeterminate state.
|
|
2980
|
+
*/
|
|
2981
|
+
isPartiallySelected: boolean;
|
|
2982
|
+
/**
|
|
2983
|
+
* Adds `item` to the selection.
|
|
2984
|
+
* @remarks No-ops if `item` resolves to a disabled id.
|
|
2985
|
+
* @param item - A raw id, or a full item (requires `field` to have been configured).
|
|
2986
|
+
*/
|
|
2987
|
+
select: (item: TId | T) => void;
|
|
2988
|
+
/**
|
|
2989
|
+
* Removes `item` from the selection. Always allowed, even for disabled ids.
|
|
2990
|
+
* @param item - A raw id, or a full item.
|
|
2991
|
+
*/
|
|
2992
|
+
deselect: (item: TId | T) => void;
|
|
2993
|
+
/**
|
|
2994
|
+
* Adds `item` if not selected, removes it if selected.
|
|
2995
|
+
* @remarks The add-direction is blocked for disabled ids; the remove-direction never is.
|
|
2996
|
+
* @param item - A raw id, or a full item.
|
|
2997
|
+
*/
|
|
2998
|
+
toggle: (item: TId | T) => void;
|
|
2999
|
+
/**
|
|
3000
|
+
* Checks whether `item` is currently selected.
|
|
3001
|
+
* @param item - A raw id, or a full item.
|
|
3002
|
+
* @returns `true` if currently selected.
|
|
3003
|
+
*/
|
|
3004
|
+
isSelected: (item: TId | T) => boolean;
|
|
3005
|
+
/** Restores the selection to the current `defaultSelectedIds` (or empty, if none was provided). */
|
|
3006
|
+
reset: () => void;
|
|
3007
|
+
/**
|
|
3008
|
+
* Replaces the entire selection with exactly these ids/items.
|
|
3009
|
+
* @remarks Disabled ids are filtered out of the replacement set.
|
|
3010
|
+
*/
|
|
3011
|
+
replaceSelection: (newSelectedItems: readonly TId[] | readonly T[]) => void;
|
|
3012
|
+
/** Selects every selectable (non-disabled) item in `items`. */
|
|
2858
3013
|
selectAll: () => void;
|
|
3014
|
+
/** Clears the entire selection, including any disabled-but-selected or orphaned ids. */
|
|
2859
3015
|
deselectAll: () => void;
|
|
3016
|
+
/**
|
|
3017
|
+
* If every selectable item in `items` is currently selected, clears the
|
|
3018
|
+
* whole selection; otherwise selects every selectable item in `items`.
|
|
3019
|
+
*
|
|
3020
|
+
* @remarks
|
|
3021
|
+
* Determined by actual set membership against every selectable item, not
|
|
3022
|
+
* a size comparison — this stays correct even if `items` contains duplicate
|
|
3023
|
+
* resolved ids, or the current selection contains ids no longer present in
|
|
3024
|
+
* `items` (both of which would silently misfire a naive `prev.size === items.length` check).
|
|
3025
|
+
*/
|
|
2860
3026
|
toggleAll: () => void;
|
|
3027
|
+
/** Selects every currently-unselected selectable item, and deselects everything else. */
|
|
2861
3028
|
invertSelection: () => void;
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
3029
|
+
/**
|
|
3030
|
+
* Adds multiple ids/items to the selection at once.
|
|
3031
|
+
* @remarks Disabled ids are filtered out.
|
|
3032
|
+
*/
|
|
3033
|
+
selectMultiple: (newItems: readonly TId[] | readonly T[]) => void;
|
|
3034
|
+
/** Removes multiple ids/items from the selection at once. Always allowed. */
|
|
3035
|
+
deselectMultiple: (itemsToRemove: readonly TId[] | readonly T[]) => void;
|
|
3036
|
+
/** Keeps only the ids/items in `itemsToRetain` that are already selected (an intersection); never adds anything new. */
|
|
3037
|
+
retainOnly: (itemsToRetain: readonly TId[] | readonly T[]) => void;
|
|
2865
3038
|
}
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
3039
|
+
/**
|
|
3040
|
+
* Manages multi-item selection state (e.g. checkboxes in a table, a
|
|
3041
|
+
* multi-select list, bulk-action UI).
|
|
3042
|
+
*
|
|
3043
|
+
* @remarks
|
|
3044
|
+
* - Uncontrolled only for now — controlled mode is planned separately and
|
|
3045
|
+
* will be added without breaking this signature.
|
|
3046
|
+
* - SSR-safe: no DOM/window access; `defaultSelectedIds` must be deterministic
|
|
3047
|
+
* between server and client renders to avoid hydration mismatches.
|
|
3048
|
+
* - All returned callbacks are manually memoized with `useCallback`/`useMemo`
|
|
3049
|
+
* so this hook is safe to use even in codebases **without** the React Compiler.
|
|
3050
|
+
* - Works in two modes, picked by whether `T` is assignable to `TId`:
|
|
3051
|
+
* - **id-only mode** (default): `useMultipleSelection()` — "items" are raw
|
|
3052
|
+
* ids, no `field` needed.
|
|
3053
|
+
* - **object mode**: `useMultipleSelection<Item, string>({ items, field: "id" })` —
|
|
3054
|
+
* `field` is a type-checked dot-path into `Item` and is required.
|
|
3055
|
+
*
|
|
3056
|
+
* @typeParam T - The item shape (or `TId` itself, for id-only mode).
|
|
3057
|
+
* @typeParam TId - The id type. Defaults to `SelectionId`; narrow it for branded-id inference.
|
|
3058
|
+
* @param options - See {@link UseMultipleSelectionOptions}.
|
|
3059
|
+
* @returns The current selection state and the actions to mutate it. See {@link UseMultipleSelectionReturn}.
|
|
3060
|
+
*
|
|
3061
|
+
* @example
|
|
3062
|
+
* ```tsx
|
|
3063
|
+
* // id-only mode
|
|
3064
|
+
* const { selectedIds, toggle } = useMultipleSelection({ defaultSelectedIds: ["a"] });
|
|
3065
|
+
* ```
|
|
3066
|
+
*
|
|
3067
|
+
* @example
|
|
3068
|
+
* ```tsx
|
|
3069
|
+
* // object mode, with a nested field path and disabled rows
|
|
3070
|
+
* interface Row { id: string; locked: boolean }
|
|
3071
|
+
* const { selectedItems, toggleAll, isAllSelected, isPartiallySelected } = useMultipleSelection<Row, string>({
|
|
3072
|
+
* items: rows,
|
|
3073
|
+
* field: "id",
|
|
3074
|
+
* isDisabled: (id) => rows.find((r) => r.id === id)?.locked ?? false,
|
|
3075
|
+
* });
|
|
3076
|
+
* ```
|
|
3077
|
+
*/
|
|
3078
|
+
export declare function useMultipleSelection<T = SelectionId, TId extends SelectionId = SelectionId>(options?: UseMultipleSelectionOptions<T, TId>): UseMultipleSelectionReturn<T, TId>;
|
|
2871
3079
|
export interface UseOrderReturn<T> {
|
|
2872
3080
|
orderedItems: T[];
|
|
2873
3081
|
moveUp: (index: number) => void;
|
|
@@ -2900,16 +3108,112 @@ export interface UsePaginationReturn<T> {
|
|
|
2900
3108
|
resetPagination: () => void;
|
|
2901
3109
|
}
|
|
2902
3110
|
export declare function usePagination<T>(data: T[] | undefined, initialPageSize: number, initialPageIndex?: number): UsePaginationReturn<T>;
|
|
2903
|
-
|
|
2904
|
-
|
|
3111
|
+
/**
|
|
3112
|
+
* Configuration options for {@link useSingleSelection}.
|
|
3113
|
+
*
|
|
3114
|
+
* @typeParam TId - The concrete id type used by this selection instance.
|
|
3115
|
+
* Must be assignable to {@link SelectionId} (`string | number`), but can be
|
|
3116
|
+
* a narrower/branded type (e.g. `UserId`) for stronger inference at call sites.
|
|
3117
|
+
*/
|
|
3118
|
+
export interface UseSingleSelectionOptions<TId extends SelectionId = SelectionId> {
|
|
3119
|
+
/**
|
|
3120
|
+
* The id that is selected on mount, and the id that {@link UseSingleSelectionReturn.reset}
|
|
3121
|
+
* returns the selection to.
|
|
3122
|
+
*
|
|
3123
|
+
* @remarks
|
|
3124
|
+
* Only the value present on the **first render** is used to seed state
|
|
3125
|
+
* (standard `useState` initializer semantics — later changes to this value
|
|
3126
|
+
* do not retroactively change the current selection). However, `reset()`
|
|
3127
|
+
* always reads the **latest** `defaultSelectedId` at the time it's called,
|
|
3128
|
+
* so if this value changes across renders, `reset()` will restore to the
|
|
3129
|
+
* newest default, not the original mount-time one.
|
|
3130
|
+
*/
|
|
3131
|
+
defaultSelectedId?: TId;
|
|
3132
|
+
/**
|
|
3133
|
+
* Predicate that marks certain ids as non-selectable.
|
|
3134
|
+
*
|
|
3135
|
+
* @remarks
|
|
3136
|
+
* This guard is only enforced inside {@link UseSingleSelectionReturn.select}
|
|
3137
|
+
* and {@link UseSingleSelectionReturn.toggle}. It does **not** retroactively
|
|
3138
|
+
* clear a selection if an already-selected id later becomes disabled — the
|
|
3139
|
+
* hook has no way to know `isDisabled`'s result changed unless you call
|
|
3140
|
+
* `select`/`toggle` again. Reconcile that case yourself (e.g. via an effect)
|
|
3141
|
+
* if it matters for your use case.
|
|
3142
|
+
*
|
|
3143
|
+
* @param id - The id being checked before selection.
|
|
3144
|
+
* @returns `true` if the id must not be selectable.
|
|
3145
|
+
*/
|
|
3146
|
+
isDisabled?: (id: TId) => boolean;
|
|
3147
|
+
}
|
|
3148
|
+
/**
|
|
3149
|
+
* Return shape of {@link useSingleSelection}.
|
|
3150
|
+
*
|
|
3151
|
+
* @typeParam TId - The concrete id type used by this selection instance.
|
|
3152
|
+
*/
|
|
3153
|
+
export interface UseSingleSelectionReturn<TId extends SelectionId = SelectionId> {
|
|
3154
|
+
/** The currently selected id, or `undefined` if nothing is selected. */
|
|
3155
|
+
selectedId: TId | undefined;
|
|
3156
|
+
/**
|
|
3157
|
+
* Whether any id is currently selected.
|
|
3158
|
+
*
|
|
3159
|
+
* @remarks
|
|
3160
|
+
* Correctly distinguishes "nothing selected" from a falsy-but-valid id
|
|
3161
|
+
* such as `0` or `""` — this is `selectedId !== undefined`, not `!!selectedId`.
|
|
3162
|
+
*/
|
|
2905
3163
|
hasSelection: boolean;
|
|
2906
|
-
|
|
3164
|
+
/**
|
|
3165
|
+
* Selects the given id, replacing any current selection.
|
|
3166
|
+
*
|
|
3167
|
+
* @remarks No-ops if `id` is disabled per `isDisabled`.
|
|
3168
|
+
* @param id - The id to select.
|
|
3169
|
+
*/
|
|
3170
|
+
select: (id: TId) => void;
|
|
3171
|
+
/** Clears the current selection (sets it to `undefined`). */
|
|
2907
3172
|
deselect: () => void;
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
3173
|
+
/**
|
|
3174
|
+
* Selects `id` if it isn't already selected; deselects it if it is.
|
|
3175
|
+
*
|
|
3176
|
+
* @remarks No-ops if `id` is disabled per `isDisabled`.
|
|
3177
|
+
* @param id - The id to toggle.
|
|
3178
|
+
*/
|
|
3179
|
+
toggle: (id: TId) => void;
|
|
3180
|
+
/**
|
|
3181
|
+
* Checks whether the given id is the currently selected one.
|
|
3182
|
+
*
|
|
3183
|
+
* @param id - The id to check.
|
|
3184
|
+
* @returns `true` if `id` is currently selected.
|
|
3185
|
+
*/
|
|
3186
|
+
isSelected: (id: TId) => boolean;
|
|
3187
|
+
/**
|
|
3188
|
+
* Restores the selection to the current `defaultSelectedId`
|
|
3189
|
+
* (or `undefined` if none was provided).
|
|
3190
|
+
*/
|
|
3191
|
+
reset: () => void;
|
|
2911
3192
|
}
|
|
2912
|
-
|
|
3193
|
+
/**
|
|
3194
|
+
* Manages single-item selection state (e.g. a radio group, a single-select
|
|
3195
|
+
* list, an active tab/row).
|
|
3196
|
+
*
|
|
3197
|
+
* @remarks
|
|
3198
|
+
* - Uncontrolled only for now — controlled mode (`selectedId` + `onSelectionChange`)
|
|
3199
|
+
* is planned separately and will be added without breaking this signature.
|
|
3200
|
+
* - SSR-safe: performs no DOM/window access; `defaultSelectedId` must be
|
|
3201
|
+
* deterministic between server and client renders to avoid hydration mismatches.
|
|
3202
|
+
* - All returned callbacks are manually memoized with `useCallback` so this
|
|
3203
|
+
* hook is safe to use even in codebases **without** the React Compiler.
|
|
3204
|
+
*
|
|
3205
|
+
* @typeParam TId - The concrete id type used by this selection instance.
|
|
3206
|
+
* @param options - Optional configuration. See {@link UseSingleSelectionOptions}.
|
|
3207
|
+
* @returns The current selection state and the actions to mutate it. See {@link UseSingleSelectionReturn}.
|
|
3208
|
+
*
|
|
3209
|
+
* @example
|
|
3210
|
+
* ```tsx
|
|
3211
|
+
* const { selectedId, select, isSelected } = useSingleSelection<string>({
|
|
3212
|
+
* defaultSelectedId: "row-1",
|
|
3213
|
+
* });
|
|
3214
|
+
* ```
|
|
3215
|
+
*/
|
|
3216
|
+
export declare function useSingleSelection<TId extends SelectionId = SelectionId>(options?: UseSingleSelectionOptions<TId>): UseSingleSelectionReturn<TId>;
|
|
2913
3217
|
export type SortType = "numeric" | "alphabetical" | "alphanumeric" | "boolean" | "date" | "basic" | "custom";
|
|
2914
3218
|
export interface BaseSortOptions {
|
|
2915
3219
|
desc?: boolean;
|
|
@@ -2951,6 +3255,235 @@ export interface UseSortReturn<T> {
|
|
|
2951
3255
|
getSortIndex: (id: string) => number | undefined;
|
|
2952
3256
|
}
|
|
2953
3257
|
export declare function useSort<T>(data?: T[], initialSorts?: SortState): UseSortReturn<T>;
|
|
3258
|
+
/**
|
|
3259
|
+
* Restricts `field` to a **top-level** key of `T` whose value is assignable to `TId`.
|
|
3260
|
+
*
|
|
3261
|
+
* @remarks
|
|
3262
|
+
* Deliberately not the recursive dot-path style used by `useMultipleSelection`'s
|
|
3263
|
+
* `SelectionIdPath<T, TId>`. Tree nodes are self-referential (a `children` property
|
|
3264
|
+
* whose value is `T[]`, pointing back to `T`), and running the recursive `Path<T>`
|
|
3265
|
+
* machinery over a self-referential type produces a genuine TypeScript circular-reference
|
|
3266
|
+
* error. A tree node's id is virtually always a direct top-level property anyway — a
|
|
3267
|
+
* dot-path id nested inside a tree node would be an unusual shape — so this simpler,
|
|
3268
|
+
* non-recursive key filter is both the fix and the more correct constraint. The function
|
|
3269
|
+
* form below remains available for anything this doesn't cover.
|
|
3270
|
+
*/
|
|
3271
|
+
export type FieldKey<T, TId extends SelectionId> = {
|
|
3272
|
+
[K in keyof T]: T[K] extends TId ? K : never;
|
|
3273
|
+
}[keyof T] & string;
|
|
3274
|
+
/** Restricts `childrenField` to a top-level key of `T` whose value is `T[]` (or `undefined`). */
|
|
3275
|
+
export type ChildrenKey<T> = {
|
|
3276
|
+
[K in keyof T]: T[K] extends readonly T[] | undefined ? K : never;
|
|
3277
|
+
}[keyof T] & string;
|
|
3278
|
+
/** Either a type-checked property key, or a function, for extracting a node's id. */
|
|
3279
|
+
export type FieldAccessor<T, TId extends SelectionId> = FieldKey<T, TId> | ((item: T) => TId);
|
|
3280
|
+
/** Either a type-checked property key, or a function, for extracting a node's children. */
|
|
3281
|
+
export type ChildrenAccessor<T> = ChildrenKey<T> | ((item: T) => readonly T[] | undefined);
|
|
3282
|
+
/** The three states a tree node can be in with respect to the current selection. */
|
|
3283
|
+
export type TreeNodeState = "selected" | "indeterminate" | "unselected";
|
|
3284
|
+
/** One flattened tree entry, produced by {@link flattenForest}. */
|
|
3285
|
+
export interface FlatTreeEntry<T, TId extends SelectionId> {
|
|
3286
|
+
item: T;
|
|
3287
|
+
id: TId;
|
|
3288
|
+
parentId: TId | undefined;
|
|
3289
|
+
depth: number;
|
|
3290
|
+
}
|
|
3291
|
+
/** The precomputed structures every tree-selection operation is built on. */
|
|
3292
|
+
export interface FlattenedForest<T, TId extends SelectionId> {
|
|
3293
|
+
/** Every node in the forest, in DFS pre-order. */
|
|
3294
|
+
entries: readonly FlatTreeEntry<T, TId>[];
|
|
3295
|
+
/** O(1) lookup from id to its flattened entry. */
|
|
3296
|
+
entryById: ReadonlyMap<TId, FlatTreeEntry<T, TId>>;
|
|
3297
|
+
/** O(1) lookup from a node's id to its direct children's ids. Roots are keyed under `undefined`. */
|
|
3298
|
+
childIdsByParentId: ReadonlyMap<TId | undefined, readonly TId[]>;
|
|
3299
|
+
}
|
|
3300
|
+
export interface UseTreeSelectionOptions<T, TId extends SelectionId> {
|
|
3301
|
+
/** The forest — an array of root nodes. Each node's children are found via `childrenField`. */
|
|
3302
|
+
items: readonly T[];
|
|
3303
|
+
/** How to extract a node's id. A type-checked top-level key, or a function. */
|
|
3304
|
+
field: FieldAccessor<T, TId>;
|
|
3305
|
+
/** How to extract a node's children. A type-checked top-level key, or a function. */
|
|
3306
|
+
childrenField: ChildrenAccessor<T>;
|
|
3307
|
+
/**
|
|
3308
|
+
* The ids selected on mount, and what {@link UseTreeSelectionReturn.reset} returns to.
|
|
3309
|
+
*
|
|
3310
|
+
* @remarks
|
|
3311
|
+
* Not trusted as already cascade-consistent — always run through the same
|
|
3312
|
+
* full bottom-up normalization used by `reset`/`selectAll`/etc, so passing
|
|
3313
|
+
* e.g. only a leaf (without its ancestors) still produces correct indeterminate
|
|
3314
|
+
* ancestor state from the start.
|
|
3315
|
+
*/
|
|
3316
|
+
defaultSelectedIds?: readonly TId[];
|
|
3317
|
+
/**
|
|
3318
|
+
* Predicate marking certain ids as non-selectable.
|
|
3319
|
+
*
|
|
3320
|
+
* @remarks
|
|
3321
|
+
* A disabled node is skipped during cascade (never force-toggled) and excluded
|
|
3322
|
+
* from every "are all children selected" computation, but disabling a node does
|
|
3323
|
+
* **not** auto-disable its descendants, and does not retroactively clear it if
|
|
3324
|
+
* it was already selected before becoming disabled — same philosophy as the
|
|
3325
|
+
* flat selection hooks.
|
|
3326
|
+
*/
|
|
3327
|
+
isDisabled?: (id: TId) => boolean;
|
|
3328
|
+
/**
|
|
3329
|
+
* Independently controls whether selecting a node propagates to its descendants
|
|
3330
|
+
* (`down`) and/or its ancestors (`up`). Both default to `true`.
|
|
3331
|
+
*
|
|
3332
|
+
* @remarks
|
|
3333
|
+
* `{ down: false, up: false }` degenerates into flat, non-hierarchical
|
|
3334
|
+
* selection over tree-rendered nodes (no relationship between a node's
|
|
3335
|
+
* selection and its parent/children) — the same shape react-arborist/MUI's
|
|
3336
|
+
* default tree multi-select uses, as opposed to checkbox-tree cascading.
|
|
3337
|
+
*/
|
|
3338
|
+
cascade?: {
|
|
3339
|
+
down?: boolean;
|
|
3340
|
+
up?: boolean;
|
|
3341
|
+
};
|
|
3342
|
+
/**
|
|
3343
|
+
* When `true`, {@link UseTreeSelectionReturn.selectedIds} and
|
|
3344
|
+
* {@link UseTreeSelectionReturn.selectedItems} only include leaf nodes,
|
|
3345
|
+
* even if a fully-covered branch is internally tracked as selected.
|
|
3346
|
+
*
|
|
3347
|
+
* @remarks
|
|
3348
|
+
* This does not change `select`/`toggle`/cascade behavior at all — you can
|
|
3349
|
+
* still call `select` on a branch and it cascades normally, and
|
|
3350
|
+
* {@link UseTreeSelectionReturn.getNodeState} still reports branches correctly
|
|
3351
|
+
* as `"selected"`/`"indeterminate"` for display regardless of this option. It
|
|
3352
|
+
* only changes what the flat `selectedIds`/`selectedItems` arrays report — useful
|
|
3353
|
+
* when branches are just a UI grouping and the "real" selected resources are
|
|
3354
|
+
* always the leaves (e.g. sending a set of leaf resource ids to a backend).
|
|
3355
|
+
* {@link UseTreeSelectionReturn.selectedLeafIds} gives you the leaf subset
|
|
3356
|
+
* regardless of this option, if you want both views at once.
|
|
3357
|
+
*/
|
|
3358
|
+
leafOnly?: boolean;
|
|
3359
|
+
}
|
|
3360
|
+
export interface UseTreeSelectionReturn<T, TId extends SelectionId> {
|
|
3361
|
+
/**
|
|
3362
|
+
* Every fully-selected node's id, in forest (DFS pre-order) order.
|
|
3363
|
+
* @remarks Includes branch ids too, unless `leafOnly` is set. See {@link UseTreeSelectionOptions.leafOnly}.
|
|
3364
|
+
*/
|
|
3365
|
+
selectedIds: readonly TId[];
|
|
3366
|
+
/** Just the leaf ids among the current selection, regardless of `leafOnly`. */
|
|
3367
|
+
selectedLeafIds: readonly TId[];
|
|
3368
|
+
/** Every node currently in a partial (some-but-not-all-descendants-selected) state. */
|
|
3369
|
+
indeterminateIds: readonly TId[];
|
|
3370
|
+
/** The item objects corresponding to {@link UseTreeSelectionReturn.selectedIds}. */
|
|
3371
|
+
selectedItems: readonly T[];
|
|
3372
|
+
/** `selectedIds.length`. */
|
|
3373
|
+
selectedCount: number;
|
|
3374
|
+
/** Whether nothing at all is selected (not even indeterminate). */
|
|
3375
|
+
isEmpty: boolean;
|
|
3376
|
+
/** Whether every selectable root (and by construction, everything under it) is selected. */
|
|
3377
|
+
isAllSelected: boolean;
|
|
3378
|
+
/** Whether some, but not all, of the forest is selected or indeterminate. */
|
|
3379
|
+
isPartiallySelected: boolean;
|
|
3380
|
+
/**
|
|
3381
|
+
* The full tri-state read for a node — the primitive the rest of the boolean
|
|
3382
|
+
* getters below are built from.
|
|
3383
|
+
* @param item - A raw id, or a full item.
|
|
3384
|
+
*/
|
|
3385
|
+
getNodeState: (item: TId | T) => TreeNodeState;
|
|
3386
|
+
/** `getNodeState(item) === "selected"`. */
|
|
3387
|
+
isSelected: (item: TId | T) => boolean;
|
|
3388
|
+
/** `getNodeState(item) === "indeterminate"`. */
|
|
3389
|
+
isIndeterminate: (item: TId | T) => boolean;
|
|
3390
|
+
/**
|
|
3391
|
+
* Selects `item`, cascading per the `cascade` option.
|
|
3392
|
+
* @remarks No-ops if `item` itself resolves to a disabled id.
|
|
3393
|
+
*/
|
|
3394
|
+
select: (item: TId | T) => void;
|
|
3395
|
+
/** Deselects `item`, cascading per the `cascade` option. Always allowed, even for disabled ids. */
|
|
3396
|
+
deselect: (item: TId | T) => void;
|
|
3397
|
+
/**
|
|
3398
|
+
* Selects `item` if not selected, deselects it if selected, cascading per the `cascade` option.
|
|
3399
|
+
* @remarks The select-direction is blocked for disabled ids; the deselect-direction never is.
|
|
3400
|
+
*/
|
|
3401
|
+
toggle: (item: TId | T) => void;
|
|
3402
|
+
/** Restores the selection to the current `defaultSelectedIds` (normalized), or empty if none was given. */
|
|
3403
|
+
reset: () => void;
|
|
3404
|
+
/** Replaces the entire selection with exactly these ids/items (normalized — always internally consistent afterward). */
|
|
3405
|
+
replaceSelection: (newSelectedItems: readonly TId[] | readonly T[]) => void;
|
|
3406
|
+
/** Selects every selectable node in the forest. */
|
|
3407
|
+
selectAll: () => void;
|
|
3408
|
+
/** Clears the entire selection. */
|
|
3409
|
+
deselectAll: () => void;
|
|
3410
|
+
/** If everything selectable is currently selected, clears the selection; otherwise selects everything selectable. */
|
|
3411
|
+
toggleAll: () => void;
|
|
3412
|
+
/**
|
|
3413
|
+
* Selects multiple ids/items at once, cascading each per the `cascade` option.
|
|
3414
|
+
*
|
|
3415
|
+
* @remarks
|
|
3416
|
+
* More efficient than calling {@link UseTreeSelectionReturn.select} in a loop:
|
|
3417
|
+
* shared ancestors of multiple targets are only recomputed once each, not once
|
|
3418
|
+
* per target that shares them.
|
|
3419
|
+
*/
|
|
3420
|
+
selectMultiple: (newItems: readonly TId[] | readonly T[]) => void;
|
|
3421
|
+
/** Deselects multiple ids/items at once, cascading each per the `cascade` option. Always allowed, even for disabled ids. */
|
|
3422
|
+
deselectMultiple: (itemsToRemove: readonly TId[] | readonly T[]) => void;
|
|
3423
|
+
/**
|
|
3424
|
+
* Keeps only the ids/items in `itemsToRetain` that are already selected (an
|
|
3425
|
+
* intersection); never adds anything new. The result is re-normalized, so
|
|
3426
|
+
* ancestor indeterminate state stays correct after the shrink.
|
|
3427
|
+
*/
|
|
3428
|
+
retainOnly: (itemsToRetain: readonly TId[] | readonly T[]) => void;
|
|
3429
|
+
/**
|
|
3430
|
+
* Inverts the selection at the leaf level: every currently-unselected
|
|
3431
|
+
* selectable leaf becomes selected, every currently-selected one becomes
|
|
3432
|
+
* unselected. Branch/indeterminate state is re-derived from the result.
|
|
3433
|
+
* @remarks A disabled leaf that was selected before this call does not survive
|
|
3434
|
+
* it — like `useMultipleSelection`'s `invertSelection`, this is a full replace,
|
|
3435
|
+
* not a merge.
|
|
3436
|
+
*/
|
|
3437
|
+
invertSelection: () => void;
|
|
3438
|
+
/** The id of `item`'s direct parent, or `undefined` if it's a root. */
|
|
3439
|
+
getParentId: (item: TId | T) => TId | undefined;
|
|
3440
|
+
/** Every ancestor id of `item`, nearest first, root last. Empty if `item` is a root. */
|
|
3441
|
+
getAncestorIds: (item: TId | T) => readonly TId[];
|
|
3442
|
+
/** Every descendant id of `item`. Empty if `item` is a leaf. */
|
|
3443
|
+
getDescendantIds: (item: TId | T) => readonly TId[];
|
|
3444
|
+
}
|
|
3445
|
+
/**
|
|
3446
|
+
* Manages hierarchical (tree/forest) selection state — checkbox trees, nested
|
|
3447
|
+
* category pickers, permission trees, file explorers.
|
|
3448
|
+
*
|
|
3449
|
+
* @remarks
|
|
3450
|
+
* - Uncontrolled only for now, SSR-safe (no DOM access), all callbacks manually
|
|
3451
|
+
* memoized — same guarantees as the other selection hooks in this library.
|
|
3452
|
+
* - Expand/collapse state is explicitly **not** managed here — it's an orthogonal
|
|
3453
|
+
* view concern, not a selection concern (this hook only ever reads the full
|
|
3454
|
+
* `children` structure, regardless of what's currently expanded in the UI).
|
|
3455
|
+
* - **Performance**: a single `select`/`deselect`/`toggle` call is
|
|
3456
|
+
* O(affected subtree) for the cascade-down step plus O(depth × branching factor)
|
|
3457
|
+
* for the cascade-up step — it never re-walks the whole tree. Only whole-forest
|
|
3458
|
+
* operations (`selectAll`, `toggleAll`, `reset`, `replaceSelection`, and the
|
|
3459
|
+
* initial mount) do a full O(n) pass, which is the right complexity for
|
|
3460
|
+
* something that touches every node anyway. Verified independent of selection
|
|
3461
|
+
* order (a known bug class in at least one production tree-selection library
|
|
3462
|
+
* is indeterminate state differing based on the order nodes were selected in).
|
|
3463
|
+
* - If `items` (the tree **structure**) changes after mount — nodes added, removed,
|
|
3464
|
+
* or moved — the existing selection/indeterminate state is **not** automatically
|
|
3465
|
+
* re-normalized against the new shape (to avoid surprise O(n) work on every data
|
|
3466
|
+
* refresh). It stays correct for anything the change didn't touch, but the newly
|
|
3467
|
+
* changed area may need an explicit `reset()` or `replaceSelection()` to
|
|
3468
|
+
* guarantee full consistency again.
|
|
3469
|
+
*
|
|
3470
|
+
* @typeParam T - The tree node shape.
|
|
3471
|
+
* @typeParam TId - The id type. Defaults to `SelectionId`.
|
|
3472
|
+
* @param options - See {@link UseTreeSelectionOptions}.
|
|
3473
|
+
* @returns The current selection state and the actions to mutate it. See {@link UseTreeSelectionReturn}.
|
|
3474
|
+
*
|
|
3475
|
+
* @example
|
|
3476
|
+
* ```tsx
|
|
3477
|
+
* interface Category { id: string; name: string; children?: Category[] }
|
|
3478
|
+
*
|
|
3479
|
+
* const { getNodeState, toggle, isAllSelected, toggleAll } = useTreeSelection<Category, string>({
|
|
3480
|
+
* items: categoryTree,
|
|
3481
|
+
* field: "id",
|
|
3482
|
+
* childrenField: "children",
|
|
3483
|
+
* });
|
|
3484
|
+
* ```
|
|
3485
|
+
*/
|
|
3486
|
+
export declare function useTreeSelection<T, TId extends SelectionId = SelectionId>(options: UseTreeSelectionOptions<T, TId>): UseTreeSelectionReturn<T, TId>;
|
|
2954
3487
|
/**
|
|
2955
3488
|
* Defines how a value of type `T` is converted to and from the string
|
|
2956
3489
|
* format that `localStorage`/`sessionStorage` can actually store — the Web
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as e } from "./useEventListener.js";
|
|
2
2
|
import { n as t, t as n } from "./events2.js";
|
|
3
3
|
import { _ as r, a as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b } from "./performance2.js";
|
|
4
|
-
import { a as x, c as S, i as C,
|
|
5
|
-
import { a as
|
|
6
|
-
import { i as
|
|
7
|
-
export {
|
|
4
|
+
import { a as x, c as S, i as C, l as w, n as T, o as E, r as D, s as O, t as k } from "./state2.js";
|
|
5
|
+
import { a as A, i as j, n as M, o as N, r as P, s as F, t as I } from "./storage2.js";
|
|
6
|
+
import { i as L, n as R, r as z, t as B } from "./ui2.js";
|
|
7
|
+
export { L as FuzzyHighlighter, P as bigIntSerializer, j as dateSerializer, A as defaultSerializer, N as mapSerializer, F as setSerializer, b as useBatcher, t as useClickOutside, c as useDebouncedCallback, l as useDebouncedState, f as useDebouncedValue, r as useDebouncer, e as useEventListener, z as useExpansion, w as useFilter, S as useFuzzySearch, O as useGrouping, i as useIntersectionObserver, n as useKey, M as useLocalStorage, E as useMultipleSelection, u as useMutationObserver, x as useOrder, C as usePagination, R as usePin, s as useRateLimitedCallback, o as useRateLimitedState, y as useRateLimitedValue, h as useRateLimiter, g as useResizeObserver, I as useSessionStorage, D as useSingleSelection, T as useSort, a as useThrottledCallback, _ as useThrottledState, m as useThrottledValue, d as useThrottler, k as useTreeSelection, p as useVirtualGrid, v as useVirtualList, B as useVisibility };
|