pytech-ui 1.0.21 → 1.0.24
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/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/9.3.0/checksums/checksums.lock +0 -0
- package/android/.gradle/9.3.0/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.3.0/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/9.3.0/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.3.0/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/nb-cache/trust/8732A504261C070E1F639E78DF65F8E6DC6FFC865B3D7178A7609BB57105805F +1 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/build.gradle +47 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/myui/Dialog.kt +39 -0
- package/android/src/main/java/expo/modules/myui/ForEach/ForEachRecords.kt +23 -0
- package/android/src/main/java/expo/modules/myui/ForEach/index.kt +82 -0
- package/android/src/main/java/expo/modules/myui/Gradient/GradientView.kt +124 -0
- package/android/src/main/java/expo/modules/myui/Icon/index.kt +36 -0
- package/android/src/main/java/expo/modules/myui/Icon/utils.kt +43 -0
- package/android/src/main/java/expo/modules/myui/ListItem/Data/ListItemDataRecords.kt +84 -0
- package/android/src/main/java/expo/modules/myui/ListItem/Data/ListItemFromData.kt +127 -0
- package/android/src/main/java/expo/modules/myui/ListItem/Slots/ListItemFromSlots.kt +60 -0
- package/android/src/main/java/expo/modules/myui/ListItem/Slots/types.kt +42 -0
- package/android/src/main/java/expo/modules/myui/ListItem/_shared/Decorator/Decorator.kt +79 -0
- package/android/src/main/java/expo/modules/myui/ListItem/_shared/Decorator/Divider.kt +36 -0
- package/android/src/main/java/expo/modules/myui/ListItem/_shared/Decorator/utilsDecorator.kt +19 -0
- package/android/src/main/java/expo/modules/myui/ListItem/_shared/Dynamic/Dynamic.kt +163 -0
- package/android/src/main/java/expo/modules/myui/ListItem/_shared/Dynamic/Row.kt +136 -0
- package/android/src/main/java/expo/modules/myui/Menu/DropdownMenu.kt +48 -0
- package/android/src/main/java/expo/modules/myui/Menu/DropdownMenuRecords.kt +20 -0
- package/android/src/main/java/expo/modules/myui/MyUiModifiers.kt +94 -0
- package/android/src/main/java/expo/modules/myui/MyUiModule.kt +168 -0
- package/android/src/main/java/expo/modules/myui/SearchBar.kt +213 -0
- package/android/src/main/java/expo/modules/myui/Section/SectionHost.kt +81 -0
- package/android/src/main/java/expo/modules/myui/Section/SectionHostView.kt +65 -0
- package/android/src/main/java/expo/modules/myui/TextField.kt +251 -0
- package/android/src/main/java/expo/modules/myui/TypographySlot/TypographySlotBridge.kt +120 -0
- package/android/src/main/java/expo/modules/myui/TypographySlot/constants.kt +47 -0
- package/android/src/main/java/expo/modules/myui/TypographySlot/index.kt +43 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/ExtendedThemeView.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Colors/ExtendedColorBridge.kt +77 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Colors/index.kt +148 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Constants/Constants.kt +11 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarLargeFlexibleTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarLargeTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarMediumFlexibleTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarMediumTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarSmallTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AppBarTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/AssistChipTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/BadgeTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/BaselineButtonTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/BottomAppBarTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonGroupSmallTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonLargeTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonMediumTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonSmallTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonXLargeTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ButtonXSmallTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/CheckboxTokens.kt +35 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/CircularProgressIndicatorTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ConnectedButtonGroupSmallTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DateInputModalTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DatePickerModalTokens.kt +33 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DialogTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DividerTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DockedToolbarTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/DragHandleTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ElevatedButtonTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ElevatedCardTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ElevationTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ExpressiveMotionTokens.kt +28 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ExtendedFabLargeTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ExtendedFabMediumTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ExtendedFabPrimaryTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ExtendedFabSmallTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FabBaselineTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FabLargeTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FabMediumTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FabMenuBaselineTokens.kt +28 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FabSmallTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledAutocompleteTokens.kt +31 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledButtonTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledCardTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledIconButtonTokens.kt +18 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledTextFieldTokens.kt +31 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledTonalButtonTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilledTonalIconButtonTokens.kt +18 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FilterChipTokens.kt +28 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/FloatingToolbarTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/IconButtonTokens.kt +17 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/InputChipTokens.kt +30 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/LargeIconButtonTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/LinearProgressIndicatorTokens.kt +28 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ListTokens.kt +57 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/LoadingIndicatorTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/MediumIconButtonTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/MotionTokens.kt +44 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationBarHorizontalItemTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationBarTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationBarVerticalItemTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationDrawerTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationRailBaselineItemTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationRailCollapsedTokens.kt +23 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationRailExpandedTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationRailHorizontalItemTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/NavigationRailVerticalItemTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedAutocompleteTokens.kt +30 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedButtonTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedCardTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedIconButtonTokens.kt +18 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedSegmentedButtonTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/OutlinedTextFieldTokens.kt +31 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/PrimaryNavigationTabTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/RadioButtonTokens.kt +22 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ScrimTokens.kt +17 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SearchBarTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SearchViewTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SecondaryNavigationTabTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SegmentedMenuTokens.kt +42 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/ShapeTokens.kt +74 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SheetBottomTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SliderTokens.kt +39 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SmallIconButtonTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SnackbarTokens.kt +21 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SplitButtonLargeTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SplitButtonMediumTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SplitButtonSmallTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SplitButtonXLargeTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SplitButtonXSmallTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/StandardMenuTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/StandardMotionTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/StateTokens.kt +20 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SuggestionChipTokens.kt +25 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/SwitchTokens.kt +37 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/TextButtonTokens.kt +18 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/TimeInputTokens.kt +24 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/TimePickerTokens.kt +30 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/TonalButtonTokens.kt +19 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/TypeScaleTokens.kt +72 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/VibrantMenuTokens.kt +26 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/XLargeIconButtonTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/assets/XSmallIconButtonTokens.kt +27 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/assets/Tokens/index.kt +217 -0
- package/android/src/main/java/expo/modules/myui/extended-theme/index.kt +39 -0
- package/android/src/main/java/expo/modules/myui/utils/children.kt +127 -0
- package/android/src/main/java/expo/modules/myui/utils/modifiers.kt +45 -0
- package/package.json +2 -1
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
package expo.modules.myui
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
4
|
+
import androidx.compose.foundation.layout.Box
|
|
5
|
+
import androidx.compose.foundation.layout.Row
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
7
|
+
import androidx.compose.foundation.layout.height
|
|
8
|
+
import androidx.compose.foundation.text.BasicTextField
|
|
9
|
+
import androidx.compose.foundation.text.KeyboardActions
|
|
10
|
+
import androidx.compose.foundation.text.KeyboardOptions
|
|
11
|
+
import androidx.compose.material3.LocalTextStyle
|
|
12
|
+
import androidx.compose.material3.Text
|
|
13
|
+
import androidx.compose.runtime.Composable
|
|
14
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
15
|
+
import androidx.compose.runtime.getValue
|
|
16
|
+
import androidx.compose.runtime.mutableStateOf
|
|
17
|
+
import androidx.compose.runtime.remember
|
|
18
|
+
import androidx.compose.runtime.setValue
|
|
19
|
+
import androidx.compose.ui.Alignment
|
|
20
|
+
import androidx.compose.ui.Modifier
|
|
21
|
+
import androidx.compose.ui.focus.FocusDirection
|
|
22
|
+
import androidx.compose.ui.focus.FocusManager
|
|
23
|
+
import androidx.compose.ui.focus.FocusRequester
|
|
24
|
+
import androidx.compose.ui.focus.focusRequester
|
|
25
|
+
import androidx.compose.ui.focus.onFocusChanged
|
|
26
|
+
import androidx.compose.ui.graphics.SolidColor
|
|
27
|
+
import androidx.compose.ui.platform.LocalFocusManager
|
|
28
|
+
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
29
|
+
import androidx.compose.ui.text.input.ImeAction
|
|
30
|
+
import androidx.compose.ui.text.input.KeyboardCapitalization
|
|
31
|
+
import androidx.compose.ui.text.input.KeyboardType
|
|
32
|
+
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
|
33
|
+
import androidx.compose.ui.text.input.VisualTransformation
|
|
34
|
+
import expo.modules.kotlin.records.Field
|
|
35
|
+
import expo.modules.kotlin.records.Record
|
|
36
|
+
import expo.modules.kotlin.types.OptimizedRecord
|
|
37
|
+
import expo.modules.kotlin.views.AsyncFunctionHandle
|
|
38
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
39
|
+
import expo.modules.kotlin.views.FunctionalComposableScope
|
|
40
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
41
|
+
import expo.modules.ui.ModifierList
|
|
42
|
+
import java.io.Serializable
|
|
43
|
+
import androidx.compose.foundation.relocation.BringIntoViewRequester
|
|
44
|
+
import androidx.compose.foundation.relocation.bringIntoViewRequester
|
|
45
|
+
import androidx.compose.runtime.rememberCoroutineScope
|
|
46
|
+
import androidx.compose.ui.focus.onFocusEvent
|
|
47
|
+
import kotlinx.coroutines.delay
|
|
48
|
+
import kotlinx.coroutines.launch
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
data class TextFieldValueChangeEvent(
|
|
52
|
+
@Field val value: String = ""
|
|
53
|
+
) : Record, Serializable
|
|
54
|
+
|
|
55
|
+
data class TextFieldFocusChangeEvent(
|
|
56
|
+
@Field val value: Boolean = false
|
|
57
|
+
) : Record, Serializable
|
|
58
|
+
|
|
59
|
+
@OptimizedRecord
|
|
60
|
+
data class TextFieldKeyboardOptionsRecord(
|
|
61
|
+
@Field val capitalization: String? = null,
|
|
62
|
+
@Field val autoCorrectEnabled: Boolean? = null,
|
|
63
|
+
@Field val keyboardType: String? = null,
|
|
64
|
+
@Field val imeAction: String? = null
|
|
65
|
+
) : Record
|
|
66
|
+
|
|
67
|
+
data class KeyboardActionEvent(
|
|
68
|
+
@Field val action: String,
|
|
69
|
+
@Field val value: String
|
|
70
|
+
) : Record
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* [value] es solo el valor inicial; el texto editado vive en estado interno.
|
|
74
|
+
* [headlineText] opcional: se muestra a la izquierda del campo (misma fila que el input).
|
|
75
|
+
*/
|
|
76
|
+
data class TextFieldProps(
|
|
77
|
+
val value: String = "",
|
|
78
|
+
val placeholder: String? = null,
|
|
79
|
+
val headlineText: String? = null,
|
|
80
|
+
val enabled: Boolean = true,
|
|
81
|
+
val autoFocus: Boolean = false,
|
|
82
|
+
val lines: Int = 1,
|
|
83
|
+
val keyboardOptions: TextFieldKeyboardOptionsRecord? = null,
|
|
84
|
+
val rowModifiers: ModifierList = emptyList(),
|
|
85
|
+
val textFieldModifiers: ModifierList = emptyList()
|
|
86
|
+
) : ComposeProps
|
|
87
|
+
|
|
88
|
+
private fun String?.toKeyboardType(): KeyboardType = when (this) {
|
|
89
|
+
"text" -> KeyboardType.Text
|
|
90
|
+
"number" -> KeyboardType.Number
|
|
91
|
+
"email" -> KeyboardType.Email
|
|
92
|
+
"phone" -> KeyboardType.Phone
|
|
93
|
+
"decimal" -> KeyboardType.Decimal
|
|
94
|
+
"password" -> KeyboardType.Password
|
|
95
|
+
"ascii" -> KeyboardType.Ascii
|
|
96
|
+
"uri" -> KeyboardType.Uri
|
|
97
|
+
"numberPassword" -> KeyboardType.NumberPassword
|
|
98
|
+
else -> KeyboardType.Text
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private fun String?.toCapitalization(): KeyboardCapitalization = when (this) {
|
|
102
|
+
"characters" -> KeyboardCapitalization.Characters
|
|
103
|
+
"none" -> KeyboardCapitalization.None
|
|
104
|
+
"sentences" -> KeyboardCapitalization.Sentences
|
|
105
|
+
"words" -> KeyboardCapitalization.Words
|
|
106
|
+
else -> KeyboardCapitalization.None
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private fun String?.toImeAction(): ImeAction = when (this) {
|
|
110
|
+
"default" -> ImeAction.Default
|
|
111
|
+
"none" -> ImeAction.None
|
|
112
|
+
"go" -> ImeAction.Go
|
|
113
|
+
"search" -> ImeAction.Search
|
|
114
|
+
"send" -> ImeAction.Send
|
|
115
|
+
"previous" -> ImeAction.Previous
|
|
116
|
+
"next" -> ImeAction.Next
|
|
117
|
+
"done" -> ImeAction.Done
|
|
118
|
+
else -> ImeAction.Default
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private fun FocusManager.performDefaultKeyboardAction(imeAction: ImeAction) {
|
|
122
|
+
when (imeAction) {
|
|
123
|
+
ImeAction.Next -> clearFocus() //moveFocus(FocusDirection.Down)
|
|
124
|
+
ImeAction.Previous -> clearFocus() //moveFocus(FocusDirection.Up)
|
|
125
|
+
ImeAction.Done, ImeAction.Go, ImeAction.Search, ImeAction.Send -> clearFocus()
|
|
126
|
+
else -> Unit
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
data class ExampleComposeViewProps(
|
|
131
|
+
@Field val title: String = "",
|
|
132
|
+
@Field val modifiers: ModifierList = emptyList()
|
|
133
|
+
) : ComposeProps
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@Composable
|
|
137
|
+
internal fun FunctionalComposableScope.TextFieldContent(
|
|
138
|
+
props: TextFieldProps,
|
|
139
|
+
focus: AsyncFunctionHandle<Unit>,
|
|
140
|
+
blur: AsyncFunctionHandle<Unit>,
|
|
141
|
+
onValueChange: (String) -> Unit,
|
|
142
|
+
onFocusChanged: (Boolean) -> Unit,
|
|
143
|
+
onKeyboardActionTriggered: (KeyboardActionEvent) -> Unit
|
|
144
|
+
) {
|
|
145
|
+
var text by remember { mutableStateOf(props.value) }
|
|
146
|
+
val focusManager = LocalFocusManager.current
|
|
147
|
+
val focusRequester = remember { FocusRequester() }
|
|
148
|
+
val keyboardController = LocalSoftwareKeyboardController.current
|
|
149
|
+
|
|
150
|
+
focus.handle {
|
|
151
|
+
focusRequester.requestFocus()
|
|
152
|
+
keyboardController?.show()
|
|
153
|
+
}
|
|
154
|
+
blur.handle {
|
|
155
|
+
focusManager.clearFocus()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (props.autoFocus) {
|
|
159
|
+
LaunchedEffect(Unit) {
|
|
160
|
+
delay(300)
|
|
161
|
+
runCatching {
|
|
162
|
+
focusRequester.requestFocus()
|
|
163
|
+
keyboardController?.show()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
val kbOpts = props.keyboardOptions
|
|
169
|
+
val keyboardTypeKey = kbOpts?.keyboardType
|
|
170
|
+
val visualTransformation =
|
|
171
|
+
if (keyboardTypeKey == "password" || keyboardTypeKey == "numberPassword") {
|
|
172
|
+
PasswordVisualTransformation()
|
|
173
|
+
} else {
|
|
174
|
+
VisualTransformation.None
|
|
175
|
+
}
|
|
176
|
+
val keyboardOptions = KeyboardOptions.Default.copy(
|
|
177
|
+
keyboardType = keyboardTypeKey.toKeyboardType(),
|
|
178
|
+
autoCorrectEnabled = kbOpts?.autoCorrectEnabled ?: true,
|
|
179
|
+
capitalization = kbOpts?.capitalization.toCapitalization(),
|
|
180
|
+
imeAction = kbOpts?.imeAction.toImeAction()
|
|
181
|
+
)
|
|
182
|
+
val currentText = { text }
|
|
183
|
+
val keyboardActions = KeyboardActions(
|
|
184
|
+
onDone = {
|
|
185
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Done)
|
|
186
|
+
onKeyboardActionTriggered(KeyboardActionEvent("done", currentText()))
|
|
187
|
+
},
|
|
188
|
+
onGo = {
|
|
189
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Go)
|
|
190
|
+
onKeyboardActionTriggered(KeyboardActionEvent("go", currentText()))
|
|
191
|
+
},
|
|
192
|
+
onNext = {
|
|
193
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Next)
|
|
194
|
+
onKeyboardActionTriggered(KeyboardActionEvent("next", currentText()))
|
|
195
|
+
},
|
|
196
|
+
onPrevious = {
|
|
197
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Previous)
|
|
198
|
+
onKeyboardActionTriggered(KeyboardActionEvent("previous", currentText()))
|
|
199
|
+
},
|
|
200
|
+
onSearch = {
|
|
201
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Search)
|
|
202
|
+
onKeyboardActionTriggered(KeyboardActionEvent("search", currentText()))
|
|
203
|
+
},
|
|
204
|
+
onSend = {
|
|
205
|
+
focusManager.performDefaultKeyboardAction(ImeAction.Send)
|
|
206
|
+
onKeyboardActionTriggered(KeyboardActionEvent("send", currentText()))
|
|
207
|
+
},
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
val bringIntoViewRequester = remember { BringIntoViewRequester() }
|
|
211
|
+
val scope = rememberCoroutineScope()
|
|
212
|
+
|
|
213
|
+
BasicTextField(
|
|
214
|
+
value = text,
|
|
215
|
+
onValueChange = { newValue ->
|
|
216
|
+
text = newValue
|
|
217
|
+
onValueChange(newValue)
|
|
218
|
+
},
|
|
219
|
+
modifier = Modifier
|
|
220
|
+
.fillMaxWidth()
|
|
221
|
+
.focusRequester(focusRequester)
|
|
222
|
+
.onFocusChanged { onFocusChanged(it.isFocused) }
|
|
223
|
+
.bringIntoViewRequester(bringIntoViewRequester)
|
|
224
|
+
.onFocusChanged { focusState ->
|
|
225
|
+
onFocusChanged(focusState.isFocused)
|
|
226
|
+
if (focusState.isFocused) {
|
|
227
|
+
scope.launch {
|
|
228
|
+
kotlinx.coroutines.delay(100)
|
|
229
|
+
bringIntoViewRequester.bringIntoView()
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
enabled = props.enabled,
|
|
234
|
+
textStyle = LocalTextStyle.current,
|
|
235
|
+
singleLine = props.lines == 1,
|
|
236
|
+
maxLines = if (props.lines > 1) props.lines.coerceAtLeast(2) else Int.MAX_VALUE,
|
|
237
|
+
cursorBrush = SolidColor(ExtendedTheme.colorScheme.systemBlue),
|
|
238
|
+
keyboardOptions = keyboardOptions,
|
|
239
|
+
keyboardActions = keyboardActions,
|
|
240
|
+
visualTransformation = visualTransformation,
|
|
241
|
+
decorationBox = { innerTextField ->
|
|
242
|
+
if (text.isEmpty() && !props.placeholder.isNullOrBlank()) {
|
|
243
|
+
Text(
|
|
244
|
+
text = props.placeholder!!,
|
|
245
|
+
color = ExtendedTheme.colorScheme.placeholderText
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
innerTextField()
|
|
249
|
+
},
|
|
250
|
+
)
|
|
251
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
package expo.modules.myui.TypographySlot
|
|
2
|
+
|
|
3
|
+
import androidx.compose.material3.MaterialTheme
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.ui.graphics.Color
|
|
6
|
+
import androidx.compose.ui.text.TextStyle
|
|
7
|
+
import androidx.compose.ui.text.font.FontWeight
|
|
8
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
9
|
+
import androidx.compose.ui.unit.sp
|
|
10
|
+
import expo.modules.kotlin.records.Field
|
|
11
|
+
import expo.modules.kotlin.records.Record
|
|
12
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
13
|
+
|
|
14
|
+
data class SlotTypographyStyleRecord(
|
|
15
|
+
@Field val typography: String? = null,
|
|
16
|
+
@Field val fontSize: Double? = null,
|
|
17
|
+
@Field val lineHeight: Double? = null,
|
|
18
|
+
@Field val fontWeight: String? = null,
|
|
19
|
+
@Field val textAlign: String? = null,
|
|
20
|
+
) : Record
|
|
21
|
+
|
|
22
|
+
data class SlotTextStyleRecord(
|
|
23
|
+
@Field val style: SlotTypographyStyleRecord,
|
|
24
|
+
@Field val color: String? = null,
|
|
25
|
+
@Field val overflow: String? = null,
|
|
26
|
+
@Field val maxLines: Int? = null,
|
|
27
|
+
) : Record
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Bridge de estilos por slot (Compose + JS vía [slotTextStylePayload]).
|
|
31
|
+
* Los valores viven en [Typographies.specs].
|
|
32
|
+
*/
|
|
33
|
+
internal object TypographySlotBridge {
|
|
34
|
+
|
|
35
|
+
fun slotTextStylePayload(slotName: String): SlotTextStyleRecord? {
|
|
36
|
+
val spec = Typographies.specs[slotName.lowercase()] ?: return null
|
|
37
|
+
return SlotTextStyleRecord(
|
|
38
|
+
style = SlotTypographyStyleRecord(
|
|
39
|
+
typography = spec.typography,
|
|
40
|
+
fontSize = spec.fontSize?.toDouble(),
|
|
41
|
+
lineHeight = spec.lineHeight?.toDouble(),
|
|
42
|
+
fontWeight = spec.fontWeight?.toString(),
|
|
43
|
+
textAlign = spec.textAlign,
|
|
44
|
+
),
|
|
45
|
+
color = spec.color,
|
|
46
|
+
overflow = spec.overflow,
|
|
47
|
+
maxLines = spec.maxLines,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Composable
|
|
52
|
+
fun textStyleForSlot(slotName: String): TextStyle? {
|
|
53
|
+
val spec = Typographies.specs[slotName.lowercase()] ?: return null
|
|
54
|
+
var style = typographyFromToken(spec.typography)
|
|
55
|
+
spec.fontSize?.let { style = style.copy(fontSize = it.sp) }
|
|
56
|
+
spec.lineHeight?.let { style = style.copy(lineHeight = it.sp) }
|
|
57
|
+
spec.fontWeight?.let { style = style.copy(fontWeight = fontWeightFromValue(it)) }
|
|
58
|
+
spec.textAlign?.let { align ->
|
|
59
|
+
textAlignFromValue(align)?.let { style = style.copy(textAlign = it) }
|
|
60
|
+
}
|
|
61
|
+
colorFromToken(spec.color)?.let { style = style.copy(color = it) }
|
|
62
|
+
return style
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Composable
|
|
66
|
+
private fun typographyFromToken(token: String): TextStyle =
|
|
67
|
+
when (token) {
|
|
68
|
+
"displayLarge" -> MaterialTheme.typography.displayLarge
|
|
69
|
+
"displayMedium" -> MaterialTheme.typography.displayMedium
|
|
70
|
+
"displaySmall" -> MaterialTheme.typography.displaySmall
|
|
71
|
+
"headlineLarge" -> MaterialTheme.typography.headlineLarge
|
|
72
|
+
"headlineMedium" -> MaterialTheme.typography.headlineMedium
|
|
73
|
+
"headlineSmall" -> MaterialTheme.typography.headlineSmall
|
|
74
|
+
"titleLarge" -> MaterialTheme.typography.titleLarge
|
|
75
|
+
"titleMedium" -> MaterialTheme.typography.titleMedium
|
|
76
|
+
"titleSmall" -> MaterialTheme.typography.titleSmall
|
|
77
|
+
"bodyLarge" -> MaterialTheme.typography.bodyLarge
|
|
78
|
+
"bodyMedium" -> MaterialTheme.typography.bodyMedium
|
|
79
|
+
"bodySmall" -> MaterialTheme.typography.bodySmall
|
|
80
|
+
"labelLarge" -> MaterialTheme.typography.labelLarge
|
|
81
|
+
"labelMedium" -> MaterialTheme.typography.labelMedium
|
|
82
|
+
"labelSmall" -> MaterialTheme.typography.labelSmall
|
|
83
|
+
else -> MaterialTheme.typography.bodyLarge
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private fun textAlignFromValue(value: String): TextAlign? =
|
|
87
|
+
when (value.lowercase()) {
|
|
88
|
+
"left" -> TextAlign.Left
|
|
89
|
+
"right" -> TextAlign.Right
|
|
90
|
+
"center" -> TextAlign.Center
|
|
91
|
+
"justify" -> TextAlign.Justify
|
|
92
|
+
"start" -> TextAlign.Start
|
|
93
|
+
"end" -> TextAlign.End
|
|
94
|
+
else -> null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun fontWeightFromValue(value: Int): FontWeight =
|
|
98
|
+
when (value) {
|
|
99
|
+
100 -> FontWeight.Thin
|
|
100
|
+
200 -> FontWeight.ExtraLight
|
|
101
|
+
300 -> FontWeight.Light
|
|
102
|
+
400 -> FontWeight.Normal
|
|
103
|
+
500 -> FontWeight.Medium
|
|
104
|
+
600 -> FontWeight.SemiBold
|
|
105
|
+
700 -> FontWeight.Bold
|
|
106
|
+
800 -> FontWeight.ExtraBold
|
|
107
|
+
900 -> FontWeight.Black
|
|
108
|
+
else -> FontWeight(value)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Composable
|
|
112
|
+
private fun colorFromToken(token: String?): Color? =
|
|
113
|
+
when (token?.lowercase()) {
|
|
114
|
+
"label" -> ExtendedTheme.colorScheme.label
|
|
115
|
+
"secondarylabel" -> ExtendedTheme.colorScheme.secondaryLabel
|
|
116
|
+
"tertiarylabel" -> ExtendedTheme.colorScheme.tertiaryLabel
|
|
117
|
+
"link" -> ExtendedTheme.colorScheme.link
|
|
118
|
+
else -> null
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package expo.modules.myui.TypographySlot
|
|
2
|
+
|
|
3
|
+
internal data class SlotTextSpec(
|
|
4
|
+
val typography: String,
|
|
5
|
+
val fontSize: Float? = null,
|
|
6
|
+
val lineHeight: Float? = null,
|
|
7
|
+
val fontWeight: Int? = null,
|
|
8
|
+
val color: String? = null,
|
|
9
|
+
/** Valores de `@expo/ui` Text: `clip`, `ellipsis`, `visible`. */
|
|
10
|
+
val overflow: String? = null,
|
|
11
|
+
val maxLines: Int? = null,
|
|
12
|
+
/** Valores de `@expo/ui` Text: `left`, `right`, `center`, `justify`, `start`, `end`. */
|
|
13
|
+
val textAlign: String? = null,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Estilos por slot (minúsculas). Compartidos por [TypographySlotBridge] (Compose + JS).
|
|
18
|
+
*/
|
|
19
|
+
internal object Typographies {
|
|
20
|
+
|
|
21
|
+
val specs: Map<String, SlotTextSpec> = mapOf(
|
|
22
|
+
"headlinecontent" to SlotTextSpec("bodyLarge", 17f, 22f, 400 /*, maxLines = 1*/, textAlign = "left"),
|
|
23
|
+
"trailingcontent" to SlotTextSpec("bodyLarge", 17f, 22f, 400 /*, , maxLines = 1*/, textAlign = "end", overflow = "ellipsis"),
|
|
24
|
+
"supportingcontent" to SlotTextSpec("bodyMedium", 15f, 20f, 400),
|
|
25
|
+
"leadingcontent" to SlotTextSpec("headlineSmall"),
|
|
26
|
+
"overlinecontent" to SlotTextSpec("labelMedium"),
|
|
27
|
+
|
|
28
|
+
"title" to SlotTextSpec("bodyLarge", 17f, 22f, 600, "secondaryLabel"),
|
|
29
|
+
"header" to SlotTextSpec("bodyLarge", 17f, 22f, 600, "secondaryLabel"),
|
|
30
|
+
"footer" to SlotTextSpec("bodySmall", 13f, 16f, 400, "secondaryLabel"),
|
|
31
|
+
"footercount" to SlotTextSpec("bodyLarge", 17f, 22f, 500, "label", textAlign = "center"),
|
|
32
|
+
|
|
33
|
+
"icontitle" to SlotTextSpec("bodyLarge", 28f, 34f, 700, "label"),
|
|
34
|
+
"iconsubtitle" to SlotTextSpec("bodyLarge", 17f, 22f, 400, "secondaryLabel"),
|
|
35
|
+
"iconbutton" to SlotTextSpec("bodyLarge", 17f, 22f, 500, "label"),
|
|
36
|
+
|
|
37
|
+
"menuitemheadline" to SlotTextSpec("bodyLarge", 17f, 20f, 400),
|
|
38
|
+
"menuitemsupporting" to SlotTextSpec("bodyMedium", 13f, 18f, 400, "secondaryLabel"),
|
|
39
|
+
"menuitemtrailing" to SlotTextSpec("bodyMedium", 15f, 20f, 500, "secondaryLabel"),
|
|
40
|
+
|
|
41
|
+
"modalheader" to SlotTextSpec("bodyLarge", 17f, 22f, 600),
|
|
42
|
+
|
|
43
|
+
"titlealert" to SlotTextSpec("bodyLarge", 17f, 22f, 600),
|
|
44
|
+
"messagetalert" to SlotTextSpec("bodyLarge", 17f, 22f, 400),
|
|
45
|
+
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package expo.modules.myui.TypographySlot
|
|
2
|
+
|
|
3
|
+
import androidx.compose.material3.ProvideTextStyle
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
6
|
+
import expo.modules.kotlin.views.FunctionalComposableScope
|
|
7
|
+
|
|
8
|
+
import expo.modules.myui.Children
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* [slotName] debe coincidir con los strings de slot de ListItem en Compose / `@expo/ui`
|
|
12
|
+
* (p. ej. `headlineContent`, `trailingContent`), no con las claves TS (`HeadlineContent`).
|
|
13
|
+
*/
|
|
14
|
+
data class TypographySlotProps(
|
|
15
|
+
val slotName: String = "",
|
|
16
|
+
/** Si es false, solo se delega a [content] sin envolver en [ProvideTextStyle]. */
|
|
17
|
+
val applyTypography: Boolean = true,
|
|
18
|
+
) : ComposeProps
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Aplica la tipografía del slot al [content] composable.
|
|
22
|
+
* Compartido por [TypographySlotContent] y [expo.modules.myui.ListItem.ListItemDynamic].
|
|
23
|
+
*/
|
|
24
|
+
@Composable
|
|
25
|
+
internal fun SlotTypography(
|
|
26
|
+
slotName: String,
|
|
27
|
+
applyTypography: Boolean = true,
|
|
28
|
+
content: @Composable () -> Unit,
|
|
29
|
+
) {
|
|
30
|
+
val style = TypographySlotBridge.textStyleForSlot(slotName)
|
|
31
|
+
if (applyTypography && style != null) {
|
|
32
|
+
ProvideTextStyle(style, content = content)
|
|
33
|
+
} else {
|
|
34
|
+
content()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Composable
|
|
39
|
+
internal fun FunctionalComposableScope.TypographySlotContent(props: TypographySlotProps) {
|
|
40
|
+
SlotTypography(props.slotName, props.applyTypography) {
|
|
41
|
+
Children()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package expo.modules.myui
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
5
|
+
import expo.modules.kotlin.views.FunctionalComposableScope
|
|
6
|
+
|
|
7
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
8
|
+
|
|
9
|
+
/** Props para `View("ExtendedTheme")` — constructor con defaults (Expo Modules). */
|
|
10
|
+
data class ExtendedThemeProps(
|
|
11
|
+
private val unused: Boolean = false,
|
|
12
|
+
) : ComposeProps
|
|
13
|
+
|
|
14
|
+
@Composable
|
|
15
|
+
internal fun FunctionalComposableScope.ExtendedThemeViewContent(props: ExtendedThemeProps) {
|
|
16
|
+
ExtendedTheme {
|
|
17
|
+
Children()
|
|
18
|
+
}
|
|
19
|
+
}
|
package/android/src/main/java/expo/modules/myui/extended-theme/assets/Colors/ExtendedColorBridge.kt
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
package expo.modules.myui.theme.colors
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// Agregar esto al MyUiModule.kt
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
Function("getExtendedColor") { name: String, scheme: String ->
|
|
8
|
+
val context =
|
|
9
|
+
appContext.reactContext
|
|
10
|
+
?: throw IllegalStateException("React context is not available")
|
|
11
|
+
ExtendedColorBridge.extendedColorHex(name, scheme, context)
|
|
12
|
+
}
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import android.content.Context
|
|
18
|
+
import android.content.res.Configuration
|
|
19
|
+
import androidx.compose.ui.graphics.Color
|
|
20
|
+
import androidx.compose.ui.graphics.toArgb
|
|
21
|
+
import java.util.Locale
|
|
22
|
+
import kotlin.reflect.KProperty1
|
|
23
|
+
import kotlin.reflect.full.memberProperties
|
|
24
|
+
|
|
25
|
+
import expo.modules.myui.theme.colors.ExtendedColorScheme
|
|
26
|
+
import expo.modules.myui.theme.colors.extendedDark
|
|
27
|
+
import expo.modules.myui.theme.colors.extendedLight
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resuelve light/dark como Expo Router: si [scheme] no es "light" ni "dark",
|
|
32
|
+
* usa el UI mode del [context] (p. ej. cuando JS manda "unspecified").
|
|
33
|
+
*
|
|
34
|
+
* Los tokens de color se derivan de [ExtendedColorScheme]: cada propiedad `Color`
|
|
35
|
+
* queda expuesta como clave en minúsculas (`BLUE` → `"blue"`, `SECONDARY_LABEL` → `"secondary_label"`).
|
|
36
|
+
*/
|
|
37
|
+
internal object ExtendedColorBridge {
|
|
38
|
+
|
|
39
|
+
private val colorAccessors: Map<String, (ExtendedColorScheme) -> Color> by lazy {
|
|
40
|
+
ExtendedColorScheme::class.memberProperties.mapNotNull { prop ->
|
|
41
|
+
val getter = prop as? KProperty1<ExtendedColorScheme, *> ?: return@mapNotNull null
|
|
42
|
+
if (getter.returnType.classifier != Color::class) return@mapNotNull null
|
|
43
|
+
prop.name.lowercase(Locale.US) to { scheme: ExtendedColorScheme ->
|
|
44
|
+
getter.get(scheme) as Color
|
|
45
|
+
}
|
|
46
|
+
}.toMap()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
fun resolveScheme(scheme: String, context: Context): String {
|
|
50
|
+
if (scheme == "dark" || scheme == "light") {
|
|
51
|
+
return scheme
|
|
52
|
+
}
|
|
53
|
+
val flags = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
|
54
|
+
return when (flags) {
|
|
55
|
+
Configuration.UI_MODE_NIGHT_YES -> "dark"
|
|
56
|
+
else -> "light"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* HEX #RRGGBB para un token de [ExtendedColorScheme].
|
|
62
|
+
* [name]: case-insensitive; debe coincidir con el nombre de la propiedad en minúsculas.
|
|
63
|
+
* Devuelve null si el token no existe.
|
|
64
|
+
*/
|
|
65
|
+
fun extendedColorHex(name: String, scheme: String, context: Context): String? {
|
|
66
|
+
val resolved = resolveScheme(scheme, context)
|
|
67
|
+
val palette: ExtendedColorScheme =
|
|
68
|
+
if (resolved == "dark") extendedDark else extendedLight
|
|
69
|
+
val color = pickColor(palette, name.lowercase(Locale.US)) ?: return null
|
|
70
|
+
return String.format(Locale.US, "#%06X", 0xFFFFFF and color.toArgb())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private fun pickColor(scheme: ExtendedColorScheme, key: String): Color? {
|
|
74
|
+
val accessor = colorAccessors[key.lowercase(Locale.US)] ?: return null
|
|
75
|
+
return accessor(scheme)
|
|
76
|
+
}
|
|
77
|
+
}
|