react-native-platform-components 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +295 -129
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -7,6 +7,8 @@ High-quality **native UI components for React Native**, implemented with platfor
7
7
 
8
8
  This library focuses on **true native behavior**, not JavaScript re-implementations.
9
9
 
10
+ **Have a component request?** If there's a native UI component you'd like to see added, [open an issue](https://github.com/JarX-Concepts/react-native-platform-components/issues/new) describing the component and its native APIs on iOS and Android.
11
+
10
12
  <table>
11
13
  <tr>
12
14
  <td align="center"><strong>iOS DatePicker</strong></td>
@@ -89,7 +91,7 @@ pod install
89
91
 
90
92
  - Uses native Android Views with Material Design (including `PopupMenu` for context menus)
91
93
  - Supports **Material 3** styling
92
- - No additional setup required beyond autolinking
94
+ - **⚠️ Your app may crash if theme is not configured** — See [Android Theme Configuration](#android-theme-configuration) below
93
95
 
94
96
  ### Expo (Managed Workflow)
95
97
 
@@ -115,12 +117,11 @@ eas build --platform android
115
117
  **Config Plugin:**
116
118
 
117
119
  Add to your `app.json`:
120
+
118
121
  ```json
119
122
  {
120
123
  "expo": {
121
- "plugins": [
122
- ["react-native-platform-components/app.plugin", {}]
123
- ]
124
+ "plugins": [["react-native-platform-components/app.plugin", {}]]
124
125
  }
125
126
  }
126
127
  ```
@@ -133,18 +134,20 @@ For a complete working example, see the [`example-expo/`](./example-expo) direct
133
134
 
134
135
  This library is built for the **React Native New Architecture** (Fabric + TurboModules).
135
136
 
136
- | Feature | Status |
137
- |---------|--------|
138
- | Fabric (New Renderer) | Supported |
139
- | Codegen | Used for type-safe native bindings |
140
- | TurboModules | N/A (view components only) |
141
- | Old Architecture | Not supported |
137
+ | Feature | Status |
138
+ | --------------------- | ---------------------------------- |
139
+ | Fabric (New Renderer) | Supported |
140
+ | Codegen | Used for type-safe native bindings |
141
+ | TurboModules | N/A (view components only) |
142
+ | Old Architecture | Not supported |
142
143
 
143
144
  **Tested with:**
145
+
144
146
  - React Native 0.81+ (bare and Expo)
145
147
  - Expo SDK 54+
146
148
 
147
149
  **Requirements:**
150
+
148
151
  - New Architecture must be enabled in your app
149
152
  - For bare React Native: set `newArchEnabled=true` in `gradle.properties` (Android) and use the `RCT_NEW_ARCH_ENABLED` flag (iOS)
150
153
  - For Expo: set `"newArchEnabled": true` in `app.json`
@@ -176,8 +179,8 @@ export function Example() {
176
179
  setVisible(false);
177
180
  }}
178
181
  onClosed={() => setVisible(false)}
179
- ios={{preferredStyle: 'inline'}}
180
- android={{material: 'system'}}
182
+ ios={{ preferredStyle: 'inline' }}
183
+ android={{ material: 'system' }}
181
184
  />
182
185
  </>
183
186
  );
@@ -198,8 +201,8 @@ export function Example() {
198
201
  presentation="embedded"
199
202
  mode="date"
200
203
  onConfirm={(d) => setDate(d)}
201
- ios={{preferredStyle: 'inline'}}
202
- android={{material: 'system'}}
204
+ ios={{ preferredStyle: 'inline' }}
205
+ android={{ material: 'system' }}
203
206
  />
204
207
  );
205
208
  }
@@ -239,7 +242,9 @@ export function Example() {
239
242
  ]}
240
243
  onPressAction={(id, title) => setLastAction(title)}
241
244
  >
242
- <View style={{ padding: 20, backgroundColor: '#E8F4FD', borderRadius: 8 }}>
245
+ <View
246
+ style={{ padding: 20, backgroundColor: '#E8F4FD', borderRadius: 8 }}
247
+ >
243
248
  <Text>Long-press me</Text>
244
249
  </View>
245
250
  </ContextMenu>
@@ -400,18 +405,30 @@ export function Example() {
400
405
  ### LiquidGlass
401
406
 
402
407
  ```tsx
403
- import { LiquidGlass, isLiquidGlassSupported } from 'react-native-platform-components';
408
+ import {
409
+ LiquidGlass,
410
+ isLiquidGlassSupported,
411
+ } from 'react-native-platform-components';
404
412
  import { View, Text, Image } from 'react-native';
405
413
 
406
414
  export function Example() {
407
415
  return (
408
416
  <View style={{ flex: 1 }}>
409
417
  {/* Background content */}
410
- <Image source={{ uri: 'https://example.com/photo.jpg' }} style={{ flex: 1 }} />
418
+ <Image
419
+ source={{ uri: 'https://example.com/photo.jpg' }}
420
+ style={{ flex: 1 }}
421
+ />
411
422
 
412
423
  {/* Glass effect overlay */}
413
424
  <LiquidGlass
414
- style={{ position: 'absolute', top: 50, left: 20, right: 20, padding: 20 }}
425
+ style={{
426
+ position: 'absolute',
427
+ top: 50,
428
+ left: 20,
429
+ right: 20,
430
+ padding: 20,
431
+ }}
415
432
  cornerRadius={20}
416
433
  ios={{
417
434
  effect: 'regular',
@@ -441,37 +458,37 @@ Native date & time picker using **platform system pickers**.
441
458
 
442
459
  ### Props
443
460
 
444
- | Prop | Type | Description |
445
- |------|------|-------------|
446
- | `date` | `Date \| null` | Controlled date value |
447
- | `minDate` | `Date \| null` | Minimum selectable date |
448
- | `maxDate` | `Date \| null` | Maximum selectable date |
449
- | `locale` | `string` | Locale identifier (e.g., `'en-US'`) |
450
- | `timeZoneName` | `string` | Time zone identifier |
451
- | `mode` | `'date' \| 'time' \| 'dateAndTime' \| 'countDownTimer'` | Picker mode |
452
- | `presentation` | `'modal' \| 'embedded'` | Presentation style |
453
- | `visible` | `boolean` | Controls modal visibility (modal mode only) |
454
- | `onConfirm` | `(date: Date) => void` | Called when user confirms selection |
455
- | `onClosed` | `() => void` | Called when modal is dismissed |
461
+ | Prop | Type | Description |
462
+ | -------------- | ------------------------------------------------------- | ------------------------------------------- |
463
+ | `date` | `Date \| null` | Controlled date value |
464
+ | `minDate` | `Date \| null` | Minimum selectable date |
465
+ | `maxDate` | `Date \| null` | Maximum selectable date |
466
+ | `locale` | `string` | Locale identifier (e.g., `'en-US'`) |
467
+ | `timeZoneName` | `string` | Time zone identifier |
468
+ | `mode` | `'date' \| 'time' \| 'dateAndTime' \| 'countDownTimer'` | Picker mode |
469
+ | `presentation` | `'modal' \| 'embedded'` | Presentation style |
470
+ | `visible` | `boolean` | Controls modal visibility (modal mode only) |
471
+ | `onConfirm` | `(date: Date) => void` | Called when user confirms selection |
472
+ | `onClosed` | `() => void` | Called when modal is dismissed |
456
473
 
457
474
  ### iOS Props (`ios`)
458
475
 
459
- | Prop | Type | Description |
460
- |------|------|-------------|
461
- | `preferredStyle` | `'automatic' \| 'compact' \| 'inline' \| 'wheels'` | iOS date picker style |
462
- | `countDownDurationSeconds` | `number` | Duration for countdown timer mode |
463
- | `minuteInterval` | `number` | Minute interval (1-30) |
464
- | `roundsToMinuteInterval` | `'inherit' \| 'round' \| 'noRound'` | Rounding behavior |
476
+ | Prop | Type | Description |
477
+ | -------------------------- | -------------------------------------------------- | --------------------------------- |
478
+ | `preferredStyle` | `'automatic' \| 'compact' \| 'inline' \| 'wheels'` | iOS date picker style |
479
+ | `countDownDurationSeconds` | `number` | Duration for countdown timer mode |
480
+ | `minuteInterval` | `number` | Minute interval (1-30) |
481
+ | `roundsToMinuteInterval` | `'inherit' \| 'round' \| 'noRound'` | Rounding behavior |
465
482
 
466
483
  ### Android Props (`android`)
467
484
 
468
- | Prop | Type | Description |
469
- |------|------|-------------|
470
- | `firstDayOfWeek` | `number` | First day of week (1-7, Sunday=1) |
471
- | `material` | `'system' \| 'm3'` | Material Design style (modal only; embedded always uses system picker) |
472
- | `dialogTitle` | `string` | Custom dialog title |
473
- | `positiveButtonTitle` | `string` | Custom confirm button text |
474
- | `negativeButtonTitle` | `string` | Custom cancel button text |
485
+ | Prop | Type | Description |
486
+ | --------------------- | ------------------ | ---------------------------------------------------------------------- |
487
+ | `firstDayOfWeek` | `number` | First day of week (1-7, Sunday=1) |
488
+ | `material` | `'system' \| 'm3'` | Material Design style (modal only; embedded always uses system picker) |
489
+ | `dialogTitle` | `string` | Custom dialog title |
490
+ | `positiveButtonTitle` | `string` | Custom confirm button text |
491
+ | `negativeButtonTitle` | `string` | Custom cancel button text |
475
492
 
476
493
  ---
477
494
 
@@ -481,42 +498,42 @@ Native context menu that wraps content and responds to **long-press** or **tap**
481
498
 
482
499
  ### Props
483
500
 
484
- | Prop | Type | Description |
485
- |------|------|-------------|
486
- | `title` | `string` | Menu title (shown as header on iOS) |
487
- | `actions` | `ContextMenuAction[]` | Array of menu actions |
488
- | `disabled` | `boolean` | Disables the menu |
489
- | `trigger` | `'longPress' \| 'tap'` | How the menu opens (default: `'longPress'`) |
490
- | `onPressAction` | `(actionId, actionTitle) => void` | Called when user selects an action |
491
- | `onMenuOpen` | `() => void` | Called when menu opens |
492
- | `onMenuClose` | `() => void` | Called when menu closes |
493
- | `children` | `ReactNode` | Content to wrap (required) |
501
+ | Prop | Type | Description |
502
+ | --------------- | --------------------------------- | ------------------------------------------- |
503
+ | `title` | `string` | Menu title (shown as header on iOS) |
504
+ | `actions` | `ContextMenuAction[]` | Array of menu actions |
505
+ | `disabled` | `boolean` | Disables the menu |
506
+ | `trigger` | `'longPress' \| 'tap'` | How the menu opens (default: `'longPress'`) |
507
+ | `onPressAction` | `(actionId, actionTitle) => void` | Called when user selects an action |
508
+ | `onMenuOpen` | `() => void` | Called when menu opens |
509
+ | `onMenuClose` | `() => void` | Called when menu closes |
510
+ | `children` | `ReactNode` | Content to wrap (required) |
494
511
 
495
512
  ### ContextMenuAction
496
513
 
497
- | Property | Type | Description |
498
- |----------|------|-------------|
499
- | `id` | `string` | Unique identifier returned in callbacks |
500
- | `title` | `string` | Display text |
501
- | `subtitle` | `string` | Secondary text (iOS only) |
502
- | `image` | `string` | Icon name (SF Symbol on iOS, drawable on Android) |
503
- | `imageColor` | `string` | Tint color for the icon (hex string) |
504
- | `attributes` | `{ destructive?, disabled?, hidden? }` | Action attributes |
505
- | `state` | `'off' \| 'on' \| 'mixed'` | Checkmark state |
506
- | `subactions` | `ContextMenuAction[]` | Nested actions for submenu |
514
+ | Property | Type | Description |
515
+ | ------------ | -------------------------------------- | ------------------------------------------------- |
516
+ | `id` | `string` | Unique identifier returned in callbacks |
517
+ | `title` | `string` | Display text |
518
+ | `subtitle` | `string` | Secondary text (iOS only) |
519
+ | `image` | `string` | Icon name (SF Symbol on iOS, drawable on Android) |
520
+ | `imageColor` | `string` | Tint color for the icon (hex string) |
521
+ | `attributes` | `{ destructive?, disabled?, hidden? }` | Action attributes |
522
+ | `state` | `'off' \| 'on' \| 'mixed'` | Checkmark state |
523
+ | `subactions` | `ContextMenuAction[]` | Nested actions for submenu |
507
524
 
508
525
  ### iOS Props (`ios`)
509
526
 
510
- | Prop | Type | Description |
511
- |------|------|-------------|
527
+ | Prop | Type | Description |
528
+ | --------------- | --------- | --------------------------------- |
512
529
  | `enablePreview` | `boolean` | Enable preview when long-pressing |
513
530
 
514
531
  ### Android Props (`android`)
515
532
 
516
- | Prop | Type | Description |
517
- |------|------|-------------|
518
- | `anchorPosition` | `'left' \| 'right'` | Anchor position for the popup menu |
519
- | `visible` | `boolean` | Programmatic visibility control (Android only) |
533
+ | Prop | Type | Description |
534
+ | ---------------- | ------------------- | ---------------------------------------------- |
535
+ | `anchorPosition` | `'left' \| 'right'` | Anchor position for the popup menu |
536
+ | `visible` | `boolean` | Programmatic visibility control (Android only) |
520
537
 
521
538
  ### Trigger Modes
522
539
 
@@ -537,17 +554,17 @@ Native selection menu with **modal** and **embedded** modes.
537
554
 
538
555
  ### Props
539
556
 
540
- | Prop | Type | Description |
541
- |------|------|-------------|
542
- | `options` | `{ label: string; data: string }[]` | Array of options to display |
543
- | `selected` | `string \| null` | Currently selected option's `data` value |
544
- | `disabled` | `boolean` | Disables the menu |
545
- | `placeholder` | `string` | Placeholder text when no selection |
546
- | `presentation` | `'modal' \| 'embedded'` | Presentation mode (default: `'modal'`) |
547
- | `visible` | `boolean` | Controls modal mode menu visibility |
548
- | `onSelect` | `(data, label, index) => void` | Called when user selects an option |
549
- | `onRequestClose` | `() => void` | Called when menu is dismissed without selection |
550
- | `android.material` | `'system' \| 'm3'` | Material Design style preference |
557
+ | Prop | Type | Description |
558
+ | ------------------ | ----------------------------------- | ----------------------------------------------- |
559
+ | `options` | `{ label: string; data: string }[]` | Array of options to display |
560
+ | `selected` | `string \| null` | Currently selected option's `data` value |
561
+ | `disabled` | `boolean` | Disables the menu |
562
+ | `placeholder` | `string` | Placeholder text when no selection |
563
+ | `presentation` | `'modal' \| 'embedded'` | Presentation mode (default: `'modal'`) |
564
+ | `visible` | `boolean` | Controls modal mode menu visibility |
565
+ | `onSelect` | `(data, label, index) => void` | Called when user selects an option |
566
+ | `onRequestClose` | `() => void` | Called when menu is dismissed without selection |
567
+ | `android.material` | `'system' \| 'm3'` | Material Design style preference |
551
568
 
552
569
  ### Modes
553
570
 
@@ -564,39 +581,40 @@ Native segmented control using **UISegmentedControl** on iOS and **MaterialButto
564
581
 
565
582
  ### Props
566
583
 
567
- | Prop | Type | Description |
568
- |------|------|-------------|
569
- | `segments` | `SegmentedControlSegment[]` | Array of segments to display |
570
- | `selectedValue` | `string \| null` | Currently selected segment's `value` |
571
- | `disabled` | `boolean` | Disables the entire control |
572
- | `onSelect` | `(value: string, index: number) => void` | Called when user selects a segment |
584
+ | Prop | Type | Description |
585
+ | --------------- | ---------------------------------------- | ------------------------------------ |
586
+ | `segments` | `SegmentedControlSegment[]` | Array of segments to display |
587
+ | `selectedValue` | `string \| null` | Currently selected segment's `value` |
588
+ | `disabled` | `boolean` | Disables the entire control |
589
+ | `onSelect` | `(value: string, index: number) => void` | Called when user selects a segment |
573
590
 
574
591
  ### SegmentedControlSegment
575
592
 
576
- | Property | Type | Description |
577
- |----------|------|-------------|
578
- | `label` | `string` | Display text for the segment |
579
- | `value` | `string` | Unique value returned in callbacks |
580
- | `disabled` | `boolean` | Disables this specific segment |
581
- | `icon` | `string` | Icon name (SF Symbol on iOS, drawable on Android) |
593
+ | Property | Type | Description |
594
+ | ---------- | --------- | ------------------------------------------------- |
595
+ | `label` | `string` | Display text for the segment |
596
+ | `value` | `string` | Unique value returned in callbacks |
597
+ | `disabled` | `boolean` | Disables this specific segment |
598
+ | `icon` | `string` | Icon name (SF Symbol on iOS, drawable on Android) |
582
599
 
583
600
  ### iOS Props (`ios`)
584
601
 
585
- | Prop | Type | Description |
586
- |------|------|-------------|
587
- | `momentary` | `boolean` | If true, segments don't show selected state |
602
+ | Prop | Type | Description |
603
+ | ---------------------------------- | --------- | --------------------------------------------------- |
604
+ | `momentary` | `boolean` | If true, segments don't show selected state |
588
605
  | `apportionsSegmentWidthsByContent` | `boolean` | If true, segment widths are proportional to content |
589
- | `selectedSegmentTintColor` | `string` | Tint color for selected segment (hex string) |
606
+ | `selectedSegmentTintColor` | `string` | Tint color for selected segment (hex string) |
590
607
 
591
608
  ### Android Props (`android`)
592
609
 
593
- | Prop | Type | Description |
594
- |------|------|-------------|
610
+ | Prop | Type | Description |
611
+ | ------------------- | --------- | -------------------------------------------- |
595
612
  | `selectionRequired` | `boolean` | If true, one segment must always be selected |
596
613
 
597
614
  ### Icon Support
598
615
 
599
616
  Icons work the same as ContextMenu:
617
+
600
618
  - **iOS**: Use SF Symbol names (e.g., `'list.bullet'`, `'square.grid.2x2'`)
601
619
  - **Android**: Use drawable resource names (e.g., `'list_bullet'`, `'grid_view'`)
602
620
 
@@ -610,32 +628,32 @@ Native glass morphism effect using **UIGlassEffect** on iOS 26+. On Android and
610
628
 
611
629
  ### Props
612
630
 
613
- | Prop | Type | Description |
614
- |------|------|-------------|
615
- | `cornerRadius` | `number` | Corner radius for the glass effect (default: `0`) |
616
- | `children` | `ReactNode` | Content to render inside the glass container |
631
+ | Prop | Type | Description |
632
+ | -------------- | ----------- | ------------------------------------------------- |
633
+ | `cornerRadius` | `number` | Corner radius for the glass effect (default: `0`) |
634
+ | `children` | `ReactNode` | Content to render inside the glass container |
617
635
 
618
636
  ### iOS Props (`ios`)
619
637
 
620
- | Prop | Type | Description |
621
- |------|------|-------------|
622
- | `effect` | `'clear' \| 'regular' \| 'none'` | Glass effect intensity (default: `'regular'`) |
623
- | `interactive` | `boolean` | Enable touch interaction feedback (default: `false`) |
624
- | `tintColor` | `string` | Overlay tint color (hex string) |
625
- | `colorScheme` | `'light' \| 'dark' \| 'system'` | Appearance mode (default: `'system'`) |
626
- | `shadowRadius` | `number` | Shadow/glow radius (default: `20`) |
627
- | `isHighlighted` | `boolean` | Manual highlight state control |
638
+ | Prop | Type | Description |
639
+ | --------------- | -------------------------------- | ---------------------------------------------------- |
640
+ | `effect` | `'clear' \| 'regular' \| 'none'` | Glass effect intensity (default: `'regular'`) |
641
+ | `interactive` | `boolean` | Enable touch interaction feedback (default: `false`) |
642
+ | `tintColor` | `string` | Overlay tint color (hex string) |
643
+ | `colorScheme` | `'light' \| 'dark' \| 'system'` | Appearance mode (default: `'system'`) |
644
+ | `shadowRadius` | `number` | Shadow/glow radius (default: `20`) |
645
+ | `isHighlighted` | `boolean` | Manual highlight state control |
628
646
 
629
647
  ### Android Props (`android`)
630
648
 
631
- | Prop | Type | Description |
632
- |------|------|-------------|
649
+ | Prop | Type | Description |
650
+ | ------------------------- | -------- | ---------------------------------------------- |
633
651
  | `fallbackBackgroundColor` | `string` | Background color when glass effect unavailable |
634
652
 
635
653
  ### Constants
636
654
 
637
- | Export | Type | Description |
638
- |--------|------|-------------|
655
+ | Export | Type | Description |
656
+ | ------------------------ | --------- | ------------------------------------ |
639
657
  | `isLiquidGlassSupported` | `boolean` | `true` on iOS 26+, `false` otherwise |
640
658
 
641
659
  ### Effect Modes
@@ -646,13 +664,13 @@ Native glass morphism effect using **UIGlassEffect** on iOS 26+. On Android and
646
664
 
647
665
  ### Platform Behavior
648
666
 
649
- | Platform | iOS 26+ | iOS < 26 | Android |
650
- |----------|---------|----------|---------|
651
- | Glass Effect | Full glass morphism | No effect | No effect |
652
- | Corner Radius | Applied | Applied | Applied |
653
- | Tint Color | Supported | Ignored | Ignored |
654
- | Interactive | Supported | Ignored | Ignored |
655
- | Fallback BG | N/A | Transparent | Configurable |
667
+ | Platform | iOS 26+ | iOS < 26 | Android |
668
+ | ------------- | ------------------- | ----------- | ------------ |
669
+ | Glass Effect | Full glass morphism | No effect | No effect |
670
+ | Corner Radius | Applied | Applied | Applied |
671
+ | Tint Color | Supported | Ignored | Ignored |
672
+ | Interactive | Supported | Ignored | Ignored |
673
+ | Fallback BG | N/A | Transparent | Configurable |
656
674
 
657
675
  ### Usage Tips
658
676
 
@@ -684,6 +702,142 @@ This is intentional. The goal is native fidelity, not pixel-level customization.
684
702
 
685
703
  ---
686
704
 
705
+ ## Android Theme Configuration
706
+
707
+ > **⚠️ Your app may hard crash if you skip this section.** Android components require specific theme configuration. Components can crash immediately on mount if the required theme attributes are missing.
708
+
709
+ ### Theme Requirements by Component
710
+
711
+ | Component | Mode | Required Theme | Crash if Missing |
712
+ | -------------------- | ---------------------------- | ------------------- | ---------------- |
713
+ | **SegmentedControl** | (always M3) | `Theme.Material3.*` | ✅ Yes |
714
+ | **DatePicker** | `android.material: 'm3'` | `Theme.Material3.*` | ✅ Yes |
715
+ | **DatePicker** | `android.material: 'system'` | `Theme.AppCompat.*` | ✅ Yes |
716
+ | **SelectionMenu** | `android.material: 'm3'` | `Theme.Material3.*` | ✅ Yes |
717
+ | **SelectionMenu** | `android.material: 'system'` | `Theme.AppCompat.*` | ✅ Yes |
718
+ | **ContextMenu** | — | Any | ❌ No |
719
+ | **LiquidGlass** | — | Any | ❌ No |
720
+
721
+ ### Material 3 Theme Setup (Required for SegmentedControl)
722
+
723
+ `SegmentedControl` always uses Material 3 widgets (`MaterialButtonToggleGroup`). Your app **must** use a Material 3 theme or the app will crash on component mount.
724
+
725
+ **1. Update your app theme in `android/app/src/main/res/values/styles.xml`:**
726
+
727
+ ```xml
728
+ <resources>
729
+ <!-- Base application theme - MUST inherit from Material3 -->
730
+ <style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
731
+ <!-- Material 3 requires these color attributes -->
732
+ <item name="colorPrimary">@color/md_theme_primary</item>
733
+ <item name="colorOnPrimary">@color/md_theme_onPrimary</item>
734
+ <item name="colorPrimaryContainer">@color/md_theme_primaryContainer</item>
735
+ <item name="colorOnPrimaryContainer">@color/md_theme_onPrimaryContainer</item>
736
+ <item name="colorSecondary">@color/md_theme_secondary</item>
737
+ <item name="colorOnSecondary">@color/md_theme_onSecondary</item>
738
+ <item name="colorSecondaryContainer">@color/md_theme_secondaryContainer</item>
739
+ <item name="colorOnSecondaryContainer">@color/md_theme_onSecondaryContainer</item>
740
+ <item name="colorTertiary">@color/md_theme_tertiary</item>
741
+ <item name="colorOnTertiary">@color/md_theme_onTertiary</item>
742
+ <item name="colorBackground">@color/md_theme_background</item>
743
+ <item name="colorOnBackground">@color/md_theme_onBackground</item>
744
+ <item name="colorSurface">@color/md_theme_surface</item>
745
+ <item name="colorOnSurface">@color/md_theme_onSurface</item>
746
+ <item name="colorError">@color/md_theme_error</item>
747
+ <item name="colorOnError">@color/md_theme_onError</item>
748
+ </style>
749
+ </resources>
750
+ ```
751
+
752
+ **2. Define your Material 3 colors in `android/app/src/main/res/values/colors.xml`:**
753
+
754
+ ```xml
755
+ <resources>
756
+ <!-- Generate these using Material Theme Builder: https://m3.material.io/theme-builder -->
757
+ <color name="md_theme_primary">#6750A4</color>
758
+ <color name="md_theme_onPrimary">#FFFFFF</color>
759
+ <color name="md_theme_primaryContainer">#EADDFF</color>
760
+ <color name="md_theme_onPrimaryContainer">#21005D</color>
761
+ <color name="md_theme_secondary">#625B71</color>
762
+ <color name="md_theme_onSecondary">#FFFFFF</color>
763
+ <color name="md_theme_secondaryContainer">#E8DEF8</color>
764
+ <color name="md_theme_onSecondaryContainer">#1D192B</color>
765
+ <color name="md_theme_tertiary">#7D5260</color>
766
+ <color name="md_theme_onTertiary">#FFFFFF</color>
767
+ <color name="md_theme_background">#FFFBFE</color>
768
+ <color name="md_theme_onBackground">#1C1B1F</color>
769
+ <color name="md_theme_surface">#FFFBFE</color>
770
+ <color name="md_theme_onSurface">#1C1B1F</color>
771
+ <color name="md_theme_error">#B3261E</color>
772
+ <color name="md_theme_onError">#FFFFFF</color>
773
+ </resources>
774
+ ```
775
+
776
+ > **Tip:** Use Google's [Material Theme Builder](https://m3.material.io/theme-builder) to generate a complete color scheme.
777
+
778
+ ### Common Crash Scenarios
779
+
780
+ #### Crash: `Cannot find theme attribute materialButtonOutlinedStyle`
781
+
782
+ **Cause:** Using `SegmentedControl` without a Material 3 theme.
783
+
784
+ **Fix:** Update your theme to inherit from `Theme.Material3.*`:
785
+
786
+ ```xml
787
+ <!-- Change this -->
788
+ <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
789
+
790
+ <!-- To this -->
791
+ <style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
792
+ ```
793
+
794
+ #### Crash: `You need to use a Theme.AppCompat theme`
795
+
796
+ **Cause:** Using `DatePicker` or `SelectionMenu` with `android.material: 'system'` while not extending AppCompat.
797
+
798
+ **Fix:** Ensure your theme inherits from `Theme.AppCompat.*` or `Theme.Material3.*` (which extends AppCompat), and your `MainActivity` extends `AppCompatActivity`.
799
+
800
+ ### Mode Selection Guide
801
+
802
+ Choose the appropriate mode based on your app's theme:
803
+
804
+ ```tsx
805
+ // If your app uses Theme.Material3.* (recommended)
806
+ <DatePicker android={{ material: 'm3' }} />
807
+ <SelectionMenu android={{ material: 'm3' }} />
808
+ <SegmentedControl /> // Always M3
809
+
810
+ // If your app uses Theme.AppCompat.*
811
+ <DatePicker android={{ material: 'system' }} />
812
+ <SelectionMenu android={{ material: 'system' }} />
813
+ // ⚠️ SegmentedControl will crash - upgrade to Material 3
814
+ ```
815
+
816
+ ### Expo Configuration
817
+
818
+ For Expo projects, the config plugin can configure your theme automatically. Add to `app.json`:
819
+
820
+ ```json
821
+ {
822
+ "expo": {
823
+ "plugins": [
824
+ [
825
+ "react-native-platform-components/app.plugin",
826
+ {
827
+ "android": {
828
+ "theme": "material3"
829
+ }
830
+ }
831
+ ]
832
+ ]
833
+ }
834
+ }
835
+ ```
836
+
837
+ Then run `npx expo prebuild` to apply the configuration.
838
+
839
+ ---
840
+
687
841
  ## Icons
688
842
 
689
843
  ContextMenu supports icons on menu items. Icons are specified by name and resolved differently on each platform.
@@ -694,11 +848,11 @@ Use [SF Symbols](https://developer.apple.com/sf-symbols/) names. These are built
694
848
 
695
849
  ```tsx
696
850
  // Common SF Symbols
697
- image: 'doc.on.doc' // Copy
698
- image: 'square.and.arrow.up' // Share
699
- image: 'trash' // Delete
700
- image: 'pencil' // Edit
701
- image: 'checkmark.circle' // Checkmark
851
+ image: 'doc.on.doc'; // Copy
852
+ image: 'square.and.arrow.up'; // Share
853
+ image: 'trash'; // Delete
854
+ image: 'pencil'; // Edit
855
+ image: 'checkmark.circle'; // Checkmark
702
856
  ```
703
857
 
704
858
  Browse available symbols using Apple's SF Symbols app or [sfsymbols.com](https://sfsymbols.com).
@@ -709,9 +863,9 @@ Use drawable resource names from your app's `res/drawable` directory. You must a
709
863
 
710
864
  ```tsx
711
865
  // Reference drawable by name (without extension)
712
- image: 'content_copy' // res/drawable/content_copy.xml
713
- image: 'share' // res/drawable/share.xml
714
- image: 'delete' // res/drawable/delete.xml
866
+ image: 'content_copy'; // res/drawable/content_copy.xml
867
+ image: 'share'; // res/drawable/share.xml
868
+ image: 'delete'; // res/drawable/delete.xml
715
869
  ```
716
870
 
717
871
  **Adding drawable resources:**
@@ -772,3 +926,15 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
772
926
  ## License
773
927
 
774
928
  MIT
929
+
930
+ ---
931
+
932
+ ## Author
933
+
934
+ **Andrew Tosh** — Santa Barbara, California
935
+
936
+ Full-stack developer with deep experience across entertainment and defense industries, specializing in simulation, visualization, and cross-platform mobile development. Technical focus areas include React Native, Rust, C++, real-time 3D visualization, and game engine technologies.
937
+
938
+ **Available for contract work** — Always interested in connecting with new clients for mobile development, visualization systems, and related projects. Hit me up at [andrew.tosh@jarxconcepts.com](mailto:andrew.tosh@jarxconcepts.com).
939
+
940
+ [LinkedIn](https://www.linkedin.com/in/atosh/) · [JarX Concepts](https://github.com/JarX-Concepts)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-platform-components",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Native UI components for React Native: DatePicker, ContextMenu, SelectionMenu, SegmentedControl, LiquidGlass.",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",