react-native-platform-components 0.3.1 → 0.4.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.
package/README.md CHANGED
@@ -1,43 +1,22 @@
1
1
  # react-native-platform-components
2
2
 
3
- > 🚧 In development — not ready for public use.
4
-
5
3
  High-quality **native UI components for React Native**, implemented with platform-first APIs and exposed through clean, typed JavaScript interfaces.
6
4
 
7
- This library focuses on **true native behavior**, not JavaScript re-implementations — starting with:
5
+ This library focuses on **true native behavior**, not JavaScript re-implementations — providing:
8
6
 
9
- - **SelectionMenu** – native selection menus (Material on Android, system menus on iOS, web fallback)
10
- - **DatePicker** – native date & time pickers with modal and inline presentations
7
+ - **SelectionMenu** – native selection menus (Material on Android, system menus on iOS)
8
+ - **DatePicker** – native date & time pickers with modal and embedded presentations
11
9
 
12
10
  The goal is to provide components that:
13
11
 
14
12
  - Feel **100% native** on each platform
15
- - Support modern platform design systems (Material 2 / Material 3 on Android, system pickers on iOS)
13
+ - Support modern platform design systems (Material 3 on Android, system pickers on iOS)
16
14
  - Offer **headless** and **inline** modes for maximum layout control
17
15
  - Integrate cleanly with **React Native Codegen / Fabric**
18
- - Degrade gracefully on **Web**
19
-
20
- ---
21
-
22
- ## 🎥 Demos
23
-
24
- ### SelectionMenu
25
- Native Material / system selection menus with headless and inline modes.
26
-
27
- 📹 **Demo video:**
28
- 👉 *(add SelectionMenu demo link here)*
29
16
 
30
17
  ---
31
18
 
32
- ### DatePicker
33
- Native date & time pickers using platform system UI.
34
-
35
- 📹 **Demo video:**
36
- 👉 *(add DatePicker demo link here)*
37
-
38
- ---
39
-
40
- ## 📦 Installation
19
+ ## Installation
41
20
 
42
21
  ```sh
43
22
  npm install react-native-platform-components
@@ -53,22 +32,17 @@ pod install
53
32
  ```
54
33
 
55
34
  - Minimum iOS version: **iOS 13+**
56
- - Uses `UIDatePicker` and system selection menus
35
+ - Uses `UIDatePicker` and SwiftUI Menu
57
36
 
58
37
  ### Android
59
38
 
60
- - Uses native Android Views
61
- - Supports **Material 2** and **Material 3**
39
+ - Uses native Android Views with Material Design
40
+ - Supports **Material 3** styling
62
41
  - No additional setup required beyond autolinking
63
42
 
64
- ### Web
65
-
66
- - **SelectionMenu** is supported with a web-appropriate fallback
67
- - **DatePicker** currently targets native platforms only
68
-
69
43
  ---
70
44
 
71
- ## 🚀 Quick Start
45
+ ## Quick Start
72
46
 
73
47
  ### SelectionMenu (Headless)
74
48
 
@@ -104,6 +78,33 @@ export function Example() {
104
78
  }
105
79
  ```
106
80
 
81
+ ### SelectionMenu (Inline)
82
+
83
+ ```tsx
84
+ import { SelectionMenu } from 'react-native-platform-components';
85
+
86
+ const options = [
87
+ { label: 'Apple', data: 'apple' },
88
+ { label: 'Banana', data: 'banana' },
89
+ { label: 'Orange', data: 'orange' },
90
+ ];
91
+
92
+ export function Example() {
93
+ const [value, setValue] = React.useState<string | null>(null);
94
+
95
+ return (
96
+ <SelectionMenu
97
+ options={options}
98
+ selected={value}
99
+ inlineMode
100
+ placeholder="Select fruit"
101
+ onSelect={(data) => setValue(data)}
102
+ android={{ material: 'm3' }}
103
+ />
104
+ );
105
+ }
106
+ ```
107
+
107
108
  ---
108
109
 
109
110
  ### DatePicker (Modal)
@@ -134,45 +135,51 @@ export function Example() {
134
135
  }
135
136
  ```
136
137
 
137
- ---
138
-
139
- ## 🧩 Components
140
-
141
- ## SelectionMenu
138
+ ### DatePicker (Embedded)
142
139
 
143
- Native selection menu with **inline** and **headless** modes.
140
+ ```tsx
141
+ import { DatePicker } from 'react-native-platform-components';
144
142
 
145
- ### Props
143
+ export function Example() {
144
+ const [date, setDate] = React.useState<Date | null>(new Date());
146
145
 
147
- ```ts
148
- type SelectionMenuProps = {
149
- style?: StyleProp<ViewStyle>;
146
+ return (
147
+ <DatePicker
148
+ date={date}
149
+ presentation="embedded"
150
+ mode="dateAndTime"
151
+ onConfirm={(d) => setDate(d)}
152
+ />
153
+ );
154
+ }
155
+ ```
150
156
 
151
- options: readonly {
152
- label: string;
153
- data: string;
154
- }[];
157
+ ---
155
158
 
156
- selected: string | null;
159
+ ## Components
157
160
 
158
- disabled?: boolean;
159
- placeholder?: string;
161
+ ## SelectionMenu
160
162
 
161
- inlineMode?: boolean;
162
- visible?: boolean;
163
+ Native selection menu with **inline** and **headless** modes.
163
164
 
164
- presentation?: 'auto' | 'popover' | 'sheet';
165
+ ### Props
165
166
 
166
- onSelect?: (data: string, label: string, index: number) => void;
167
- onRequestClose?: () => void;
167
+ | Prop | Type | Description |
168
+ |------|------|-------------|
169
+ | `options` | `{ label: string; data: string }[]` | Array of options to display |
170
+ | `selected` | `string \| null` | Currently selected option's `data` value |
171
+ | `disabled` | `boolean` | Disables the menu |
172
+ | `placeholder` | `string` | Placeholder text when no selection |
173
+ | `inlineMode` | `boolean` | If true, renders native inline picker UI |
174
+ | `visible` | `boolean` | Controls headless mode menu visibility |
175
+ | `onSelect` | `(data, label, index) => void` | Called when user selects an option |
176
+ | `onRequestClose` | `() => void` | Called when menu is dismissed without selection |
177
+ | `android.material` | `'system' \| 'm3'` | Material Design style preference |
168
178
 
169
- ios?: {};
179
+ ### Modes
170
180
 
171
- android?: {
172
- material?: 'auto' | 'm2' | 'm3';
173
- };
174
- };
175
- ```
181
+ - **Headless mode** (default): Menu visibility controlled by `visible` prop. Use for custom trigger UI.
182
+ - **Inline mode** (`inlineMode={true}`): Native picker UI rendered inline. Menu managed internally.
176
183
 
177
184
  ---
178
185
 
@@ -182,54 +189,54 @@ Native date & time picker using **platform system pickers**.
182
189
 
183
190
  ### Props
184
191
 
185
- ```ts
186
- type DatePickerProps = {
187
- style?: StyleProp<ViewStyle>;
188
-
189
- date: Date | null;
190
-
191
- minDate?: Date | null;
192
- maxDate?: Date | null;
193
-
194
- locale?: string;
195
- timeZoneName?: string;
196
-
197
- mode?: 'date' | 'time' | 'dateAndTime' | 'countDownTimer';
198
- presentation?: 'modal' | 'inline';
199
-
200
- visible?: boolean;
201
-
202
- onConfirm?: (dateTime: Date) => void;
203
- onClosed?: () => void;
204
-
205
- ios?: {
206
- preferredStyle?: 'automatic' | 'wheels' | 'inline' | 'compact';
207
- countDownDurationSeconds?: number;
208
- minuteInterval?: number;
209
- roundsToMinuteInterval?: boolean;
210
- };
211
-
212
- android?: {
213
- firstDayOfWeek?: number;
214
- material?: 'auto' | 'm2' | 'm3';
215
- dialogTitle?: string;
216
- positiveButtonTitle?: string;
217
- negativeButtonTitle?: string;
218
- };
219
- };
220
- ```
192
+ | Prop | Type | Description |
193
+ |------|------|-------------|
194
+ | `date` | `Date \| null` | Controlled date value |
195
+ | `minDate` | `Date \| null` | Minimum selectable date |
196
+ | `maxDate` | `Date \| null` | Maximum selectable date |
197
+ | `locale` | `string` | Locale identifier (e.g., `'en-US'`) |
198
+ | `timeZoneName` | `string` | Time zone identifier |
199
+ | `mode` | `'date' \| 'time' \| 'dateAndTime' \| 'countDownTimer'` | Picker mode |
200
+ | `presentation` | `'modal' \| 'embedded'` | Presentation style |
201
+ | `visible` | `boolean` | Controls modal visibility (modal mode only) |
202
+ | `onConfirm` | `(date: Date) => void` | Called when user confirms selection |
203
+ | `onClosed` | `() => void` | Called when modal is dismissed |
204
+
205
+ ### iOS Props (`ios`)
206
+
207
+ | Prop | Type | Description |
208
+ |------|------|-------------|
209
+ | `preferredStyle` | `'automatic' \| 'compact' \| 'inline' \| 'wheels'` | iOS date picker style |
210
+ | `countDownDurationSeconds` | `number` | Duration for countdown timer mode |
211
+ | `minuteInterval` | `number` | Minute interval (1-30) |
212
+ | `roundsToMinuteInterval` | `'inherit' \| 'round' \| 'noRound'` | Rounding behavior |
213
+
214
+ ### Android Props (`android`)
215
+
216
+ | Prop | Type | Description |
217
+ |------|------|-------------|
218
+ | `firstDayOfWeek` | `number` | First day of week (1-7, Sunday=1) |
219
+ | `material` | `'system' \| 'm3'` | Material Design style |
220
+ | `dialogTitle` | `string` | Custom dialog title |
221
+ | `positiveButtonTitle` | `string` | Custom confirm button text |
222
+ | `negativeButtonTitle` | `string` | Custom cancel button text |
221
223
 
222
224
  ---
223
225
 
224
- ## 🧠 Design Philosophy
226
+ ## Design Philosophy
225
227
 
226
228
  - **Native first** — no JS re-implementation of pickers
227
229
  - **Headless-friendly** — works with any custom UI
228
- - **Codegen-safe** — string unions & sentinel values
230
+ - **Codegen-safe** — string unions & sentinel values for type safety
229
231
  - **Predictable behavior** — no surprise re-renders or layout hacks
232
+ - **Platform conventions** — respects native UX patterns
230
233
 
231
234
  ---
232
235
 
233
- ## 📄 License
236
+ ## Contributing
237
+
238
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
239
+
240
+ ## License
234
241
 
235
242
  MIT
@@ -0,0 +1,17 @@
1
+ package com.platformcomponents
2
+
3
+ /**
4
+ * Centralized sizing constants for Platform Components Android implementations.
5
+ * These values control touch targets, default dimensions, and fallback sizes.
6
+ */
7
+ object PCConstants {
8
+ // MARK: - Touch Targets
9
+
10
+ /** Minimum touch target height in dp (Material Design 3 recommends 48dp, we use 56dp for text fields) */
11
+ const val MIN_TOUCH_TARGET_HEIGHT_DP = 56f
12
+
13
+ // MARK: - Fallback Dimensions
14
+
15
+ /** Fallback width in dp when constraint width is unavailable */
16
+ const val FALLBACK_WIDTH_DP = 320f
17
+ }
@@ -5,6 +5,7 @@ import android.content.Context
5
5
  import android.content.ContextWrapper
6
6
  import android.content.DialogInterface
7
7
  import android.os.Build
8
+ import android.util.Log
8
9
  import android.view.Gravity
9
10
  import android.view.View
10
11
  import android.view.ViewGroup
@@ -27,6 +28,10 @@ import kotlin.math.min
27
28
 
28
29
  class PCDatePickerView(context: Context) : FrameLayout(context) {
29
30
 
31
+ companion object {
32
+ private const val TAG = "PCDatePicker"
33
+ }
34
+
30
35
  // --- Public props (set by manager) ---
31
36
  private var mode: String = "date" // "date" | "time" | "dateAndTime"
32
37
  private var presentation: String = "modal" // "inline" | "modal" | "popover" | "sheet" | "auto" (we treat non-inline as modal-ish)
@@ -80,6 +85,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context) {
80
85
  "date", "time", "dateAndTime" -> value
81
86
  else -> "date"
82
87
  }
88
+ Log.d(TAG, "applyMode mode=$mode")
83
89
  rebuildUI()
84
90
  }
85
91
 
@@ -94,6 +100,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context) {
94
100
  "open", "closed" -> value
95
101
  else -> "closed"
96
102
  }
103
+ Log.d(TAG, "applyVisible visible=$visible isInline=${isInline()}")
97
104
  if (isInline()) return
98
105
 
99
106
  if (visible == "open") presentIfNeeded() else dismissIfNeeded()
@@ -313,12 +320,13 @@ class PCDatePickerView(context: Context) : FrameLayout(context) {
313
320
  private fun presentIfNeeded() {
314
321
  if (showingModal) return
315
322
  val act = findFragmentActivity() ?: run {
316
- // If we cannot present, treat as cancel
323
+ Log.w(TAG, "presentIfNeeded: no FragmentActivity found")
317
324
  onCancel?.invoke()
318
325
  showingModal = false
319
326
  return
320
327
  }
321
328
 
329
+ Log.d(TAG, "presentIfNeeded mode=$mode material=$androidMaterialMode")
322
330
  showingModal = true
323
331
 
324
332
  when (mode) {
@@ -641,9 +649,8 @@ class PCDatePickerView(context: Context) : FrameLayout(context) {
641
649
  // -----------------------------
642
650
 
643
651
  private fun onCancelOrClose() {
652
+ Log.d(TAG, "onCancelOrClose")
644
653
  showingModal = false
645
- // JS typically sets visible="closed" in response to onCancel/onConfirm,
646
- // but we defensively mark ourselves closed.
647
654
  }
648
655
 
649
656
  private fun clamp(valueMs: Long): Long {
@@ -59,7 +59,7 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context) {
59
59
  }
60
60
 
61
61
  private val minInlineHeightPx: Int by lazy {
62
- (56f * resources.displayMetrics.density).toInt() // M3 default touch target
62
+ (PCConstants.MIN_TOUCH_TARGET_HEIGHT_DP * resources.displayMetrics.density).toInt()
63
63
  }
64
64
 
65
65
  // Headless needs a non-zero anchor rect for dropdown
@@ -0,0 +1,34 @@
1
+ import UIKit
2
+
3
+ /// Centralized sizing constants for Platform Components iOS implementations.
4
+ /// These values control touch targets, popover sizes, and fallback dimensions.
5
+ enum PCConstants {
6
+ // MARK: - Touch Targets
7
+
8
+ /// Minimum touch target height (Apple HIG recommends 44pt)
9
+ static let minTouchTargetHeight: CGFloat = 44
10
+
11
+ // MARK: - Popover Sizing
12
+
13
+ /// Default popover width for selection menus
14
+ static let popoverWidth: CGFloat = 250
15
+
16
+ /// Maximum popover height before scrolling
17
+ static let popoverMaxHeight: CGFloat = 400
18
+
19
+ /// Row height in selection menu popover
20
+ static let popoverRowHeight: CGFloat = 44
21
+
22
+ /// Vertical padding in selection menu popover (top + bottom)
23
+ static let popoverVerticalPadding: CGFloat = 16
24
+
25
+ // MARK: - Fallback Dimensions
26
+
27
+ /// Fallback width when constraint width is unavailable
28
+ static let fallbackWidth: CGFloat = 320
29
+
30
+ // MARK: - Timing
31
+
32
+ /// Delay before presenting headless menu (allows layout to settle)
33
+ static let headlessPresentationDelay: TimeInterval = 0.1
34
+ }
@@ -1,5 +1,8 @@
1
+ import os.log
1
2
  import UIKit
2
3
 
4
+ private let logger = Logger(subsystem: "com.platformcomponents", category: "DatePicker")
5
+
3
6
  @objcMembers
4
7
  public final class PCDatePickerView: UIControl,
5
8
  UIPopoverPresentationControllerDelegate,
@@ -131,7 +134,7 @@ public final class PCDatePickerView: UIControl,
131
134
  picker.setNeedsLayout()
132
135
  picker.layoutIfNeeded()
133
136
  let fitted = picker.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
134
- return CGSize(width: UIView.noIntrinsicMetric, height: max(44, fitted.height))
137
+ return CGSize(width: UIView.noIntrinsicMetric, height: max(PCConstants.minTouchTargetHeight, fitted.height))
135
138
  }
136
139
 
137
140
  /// ✅ Called by your measuring pipeline.
@@ -144,13 +147,13 @@ public final class PCDatePickerView: UIControl,
144
147
 
145
148
  let width =
146
149
  (constrainedSize.width.isFinite && constrainedSize.width > 1)
147
- ? constrainedSize.width : 320
150
+ ? constrainedSize.width : PCConstants.fallbackWidth
148
151
  let fitted = picker.systemLayoutSizeFitting(
149
152
  CGSize(width: width, height: UIView.layoutFittingCompressedSize.height),
150
153
  withHorizontalFittingPriority: .required,
151
154
  verticalFittingPriority: .fittingSizeLevel
152
155
  )
153
- return CGSize(width: constrainedSize.width, height: max(44, fitted.height))
156
+ return CGSize(width: constrainedSize.width, height: max(PCConstants.minTouchTargetHeight, fitted.height))
154
157
  }
155
158
 
156
159
  /// Separate sizing for popover content.
@@ -204,7 +207,11 @@ public final class PCDatePickerView: UIControl,
204
207
 
205
208
  private func presentIfNeeded() {
206
209
  guard modalVC == nil else { return }
207
- guard let top = topViewController() else { return }
210
+ guard let top = topViewController() else {
211
+ logger.warning("presentIfNeeded: no view controller found")
212
+ return
213
+ }
214
+ logger.debug("presentIfNeeded: presenting modal picker")
208
215
 
209
216
  // Prevent “settle” events right as we present.
210
217
  suppressNextChangesBriefly()
@@ -239,6 +246,7 @@ public final class PCDatePickerView: UIControl,
239
246
 
240
247
  private func dismissIfNeeded(emitCancel: Bool) {
241
248
  guard let vc = modalVC else { return }
249
+ logger.debug("dismissIfNeeded: dismissing modal, emitCancel=\(emitCancel)")
242
250
  modalVC = nil
243
251
  vc.dismiss(animated: true) { [weak self] in
244
252
  guard let self else { return }
@@ -1,6 +1,9 @@
1
+ import os.log
1
2
  import SwiftUI
2
3
  import UIKit
3
4
 
5
+ private let logger = Logger(subsystem: "com.platformcomponents", category: "SelectionMenu")
6
+
4
7
  // MARK: - Option model (bridged from ObjC++ as dictionaries)
5
8
 
6
9
  struct PCSelectionMenuOption {
@@ -259,24 +262,31 @@ public final class PCSelectionMenuView: UIControl {
259
262
  let opts = parsedOptions
260
263
  guard !opts.isEmpty else { return }
261
264
 
262
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
265
+ logger.debug("presentHeadlessMenuIfNeeded: scheduling presentation with \(opts.count) options")
266
+ DispatchQueue.main.asyncAfter(deadline: .now() + PCConstants.headlessPresentationDelay) {
263
267
  let menuVC = PCMenuViewController(
264
268
  options: opts,
265
269
  onSelect: { [weak self] idx in
266
270
  guard let self else { return }
267
271
  let opt = opts[idx]
272
+ logger.debug("headless menu selected: index=\(idx), data=\(opt.data)")
268
273
  self.selectedData = opt.data
269
274
  self.onSelect?(idx, opt.label, opt.data)
270
275
  },
271
276
  onCancel: { [weak self] in
277
+ logger.debug("headless menu cancelled")
272
278
  self?.onRequestClose?()
273
279
  }
274
280
  )
275
281
 
276
282
  menuVC.modalPresentationStyle = .popover
283
+ let popoverHeight = min(
284
+ CGFloat(opts.count) * PCConstants.popoverRowHeight + PCConstants.popoverVerticalPadding,
285
+ PCConstants.popoverMaxHeight
286
+ )
277
287
  menuVC.preferredContentSize = CGSize(
278
- width: 250,
279
- height: min(CGFloat(opts.count) * 44 + 16, 400) // Account for top/bottom padding
288
+ width: PCConstants.popoverWidth,
289
+ height: popoverHeight
280
290
  )
281
291
 
282
292
  if let popover = menuVC.popoverPresentationController {
@@ -290,19 +300,18 @@ public final class PCSelectionMenuView: UIControl {
290
300
  }
291
301
  }
292
302
 
293
- // MARK: - sizing
303
+ // MARK: - Sizing
294
304
 
295
305
  public override func sizeThatFits(_ size: CGSize) -> CGSize {
296
306
  if anchorMode != "inline" { return CGSize(width: size.width, height: 1) }
297
307
 
298
- let minH: CGFloat = 44
299
308
  guard let host = hostingController else {
300
- return CGSize(width: size.width, height: minH)
309
+ return CGSize(width: size.width, height: PCConstants.minTouchTargetHeight)
301
310
  }
302
311
 
303
- let w = (size.width > 1) ? size.width : 320
312
+ let w = (size.width > 1) ? size.width : PCConstants.fallbackWidth
304
313
  let fitted = host.sizeThatFits(in: CGSize(width: w, height: .greatestFiniteMagnitude))
305
- return CGSize(width: size.width, height: max(minH, fitted.height))
314
+ return CGSize(width: size.width, height: max(PCConstants.minTouchTargetHeight, fitted.height))
306
315
  }
307
316
 
308
317
  public override var intrinsicContentSize: CGSize {
@@ -310,7 +319,9 @@ public final class PCSelectionMenuView: UIControl {
310
319
  return CGSize(width: UIView.noIntrinsicMetric, height: 1)
311
320
  }
312
321
  let h = max(
313
- 44, sizeThatFits(CGSize(width: bounds.width, height: .greatestFiniteMagnitude)).height)
322
+ PCConstants.minTouchTargetHeight,
323
+ sizeThatFits(CGSize(width: bounds.width, height: .greatestFiniteMagnitude)).height
324
+ )
314
325
  return CGSize(width: UIView.noIntrinsicMetric, height: h)
315
326
  }
316
327
  }
@@ -348,10 +359,11 @@ private class PCMenuViewController: UIViewController, UITableViewDelegate, UITab
348
359
  tableView.dataSource = self
349
360
  tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
350
361
  tableView.backgroundColor = .clear
351
- tableView.separatorStyle = .none // Remove dividers to match inline
362
+ tableView.separatorStyle = .none
352
363
  tableView.isScrollEnabled = true
353
- tableView.rowHeight = 44
354
- tableView.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0) // Add top/bottom padding
364
+ tableView.rowHeight = PCConstants.popoverRowHeight
365
+ let verticalPad = PCConstants.popoverVerticalPadding / 2
366
+ tableView.contentInset = UIEdgeInsets(top: verticalPad, left: 0, bottom: verticalPad, right: 0)
355
367
  tableView.translatesAutoresizingMaskIntoConstraints = false
356
368
 
357
369
  blurView.contentView.addSubview(tableView)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-platform-components",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "A cross-platform toolkit of native UI components for React Native.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -63,32 +63,32 @@
63
63
  "registry": "https://registry.npmjs.org/"
64
64
  },
65
65
  "devDependencies": {
66
- "@commitlint/config-conventional": "^19.8.1",
67
- "@eslint/compat": "^1.3.2",
68
- "@eslint/eslintrc": "^3.3.1",
69
- "@eslint/js": "^9.35.0",
70
- "@react-native-community/cli": "20.0.1",
71
- "@react-native/babel-preset": "0.81.1",
72
- "@react-native/eslint-config": "^0.81.1",
73
- "@release-it/conventional-changelog": "^10.0.1",
74
- "@types/jest": "^29.5.14",
75
- "@types/react": "^19.1.0",
66
+ "@commitlint/config-conventional": "^20.3.1",
67
+ "@eslint/compat": "^2.0.1",
68
+ "@eslint/eslintrc": "^3.3.3",
69
+ "@eslint/js": "^9.39.2",
70
+ "@react-native-community/cli": "20.1.0",
71
+ "@react-native/babel-preset": "0.83.1",
72
+ "@react-native/eslint-config": "^0.83.1",
73
+ "@release-it/conventional-changelog": "^10.0.4",
74
+ "@types/jest": "^30.0.0",
75
+ "@types/react": "^19.2.9",
76
76
  "@types/react-test-renderer": "^19.1.0",
77
- "commitlint": "^19.8.1",
78
- "del-cli": "^6.0.0",
79
- "eslint": "^9.35.0",
77
+ "commitlint": "^20.3.1",
78
+ "del-cli": "^7.0.0",
79
+ "eslint": "^9.39.2",
80
80
  "eslint-config-prettier": "^10.1.8",
81
- "eslint-plugin-prettier": "^5.5.4",
82
- "jest": "^29.7.0",
83
- "lefthook": "^2.0.3",
84
- "prettier": "^2.8.8",
85
- "react": "19.1.0",
86
- "react-native": "0.81.1",
87
- "react-native-builder-bob": "^0.40.16",
88
- "react-test-renderer": "19.1.0",
81
+ "eslint-plugin-prettier": "^5.5.5",
82
+ "jest": "^30.2.0",
83
+ "lefthook": "^2.0.15",
84
+ "prettier": "^3.8.1",
85
+ "react": "19.2.3",
86
+ "react-native": "0.83.1",
87
+ "react-native-builder-bob": "^0.40.17",
88
+ "react-test-renderer": "19.2.3",
89
89
  "release-it": "^19.2.4",
90
- "turbo": "^2.5.6",
91
- "typescript": "^5.9.2"
90
+ "turbo": "^2.7.5",
91
+ "typescript": "^5.9.3"
92
92
  },
93
93
  "peerDependencies": {
94
94
  "react": "*",
@@ -145,10 +145,16 @@
145
145
  "release-it": {
146
146
  "git": {
147
147
  "commitMessage": "chore: release ${version}",
148
- "tagName": "v${version}"
148
+ "tagName": "v${version}",
149
+ "requireCleanWorkingDir": false
149
150
  },
150
151
  "npm": {
151
- "publish": false
152
+ "publish": true,
153
+ "skipChecks": true,
154
+ "publishArgs": [
155
+ "--access",
156
+ "public"
157
+ ]
152
158
  },
153
159
  "github": {
154
160
  "release": true