Skip to content

Commit cf845d7

Browse files
committed
feat: loadingCheckPropagationItems state
1 parent 597faad commit cf845d7

File tree

4 files changed

+74
-32
lines changed

4 files changed

+74
-32
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@headless-tree/core": patch
3+
---
4+
5+
Added new state variable `loadingCheckPropagationItems` to indicate if, in async trees with checkboxes and state propagation enabled, data loading operations are currently loading due to a checkbox propagation taking place

packages/core/src/features/checkboxes/feature.ts

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,32 @@ const getAllDescendants = async <T>(
3838
return includeFolders ? [itemId, ...descendants] : descendants;
3939
};
4040

41+
const withLoadingState = async <T>(
42+
tree: TreeInstance<T>,
43+
itemId: string,
44+
callback: () => Promise<void>,
45+
) => {
46+
tree.applySubStateUpdate("loadingCheckPropagationItems", (items) => [
47+
...items,
48+
itemId,
49+
]);
50+
try {
51+
await callback();
52+
} finally {
53+
tree.applySubStateUpdate("loadingCheckPropagationItems", (items) =>
54+
items.filter((id) => id !== itemId),
55+
);
56+
}
57+
};
58+
4159
export const checkboxesFeature: FeatureImplementation = {
4260
key: "checkboxes",
4361

4462
overwrites: ["selection"],
4563

4664
getInitialState: (initialState) => ({
4765
checkedItems: [],
66+
loadingCheckPropagationItems: [],
4867
...initialState,
4968
}),
5069

@@ -61,6 +80,10 @@ export const checkboxesFeature: FeatureImplementation = {
6180
defaultConfig.canCheckFolders ?? !propagateCheckedState;
6281
return {
6382
setCheckedItems: makeStateUpdater("checkedItems", tree),
83+
setLoadingCheckPropagationItems: makeStateUpdater(
84+
"loadingCheckPropagationItems",
85+
tree,
86+
),
6487
propagateCheckedState,
6588
canCheckFolders,
6689
...defaultConfig,
@@ -69,6 +92,7 @@ export const checkboxesFeature: FeatureImplementation = {
6992

7093
stateHandlerNames: {
7194
checkedItems: "setCheckedItems",
95+
loadingCheckPropagationItems: "setLoadingCheckPropagationItems",
7296
},
7397

7498
treeInstance: {
@@ -123,38 +147,45 @@ export const checkboxesFeature: FeatureImplementation = {
123147
},
124148

125149
setChecked: async ({ item, tree, itemId }) => {
126-
const { propagateCheckedState, canCheckFolders } = tree.getConfig();
127-
if (item.isFolder() && propagateCheckedState) {
128-
const descendants = await getAllDescendants(
129-
tree,
130-
itemId,
131-
canCheckFolders,
132-
);
133-
tree.applySubStateUpdate("checkedItems", (items) => [
134-
...items,
135-
...descendants,
136-
]);
137-
} else if (!item.isFolder() || canCheckFolders) {
138-
tree.applySubStateUpdate("checkedItems", (items) => [...items, itemId]);
139-
}
150+
await withLoadingState(tree, itemId, async () => {
151+
const { propagateCheckedState, canCheckFolders } = tree.getConfig();
152+
if (item.isFolder() && propagateCheckedState) {
153+
const descendants = await getAllDescendants(
154+
tree,
155+
itemId,
156+
canCheckFolders,
157+
);
158+
tree.applySubStateUpdate("checkedItems", (items) => [
159+
...items,
160+
...descendants,
161+
]);
162+
} else if (!item.isFolder() || canCheckFolders) {
163+
tree.applySubStateUpdate("checkedItems", (items) => [
164+
...items,
165+
itemId,
166+
]);
167+
}
168+
});
140169
},
141170

142171
setUnchecked: async ({ item, tree, itemId }) => {
143-
const { propagateCheckedState, canCheckFolders } = tree.getConfig();
144-
if (item.isFolder() && propagateCheckedState) {
145-
const descendants = await getAllDescendants(
146-
tree,
147-
itemId,
148-
canCheckFolders,
149-
);
150-
tree.applySubStateUpdate("checkedItems", (items) =>
151-
items.filter((id) => !descendants.includes(id) && id !== itemId),
152-
);
153-
} else {
154-
tree.applySubStateUpdate("checkedItems", (items) =>
155-
items.filter((id) => id !== itemId),
156-
);
157-
}
172+
await withLoadingState(tree, itemId, async () => {
173+
const { propagateCheckedState, canCheckFolders } = tree.getConfig();
174+
if (item.isFolder() && propagateCheckedState) {
175+
const descendants = await getAllDescendants(
176+
tree,
177+
itemId,
178+
canCheckFolders,
179+
);
180+
tree.applySubStateUpdate("checkedItems", (items) =>
181+
items.filter((id) => !descendants.includes(id) && id !== itemId),
182+
);
183+
} else {
184+
tree.applySubStateUpdate("checkedItems", (items) =>
185+
items.filter((id) => id !== itemId),
186+
);
187+
}
188+
});
158189
},
159190
},
160191
};

packages/core/src/features/checkboxes/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export enum CheckedState {
99
export type CheckboxesFeatureDef<T> = {
1010
state: {
1111
checkedItems: string[];
12+
loadingCheckPropagationItems: string[];
1213
};
1314
config: {
1415
setCheckedItems?: SetStateFn<string[]>;
16+
setLoadingCheckPropagationItems?: SetStateFn<string[]>;
1517
canCheckFolders?: boolean;
1618
propagateCheckedState?: boolean;
1719
};
@@ -33,6 +35,8 @@ export type CheckboxesFeatureDef<T> = {
3335

3436
getCheckedState: () => CheckedState;
3537
getCheckboxProps: () => Record<string, any>;
38+
39+
isLoadingCheckPropagation: () => boolean;
3640
};
3741
hotkeys: never;
3842
};

packages/sb-react/src/checkboxes/async-configurability.stories.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ export const AsyncConfigurability = () => {
8282
</button>
8383
{!tree
8484
.getState()
85-
.loadingItemChildrens.some((child) =>
86-
tree.getItemInstance(child).isDescendentOf(item.getId()),
87-
) ? (
85+
.loadingCheckPropagationItems.includes(item.getId()) ? (
8886
<input type="checkbox" {...item.getCheckboxProps()} />
8987
) : (
9088
<>Loading</>
@@ -100,6 +98,10 @@ export const AsyncConfigurability = () => {
10098
<pre>
10199
Loading Item Data: {JSON.stringify(tree.getState().loadingItemData)}
102100
</pre>
101+
<pre>
102+
Loading Checkbox propagation:{" "}
103+
{JSON.stringify(tree.getState().loadingCheckPropagationItems)}
104+
</pre>
103105
</>
104106
);
105107
};

0 commit comments

Comments
 (0)