@tatil/react-native-wheel-date-picker 0.0.0-stage → 0.1.1
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/README.md +113 -2
- package/android/build.gradle +55 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/tatil/wheeldatepicker/DateChangeEvent.kt +17 -0
- package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerPackage.kt +16 -0
- package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerView.kt +161 -0
- package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerViewManager.kt +42 -0
- package/android/src/main/res/values/styles.xml +18 -0
- package/lib/module/DateWheel.android.js +37 -0
- package/lib/module/DateWheel.android.js.map +1 -0
- package/lib/module/DateWheel.ios.js +37 -0
- package/lib/module/DateWheel.ios.js.map +1 -0
- package/lib/module/DateWheel.js +8 -0
- package/lib/module/DateWheel.js.map +1 -0
- package/lib/module/TatilWheelDatePickerViewNativeComponent.ts +27 -0
- package/lib/module/WheelDatePicker.js +27 -0
- package/lib/module/WheelDatePicker.js.map +1 -0
- package/lib/module/dateUtils.js +16 -0
- package/lib/module/dateUtils.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/DateWheel.android.d.ts +4 -0
- package/lib/typescript/src/DateWheel.android.d.ts.map +1 -0
- package/lib/typescript/src/DateWheel.d.ts +4 -0
- package/lib/typescript/src/DateWheel.d.ts.map +1 -0
- package/lib/typescript/src/DateWheel.ios.d.ts +4 -0
- package/lib/typescript/src/DateWheel.ios.d.ts.map +1 -0
- package/lib/typescript/src/TatilWheelDatePickerViewNativeComponent.d.ts +18 -0
- package/lib/typescript/src/TatilWheelDatePickerViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/WheelDatePicker.d.ts +7 -0
- package/lib/typescript/src/WheelDatePicker.d.ts.map +1 -0
- package/lib/typescript/src/dateUtils.d.ts +10 -0
- package/lib/typescript/src/dateUtils.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +22 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +135 -4
- package/react-native.config.js +10 -0
- package/src/DateWheel.android.tsx +34 -0
- package/src/DateWheel.ios.tsx +29 -0
- package/src/DateWheel.tsx +10 -0
- package/src/TatilWheelDatePickerViewNativeComponent.ts +27 -0
- package/src/WheelDatePicker.tsx +23 -0
- package/src/dateUtils.ts +18 -0
- package/src/index.tsx +2 -0
- package/src/types.ts +23 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Uğur Karataş
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,114 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tatil/react-native-wheel-date-picker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Inline native wheel date picker for React Native.
|
|
4
|
+
|
|
5
|
+
- **Android:** the platform `DatePicker` in spinner mode (three wheels, no calendar), as a Fabric view.
|
|
6
|
+
- **iOS:** `UIDatePicker` wheels through [`@react-native-community/datetimepicker`](https://github.com/react-native-datetimepicker/datetimepicker).
|
|
7
|
+
|
|
8
|
+
The picker is a plain view: place it wherever you need, for example inside your own bottom sheet or modal. `onChange` fires on every wheel step, so a "Save" button can read the value at any moment, even while the wheel is still spinning.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
> [!IMPORTANT]
|
|
13
|
+
> **New Architecture only.** The Android picker is a Fabric component and does not work on the old architecture (Paper).
|
|
14
|
+
|
|
15
|
+
| Dependency | Version |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `react-native` | `>= 0.80` with the New Architecture enabled |
|
|
18
|
+
| `react` | `>= 19` |
|
|
19
|
+
| `@react-native-community/datetimepicker` | `>= 9.1.0` (peer dependency, used on iOS) |
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
yarn add @tatil/react-native-wheel-date-picker @react-native-community/datetimepicker
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npm install @tatil/react-native-wheel-date-picker @react-native-community/datetimepicker
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then install pods and rebuild the native apps:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
cd ios && bundle exec pod install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Autolinking handles the rest; no manual registration is needed.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { useState } from 'react';
|
|
43
|
+
import { WheelDatePicker } from '@tatil/react-native-wheel-date-picker';
|
|
44
|
+
|
|
45
|
+
const BirthDateField = () => {
|
|
46
|
+
const [date, setDate] = useState(new Date(1990, 0, 1));
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<WheelDatePicker
|
|
50
|
+
value={date}
|
|
51
|
+
onChange={setDate}
|
|
52
|
+
minimumDate={new Date(1920, 0, 1)}
|
|
53
|
+
maximumDate={new Date()}
|
|
54
|
+
locale="tr-TR"
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The picker is controlled: keep the date in state and update it in `onChange`.
|
|
61
|
+
|
|
62
|
+
### Props
|
|
63
|
+
|
|
64
|
+
| Prop | Type | Platform | Description |
|
|
65
|
+
| --- | --- | --- | --- |
|
|
66
|
+
| `value` | `Date` | both | Selected date. **Required.** |
|
|
67
|
+
| `onChange` | `(date: Date) => void` | both | Called on every wheel step. **Required.** |
|
|
68
|
+
| `minimumDate` | `Date` | both | Earliest selectable date. |
|
|
69
|
+
| `maximumDate` | `Date` | both | Latest selectable date. |
|
|
70
|
+
| `textColor` | `string` | both | Wheel text color, e.g. `'#1F1F1F'`. Android 10 (API 29) and later; older Android versions use the theme color. |
|
|
71
|
+
| `locale` | `string` | iOS | Locale for month names and wheel order, e.g. `'tr-TR'`. |
|
|
72
|
+
| `style` | `StyleProp<ViewStyle>` | both | Size and layout. Android defaults to full width and 200 pt height. |
|
|
73
|
+
|
|
74
|
+
### Dates and time zones
|
|
75
|
+
|
|
76
|
+
Every date going in and out of the picker is normalized to **12:00 local time** on the selected day. Some time zones changed their UTC offset in the past (for example Türkiye before 2016), and a midnight `Date` can shift to 23:00 of the previous day during conversions. Noon keeps the day stable. If you need midnight, reset the hours yourself.
|
|
77
|
+
|
|
78
|
+
## Platform notes
|
|
79
|
+
|
|
80
|
+
### Android
|
|
81
|
+
|
|
82
|
+
- **Language:** month names and wheel order (day, month, year) follow the device language. The `locale` prop has no effect on Android.
|
|
83
|
+
- **Theme:** the wheel uses a light theme. To change the default text and divider colors, declare a style with the same name in your app's `android/app/src/main/res/values/styles.xml`:
|
|
84
|
+
|
|
85
|
+
```xml
|
|
86
|
+
<style name="ThemeOverlay.TatilWheelDatePicker" parent="">
|
|
87
|
+
<item name="android:datePickerStyle">@style/Widget.TatilWheelDatePicker</item>
|
|
88
|
+
<!-- Wheel text -->
|
|
89
|
+
<item name="android:textColorPrimary">#1F1F1F</item>
|
|
90
|
+
<!-- Selection divider lines -->
|
|
91
|
+
<item name="android:colorControlNormal">#525252</item>
|
|
92
|
+
</style>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **Gestures:** while a wheel is being dragged, parent scroll views and bottom sheets do not take over the touch.
|
|
96
|
+
|
|
97
|
+
### iOS
|
|
98
|
+
|
|
99
|
+
- The wheel always uses the light appearance.
|
|
100
|
+
- The package ships no iOS native code of its own; `@react-native-community/datetimepicker` must be installed in the app.
|
|
101
|
+
|
|
102
|
+
## Contributing
|
|
103
|
+
|
|
104
|
+
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
105
|
+
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
106
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.ReactNativeWheelDatePicker = [
|
|
3
|
+
kotlinVersion: "2.0.21",
|
|
4
|
+
minSdkVersion: 24,
|
|
5
|
+
compileSdkVersion: 36
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
ext.getExtOrDefault = { prop ->
|
|
9
|
+
if (rootProject.ext.has(prop)) {
|
|
10
|
+
return rootProject.ext.get(prop)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return ReactNativeWheelDatePicker[prop]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
repositories {
|
|
17
|
+
google()
|
|
18
|
+
mavenCentral()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dependencies {
|
|
22
|
+
classpath "com.android.tools.build:gradle:8.7.2"
|
|
23
|
+
// noinspection DifferentKotlinGradleVersion
|
|
24
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
apply plugin: "com.android.library"
|
|
30
|
+
|
|
31
|
+
if (project.extensions.findByName("kotlin") == null) {
|
|
32
|
+
apply plugin: "kotlin-android"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
apply plugin: "com.facebook.react"
|
|
37
|
+
|
|
38
|
+
android {
|
|
39
|
+
namespace "com.tatil.wheeldatepicker"
|
|
40
|
+
|
|
41
|
+
compileSdkVersion getExtOrDefault("compileSdkVersion")
|
|
42
|
+
|
|
43
|
+
defaultConfig {
|
|
44
|
+
minSdkVersion getExtOrDefault("minSdkVersion")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
compileOptions {
|
|
48
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
49
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
dependencies {
|
|
54
|
+
implementation "com.facebook.react:react-android"
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package com.tatil.wheeldatepicker
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.facebook.react.uimanager.events.Event
|
|
6
|
+
|
|
7
|
+
class DateChangeEvent(surfaceId: Int, viewTag: Int, private val date: String) :
|
|
8
|
+
Event<DateChangeEvent>(surfaceId, viewTag) {
|
|
9
|
+
|
|
10
|
+
override fun getEventName() = EVENT_NAME
|
|
11
|
+
|
|
12
|
+
override fun getEventData(): WritableMap = Arguments.createMap().apply { putString("date", date) }
|
|
13
|
+
|
|
14
|
+
companion object {
|
|
15
|
+
const val EVENT_NAME = "topDateChange"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.tatil.wheeldatepicker
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.BaseReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
7
|
+
import com.facebook.react.uimanager.ViewManager
|
|
8
|
+
|
|
9
|
+
class TatilWheelDatePickerPackage : BaseReactPackage() {
|
|
10
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
11
|
+
listOf(TatilWheelDatePickerViewManager())
|
|
12
|
+
|
|
13
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
|
|
14
|
+
|
|
15
|
+
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider { emptyMap() }
|
|
16
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
package com.tatil.wheeldatepicker
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import android.view.ContextThemeWrapper
|
|
6
|
+
import android.view.Gravity
|
|
7
|
+
import android.view.MotionEvent
|
|
8
|
+
import android.view.View
|
|
9
|
+
import android.view.ViewGroup
|
|
10
|
+
import android.widget.DatePicker
|
|
11
|
+
import android.widget.FrameLayout
|
|
12
|
+
import android.widget.NumberPicker
|
|
13
|
+
import com.facebook.react.bridge.ReactContext
|
|
14
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
15
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
|
+
import java.util.Calendar
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Inline Android date wheel: android.widget.DatePicker in spinner mode
|
|
20
|
+
* (theme: ThemeOverlay.TatilWheelDatePicker). Dates travel to and from JS as
|
|
21
|
+
* 'YYYY-MM-DD' strings so no time zone is involved.
|
|
22
|
+
*/
|
|
23
|
+
@SuppressLint("ViewConstructor")
|
|
24
|
+
class TatilWheelDatePickerView(context: ThemedReactContext) : FrameLayout(context) {
|
|
25
|
+
|
|
26
|
+
private var value: String? = null
|
|
27
|
+
private var minDate: String? = null
|
|
28
|
+
private var maxDate: String? = null
|
|
29
|
+
private var textColor: Int? = null
|
|
30
|
+
|
|
31
|
+
// Changes coming from props must not be echoed back to JS as events.
|
|
32
|
+
private var isApplyingProps = false
|
|
33
|
+
|
|
34
|
+
private val picker =
|
|
35
|
+
DatePicker(ContextThemeWrapper(context, R.style.ThemeOverlay_TatilWheelDatePicker))
|
|
36
|
+
|
|
37
|
+
// Fires on every wheel step, before scrolling settles.
|
|
38
|
+
private val onDateChanged =
|
|
39
|
+
DatePicker.OnDateChangedListener { _, year, month, day ->
|
|
40
|
+
if (!isApplyingProps) emitDateChange(year, month, day)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// React Native does not handle requestLayout from native children; when a
|
|
44
|
+
// NumberPicker asks to be measured again, measure and lay out here.
|
|
45
|
+
private val measureAndLayout = Runnable {
|
|
46
|
+
measure(
|
|
47
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
48
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
|
|
49
|
+
)
|
|
50
|
+
layout(left, top, right, bottom)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
init {
|
|
54
|
+
val today = Calendar.getInstance()
|
|
55
|
+
picker.init(
|
|
56
|
+
today.get(Calendar.YEAR),
|
|
57
|
+
today.get(Calendar.MONTH),
|
|
58
|
+
today.get(Calendar.DAY_OF_MONTH),
|
|
59
|
+
onDateChanged,
|
|
60
|
+
)
|
|
61
|
+
addView(picker, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
fun setValue(value: String?) {
|
|
65
|
+
this.value = value
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fun setMinDate(minDate: String?) {
|
|
69
|
+
this.minDate = minDate
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fun setMaxDate(maxDate: String?) {
|
|
73
|
+
this.maxDate = maxDate
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun setTextColor(textColor: Int?) {
|
|
77
|
+
this.textColor = textColor
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Called once all props of an update have been set. */
|
|
81
|
+
fun applyProps() {
|
|
82
|
+
isApplyingProps = true
|
|
83
|
+
// Open max first so a new min never lands above the old max.
|
|
84
|
+
picker.maxDate = toMillis(DEFAULT_MAX_DATE)
|
|
85
|
+
picker.minDate = toMillis(minDate ?: DEFAULT_MIN_DATE)
|
|
86
|
+
picker.maxDate = toMillis(maxDate ?: DEFAULT_MAX_DATE)
|
|
87
|
+
|
|
88
|
+
val requested = value?.let(::parse)
|
|
89
|
+
if (requested != null) {
|
|
90
|
+
val (year, month, day) = requested
|
|
91
|
+
if (year != picker.year || month != picker.month || day != picker.dayOfMonth) {
|
|
92
|
+
picker.updateDate(year, month, day)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
isApplyingProps = false
|
|
96
|
+
|
|
97
|
+
applyTextColor()
|
|
98
|
+
|
|
99
|
+
// An out-of-range value snaps to the bound; keep JS in sync with what is shown.
|
|
100
|
+
if (requested != null && requested != Triple(picker.year, picker.month, picker.dayOfMonth)) {
|
|
101
|
+
emitDateChange(picker.year, picker.month, picker.dayOfMonth)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
106
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
107
|
+
// Keep parent scroll views and sheets from taking over while a wheel spins.
|
|
108
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
109
|
+
parent?.requestDisallowInterceptTouchEvent(true)
|
|
110
|
+
}
|
|
111
|
+
return super.dispatchTouchEvent(event)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
override fun requestLayout() {
|
|
115
|
+
super.requestLayout()
|
|
116
|
+
post(measureAndLayout)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// NumberPicker.setTextColor exists from Android 10 (API 29); below that the
|
|
120
|
+
// theme color is used.
|
|
121
|
+
private fun applyTextColor() {
|
|
122
|
+
val color = textColor ?: return
|
|
123
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return
|
|
124
|
+
forEachNumberPicker(picker) { it.textColor = color }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private fun forEachNumberPicker(view: View, action: (NumberPicker) -> Unit) {
|
|
128
|
+
if (view is NumberPicker) return action(view)
|
|
129
|
+
if (view !is ViewGroup) return
|
|
130
|
+
for (index in 0 until view.childCount) forEachNumberPicker(view.getChildAt(index), action)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private fun emitDateChange(year: Int, month: Int, day: Int) {
|
|
134
|
+
val reactContext = context as ReactContext
|
|
135
|
+
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
136
|
+
UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
137
|
+
?.dispatchEvent(DateChangeEvent(surfaceId, id, format(year, month, day)))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private companion object {
|
|
141
|
+
const val DEFAULT_MIN_DATE = "1900-01-01"
|
|
142
|
+
const val DEFAULT_MAX_DATE = "2100-12-31"
|
|
143
|
+
|
|
144
|
+
/** 'YYYY-MM-DD' to (year, zero-based month, day). */
|
|
145
|
+
fun parse(date: String): Triple<Int, Int, Int>? {
|
|
146
|
+
val parts = date.split("-").mapNotNull { it.toIntOrNull() }
|
|
147
|
+
if (parts.size != 3) return null
|
|
148
|
+
return Triple(parts[0], parts[1] - 1, parts[2])
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fun format(year: Int, month: Int, day: Int) =
|
|
152
|
+
"%04d-%02d-%02d".format(year, month + 1, day)
|
|
153
|
+
|
|
154
|
+
fun toMillis(date: String): Long {
|
|
155
|
+
val calendar = Calendar.getInstance()
|
|
156
|
+
calendar.clear()
|
|
157
|
+
parse(date)?.let { (year, month, day) -> calendar.set(year, month, day) }
|
|
158
|
+
return calendar.timeInMillis
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package com.tatil.wheeldatepicker
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
4
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
7
|
+
import com.facebook.react.viewmanagers.TatilWheelDatePickerViewManagerDelegate
|
|
8
|
+
import com.facebook.react.viewmanagers.TatilWheelDatePickerViewManagerInterface
|
|
9
|
+
|
|
10
|
+
@ReactModule(name = TatilWheelDatePickerViewManager.NAME)
|
|
11
|
+
class TatilWheelDatePickerViewManager :
|
|
12
|
+
SimpleViewManager<TatilWheelDatePickerView>(),
|
|
13
|
+
TatilWheelDatePickerViewManagerInterface<TatilWheelDatePickerView> {
|
|
14
|
+
|
|
15
|
+
private val delegate = TatilWheelDatePickerViewManagerDelegate(this)
|
|
16
|
+
|
|
17
|
+
override fun getDelegate(): ViewManagerDelegate<TatilWheelDatePickerView> = delegate
|
|
18
|
+
|
|
19
|
+
override fun getName() = NAME
|
|
20
|
+
|
|
21
|
+
override fun createViewInstance(context: ThemedReactContext) = TatilWheelDatePickerView(context)
|
|
22
|
+
|
|
23
|
+
override fun setValue(view: TatilWheelDatePickerView, value: String?) = view.setValue(value)
|
|
24
|
+
|
|
25
|
+
override fun setMinDate(view: TatilWheelDatePickerView, value: String?) = view.setMinDate(value)
|
|
26
|
+
|
|
27
|
+
override fun setMaxDate(view: TatilWheelDatePickerView, value: String?) = view.setMaxDate(value)
|
|
28
|
+
|
|
29
|
+
override fun setTextColor(view: TatilWheelDatePickerView, value: Int?) = view.setTextColor(value)
|
|
30
|
+
|
|
31
|
+
override fun onAfterUpdateTransaction(view: TatilWheelDatePickerView) {
|
|
32
|
+
super.onAfterUpdateTransaction(view)
|
|
33
|
+
view.applyProps()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> =
|
|
37
|
+
mapOf(DateChangeEvent.EVENT_NAME to mapOf("registrationName" to "onDateChange"))
|
|
38
|
+
|
|
39
|
+
companion object {
|
|
40
|
+
const val NAME = "TatilWheelDatePickerView"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<resources>
|
|
3
|
+
<!-- Opens DatePicker in spinner mode without the calendar. Apps can
|
|
4
|
+
restyle the wheel by declaring a style with the same name in their
|
|
5
|
+
own res/values/styles.xml. -->
|
|
6
|
+
<style name="ThemeOverlay.TatilWheelDatePicker" parent="">
|
|
7
|
+
<item name="android:datePickerStyle">@style/Widget.TatilWheelDatePicker</item>
|
|
8
|
+
<!-- Wheel text -->
|
|
9
|
+
<item name="android:textColorPrimary">#1F1F1F</item>
|
|
10
|
+
<!-- Selection divider lines -->
|
|
11
|
+
<item name="android:colorControlNormal">#525252</item>
|
|
12
|
+
</style>
|
|
13
|
+
|
|
14
|
+
<style name="Widget.TatilWheelDatePicker" parent="android:Widget.Material.Light.DatePicker">
|
|
15
|
+
<item name="android:datePickerMode">spinner</item>
|
|
16
|
+
<item name="android:calendarViewShown">false</item>
|
|
17
|
+
</style>
|
|
18
|
+
</resources>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { StyleSheet } from 'react-native';
|
|
4
|
+
import TatilWheelDatePickerView from './TatilWheelDatePickerViewNativeComponent';
|
|
5
|
+
import { fromDateString, toDateString } from "./dateUtils.js";
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
const DateWheel = ({
|
|
8
|
+
value,
|
|
9
|
+
onChange,
|
|
10
|
+
minimumDate,
|
|
11
|
+
maximumDate,
|
|
12
|
+
textColor,
|
|
13
|
+
style
|
|
14
|
+
}) => /*#__PURE__*/_jsx(TatilWheelDatePickerView, {
|
|
15
|
+
style: [styles.wheel, style],
|
|
16
|
+
value: toDateString(value),
|
|
17
|
+
...(minimumDate && {
|
|
18
|
+
minDate: toDateString(minimumDate)
|
|
19
|
+
}),
|
|
20
|
+
...(maximumDate && {
|
|
21
|
+
maxDate: toDateString(maximumDate)
|
|
22
|
+
}),
|
|
23
|
+
...(textColor && {
|
|
24
|
+
textColor
|
|
25
|
+
}),
|
|
26
|
+
onDateChange: ({
|
|
27
|
+
nativeEvent
|
|
28
|
+
}) => onChange(fromDateString(nativeEvent.date))
|
|
29
|
+
});
|
|
30
|
+
const styles = StyleSheet.create({
|
|
31
|
+
wheel: {
|
|
32
|
+
width: '100%',
|
|
33
|
+
height: 200
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
export default DateWheel;
|
|
37
|
+
//# sourceMappingURL=DateWheel.android.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["StyleSheet","TatilWheelDatePickerView","fromDateString","toDateString","jsx","_jsx","DateWheel","value","onChange","minimumDate","maximumDate","textColor","style","styles","wheel","minDate","maxDate","onDateChange","nativeEvent","date","create","width","height"],"sourceRoot":"../../src","sources":["DateWheel.android.tsx"],"mappings":";;AAAA,SAASA,UAAU,QAAQ,cAAc;AAEzC,OAAOC,wBAAwB,MAAM,2CAA2C;AAChF,SAASC,cAAc,EAAEC,YAAY,QAAQ,gBAAa;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAG3D,MAAMC,SAAS,GAAGA,CAAC;EACjBC,KAAK;EACLC,QAAQ;EACRC,WAAW;EACXC,WAAW;EACXC,SAAS;EACTC;AACc,CAAC,kBACfP,IAAA,CAACJ,wBAAwB;EACvBW,KAAK,EAAE,CAACC,MAAM,CAACC,KAAK,EAAEF,KAAK,CAAE;EAC7BL,KAAK,EAAEJ,YAAY,CAACI,KAAK,CAAE;EAAA,IACtBE,WAAW,IAAI;IAAEM,OAAO,EAAEZ,YAAY,CAACM,WAAW;EAAE,CAAC;EAAA,IACrDC,WAAW,IAAI;IAAEM,OAAO,EAAEb,YAAY,CAACO,WAAW;EAAE,CAAC;EAAA,IACrDC,SAAS,IAAI;IAAEA;EAAU,CAAC;EAC/BM,YAAY,EAAEA,CAAC;IAAEC;EAAY,CAAC,KAC5BV,QAAQ,CAACN,cAAc,CAACgB,WAAW,CAACC,IAAI,CAAC;AAC1C,CACF,CACF;AAED,MAAMN,MAAM,GAAGb,UAAU,CAACoB,MAAM,CAAC;EAC/BN,KAAK,EAAE;IACLO,KAAK,EAAE,MAAM;IACbC,MAAM,EAAE;EACV;AACF,CAAC,CAAC;AAEF,eAAehB,SAAS","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import DateTimePicker from '@react-native-community/datetimepicker';
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
// Inline UIDatePicker wheels.
|
|
6
|
+
const DateWheel = ({
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
minimumDate,
|
|
10
|
+
maximumDate,
|
|
11
|
+
textColor,
|
|
12
|
+
locale,
|
|
13
|
+
style
|
|
14
|
+
}) => /*#__PURE__*/_jsx(DateTimePicker, {
|
|
15
|
+
value: value,
|
|
16
|
+
mode: "date",
|
|
17
|
+
display: "spinner",
|
|
18
|
+
themeVariant: "light",
|
|
19
|
+
...(style && {
|
|
20
|
+
style
|
|
21
|
+
}),
|
|
22
|
+
...(locale && {
|
|
23
|
+
locale
|
|
24
|
+
}),
|
|
25
|
+
...(textColor && {
|
|
26
|
+
textColor
|
|
27
|
+
}),
|
|
28
|
+
...(minimumDate && {
|
|
29
|
+
minimumDate
|
|
30
|
+
}),
|
|
31
|
+
...(maximumDate && {
|
|
32
|
+
maximumDate
|
|
33
|
+
}),
|
|
34
|
+
onValueChange: (_, date) => onChange(date)
|
|
35
|
+
});
|
|
36
|
+
export default DateWheel;
|
|
37
|
+
//# sourceMappingURL=DateWheel.ios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DateTimePicker","jsx","_jsx","DateWheel","value","onChange","minimumDate","maximumDate","textColor","locale","style","mode","display","themeVariant","onValueChange","_","date"],"sourceRoot":"../../src","sources":["DateWheel.ios.tsx"],"mappings":";;AAAA,OAAOA,cAAc,MAAM,wCAAwC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAIpE;AACA,MAAMC,SAAS,GAAGA,CAAC;EACjBC,KAAK;EACLC,QAAQ;EACRC,WAAW;EACXC,WAAW;EACXC,SAAS;EACTC,MAAM;EACNC;AACc,CAAC,kBACfR,IAAA,CAACF,cAAc;EACbI,KAAK,EAAEA,KAAM;EACbO,IAAI,EAAC,MAAM;EACXC,OAAO,EAAC,SAAS;EACjBC,YAAY,EAAC,OAAO;EAAA,IACfH,KAAK,IAAI;IAAEA;EAAM,CAAC;EAAA,IAClBD,MAAM,IAAI;IAAEA;EAAO,CAAC;EAAA,IACpBD,SAAS,IAAI;IAAEA;EAAU,CAAC;EAAA,IAC1BF,WAAW,IAAI;IAAEA;EAAY,CAAC;EAAA,IAC9BC,WAAW,IAAI;IAAEA;EAAY,CAAC;EACnCO,aAAa,EAAEA,CAACC,CAAC,EAAEC,IAAI,KAAKX,QAAQ,CAACW,IAAI;AAAE,CAC5C,CACF;AAED,eAAeb,SAAS","ignoreList":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Platforms other than Android and iOS (e.g. web) are not supported.
|
|
4
|
+
const DateWheel = _props => {
|
|
5
|
+
throw new Error("'@tatil/react-native-wheel-date-picker' is only supported on Android and iOS.");
|
|
6
|
+
};
|
|
7
|
+
export default DateWheel;
|
|
8
|
+
//# sourceMappingURL=DateWheel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DateWheel","_props","Error"],"sourceRoot":"../../src","sources":["DateWheel.tsx"],"mappings":";;AAEA;AACA,MAAMA,SAAS,GAAIC,MAAsB,IAAY;EACnD,MAAM,IAAIC,KAAK,CACb,+EACF,CAAC;AACH,CAAC;AAED,eAAeF,SAAS","ignoreList":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen spec of the Android date wheel (android.widget.DatePicker in spinner
|
|
3
|
+
* mode). Dates are 'YYYY-MM-DD' strings so no time zone is involved.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
codegenNativeComponent,
|
|
7
|
+
type CodegenTypes,
|
|
8
|
+
type ColorValue,
|
|
9
|
+
type HostComponent,
|
|
10
|
+
type ViewProps,
|
|
11
|
+
} from 'react-native';
|
|
12
|
+
|
|
13
|
+
type DateChangeEvent = Readonly<{
|
|
14
|
+
date: string;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
interface NativeProps extends ViewProps {
|
|
18
|
+
value: string;
|
|
19
|
+
minDate?: string;
|
|
20
|
+
maxDate?: string;
|
|
21
|
+
textColor?: ColorValue;
|
|
22
|
+
onDateChange?: CodegenTypes.DirectEventHandler<DateChangeEvent>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default codegenNativeComponent<NativeProps>(
|
|
26
|
+
'TatilWheelDatePickerView',
|
|
27
|
+
) as HostComponent<NativeProps>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import DateWheel from './DateWheel';
|
|
4
|
+
import { toLocalNoon } from "./dateUtils.js";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
/**
|
|
7
|
+
* Inline native date wheel: Android DatePicker spinner, iOS UIDatePicker
|
|
8
|
+
* wheels. Every date going in and out is normalized to 12:00 local time.
|
|
9
|
+
*/
|
|
10
|
+
export const WheelDatePicker = ({
|
|
11
|
+
value,
|
|
12
|
+
onChange,
|
|
13
|
+
minimumDate,
|
|
14
|
+
maximumDate,
|
|
15
|
+
...rest
|
|
16
|
+
}) => /*#__PURE__*/_jsx(DateWheel, {
|
|
17
|
+
...rest,
|
|
18
|
+
value: toLocalNoon(value),
|
|
19
|
+
...(minimumDate && {
|
|
20
|
+
minimumDate: toLocalNoon(minimumDate)
|
|
21
|
+
}),
|
|
22
|
+
...(maximumDate && {
|
|
23
|
+
maximumDate: toLocalNoon(maximumDate)
|
|
24
|
+
}),
|
|
25
|
+
onChange: date => onChange(toLocalNoon(date))
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=WheelDatePicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DateWheel","toLocalNoon","jsx","_jsx","WheelDatePicker","value","onChange","minimumDate","maximumDate","rest","date"],"sourceRoot":"../../src","sources":["WheelDatePicker.tsx"],"mappings":";;AAAA,OAAOA,SAAS,MAAM,aAAa;AACnC,SAASC,WAAW,QAAQ,gBAAa;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAG1C;AACA;AACA;AACA;AACA,OAAO,MAAMC,eAAe,GAAGA,CAAC;EAC9BC,KAAK;EACLC,QAAQ;EACRC,WAAW;EACXC,WAAW;EACX,GAAGC;AACiB,CAAC,kBACrBN,IAAA,CAACH,SAAS;EAAA,GACJS,IAAI;EACRJ,KAAK,EAAEJ,WAAW,CAACI,KAAK,CAAE;EAAA,IACrBE,WAAW,IAAI;IAAEA,WAAW,EAAEN,WAAW,CAACM,WAAW;EAAE,CAAC;EAAA,IACxDC,WAAW,IAAI;IAAEA,WAAW,EAAEP,WAAW,CAACO,WAAW;EAAE,CAAC;EAC7DF,QAAQ,EAAEI,IAAI,IAAIJ,QAAQ,CAACL,WAAW,CAACS,IAAI,CAAC;AAAE,CAC/C,CACF","ignoreList":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dates exchanged with the wheels are kept at 12:00 local time. Some time
|
|
5
|
+
* zones changed their offset in the past (e.g. Türkiye before 2016), so a
|
|
6
|
+
* midnight Date can shift to 23:00 of the previous day in conversions; noon
|
|
7
|
+
* leaves room on both sides.
|
|
8
|
+
*/
|
|
9
|
+
export const toLocalNoon = date => new Date(date.getFullYear(), date.getMonth(), date.getDate(), 12);
|
|
10
|
+
const pad = number => String(number).padStart(2, '0');
|
|
11
|
+
export const toDateString = date => `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
12
|
+
export const fromDateString = dateString => {
|
|
13
|
+
const [year = 1970, month = 1, day = 1] = dateString.split('-').map(Number);
|
|
14
|
+
return new Date(year, month - 1, day, 12);
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=dateUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["toLocalNoon","date","Date","getFullYear","getMonth","getDate","pad","number","String","padStart","toDateString","fromDateString","dateString","year","month","day","split","map","Number"],"sourceRoot":"../../src","sources":["dateUtils.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,WAAW,GAAIC,IAAU,IACpC,IAAIC,IAAI,CAACD,IAAI,CAACE,WAAW,CAAC,CAAC,EAAEF,IAAI,CAACG,QAAQ,CAAC,CAAC,EAAEH,IAAI,CAACI,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC;AAEnE,MAAMC,GAAG,GAAIC,MAAc,IAAaC,MAAM,CAACD,MAAM,CAAC,CAACE,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;AAEvE,OAAO,MAAMC,YAAY,GAAIT,IAAU,IACrC,GAAGA,IAAI,CAACE,WAAW,CAAC,CAAC,IAAIG,GAAG,CAACL,IAAI,CAACG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAIE,GAAG,CAACL,IAAI,CAACI,OAAO,CAAC,CAAC,CAAC,EAAE;AAE5E,OAAO,MAAMM,cAAc,GAAIC,UAAkB,IAAW;EAC1D,MAAM,CAACC,IAAI,GAAG,IAAI,EAAEC,KAAK,GAAG,CAAC,EAAEC,GAAG,GAAG,CAAC,CAAC,GAAGH,UAAU,CAACI,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CAACC,MAAM,CAAC;EAC3E,OAAO,IAAIhB,IAAI,CAACW,IAAI,EAAEC,KAAK,GAAG,CAAC,EAAEC,GAAG,EAAE,EAAE,CAAC;AAC3C,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["WheelDatePicker"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,eAAe,QAAQ,sBAAmB","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateWheel.android.d.ts","sourceRoot":"","sources":["../../../src/DateWheel.android.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAE9C,QAAA,MAAM,SAAS,GAAI,kEAOhB,cAAc,gCAWhB,CAAC;AASF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateWheel.d.ts","sourceRoot":"","sources":["../../../src/DateWheel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAG9C,QAAA,MAAM,SAAS,GAAI,QAAQ,cAAc,KAAG,KAI3C,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateWheel.ios.d.ts","sourceRoot":"","sources":["../../../src/DateWheel.ios.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAG9C,QAAA,MAAM,SAAS,GAAI,0EAQhB,cAAc,gCAahB,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen spec of the Android date wheel (android.widget.DatePicker in spinner
|
|
3
|
+
* mode). Dates are 'YYYY-MM-DD' strings so no time zone is involved.
|
|
4
|
+
*/
|
|
5
|
+
import { type CodegenTypes, type ColorValue, type HostComponent, type ViewProps } from 'react-native';
|
|
6
|
+
type DateChangeEvent = Readonly<{
|
|
7
|
+
date: string;
|
|
8
|
+
}>;
|
|
9
|
+
interface NativeProps extends ViewProps {
|
|
10
|
+
value: string;
|
|
11
|
+
minDate?: string;
|
|
12
|
+
maxDate?: string;
|
|
13
|
+
textColor?: ColorValue;
|
|
14
|
+
onDateChange?: CodegenTypes.DirectEventHandler<DateChangeEvent>;
|
|
15
|
+
}
|
|
16
|
+
declare const _default: HostComponent<NativeProps>;
|
|
17
|
+
export default _default;
|
|
18
|
+
//# sourceMappingURL=TatilWheelDatePickerViewNativeComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TatilWheelDatePickerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/TatilWheelDatePickerViewNativeComponent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAEtB,KAAK,eAAe,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH,UAAU,WAAY,SAAQ,SAAS;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;CACjE;wBAII,aAAa,CAAC,WAAW,CAAC;AAF/B,wBAEgC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { WheelDatePickerProps } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Inline native date wheel: Android DatePicker spinner, iOS UIDatePicker
|
|
4
|
+
* wheels. Every date going in and out is normalized to 12:00 local time.
|
|
5
|
+
*/
|
|
6
|
+
export declare const WheelDatePicker: ({ value, onChange, minimumDate, maximumDate, ...rest }: WheelDatePickerProps) => import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=WheelDatePicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WheelDatePicker.d.ts","sourceRoot":"","sources":["../../../src/WheelDatePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAS,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,wDAM7B,oBAAoB,gCAQtB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dates exchanged with the wheels are kept at 12:00 local time. Some time
|
|
3
|
+
* zones changed their offset in the past (e.g. Türkiye before 2016), so a
|
|
4
|
+
* midnight Date can shift to 23:00 of the previous day in conversions; noon
|
|
5
|
+
* leaves room on both sides.
|
|
6
|
+
*/
|
|
7
|
+
export declare const toLocalNoon: (date: Date) => Date;
|
|
8
|
+
export declare const toDateString: (date: Date) => string;
|
|
9
|
+
export declare const fromDateString: (dateString: string) => Date;
|
|
10
|
+
//# sourceMappingURL=dateUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateUtils.d.ts","sourceRoot":"","sources":["../../../src/dateUtils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,IAAI,KAAG,IAC0B,CAAC;AAIpE,eAAO,MAAM,YAAY,GAAI,MAAM,IAAI,KAAG,MACkC,CAAC;AAE7E,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,KAAG,IAGnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAS,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
export type WheelDatePickerProps = {
|
|
3
|
+
/** Selected date. The picker is controlled: update it in `onChange`. */
|
|
4
|
+
value: Date;
|
|
5
|
+
/** Called on every wheel step, before scrolling settles. */
|
|
6
|
+
onChange: (date: Date) => void;
|
|
7
|
+
minimumDate?: Date;
|
|
8
|
+
maximumDate?: Date;
|
|
9
|
+
/**
|
|
10
|
+
* Wheel text color, e.g. '#1F1F1F'. On Android it applies from Android 10
|
|
11
|
+
* (API 29); below that the theme color is used.
|
|
12
|
+
*/
|
|
13
|
+
textColor?: string;
|
|
14
|
+
/**
|
|
15
|
+
* iOS only, e.g. 'tr-TR'. Android follows the device language for month
|
|
16
|
+
* names and wheel order.
|
|
17
|
+
*/
|
|
18
|
+
locale?: string;
|
|
19
|
+
style?: StyleProp<ViewStyle>;
|
|
20
|
+
};
|
|
21
|
+
export type DateWheelProps = WheelDatePickerProps;
|
|
22
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAAG;IACjC,wEAAwE;IACxE,KAAK,EAAE,IAAI,CAAC;IACZ,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,137 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tatil/react-native-wheel-date-picker",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Native inline wheel date picker for React Native (New Architecture): Android DatePicker spinner, iOS UIDatePicker wheels.",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"tatil-react-native-wheel-date-picker-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
|
+
"android",
|
|
19
|
+
"react-native.config.js",
|
|
20
|
+
"!android/build",
|
|
21
|
+
"!android/gradle",
|
|
22
|
+
"!android/gradlew",
|
|
23
|
+
"!android/gradlew.bat",
|
|
24
|
+
"!android/local.properties",
|
|
25
|
+
"!**/*.iml",
|
|
26
|
+
"!**/*.tgz",
|
|
27
|
+
"!**/*.log",
|
|
28
|
+
"!**/*.tsbuildinfo",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"example": "yarn workspace @tatil/react-native-wheel-date-picker-example",
|
|
36
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
37
|
+
"prepare": "bob build",
|
|
38
|
+
"typecheck": "tsc",
|
|
39
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"react-native",
|
|
43
|
+
"android",
|
|
44
|
+
"ios",
|
|
45
|
+
"date-picker",
|
|
46
|
+
"datepicker",
|
|
47
|
+
"wheel",
|
|
48
|
+
"spinner",
|
|
49
|
+
"fabric",
|
|
50
|
+
"new-architecture"
|
|
51
|
+
],
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://gitlab.tatilsepeti.com/tatilsepeti/react-native-wheel-date-picker.git"
|
|
55
|
+
},
|
|
56
|
+
"author": "Uğur Karataş <ugur.karatas@tatilsepeti.com> (https://www.npmjs.com/~ugur.karatas)",
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://gitlab.tatilsepeti.com/tatilsepeti/react-native-wheel-date-picker/-/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://gitlab.tatilsepeti.com/tatilsepeti/react-native-wheel-date-picker#readme",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"registry": "https://registry.npmjs.org/",
|
|
64
|
+
"access": "public"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@eslint/compat": "^2.1.0",
|
|
68
|
+
"@eslint/eslintrc": "^3.3.6",
|
|
69
|
+
"@eslint/js": "^9.39.5",
|
|
70
|
+
"@react-native-community/datetimepicker": "9.2.1",
|
|
71
|
+
"@react-native/babel-preset": "0.86.2",
|
|
72
|
+
"@react-native/eslint-config": "0.86.2",
|
|
73
|
+
"@types/react": "^19.2.0",
|
|
74
|
+
"del-cli": "^7.0.0",
|
|
75
|
+
"eslint": "^9.39.5",
|
|
76
|
+
"eslint-config-prettier": "^10.1.8",
|
|
77
|
+
"eslint-plugin-ft-flow": "^3.0.11",
|
|
78
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
79
|
+
"prettier": "^3.9.6",
|
|
80
|
+
"react": "19.2.3",
|
|
81
|
+
"react-native": "0.86.2",
|
|
82
|
+
"react-native-builder-bob": "^0.43.2",
|
|
83
|
+
"turbo": "^2.10.8",
|
|
84
|
+
"typescript": "^6.0.3"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"@react-native-community/datetimepicker": ">=9.1.0",
|
|
88
|
+
"react": ">=19.0.0",
|
|
89
|
+
"react-native": ">=0.80.0"
|
|
90
|
+
},
|
|
91
|
+
"workspaces": [
|
|
92
|
+
"example"
|
|
93
|
+
],
|
|
94
|
+
"packageManager": "yarn@4.11.0",
|
|
95
|
+
"react-native-builder-bob": {
|
|
96
|
+
"source": "src",
|
|
97
|
+
"output": "lib",
|
|
98
|
+
"targets": [
|
|
99
|
+
[
|
|
100
|
+
"module",
|
|
101
|
+
{
|
|
102
|
+
"esm": true
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
"typescript",
|
|
107
|
+
{
|
|
108
|
+
"project": "tsconfig.build.json"
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
"codegenConfig": {
|
|
114
|
+
"name": "TatilWheelDatePickerSpec",
|
|
115
|
+
"type": "components",
|
|
116
|
+
"jsSrcsDir": "src",
|
|
117
|
+
"android": {
|
|
118
|
+
"javaPackageName": "com.tatil.wheeldatepicker"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"prettier": {
|
|
122
|
+
"arrowParens": "avoid",
|
|
123
|
+
"quoteProps": "consistent",
|
|
124
|
+
"singleQuote": true,
|
|
125
|
+
"tabWidth": 2,
|
|
126
|
+
"trailingComma": "all",
|
|
127
|
+
"useTabs": false
|
|
128
|
+
},
|
|
129
|
+
"create-react-native-library": {
|
|
130
|
+
"type": "fabric-view",
|
|
131
|
+
"languages": "kotlin-objc",
|
|
132
|
+
"tools": [
|
|
133
|
+
"eslint"
|
|
134
|
+
],
|
|
135
|
+
"version": "0.63.1"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import TatilWheelDatePickerView from './TatilWheelDatePickerViewNativeComponent';
|
|
4
|
+
import { fromDateString, toDateString } from './dateUtils';
|
|
5
|
+
import type { DateWheelProps } from './types';
|
|
6
|
+
|
|
7
|
+
const DateWheel = ({
|
|
8
|
+
value,
|
|
9
|
+
onChange,
|
|
10
|
+
minimumDate,
|
|
11
|
+
maximumDate,
|
|
12
|
+
textColor,
|
|
13
|
+
style,
|
|
14
|
+
}: DateWheelProps) => (
|
|
15
|
+
<TatilWheelDatePickerView
|
|
16
|
+
style={[styles.wheel, style]}
|
|
17
|
+
value={toDateString(value)}
|
|
18
|
+
{...(minimumDate && { minDate: toDateString(minimumDate) })}
|
|
19
|
+
{...(maximumDate && { maxDate: toDateString(maximumDate) })}
|
|
20
|
+
{...(textColor && { textColor })}
|
|
21
|
+
onDateChange={({ nativeEvent }) =>
|
|
22
|
+
onChange(fromDateString(nativeEvent.date))
|
|
23
|
+
}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const styles = StyleSheet.create({
|
|
28
|
+
wheel: {
|
|
29
|
+
width: '100%',
|
|
30
|
+
height: 200,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export default DateWheel;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import DateTimePicker from '@react-native-community/datetimepicker';
|
|
2
|
+
|
|
3
|
+
import type { DateWheelProps } from './types';
|
|
4
|
+
|
|
5
|
+
// Inline UIDatePicker wheels.
|
|
6
|
+
const DateWheel = ({
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
minimumDate,
|
|
10
|
+
maximumDate,
|
|
11
|
+
textColor,
|
|
12
|
+
locale,
|
|
13
|
+
style,
|
|
14
|
+
}: DateWheelProps) => (
|
|
15
|
+
<DateTimePicker
|
|
16
|
+
value={value}
|
|
17
|
+
mode="date"
|
|
18
|
+
display="spinner"
|
|
19
|
+
themeVariant="light"
|
|
20
|
+
{...(style && { style })}
|
|
21
|
+
{...(locale && { locale })}
|
|
22
|
+
{...(textColor && { textColor })}
|
|
23
|
+
{...(minimumDate && { minimumDate })}
|
|
24
|
+
{...(maximumDate && { maximumDate })}
|
|
25
|
+
onValueChange={(_, date) => onChange(date)}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default DateWheel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DateWheelProps } from './types';
|
|
2
|
+
|
|
3
|
+
// Platforms other than Android and iOS (e.g. web) are not supported.
|
|
4
|
+
const DateWheel = (_props: DateWheelProps): never => {
|
|
5
|
+
throw new Error(
|
|
6
|
+
"'@tatil/react-native-wheel-date-picker' is only supported on Android and iOS.",
|
|
7
|
+
);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default DateWheel;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen spec of the Android date wheel (android.widget.DatePicker in spinner
|
|
3
|
+
* mode). Dates are 'YYYY-MM-DD' strings so no time zone is involved.
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
codegenNativeComponent,
|
|
7
|
+
type CodegenTypes,
|
|
8
|
+
type ColorValue,
|
|
9
|
+
type HostComponent,
|
|
10
|
+
type ViewProps,
|
|
11
|
+
} from 'react-native';
|
|
12
|
+
|
|
13
|
+
type DateChangeEvent = Readonly<{
|
|
14
|
+
date: string;
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
interface NativeProps extends ViewProps {
|
|
18
|
+
value: string;
|
|
19
|
+
minDate?: string;
|
|
20
|
+
maxDate?: string;
|
|
21
|
+
textColor?: ColorValue;
|
|
22
|
+
onDateChange?: CodegenTypes.DirectEventHandler<DateChangeEvent>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default codegenNativeComponent<NativeProps>(
|
|
26
|
+
'TatilWheelDatePickerView',
|
|
27
|
+
) as HostComponent<NativeProps>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import DateWheel from './DateWheel';
|
|
2
|
+
import { toLocalNoon } from './dateUtils';
|
|
3
|
+
import type { WheelDatePickerProps } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Inline native date wheel: Android DatePicker spinner, iOS UIDatePicker
|
|
7
|
+
* wheels. Every date going in and out is normalized to 12:00 local time.
|
|
8
|
+
*/
|
|
9
|
+
export const WheelDatePicker = ({
|
|
10
|
+
value,
|
|
11
|
+
onChange,
|
|
12
|
+
minimumDate,
|
|
13
|
+
maximumDate,
|
|
14
|
+
...rest
|
|
15
|
+
}: WheelDatePickerProps) => (
|
|
16
|
+
<DateWheel
|
|
17
|
+
{...rest}
|
|
18
|
+
value={toLocalNoon(value)}
|
|
19
|
+
{...(minimumDate && { minimumDate: toLocalNoon(minimumDate) })}
|
|
20
|
+
{...(maximumDate && { maximumDate: toLocalNoon(maximumDate) })}
|
|
21
|
+
onChange={date => onChange(toLocalNoon(date))}
|
|
22
|
+
/>
|
|
23
|
+
);
|
package/src/dateUtils.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dates exchanged with the wheels are kept at 12:00 local time. Some time
|
|
3
|
+
* zones changed their offset in the past (e.g. Türkiye before 2016), so a
|
|
4
|
+
* midnight Date can shift to 23:00 of the previous day in conversions; noon
|
|
5
|
+
* leaves room on both sides.
|
|
6
|
+
*/
|
|
7
|
+
export const toLocalNoon = (date: Date): Date =>
|
|
8
|
+
new Date(date.getFullYear(), date.getMonth(), date.getDate(), 12);
|
|
9
|
+
|
|
10
|
+
const pad = (number: number): string => String(number).padStart(2, '0');
|
|
11
|
+
|
|
12
|
+
export const toDateString = (date: Date): string =>
|
|
13
|
+
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
14
|
+
|
|
15
|
+
export const fromDateString = (dateString: string): Date => {
|
|
16
|
+
const [year = 1970, month = 1, day = 1] = dateString.split('-').map(Number);
|
|
17
|
+
return new Date(year, month - 1, day, 12);
|
|
18
|
+
};
|
package/src/index.tsx
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export type WheelDatePickerProps = {
|
|
4
|
+
/** Selected date. The picker is controlled: update it in `onChange`. */
|
|
5
|
+
value: Date;
|
|
6
|
+
/** Called on every wheel step, before scrolling settles. */
|
|
7
|
+
onChange: (date: Date) => void;
|
|
8
|
+
minimumDate?: Date;
|
|
9
|
+
maximumDate?: Date;
|
|
10
|
+
/**
|
|
11
|
+
* Wheel text color, e.g. '#1F1F1F'. On Android it applies from Android 10
|
|
12
|
+
* (API 29); below that the theme color is used.
|
|
13
|
+
*/
|
|
14
|
+
textColor?: string;
|
|
15
|
+
/**
|
|
16
|
+
* iOS only, e.g. 'tr-TR'. Android follows the device language for month
|
|
17
|
+
* names and wheel order.
|
|
18
|
+
*/
|
|
19
|
+
locale?: string;
|
|
20
|
+
style?: StyleProp<ViewStyle>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type DateWheelProps = WheelDatePickerProps;
|