@rnzeus/atlas 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/README.md +21 -0
- package/dist/config/internal.d.ts +1 -0
- package/dist/config/internal.js +1 -0
- package/dist/config/navigation/index.d.ts +1 -0
- package/dist/config/navigation/index.js +1 -0
- package/dist/config/navigation/types.d.ts +55 -0
- package/dist/config/navigation/types.js +1 -0
- package/dist/config/navigation.types.d.ts +25 -0
- package/dist/config/navigation.types.js +1 -0
- package/dist/hooks/README.md +11 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/internal.d.ts +1 -0
- package/dist/hooks/internal.js +1 -0
- package/dist/hooks/use-path-navigation/README.md +66 -0
- package/dist/hooks/use-path-navigation/hook.d.ts +119 -0
- package/dist/hooks/use-path-navigation/hook.js +52 -0
- package/dist/hooks/use-path-navigation/index.d.ts +1 -0
- package/dist/hooks/use-path-navigation/index.js +1 -0
- package/dist/services/README.md +17 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +3 -0
- package/dist/services/internal.d.ts +1 -0
- package/dist/services/internal.js +1 -0
- package/dist/services/navigation/README.md +131 -0
- package/dist/services/navigation/api.d.ts +5 -0
- package/dist/services/navigation/api.js +11 -0
- package/dist/services/navigation/chain-builder.d.ts +16 -0
- package/dist/services/navigation/chain-builder.js +31 -0
- package/dist/services/navigation/index.d.ts +3 -0
- package/dist/services/navigation/index.js +3 -0
- package/dist/services/navigation/service.d.ts +55 -0
- package/dist/services/navigation/service.js +536 -0
- package/dist/services/navigation/types.d.ts +13 -0
- package/dist/services/navigation/types.js +1 -0
- package/dist/services/navigation/zod-adapter.d.ts +22 -0
- package/dist/services/navigation/zod-adapter.js +36 -0
- package/dist/services/transport/README.md +79 -0
- package/dist/services/transport/build-query.d.ts +2 -0
- package/dist/services/transport/build-query.js +3 -0
- package/dist/services/transport/create-transport-methods.d.ts +8 -0
- package/dist/services/transport/create-transport-methods.js +34 -0
- package/dist/services/transport/error-exception.d.ts +8 -0
- package/dist/services/transport/error-exception.js +16 -0
- package/dist/services/transport/index.d.ts +3 -0
- package/dist/services/transport/index.js +2 -0
- package/dist/services/transport/read-response-body.d.ts +3 -0
- package/dist/services/transport/read-response-body.js +27 -0
- package/dist/services/transport/service.d.ts +22 -0
- package/dist/services/transport/service.js +102 -0
- package/dist/services/transport/types.d.ts +4 -0
- package/dist/services/transport/types.js +1 -0
- package/dist/ui/README.md +17 -0
- package/dist/ui/debug-dock/README.md +58 -0
- package/dist/ui/debug-dock/debug-dock.d.ts +13 -0
- package/dist/ui/debug-dock/debug-dock.js +20 -0
- package/dist/ui/debug-dock/index.d.ts +2 -0
- package/dist/ui/debug-dock/index.js +1 -0
- package/dist/ui/debug-dock/styles.d.ts +8 -0
- package/dist/ui/debug-dock/styles.js +25 -0
- package/dist/ui/debug-dock/use-debug-dock.d.ts +20 -0
- package/dist/ui/debug-dock/use-debug-dock.js +71 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/toast/README.md +62 -0
- package/dist/ui/toast/context.d.ts +7 -0
- package/dist/ui/toast/context.js +6 -0
- package/dist/ui/toast/index.d.ts +5 -0
- package/dist/ui/toast/index.js +2 -0
- package/dist/ui/toast/toast-plate/README.md +38 -0
- package/dist/ui/toast/toast-plate/index.d.ts +2 -0
- package/dist/ui/toast/toast-plate/index.js +1 -0
- package/dist/ui/toast/toast-plate/toast-plate.d.ts +9 -0
- package/dist/ui/toast/toast-plate/toast-plate.js +11 -0
- package/dist/ui/toast/toast-plate/use-toast-plate.d.ts +4 -0
- package/dist/ui/toast/toast-plate/use-toast-plate.js +33 -0
- package/dist/ui/toast/toast-provider.d.ts +10 -0
- package/dist/ui/toast/toast-provider.js +53 -0
- package/dist/ui/toast/toast-viewport/README.md +38 -0
- package/dist/ui/toast/toast-viewport/index.d.ts +2 -0
- package/dist/ui/toast/toast-viewport/index.js +1 -0
- package/dist/ui/toast/toast-viewport/styles.d.ts +5 -0
- package/dist/ui/toast/toast-viewport/styles.js +10 -0
- package/dist/ui/toast/toast-viewport/toast-viewport.d.ts +10 -0
- package/dist/ui/toast/toast-viewport/toast-viewport.js +13 -0
- package/dist/ui/toast/types.d.ts +25 -0
- package/dist/ui/toast/types.js +1 -0
- package/dist/ui/toast/use-toast.d.ts +1 -0
- package/dist/ui/toast/use-toast.js +5 -0
- package/dist/utils/README.md +23 -0
- package/dist/utils/create-typography/README.md +71 -0
- package/dist/utils/create-typography/helper.d.ts +23 -0
- package/dist/utils/create-typography/helper.js +72 -0
- package/dist/utils/create-typography/index.d.ts +1 -0
- package/dist/utils/create-typography/index.js +1 -0
- package/dist/utils/define-route/README.md +50 -0
- package/dist/utils/define-route/helper.d.ts +2 -0
- package/dist/utils/define-route/helper.js +1 -0
- package/dist/utils/define-route/index.d.ts +1 -0
- package/dist/utils/define-route/index.js +1 -0
- package/dist/utils/display-name/README.md +46 -0
- package/dist/utils/display-name/helper.d.ts +2 -0
- package/dist/utils/display-name/helper.js +91 -0
- package/dist/utils/display-name/index.d.ts +1 -0
- package/dist/utils/display-name/index.js +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/internal.d.ts +3 -0
- package/dist/utils/internal.js +3 -0
- package/package.json +74 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { ToastApi } from './context';
|
|
2
|
+
export type { ToastProviderProps } from './toast-provider';
|
|
3
|
+
export { ToastProvider } from './toast-provider';
|
|
4
|
+
export type { ToastId, ToastOptions, ToastRender, ToastRenderContext } from './types';
|
|
5
|
+
export { useToast } from './use-toast';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# `@rnzeus/atlas/ui/toast/toast-plate`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas/ui/toast`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Animated wrapper for a single toast item. Handles entry/exit transitions and auto-hide timing.
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import {ToastPlate} from '@rnzeus/atlas/ui';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API (public surface)
|
|
16
|
+
|
|
17
|
+
- `ToastPlate(props)`
|
|
18
|
+
- `toast: ToastItem`
|
|
19
|
+
|
|
20
|
+
## Usage (minimal)
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import {ToastPlate} from '@rnzeus/atlas/ui';
|
|
24
|
+
|
|
25
|
+
<ToastPlate toast={toast} />;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Notes
|
|
29
|
+
|
|
30
|
+
- Uses Reanimated transitions (`SlideInUp`, `FadeOut`, `LinearTransition`).
|
|
31
|
+
- `useToastPlate()` schedules auto-hide after enter animation when `toast.autoHide` is enabled.
|
|
32
|
+
- Usually consumed indirectly via `ToastViewport`.
|
|
33
|
+
|
|
34
|
+
## Sources
|
|
35
|
+
|
|
36
|
+
- [`toast-plate`](./toast-plate.js)
|
|
37
|
+
- [`use-toast-plate`](./use-toast-plate.js)
|
|
38
|
+
- [`index`](./index.js)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ToastPlate } from './toast-plate';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
import type { ToastItem } from '../types';
|
|
3
|
+
export type ToastPlateProps = {
|
|
4
|
+
toast: ToastItem;
|
|
5
|
+
};
|
|
6
|
+
export declare function ToastPlate({ toast }: ToastPlateProps): JSX.Element;
|
|
7
|
+
export declare namespace ToastPlate {
|
|
8
|
+
var displayName: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Animated, { FadeOut, LinearTransition, ReduceMotion, SlideInUp } from 'react-native-reanimated';
|
|
3
|
+
import { displayName } from '../../../utils';
|
|
4
|
+
import { useToast } from '../use-toast';
|
|
5
|
+
import { useToastPlate } from './use-toast-plate';
|
|
6
|
+
export function ToastPlate({ toast }) {
|
|
7
|
+
const { dismiss } = useToast();
|
|
8
|
+
const { handleEnteringEnd } = useToastPlate(toast);
|
|
9
|
+
return (_jsx(Animated.View, { entering: SlideInUp.withCallback(handleEnteringEnd), exiting: FadeOut, layout: LinearTransition.reduceMotion(ReduceMotion.System), children: toast.render({ id: toast.id, dismiss: () => dismiss(toast.id) }) }, `toast-${toast.id}`));
|
|
10
|
+
}
|
|
11
|
+
ToastPlate.displayName = displayName('ui', 'toast-plate');
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
3
|
+
import { useToast } from '../use-toast';
|
|
4
|
+
export function useToastPlate(toast) {
|
|
5
|
+
const { dismiss } = useToast();
|
|
6
|
+
const timer = useRef(null);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
return () => {
|
|
9
|
+
if (timer.current) {
|
|
10
|
+
clearTimeout(timer.current);
|
|
11
|
+
timer.current = null;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}, []);
|
|
15
|
+
const startAutoHide = useCallback(() => {
|
|
16
|
+
if (!toast.autoHide)
|
|
17
|
+
return;
|
|
18
|
+
if (timer.current)
|
|
19
|
+
return;
|
|
20
|
+
timer.current = setTimeout(() => {
|
|
21
|
+
dismiss(toast.id);
|
|
22
|
+
if (timer.current) {
|
|
23
|
+
clearTimeout(timer.current);
|
|
24
|
+
timer.current = null;
|
|
25
|
+
}
|
|
26
|
+
}, toast.visibilityTime);
|
|
27
|
+
}, [dismiss, toast.autoHide, toast.id, toast.visibilityTime]);
|
|
28
|
+
const handleEnteringEnd = useCallback(() => {
|
|
29
|
+
'worklet';
|
|
30
|
+
scheduleOnRN(startAutoHide);
|
|
31
|
+
}, [startAutoHide]);
|
|
32
|
+
return { handleEnteringEnd };
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from 'react';
|
|
2
|
+
export type ToastProviderProps = {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
maxToasts?: number;
|
|
5
|
+
zIndex?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function ToastProvider({ children, maxToasts, zIndex }: ToastProviderProps): JSX.Element;
|
|
8
|
+
export declare namespace ToastProvider {
|
|
9
|
+
var displayName: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { displayName } from '../../utils';
|
|
4
|
+
import { ToastContext } from './context';
|
|
5
|
+
import { ToastViewport } from './toast-viewport';
|
|
6
|
+
function createToastIdFactory() {
|
|
7
|
+
let seq = 0;
|
|
8
|
+
return () => {
|
|
9
|
+
seq = (seq + 1) % 1000000;
|
|
10
|
+
return `${Date.now()}-${seq}`;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function ToastProvider({ children, maxToasts = 3, zIndex }) {
|
|
14
|
+
const nextId = useMemo(() => createToastIdFactory(), []);
|
|
15
|
+
const [toasts, setToasts] = useState([]);
|
|
16
|
+
const toastsRef = useRef([]);
|
|
17
|
+
toastsRef.current = toasts;
|
|
18
|
+
const dismiss = useCallback((id) => {
|
|
19
|
+
requestAnimationFrame(() => {
|
|
20
|
+
setToasts(state => state.filter(t => t.id !== id));
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
const clear = useCallback(() => {
|
|
24
|
+
requestAnimationFrame(() => {
|
|
25
|
+
setToasts([]);
|
|
26
|
+
});
|
|
27
|
+
}, []);
|
|
28
|
+
const show = useCallback((options) => {
|
|
29
|
+
const id = options.id ?? nextId();
|
|
30
|
+
requestAnimationFrame(() => {
|
|
31
|
+
setToasts(state => {
|
|
32
|
+
if (options.uuid) {
|
|
33
|
+
const existing = state.find(t => t.uuid === options.uuid);
|
|
34
|
+
if (existing)
|
|
35
|
+
return state;
|
|
36
|
+
}
|
|
37
|
+
const item = {
|
|
38
|
+
id,
|
|
39
|
+
uuid: options.uuid,
|
|
40
|
+
render: options.render,
|
|
41
|
+
autoHide: options.autoHide ?? true,
|
|
42
|
+
visibilityTime: options.visibilityTime ?? 3000,
|
|
43
|
+
};
|
|
44
|
+
const next = [item, ...state];
|
|
45
|
+
return next.slice(0, maxToasts);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
return id;
|
|
49
|
+
}, [maxToasts, nextId]);
|
|
50
|
+
const value = useMemo(() => ({ show, dismiss, clear }), [clear, dismiss, show]);
|
|
51
|
+
return (_jsxs(ToastContext.Provider, { value: value, children: [children, _jsx(ToastViewport, { toasts: toastsRef.current, zIndex: zIndex })] }));
|
|
52
|
+
}
|
|
53
|
+
ToastProvider.displayName = displayName('ui', 'toast-provider');
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# `@rnzeus/atlas/ui/toast/toast-viewport`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas/ui/toast`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Render layer for active toasts. Positions toast list at the top, applies safe-area offset, and renders each item through `ToastPlate`.
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import {ToastViewport} from '@rnzeus/atlas/ui';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API (public surface)
|
|
16
|
+
|
|
17
|
+
- `ToastViewport(props)`
|
|
18
|
+
- `toasts: ToastItem[]`
|
|
19
|
+
- `zIndex?: number` (default `10`)
|
|
20
|
+
|
|
21
|
+
## Usage (minimal)
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import {ToastViewport} from '@rnzeus/atlas/ui';
|
|
25
|
+
|
|
26
|
+
<ToastViewport toasts={toasts} zIndex={20} />;
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Notes
|
|
30
|
+
|
|
31
|
+
- Uses `useSafeAreaInsets()` and adds top padding (`insets.top + 10`).
|
|
32
|
+
- `ToastProvider` already renders this component internally.
|
|
33
|
+
|
|
34
|
+
## Sources
|
|
35
|
+
|
|
36
|
+
- [`toast-viewport`](./toast-viewport.js)
|
|
37
|
+
- [`index`](./index.js)
|
|
38
|
+
- [`styles`](./styles.js)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ToastViewport } from './toast-viewport';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
import type { ToastItem } from '../types';
|
|
3
|
+
export type ToastViewportProps = {
|
|
4
|
+
toasts: ToastItem[];
|
|
5
|
+
zIndex?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function ToastViewport({ toasts, zIndex }: ToastViewportProps): JSX.Element;
|
|
8
|
+
export declare namespace ToastViewport {
|
|
9
|
+
var displayName: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
import { displayName } from '../../../utils';
|
|
6
|
+
import { ToastPlate } from '../toast-plate';
|
|
7
|
+
import { styles } from './styles';
|
|
8
|
+
export function ToastViewport({ toasts, zIndex = 10 }) {
|
|
9
|
+
const insets = useSafeAreaInsets();
|
|
10
|
+
const containerExtraStyles = useMemo(() => ({ paddingTop: insets.top + 10, zIndex }), [insets.top, zIndex]);
|
|
11
|
+
return (_jsx(View, { style: [styles.container, containerExtraStyles], pointerEvents: "box-none", children: toasts.map(toast => (_jsx(ToastPlate, { toast: toast }, toast.id))) }));
|
|
12
|
+
}
|
|
13
|
+
ToastViewport.displayName = displayName('ui', 'toast-viewport');
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type ToastId = string;
|
|
3
|
+
export type ToastRenderContext = {
|
|
4
|
+
id: ToastId;
|
|
5
|
+
dismiss: () => void;
|
|
6
|
+
};
|
|
7
|
+
export type ToastRender = (ctx: ToastRenderContext) => ReactNode;
|
|
8
|
+
export type ToastOptions = {
|
|
9
|
+
id?: ToastId;
|
|
10
|
+
/**
|
|
11
|
+
* Optional dedupe key.
|
|
12
|
+
* If a toast with the same uuid already exists, show() becomes a no-op.
|
|
13
|
+
*/
|
|
14
|
+
uuid?: string;
|
|
15
|
+
render: ToastRender;
|
|
16
|
+
autoHide?: boolean;
|
|
17
|
+
visibilityTime?: number;
|
|
18
|
+
};
|
|
19
|
+
export type ToastItem = {
|
|
20
|
+
id: ToastId;
|
|
21
|
+
uuid?: string;
|
|
22
|
+
render: ToastRender;
|
|
23
|
+
autoHide: boolean;
|
|
24
|
+
visibilityTime: number;
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useToast(): import("./context").ToastApi;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# `@rnzeus/atlas/utils`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
- **[`display-name`](./display-name/README.md)** — generate stable component display names using a layer prefix (`A/P/W/F/E/S`) and a PascalCased name.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {displayName} from '@rnzeus/atlas/utils';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- **[`create-typography`](./create-typography/README.md)** — build a typed typography map and a `createTextTypography()` helper (with optional scaling and platform lineHeight handling).
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import {createTypography} from '@rnzeus/atlas/utils';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- **[`define-route`](./define-route/README.md)** — define typed route objects (`RouteDef<P>`) for `Navigation.build()`.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {defineRoute} from '@rnzeus/atlas/utils';
|
|
23
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# `@rnzeus/atlas/utils/create-typography`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas/utils`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Create a typed typography registry and a helper that returns React Native `TextStyle` objects with optional scaling and platform-specific `lineHeight` handling.
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import {createTypography} from '@rnzeus/atlas/utils';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API (public surface)
|
|
16
|
+
|
|
17
|
+
`createTypography(cfg)` returns:
|
|
18
|
+
|
|
19
|
+
- `TYPOGRAPHY`: a typed map of your entries (key → config)
|
|
20
|
+
- `createTextTypography(key)`: returns a `TextStyle` for the given key
|
|
21
|
+
|
|
22
|
+
Config:
|
|
23
|
+
|
|
24
|
+
- `entries`: `[key, typographyConfig][]`
|
|
25
|
+
- `scale?`: `(n: number) => number` (e.g. `sw`)
|
|
26
|
+
- `platform?`: `'ios' | 'android'` (or any `PlatformOSType`)
|
|
27
|
+
- `iosZeroLineHeightIfEqual?`: if `true`, sets `lineHeight: 0` on iOS when `fontSize === lineHeight`
|
|
28
|
+
- `debug?`: if `true`, logs registry details (keys, count, platform, scale, fallback)
|
|
29
|
+
- `strict?`: if `true`, throws on invalid runtime keys (instead of falling back)
|
|
30
|
+
- `fallback?`: key used when `strict=false` and a runtime key is invalid (defaults to the first entry key)
|
|
31
|
+
- `onError?`: `(error, context?) => void` (called when `strict=false` and a runtime key is invalid)
|
|
32
|
+
|
|
33
|
+
## Usage (minimal)
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import {createTypography} from '@rnzeus/atlas/utils';
|
|
37
|
+
|
|
38
|
+
const {createTextTypography} = createTypography({
|
|
39
|
+
platform: 'ios',
|
|
40
|
+
entries: [
|
|
41
|
+
[
|
|
42
|
+
'title',
|
|
43
|
+
{
|
|
44
|
+
fontFamily: 'Inter',
|
|
45
|
+
fontSize: 20,
|
|
46
|
+
lineHeight: 24,
|
|
47
|
+
fontWeight: '600',
|
|
48
|
+
letterSpacing: 0,
|
|
49
|
+
textTransform: 'none',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
] as const,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const title = createTextTypography('title');
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Notes
|
|
59
|
+
|
|
60
|
+
- **Typing**: use `as const` on `entries` to keep keys strongly typed.
|
|
61
|
+
- **Scaling**: if `scale` is provided, both `fontSize` and `lineHeight` are scaled.
|
|
62
|
+
- **Platform lineHeight**: when `platform` is not provided, it uses a “safe” cross-platform behavior.
|
|
63
|
+
- **Runtime key safety**:
|
|
64
|
+
- `createTextTypography` is typed, but invalid keys can still happen at runtime (e.g. when a key comes from remote config)
|
|
65
|
+
- use `strict: true` to fail fast
|
|
66
|
+
- keep `strict: false` + `fallback` + `onError` for safe production behavior
|
|
67
|
+
|
|
68
|
+
## Sources
|
|
69
|
+
|
|
70
|
+
- [`helper`](./helper.js)
|
|
71
|
+
- [`index`](./index.js)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PlatformOSType, TextStyle } from 'react-native';
|
|
2
|
+
type ExtraTypographyStyle = 'fontSize' | 'lineHeight' | 'fontFamily' | 'fontWeight' | 'letterSpacing' | 'textTransform';
|
|
3
|
+
type TypographyConfig = Required<Pick<TextStyle, ExtraTypographyStyle>>;
|
|
4
|
+
type TypographyEntry<K extends string = string> = readonly [K, TypographyConfig];
|
|
5
|
+
export type TypographyErrorContext = {
|
|
6
|
+
where: string;
|
|
7
|
+
key?: string;
|
|
8
|
+
};
|
|
9
|
+
type CreateTypographyConfig<E extends readonly TypographyEntry[]> = {
|
|
10
|
+
entries: E;
|
|
11
|
+
scale?: (n: number) => number;
|
|
12
|
+
platform?: PlatformOSType | 'ios' | 'android';
|
|
13
|
+
iosZeroLineHeightIfEqual?: boolean;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
strict?: boolean;
|
|
16
|
+
onError?: (error: Error, context?: TypographyErrorContext) => void;
|
|
17
|
+
fallback?: E[number][0];
|
|
18
|
+
};
|
|
19
|
+
declare const createTypography: <const E extends readonly TypographyEntry[]>(cfg: CreateTypographyConfig<E>) => {
|
|
20
|
+
readonly TYPOGRAPHY: { [K in E[number][0]]: Extract<E[number], readonly [K, Required<Pick<TextStyle, ExtraTypographyStyle>>]>[1]; };
|
|
21
|
+
readonly createTextTypography: (typography: E[number][0]) => TextStyle;
|
|
22
|
+
};
|
|
23
|
+
export default createTypography;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const createTypography = (cfg) => {
|
|
2
|
+
if (!cfg.entries.length) {
|
|
3
|
+
throw new Error('[Typography] entries must not be empty');
|
|
4
|
+
}
|
|
5
|
+
const TYPOGRAPHY = Object.fromEntries(cfg.entries);
|
|
6
|
+
const keys = cfg.entries.map(e => e[0]);
|
|
7
|
+
const strict = cfg.strict ?? false;
|
|
8
|
+
const onError = cfg.onError;
|
|
9
|
+
const debug = cfg.debug ?? false;
|
|
10
|
+
const platform = cfg.platform;
|
|
11
|
+
const scale = cfg.scale;
|
|
12
|
+
// fallback key: explicit or first entry key
|
|
13
|
+
const fallbackKey = (cfg.fallback ?? keys[0]);
|
|
14
|
+
const errorValue = (message, context) => {
|
|
15
|
+
const err = new Error(message);
|
|
16
|
+
if (strict)
|
|
17
|
+
throw err;
|
|
18
|
+
try {
|
|
19
|
+
onError?.(err, context);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// ignore logging errors
|
|
23
|
+
}
|
|
24
|
+
return TYPOGRAPHY[fallbackKey];
|
|
25
|
+
};
|
|
26
|
+
const getConfig = (key) => {
|
|
27
|
+
const v = TYPOGRAPHY[key];
|
|
28
|
+
if (!v) {
|
|
29
|
+
return errorValue(`Unknown typography key: ${key}`, { where: 'getConfig', key });
|
|
30
|
+
}
|
|
31
|
+
return v;
|
|
32
|
+
};
|
|
33
|
+
const createTextTypography = (typography) => {
|
|
34
|
+
const v = getConfig(String(typography));
|
|
35
|
+
const fz = v.fontSize;
|
|
36
|
+
const lh = v.lineHeight;
|
|
37
|
+
const s = (n) => (scale ? scale(n) : n);
|
|
38
|
+
return {
|
|
39
|
+
fontFamily: v.fontFamily,
|
|
40
|
+
fontSize: s(fz),
|
|
41
|
+
...(platform === 'ios'
|
|
42
|
+
? { lineHeight: cfg.iosZeroLineHeightIfEqual && fz === lh ? 0 : s(lh) }
|
|
43
|
+
: { lineHeight: s(lh) }),
|
|
44
|
+
fontWeight: v.fontWeight,
|
|
45
|
+
letterSpacing: v.letterSpacing,
|
|
46
|
+
textTransform: v.textTransform,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
if (debug) {
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
console.groupCollapsed?.('[Typography]');
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.log('Strict:', strict);
|
|
54
|
+
// eslint-disable-next-line no-console
|
|
55
|
+
console.log('Platform:', platform ?? '(auto)');
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.log('Scale:', scale ? 'on' : 'off');
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.log('Fallback:', fallbackKey);
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.log('Keys:', [...keys].sort());
|
|
62
|
+
// eslint-disable-next-line no-console
|
|
63
|
+
console.log('Count:', keys.length);
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.groupEnd?.();
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
TYPOGRAPHY,
|
|
69
|
+
createTextTypography,
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
export default createTypography;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as createTypography } from './helper';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as createTypography } from './helper';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# `@rnzeus/atlas/utils/define-route`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas/utils`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Define typed route objects (`RouteDef<P, Q>`) to be used with Atlas navigation helpers (e.g. `Navigation.build(route, params)`), keeping route params/query strongly typed.
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import {defineRoute} from '@rnzeus/atlas/utils';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API (public surface)
|
|
16
|
+
|
|
17
|
+
`defineRoute<P = undefined, Q = undefined>()(def) => RouteDef<P, Q> & def`
|
|
18
|
+
|
|
19
|
+
- `P` is the type of route params (e.g. `{id: number}`)
|
|
20
|
+
- `Q` is the type of route query (e.g. `{step?: 'seats' | 'payment'}`)
|
|
21
|
+
- `def` is a route definition object (`name`, `path`, `linking`, optional `key`)
|
|
22
|
+
- optional schemas:
|
|
23
|
+
- `paramsSchema?: { safeParse(input): ... }` (e.g. a Zod schema)
|
|
24
|
+
- `querySchema?: { safeParse(input): ... }` (e.g. a Zod schema)
|
|
25
|
+
|
|
26
|
+
## Usage (minimal)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import {Navigation} from '@rnzeus/atlas/services';
|
|
30
|
+
import {defineRoute} from '@rnzeus/atlas/utils';
|
|
31
|
+
|
|
32
|
+
const BOOKING = defineRoute<{id: number}>()({
|
|
33
|
+
name: 'Booking',
|
|
34
|
+
path: 'non-tabbar/booking/:id',
|
|
35
|
+
linking: 'booking',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const path = Navigation.build(BOOKING, {id: 42});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
|
|
43
|
+
- This is a **type helper**: at runtime it returns the same object you pass in.
|
|
44
|
+
- `RouteDef<P, Q>` includes internal `__params` / `__query` fields used only for typing.
|
|
45
|
+
- Schema fields (`paramsSchema` / `querySchema`) are used by `Navigation.build()` / `Navigation.query()` when validation is enabled.
|
|
46
|
+
|
|
47
|
+
## Sources
|
|
48
|
+
|
|
49
|
+
- [`helper`](./helper.js)
|
|
50
|
+
- [`index`](./index.js)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const defineRoute = () => (def) => def;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defineRoute } from './helper';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defineRoute } from './helper';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# `@rnzeus/atlas/utils/display-name`
|
|
2
|
+
|
|
3
|
+
← [`@rnzeus/atlas/utils`](../README.md)
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Generate stable component display names for logging/debugging. The name is built as:
|
|
8
|
+
|
|
9
|
+
- a **layer prefix** (`A/P/W/F/E/S`)
|
|
10
|
+
- a **PascalCased** component name
|
|
11
|
+
|
|
12
|
+
## Import
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {displayName} from '@rnzeus/atlas/utils';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## API (public surface)
|
|
19
|
+
|
|
20
|
+
`displayName(layerOrPath: string, nameMaybe?: string): string`
|
|
21
|
+
|
|
22
|
+
Overloads:
|
|
23
|
+
|
|
24
|
+
- `displayName('features', 'logger-button')` → `FLoggerButton`
|
|
25
|
+
- `displayName('src/features/logger/ui/logger-button/button.tsx')` → `FButton`
|
|
26
|
+
|
|
27
|
+
## Usage (minimal)
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import {displayName} from '@rnzeus/atlas/utils';
|
|
31
|
+
|
|
32
|
+
const name = displayName('features', 'logger-button'); // "FLoggerButton"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
|
|
37
|
+
- **Layer detection**: when you pass a path, the layer is inferred from folder names (`app/pages/widgets/features/entities/shared`). If no layer is detected, it falls back to `shared` (`S`).
|
|
38
|
+
- **Normalization**:
|
|
39
|
+
- paths are normalized to `/` separators
|
|
40
|
+
- `@` and leading `./` are stripped before matching
|
|
41
|
+
- **PascalCase**: the base name is derived from the file name (without extension) and converted to PascalCase.
|
|
42
|
+
|
|
43
|
+
## Sources
|
|
44
|
+
|
|
45
|
+
- [`helper`](./helper.js)
|
|
46
|
+
- [`index`](./index.js)
|