一些检查失败了
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
86 行
2.7 KiB
TypeScript
86 行
2.7 KiB
TypeScript
|
|
import * as React from 'react';
|
|
import { TextStyle, Text, StyleProp } from 'react-native';
|
|
|
|
import { FontAwesome5 } from '@react-native-vector-icons/fontawesome5';
|
|
import { MaterialDesignIcons } from '@react-native-vector-icons/material-design-icons';
|
|
import { Ionicons } from '@react-native-vector-icons/ionicons';
|
|
|
|
type IconNameProp<IconComponent> = IconComponent extends (props: { name: infer NameType })=> unknown ? NameType : never;
|
|
|
|
type FontAwesome5Name = IconNameProp<typeof FontAwesome5>;
|
|
type MaterialIconName = IconNameProp<typeof MaterialDesignIcons>;
|
|
type IoniconsName = IconNameProp<typeof Ionicons>;
|
|
|
|
interface Props {
|
|
name: string;
|
|
style: StyleProp<TextStyle>;
|
|
|
|
// If `null` is given, the content must be labeled elsewhere.
|
|
accessibilityLabel: string|null;
|
|
|
|
allowFontScaling?: boolean;
|
|
}
|
|
|
|
const Icon: React.FC<Props> = props => {
|
|
// Matches:
|
|
// 1. A prefix of word characters (\w+)
|
|
// 2. A suffix of non-spaces (\S+)
|
|
// An "fa-" at the beginning of the suffix is ignored.
|
|
const nameMatch = props.name.match(/^(\w+)\s+(?:fa-)?(\S+)$/);
|
|
|
|
const namePrefix = nameMatch ? nameMatch[1] : '';
|
|
const nameSuffix = nameMatch ? nameMatch[2] : props.name;
|
|
|
|
// If there's no label, make sure that the screen reader doesn't try
|
|
// to read the characters from the icon font (they don't make sense
|
|
// without the icon font applied).
|
|
const accessibilityHidden = props.accessibilityLabel === null;
|
|
const importantForAccessibility = accessibilityHidden ? 'no-hide-descendants' as const : 'yes' as const;
|
|
|
|
const sharedProps = {
|
|
importantForAccessibility, // Android
|
|
accessibilityElementsHidden: accessibilityHidden, // iOS
|
|
'aria-hidden': accessibilityHidden, // Web
|
|
accessibilityLabel: props.accessibilityLabel,
|
|
style: props.style,
|
|
allowFontScaling: props.allowFontScaling,
|
|
};
|
|
|
|
if (namePrefix.match(/^fa[bsr]?$/)) {
|
|
let iconStyle: 'solid'|'brand' = 'solid';
|
|
if (namePrefix.startsWith('fab')) {
|
|
iconStyle = 'brand';
|
|
} else if (namePrefix.startsWith('fas')) {
|
|
iconStyle = 'solid';
|
|
}
|
|
|
|
return (
|
|
<FontAwesome5
|
|
name={nameSuffix as FontAwesome5Name}
|
|
iconStyle={iconStyle}
|
|
{...sharedProps}
|
|
/>
|
|
);
|
|
} else if (namePrefix === 'material') {
|
|
return <MaterialDesignIcons name={nameSuffix as MaterialIconName} {...sharedProps}/>;
|
|
} else if (namePrefix === 'ionicon') {
|
|
return <Ionicons name={nameSuffix as IoniconsName} {...sharedProps}/>;
|
|
} else if (namePrefix === 'text') {
|
|
return (
|
|
<Text
|
|
style={props.style}
|
|
aria-hidden={accessibilityHidden}
|
|
importantForAccessibility={importantForAccessibility}
|
|
accessibilityElementsHidden={accessibilityHidden}
|
|
>
|
|
{nameSuffix}
|
|
</Text>
|
|
);
|
|
} else {
|
|
return <FontAwesome5 name='cog' iconStyle='solid' {...sharedProps}/>;
|
|
}
|
|
};
|
|
|
|
export default Icon;
|