文件
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

124 行
2.6 KiB
TypeScript

import * as React from 'react';
import { useMemo, useCallback, useRef } from 'react';
import { TouchableOpacity, StyleSheet, Text, Linking, View } from 'react-native';
import { themeStyle } from '../global-style';
import NavService from '@joplin/lib/services/NavService';
interface UrlTarget {
url: string;
screen?: undefined;
}
interface ScreenTarget {
screen: string;
screenProps?: Record<string, unknown>;
url?: undefined;
}
interface CallbackTarget {
onPress: ()=> void;
url?: undefined;
screen?: undefined;
}
export type WarningBoxTarget = UrlTarget|ScreenTarget|CallbackTarget;
export interface WarningBoxAction {
title: string;
onPress: ()=> void;
}
interface Props {
themeId: number;
target: WarningBoxTarget;
message: string;
testID?: string;
actions?: WarningBoxAction[];
}
const useStyles = (themeId: number) => {
return useMemo(() => {
const theme = themeStyle(themeId);
return StyleSheet.create({
container: {
backgroundColor: '#ff9900',
flexDirection: 'row',
padding: theme.marginLeft,
},
text: {
flex: 1,
color: 'black',
},
actionText: {
color: 'black',
fontWeight: 'bold',
textDecorationLine: 'underline',
marginLeft: theme.marginLeft,
},
});
}, [themeId]);
};
const WarningBox: React.FC<Props> = props => {
const styles = useStyles(props.themeId);
const propsRef = useRef(props);
propsRef.current = props;
const onPress = useCallback(() => {
const target = propsRef.current.target;
if (!target) return;
const isUrlTarget = (target: WarningBoxTarget): target is UrlTarget => !!target.url;
if (isUrlTarget(target)) {
void Linking.openURL(target.url);
} else if ('onPress' in target) {
target.onPress();
} else {
void NavService.go(target.screen, target.screenProps);
}
}, []);
const hasTarget = !!propsRef.current.target;
const bannerContent = <Text style={styles.text}>{props.message}</Text>;
if (props.actions) {
return (
<View style={styles.container} testID={props.testID}>
{bannerContent}
{props.actions.map(action => (
<TouchableOpacity key={action.title} onPress={action.onPress} accessibilityRole='button'>
<Text style={styles.actionText}>{action.title}</Text>
</TouchableOpacity>
))}
</View>
);
}
if (hasTarget) {
return (
<TouchableOpacity
style={styles.container}
onPress={onPress}
activeOpacity={0.8}
accessibilityRole={'button'}
testID={props.testID}
>
{bannerContent}
</TouchableOpacity>
);
} else {
return (
<View
style={styles.container}
testID={props.testID}
>
{bannerContent}
</View>
);
}
};
export default WarningBox;