Skip to content

Commit

Permalink
Merge branch 'next' into iconButton
Browse files Browse the repository at this point in the history
  • Loading branch information
huhuanming authored Oct 16, 2023
2 parents 8b56335 + d600ffd commit da5849c
Show file tree
Hide file tree
Showing 64 changed files with 1,747 additions and 452 deletions.
5 changes: 0 additions & 5 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@
"@react-native-firebase/perf": "^14",
"@react-native-google-signin/google-signin": "^9.1.0",
"@react-native-segmented-control/segmented-control": "^2.4.1",
"@react-navigation/bottom-tabs": "^6.5.8",
"@react-navigation/drawer": "^6.6.3",
"@react-navigation/native": "6.1.7",
"@react-navigation/native-stack": "^6.9.13",
"@react-navigation/stack": "^6.3.17",
"@tamagui/animations-moti": "1.74.13",
"@tamagui/babel-plugin": "1.74.13",
"@tamagui/config": "1.74.13",
Expand Down
6 changes: 3 additions & 3 deletions packages/components/src/DelayedFreeze/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useState } from 'react';
import { Freeze } from 'react-freeze';

interface FreezeWrapperProps {
freeze: boolean;
freeze: boolean | undefined;
children: ReactNode;
placeholder?: ReactNode;
}
Expand All @@ -18,15 +18,15 @@ function DelayedFreeze({
freeze,
children,
placeholder = null,
}: FreezeWrapperProps) {
}: FreezeWrapperProps): JSX.Element {
// flag used for determining whether freeze should be enabled
const [freezeState, setFreezeState] = useState(false);

if (freeze !== freezeState) {
// setImmediate is executed at the end of the JS execution block.
// Used here for changing the state right after the render.
setImmediate(() => {
setFreezeState(freeze);
setFreezeState(!!freeze);
});
}

Expand Down
133 changes: 133 additions & 0 deletions packages/components/src/ModalContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { Button } from '../Button';
import { Checkbox } from '../Checkbox';
import { Stack, XStack } from '../Stack';

import type { GetProps } from 'tamagui';

type ModalButtonGroupProps = {
onConfirm?: () => void | Promise<boolean>;
onCancel?: () => void;
confirmButtonProps?: GetProps<typeof Button>;
cancelButtonProps?: GetProps<typeof Button>;
confirmButtonTextProps?: GetProps<typeof Button.Text>;
cancelButtonTextProps?: GetProps<typeof Button.Text>;
};

function ModalButtonGroup({
onCancel,
onConfirm,
confirmButtonProps,
cancelButtonProps,
confirmButtonTextProps,
cancelButtonTextProps,
}: ModalButtonGroupProps) {
return (
<XStack
$sm={{
width: '100%',
justifyContent: 'center',
gap: '$5',
}}
$gtSm={{
justifyContent: 'flex-end',
gap: '$2',
}}
>
{(!!cancelButtonProps || !!onCancel) && (
<Button
buttonVariant="secondary"
$sm={{
flex: 1,
size: 'large',
}}
$gtSm={{
size: 'medium',
}}
onPress={onCancel}
{...cancelButtonProps}
>
<Button.Text paddingHorizontal="$3" {...cancelButtonTextProps}>
Cancel
</Button.Text>
</Button>
)}
{(!!confirmButtonProps || !!onConfirm) && (
<Button
buttonVariant="primary"
$sm={{
flex: 1,
size: 'large',
}}
$gtSm={{
size: 'medium',
}}
onPress={onConfirm}
{...confirmButtonProps}
>
<Button.Text paddingHorizontal="$3" {...confirmButtonTextProps}>
Confirm
</Button.Text>
</Button>
)}
</XStack>
);
}

type ModalContainerProps = {
children: React.ReactNode;
checkboxProps?: GetProps<typeof Checkbox>;
} & ModalButtonGroupProps;

export function ModalContainer({
children,
checkboxProps,
onCancel,
onConfirm,
confirmButtonProps,
cancelButtonProps,
confirmButtonTextProps,
cancelButtonTextProps,
}: ModalContainerProps) {
return (
<Stack flex={1}>
<Stack flex={1}>{children}</Stack>

<Stack
bg="$bg"
padding="$5"
$sm={{
flexDirection: 'column',
alignItems: 'center',
}}
$gtSm={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
{!!checkboxProps && (
<Stack
$sm={{
width: '100%',
alignItems: 'flex-start',
mb: '$2.5',
}}
$gtSm={{
justifyContent: 'center',
}}
>
<Checkbox {...checkboxProps} />
</Stack>
)}
<ModalButtonGroup
onCancel={onCancel}
onConfirm={onConfirm}
confirmButtonProps={confirmButtonProps}
cancelButtonProps={cancelButtonProps}
confirmButtonTextProps={confirmButtonTextProps}
cancelButtonTextProps={cancelButtonTextProps}
/>
</Stack>
</Stack>
);
}
93 changes: 93 additions & 0 deletions packages/components/src/Navigation/Header/HeaderSearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { useCallback } from 'react';

import { useMedia } from 'tamagui';

import { SearchBar } from '../../SearchBar';

import type {
NativeSyntheticEvent,
TargetedEvent,
TextInputFocusEventData,
TextInputSubmitEditingEventData,
} from 'react-native';

type HeaderSearchBarProps = {
height?: string;
/**
* A callback that gets called when search bar has lost focus
*/
onBlur?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
/**
* A callback that gets called when the text changes. It receives the current text value of the search bar.
*/
onChangeText?: (e: NativeSyntheticEvent<TextInputFocusEventData>) => void;
/**
* A callback that gets called when search bar has received focus
*/
onFocus?: (e: NativeSyntheticEvent<TargetedEvent>) => void;
/**
* A callback that gets called when the search button is pressed. It receives the current text value of the search bar.
*/
onSearchButtonPress?: (
e: NativeSyntheticEvent<TextInputFocusEventData>,
) => void;
/**
* Text displayed when search field is empty
*/
placeholder?: string;
};

function HeaderSearchBar({
onBlur,
onFocus,
onChangeText,
onSearchButtonPress,
placeholder,
}: HeaderSearchBarProps) {
const media = useMedia();

const handleChangeCallback = useCallback(
(value: string) => {
onChangeText?.({
nativeEvent: {
text: value,
},
} as NativeSyntheticEvent<TextInputFocusEventData>);
},
[onChangeText],
);

const onBlurCallback = useCallback(
(e: NativeSyntheticEvent<TextInputFocusEventData>) => {
onBlur?.(e);
},
[onBlur],
);

const onFocusCallback = useCallback(
(e: NativeSyntheticEvent<TextInputFocusEventData>) => {
onFocus?.(e); // Stub event object
},
[onFocus],
);

const onSubmitEditingCallback = useCallback(
(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
onSearchButtonPress?.(e as NativeSyntheticEvent<TextInputFocusEventData>);
},
[onSearchButtonPress],
);

return (
<SearchBar
height={media.gtMd ? '$8' : '$9'}
onBlur={onBlurCallback}
onFocus={onFocusCallback}
onChange={handleChangeCallback}
onSubmitEditing={onSubmitEditingCallback}
placeholder={placeholder}
/>
);
}

export default HeaderSearchBar;
18 changes: 7 additions & 11 deletions packages/components/src/Navigation/Header/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import * as React from 'react';
import { Header } from '@react-navigation/elements';
import { get } from 'lodash';
import { StyleSheet } from 'react-native';
import { Input } from 'tamagui';

import { Stack, useThemeValue } from '../../index';

import HeaderButtonBack from './HeaderButtonBack';
import HeaderSearchBar from './HeaderSearchBar';

import type { StackHeaderProps } from '../ScreenProps';
import type { OneKeyStackHeaderProps } from './HeaderScreenOptions';
Expand Down Expand Up @@ -145,19 +145,15 @@ function HeaderView({
py: isModelScreen ? '$0' : '$3.5',
pb: isModelScreen ? '$4' : '$0',
width: isModelScreen ? '100%' : '$60',
alignItems: isModelScreen ? 'flex-start' : 'center',
}}
>
{/* Demo SearchBar */}
<Input
$md={{
height: '$9',
}}
$gtMd={{
height: '$8',
}}
borderWidth={1}
<HeaderSearchBar
placeholder={headerSearchBarOptions?.placeholder}
onChange={headerSearchBarOptions?.onChangeText}
onChangeText={headerSearchBarOptions?.onChangeText}
onBlur={headerSearchBarOptions?.onBlur}
onFocus={headerSearchBarOptions?.onFocus}
onSearchButtonPress={headerSearchBarOptions?.onSearchButtonPress}
/>
</Stack>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
StackRouter,
createNavigatorFactory,
useNavigationBuilder,
} from '@react-navigation/native';
} from '@react-navigation/core';

import ModalStack from './ModalStack';

Expand Down
1 change: 1 addition & 0 deletions packages/components/src/Navigation/Modal/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type Scene = {
export type ModalNavigationConfig = NonNullable<unknown>;

export type ModalNavigationOptions = StackNavigationOptions & {
allowDisableClose?: boolean;
disableClose?: boolean;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { memo, useCallback } from 'react';

import { useIntl } from 'react-intl';

import { useThemeValue } from '../../Provider/hooks/useThemeValue';
import { makeModalStackNavigatorOptions } from '../GlobalScreenOptions';
import createModalNavigator from '../Modal/createModalNavigator';
import { createStackNavigator } from '../StackNavigator';

import { hasStackNavigatorModal } from './CommonConfig.ts';

import type { LocaleIds } from '../../locale';
import type { ModalNavigationOptions } from '../ScreenProps';
import type { CommonNavigatorConfig } from './types';
import type { ParamListBase } from '@react-navigation/routers';
Expand All @@ -15,7 +18,8 @@ export interface ModalFlowNavigatorConfig<
RouteName extends string,
P extends ParamListBase,
> extends CommonNavigatorConfig<RouteName, P> {
translationId: string;
translationId: LocaleIds;
allowDisableClose?: boolean;
disableClose?: boolean;
}

Expand All @@ -34,6 +38,7 @@ function ModalFlowNavigator<RouteName extends string, P extends ParamListBase>({
config,
}: ModalFlowNavigatorProps<RouteName, P>) {
const [bgColor, titleColor] = useThemeValue(['bg', 'text']);
const intl = useIntl();

const makeScreenOptions = useCallback(
(navInfo) => ({
Expand All @@ -50,13 +55,21 @@ function ModalFlowNavigator<RouteName extends string, P extends ParamListBase>({
// @ts-expect-error
<ModalStack.Navigator screenOptions={makeScreenOptions}>
{config.map(
({ name, component, options, translationId, disableClose }) => {
({
name,
component,
options,
translationId,
allowDisableClose,
disableClose,
}) => {
const customOptions: ModalNavigationOptions = {
...options,
allowDisableClose,
disableClose,
// Fixes: iOS config static configuration disableClose software can not unlock the problem
presentation: disableClose ? 'modal' : undefined,
title: translationId,
title: intl.formatMessage({
id: translationId,
}),
};

return (
Expand Down
Loading

0 comments on commit da5849c

Please sign in to comment.