@tatil/react-native-wheel-date-picker 0.0.0-stage → 0.1.0

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.
Files changed (52) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +113 -2
  3. package/android/build.gradle +55 -0
  4. package/android/src/main/AndroidManifest.xml +2 -0
  5. package/android/src/main/java/com/tatil/wheeldatepicker/DateChangeEvent.kt +17 -0
  6. package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerPackage.kt +16 -0
  7. package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerView.kt +161 -0
  8. package/android/src/main/java/com/tatil/wheeldatepicker/TatilWheelDatePickerViewManager.kt +42 -0
  9. package/android/src/main/res/values/styles.xml +18 -0
  10. package/lib/module/DateWheel.android.js +37 -0
  11. package/lib/module/DateWheel.android.js.map +1 -0
  12. package/lib/module/DateWheel.ios.js +37 -0
  13. package/lib/module/DateWheel.ios.js.map +1 -0
  14. package/lib/module/DateWheel.js +8 -0
  15. package/lib/module/DateWheel.js.map +1 -0
  16. package/lib/module/TatilWheelDatePickerViewNativeComponent.ts +27 -0
  17. package/lib/module/WheelDatePicker.js +27 -0
  18. package/lib/module/WheelDatePicker.js.map +1 -0
  19. package/lib/module/dateUtils.js +16 -0
  20. package/lib/module/dateUtils.js.map +1 -0
  21. package/lib/module/index.js +4 -0
  22. package/lib/module/index.js.map +1 -0
  23. package/lib/module/package.json +1 -0
  24. package/lib/module/types.js +4 -0
  25. package/lib/module/types.js.map +1 -0
  26. package/lib/typescript/package.json +1 -0
  27. package/lib/typescript/src/DateWheel.android.d.ts +4 -0
  28. package/lib/typescript/src/DateWheel.android.d.ts.map +1 -0
  29. package/lib/typescript/src/DateWheel.d.ts +4 -0
  30. package/lib/typescript/src/DateWheel.d.ts.map +1 -0
  31. package/lib/typescript/src/DateWheel.ios.d.ts +4 -0
  32. package/lib/typescript/src/DateWheel.ios.d.ts.map +1 -0
  33. package/lib/typescript/src/TatilWheelDatePickerViewNativeComponent.d.ts +18 -0
  34. package/lib/typescript/src/TatilWheelDatePickerViewNativeComponent.d.ts.map +1 -0
  35. package/lib/typescript/src/WheelDatePicker.d.ts +7 -0
  36. package/lib/typescript/src/WheelDatePicker.d.ts.map +1 -0
  37. package/lib/typescript/src/dateUtils.d.ts +10 -0
  38. package/lib/typescript/src/dateUtils.d.ts.map +1 -0
  39. package/lib/typescript/src/index.d.ts +3 -0
  40. package/lib/typescript/src/index.d.ts.map +1 -0
  41. package/lib/typescript/src/types.d.ts +22 -0
  42. package/lib/typescript/src/types.d.ts.map +1 -0
  43. package/package.json +135 -4
  44. package/react-native.config.js +10 -0
  45. package/src/DateWheel.android.tsx +34 -0
  46. package/src/DateWheel.ios.tsx +29 -0
  47. package/src/DateWheel.tsx +10 -0
  48. package/src/TatilWheelDatePickerViewNativeComponent.ts +27 -0
  49. package/src/WheelDatePicker.tsx +23 -0
  50. package/src/dateUtils.ts +18 -0
  51. package/src/index.tsx +2 -0
  52. 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
- # Temporary Holding Version
1
+ # @tatil/react-native-wheel-date-picker
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -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,4 @@
1
+ "use strict";
2
+
3
+ export { WheelDatePicker } from "./WheelDatePicker.js";
4
+ //# sourceMappingURL=index.js.map
@@ -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,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,4 @@
1
+ import type { DateWheelProps } from './types.js';
2
+ declare const DateWheel: ({ value, onChange, minimumDate, maximumDate, textColor, style, }: DateWheelProps) => import("react").JSX.Element;
3
+ export default DateWheel;
4
+ //# sourceMappingURL=DateWheel.android.d.ts.map
@@ -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,4 @@
1
+ import type { DateWheelProps } from './types.js';
2
+ declare const DateWheel: (_props: DateWheelProps) => never;
3
+ export default DateWheel;
4
+ //# sourceMappingURL=DateWheel.d.ts.map
@@ -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,4 @@
1
+ import type { DateWheelProps } from './types.js';
2
+ declare const DateWheel: ({ value, onChange, minimumDate, maximumDate, textColor, locale, style, }: DateWheelProps) => import("react").JSX.Element;
3
+ export default DateWheel;
4
+ //# sourceMappingURL=DateWheel.ios.d.ts.map
@@ -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,3 @@
1
+ export { WheelDatePicker } from './WheelDatePicker.js';
2
+ export type { WheelDatePickerProps } from './types.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
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,10 @@
1
+ // The native code is Android only. On iOS the JS side renders
2
+ // @react-native-community/datetimepicker, so iOS autolinking and codegen skip
3
+ // this package.
4
+ module.exports = {
5
+ dependency: {
6
+ platforms: {
7
+ ios: null,
8
+ },
9
+ },
10
+ };
@@ -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
+ );
@@ -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
@@ -0,0 +1,2 @@
1
+ export { WheelDatePicker } from './WheelDatePicker';
2
+ export type { WheelDatePickerProps } from './types';
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;