pytech-ui 1.0.31 → 1.0.32

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.
@@ -35,6 +35,7 @@ dependencies {
35
35
  implementation 'androidx.compose.foundation:foundation-android:1.10.6'
36
36
  implementation 'androidx.compose.ui:ui-android:1.10.6'
37
37
  implementation 'androidx.compose.material3:material3-android:1.5.0-alpha17'
38
+ implementation 'androidx.navigation:navigation-compose:2.10.2'
38
39
  if (findProject(':expo-ui') != null) {
39
40
  implementation project(':expo-ui')
40
41
  } else {
@@ -0,0 +1,80 @@
1
+ package expo.modules.pytechui.navigation
2
+
3
+ import androidx.compose.foundation.layout.fillMaxSize
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.runtime.CompositionLocalProvider
6
+ import androidx.compose.runtime.DisposableEffect
7
+ import androidx.compose.runtime.staticCompositionLocalOf
8
+ import androidx.compose.ui.Modifier
9
+ import androidx.navigation.NavHostController
10
+ import androidx.navigation.compose.NavHost
11
+ import androidx.navigation.compose.composable
12
+ import androidx.navigation.compose.rememberNavController
13
+ import expo.modules.kotlin.views.ComposeProps
14
+ import expo.modules.kotlin.views.FunctionalComposableScope
15
+ import expo.modules.pytechui.findChildBySlotName
16
+ import expo.modules.ui.SlotView
17
+
18
+ object PytechRoutes {
19
+ const val SCREEN_A = "screen_A"
20
+ const val SCREEN_B = "screen_B"
21
+ }
22
+
23
+ /**
24
+ * Referencia global al NavController del wrapper activo.
25
+ * Se setea al montar `NavigationWrapperView` y se limpia al desmontarlo.
26
+ * Debe usarse sólo desde el hilo principal.
27
+ */
28
+ object PytechNavigation {
29
+ var navController: NavHostController? = null
30
+ internal set
31
+
32
+ fun navigate(route: String) {
33
+ navController?.navigate(route)
34
+ }
35
+
36
+ fun goBack(): Boolean = navController?.popBackStack() ?: false
37
+ }
38
+
39
+ /** Disponible para cualquier composable renderizado dentro del wrapper. */
40
+ val LocalPytechNavController = staticCompositionLocalOf<NavHostController?> { null }
41
+
42
+ data class NavigationWrapperProps(
43
+ val startDestination: String = PytechRoutes.SCREEN_A,
44
+ ) : ComposeProps
45
+
46
+ @Composable
47
+ internal fun FunctionalComposableScope.NavigationWrapperViewContent(props: NavigationWrapperProps) {
48
+ val navController = rememberNavController()
49
+
50
+ DisposableEffect(navController) {
51
+ PytechNavigation.navController = navController
52
+ onDispose {
53
+ if (PytechNavigation.navController === navController) {
54
+ PytechNavigation.navController = null
55
+ }
56
+ }
57
+ }
58
+
59
+ val screenA = findChildBySlotName(PytechRoutes.SCREEN_A)
60
+ val screenB = findChildBySlotName(PytechRoutes.SCREEN_B)
61
+
62
+ CompositionLocalProvider(LocalPytechNavController provides navController) {
63
+ NavHost(
64
+ navController = navController,
65
+ startDestination = props.startDestination,
66
+ modifier = Modifier.fillMaxSize(),
67
+ ) {
68
+ composable(PytechRoutes.SCREEN_A) { RenderScreen(screenA) }
69
+ composable(PytechRoutes.SCREEN_B) { RenderScreen(screenB) }
70
+ }
71
+ }
72
+ }
73
+
74
+ @Composable
75
+ private fun FunctionalComposableScope.RenderScreen(slot: SlotView?) {
76
+ slot ?: return
77
+ with(composableScope) {
78
+ with(slot) { Content() }
79
+ }
80
+ }
@@ -26,6 +26,10 @@ import expo.modules.pytechui.menu.DropdownMenuContent
26
26
  import expo.modules.pytechui.menu.DropdownMenuProps
27
27
  import expo.modules.pytechui.gradient.GradientProps
28
28
  import expo.modules.pytechui.gradient.GradientViewContent
29
+ import expo.modules.pytechui.navigation.NavigationWrapperProps
30
+ import expo.modules.pytechui.navigation.NavigationWrapperViewContent
31
+ import expo.modules.pytechui.navigation.PytechNavigation
32
+ import expo.modules.kotlin.functions.Queues
29
33
  import java.io.Serializable
30
34
  import expo.modules.kotlin.records.Field
31
35
  import expo.modules.kotlin.records.Record
@@ -59,6 +63,20 @@ class PytechUiModule : Module() {
59
63
  TypographySlotBridge.slotTextStylePayload(slotName)
60
64
  }
61
65
 
66
+ AsyncFunction("navigate") { route: String ->
67
+ PytechNavigation.navigate(route)
68
+ }.runOnQueue(Queues.MAIN)
69
+
70
+ AsyncFunction("goBack") {
71
+ PytechNavigation.goBack()
72
+ }.runOnQueue(Queues.MAIN)
73
+
74
+ ExpoUIView<NavigationWrapperProps>("NavigationWrapperView") {
75
+ Content { props ->
76
+ NavigationWrapperViewContent(props)
77
+ }
78
+ }
79
+
62
80
  ExpoUIView<IconProps>("IconView") {
63
81
  Content { props ->
64
82
  IconViewContent(props)
@@ -1,3 +1,4 @@
1
- import { HostProps } from '@expo/ui/jetpack-compose';
2
- export declare const Host: ({ style, ...props }: HostProps) => import("react").JSX.Element;
3
- export { HostProps };
1
+ import { HostProps as ExpoHostProps } from '@expo/ui/jetpack-compose';
2
+ import { NavigationWrapperProps } from './NavigationWrapper';
3
+ export type HostProps = ExpoHostProps & Partial<NavigationWrapperProps>;
4
+ export declare const Host: ({ style, screenA, screenB, startDestination, ...props }: HostProps) => import("react").JSX.Element;
@@ -3,10 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Host = void 0;
4
4
  const expo_1 = require("expo");
5
5
  const jetpack_compose_1 = require("@expo/ui/jetpack-compose");
6
+ const NavigationWrapper_1 = require("./NavigationWrapper");
6
7
  const ExtendedTheme = (0, expo_1.requireNativeView)('PytechUi', 'ExtendedTheme');
7
- const Host = ({ style, ...props }) => {
8
+ const Host = ({ style, screenA, screenB, startDestination, ...props }) => {
9
+ const hasNavigation = screenA != null && screenB != null;
8
10
  return (<jetpack_compose_1.Host style={{ flex: 1, ...style }} {...props}>
9
- <ExtendedTheme>{props.children}</ExtendedTheme>
11
+ <ExtendedTheme>
12
+ {hasNavigation ? (<NavigationWrapper_1.NavigationWrapper screenA={screenA} screenB={screenB} startDestination={startDestination}/>) : (props.children)}
13
+ </ExtendedTheme>
10
14
  </jetpack_compose_1.Host>);
11
15
  };
12
16
  exports.Host = Host;
@@ -0,0 +1,7 @@
1
+ import { ButtonProps } from '@expo/ui/jetpack-compose';
2
+ import { NavigationRoute } from './NavigationWrapper';
3
+ export type NavigationButtonProps = Omit<ButtonProps, 'onClick'> & {
4
+ route: NavigationRoute;
5
+ onClick?: (route: NavigationRoute) => void;
6
+ };
7
+ export declare const NavigationButton: ({ route, onClick, children, ...props }: NavigationButtonProps) => import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NavigationButton = void 0;
4
+ const jetpack_compose_1 = require("@expo/ui/jetpack-compose");
5
+ const NavigationWrapper_1 = require("./NavigationWrapper");
6
+ const TextSlot_1 = require("./TextSlot");
7
+ const NavigationButton = ({ route, onClick, children, ...props }) => {
8
+ const handleClick = () => {
9
+ onClick?.(route);
10
+ (0, NavigationWrapper_1.navigate)(route);
11
+ };
12
+ return (<jetpack_compose_1.Button {...props} onClick={handleClick}>
13
+ {typeof children === 'string' ? <TextSlot_1.Text>{children}</TextSlot_1.Text> : children}
14
+ </jetpack_compose_1.Button>);
15
+ };
16
+ exports.NavigationButton = NavigationButton;
@@ -0,0 +1,10 @@
1
+ import { ReactNode } from 'react';
2
+ export type NavigationRoute = 'screen_A' | 'screen_B';
3
+ export type NavigationWrapperProps = {
4
+ screenA: ReactNode;
5
+ screenB: ReactNode;
6
+ startDestination?: NavigationRoute;
7
+ };
8
+ export declare const navigate: (route: NavigationRoute) => Promise<void>;
9
+ export declare const goBack: () => Promise<boolean>;
10
+ export declare const NavigationWrapper: ({ screenA, screenB, startDestination }: NavigationWrapperProps) => import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NavigationWrapper = exports.goBack = exports.navigate = void 0;
4
+ const expo_1 = require("expo");
5
+ const SlotNativeView = (0, expo_1.requireNativeView)('ExpoUI', 'SlotView');
6
+ const NavigationWrapperNativeView = (0, expo_1.requireNativeView)('PytechUi', 'NavigationWrapperView');
7
+ const Native = (0, expo_1.requireNativeModule)('PytechUi');
8
+ const navigate = (route) => Native.navigate(route);
9
+ exports.navigate = navigate;
10
+ const goBack = () => Native.goBack();
11
+ exports.goBack = goBack;
12
+ const NavigationWrapper = ({ screenA, screenB, startDestination }) => (<NavigationWrapperNativeView startDestination={startDestination}>
13
+ <SlotNativeView slotName="screen_A">{screenA}</SlotNativeView>
14
+ <SlotNativeView slotName="screen_B">{screenB}</SlotNativeView>
15
+ </NavigationWrapperNativeView>);
16
+ exports.NavigationWrapper = NavigationWrapper;
@@ -10,6 +10,8 @@ export * from './components/IconSection';
10
10
  export * from './components/List';
11
11
  export * from './components/ListItem/index';
12
12
  export * from './components/Menu';
13
+ export * from './components/NavigationWrapper';
14
+ export * from './components/NavigationButton';
13
15
  export * from './components/PagePicker';
14
16
  export * from './components/PullToRefreshBox';
15
17
  export * from './components/Section';
@@ -26,6 +26,8 @@ __exportStar(require("./components/IconSection"), exports);
26
26
  __exportStar(require("./components/List"), exports);
27
27
  __exportStar(require("./components/ListItem/index"), exports);
28
28
  __exportStar(require("./components/Menu"), exports);
29
+ __exportStar(require("./components/NavigationWrapper"), exports);
30
+ __exportStar(require("./components/NavigationButton"), exports);
29
31
  __exportStar(require("./components/PagePicker"), exports);
30
32
  __exportStar(require("./components/PullToRefreshBox"), exports);
31
33
  __exportStar(require("./components/Section"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pytech-ui",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "Librería de componentes de UI para Pytech",
5
5
  "keywords": [
6
6
  "react-native",