react-arborist
react-arborist copied to clipboard
Windows: Multi-select should use Ctrl+Click, not Meta+Click
When performing multi-selection with the mouse, the expected behavior (familiar from applications like Windows File Explorer) is to use CTRL + Click to select multiple items.
Currently, react-arborist uses e.metaKey to detect multi-selection, which is standard on macOS but not Windows. This results in an inconsistent user experience on Windows.
Current Behavior
The relevant code can be found here:
https://github.com/brimdata/react-arborist/blob/c851c6f76ad5878f3ea7b68602e9b2f970df142e/modules/react-arborist/src/interfaces/node-api.ts#L199-L208
Expected Behavior
The following diff demonstrates how to modify the handleClick function to correctly handle multi-selection on both macOS and Windows by checking for either e.metaKey (Cmd on macOS) or e.ctrlKey (Ctrl on Windows):
handleClick = (e: React.MouseEvent) => {
- if (e.metaKey && !this.tree.props.disableMultiSelection) {
+ if ((e.metaKey || e.ctrlKey) && !this.tree.props.disableMultiSelection) {
this.isSelected ? this.deselect() : this.selectMulti();
} else if (e.shiftKey && !this.tree.props.disableMultiSelection) {
this.selectContiguous();
} else {
this.select();
this.activate();
}
};
Alternative Solution
An alternative, more flexible solution would be to allow users to customize the selection shortcuts.
I support the proposition made in https://github.com/brimdata/react-arborist/issues/57. While this approach is more involved, it provides greater flexibility.
The proposed change in this issue offers a quick fix for the common Windows use case.
Made the PR, ready for merge: https://github.com/brimdata/react-arborist/pull/304 Deployed Demo: https://react-arborist-showcase.vercel.app/ Tests are passing ✅
For now as a workaround for my project, I use a script that patch the library, and it run in post-install:
import fs from "fs";
import path from "path";
export function patchReactArborist() {
try {
console.log("Patching react-arborist");
const rootDir = "node_modules/react-arborist";
const replaceBefore = "e.metaKey";
const replaceAfter = "(e.metaKey || e.ctrlKey)";
// Function to recursively find and patch files
function findAndPatchFiles(directory: string) {
const files = fs.readdirSync(directory);
for (const file of files) {
const filePath = path.join(directory, file);
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
// Recursively search subdirectories
findAndPatchFiles(filePath);
} else if (
stats.isFile() &&
(file.endsWith(".ts") || file.endsWith(".tsx") || file.endsWith(".js") || file.endsWith(".jsx"))
) {
// Process TypeScript and JavaScript files
const content = fs.readFileSync(filePath, "utf8");
if (content.includes(replaceBefore)) {
const newContent = content.replace(new RegExp(replaceBefore, "g"), replaceAfter);
fs.writeFileSync(filePath, newContent);
console.log(`Patched ${filePath}`);
}
}
}
}
findAndPatchFiles(rootDir);
console.log("Patched react-arborist");
} catch (error) {
console.error("Error patching react-arborist", error);
}
}
Output :
Patching react-arborist
Patched node_modules\react-arborist\dist\main\components\default-container.js
Patched node_modules\react-arborist\dist\main\interfaces\node-api.js
Patched node_modules\react-arborist\dist\module\components\default-container.js
Patched node_modules\react-arborist\dist\module\interfaces\node-api.js
Patched node_modules\react-arborist\src\components\default-container.tsx
Patched node_modules\react-arborist\src\interfaces\node-api.ts
Patched react-arborist
@jameskerr Please review 🙏