pytech-ui 1.0.21 → 1.0.23
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,60 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.ui.Modifier
|
|
6
|
+
import expo.modules.kotlin.views.ExpoComposeView
|
|
7
|
+
import expo.modules.kotlin.views.FunctionalComposableScope
|
|
8
|
+
import expo.modules.ui.SlotView
|
|
9
|
+
|
|
10
|
+
import expo.modules.myui.getModifier
|
|
11
|
+
import expo.modules.myui.section.sectionItemPosition
|
|
12
|
+
import expo.modules.myui.ListItem.ListItemDynamic
|
|
13
|
+
import expo.modules.myui.ListItem.Decorator
|
|
14
|
+
import expo.modules.myui.ListItem.RenderSlot
|
|
15
|
+
import expo.modules.myui.findChildBySlotName
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// Crea el ListItem desde los slots
|
|
21
|
+
|
|
22
|
+
@Composable
|
|
23
|
+
internal fun FunctionalComposableScope.ListItemFromSlots(props: ListItemProps) {
|
|
24
|
+
val composeView = view as ExpoComposeView<*>
|
|
25
|
+
val sectionPosition = composeView.sectionItemPosition(props)
|
|
26
|
+
|
|
27
|
+
val isFirst = sectionPosition?.isFirst ?: (props.isFirst ?: true)
|
|
28
|
+
val isLast = sectionPosition?.isLast ?: (props.isLast ?: true)
|
|
29
|
+
|
|
30
|
+
val headlineSlot = findChildBySlotName("headlineContent")
|
|
31
|
+
val overlineSlot = findChildBySlotName("overlineContent")
|
|
32
|
+
val supportingSlot = findChildBySlotName("supportingContent")
|
|
33
|
+
val leadingSlot = findChildBySlotName("leadingContent")
|
|
34
|
+
val trailingSlot = findChildBySlotName("trailingContent")
|
|
35
|
+
Decorator(
|
|
36
|
+
isFirst = isFirst,
|
|
37
|
+
isLast = isLast,
|
|
38
|
+
showDivider = props.showDivider,
|
|
39
|
+
modifier = getModifier(props.modifiers),
|
|
40
|
+
) { innerProps ->
|
|
41
|
+
ListItemDynamic(
|
|
42
|
+
props = props,
|
|
43
|
+
modifier = Modifier.fillMaxWidth(),
|
|
44
|
+
innerProps = innerProps,
|
|
45
|
+
leadingContent = leadingSlot?.let { slot -> { RenderSlot(slot) } },
|
|
46
|
+
overlineContent = overlineSlot?.let { slot -> { RenderSlot(slot) } },
|
|
47
|
+
supportingContent = supportingSlot?.let { slot -> { RenderSlot(slot) } },
|
|
48
|
+
headlineContent = headlineSlot?.let { slot -> { RenderSlot(slot) } },
|
|
49
|
+
trailingContent = trailingSlot?.let { slot -> { RenderSlot(slot) } },
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@Composable
|
|
56
|
+
internal fun FunctionalComposableScope.RenderSlot(slot: SlotView) {
|
|
57
|
+
with(composableScope) {
|
|
58
|
+
with(slot) { Content() }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import androidx.compose.ui.unit.Dp
|
|
5
|
+
import expo.modules.kotlin.records.Field
|
|
6
|
+
import expo.modules.kotlin.records.Record
|
|
7
|
+
import expo.modules.kotlin.types.OptimizedRecord
|
|
8
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
9
|
+
import expo.modules.kotlin.views.OptimizedComposeProps
|
|
10
|
+
import expo.modules.ui.ModifierList
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@OptimizedRecord
|
|
15
|
+
data class ListItemColorsRecord(
|
|
16
|
+
@Field val containerColor: Color? = null,
|
|
17
|
+
@Field val contentColor: Color? = null,
|
|
18
|
+
@Field val leadingContentColor: Color? = null,
|
|
19
|
+
@Field val trailingContentColor: Color? = null,
|
|
20
|
+
@Field val supportingContentColor: Color? = null,
|
|
21
|
+
@Field val overlineContentColor: Color? = null,
|
|
22
|
+
) : Record
|
|
23
|
+
|
|
24
|
+
@OptimizedComposeProps
|
|
25
|
+
data class ListItemProps(
|
|
26
|
+
|
|
27
|
+
val showDivider: Boolean = true,
|
|
28
|
+
val isFirst: Boolean? = null,
|
|
29
|
+
val isLast: Boolean? = null,
|
|
30
|
+
val hasNavigationLink: Boolean? = null,
|
|
31
|
+
|
|
32
|
+
val tonalElevation: Float? = null,
|
|
33
|
+
val shadowElevation: Float? = null,
|
|
34
|
+
val colors: ListItemColorsRecord? = null,
|
|
35
|
+
val modifiers: ModifierList = emptyList(),
|
|
36
|
+
|
|
37
|
+
) : ComposeProps
|
|
38
|
+
|
|
39
|
+
/** Props internas de Kotlin; el callback no puede venir del bridge JS. */
|
|
40
|
+
internal data class ListItemInnerProps(
|
|
41
|
+
val onLeadingWidthChanged: ((Dp) -> Unit)? = null,
|
|
42
|
+
)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Column
|
|
5
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
6
|
+
import androidx.compose.runtime.Composable
|
|
7
|
+
import androidx.compose.runtime.getValue
|
|
8
|
+
import androidx.compose.runtime.mutableStateOf
|
|
9
|
+
import androidx.compose.runtime.remember
|
|
10
|
+
import androidx.compose.runtime.setValue
|
|
11
|
+
import androidx.compose.ui.Modifier
|
|
12
|
+
import androidx.compose.ui.draw.clip
|
|
13
|
+
import androidx.compose.ui.unit.dp
|
|
14
|
+
|
|
15
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
|
|
21
|
+
Decorator para el ListItem
|
|
22
|
+
|
|
23
|
+
Agrega:
|
|
24
|
+
|
|
25
|
+
- Background
|
|
26
|
+
- Shape
|
|
27
|
+
- Divider
|
|
28
|
+
|
|
29
|
+
Tiene la logica interna del LeadingWidth
|
|
30
|
+
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
@Composable
|
|
34
|
+
internal fun Decorator(
|
|
35
|
+
isFirst: Boolean,
|
|
36
|
+
isLast: Boolean,
|
|
37
|
+
showDivider: Boolean = true,
|
|
38
|
+
modifier: Modifier = Modifier,
|
|
39
|
+
content: @Composable (ListItemInnerProps) -> Unit,
|
|
40
|
+
|
|
41
|
+
) {
|
|
42
|
+
|
|
43
|
+
val shouldShowDivider = showDivider && !isLast
|
|
44
|
+
val backgroundColor = ExtendedTheme.colorScheme.secondarySystemGroupedBackground
|
|
45
|
+
val shape =
|
|
46
|
+
if (isFirst || isLast) {
|
|
47
|
+
itemClipShape(isFirst, isLast)
|
|
48
|
+
} else {
|
|
49
|
+
null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var leadingWidth by remember { mutableStateOf(0.dp) }
|
|
53
|
+
val shapeModifier = if (shape != null) {
|
|
54
|
+
Modifier.clip(shape).background(backgroundColor, shape)
|
|
55
|
+
} else {
|
|
56
|
+
Modifier.background(backgroundColor)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// clickable debe ir después de clip para que el ripple respete las esquinas
|
|
60
|
+
val rowModifier = Modifier
|
|
61
|
+
.fillMaxWidth()
|
|
62
|
+
.then(shapeModifier)
|
|
63
|
+
.then(modifier)
|
|
64
|
+
|
|
65
|
+
Column(modifier = rowModifier) {
|
|
66
|
+
content(
|
|
67
|
+
ListItemInnerProps(
|
|
68
|
+
onLeadingWidthChanged =
|
|
69
|
+
if (shouldShowDivider) {
|
|
70
|
+
{ width -> if (width != leadingWidth) { leadingWidth = width } }
|
|
71
|
+
} else {
|
|
72
|
+
null
|
|
73
|
+
},
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if (shouldShowDivider) { ListItemDivider(leadingWidth = leadingWidth) }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
4
|
+
import androidx.compose.foundation.layout.padding
|
|
5
|
+
import androidx.compose.material3.HorizontalDivider
|
|
6
|
+
import androidx.compose.runtime.Composable
|
|
7
|
+
import androidx.compose.ui.Modifier
|
|
8
|
+
import androidx.compose.ui.unit.Dp
|
|
9
|
+
import androidx.compose.ui.unit.dp
|
|
10
|
+
|
|
11
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
12
|
+
import expo.modules.myui.theme.tokens.ListTokens
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/* Crea el divider segun el leadingWidth */
|
|
17
|
+
|
|
18
|
+
@Composable
|
|
19
|
+
internal fun ListItemDivider(leadingWidth: Dp) {
|
|
20
|
+
val leadingInset = if (leadingWidth > 0.dp) {
|
|
21
|
+
leadingWidth + ListTokens.ItemBetweenSpace + 4.dp // +4.dp porque tiene que dar 16.dp
|
|
22
|
+
} else {
|
|
23
|
+
0.dp
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
HorizontalDivider(
|
|
27
|
+
modifier = Modifier
|
|
28
|
+
.fillMaxWidth()
|
|
29
|
+
.padding(
|
|
30
|
+
start = ListTokens.DividerLeadingSpace + leadingInset,
|
|
31
|
+
end = ListTokens.DividerTrailingSpace,
|
|
32
|
+
),
|
|
33
|
+
color = ExtendedTheme.colorScheme.separator.copy(alpha = 0.4f),
|
|
34
|
+
thickness = 1.dp,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
4
|
+
import androidx.compose.ui.unit.dp
|
|
5
|
+
|
|
6
|
+
import expo.modules.myui.theme.tokens.ShapeTokens
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
private val GroupCornerRadius = ShapeTokens.CornerValueExtraLarge
|
|
11
|
+
|
|
12
|
+
internal fun itemClipShape(isFirst: Boolean, isLast: Boolean): RoundedCornerShape {
|
|
13
|
+
return RoundedCornerShape(
|
|
14
|
+
topStart = if (isFirst) GroupCornerRadius else 0.dp,
|
|
15
|
+
topEnd = if (isFirst) GroupCornerRadius else 0.dp,
|
|
16
|
+
bottomStart = if (isLast) GroupCornerRadius else 0.dp,
|
|
17
|
+
bottomEnd = if (isLast) GroupCornerRadius else 0.dp,
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
5
|
+
import androidx.compose.foundation.layout.size
|
|
6
|
+
import androidx.compose.material.icons.Icons
|
|
7
|
+
import androidx.compose.material.icons.rounded.ArrowForwardIos
|
|
8
|
+
import androidx.compose.material3.Icon
|
|
9
|
+
import androidx.compose.material3.ListItem as ListItemMaterial
|
|
10
|
+
import androidx.compose.material3.ListItemDefaults
|
|
11
|
+
import androidx.compose.material3.Surface
|
|
12
|
+
import androidx.compose.runtime.Composable
|
|
13
|
+
import androidx.compose.ui.Alignment
|
|
14
|
+
import androidx.compose.ui.Modifier
|
|
15
|
+
import androidx.compose.ui.graphics.Color
|
|
16
|
+
import androidx.compose.ui.graphics.Color as ComposeColor
|
|
17
|
+
import androidx.compose.ui.layout.onSizeChanged
|
|
18
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
19
|
+
import androidx.compose.ui.unit.dp
|
|
20
|
+
import expo.modules.ui.composeOrNull
|
|
21
|
+
|
|
22
|
+
import expo.modules.myui.TypographySlot.SlotTypography
|
|
23
|
+
import expo.modules.myui.theme.ExtendedTheme
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
|
|
29
|
+
ListItemDynamic es el componente que se encarga de la logica interna del ListItem
|
|
30
|
+
|
|
31
|
+
Se encarga de poner visualmente:
|
|
32
|
+
|
|
33
|
+
- LeadingContent
|
|
34
|
+
- HeadlineContent
|
|
35
|
+
- TrailingContent
|
|
36
|
+
- OverlineContent
|
|
37
|
+
- SupportingContent
|
|
38
|
+
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
@Composable
|
|
42
|
+
internal fun ListItemDynamic(
|
|
43
|
+
props: ListItemProps = ListItemProps(),
|
|
44
|
+
modifier: Modifier = Modifier,
|
|
45
|
+
innerProps: ListItemInnerProps = ListItemInnerProps(),
|
|
46
|
+
leadingContent: (@Composable () -> Unit)? = null,
|
|
47
|
+
headlineContent: (@Composable () -> Unit)? = null,
|
|
48
|
+
trailingContent: (@Composable () -> Unit)? = null,
|
|
49
|
+
overlineContent: (@Composable () -> Unit)? = null,
|
|
50
|
+
supportingContent: (@Composable () -> Unit)? = null,
|
|
51
|
+
) {
|
|
52
|
+
val density = LocalDensity.current
|
|
53
|
+
|
|
54
|
+
val colors = listItemColors(props)
|
|
55
|
+
|
|
56
|
+
ListItemMaterial(
|
|
57
|
+
modifier = modifier,
|
|
58
|
+
colors = colors,
|
|
59
|
+
tonalElevation = props.tonalElevation?.dp ?: ListItemDefaults.Elevation,
|
|
60
|
+
shadowElevation = props.shadowElevation?.dp ?: ListItemDefaults.Elevation,
|
|
61
|
+
supportingContent = supportingContent?.let { content ->
|
|
62
|
+
{ StyledSlotContent("supportingcontent", colors.supportingContentColor, content) }
|
|
63
|
+
},
|
|
64
|
+
leadingContent = leadingContent?.let { content ->
|
|
65
|
+
{
|
|
66
|
+
val styledContent: @Composable () -> Unit = {
|
|
67
|
+
StyledSlotContent("leadingcontent", colors.leadingContentColor, content)
|
|
68
|
+
}
|
|
69
|
+
val onLeadingWidthChanged = innerProps.onLeadingWidthChanged
|
|
70
|
+
if (onLeadingWidthChanged != null) {
|
|
71
|
+
Box(
|
|
72
|
+
modifier = Modifier.onSizeChanged { size ->
|
|
73
|
+
onLeadingWidthChanged(with(density) { size.width.toDp() })
|
|
74
|
+
},
|
|
75
|
+
) {
|
|
76
|
+
styledContent()
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
styledContent()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
overlineContent = overlineContent?.let { content ->
|
|
84
|
+
{ StyledSlotContent("overlinecontent", colors.overlineContentColor, content) }
|
|
85
|
+
},
|
|
86
|
+
headlineContent = {
|
|
87
|
+
when {
|
|
88
|
+
headlineContent == null && trailingContent == null -> Unit
|
|
89
|
+
trailingContent == null -> {
|
|
90
|
+
Box(modifier = Modifier.fillMaxWidth()) {
|
|
91
|
+
headlineContent?.let { content ->
|
|
92
|
+
StyledSlotContent("headlinecontent", colors.contentColor, content)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
headlineContent == null -> {
|
|
97
|
+
Box(
|
|
98
|
+
modifier = Modifier.fillMaxWidth(),
|
|
99
|
+
contentAlignment = Alignment.CenterEnd,
|
|
100
|
+
) {
|
|
101
|
+
StyledSlotContent("trailingcontent", colors.trailingContentColor, trailingContent)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else -> {
|
|
105
|
+
DynamicRow(
|
|
106
|
+
first = { StyledSlotContent("headlinecontent", colors.contentColor, headlineContent) },
|
|
107
|
+
second = { StyledSlotContent("trailingcontent", colors.trailingContentColor, trailingContent) },
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
trailingContent = if (props.hasNavigationLink == true) {
|
|
113
|
+
{
|
|
114
|
+
Icon(
|
|
115
|
+
imageVector = Icons.Rounded.ArrowForwardIos,
|
|
116
|
+
contentDescription = null,
|
|
117
|
+
tint = ExtendedTheme.colorScheme.tertiaryLabel,
|
|
118
|
+
modifier = Modifier.size(17.dp),
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
null
|
|
123
|
+
},
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@Composable
|
|
129
|
+
internal fun listItemColors(props: ListItemProps) = ListItemDefaults.colors(
|
|
130
|
+
containerColor = props.colors?.containerColor.composeOrNull ?: ComposeColor.Transparent,
|
|
131
|
+
contentColor = props.colors?.contentColor.composeOrNull ?: ExtendedTheme.colorScheme.label,
|
|
132
|
+
leadingContentColor = props.colors?.leadingContentColor.composeOrNull ?: ExtendedTheme.colorScheme.link,
|
|
133
|
+
trailingContentColor = props.colors?.trailingContentColor.composeOrNull ?: ExtendedTheme.colorScheme.secondaryLabel,
|
|
134
|
+
supportingContentColor = props.colors?.supportingContentColor.composeOrNull ?: ExtendedTheme.colorScheme.secondaryLabel,
|
|
135
|
+
overlineContentColor = props.colors?.overlineContentColor.composeOrNull ?: ExtendedTheme.colorScheme.secondaryLabel,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@Composable
|
|
139
|
+
private fun SlotContentColor(
|
|
140
|
+
contentColor: Color?,
|
|
141
|
+
content: @Composable () -> Unit,
|
|
142
|
+
) {
|
|
143
|
+
if (contentColor != null) {
|
|
144
|
+
Surface(color = Color.Transparent, contentColor = contentColor) {
|
|
145
|
+
content()
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
content()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@Composable
|
|
153
|
+
private fun StyledSlotContent(
|
|
154
|
+
slotName: String,
|
|
155
|
+
contentColor: Color?,
|
|
156
|
+
content: @Composable () -> Unit,
|
|
157
|
+
) {
|
|
158
|
+
SlotContentColor(contentColor) {
|
|
159
|
+
SlotTypography(slotName) {
|
|
160
|
+
content()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
package expo.modules.myui.ListItem
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
5
|
+
import androidx.compose.foundation.layout.wrapContentWidth
|
|
6
|
+
import androidx.compose.runtime.Composable
|
|
7
|
+
import androidx.compose.ui.Alignment
|
|
8
|
+
import androidx.compose.ui.Modifier
|
|
9
|
+
import androidx.compose.ui.layout.SubcomposeLayout
|
|
10
|
+
import androidx.compose.ui.unit.Constraints
|
|
11
|
+
import androidx.compose.ui.unit.Dp
|
|
12
|
+
import kotlin.math.max
|
|
13
|
+
|
|
14
|
+
import expo.modules.myui.theme.tokens.ListTokens
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Headline + trailing en una fila.
|
|
20
|
+
*
|
|
21
|
+
* - Caben con ancho natural: headline al inicio, trailing al final.
|
|
22
|
+
* - No caben: el que no supera la mitad queda en su ancho natural; el otro ocupa el resto.
|
|
23
|
+
* - Si ambos superan la mitad: reparto 50/50.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
@Composable
|
|
27
|
+
internal fun DynamicRow(
|
|
28
|
+
modifier: Modifier = Modifier,
|
|
29
|
+
spacing: Dp = ListTokens.ItemBetweenSpace,
|
|
30
|
+
first: @Composable () -> Unit,
|
|
31
|
+
second: @Composable () -> Unit,
|
|
32
|
+
) {
|
|
33
|
+
SubcomposeLayout(
|
|
34
|
+
modifier = modifier.fillMaxWidth(),
|
|
35
|
+
) { constraints ->
|
|
36
|
+
val spacingPx = spacing.roundToPx()
|
|
37
|
+
val maxWidth = constraints.maxWidth
|
|
38
|
+
|
|
39
|
+
val naturalConstraints = Constraints(
|
|
40
|
+
minWidth = 0,
|
|
41
|
+
maxWidth = maxWidth,
|
|
42
|
+
minHeight = 0,
|
|
43
|
+
maxHeight = constraints.maxHeight,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
val firstNatural = subcompose(Slot.FirstMeasure) {
|
|
47
|
+
Box(Modifier.wrapContentWidth(Alignment.Start)) { first() }
|
|
48
|
+
}.first().measure(naturalConstraints)
|
|
49
|
+
|
|
50
|
+
val secondNatural = subcompose(Slot.SecondMeasure) {
|
|
51
|
+
Box(Modifier.wrapContentWidth(Alignment.End)) { second() }
|
|
52
|
+
}.first().measure(naturalConstraints)
|
|
53
|
+
|
|
54
|
+
val needsSplit = firstNatural.width + spacingPx + secondNatural.width > maxWidth
|
|
55
|
+
|
|
56
|
+
if (needsSplit) {
|
|
57
|
+
val available = max(0, maxWidth - spacingPx)
|
|
58
|
+
val halfWidth = available / 2
|
|
59
|
+
val firstExceedsHalf = firstNatural.width > halfWidth
|
|
60
|
+
val secondExceedsHalf = secondNatural.width > halfWidth
|
|
61
|
+
|
|
62
|
+
val firstWidth: Int
|
|
63
|
+
val secondWidth: Int
|
|
64
|
+
when {
|
|
65
|
+
firstExceedsHalf && !secondExceedsHalf -> {
|
|
66
|
+
secondWidth = secondNatural.width
|
|
67
|
+
firstWidth = available - secondWidth
|
|
68
|
+
}
|
|
69
|
+
secondExceedsHalf && !firstExceedsHalf -> {
|
|
70
|
+
firstWidth = firstNatural.width
|
|
71
|
+
secondWidth = available - firstWidth
|
|
72
|
+
}
|
|
73
|
+
else -> {
|
|
74
|
+
firstWidth = halfWidth
|
|
75
|
+
secondWidth = halfWidth
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
val firstConstraints = Constraints(
|
|
80
|
+
minWidth = firstWidth,
|
|
81
|
+
maxWidth = firstWidth,
|
|
82
|
+
minHeight = 0,
|
|
83
|
+
maxHeight = constraints.maxHeight,
|
|
84
|
+
)
|
|
85
|
+
val secondConstraints = Constraints(
|
|
86
|
+
minWidth = secondWidth,
|
|
87
|
+
maxWidth = secondWidth,
|
|
88
|
+
minHeight = 0,
|
|
89
|
+
maxHeight = constraints.maxHeight,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
val firstSplit = subcompose(Slot.FirstSplit) {
|
|
93
|
+
Box(
|
|
94
|
+
modifier = Modifier.fillMaxWidth(),
|
|
95
|
+
contentAlignment = Alignment.CenterStart,
|
|
96
|
+
) {
|
|
97
|
+
first()
|
|
98
|
+
}
|
|
99
|
+
}.first().measure(firstConstraints)
|
|
100
|
+
|
|
101
|
+
val secondSplit = subcompose(Slot.SecondSplit) {
|
|
102
|
+
Box(
|
|
103
|
+
modifier = Modifier.fillMaxWidth(),
|
|
104
|
+
contentAlignment = Alignment.CenterEnd,
|
|
105
|
+
) {
|
|
106
|
+
second()
|
|
107
|
+
}
|
|
108
|
+
}.first().measure(secondConstraints)
|
|
109
|
+
|
|
110
|
+
val height = max(firstSplit.height, secondSplit.height).coerceAtLeast(constraints.minHeight)
|
|
111
|
+
|
|
112
|
+
layout(maxWidth, height) {
|
|
113
|
+
val firstY = (height - firstSplit.height) / 2
|
|
114
|
+
val secondY = (height - secondSplit.height) / 2
|
|
115
|
+
firstSplit.placeRelative(0, firstY)
|
|
116
|
+
secondSplit.placeRelative(firstWidth + spacingPx, secondY)
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
val height = max(firstNatural.height, secondNatural.height).coerceAtLeast(constraints.minHeight)
|
|
120
|
+
|
|
121
|
+
layout(maxWidth, height) {
|
|
122
|
+
val firstY = (height - firstNatural.height) / 2
|
|
123
|
+
val secondY = (height - secondNatural.height) / 2
|
|
124
|
+
firstNatural.placeRelative(0, firstY)
|
|
125
|
+
secondNatural.placeRelative(maxWidth - secondNatural.width, secondY)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private enum class Slot {
|
|
132
|
+
FirstMeasure,
|
|
133
|
+
SecondMeasure,
|
|
134
|
+
FirstSplit,
|
|
135
|
+
SecondSplit,
|
|
136
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
package expo.modules.myui.menu
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.layout.Box
|
|
4
|
+
import androidx.compose.foundation.layout.widthIn
|
|
5
|
+
import androidx.compose.material3.DropdownMenu
|
|
6
|
+
import androidx.compose.material3.MenuDefaults
|
|
7
|
+
import androidx.compose.runtime.Composable
|
|
8
|
+
import androidx.compose.ui.Modifier
|
|
9
|
+
import androidx.compose.ui.platform.LocalConfiguration
|
|
10
|
+
import androidx.compose.ui.unit.dp
|
|
11
|
+
import expo.modules.kotlin.views.FunctionalComposableScope
|
|
12
|
+
import expo.modules.myui.theme.tokens.ShapeTokens
|
|
13
|
+
import expo.modules.ui.ModifierRegistry
|
|
14
|
+
import expo.modules.ui.UIComposableScope
|
|
15
|
+
import expo.modules.ui.composeOrNull
|
|
16
|
+
import expo.modules.ui.findChildSlotView
|
|
17
|
+
import expo.modules.ui.isSlotView
|
|
18
|
+
|
|
19
|
+
private val HorizontalScreenInset = 16.dp
|
|
20
|
+
|
|
21
|
+
@Composable
|
|
22
|
+
fun FunctionalComposableScope.DropdownMenuContent(
|
|
23
|
+
props: DropdownMenuProps,
|
|
24
|
+
onDismissRequest: () -> Unit
|
|
25
|
+
) {
|
|
26
|
+
val itemsSlotView = findChildSlotView(view, "items")
|
|
27
|
+
val maxMenuWidth = LocalConfiguration.current.screenWidthDp.dp - HorizontalScreenInset * 2
|
|
28
|
+
|
|
29
|
+
Box(modifier = ModifierRegistry.applyModifiers(props.modifiers, appContext, composableScope, globalEventDispatcher)) {
|
|
30
|
+
Children(UIComposableScope(), filter = { !isSlotView(it) })
|
|
31
|
+
|
|
32
|
+
DropdownMenu(
|
|
33
|
+
containerColor = props.color?.composeOrNull ?: MenuDefaults.containerColor,
|
|
34
|
+
expanded = props.expanded,
|
|
35
|
+
onDismissRequest = onDismissRequest,
|
|
36
|
+
shape = ShapeTokens.CornerExtraLarge,
|
|
37
|
+
modifier = Modifier.widthIn(max = maxMenuWidth),
|
|
38
|
+
) {
|
|
39
|
+
itemsSlotView?.let {
|
|
40
|
+
with(UIComposableScope()) {
|
|
41
|
+
with(it) {
|
|
42
|
+
Content()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package expo.modules.myui.menu
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import expo.modules.kotlin.types.Enumerable
|
|
5
|
+
import expo.modules.kotlin.views.ComposeProps
|
|
6
|
+
import expo.modules.ui.ModifierList
|
|
7
|
+
import expo.modules.kotlin.views.OptimizedComposeProps
|
|
8
|
+
|
|
9
|
+
enum class ActivationMethod(val value: String) : Enumerable {
|
|
10
|
+
SINGLE_PRESS("singlePress"),
|
|
11
|
+
LONG_PRESS("longPress")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@OptimizedComposeProps
|
|
15
|
+
data class DropdownMenuProps(
|
|
16
|
+
val activationMethod: ActivationMethod = ActivationMethod.SINGLE_PRESS,
|
|
17
|
+
val expanded: Boolean = false,
|
|
18
|
+
val color: Color? = null,
|
|
19
|
+
val modifiers: ModifierList = emptyList()
|
|
20
|
+
) : ComposeProps
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
package expo.modules.myui
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color as AndroidColor
|
|
4
|
+
import androidx.compose.foundation.layout.heightIn
|
|
5
|
+
import androidx.compose.ui.Modifier
|
|
6
|
+
import androidx.compose.ui.draw.drawBehind
|
|
7
|
+
import androidx.compose.ui.geometry.Offset
|
|
8
|
+
import androidx.compose.ui.graphics.Brush
|
|
9
|
+
import androidx.compose.ui.graphics.Color as ComposeColor
|
|
10
|
+
import androidx.compose.ui.platform.LocalConfiguration
|
|
11
|
+
import androidx.compose.ui.unit.Dp
|
|
12
|
+
import androidx.compose.ui.unit.dp
|
|
13
|
+
import expo.modules.ui.ModifierRegistry
|
|
14
|
+
import expo.modules.ui.columnScope
|
|
15
|
+
import expo.modules.ui.rowScope
|
|
16
|
+
|
|
17
|
+
private fun normalizeColorString(s: String): String {
|
|
18
|
+
val t = s.trim()
|
|
19
|
+
return if (t.startsWith("#")) t else "#$t"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Registra modificadores extra para Jetpack Compose (p. ej. degradados con [Brush]).
|
|
24
|
+
* Debe llamarse al crear el módulo nativo; [ModifierRegistry] es el mismo que usa @expo/ui.
|
|
25
|
+
*/
|
|
26
|
+
fun registerModifiers() {
|
|
27
|
+
|
|
28
|
+
// --------------------------- backgroundLinearGradient---------------------------
|
|
29
|
+
|
|
30
|
+
ModifierRegistry.register("backgroundLinearGradient") { map, _, _, _ ->
|
|
31
|
+
val raw = map["colors"] as? List<*> ?: return@register Modifier
|
|
32
|
+
val composeColors = raw.mapNotNull { item ->
|
|
33
|
+
val hex = (item as? String)?.trim()?.takeIf { it.isNotEmpty() } ?: return@mapNotNull null
|
|
34
|
+
runCatching {
|
|
35
|
+
val argb = AndroidColor.parseColor(normalizeColorString(hex))
|
|
36
|
+
ComposeColor(argb)
|
|
37
|
+
}.getOrNull()
|
|
38
|
+
}
|
|
39
|
+
if (composeColors.size < 2) return@register Modifier
|
|
40
|
+
|
|
41
|
+
val sx = (map["startX"] as? Number)?.toFloat() ?: 0f
|
|
42
|
+
val sy = (map["startY"] as? Number)?.toFloat() ?: 0f
|
|
43
|
+
val ex = (map["endX"] as? Number)?.toFloat() ?: 0f
|
|
44
|
+
val ey = (map["endY"] as? Number)?.toFloat() ?: 1f
|
|
45
|
+
|
|
46
|
+
Modifier.drawBehind {
|
|
47
|
+
val brush = Brush.linearGradient(
|
|
48
|
+
colors = composeColors,
|
|
49
|
+
start = Offset(size.width * sx, size.height * sy),
|
|
50
|
+
end = Offset(size.width * ex, size.height * ey)
|
|
51
|
+
)
|
|
52
|
+
drawRect(brush = brush, size = size)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// --------------------------- heightIn ------------------------------------------
|
|
57
|
+
|
|
58
|
+
ModifierRegistry.register("heightIn") { map, _, _, _ ->
|
|
59
|
+
val minDp = (map["min"] as? Number)?.toFloat()
|
|
60
|
+
val maxDp = (map["max"] as? Number)?.toFloat()
|
|
61
|
+
val minFraction = (map["minFraction"] as? Number)?.toFloat()
|
|
62
|
+
val maxFraction = (map["maxFraction"] as? Number)?.toFloat()
|
|
63
|
+
|
|
64
|
+
val screenHeightDp = LocalConfiguration.current.screenHeightDp.toFloat()
|
|
65
|
+
|
|
66
|
+
val resolvedMin = when {
|
|
67
|
+
minDp != null -> minDp.dp
|
|
68
|
+
minFraction != null -> (screenHeightDp * minFraction).dp
|
|
69
|
+
else -> Dp.Unspecified
|
|
70
|
+
}
|
|
71
|
+
val resolvedMax = when {
|
|
72
|
+
maxFraction != null -> (screenHeightDp * maxFraction).dp
|
|
73
|
+
maxDp != null -> maxDp.dp
|
|
74
|
+
else -> Dp.Unspecified
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Modifier.heightIn(min = resolvedMin, max = resolvedMax)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// --------------------------- flexWeight ----------------------------------------
|
|
81
|
+
|
|
82
|
+
ModifierRegistry.register("flexWeight") { map, scope, _, _ ->
|
|
83
|
+
val weight = (map["weight"] as? Number)?.toFloat() ?: 1f
|
|
84
|
+
val fill = map["fill"] as? Boolean ?: false
|
|
85
|
+
|
|
86
|
+
scope?.rowScope?.run {
|
|
87
|
+
Modifier.weight(weight, fill = fill)
|
|
88
|
+
} ?: scope?.columnScope?.run {
|
|
89
|
+
Modifier.weight(weight, fill = fill)
|
|
90
|
+
} ?: Modifier
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// -------------------------------------------------------------------------------
|
|
94
|
+
}
|