Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions src/lib/src/ui/safe-area-view/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,36 @@ import { ReactElement, useMemo } from 'react';
import { StyleSheet, View, ViewProps } from 'react-native';
import { Edge, useSafeAreaInsets } from 'react-native-safe-area-context';

/**
* Props for {@link AppSafeAreaView}.
*
* @property children Elements rendered inside the padded container.
* @property edges An array indicating which edges of the screen to respect. Possible values are 'top', 'right', 'bottom', 'left'. Defaults to all edges.
* @property style Custom styles to apply to the view. Note that padding values will be adjusted to respect safe area insets.
* @property ...rest All other {@link https://reactnative.dev/docs/view#props | ViewProps} are forwarded.
*/
export interface AppSafeAreaViewProps extends ViewProps {
edges?: Array<Edge>;
}

const defaultEdges: Array<Edge> = ['top', 'right', 'bottom', 'left'];

export function AppSafeAreaView({ children, edges = defaultEdges, style = {}, ...props }: AppSafeAreaViewProps): ReactElement {
/**
* A component for granular control of safe area edges on each screen.
* The difference from `SafeAreaView` in [react-native-safe-area-context](https://www.npmjs.com/package/react-native-safe-area-context) is that the container adds padding to the elements inside it,
* rather than to the entire screen, making it more flexible for use.
*
* > Requires the `react-native-safe-area-context`.
*
* @param props Component props. See {@link AppSafeAreaViewProps} for a detailed list.
* @returns ReactElement
*/
export function AppSafeAreaView({
children,
edges = defaultEdges,
style = {},
...props
}: AppSafeAreaViewProps): ReactElement {
const insets = useSafeAreaInsets();

const containerStyle = useMemo(() => {
Expand All @@ -21,9 +44,13 @@ export function AppSafeAreaView({ children, edges = defaultEdges, style = {}, ..

return [...acc, { [paddingName]: Number(paddings[paddingName] ?? 0) + insets[edge] }];
},
[style]
[style],
);
}, [style, insets, edges]);

return <View style={containerStyle} {...props}>{children}</View>;
return (
<View style={containerStyle} {...props}>
{children}
</View>
);
}
6 changes: 6 additions & 0 deletions src/lib/src/utils/i18n/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { I18n } from 'i18n-js';

/**
* Global {@link I18n} instance.
*
* Import this singleton anywhere you need direct access to `i18n.t()`
* or other i18n‑js APIs.
*/
export const i18n = new I18n();
15 changes: 14 additions & 1 deletion src/lib/src/utils/i18n/set-language.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import * as Localization from 'expo-localization';
import { i18n } from './i18n';

/**
* Register translation tables **once** and receive a helper to change the active language.
*
* > Requires `i18n-js` and `expo-localization`.
*
* @typeParam T Map of language codes (`en`, `fr`, `ru`, …) to their translation dictionaries.
*
* @param translations Object containing translation tables keyed by language code.
* @param defaultLanguage Language that will be used when the requested language is missing.
*
* @returns Function that sets `i18n.locale`.
* When called **without** arguments, the device locale from `expo-localization` is used.
*/
export function setLanguage<T extends (typeof i18n)['translations']>(
translations: T,
defaultLanguage: keyof typeof translations
defaultLanguage: keyof typeof translations,
): (language?: keyof typeof translations) => void {
i18n.translations = translations;

Expand Down
8 changes: 8 additions & 0 deletions src/lib/src/utils/i18n/use-translation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { TranslateOptions } from 'i18n-js';
import { i18n } from './i18n';

/**
* Returns a function bound to a **base namespace** so you can translate keys without repetition.
*
* > Requires `i18n-js`.
*
* @param basePath Translation namespace, e.g. `'ACCOUNT.WELCOME'`.
* @returns Translator function `(key, options?) => string`.
*/
export function useTranslation(basePath: string) {
return (key: string, options?: TranslateOptions): string => {
return i18n.t(`${basePath}.${key}`, options);
Expand Down