react-native-platform-components 0.9.0 → 1.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.
- package/README.md +73 -1011
- package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +17 -3
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +5 -3
- package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +2 -1
- package/android/src/main/java/com/platformcomponents/PCThemeSupport.kt +94 -0
- package/android/src/main/res/values/styles.xml +40 -0
- package/lib/typescript/commonjs/docs/docusaurus.config.d.ts +4 -0
- package/lib/typescript/commonjs/docs/docusaurus.config.d.ts.map +1 -0
- package/lib/typescript/commonjs/docs/sidebars.d.ts +4 -0
- package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -0
- package/lib/typescript/module/docs/docusaurus.config.d.ts +4 -0
- package/lib/typescript/module/docs/docusaurus.config.d.ts.map +1 -0
- package/lib/typescript/module/docs/sidebars.d.ts +4 -0
- package/lib/typescript/module/docs/sidebars.d.ts.map +1 -0
- package/package.json +34 -13
- package/plugin/build/index.cjs +58 -17
- package/plugin/build/index.d.ts +32 -15
- package/plugin/build/index.d.ts.map +1 -1
- package/plugin/tsconfig.json +7 -2
|
@@ -465,7 +465,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
465
465
|
addView(picker)
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
val dlg = AlertDialog.Builder(act)
|
|
468
|
+
val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
|
|
469
469
|
.setTitle(androidDialogTitle ?: "")
|
|
470
470
|
.setView(container)
|
|
471
471
|
.setPositiveButton(androidPositiveTitle ?: "OK") { _, _ ->
|
|
@@ -513,7 +513,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
|
|
516
|
-
val dlg = AlertDialog.Builder(act)
|
|
516
|
+
val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
|
|
517
517
|
.setTitle(androidDialogTitle ?: "")
|
|
518
518
|
.setView(picker)
|
|
519
519
|
.setPositiveButton(androidPositiveTitle ?: "OK") { _, _ ->
|
|
@@ -580,7 +580,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
580
580
|
addView(picker)
|
|
581
581
|
}
|
|
582
582
|
|
|
583
|
-
val dlg = AlertDialog.Builder(act)
|
|
583
|
+
val dlg = AlertDialog.Builder(PCThemeSupport.appCompatDialogContext(act, "DatePicker"))
|
|
584
584
|
.setTitle(androidDialogTitle ?: "")
|
|
585
585
|
.setView(container)
|
|
586
586
|
.setPositiveButton(androidPositiveTitle ?: "Next") { _, _ ->
|
|
@@ -617,6 +617,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
617
617
|
|
|
618
618
|
val builder = MaterialDatePicker.Builder.datePicker()
|
|
619
619
|
.setSelection(ts)
|
|
620
|
+
.setTheme(m3CalendarTheme(act))
|
|
620
621
|
|
|
621
622
|
androidDialogTitle?.let { builder.setTitleText(it) }
|
|
622
623
|
androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
|
|
@@ -660,6 +661,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
660
661
|
|
|
661
662
|
val is24 = android.text.format.DateFormat.is24HourFormat(act)
|
|
662
663
|
val builder = MaterialTimePicker.Builder()
|
|
664
|
+
.setTheme(m3TimePickerTheme(act))
|
|
663
665
|
.setTimeFormat(if (is24) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H)
|
|
664
666
|
.setHour(cal.get(Calendar.HOUR_OF_DAY))
|
|
665
667
|
.setMinute(cal.get(Calendar.MINUTE))
|
|
@@ -698,6 +700,7 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
698
700
|
|
|
699
701
|
val builder = MaterialDatePicker.Builder.datePicker()
|
|
700
702
|
.setSelection(ts)
|
|
703
|
+
.setTheme(m3CalendarTheme(act))
|
|
701
704
|
|
|
702
705
|
androidDialogTitle?.let { builder.setTitleText(it) }
|
|
703
706
|
androidPositiveTitle?.let { builder.setPositiveButtonText(it) }
|
|
@@ -733,6 +736,17 @@ class PCDatePickerView(context: Context) : FrameLayout(context), ReactScrollView
|
|
|
733
736
|
picker.show(act.supportFragmentManager, "PCDatePicker_M3_DATE_THEN_TIME")
|
|
734
737
|
}
|
|
735
738
|
|
|
739
|
+
/**
|
|
740
|
+
* Material pickers resolve their theme from the activity. When the app theme is
|
|
741
|
+
* not a Material theme they would throw, so hand them a full Material 3 dialog
|
|
742
|
+
* theme instead (0 = use the activity theme).
|
|
743
|
+
*/
|
|
744
|
+
private fun m3CalendarTheme(act: FragmentActivity): Int =
|
|
745
|
+
PCThemeSupport.materialDialogThemeOverride(act, "DatePicker", R.style.PCMaterial3CalendarDialogTheme)
|
|
746
|
+
|
|
747
|
+
private fun m3TimePickerTheme(act: FragmentActivity): Int =
|
|
748
|
+
PCThemeSupport.materialDialogThemeOverride(act, "DatePicker", R.style.PCMaterial3TimePickerDialogTheme)
|
|
749
|
+
|
|
736
750
|
private fun buildM3CalendarConstraints(): CalendarConstraints? {
|
|
737
751
|
val min = minDateMs
|
|
738
752
|
val max = maxDateMs
|
|
@@ -190,7 +190,9 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
190
190
|
rebuildGeneration += 1
|
|
191
191
|
val generation = rebuildGeneration
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
// Material widgets need a Material theme; fall back to Material 3 defaults instead of crashing.
|
|
194
|
+
val themedContext = PCThemeSupport.materialContext(context, "SegmentedControl")
|
|
195
|
+
val group = MaterialButtonToggleGroup(themedContext).apply {
|
|
194
196
|
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
|
195
197
|
isSingleSelection = true
|
|
196
198
|
isSelectionRequired = selectionRequired
|
|
@@ -207,7 +209,7 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
207
209
|
// without one keep their label. "auto" and "labeled" show icon + label.
|
|
208
210
|
val iconOnly = labelVisibility == "unlabeled" && segment.hasIcon
|
|
209
211
|
|
|
210
|
-
val button = MaterialButton(
|
|
212
|
+
val button = MaterialButton(themedContext, null, com.google.android.material.R.attr.materialButtonOutlinedStyle).apply {
|
|
211
213
|
id = View.generateViewId()
|
|
212
214
|
text = if (iconOnly) "" else segment.label
|
|
213
215
|
isAllCaps = false // Preserve original text casing
|
|
@@ -311,7 +313,7 @@ class PCSegmentedControlView(context: Context) : FrameLayout(context), ReactScro
|
|
|
311
313
|
if (segment.badge.isEmpty()) return
|
|
312
314
|
|
|
313
315
|
val inset = (2 * resources.displayMetrics.density).toInt()
|
|
314
|
-
val badge = BadgeDrawable.create(context).apply {
|
|
316
|
+
val badge = BadgeDrawable.create(button.context).apply {
|
|
315
317
|
text = segment.badge
|
|
316
318
|
badgeGravity = BadgeDrawable.TOP_END
|
|
317
319
|
badgeBackgroundColor?.let { backgroundColor = it }
|
|
@@ -356,7 +356,8 @@ class PCSelectionMenuView(context: Context) : FrameLayout(context), ReactScrollV
|
|
|
356
356
|
if (mode == MaterialMode.M3) {
|
|
357
357
|
// M3 exposed dropdown menu - the standard Material 3 way
|
|
358
358
|
// Must set box background mode BEFORE setting endIconMode to avoid IllegalStateException
|
|
359
|
-
|
|
359
|
+
// Material widgets need a Material theme; fall back to Material 3 defaults instead of crashing.
|
|
360
|
+
val til = TextInputLayout(PCThemeSupport.materialContext(context, "SelectionMenu")).apply {
|
|
360
361
|
layoutParams = FrameLayout.LayoutParams(
|
|
361
362
|
FrameLayout.LayoutParams.WRAP_CONTENT,
|
|
362
363
|
FrameLayout.LayoutParams.WRAP_CONTENT
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
package com.platformcomponents
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
5
|
+
import android.util.TypedValue
|
|
6
|
+
import android.view.ContextThemeWrapper
|
|
7
|
+
import androidx.annotation.AttrRes
|
|
8
|
+
import androidx.appcompat.R as AppCompatR
|
|
9
|
+
import com.google.android.material.R as MaterialR
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Theme guards for the Material and AppCompat widgets this library creates.
|
|
13
|
+
*
|
|
14
|
+
* React Native and Expo templates ship an AppCompat app theme. Material widgets
|
|
15
|
+
* (MaterialButtonToggleGroup, TextInputLayout, MaterialDatePicker, ...) throw during
|
|
16
|
+
* inflation when the host theme is not a Material Components / Material 3 theme.
|
|
17
|
+
* Rather than crash the app, wrap the context in a Material 3 theme (widgets) or
|
|
18
|
+
* hand the picker dialogs a full Material 3 dialog theme, and warn once so the
|
|
19
|
+
* developer knows how to get their own colors applied.
|
|
20
|
+
*/
|
|
21
|
+
internal object PCThemeSupport {
|
|
22
|
+
private const val TAG = "PlatformComponents"
|
|
23
|
+
|
|
24
|
+
@Volatile private var warnedMaterial = false
|
|
25
|
+
@Volatile private var warnedAppCompat = false
|
|
26
|
+
|
|
27
|
+
/** True for Theme.MaterialComponents.* and Theme.Material3.* (and descendants). */
|
|
28
|
+
fun hasMaterialTheme(context: Context): Boolean =
|
|
29
|
+
resolves(context, MaterialR.attr.materialButtonOutlinedStyle) &&
|
|
30
|
+
resolves(context, MaterialR.attr.colorSurface)
|
|
31
|
+
|
|
32
|
+
/** True for Theme.AppCompat.* and descendants, which includes every Material theme. */
|
|
33
|
+
fun hasAppCompatTheme(context: Context): Boolean =
|
|
34
|
+
resolves(context, AppCompatR.attr.alertDialogTheme)
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Context to build Material widgets from. The host context when its theme is a
|
|
38
|
+
* Material theme; otherwise a Theme.Material3.DayNight wrapper, so the widget
|
|
39
|
+
* renders with Material 3 defaults instead of throwing.
|
|
40
|
+
*/
|
|
41
|
+
fun materialContext(context: Context, component: String): Context {
|
|
42
|
+
if (hasMaterialTheme(context)) return context
|
|
43
|
+
warnMaterial(component)
|
|
44
|
+
return ContextThemeWrapper(context, MaterialR.style.Theme_Material3_DayNight_NoActionBar)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Context to build AppCompat dialogs from. The host context when its theme is an
|
|
49
|
+
* AppCompat theme; otherwise a Theme.AppCompat.DayNight.Dialog.Alert wrapper.
|
|
50
|
+
*/
|
|
51
|
+
fun appCompatDialogContext(context: Context, component: String): Context {
|
|
52
|
+
if (hasAppCompatTheme(context)) return context
|
|
53
|
+
warnAppCompat(component)
|
|
54
|
+
return ContextThemeWrapper(context, AppCompatR.style.Theme_AppCompat_DayNight_Dialog_Alert)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Theme override for MaterialDatePicker / MaterialTimePicker when the activity
|
|
59
|
+
* theme is not a Material theme. Returns 0 (no override) when it is.
|
|
60
|
+
*/
|
|
61
|
+
fun materialDialogThemeOverride(context: Context, component: String, fallbackTheme: Int): Int {
|
|
62
|
+
if (hasMaterialTheme(context)) return 0
|
|
63
|
+
warnMaterial(component)
|
|
64
|
+
return fallbackTheme
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private fun resolves(context: Context, @AttrRes attr: Int): Boolean =
|
|
68
|
+
context.theme.resolveAttribute(attr, TypedValue(), true)
|
|
69
|
+
|
|
70
|
+
private fun warnMaterial(component: String) {
|
|
71
|
+
if (warnedMaterial) return
|
|
72
|
+
warnedMaterial = true
|
|
73
|
+
Log.w(
|
|
74
|
+
TAG,
|
|
75
|
+
"$component: the app theme is not a Material 3 theme, so Material components " +
|
|
76
|
+
"fall back to Material 3 default colors. To use your app's colors, make " +
|
|
77
|
+
"AppTheme inherit from Theme.Material3.DayNight.NoActionBar in " +
|
|
78
|
+
"android/app/src/main/res/values/styles.xml (Expo: pass " +
|
|
79
|
+
"{ android: { theme: 'material3' } } to the react-native-platform-components " +
|
|
80
|
+
"config plugin). See the README section \"Android Theme Configuration\"."
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private fun warnAppCompat(component: String) {
|
|
85
|
+
if (warnedAppCompat) return
|
|
86
|
+
warnedAppCompat = true
|
|
87
|
+
Log.w(
|
|
88
|
+
TAG,
|
|
89
|
+
"$component: the app theme is not an AppCompat theme, so system dialogs fall " +
|
|
90
|
+
"back to Theme.AppCompat.DayNight.Dialog.Alert. Make AppTheme inherit from " +
|
|
91
|
+
"Theme.AppCompat.* or Theme.Material3.* to style them with your theme."
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<resources>
|
|
3
|
+
<!--
|
|
4
|
+
Fallback dialog themes for MaterialDatePicker / MaterialTimePicker when the host
|
|
5
|
+
app theme is not a Material theme (see PCThemeSupport). Each is a full
|
|
6
|
+
Theme.Material3 dialog theme plus the items from ThemeOverlay.Material3.MaterialCalendar
|
|
7
|
+
and ThemeOverlay.Material3.MaterialTimePicker (material 1.12.0), which the pickers
|
|
8
|
+
skip resolving when a theme override is supplied.
|
|
9
|
+
-->
|
|
10
|
+
<style name="PCMaterial3CalendarDialogTheme" parent="Theme.Material3.DayNight.Dialog">
|
|
11
|
+
<item name="buttonBarButtonStyle">@style/Widget.Material3.Button.TextButton.Dialog.Flush</item>
|
|
12
|
+
<item name="materialCalendarStyle">@style/Widget.Material3.MaterialCalendar</item>
|
|
13
|
+
<item name="materialCalendarHeaderLayout">@style/Widget.Material3.MaterialCalendar.HeaderLayout</item>
|
|
14
|
+
<item name="materialCalendarHeaderDivider">@style/Widget.Material3.MaterialCalendar.HeaderDivider</item>
|
|
15
|
+
<item name="materialCalendarHeaderTitle">@style/Widget.Material3.MaterialCalendar.HeaderTitle</item>
|
|
16
|
+
<item name="materialCalendarHeaderSelection">@style/Widget.Material3.MaterialCalendar.HeaderSelection</item>
|
|
17
|
+
<item name="materialCalendarHeaderCancelButton">@style/Widget.Material3.MaterialCalendar.HeaderCancelButton</item>
|
|
18
|
+
<item name="materialCalendarHeaderConfirmButton">@style/Widget.Material3.Button.TextButton</item>
|
|
19
|
+
<item name="materialCalendarHeaderToggleButton">@style/Widget.Material3.MaterialCalendar.HeaderToggleButton</item>
|
|
20
|
+
<item name="materialCalendarYearNavigationButton">@style/Widget.Material3.MaterialCalendar.YearNavigationButton</item>
|
|
21
|
+
<item name="materialCalendarMonthNavigationButton">@style/Widget.Material3.MaterialCalendar.MonthNavigationButton</item>
|
|
22
|
+
<item name="materialCalendarDayOfWeekLabel">@style/Widget.Material3.MaterialCalendar.DayOfWeekLabel</item>
|
|
23
|
+
<item name="materialCalendarDay">@style/Widget.Material3.MaterialCalendar.DayTextView</item>
|
|
24
|
+
<item name="materialCalendarMonth">@style/Widget.Material3.MaterialCalendar.MonthTextView</item>
|
|
25
|
+
<item name="buttonBarPositiveButtonStyle">@style/Widget.Material3.Button.TextButton.Dialog</item>
|
|
26
|
+
<item name="buttonBarNegativeButtonStyle">@style/Widget.Material3.Button.TextButton.Dialog</item>
|
|
27
|
+
</style>
|
|
28
|
+
|
|
29
|
+
<style name="PCMaterial3TimePickerDialogTheme" parent="Theme.Material3.DayNight.Dialog">
|
|
30
|
+
<item name="buttonBarButtonStyle">@style/Widget.Material3.Button.TextButton.Dialog.Flush</item>
|
|
31
|
+
<item name="chipStyle">@style/Widget.Material3.MaterialTimePicker.Display</item>
|
|
32
|
+
<item name="textInputStyle">@style/Widget.Material3.MaterialTimePicker.Display.TextInputLayout</item>
|
|
33
|
+
<item name="materialDisplayDividerStyle">@style/Widget.Material3.MaterialTimePicker.Display.Divider</item>
|
|
34
|
+
<item name="materialButtonOutlinedStyle">@style/Widget.Material3.MaterialTimePicker.Button</item>
|
|
35
|
+
<item name="materialClockStyle">@style/Widget.Material3.MaterialTimePicker.Clock</item>
|
|
36
|
+
<item name="materialTimePickerStyle">@style/Widget.Material3.MaterialTimePicker</item>
|
|
37
|
+
<item name="imageButtonStyle">@style/Widget.Material3.MaterialTimePicker.ImageButton</item>
|
|
38
|
+
<item name="materialTimePickerTitleStyle">@style/TextAppearance.Material3.MaterialTimePicker.Title</item>
|
|
39
|
+
</style>
|
|
40
|
+
</resources>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docusaurus.config.d.ts","sourceRoot":"","sources":["../../../../docs/docusaurus.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAMhD,QAAA,MAAM,MAAM,EAAE,MA2Fb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebars.d.ts","sourceRoot":"","sources":["../../../../docs/sidebars.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,QAAA,MAAM,QAAQ,EAAE,cAwBf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docusaurus.config.d.ts","sourceRoot":"","sources":["../../../../docs/docusaurus.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAMhD,QAAA,MAAM,MAAM,EAAE,MA2Fb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebars.d.ts","sourceRoot":"","sources":["../../../../docs/sidebars.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,QAAA,MAAM,QAAQ,EAAE,cAwBf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-platform-components",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Native UI components for React Native: DatePicker, ContextMenu, SelectionMenu, SegmentedControl
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Native UI components for React Native that are native on Android too: DatePicker, ContextMenu, SelectionMenu, SegmentedControl (Material 3) and LiquidGlass (iOS 26). Fabric, typed, Expo config plugin.",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/module/index.js",
|
|
7
7
|
"browser": "./lib/module/index.web.js",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"example": "yarn workspace react-native-platform-components-example",
|
|
59
59
|
"example-expo": "yarn workspace react-native-platform-components-example-expo",
|
|
60
|
+
"docs": "yarn workspace react-native-platform-components-docs",
|
|
60
61
|
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib plugin/build",
|
|
61
62
|
"prepare": "bob build && yarn build:plugin",
|
|
62
63
|
"typecheck": "tsc",
|
|
@@ -71,26 +72,42 @@
|
|
|
71
72
|
},
|
|
72
73
|
"keywords": [
|
|
73
74
|
"react-native",
|
|
75
|
+
"expo",
|
|
76
|
+
"expo-config-plugin",
|
|
74
77
|
"ios",
|
|
75
78
|
"android",
|
|
79
|
+
"fabric",
|
|
80
|
+
"new-architecture",
|
|
81
|
+
"native-ui",
|
|
82
|
+
"ui-components",
|
|
76
83
|
"datepicker",
|
|
77
84
|
"date-picker",
|
|
78
85
|
"time-picker",
|
|
79
|
-
"
|
|
86
|
+
"datetimepicker",
|
|
87
|
+
"uidatepicker",
|
|
88
|
+
"material-date-picker",
|
|
80
89
|
"menu",
|
|
81
|
-
"selection-menu",
|
|
82
90
|
"context-menu",
|
|
91
|
+
"contextmenu",
|
|
92
|
+
"popup-menu",
|
|
93
|
+
"uicontextmenu",
|
|
94
|
+
"selection-menu",
|
|
83
95
|
"dropdown",
|
|
84
|
-
"
|
|
85
|
-
"material-design",
|
|
86
|
-
"expo",
|
|
96
|
+
"picker",
|
|
87
97
|
"segmented-control",
|
|
88
98
|
"segmentedcontrol",
|
|
89
|
-
"tabs",
|
|
90
99
|
"segmented-buttons",
|
|
91
100
|
"segmentedbuttons",
|
|
101
|
+
"uisegmentedcontrol",
|
|
102
|
+
"tabs",
|
|
92
103
|
"liquid-glass",
|
|
93
|
-
"liquidglass"
|
|
104
|
+
"liquidglass",
|
|
105
|
+
"glass-effect",
|
|
106
|
+
"uiglasseffect",
|
|
107
|
+
"material-design",
|
|
108
|
+
"material3",
|
|
109
|
+
"material-3",
|
|
110
|
+
"material-you"
|
|
94
111
|
],
|
|
95
112
|
"repository": {
|
|
96
113
|
"type": "git",
|
|
@@ -141,12 +158,13 @@
|
|
|
141
158
|
"typescript": "~6.0.3"
|
|
142
159
|
},
|
|
143
160
|
"peerDependencies": {
|
|
144
|
-
"react": "
|
|
145
|
-
"react-native": "
|
|
161
|
+
"react": ">=19.0.0",
|
|
162
|
+
"react-native": ">=0.81.0"
|
|
146
163
|
},
|
|
147
164
|
"workspaces": [
|
|
148
165
|
"example",
|
|
149
|
-
"example-expo"
|
|
166
|
+
"example-expo",
|
|
167
|
+
"docs"
|
|
150
168
|
],
|
|
151
169
|
"packageManager": "yarn@4.11.0",
|
|
152
170
|
"react-native-builder-bob": {
|
|
@@ -218,7 +236,9 @@
|
|
|
218
236
|
"@release-it/conventional-changelog": {
|
|
219
237
|
"preset": {
|
|
220
238
|
"name": "angular"
|
|
221
|
-
}
|
|
239
|
+
},
|
|
240
|
+
"infile": "CHANGELOG.md",
|
|
241
|
+
"header": "# Changelog"
|
|
222
242
|
}
|
|
223
243
|
}
|
|
224
244
|
},
|
|
@@ -226,6 +246,7 @@
|
|
|
226
246
|
"preset": "@react-native/jest-preset",
|
|
227
247
|
"modulePathIgnorePatterns": [
|
|
228
248
|
"<rootDir>/example/node_modules",
|
|
249
|
+
"<rootDir>/docs/",
|
|
229
250
|
"<rootDir>/lib/"
|
|
230
251
|
],
|
|
231
252
|
"testPathIgnorePatterns": [
|
package/plugin/build/index.cjs
CHANGED
|
@@ -1,26 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MATERIAL3_THEME_PARENT = void 0;
|
|
4
|
+
exports.resolveMaterial3Parent = resolveMaterial3Parent;
|
|
5
|
+
exports.applyMaterial3Theme = applyMaterial3Theme;
|
|
6
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
7
|
+
exports.MATERIAL3_THEME_PARENT = 'Theme.Material3.DayNight.NoActionBar';
|
|
8
|
+
/**
|
|
9
|
+
* `react-native-edge-to-edge` re-parents `AppTheme` onto its own themes. When we
|
|
10
|
+
* see one of those, switch to the matching Material 3 flavour instead of
|
|
11
|
+
* replacing it, so edge-to-edge keeps working.
|
|
12
|
+
*/
|
|
13
|
+
const EDGE_TO_EDGE_PREFIX = 'Theme.EdgeToEdge';
|
|
14
|
+
const APP_THEME_NAME = 'AppTheme';
|
|
15
|
+
function resolveMaterial3Parent(currentParent) {
|
|
16
|
+
if (!currentParent || !currentParent.startsWith(EDGE_TO_EDGE_PREFIX)) {
|
|
17
|
+
return exports.MATERIAL3_THEME_PARENT;
|
|
18
|
+
}
|
|
19
|
+
if (currentParent.includes('.Material3')) {
|
|
20
|
+
return currentParent;
|
|
21
|
+
}
|
|
22
|
+
const suffix = currentParent.slice(EDGE_TO_EDGE_PREFIX.length); // '' | '.Light'
|
|
23
|
+
return `${EDGE_TO_EDGE_PREFIX}.Material3${suffix}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Re-parents the app theme onto Material 3, keeping every existing `<item>`
|
|
27
|
+
* (`colorPrimary`, `android:editTextBackground`, status bar colors, ...).
|
|
28
|
+
* Idempotent: running prebuild again leaves the result unchanged.
|
|
29
|
+
*/
|
|
30
|
+
function applyMaterial3Theme(xml) {
|
|
31
|
+
const styles = xml.resources.style ?? [];
|
|
32
|
+
const appTheme = styles.find((style) => style.$.name === APP_THEME_NAME);
|
|
33
|
+
if (appTheme) {
|
|
34
|
+
appTheme.$.parent = resolveMaterial3Parent(appTheme.$.parent);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
styles.push({
|
|
38
|
+
$: { name: APP_THEME_NAME, parent: exports.MATERIAL3_THEME_PARENT },
|
|
39
|
+
item: [],
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
xml.resources.style = styles;
|
|
43
|
+
return xml;
|
|
44
|
+
}
|
|
3
45
|
/**
|
|
4
46
|
* Expo config plugin for react-native-platform-components.
|
|
5
47
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* autolinking system.
|
|
9
|
-
*
|
|
10
|
-
* iOS:
|
|
11
|
-
* - Pod linkage works automatically via the standard podspec
|
|
12
|
-
* - No Info.plist, entitlements, or AppDelegate changes required
|
|
13
|
-
*
|
|
14
|
-
* Android:
|
|
15
|
-
* - Gradle linkage works automatically via autolinking
|
|
16
|
-
* - No AndroidManifest.xml, theme, or permission changes required
|
|
48
|
+
* Native linking needs no configuration on either platform: CocoaPods and
|
|
49
|
+
* Gradle autolinking pick the library up during `expo prebuild`.
|
|
17
50
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
51
|
+
* The plugin's job is the Android theme. Expo's generated `AppTheme` inherits
|
|
52
|
+
* from AppCompat, which is enough for ContextMenu, LiquidGlass and the
|
|
53
|
+
* `material: 'system'` modes, but Material 3 widgets look best under a
|
|
54
|
+
* Material 3 app theme. Pass `{ android: { theme: 'material3' } }` to have
|
|
55
|
+
* prebuild re-parent `AppTheme` accordingly.
|
|
20
56
|
*/
|
|
21
|
-
const withPlatformComponents = (config) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
57
|
+
const withPlatformComponents = (config, options) => {
|
|
58
|
+
const theme = options?.android?.theme ?? 'appcompat';
|
|
59
|
+
if (theme !== 'material3') {
|
|
60
|
+
return config;
|
|
61
|
+
}
|
|
62
|
+
return (0, config_plugins_1.withAndroidStyles)(config, (styleConfig) => {
|
|
63
|
+
styleConfig.modResults = applyMaterial3Theme(styleConfig.modResults);
|
|
64
|
+
return styleConfig;
|
|
65
|
+
});
|
|
25
66
|
};
|
|
26
67
|
exports.default = withPlatformComponents;
|
package/plugin/build/index.d.ts
CHANGED
|
@@ -1,22 +1,39 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AndroidConfig, type ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
type ResourceXML = AndroidConfig.Resources.ResourceXML;
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* This library requires no manual native configuration on either iOS or Android.
|
|
6
|
-
* The native modules are automatically linked via Expo prebuild and React Native's
|
|
7
|
-
* autolinking system.
|
|
4
|
+
* Parent theme for the Android `AppTheme` style.
|
|
8
5
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* - `'material3'`: re-parent `AppTheme` onto `Theme.Material3.DayNight.NoActionBar`.
|
|
7
|
+
* Required for `SegmentedControl` and for `DatePicker` / `SelectionMenu` in
|
|
8
|
+
* `android={{ material: 'm3' }}` mode to pick up your app's Material colors.
|
|
9
|
+
* - `'appcompat'` (default): leave Expo's `Theme.AppCompat.DayNight.NoActionBar` as is.
|
|
10
|
+
*/
|
|
11
|
+
export type AndroidTheme = 'material3' | 'appcompat';
|
|
12
|
+
export type PlatformComponentsPluginOptions = {
|
|
13
|
+
android?: {
|
|
14
|
+
theme?: AndroidTheme;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const MATERIAL3_THEME_PARENT = "Theme.Material3.DayNight.NoActionBar";
|
|
18
|
+
export declare function resolveMaterial3Parent(currentParent: string | undefined): string;
|
|
19
|
+
/**
|
|
20
|
+
* Re-parents the app theme onto Material 3, keeping every existing `<item>`
|
|
21
|
+
* (`colorPrimary`, `android:editTextBackground`, status bar colors, ...).
|
|
22
|
+
* Idempotent: running prebuild again leaves the result unchanged.
|
|
23
|
+
*/
|
|
24
|
+
export declare function applyMaterial3Theme(xml: ResourceXML): ResourceXML;
|
|
25
|
+
/**
|
|
26
|
+
* Expo config plugin for react-native-platform-components.
|
|
12
27
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* - No AndroidManifest.xml, theme, or permission changes required
|
|
28
|
+
* Native linking needs no configuration on either platform: CocoaPods and
|
|
29
|
+
* Gradle autolinking pick the library up during `expo prebuild`.
|
|
16
30
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
31
|
+
* The plugin's job is the Android theme. Expo's generated `AppTheme` inherits
|
|
32
|
+
* from AppCompat, which is enough for ContextMenu, LiquidGlass and the
|
|
33
|
+
* `material: 'system'` modes, but Material 3 widgets look best under a
|
|
34
|
+
* Material 3 app theme. Pass `{ android: { theme: 'material3' } }` to have
|
|
35
|
+
* prebuild re-parent `AppTheme` accordingly.
|
|
19
36
|
*/
|
|
20
|
-
declare const withPlatformComponents: ConfigPlugin
|
|
37
|
+
declare const withPlatformComponents: ConfigPlugin<PlatformComponentsPluginOptions | void>;
|
|
21
38
|
export default withPlatformComponents;
|
|
22
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,WAAW,GAAG,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;AAErD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,YAAY,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,sBAAsB,yCAAyC,CAAC;AAW7E,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC,MAAM,CASR;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,WAAW,CAejE;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,sBAAsB,EAAE,YAAY,CACxC,+BAA+B,GAAG,IAAI,CAWvC,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|