react-native-platform-components 0.0.2
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/LICENSE +20 -0
- package/PlatformComponents.podspec +20 -0
- package/README.md +233 -0
- package/android/build.gradle +78 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/platformcomponents/DateConstraints.kt +83 -0
- package/android/src/main/java/com/platformcomponents/Helper.kt +27 -0
- package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +684 -0
- package/android/src/main/java/com/platformcomponents/PCDatePickerViewManager.kt +149 -0
- package/android/src/main/java/com/platformcomponents/PCMaterialMode.kt +16 -0
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +410 -0
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuViewManager.kt +114 -0
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +22 -0
- package/ios/PCDatePicker.h +11 -0
- package/ios/PCDatePicker.mm +248 -0
- package/ios/PCDatePickerView.swift +405 -0
- package/ios/PCSelectionMenu.h +10 -0
- package/ios/PCSelectionMenu.mm +182 -0
- package/ios/PCSelectionMenu.swift +434 -0
- package/lib/module/DatePicker.js +74 -0
- package/lib/module/DatePicker.js.map +1 -0
- package/lib/module/DatePickerNativeComponent.ts +68 -0
- package/lib/module/SelectionMenu.js +79 -0
- package/lib/module/SelectionMenu.js.map +1 -0
- package/lib/module/SelectionMenu.web.js +57 -0
- package/lib/module/SelectionMenu.web.js.map +1 -0
- package/lib/module/SelectionMenuNativeComponent.ts +106 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/sharedTypes.js +4 -0
- package/lib/module/sharedTypes.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/DatePicker.d.ts +38 -0
- package/lib/typescript/src/DatePicker.d.ts.map +1 -0
- package/lib/typescript/src/DatePickerNativeComponent.d.ts +53 -0
- package/lib/typescript/src/DatePickerNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/SelectionMenu.d.ts +50 -0
- package/lib/typescript/src/SelectionMenu.d.ts.map +1 -0
- package/lib/typescript/src/SelectionMenu.web.d.ts +19 -0
- package/lib/typescript/src/SelectionMenu.web.d.ts.map +1 -0
- package/lib/typescript/src/SelectionMenuNativeComponent.d.ts +85 -0
- package/lib/typescript/src/SelectionMenuNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/sharedTypes.d.ts +10 -0
- package/lib/typescript/src/sharedTypes.d.ts.map +1 -0
- package/package.json +178 -0
- package/shared/PCDatePickerComponentDescriptors-custom.h +52 -0
- package/shared/PCDatePickerShadowNode-custom.cpp +1 -0
- package/shared/PCDatePickerShadowNode-custom.h +27 -0
- package/shared/PCDatePickerState-custom.h +13 -0
- package/shared/PCSelectionMenuComponentDescriptors-custom.h +25 -0
- package/shared/PCSelectionMenuShadowNode-custom.cpp +36 -0
- package/shared/PCSelectionMenuShadowNode-custom.h +46 -0
- package/src/DatePicker.tsx +146 -0
- package/src/DatePickerNativeComponent.ts +68 -0
- package/src/SelectionMenu.tsx +170 -0
- package/src/SelectionMenu.web.tsx +93 -0
- package/src/SelectionMenuNativeComponent.ts +106 -0
- package/src/index.tsx +3 -0
- package/src/sharedTypes.ts +14 -0
package/package.json
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-platform-components",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A cross-platform toolkit of native UI components for React Native.",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.tsx",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"shared",
|
|
19
|
+
"android",
|
|
20
|
+
"ios",
|
|
21
|
+
"cpp",
|
|
22
|
+
"*.podspec",
|
|
23
|
+
"react-native.config.js",
|
|
24
|
+
"!ios/build",
|
|
25
|
+
"!android/build",
|
|
26
|
+
"!android/gradle",
|
|
27
|
+
"!android/gradlew",
|
|
28
|
+
"!android/gradlew.bat",
|
|
29
|
+
"!android/local.properties",
|
|
30
|
+
"!**/__tests__",
|
|
31
|
+
"!**/__fixtures__",
|
|
32
|
+
"!**/__mocks__",
|
|
33
|
+
"!**/.*"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"example": "yarn workspace react-native-platform-components-example",
|
|
37
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
38
|
+
"prepare": "bob build",
|
|
39
|
+
"typecheck": "tsc",
|
|
40
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
41
|
+
"release": "release-it --only-version",
|
|
42
|
+
"test": "jest"
|
|
43
|
+
},
|
|
44
|
+
"keywords": [
|
|
45
|
+
"react-native",
|
|
46
|
+
"ios",
|
|
47
|
+
"android"
|
|
48
|
+
],
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/BearPeak-Technology-Group/react-native-platform-components.git"
|
|
52
|
+
},
|
|
53
|
+
"author": "Andrew Tosh <andrew.tosh@jarxconcepts.com> (https://github.com/ajtosh77)",
|
|
54
|
+
"license": "MIT",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/BearPeak-Technology-Group/react-native-platform-components/issues"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://github.com/BearPeak-Technology-Group/react-native-platform-components#readme",
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"registry": "https://registry.npmjs.org/"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
64
|
+
"@eslint/compat": "^1.3.2",
|
|
65
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
66
|
+
"@eslint/js": "^9.35.0",
|
|
67
|
+
"@react-native-community/cli": "20.0.1",
|
|
68
|
+
"@react-native/babel-preset": "0.81.1",
|
|
69
|
+
"@react-native/eslint-config": "^0.81.1",
|
|
70
|
+
"@release-it/conventional-changelog": "^10.0.1",
|
|
71
|
+
"@types/jest": "^29.5.14",
|
|
72
|
+
"@types/react": "^19.1.0",
|
|
73
|
+
"commitlint": "^19.8.1",
|
|
74
|
+
"del-cli": "^6.0.0",
|
|
75
|
+
"eslint": "^9.35.0",
|
|
76
|
+
"eslint-config-prettier": "^10.1.8",
|
|
77
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
78
|
+
"jest": "^29.7.0",
|
|
79
|
+
"lefthook": "^2.0.3",
|
|
80
|
+
"prettier": "^2.8.8",
|
|
81
|
+
"react": "19.1.0",
|
|
82
|
+
"react-native": "0.81.1",
|
|
83
|
+
"react-native-builder-bob": "^0.40.16",
|
|
84
|
+
"release-it": "^19.1.0",
|
|
85
|
+
"turbo": "^2.5.6",
|
|
86
|
+
"typescript": "^5.9.2"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {
|
|
89
|
+
"react": "*",
|
|
90
|
+
"react-native": "*"
|
|
91
|
+
},
|
|
92
|
+
"workspaces": [
|
|
93
|
+
"example"
|
|
94
|
+
],
|
|
95
|
+
"packageManager": "yarn@4.11.0",
|
|
96
|
+
"react-native-builder-bob": {
|
|
97
|
+
"source": "src",
|
|
98
|
+
"output": "lib",
|
|
99
|
+
"targets": [
|
|
100
|
+
[
|
|
101
|
+
"module",
|
|
102
|
+
{
|
|
103
|
+
"esm": true
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
[
|
|
107
|
+
"typescript",
|
|
108
|
+
{
|
|
109
|
+
"project": "tsconfig.build.json"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"codegenConfig": {
|
|
115
|
+
"name": "PlatformComponentsViewSpec",
|
|
116
|
+
"type": "components",
|
|
117
|
+
"jsSrcsDir": "src",
|
|
118
|
+
"android": {
|
|
119
|
+
"javaPackageName": "com.platformcomponents"
|
|
120
|
+
},
|
|
121
|
+
"ios": {
|
|
122
|
+
"componentProvider": {
|
|
123
|
+
"PCSelectionMenu": "PCSelectionMenu",
|
|
124
|
+
"PCDatePicker": "PCDatePicker"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"prettier": {
|
|
129
|
+
"quoteProps": "consistent",
|
|
130
|
+
"singleQuote": true,
|
|
131
|
+
"tabWidth": 2,
|
|
132
|
+
"trailingComma": "es5",
|
|
133
|
+
"useTabs": false
|
|
134
|
+
},
|
|
135
|
+
"commitlint": {
|
|
136
|
+
"extends": [
|
|
137
|
+
"@commitlint/config-conventional"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
"release-it": {
|
|
141
|
+
"git": {
|
|
142
|
+
"commitMessage": "chore: release ${version}",
|
|
143
|
+
"tagName": "v${version}"
|
|
144
|
+
},
|
|
145
|
+
"npm": {
|
|
146
|
+
"publish": true,
|
|
147
|
+
"skipChecks": true
|
|
148
|
+
},
|
|
149
|
+
"github": {
|
|
150
|
+
"release": true
|
|
151
|
+
},
|
|
152
|
+
"plugins": {
|
|
153
|
+
"@release-it/conventional-changelog": {
|
|
154
|
+
"preset": {
|
|
155
|
+
"name": "angular"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"jest": {
|
|
161
|
+
"preset": "react-native",
|
|
162
|
+
"modulePathIgnorePatterns": [
|
|
163
|
+
"<rootDir>/example/node_modules",
|
|
164
|
+
"<rootDir>/lib/"
|
|
165
|
+
]
|
|
166
|
+
},
|
|
167
|
+
"create-react-native-library": {
|
|
168
|
+
"languages": "kotlin-objc",
|
|
169
|
+
"type": "fabric-view",
|
|
170
|
+
"tools": [
|
|
171
|
+
"eslint",
|
|
172
|
+
"lefthook",
|
|
173
|
+
"release-it",
|
|
174
|
+
"jest"
|
|
175
|
+
],
|
|
176
|
+
"version": "0.55.1"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "PCDatePickerShadowNode-custom.h"
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
6
|
+
#include <react/renderer/mounting/ShadowView.h>
|
|
7
|
+
#include <react/renderer/core/ShadowNode.h>
|
|
8
|
+
#include <react/renderer/core/ShadowNodeTraits.h>
|
|
9
|
+
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
10
|
+
#include <react/renderer/core/ShadowNodeFamily.h>
|
|
11
|
+
#include <react/renderer/components/view/YogaLayoutableShadowNode.h>
|
|
12
|
+
|
|
13
|
+
namespace facebook::react
|
|
14
|
+
{
|
|
15
|
+
|
|
16
|
+
class MeasuringPCDatePickerComponentDescriptor final
|
|
17
|
+
: public ConcreteComponentDescriptor<MeasuringPCDatePickerShadowNode>
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
21
|
+
|
|
22
|
+
void adopt(ShadowNode &shadowNode) const override
|
|
23
|
+
{
|
|
24
|
+
auto &pickerShadowNode =
|
|
25
|
+
static_cast<MeasuringPCDatePickerShadowNode &>(shadowNode);
|
|
26
|
+
auto &layoutableShadowNode =
|
|
27
|
+
static_cast<YogaLayoutableShadowNode &>(pickerShadowNode);
|
|
28
|
+
|
|
29
|
+
auto state =
|
|
30
|
+
std::static_pointer_cast<
|
|
31
|
+
const MeasuringPCDatePickerShadowNode::ConcreteState
|
|
32
|
+
>(shadowNode.getState());
|
|
33
|
+
|
|
34
|
+
if (state)
|
|
35
|
+
{
|
|
36
|
+
auto stateData = state->getData();
|
|
37
|
+
auto frameSize = stateData.frameSize;
|
|
38
|
+
|
|
39
|
+
if (frameSize.width >= 0 && frameSize.height >= 0)
|
|
40
|
+
{
|
|
41
|
+
layoutableShadowNode.setSize(Size{
|
|
42
|
+
frameSize.width,
|
|
43
|
+
frameSize.height,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#include "PCDatePickerShadowNode-custom.h"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
|
|
4
|
+
#include <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
|
|
5
|
+
#include <react/renderer/components/PlatformComponentsViewSpec/Props.h>
|
|
6
|
+
|
|
7
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
8
|
+
#include <react/renderer/core/ConcreteState.h>
|
|
9
|
+
#include <react/renderer/core/ShadowNodeTraits.h>
|
|
10
|
+
#include <react/renderer/mounting/ShadowView.h>
|
|
11
|
+
|
|
12
|
+
#include "PCDatePickerState-custom.h"
|
|
13
|
+
|
|
14
|
+
namespace facebook::react
|
|
15
|
+
{
|
|
16
|
+
class MeasuringPCDatePickerShadowNode final
|
|
17
|
+
: public ConcreteViewShadowNode<
|
|
18
|
+
PCDatePickerComponentName,
|
|
19
|
+
PCDatePickerProps,
|
|
20
|
+
PCDatePickerEventEmitter,
|
|
21
|
+
PCDatePickerStateFrameSize>
|
|
22
|
+
{
|
|
23
|
+
public:
|
|
24
|
+
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/core/LayoutPrimitives.h>
|
|
4
|
+
|
|
5
|
+
namespace facebook::react {
|
|
6
|
+
|
|
7
|
+
struct PCDatePickerStateFrameSize final {
|
|
8
|
+
using Shared = std::shared_ptr<const PCDatePickerStateFrameSize>;
|
|
9
|
+
|
|
10
|
+
Size frameSize{}; // {width, height} in points
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "PCSelectionMenuShadowNode-custom.h"
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
6
|
+
#include <react/renderer/mounting/ShadowView.h>
|
|
7
|
+
#include <react/renderer/core/ShadowNode.h>
|
|
8
|
+
#include <react/renderer/core/ShadowNodeTraits.h>
|
|
9
|
+
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
10
|
+
#include <react/renderer/core/ShadowNodeFamily.h>
|
|
11
|
+
#include <react/renderer/components/view/YogaLayoutableShadowNode.h>
|
|
12
|
+
|
|
13
|
+
namespace facebook::react
|
|
14
|
+
{
|
|
15
|
+
using MeasuringPCSelectionMenuComponentDescriptor = ConcreteComponentDescriptor<MeasuringPCSelectionMenuShadowNode>;
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
class MeasuringPCDatePickerComponentDescriptor final
|
|
19
|
+
: public ConcreteComponentDescriptor<MeasuringPCSelectionMenuShadowNode>
|
|
20
|
+
{
|
|
21
|
+
public:
|
|
22
|
+
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
23
|
+
};*/
|
|
24
|
+
|
|
25
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#include <react/renderer/core/LayoutConstraints.h>
|
|
2
|
+
#include "PCSelectionMenuShadowNode-Custom.h"
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
|
|
6
|
+
namespace facebook::react {
|
|
7
|
+
|
|
8
|
+
Size MeasuringPCSelectionMenuShadowNode::measureContent(
|
|
9
|
+
const LayoutContext&,
|
|
10
|
+
const LayoutConstraints& layoutConstraints) const {
|
|
11
|
+
|
|
12
|
+
const Float kHuge = static_cast<Float>(1.0e9);
|
|
13
|
+
|
|
14
|
+
const Float maxW = layoutConstraints.maximumSize.width;
|
|
15
|
+
const Float measuredW = (maxW > 0 && maxW < kHuge) ? maxW : 0;
|
|
16
|
+
|
|
17
|
+
const auto& props = *std::static_pointer_cast<const PCSelectionMenuProps>(getProps());
|
|
18
|
+
const bool inlineMode = props.anchorMode == "inline";
|
|
19
|
+
|
|
20
|
+
Float measuredH = 0;
|
|
21
|
+
|
|
22
|
+
if (inlineMode) {
|
|
23
|
+
measuredH = static_cast<Float>(kMinRowHeight); // 44
|
|
24
|
+
} else {
|
|
25
|
+
measuredH = 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Respect layout constraints (min/max) coming from JS styles
|
|
29
|
+
measuredH = std::max<Float>(measuredH, layoutConstraints.minimumSize.height);
|
|
30
|
+
measuredH = std::min<Float>(measuredH, layoutConstraints.maximumSize.height);
|
|
31
|
+
|
|
32
|
+
Size result{measuredW, measuredH};
|
|
33
|
+
return layoutConstraints.clamp(result);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
4
|
+
|
|
5
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
|
|
6
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
|
|
7
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
|
|
8
|
+
|
|
9
|
+
namespace facebook::react {
|
|
10
|
+
|
|
11
|
+
extern const char PCSelectionMenuComponentName[];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ShadowNode for SelectionMenu.
|
|
15
|
+
*
|
|
16
|
+
* Key behavior:
|
|
17
|
+
* - Provides a non-zero default measured height (minRowHeight) so the view
|
|
18
|
+
* remains tappable when JS does not specify an explicit height.
|
|
19
|
+
*/
|
|
20
|
+
class MeasuringPCSelectionMenuShadowNode final : public ConcreteViewShadowNode<
|
|
21
|
+
PCSelectionMenuComponentName,
|
|
22
|
+
PCSelectionMenuProps,
|
|
23
|
+
PCSelectionMenuEventEmitter,
|
|
24
|
+
PCSelectionMenuState> {
|
|
25
|
+
public:
|
|
26
|
+
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
27
|
+
|
|
28
|
+
static constexpr float kMinRowHeight = 44.0f;
|
|
29
|
+
|
|
30
|
+
static ShadowNodeTraits BaseTraits() {
|
|
31
|
+
auto traits = ConcreteViewShadowNode::BaseTraits();
|
|
32
|
+
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
|
|
33
|
+
traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
|
|
34
|
+
return traits;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Called by Yoga when it needs the intrinsic size of the component.
|
|
39
|
+
* We ensure a sensible minimum height so the view doesn't measure to 0.
|
|
40
|
+
*/
|
|
41
|
+
Size measureContent(
|
|
42
|
+
const LayoutContext& layoutContext,
|
|
43
|
+
const LayoutConstraints& layoutConstraints) const override;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// DatePicker.tsx
|
|
2
|
+
import React, { useCallback, useMemo } from 'react';
|
|
3
|
+
import type { NativeSyntheticEvent, StyleProp, ViewStyle } from 'react-native';
|
|
4
|
+
import { StyleSheet } from 'react-native';
|
|
5
|
+
|
|
6
|
+
import NativeDatePicker, {
|
|
7
|
+
type DateChangeEvent,
|
|
8
|
+
type NativeProps as NativeDatePickerProps,
|
|
9
|
+
type IOSProps as NativeIOSProps,
|
|
10
|
+
type AndroidProps as NativeAndroidProps,
|
|
11
|
+
type DatePickerPresentation,
|
|
12
|
+
type DatePickerMode,
|
|
13
|
+
type IOSRoundsToMinuteInterval,
|
|
14
|
+
type IOSDatePickerStyle,
|
|
15
|
+
} from './DatePickerNativeComponent';
|
|
16
|
+
|
|
17
|
+
import type { AndroidMaterialMode, Visible } from './sharedTypes';
|
|
18
|
+
|
|
19
|
+
export type DatePickerProps = {
|
|
20
|
+
style?: StyleProp<ViewStyle>;
|
|
21
|
+
|
|
22
|
+
/** Controlled value. Use `null` for "no date selected". */
|
|
23
|
+
date: Date | null;
|
|
24
|
+
|
|
25
|
+
/** Optional bounds. Use `null` for "unbounded". */
|
|
26
|
+
minDate?: Date | null;
|
|
27
|
+
maxDate?: Date | null;
|
|
28
|
+
|
|
29
|
+
locale?: string;
|
|
30
|
+
timeZoneName?: string;
|
|
31
|
+
mode?: DatePickerMode;
|
|
32
|
+
presentation?: DatePickerPresentation;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Modal only. If presentation !== "modal", ignored.
|
|
36
|
+
* Wrapper ergonomics: boolean.
|
|
37
|
+
*/
|
|
38
|
+
visible?: boolean;
|
|
39
|
+
|
|
40
|
+
onConfirm?: (dateTime: Date) => void;
|
|
41
|
+
onClosed?: () => void;
|
|
42
|
+
|
|
43
|
+
ios?: {
|
|
44
|
+
preferredStyle?: IOSDatePickerStyle;
|
|
45
|
+
countDownDurationSeconds?: NativeIOSProps['countDownDurationSeconds'];
|
|
46
|
+
minuteInterval?: NativeIOSProps['minuteInterval'];
|
|
47
|
+
roundsToMinuteInterval?: IOSRoundsToMinuteInterval;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
android?: {
|
|
51
|
+
firstDayOfWeek?: NativeAndroidProps['firstDayOfWeek'];
|
|
52
|
+
material?: AndroidMaterialMode;
|
|
53
|
+
dialogTitle?: NativeAndroidProps['dialogTitle'];
|
|
54
|
+
positiveButtonTitle?: NativeAndroidProps['positiveButtonTitle'];
|
|
55
|
+
negativeButtonTitle?: NativeAndroidProps['negativeButtonTitle'];
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function dateToMsOrMinusOne(d: Date | null | undefined): number {
|
|
60
|
+
return d ? d.getTime() : -1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function normalizeVisible(
|
|
64
|
+
presentation: NativeDatePickerProps['presentation'] | undefined,
|
|
65
|
+
visible: boolean | undefined
|
|
66
|
+
): Visible | undefined {
|
|
67
|
+
// Only meaningful in modal presentation. Keep undefined for inline to avoid noise.
|
|
68
|
+
if (presentation !== 'modal') return undefined;
|
|
69
|
+
return visible ? 'open' : 'closed';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function DatePicker(props: DatePickerProps): React.ReactElement {
|
|
73
|
+
const {
|
|
74
|
+
style,
|
|
75
|
+
date,
|
|
76
|
+
minDate,
|
|
77
|
+
maxDate,
|
|
78
|
+
locale,
|
|
79
|
+
timeZoneName,
|
|
80
|
+
mode,
|
|
81
|
+
presentation = 'modal',
|
|
82
|
+
visible,
|
|
83
|
+
onConfirm,
|
|
84
|
+
onClosed,
|
|
85
|
+
ios,
|
|
86
|
+
android,
|
|
87
|
+
} = props;
|
|
88
|
+
|
|
89
|
+
const handleConfirm = useCallback(
|
|
90
|
+
(e: NativeSyntheticEvent<DateChangeEvent>) => {
|
|
91
|
+
onConfirm?.(new Date(e.nativeEvent.timestampMs));
|
|
92
|
+
},
|
|
93
|
+
[onConfirm]
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const handleClosed = useCallback(() => {
|
|
97
|
+
onClosed?.();
|
|
98
|
+
}, [onClosed]);
|
|
99
|
+
|
|
100
|
+
const styles = useMemo(() => createStyles(), []);
|
|
101
|
+
|
|
102
|
+
const nativeProps: NativeDatePickerProps = {
|
|
103
|
+
style: [styles.picker, style] as any,
|
|
104
|
+
|
|
105
|
+
mode,
|
|
106
|
+
locale,
|
|
107
|
+
timeZoneName,
|
|
108
|
+
|
|
109
|
+
presentation,
|
|
110
|
+
visible: normalizeVisible(presentation, visible) as any,
|
|
111
|
+
|
|
112
|
+
dateMs: dateToMsOrMinusOne(date) as any,
|
|
113
|
+
minDateMs: dateToMsOrMinusOne(minDate ?? null) as any,
|
|
114
|
+
maxDateMs: dateToMsOrMinusOne(maxDate ?? null) as any,
|
|
115
|
+
|
|
116
|
+
onConfirm: onConfirm ? handleConfirm : undefined,
|
|
117
|
+
onClosed: onClosed ? handleClosed : undefined,
|
|
118
|
+
|
|
119
|
+
ios: ios
|
|
120
|
+
? {
|
|
121
|
+
preferredStyle: ios.preferredStyle,
|
|
122
|
+
countDownDurationSeconds: ios.countDownDurationSeconds,
|
|
123
|
+
minuteInterval: ios.minuteInterval,
|
|
124
|
+
roundsToMinuteInterval: ios.roundsToMinuteInterval,
|
|
125
|
+
}
|
|
126
|
+
: undefined,
|
|
127
|
+
|
|
128
|
+
android: android
|
|
129
|
+
? {
|
|
130
|
+
firstDayOfWeek: android.firstDayOfWeek,
|
|
131
|
+
material: android.material as any,
|
|
132
|
+
dialogTitle: android.dialogTitle,
|
|
133
|
+
positiveButtonTitle: android.positiveButtonTitle,
|
|
134
|
+
negativeButtonTitle: android.negativeButtonTitle,
|
|
135
|
+
}
|
|
136
|
+
: undefined,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return <NativeDatePicker {...nativeProps} />;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function createStyles() {
|
|
143
|
+
return StyleSheet.create({
|
|
144
|
+
picker: {},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// DatePickerNativeComponent.ts
|
|
2
|
+
import type { CodegenTypes, ViewProps } from 'react-native';
|
|
3
|
+
import { codegenNativeComponent } from 'react-native';
|
|
4
|
+
|
|
5
|
+
export type TimestampMs = CodegenTypes.Double;
|
|
6
|
+
|
|
7
|
+
export type DateChangeEvent = {
|
|
8
|
+
timestampMs: CodegenTypes.Double;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type DatePickerMode = 'date' | 'time' | 'dateAndTime' | 'countDownTimer';
|
|
12
|
+
export type DatePickerPresentation = 'modal' | 'embedded';
|
|
13
|
+
|
|
14
|
+
export type IOSDatePickerStyle = 'automatic' | 'compact' | 'inline' | 'wheels';
|
|
15
|
+
export type IOSRoundsToMinuteInterval = 'inherit' | 'round' | 'noRound';
|
|
16
|
+
|
|
17
|
+
export type IOSProps = {
|
|
18
|
+
preferredStyle?: string; // IOSDatePickerStyle
|
|
19
|
+
countDownDurationSeconds?: CodegenTypes.Double;
|
|
20
|
+
minuteInterval?: CodegenTypes.Int32;
|
|
21
|
+
roundsToMinuteInterval?: string; // IOSRoundsToMinuteInterval
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type AndroidProps = {
|
|
25
|
+
firstDayOfWeek?: CodegenTypes.Int32;
|
|
26
|
+
material?: string; // AndroidMaterialMode
|
|
27
|
+
dialogTitle?: string;
|
|
28
|
+
positiveButtonTitle?: string;
|
|
29
|
+
negativeButtonTitle?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type WebProps = Readonly<{}>;
|
|
33
|
+
export type WindowsProps = Readonly<{}>;
|
|
34
|
+
export type MacOSProps = Readonly<{}>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Sentinel convention:
|
|
38
|
+
* - `-1` means "no value / unbounded / unset".
|
|
39
|
+
*/
|
|
40
|
+
export type CommonProps = {
|
|
41
|
+
mode?: string; // DatePickerMode
|
|
42
|
+
|
|
43
|
+
dateMs?: CodegenTypes.WithDefault<TimestampMs, -1>;
|
|
44
|
+
minDateMs?: CodegenTypes.WithDefault<TimestampMs, -1>;
|
|
45
|
+
maxDateMs?: CodegenTypes.WithDefault<TimestampMs, -1>;
|
|
46
|
+
|
|
47
|
+
locale?: string;
|
|
48
|
+
timeZoneName?: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Only used when presentation === "modal".
|
|
52
|
+
* Defaults should be applied in JS wrapper (recommended).
|
|
53
|
+
*/
|
|
54
|
+
visible?: string; // Visible
|
|
55
|
+
|
|
56
|
+
/** Defaults should be applied in JS wrapper (recommended). */
|
|
57
|
+
presentation?: string; // DatePickerPresentation
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export interface NativeProps extends ViewProps, CommonProps {
|
|
61
|
+
ios?: IOSProps;
|
|
62
|
+
android?: AndroidProps;
|
|
63
|
+
|
|
64
|
+
onConfirm?: CodegenTypes.BubblingEventHandler<DateChangeEvent>;
|
|
65
|
+
onClosed?: CodegenTypes.BubblingEventHandler<Readonly<{}>>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default codegenNativeComponent<NativeProps>('PCDatePicker');
|