Files
hipmi-mobile/components/_ShareComponent/OS_Wrapper.tsx
bagasbanuna 502cd7bc65 feat: Implement OS_Wrapper system and migrate all Job screens
Create OS-specific wrapper system:
- Add IOSWrapper (based on NewWrapper for iOS)
- Add AndroidWrapper (based on NewWrapper_V2 with keyboard handling)
- Add OS_Wrapper (auto platform detection)
- Add PageWrapper (with keyboard handling for Android forms)

Migrate all Job screens (8 files):
- ScreenJobCreate: NewWrapper_V2 → PageWrapper
- ScreenJobEdit: NewWrapper_V2 → PageWrapper
- ScreenBeranda2: NewWrapper_V2 → OS_Wrapper
- ScreenArchive2: NewWrapper_V2 → OS_Wrapper
- MainViewStatus2: NewWrapper_V2 → OS_Wrapper
- ScreenBeranda: ViewWrapper → OS_Wrapper
- ScreenArchive: ViewWrapper → OS_Wrapper
- MainViewStatus: ViewWrapper → OS_Wrapper

Benefits:
- Automatic platform detection (no manual Platform.OS checks)
- Consistent tabs behavior across iOS and Android
- Keyboard handling for forms (Android only)
- Cleaner code with unified API

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-07 14:14:00 +08:00

162 lines
4.4 KiB
TypeScript

// @/components/OS_Wrapper.tsx
// OS-Specific Wrapper - Automatically routes to iOSWrapper or AndroidWrapper
// iOS: Uses NewWrapper (stable for iOS)
// Android: Uses NewWrapper_V2 (with keyboard handling)
import { Platform } from "react-native";
import type { ScrollViewProps, FlatListProps } from "react-native";
import {
NativeSafeAreaViewProps,
} from "react-native-safe-area-context";
import type { StyleProp, ViewStyle } from "react-native";
import IOSWrapper from "./IOSWrapper";
import AndroidWrapper from "./AndroidWrapper";
// ========== Base Props ==========
interface BaseProps {
withBackground?: boolean;
headerComponent?: React.ReactNode;
footerComponent?: React.ReactNode;
floatingButton?: React.ReactNode;
hideFooter?: boolean;
edgesFooter?: NativeSafeAreaViewProps["edges"];
style?: StyleProp<ViewStyle>;
refreshControl?: ScrollViewProps["refreshControl"];
}
// ========== Static Mode Props ==========
interface StaticModeProps extends BaseProps {
children: React.ReactNode;
listData?: never;
renderItem?: never;
}
// ========== List Mode Props ==========
interface ListModeProps extends BaseProps {
children?: never;
listData?: any[];
renderItem?: FlatListProps<any>["renderItem"];
onEndReached?: () => void;
ListHeaderComponent?: React.ReactElement | null;
ListFooterComponent?: React.ReactElement | null;
ListEmptyComponent?: React.ReactElement | null;
keyExtractor?: FlatListProps<any>["keyExtractor"];
}
// ========== PageWrapper Props (Android-specific keyboard handling) ==========
interface PageWrapperBaseProps extends BaseProps {
/**
* Enable keyboard handling (Android only - NewWrapper_V2)
* iOS ignores this prop
* @default false
*/
enableKeyboardHandling?: boolean;
/**
* Scroll offset when keyboard appears (Android only)
* iOS ignores this prop
* @default 100
*/
keyboardScrollOffset?: number;
/**
* Extra padding bottom for content (Android only)
* iOS ignores this prop
* @default 80
*/
contentPaddingBottom?: number;
/**
* Padding untuk content container (Android only)
* iOS ignores this prop
* @default 16
*/
contentPadding?: number;
}
interface PageWrapperStaticProps extends PageWrapperBaseProps {
children: React.ReactNode;
listData?: never;
renderItem?: never;
}
interface PageWrapperListProps extends PageWrapperBaseProps {
children?: never;
listData?: any[];
renderItem?: FlatListProps<any>["renderItem"];
onEndReached?: () => void;
ListHeaderComponent?: React.ReactElement | null;
ListFooterComponent?: React.ReactElement | null;
ListEmptyComponent?: React.ReactElement | null;
keyExtractor?: FlatListProps<any>["keyExtractor"];
}
type OS_WrapperProps = StaticModeProps | ListModeProps;
type PageWrapperProps = PageWrapperStaticProps | PageWrapperListProps;
/**
* OS_Wrapper - Automatically selects iOSWrapper or AndroidWrapper based on platform
*
* @example Static Mode
* ```tsx
* <OS_Wrapper>
* <YourContent />
* </OS_Wrapper>
* ```
*
* @example List Mode
* ```tsx
* <OS_Wrapper
* listData={data}
* renderItem={({ item }) => <ItemCard item={item} />}
* ListEmptyComponent={<EmptyState />}
* />
* ```
*/
export function OS_Wrapper(props: OS_WrapperProps) {
// iOS uses IOSWrapper (based on NewWrapper)
if (Platform.OS === "ios") {
return <IOSWrapper {...props} />;
}
// Android uses AndroidWrapper (based on NewWrapper_V2 with keyboard handling)
return <AndroidWrapper {...props} />;
}
/**
* PageWrapper - OS_Wrapper with keyboard handling support (Android only)
* Use this for forms with input fields
*
* @example
* ```tsx
* <PageWrapper enableKeyboardHandling keyboardScrollOffset={150}>
* <FormContent />
* </PageWrapper>
* ```
*/
export function PageWrapper(props: PageWrapperProps) {
// iOS: Keyboard handling props are ignored
if (Platform.OS === "ios") {
const {
enableKeyboardHandling: _,
keyboardScrollOffset: __1,
contentPaddingBottom: __2,
contentPadding: __3,
...iosProps
} = props;
return <IOSWrapper {...iosProps} />;
}
// Android: Keyboard handling props are used
return <AndroidWrapper {...props} />;
}
// Re-export individual wrappers for direct usage if needed
export { default as IOSWrapper } from "./IOSWrapper";
export { default as AndroidWrapper } from "./AndroidWrapper";
// Legacy export untuk backward compatibility
export { IOSWrapper as iOSWrapper };
export default OS_Wrapper;