react-native-tree-multi-select 1.2.0 → 1.2.3
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/.editorconfig +15 -0
- package/.gitattributes +3 -0
- package/.github/FUNDING.yml +13 -0
- package/.github/ISSUE_TEMPLATE/bug-report.md +42 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
- package/.github/actions/setup/action.yml +28 -0
- package/.github/assets/Jairaj_Jangle_Google_Pay_UPI_QR_Code.jpg +0 -0
- package/.github/assets/paypal_donate.png +0 -0
- package/.github/assets/upi.png +0 -0
- package/.github/workflows/ci.yml +225 -0
- package/.gitignore +73 -0
- package/.nvmrc +1 -0
- package/.watchmanconfig +1 -0
- package/.yarnrc +3 -0
- package/CHANGELOG.md +145 -0
- package/CODE_OF_CONDUCT.md +133 -0
- package/CONTRIBUTING.md +114 -0
- package/README.md +12 -3
- package/babel.config.js +3 -0
- package/example/.bundle/config +2 -0
- package/example/.watchmanconfig +1 -0
- package/example/Gemfile +6 -0
- package/example/README.md +79 -0
- package/example/android/app/build.gradle +130 -0
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +10 -0
- package/example/android/app/src/debug/AndroidManifest.xml +13 -0
- package/example/android/app/src/debug/java/com/treemultiselectexample/ReactNativeFlipper.java +75 -0
- package/example/android/app/src/main/AndroidManifest.xml +25 -0
- package/example/android/app/src/main/java/com/treemultiselectexample/MainActivity.java +32 -0
- package/example/android/app/src/main/java/com/treemultiselectexample/MainApplication.java +62 -0
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +3 -0
- package/example/android/app/src/main/res/values/styles.xml +9 -0
- package/example/android/app/src/release/java/com/treemultiselectexample/ReactNativeFlipper.java +20 -0
- package/example/android/build.gradle +23 -0
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +6 -0
- package/example/android/gradle.properties +44 -0
- package/example/android/gradlew +244 -0
- package/example/android/gradlew.bat +92 -0
- package/example/android/settings.gradle +4 -0
- package/example/app.json +4 -0
- package/example/babel.config.js +17 -0
- package/example/index.js +5 -0
- package/example/ios/.xcode.env +11 -0
- package/example/ios/File.swift +6 -0
- package/example/ios/Podfile +62 -0
- package/example/ios/Podfile.lock +639 -0
- package/example/ios/TreeMultiSelectExample/AppDelegate.h +6 -0
- package/example/ios/TreeMultiSelectExample/AppDelegate.mm +26 -0
- package/example/ios/TreeMultiSelectExample/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/example/ios/TreeMultiSelectExample/Images.xcassets/Contents.json +6 -0
- package/example/ios/TreeMultiSelectExample/Info.plist +74 -0
- package/example/ios/TreeMultiSelectExample/LaunchScreen.storyboard +47 -0
- package/example/ios/TreeMultiSelectExample/main.m +10 -0
- package/example/ios/TreeMultiSelectExample-Bridging-Header.h +3 -0
- package/example/ios/TreeMultiSelectExample.xcodeproj/project.pbxproj +706 -0
- package/example/ios/TreeMultiSelectExample.xcodeproj/xcshareddata/xcschemes/TreeMultiSelectExample.xcscheme +88 -0
- package/example/ios/TreeMultiSelectExample.xcworkspace/contents.xcworkspacedata +10 -0
- package/example/ios/TreeMultiSelectExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/example/ios/TreeMultiSelectExampleTests/Info.plist +24 -0
- package/example/ios/TreeMultiSelectExampleTests/TreeMultiSelectExampleTests.m +66 -0
- package/example/metro.config.js +45 -0
- package/example/package.json +41 -0
- package/example/react-native.config.js +10 -0
- package/example/src/App.tsx +70 -0
- package/example/src/components/CustomArrow.tsx +71 -0
- package/example/src/components/CustomCheckboxView.tsx +119 -0
- package/example/src/components/CustomNodeRowView.tsx +124 -0
- package/example/src/components/SearchInput.tsx +68 -0
- package/example/src/screens/CustomArrowScreen.tsx +99 -0
- package/example/src/screens/CustomCheckboxScreen.tsx +99 -0
- package/example/src/screens/CustomNodeRowViewScreen.tsx +99 -0
- package/example/src/screens/LargeDataScreen.tsx +95 -0
- package/example/src/screens/MediumDataScreen.tsx +96 -0
- package/example/src/screens/SmallDataScreen.tsx +96 -0
- package/example/src/screens/screens.styles.ts +25 -0
- package/example/src/utils/sampleDataGenerator.ts +32 -0
- package/example/yarn.lock +6368 -0
- package/lefthook.yml +17 -0
- package/lib/commonjs/TreeView.js +13 -3
- package/lib/commonjs/TreeView.js.map +1 -1
- package/lib/commonjs/helpers/expandCollapse.helper.js +88 -21
- package/lib/commonjs/helpers/expandCollapse.helper.js.map +1 -1
- package/lib/commonjs/helpers/toggleCheckbox.helper.js +0 -1
- package/lib/commonjs/helpers/toggleCheckbox.helper.js.map +1 -1
- package/lib/commonjs/utils/usePreviousState.js +20 -0
- package/lib/commonjs/utils/usePreviousState.js.map +1 -0
- package/lib/module/TreeView.js +14 -4
- package/lib/module/TreeView.js.map +1 -1
- package/lib/module/helpers/expandCollapse.helper.js +86 -21
- package/lib/module/helpers/expandCollapse.helper.js.map +1 -1
- package/lib/module/helpers/toggleCheckbox.helper.js +0 -1
- package/lib/module/helpers/toggleCheckbox.helper.js.map +1 -1
- package/lib/module/utils/usePreviousState.js +15 -0
- package/lib/module/utils/usePreviousState.js.map +1 -0
- package/lib/typescript/TreeView.d.ts.map +1 -1
- package/lib/typescript/__mocks__/generateTree.mock.d.ts +17 -0
- package/lib/typescript/__mocks__/generateTree.mock.d.ts.map +1 -0
- package/lib/typescript/__mocks__/zustand.d.ts +3 -0
- package/lib/typescript/__mocks__/zustand.d.ts.map +1 -0
- package/lib/typescript/__tests__/expandCollapse.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/expandCollapse.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/flattenTree.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/flattenTree.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/initNodeMap.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/initNodeMap.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/search.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/search.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/selectAll.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/selectAll.helper.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/store.test.d.ts +2 -0
- package/lib/typescript/__tests__/store.test.d.ts.map +1 -0
- package/lib/typescript/__tests__/toggleCheckbox.helper.test.d.ts +2 -0
- package/lib/typescript/__tests__/toggleCheckbox.helper.test.d.ts.map +1 -0
- package/lib/typescript/helpers/expandCollapse.helper.d.ts +12 -0
- package/lib/typescript/helpers/expandCollapse.helper.d.ts.map +1 -1
- package/lib/typescript/types/treeView.types.d.ts +3 -0
- package/lib/typescript/types/treeView.types.d.ts.map +1 -1
- package/lib/typescript/utils/usePreviousState.d.ts +7 -0
- package/lib/typescript/utils/usePreviousState.d.ts.map +1 -0
- package/package.json +5 -3
- package/scripts/bootstrap.js +29 -0
- package/src/TreeView.tsx +25 -4
- package/src/__mocks__/generateTree.mock.ts +125 -0
- package/src/__mocks__/zustand.ts +24 -0
- package/src/__tests__/expandCollapse.helper.test.ts +189 -0
- package/src/__tests__/flattenTree.helper.test.ts +78 -0
- package/src/__tests__/initNodeMap.helper.test.ts +46 -0
- package/src/__tests__/search.helper.test.ts +47 -0
- package/src/__tests__/selectAll.helper.test.ts +233 -0
- package/src/__tests__/store.test.ts +208 -0
- package/src/__tests__/toggleCheckbox.helper.test.ts +124 -0
- package/src/helpers/expandCollapse.helper.ts +82 -21
- package/src/helpers/toggleCheckbox.helper.ts +1 -1
- package/src/types/treeView.types.ts +5 -0
- package/src/utils/usePreviousState.ts +16 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +31 -0
- package/turbo.json +34 -0
- package/yarn.lock +9953 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Scheme
|
|
3
|
+
LastUpgradeVersion = "1210"
|
|
4
|
+
version = "1.3">
|
|
5
|
+
<BuildAction
|
|
6
|
+
parallelizeBuildables = "YES"
|
|
7
|
+
buildImplicitDependencies = "YES">
|
|
8
|
+
<BuildActionEntries>
|
|
9
|
+
<BuildActionEntry
|
|
10
|
+
buildForTesting = "YES"
|
|
11
|
+
buildForRunning = "YES"
|
|
12
|
+
buildForProfiling = "YES"
|
|
13
|
+
buildForArchiving = "YES"
|
|
14
|
+
buildForAnalyzing = "YES">
|
|
15
|
+
<BuildableReference
|
|
16
|
+
BuildableIdentifier = "primary"
|
|
17
|
+
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
|
18
|
+
BuildableName = "TreeMultiSelectExample.app"
|
|
19
|
+
BlueprintName = "TreeMultiSelectExample"
|
|
20
|
+
ReferencedContainer = "container:TreeMultiSelectExample.xcodeproj">
|
|
21
|
+
</BuildableReference>
|
|
22
|
+
</BuildActionEntry>
|
|
23
|
+
</BuildActionEntries>
|
|
24
|
+
</BuildAction>
|
|
25
|
+
<TestAction
|
|
26
|
+
buildConfiguration = "Debug"
|
|
27
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
28
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
29
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
30
|
+
<Testables>
|
|
31
|
+
<TestableReference
|
|
32
|
+
skipped = "NO">
|
|
33
|
+
<BuildableReference
|
|
34
|
+
BuildableIdentifier = "primary"
|
|
35
|
+
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
|
|
36
|
+
BuildableName = "TreeMultiSelectExampleTests.xctest"
|
|
37
|
+
BlueprintName = "TreeMultiSelectExampleTests"
|
|
38
|
+
ReferencedContainer = "container:TreeMultiSelectExample.xcodeproj">
|
|
39
|
+
</BuildableReference>
|
|
40
|
+
</TestableReference>
|
|
41
|
+
</Testables>
|
|
42
|
+
</TestAction>
|
|
43
|
+
<LaunchAction
|
|
44
|
+
buildConfiguration = "Debug"
|
|
45
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
46
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
47
|
+
launchStyle = "0"
|
|
48
|
+
useCustomWorkingDirectory = "NO"
|
|
49
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
50
|
+
debugDocumentVersioning = "YES"
|
|
51
|
+
debugServiceExtension = "internal"
|
|
52
|
+
allowLocationSimulation = "YES">
|
|
53
|
+
<BuildableProductRunnable
|
|
54
|
+
runnableDebuggingMode = "0">
|
|
55
|
+
<BuildableReference
|
|
56
|
+
BuildableIdentifier = "primary"
|
|
57
|
+
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
|
58
|
+
BuildableName = "TreeMultiSelectExample.app"
|
|
59
|
+
BlueprintName = "TreeMultiSelectExample"
|
|
60
|
+
ReferencedContainer = "container:TreeMultiSelectExample.xcodeproj">
|
|
61
|
+
</BuildableReference>
|
|
62
|
+
</BuildableProductRunnable>
|
|
63
|
+
</LaunchAction>
|
|
64
|
+
<ProfileAction
|
|
65
|
+
buildConfiguration = "Release"
|
|
66
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
67
|
+
savedToolIdentifier = ""
|
|
68
|
+
useCustomWorkingDirectory = "NO"
|
|
69
|
+
debugDocumentVersioning = "YES">
|
|
70
|
+
<BuildableProductRunnable
|
|
71
|
+
runnableDebuggingMode = "0">
|
|
72
|
+
<BuildableReference
|
|
73
|
+
BuildableIdentifier = "primary"
|
|
74
|
+
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
|
|
75
|
+
BuildableName = "TreeMultiSelectExample.app"
|
|
76
|
+
BlueprintName = "TreeMultiSelectExample"
|
|
77
|
+
ReferencedContainer = "container:TreeMultiSelectExample.xcodeproj">
|
|
78
|
+
</BuildableReference>
|
|
79
|
+
</BuildableProductRunnable>
|
|
80
|
+
</ProfileAction>
|
|
81
|
+
<AnalyzeAction
|
|
82
|
+
buildConfiguration = "Debug">
|
|
83
|
+
</AnalyzeAction>
|
|
84
|
+
<ArchiveAction
|
|
85
|
+
buildConfiguration = "Release"
|
|
86
|
+
revealArchiveInOrganizer = "YES">
|
|
87
|
+
</ArchiveAction>
|
|
88
|
+
</Scheme>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>en</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>BNDL</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleSignature</key>
|
|
20
|
+
<string>????</string>
|
|
21
|
+
<key>CFBundleVersion</key>
|
|
22
|
+
<string>1</string>
|
|
23
|
+
</dict>
|
|
24
|
+
</plist>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
#import <XCTest/XCTest.h>
|
|
3
|
+
|
|
4
|
+
#import <React/RCTLog.h>
|
|
5
|
+
#import <React/RCTRootView.h>
|
|
6
|
+
|
|
7
|
+
#define TIMEOUT_SECONDS 600
|
|
8
|
+
#define TEXT_TO_LOOK_FOR @"Welcome to React"
|
|
9
|
+
|
|
10
|
+
@interface TreeMultiSelectExampleTests : XCTestCase
|
|
11
|
+
|
|
12
|
+
@end
|
|
13
|
+
|
|
14
|
+
@implementation TreeMultiSelectExampleTests
|
|
15
|
+
|
|
16
|
+
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
|
|
17
|
+
{
|
|
18
|
+
if (test(view)) {
|
|
19
|
+
return YES;
|
|
20
|
+
}
|
|
21
|
+
for (UIView *subview in [view subviews]) {
|
|
22
|
+
if ([self findSubviewInView:subview matching:test]) {
|
|
23
|
+
return YES;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return NO;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
- (void)testRendersWelcomeScreen
|
|
30
|
+
{
|
|
31
|
+
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
|
|
32
|
+
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
|
|
33
|
+
BOOL foundElement = NO;
|
|
34
|
+
|
|
35
|
+
__block NSString *redboxError = nil;
|
|
36
|
+
#ifdef DEBUG
|
|
37
|
+
RCTSetLogFunction(
|
|
38
|
+
^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
|
|
39
|
+
if (level >= RCTLogLevelError) {
|
|
40
|
+
redboxError = message;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
|
|
46
|
+
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
|
47
|
+
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
|
48
|
+
|
|
49
|
+
foundElement = [self findSubviewInView:vc.view
|
|
50
|
+
matching:^BOOL(UIView *view) {
|
|
51
|
+
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
|
|
52
|
+
return YES;
|
|
53
|
+
}
|
|
54
|
+
return NO;
|
|
55
|
+
}];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#ifdef DEBUG
|
|
59
|
+
RCTSetLogFunction(RCTDefaultLogFunction);
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
|
|
63
|
+
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const escape = require('escape-string-regexp');
|
|
4
|
+
const exclusionList = require('metro-config/src/defaults/exclusionList');
|
|
5
|
+
const pak = require('../package.json');
|
|
6
|
+
|
|
7
|
+
const root = path.resolve(__dirname, '..');
|
|
8
|
+
const modules = Object.keys({ ...pak.peerDependencies });
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Metro configuration
|
|
12
|
+
* https://facebook.github.io/metro/docs/configuration
|
|
13
|
+
*
|
|
14
|
+
* @type {import('metro-config').MetroConfig}
|
|
15
|
+
*/
|
|
16
|
+
const config = {
|
|
17
|
+
watchFolders: [root],
|
|
18
|
+
|
|
19
|
+
// We need to make sure that only one version is loaded for peerDependencies
|
|
20
|
+
// So we block them at the root, and alias them to the versions in example's node_modules
|
|
21
|
+
resolver: {
|
|
22
|
+
blacklistRE: exclusionList(
|
|
23
|
+
modules.map(
|
|
24
|
+
(m) =>
|
|
25
|
+
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
|
|
26
|
+
)
|
|
27
|
+
),
|
|
28
|
+
|
|
29
|
+
extraNodeModules: modules.reduce((acc, name) => {
|
|
30
|
+
acc[name] = path.join(__dirname, 'node_modules', name);
|
|
31
|
+
return acc;
|
|
32
|
+
}, {}),
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
transformer: {
|
|
36
|
+
getTransformOptions: async () => ({
|
|
37
|
+
transform: {
|
|
38
|
+
experimentalImportSupport: false,
|
|
39
|
+
inlineRequires: true,
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tree-multi-select-example",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"android": "react-native run-android",
|
|
7
|
+
"ios": "react-native run-ios",
|
|
8
|
+
"ios_ip_14": "react-native run-ios --simulator=\"iPhone 14 Pro\"",
|
|
9
|
+
"start": "react-native start",
|
|
10
|
+
"pods": "pod-install --quiet"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@gorhom/showcase-template": "^2.1.0",
|
|
14
|
+
"@react-navigation/native": "^6.1.7",
|
|
15
|
+
"@react-navigation/native-stack": "^6.9.15",
|
|
16
|
+
"@react-navigation/stack": "^6.3.17",
|
|
17
|
+
"@shopify/flash-list": "^1.4.3",
|
|
18
|
+
"lodash": "^4.17.21",
|
|
19
|
+
"react": "18.2.0",
|
|
20
|
+
"react-native": "0.72.1",
|
|
21
|
+
"react-native-gesture-handler": "^2.12.0",
|
|
22
|
+
"react-native-paper": "^5.9.1",
|
|
23
|
+
"react-native-safe-area-context": "^4.7.1",
|
|
24
|
+
"react-native-screens": "^3.22.1",
|
|
25
|
+
"react-native-vector-icons": "^9.2.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@babel/core": "^7.20.0",
|
|
29
|
+
"@babel/preset-env": "^7.20.0",
|
|
30
|
+
"@babel/runtime": "^7.20.0",
|
|
31
|
+
"@react-native/eslint-config": "^0.72.2",
|
|
32
|
+
"@react-native/metro-config": "^0.72.7",
|
|
33
|
+
"@types/lodash": "^4.14.195",
|
|
34
|
+
"@types/metro-config": "^0.76.3",
|
|
35
|
+
"babel-plugin-module-resolver": "^5.0.0",
|
|
36
|
+
"metro-react-native-babel-preset": "0.76.5"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import SmallDataScreen from './screens/SmallDataScreen';
|
|
4
|
+
import { ShowcaseApp } from '@gorhom/showcase-template';
|
|
5
|
+
import {
|
|
6
|
+
ShowcaseExampleScreenSectionType
|
|
7
|
+
} from '@gorhom/showcase-template/lib/typescript/types';
|
|
8
|
+
import MediumDataScreen from './screens/MediumDataScreen';
|
|
9
|
+
import LargeDataScreen from './screens/LargeDataScreen';
|
|
10
|
+
import CustomCheckboxScreen from './screens/CustomCheckboxScreen';
|
|
11
|
+
import CustomArrowScreen from './screens/CustomArrowScreen';
|
|
12
|
+
import CustomNodeRowViewScreen from './screens/CustomNodeRowViewScreen';
|
|
13
|
+
|
|
14
|
+
const data: ShowcaseExampleScreenSectionType[] = [
|
|
15
|
+
{
|
|
16
|
+
title: 'Default UI',
|
|
17
|
+
data: [
|
|
18
|
+
{
|
|
19
|
+
name: 'Small Data',
|
|
20
|
+
slug: 'small-data',
|
|
21
|
+
getScreen: () => SmallDataScreen,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Medium Data',
|
|
25
|
+
slug: 'medium-data',
|
|
26
|
+
getScreen: () => MediumDataScreen,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Large Data',
|
|
30
|
+
slug: 'large-data',
|
|
31
|
+
getScreen: () => LargeDataScreen,
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: 'Customizations',
|
|
37
|
+
data: [
|
|
38
|
+
{
|
|
39
|
+
name: 'Custom Checkbox',
|
|
40
|
+
slug: 'custom-checkbox',
|
|
41
|
+
getScreen: () => CustomCheckboxScreen,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Custom Arrow',
|
|
45
|
+
slug: 'custom-arrow',
|
|
46
|
+
getScreen: () => CustomArrowScreen,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Custom Row Item',
|
|
50
|
+
slug: 'custom-row-item',
|
|
51
|
+
getScreen: () => CustomNodeRowViewScreen,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
export default function App() {
|
|
58
|
+
return (
|
|
59
|
+
<ShowcaseApp
|
|
60
|
+
version="1.0.0"
|
|
61
|
+
name="react-native-tree-multi-select"
|
|
62
|
+
description="⚡️Super-fast tree view with multi-selection capabilities, using checkboxes and search filtering"
|
|
63
|
+
author={{
|
|
64
|
+
username: '@JairajJangle',
|
|
65
|
+
url: 'https://github.com/JairajJangle',
|
|
66
|
+
}}
|
|
67
|
+
data={data}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
3
|
+
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
4
|
+
|
|
5
|
+
import { ExpandIconProps } from "src/types/treeView.types";
|
|
6
|
+
|
|
7
|
+
export const CustomArrow = React.memo(_CustomArrow);
|
|
8
|
+
|
|
9
|
+
function _CustomArrow(props: ExpandIconProps) {
|
|
10
|
+
const { isExpanded } = props;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<View
|
|
14
|
+
style={styles.mainView}>
|
|
15
|
+
<View
|
|
16
|
+
style={[
|
|
17
|
+
styles.innerView,
|
|
18
|
+
isExpanded
|
|
19
|
+
? styles.innerViewExpanded
|
|
20
|
+
: styles.innerViewCollapsed
|
|
21
|
+
]}>
|
|
22
|
+
<Icon
|
|
23
|
+
name={
|
|
24
|
+
isExpanded
|
|
25
|
+
? 'arrow-collapse-vertical'
|
|
26
|
+
: 'arrow-expand-vertical'
|
|
27
|
+
}
|
|
28
|
+
size={25}
|
|
29
|
+
color={isExpanded ? "black" : "white"}
|
|
30
|
+
/>
|
|
31
|
+
<Text
|
|
32
|
+
style={[styles.text,
|
|
33
|
+
isExpanded
|
|
34
|
+
? styles.textExpanded
|
|
35
|
+
: styles.textCollapsed
|
|
36
|
+
]}>
|
|
37
|
+
{isExpanded ? "Collapse" : "Expand"}
|
|
38
|
+
</Text>
|
|
39
|
+
</View>
|
|
40
|
+
</View>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const styles = StyleSheet.create({
|
|
45
|
+
mainView: {
|
|
46
|
+
flexDirection: 'row',
|
|
47
|
+
marginVertical: 5
|
|
48
|
+
},
|
|
49
|
+
innerView: {
|
|
50
|
+
flexDirection: 'row',
|
|
51
|
+
alignItems: "center",
|
|
52
|
+
borderWidth: 1,
|
|
53
|
+
borderRadius: 10,
|
|
54
|
+
padding: 2,
|
|
55
|
+
},
|
|
56
|
+
innerViewExpanded: {
|
|
57
|
+
backgroundColor: "white"
|
|
58
|
+
},
|
|
59
|
+
innerViewCollapsed: {
|
|
60
|
+
backgroundColor: "black"
|
|
61
|
+
},
|
|
62
|
+
text: {
|
|
63
|
+
fontSize: 10,
|
|
64
|
+
},
|
|
65
|
+
textExpanded: {
|
|
66
|
+
color: "black",
|
|
67
|
+
},
|
|
68
|
+
textCollapsed: {
|
|
69
|
+
color: "white",
|
|
70
|
+
}
|
|
71
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ColorValue,
|
|
4
|
+
Platform,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
Text,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
View
|
|
9
|
+
} from "react-native";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
CheckBoxViewProps,
|
|
13
|
+
} from "react-native-tree-multi-select";
|
|
14
|
+
|
|
15
|
+
function arePropsEqual(
|
|
16
|
+
prevProps: CheckBoxViewProps,
|
|
17
|
+
nextProps: CheckBoxViewProps
|
|
18
|
+
) {
|
|
19
|
+
return (
|
|
20
|
+
prevProps.value === nextProps.value &&
|
|
21
|
+
prevProps.text === nextProps.text
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const CustomCheckboxView = React.memo(_CustomCheckboxView, arePropsEqual);
|
|
26
|
+
|
|
27
|
+
function _CustomCheckboxView(props: CheckBoxViewProps) {
|
|
28
|
+
const {
|
|
29
|
+
value,
|
|
30
|
+
onValueChange,
|
|
31
|
+
text,
|
|
32
|
+
} = props;
|
|
33
|
+
|
|
34
|
+
const getCheckboxColor: () => ColorValue = useCallback(() => {
|
|
35
|
+
return (
|
|
36
|
+
value === "indeterminate"
|
|
37
|
+
? "yellow"
|
|
38
|
+
: value
|
|
39
|
+
? "green"
|
|
40
|
+
: "red"
|
|
41
|
+
);
|
|
42
|
+
}, [value]);
|
|
43
|
+
|
|
44
|
+
const getCheckboxText = useCallback(() => {
|
|
45
|
+
return (
|
|
46
|
+
value === "indeterminate"
|
|
47
|
+
? "😐"
|
|
48
|
+
: value
|
|
49
|
+
? "😃"
|
|
50
|
+
: "😶"
|
|
51
|
+
);
|
|
52
|
+
}, [value]);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* This function modifies the change in value when the previous state was indeterminate.
|
|
56
|
+
* If the prior value is 'indeterminate', it will mark the CheckBox as checked upon click.
|
|
57
|
+
*
|
|
58
|
+
* @param newValue This represents the updated CheckBox value after it's clicked.
|
|
59
|
+
*/
|
|
60
|
+
function onValueChangeModifier() {
|
|
61
|
+
// If the previous state was 'indeterminate', set checked to true
|
|
62
|
+
if (value === 'indeterminate') onValueChange(true);
|
|
63
|
+
else onValueChange(!value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<View
|
|
68
|
+
style={styles.mainView}>
|
|
69
|
+
|
|
70
|
+
<TouchableOpacity
|
|
71
|
+
style={[styles.checkboxTouchable,
|
|
72
|
+
{
|
|
73
|
+
borderColor: getCheckboxColor()
|
|
74
|
+
}]}
|
|
75
|
+
onPress={onValueChangeModifier}>
|
|
76
|
+
<Text
|
|
77
|
+
style={styles.checkboxView}>
|
|
78
|
+
{getCheckboxText()}
|
|
79
|
+
</Text>
|
|
80
|
+
</TouchableOpacity>
|
|
81
|
+
|
|
82
|
+
{text ? (
|
|
83
|
+
<TouchableOpacity
|
|
84
|
+
onPress={onValueChangeModifier}>
|
|
85
|
+
<Text
|
|
86
|
+
style={styles.checkboxTextStyle}
|
|
87
|
+
numberOfLines={1}>
|
|
88
|
+
{text}
|
|
89
|
+
</Text>
|
|
90
|
+
</TouchableOpacity>
|
|
91
|
+
) : null}
|
|
92
|
+
</View>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const styles = StyleSheet.create({
|
|
97
|
+
mainView: {
|
|
98
|
+
alignSelf: 'center',
|
|
99
|
+
alignItems: 'center',
|
|
100
|
+
flexDirection: 'row',
|
|
101
|
+
|
|
102
|
+
marginEnd: 10
|
|
103
|
+
},
|
|
104
|
+
checkboxTouchable: {
|
|
105
|
+
marginVertical: 4,
|
|
106
|
+
marginEnd: 5,
|
|
107
|
+
marginStart: 10,
|
|
108
|
+
borderWidth: 5,
|
|
109
|
+
borderRadius: 45,
|
|
110
|
+
},
|
|
111
|
+
checkboxView: {
|
|
112
|
+
fontSize: 30,
|
|
113
|
+
margin: -4
|
|
114
|
+
},
|
|
115
|
+
checkboxTextStyle: {
|
|
116
|
+
color: "black",
|
|
117
|
+
marginTop: Platform.OS === 'android' ? 2 : undefined,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TouchableOpacity, View, Text, StyleSheet } from "react-native";
|
|
3
|
+
import { NodeRowProps } from "react-native-tree-multi-select";
|
|
4
|
+
import Icon from 'react-native-vector-icons/FontAwesome';
|
|
5
|
+
|
|
6
|
+
export const CustomNodeRowView = React.memo(_CustomNodeRowView);
|
|
7
|
+
|
|
8
|
+
const VerticalLine = () => (
|
|
9
|
+
<View style={styles.verticalLineStyle} />
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const Levels = ({
|
|
13
|
+
levels
|
|
14
|
+
}: {
|
|
15
|
+
levels: number;
|
|
16
|
+
}) => {
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.levelsStyle}>
|
|
19
|
+
{
|
|
20
|
+
Array(levels).fill(null).map((_, i) => <VerticalLine key={i} />)
|
|
21
|
+
}
|
|
22
|
+
</View>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function _CustomNodeRowView(props: NodeRowProps) {
|
|
27
|
+
const { node, level, checkedValue, isExpanded, onCheck, onExpand } = props;
|
|
28
|
+
|
|
29
|
+
const backgroundColor =
|
|
30
|
+
checkedValue === true
|
|
31
|
+
? "black"
|
|
32
|
+
: checkedValue === "indeterminate"
|
|
33
|
+
? "lightgrey"
|
|
34
|
+
: "white";
|
|
35
|
+
const color =
|
|
36
|
+
checkedValue === true ? "white" : undefined;
|
|
37
|
+
const iconColor =
|
|
38
|
+
checkedValue === true
|
|
39
|
+
? isExpanded ? "white" : "#9a9a9a"
|
|
40
|
+
: isExpanded ? "black" : "#a1a1a1";
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<View style={[styles.rowView, { backgroundColor }]}>
|
|
46
|
+
<View style={styles.innerRowView}>
|
|
47
|
+
<Levels levels={level} />
|
|
48
|
+
|
|
49
|
+
<TouchableOpacity style={styles.touchableOpacity} onPress={onCheck}>
|
|
50
|
+
<View style={
|
|
51
|
+
level === 0
|
|
52
|
+
? styles.textViewMarginNegative
|
|
53
|
+
: styles.textView
|
|
54
|
+
}>
|
|
55
|
+
<Text style={{ color }}>{node.name}</Text>
|
|
56
|
+
</View>
|
|
57
|
+
</TouchableOpacity>
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
node.children?.length ? (
|
|
61
|
+
<TouchableOpacity
|
|
62
|
+
style={styles.iconTouchableView}
|
|
63
|
+
onPress={onExpand}>
|
|
64
|
+
<Icon
|
|
65
|
+
name={
|
|
66
|
+
isExpanded
|
|
67
|
+
? 'angle-double-up'
|
|
68
|
+
: 'angle-double-down'
|
|
69
|
+
}
|
|
70
|
+
size={25}
|
|
71
|
+
color={iconColor}
|
|
72
|
+
/>
|
|
73
|
+
</TouchableOpacity>
|
|
74
|
+
) : null
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
</View>
|
|
78
|
+
</View >
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const styles = StyleSheet.create({
|
|
83
|
+
verticalLineStyle: {
|
|
84
|
+
borderLeftWidth: 1,
|
|
85
|
+
height: '110%',
|
|
86
|
+
marginStart: 25,
|
|
87
|
+
borderColor: "grey",
|
|
88
|
+
},
|
|
89
|
+
levelsStyle: {
|
|
90
|
+
flexDirection: 'row',
|
|
91
|
+
marginEnd: 10
|
|
92
|
+
},
|
|
93
|
+
rowView: {
|
|
94
|
+
marginHorizontal: 10,
|
|
95
|
+
paddingEnd: 10,
|
|
96
|
+
marginVertical: 0.5,
|
|
97
|
+
flex: 1,
|
|
98
|
+
flexDirection: 'row',
|
|
99
|
+
alignItems: 'center',
|
|
100
|
+
justifyContent: "space-between",
|
|
101
|
+
borderColor: "lightgrey",
|
|
102
|
+
borderTopWidth: 1,
|
|
103
|
+
borderTopColor: "#dedede"
|
|
104
|
+
},
|
|
105
|
+
innerRowView: {
|
|
106
|
+
flexDirection: "row",
|
|
107
|
+
},
|
|
108
|
+
touchableOpacity: {
|
|
109
|
+
padding: 4,
|
|
110
|
+
paddingVertical: 8,
|
|
111
|
+
},
|
|
112
|
+
textView: {
|
|
113
|
+
flexDirection: "row"
|
|
114
|
+
},
|
|
115
|
+
textViewMarginNegative: {
|
|
116
|
+
flexDirection: "row",
|
|
117
|
+
marginStart: -5
|
|
118
|
+
},
|
|
119
|
+
iconTouchableView: {
|
|
120
|
+
flex: 1,
|
|
121
|
+
alignItems: "flex-end",
|
|
122
|
+
justifyContent: "center",
|
|
123
|
+
}
|
|
124
|
+
});
|