@sincpro/mobile-ui 1.1.0 → 2.0.1
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/README.md +156 -29
- package/assets/brand-mesh.png +0 -0
- package/assets/fonts/FFL.txt +57 -0
- package/assets/fonts/Satoshi-Black.otf +0 -0
- package/assets/fonts/Satoshi-Bold.otf +0 -0
- package/assets/fonts/Satoshi-Medium.otf +0 -0
- package/assets/fonts/Satoshi-Regular.otf +0 -0
- package/dist/Actions/Actions.Button.d.ts +10 -12
- package/dist/Actions/Actions.Button.js +9 -11
- package/dist/Actions/Actions.Dock.d.ts +20 -0
- package/dist/Actions/Actions.Dock.js +89 -0
- package/dist/Actions/Actions.FAB.d.ts +1 -2
- package/dist/Actions/Actions.FAB.js +5 -7
- package/dist/Actions/Actions.IconButton.d.ts +1 -2
- package/dist/Actions/Actions.IconButton.js +2 -2
- package/dist/Actions/index.d.ts +4 -0
- package/dist/Actions/index.js +3 -0
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +22 -34
- package/dist/Dialog/Dialog.ActionSheet.js +2 -16
- package/dist/Dialog/Dialog.Confirmation.js +7 -5
- package/dist/Dialog/Dialog.EditValue.js +3 -1
- package/dist/Dialog/Dialog.Sheet.d.ts +3 -3
- package/dist/Dialog/Dialog.Sheet.js +18 -25
- package/dist/Display/Display.Accordion.js +7 -3
- package/dist/Display/Display.AmountSummary.d.ts +28 -0
- package/dist/Display/Display.AmountSummary.js +25 -0
- package/dist/Display/Display.Carousel.d.ts +27 -4
- package/dist/Display/Display.Carousel.js +112 -12
- package/dist/Display/Display.ExpoImage.d.ts +8 -0
- package/dist/Display/Display.ExpoImage.js +15 -0
- package/dist/Display/Display.Image.d.ts +10 -6
- package/dist/Display/Display.Image.js +39 -6
- package/dist/Display/Display.ListItem.d.ts +1 -2
- package/dist/Display/Display.ListItem.js +3 -3
- package/dist/Display/Display.Logo.d.ts +2 -2
- package/dist/Display/Display.Logo.js +3 -2
- package/dist/Display/Display.MediaCard.d.ts +2 -2
- package/dist/Display/Display.MediaEmbed.d.ts +2 -2
- package/dist/Display/Display.ProductCard.d.ts +2 -2
- package/dist/Display/Display.Story.d.ts +3 -3
- package/dist/Display/Display.Story.js +5 -4
- package/dist/Display/Display.StoryTray.d.ts +4 -4
- package/dist/Display/Display.StoryTray.js +3 -2
- package/dist/Display/Display.StoryViewer.d.ts +3 -3
- package/dist/Display/Display.StoryViewer.js +6 -3
- package/dist/Display/index.d.ts +9 -0
- package/dist/Display/index.js +4 -0
- package/dist/Feedback/Feedback.DomainSplashScreen.d.ts +13 -4
- package/dist/Feedback/Feedback.DomainSplashScreen.js +68 -53
- package/dist/Feedback/Feedback.EmptyState.d.ts +3 -4
- package/dist/Feedback/Feedback.EmptyState.js +4 -3
- package/dist/Feedback/Feedback.Error.d.ts +1 -2
- package/dist/Feedback/Feedback.Error.js +2 -2
- package/dist/Feedback/Feedback.Loading.d.ts +6 -2
- package/dist/Feedback/Feedback.Loading.js +2 -2
- package/dist/Feedback/Feedback.Progress.d.ts +6 -3
- package/dist/Feedback/Feedback.Progress.js +29 -19
- package/dist/Feedback/Feedback.ProgressCircle.d.ts +3 -2
- package/dist/Feedback/Feedback.ProgressCircle.js +10 -7
- package/dist/Feedback/Feedback.Skeleton.d.ts +4 -4
- package/dist/Feedback/Feedback.Skeleton.js +15 -3
- package/dist/Feedback/Feedback.Spinner.d.ts +3 -3
- package/dist/Feedback/Feedback.Spinner.js +40 -9
- package/dist/Feedback/Feedback.Splash.d.ts +2 -2
- package/dist/Feedback/Feedback.Splash.js +5 -3
- package/dist/Feedback/Toast.context.d.ts +64 -3
- package/dist/Feedback/Toast.context.js +112 -31
- package/dist/Feedback/index.d.ts +15 -1
- package/dist/Feedback/index.js +4 -1
- package/dist/Form/Form.Checkbox.d.ts +1 -2
- package/dist/Form/Form.Checkbox.js +2 -2
- package/dist/Form/Form.DatePicker.d.ts +1 -2
- package/dist/Form/Form.DatePicker.js +2 -2
- package/dist/Form/Form.Dropdown.d.ts +15 -3
- package/dist/Form/Form.Dropdown.js +21 -6
- package/dist/Form/Form.ErrorSummary.d.ts +23 -0
- package/dist/Form/Form.ErrorSummary.js +53 -0
- package/dist/Form/Form.Input.d.ts +1 -2
- package/dist/Form/Form.Input.js +2 -2
- package/dist/Form/Form.Select.d.ts +1 -2
- package/dist/Form/Form.Select.js +6 -19
- package/dist/Form/index.d.ts +3 -0
- package/dist/Form/index.js +2 -0
- package/dist/Navigation/Navigation.AppBar.d.ts +2 -6
- package/dist/Navigation/Navigation.AppBar.js +9 -7
- package/dist/Navigation/Navigation.BottomNav.d.ts +1 -3
- package/dist/Navigation/Navigation.BottomNav.js +7 -6
- package/dist/Navigation/Navigation.Header.d.ts +2 -2
- package/dist/Navigation/Navigation.Menu.js +10 -3
- package/dist/Navigation/Navigation.Search.d.ts +41 -0
- package/dist/Navigation/Navigation.Search.js +47 -0
- package/dist/Navigation/Navigation.SearchBar.d.ts +1 -2
- package/dist/Navigation/Navigation.SearchBar.js +16 -19
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +11 -3
- package/dist/Navigation/Navigation.SegmentedControl.js +29 -16
- package/dist/Navigation/index.d.ts +11 -2
- package/dist/Navigation/index.js +2 -0
- package/dist/branding.d.ts +3 -2
- package/dist/primitives/BaseButton.d.ts +10 -12
- package/dist/primitives/BaseButton.js +9 -11
- package/dist/theme/typography.d.ts +1 -1
- package/dist/utils/image.d.ts +3 -0
- package/dist/utils/image.js +13 -0
- package/dist/utils/keys.d.ts +1 -0
- package/dist/utils/keys.js +7 -0
- package/dist/utils/progress.d.ts +1 -0
- package/dist/utils/progress.js +5 -0
- package/dist/utils/reorder.js +2 -5
- package/dist/utils/useReducedMotion.d.ts +1 -0
- package/dist/utils/useReducedMotion.js +43 -0
- package/dist/utils/useSheetTranslation.d.ts +5 -0
- package/dist/utils/useSheetTranslation.js +23 -0
- package/dist/views/AppSplashView.d.ts +3 -2
- package/dist/views/AppSplashView.js +3 -2
- package/dist/views/AuthFormView.d.ts +2 -2
- package/dist/views/FormViewV2.d.ts +2 -2
- package/dist/views/ListViewV2.context.d.ts +3 -1
- package/dist/views/ListViewV2.context.js +41 -21
- package/dist/views/ListViewV2.d.ts +15 -7
- package/dist/views/ListViewV2.js +44 -23
- package/dist/views/types/IListView.js +6 -5
- package/dist/widgets/CollectionOptions.js +9 -7
- package/dist/widgets/FilterBar.d.ts +1 -1
- package/dist/widgets/FilterBar.js +1 -1
- package/dist/widgets/FilterBuilder.js +7 -7
- package/dist/widgets/HomeHeader.d.ts +2 -2
- package/dist/widgets/PromoModal.js +3 -1
- package/dist/widgets/ScreenHeader.d.ts +2 -2
- package/package.json +5 -1
package/dist/branding.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ImageSource } from "./utils/image.js";
|
|
1
2
|
import { type ImageSourcePropType } from "react-native";
|
|
2
3
|
/**
|
|
3
4
|
* Centralized brand assets. Set once at app boot via `setBranding({ ... })`. Components
|
|
@@ -14,14 +15,14 @@ import { type ImageSourcePropType } from "react-native";
|
|
|
14
15
|
*/
|
|
15
16
|
export interface BrandingConfig {
|
|
16
17
|
/** Brand logo (used by `Display.Logo`, `widgets.ScreenHeader`, etc.). */
|
|
17
|
-
logo?:
|
|
18
|
+
logo?: ImageSource;
|
|
18
19
|
/** Brand symbol / icon used by `Display.Pattern kind="mesh"` as the tiled texture. */
|
|
19
20
|
mesh?: ImageSourcePropType;
|
|
20
21
|
/** Tile size in px (overrides `theme.pattern.size` for the brand mesh). */
|
|
21
22
|
meshSize?: number;
|
|
22
23
|
}
|
|
23
24
|
export declare function setBranding(config: BrandingConfig): void;
|
|
24
|
-
export declare function getBrandingLogo():
|
|
25
|
+
export declare function getBrandingLogo(): ImageSource | undefined;
|
|
25
26
|
export declare function getBrandingMesh(): ImageSourcePropType | undefined;
|
|
26
27
|
export declare function getBrandingMeshSize(): number | undefined;
|
|
27
28
|
/** Test-only — reset to initial empty state. Not part of the public API. */
|
|
@@ -11,18 +11,18 @@ declare const button: import("tailwind-variants").TVReturnType<{
|
|
|
11
11
|
outlineDanger: "bg-transparent border border-danger";
|
|
12
12
|
outlineBlack: "bg-transparent border border-border-strong";
|
|
13
13
|
flat: "bg-text-primary/10";
|
|
14
|
-
link: "bg-transparent
|
|
14
|
+
link: "bg-transparent";
|
|
15
15
|
transparent: "bg-transparent border border-border-light";
|
|
16
16
|
};
|
|
17
17
|
size: {
|
|
18
|
-
small: "py-1.5 px-3 min-h-[
|
|
19
|
-
medium: "py-2.5 px-4 min-h-[
|
|
18
|
+
small: "py-1.5 px-3 min-h-[48px]";
|
|
19
|
+
medium: "py-2.5 px-4 min-h-[48px]";
|
|
20
20
|
large: "py-3 px-5 min-h-[48px]";
|
|
21
21
|
};
|
|
22
22
|
disabled: {
|
|
23
23
|
true: "opacity-70";
|
|
24
24
|
};
|
|
25
|
-
}, undefined, "rounded-md items-center justify-center flex-row min-h-[
|
|
25
|
+
}, undefined, "rounded-md items-center justify-center flex-row min-h-[48px]", {
|
|
26
26
|
variant: {
|
|
27
27
|
primary: "bg-accent";
|
|
28
28
|
accent: "bg-transparent";
|
|
@@ -31,12 +31,12 @@ declare const button: import("tailwind-variants").TVReturnType<{
|
|
|
31
31
|
outlineDanger: "bg-transparent border border-danger";
|
|
32
32
|
outlineBlack: "bg-transparent border border-border-strong";
|
|
33
33
|
flat: "bg-text-primary/10";
|
|
34
|
-
link: "bg-transparent
|
|
34
|
+
link: "bg-transparent";
|
|
35
35
|
transparent: "bg-transparent border border-border-light";
|
|
36
36
|
};
|
|
37
37
|
size: {
|
|
38
|
-
small: "py-1.5 px-3 min-h-[
|
|
39
|
-
medium: "py-2.5 px-4 min-h-[
|
|
38
|
+
small: "py-1.5 px-3 min-h-[48px]";
|
|
39
|
+
medium: "py-2.5 px-4 min-h-[48px]";
|
|
40
40
|
large: "py-3 px-5 min-h-[48px]";
|
|
41
41
|
};
|
|
42
42
|
disabled: {
|
|
@@ -51,12 +51,12 @@ declare const button: import("tailwind-variants").TVReturnType<{
|
|
|
51
51
|
outlineDanger: "bg-transparent border border-danger";
|
|
52
52
|
outlineBlack: "bg-transparent border border-border-strong";
|
|
53
53
|
flat: "bg-text-primary/10";
|
|
54
|
-
link: "bg-transparent
|
|
54
|
+
link: "bg-transparent";
|
|
55
55
|
transparent: "bg-transparent border border-border-light";
|
|
56
56
|
};
|
|
57
57
|
size: {
|
|
58
|
-
small: "py-1.5 px-3 min-h-[
|
|
59
|
-
medium: "py-2.5 px-4 min-h-[
|
|
58
|
+
small: "py-1.5 px-3 min-h-[48px]";
|
|
59
|
+
medium: "py-2.5 px-4 min-h-[48px]";
|
|
60
60
|
large: "py-3 px-5 min-h-[48px]";
|
|
61
61
|
};
|
|
62
62
|
disabled: {
|
|
@@ -131,7 +131,6 @@ export interface BaseButtonProps extends VariantProps<typeof button>, Accessibil
|
|
|
131
131
|
disabled?: boolean;
|
|
132
132
|
className?: string;
|
|
133
133
|
icon?: React.ReactNode;
|
|
134
|
-
accessibleSizing?: boolean;
|
|
135
134
|
testID?: string;
|
|
136
135
|
}
|
|
137
136
|
export declare const BaseButton: FC<BaseButtonProps>;
|
|
@@ -141,7 +140,6 @@ export interface BaseButtonIconProps extends VariantProps<typeof buttonIcon>, Ac
|
|
|
141
140
|
loading?: boolean;
|
|
142
141
|
disabled?: boolean;
|
|
143
142
|
className?: string;
|
|
144
|
-
accessibleSizing?: boolean;
|
|
145
143
|
testID?: string;
|
|
146
144
|
}
|
|
147
145
|
export declare const BaseButtonIcon: FC<BaseButtonIconProps>;
|
|
@@ -8,7 +8,7 @@ import { ActivityIndicator, TouchableOpacity, View } from "react-native";
|
|
|
8
8
|
// STYLE VARIANTS
|
|
9
9
|
// ============================================================================
|
|
10
10
|
const button = tv({
|
|
11
|
-
base: "rounded-md items-center justify-center flex-row min-h-[
|
|
11
|
+
base: "rounded-md items-center justify-center flex-row min-h-[48px]",
|
|
12
12
|
variants: {
|
|
13
13
|
variant: {
|
|
14
14
|
primary: "bg-accent",
|
|
@@ -18,12 +18,12 @@ const button = tv({
|
|
|
18
18
|
outlineDanger: "bg-transparent border border-danger",
|
|
19
19
|
outlineBlack: "bg-transparent border border-border-strong",
|
|
20
20
|
flat: "bg-text-primary/10",
|
|
21
|
-
link: "bg-transparent
|
|
21
|
+
link: "bg-transparent",
|
|
22
22
|
transparent: "bg-transparent border border-border-light",
|
|
23
23
|
},
|
|
24
24
|
size: {
|
|
25
|
-
small: "py-1.5 px-3 min-h-[
|
|
26
|
-
medium: "py-2.5 px-4 min-h-[
|
|
25
|
+
small: "py-1.5 px-3 min-h-[48px]",
|
|
26
|
+
medium: "py-2.5 px-4 min-h-[48px]",
|
|
27
27
|
large: "py-3 px-5 min-h-[48px]",
|
|
28
28
|
},
|
|
29
29
|
disabled: {
|
|
@@ -192,7 +192,7 @@ function getIconSize(size) {
|
|
|
192
192
|
function getTextVariant(size) {
|
|
193
193
|
return textVariantMap[size] ?? "button";
|
|
194
194
|
}
|
|
195
|
-
export const BaseButton = ({ title, onPress, variant = "primary", size = "medium", loading = false, disabled = false, className, icon,
|
|
195
|
+
export const BaseButton = ({ title, onPress, variant = "primary", size = "medium", loading = false, disabled = false, className, icon, testID, accessibilityLabel, accessibilityState, ...accessibilityProps }) => {
|
|
196
196
|
const textColorClass = textColor({
|
|
197
197
|
variant: variant ?? "primary",
|
|
198
198
|
disabled,
|
|
@@ -204,17 +204,15 @@ export const BaseButton = ({ title, onPress, variant = "primary", size = "medium
|
|
|
204
204
|
...accessibilityState,
|
|
205
205
|
disabled: disabled || loading,
|
|
206
206
|
busy: loading,
|
|
207
|
-
}, style:
|
|
208
|
-
? { minHeight: 48, minWidth: 48, justifyContent: "center" }
|
|
209
|
-
: undefined, testID: testID, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Typography.Text, { className: textColorClass, variant: textVariantValue, children: title })) }));
|
|
207
|
+
}, style: { minHeight: 48, minWidth: 48, justifyContent: "center" }, testID: testID, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Typography.Text, { allowFontScaling: true, className: textColorClass, style: { flexShrink: 1 }, variant: textVariantValue, children: title })) }));
|
|
210
208
|
}
|
|
211
209
|
return (_jsxs(TouchableOpacity, { activeOpacity: 0.8, className: button({ variant, size, disabled, className }), disabled: disabled || loading, onPress: onPress, ...accessibilityProps, accessibilityLabel: accessibilityLabel ?? title, accessibilityRole: "button", accessibilityState: {
|
|
212
210
|
...accessibilityState,
|
|
213
211
|
disabled: disabled || loading,
|
|
214
212
|
busy: loading,
|
|
215
|
-
}, style:
|
|
213
|
+
}, style: { minHeight: 48, minWidth: 48 }, testID: testID, children: [icon && !loading && _jsx(View, { className: "mr-2", children: icon }), loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Typography.Text, { allowFontScaling: true, className: textColorClass, semibold: variant === "primary", style: { flexShrink: 1 }, variant: textVariantValue, children: title }))] }));
|
|
216
214
|
};
|
|
217
|
-
export const BaseButtonIcon = ({ icon, onPress, variant = "primary", size = "medium", loading = false, disabled = false, className,
|
|
215
|
+
export const BaseButtonIcon = ({ icon, onPress, variant = "primary", size = "medium", loading = false, disabled = false, className, testID, accessibilityState, ...accessibilityProps }) => {
|
|
218
216
|
const iconColorValue = getIconColor(variant ?? "primary", disabled);
|
|
219
217
|
const loadingColorValue = getLoadingColor(variant ?? "primary");
|
|
220
218
|
const iconSizeValue = getIconSize(size ?? "medium");
|
|
@@ -222,7 +220,7 @@ export const BaseButtonIcon = ({ icon, onPress, variant = "primary", size = "med
|
|
|
222
220
|
...accessibilityState,
|
|
223
221
|
disabled: disabled || loading,
|
|
224
222
|
busy: loading,
|
|
225
|
-
}, style:
|
|
223
|
+
}, style: { minHeight: 48, minWidth: 48 }, testID: testID, children: loading ? (_jsx(ActivityIndicator, { color: loadingColorValue, size: "small" })) : (_jsx(Icon, { color: iconColorValue, name: icon, size: iconSizeValue })) }));
|
|
226
224
|
};
|
|
227
225
|
// ============================================================================
|
|
228
226
|
// COMPOUND COMPONENT
|
|
@@ -436,7 +436,7 @@ export declare const Typography: {
|
|
|
436
436
|
readonly letterSpacing: 0;
|
|
437
437
|
};
|
|
438
438
|
};
|
|
439
|
-
readonly variantFontRole: Record<"
|
|
439
|
+
readonly variantFontRole: Record<"display" | "label" | "button" | "title" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "bodyReadable" | "bodyLarge" | "body" | "bodySmall" | "labelSmall" | "data" | "dataLarge" | "overline" | "caption" | "captionSmall" | "buttonSmall" | "buttonLarge" | "subtitle", FontRole>;
|
|
440
440
|
readonly createTextStyle: (variant: keyof typeof typographyVariants, overrides?: Partial<TextStyle>) => TextStyle;
|
|
441
441
|
readonly createCustomTextStyle: (fontSize: keyof typeof fontSizes, fontFamily: keyof typeof fontFamilies, options?: {
|
|
442
442
|
lineHeight?: keyof typeof lineHeights;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const sharedSourceKeys = new WeakMap();
|
|
2
|
+
let nextSharedSourceKey = 0;
|
|
3
|
+
export function imageSourceKey(source) {
|
|
4
|
+
if (source && typeof source === "object" && "nativeRefType" in source) {
|
|
5
|
+
let key = sharedSourceKeys.get(source);
|
|
6
|
+
if (key === undefined) {
|
|
7
|
+
key = nextSharedSourceKey++;
|
|
8
|
+
sharedSourceKeys.set(source, key);
|
|
9
|
+
}
|
|
10
|
+
return `shared-image-${key}`;
|
|
11
|
+
}
|
|
12
|
+
return JSON.stringify(source);
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uniqueKeys<T>(items: readonly T[], keyExtractor: (item: T, index: number) => string, component: string): string[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function uniqueKeys(items, keyExtractor, component) {
|
|
2
|
+
const keys = items.map(keyExtractor);
|
|
3
|
+
if (keys.some((key) => typeof key !== "string" || !key.trim()) ||
|
|
4
|
+
new Set(keys).size !== keys.length)
|
|
5
|
+
throw new Error(`${component} requires unique, non-empty string keys.`);
|
|
6
|
+
return keys;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeProgress(value: number): number;
|
package/dist/utils/reorder.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
+
import { uniqueKeys } from "./keys.js";
|
|
1
2
|
export function reorderKeys(items, keyExtractor) {
|
|
2
|
-
|
|
3
|
-
if (keys.some((key) => typeof key !== "string" || !key.trim()) ||
|
|
4
|
-
new Set(keys).size !== keys.length)
|
|
5
|
-
throw new Error("ReorderableList requires unique, non-empty string keys.");
|
|
6
|
-
return keys;
|
|
3
|
+
return uniqueKeys(items, keyExtractor, "ReorderableList");
|
|
7
4
|
}
|
|
8
5
|
export function sameOrder(left, right) {
|
|
9
6
|
return left.length === right.length && left.every((key, index) => key === right[index]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useReducedMotion(): boolean;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { AccessibilityInfo } from "react-native";
|
|
3
|
+
const listeners = new Set();
|
|
4
|
+
let reducedMotion = true;
|
|
5
|
+
let generation = 0;
|
|
6
|
+
let subscription;
|
|
7
|
+
function publish(enabled) {
|
|
8
|
+
if (reducedMotion === enabled)
|
|
9
|
+
return;
|
|
10
|
+
reducedMotion = enabled;
|
|
11
|
+
for (const listener of [...listeners])
|
|
12
|
+
listener();
|
|
13
|
+
}
|
|
14
|
+
function subscribe(listener) {
|
|
15
|
+
listeners.add(listener);
|
|
16
|
+
if (listeners.size === 1) {
|
|
17
|
+
const request = ++generation;
|
|
18
|
+
let receivedChange = false;
|
|
19
|
+
subscription = AccessibilityInfo.addEventListener("reduceMotionChanged", (enabled) => {
|
|
20
|
+
receivedChange = true;
|
|
21
|
+
publish(enabled);
|
|
22
|
+
});
|
|
23
|
+
AccessibilityInfo.isReduceMotionEnabled().then((enabled) => {
|
|
24
|
+
if (request === generation && !receivedChange)
|
|
25
|
+
publish(enabled);
|
|
26
|
+
}, (error) => {
|
|
27
|
+
if (request === generation)
|
|
28
|
+
console.warn("[useReducedMotion] Could not read accessibility preference", error);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return () => {
|
|
32
|
+
listeners.delete(listener);
|
|
33
|
+
if (listeners.size === 0) {
|
|
34
|
+
generation += 1;
|
|
35
|
+
subscription?.remove();
|
|
36
|
+
subscription = undefined;
|
|
37
|
+
reducedMotion = true;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function useReducedMotion() {
|
|
42
|
+
return useSyncExternalStore(subscribe, () => reducedMotion, () => true);
|
|
43
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useReducedMotion } from "./useReducedMotion.js";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Animated } from "react-native";
|
|
4
|
+
export function useSheetTranslation(visible, hiddenOffset = 800) {
|
|
5
|
+
const reducedMotion = useReducedMotion();
|
|
6
|
+
const [translateY] = useState(() => new Animated.Value(visible ? 0 : hiddenOffset));
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
translateY.stopAnimation();
|
|
9
|
+
if (visible && !reducedMotion) {
|
|
10
|
+
const animation = Animated.spring(translateY, {
|
|
11
|
+
toValue: 0,
|
|
12
|
+
useNativeDriver: true,
|
|
13
|
+
damping: 20,
|
|
14
|
+
stiffness: 300,
|
|
15
|
+
});
|
|
16
|
+
animation.start();
|
|
17
|
+
return () => animation.stop();
|
|
18
|
+
}
|
|
19
|
+
translateY.setValue(visible ? 0 : hiddenOffset);
|
|
20
|
+
return () => translateY.stopAnimation();
|
|
21
|
+
}, [visible, hiddenOffset, reducedMotion, translateY]);
|
|
22
|
+
return { translateY, reducedMotion };
|
|
23
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { type SpinnerVariant } from "../Feedback/Feedback.Spinner.js";
|
|
2
2
|
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
3
|
+
import type { ImageSource } from "../utils/image.js";
|
|
3
4
|
import type { ReactNode } from "react";
|
|
4
|
-
import { type
|
|
5
|
+
import { type ViewStyle } from "react-native";
|
|
5
6
|
export interface AppSplashViewProps {
|
|
6
7
|
/** Gradient + pattern background. Defaults to `night-green` preset. */
|
|
7
8
|
background?: AppBarBackground;
|
|
8
9
|
/** App logo shown centered above the loading indicator. */
|
|
9
|
-
logo?:
|
|
10
|
+
logo?: ImageSource;
|
|
10
11
|
/** Built-in loading animation variant. Ignored when `loader` is provided. Defaults to `"dots"`. */
|
|
11
12
|
loadingVariant?: SpinnerVariant;
|
|
12
13
|
/** Fully custom loading element. Takes precedence over `loadingVariant`. */
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import ExpoImage from "../Display/Display.ExpoImage.js";
|
|
2
3
|
import GradientSurface from "../Display/Display.GradientSurface.js";
|
|
3
4
|
import { Pattern } from "../Display/Display.Pattern.js";
|
|
4
5
|
import Spinner from "../Feedback/Feedback.Spinner.js";
|
|
5
|
-
import {
|
|
6
|
+
import { View } from "react-native";
|
|
6
7
|
export function AppSplashView({ background, logo, loadingVariant = "dots", loader, style, }) {
|
|
7
|
-
return (_jsxs(GradientSurface, { className: "flex-1", colors: background?.colors, end: background?.end, padding: "none", preset: background?.surface ?? "night-green", radius: "none", start: background?.start, style: { flex: 1, ...style }, children: [background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, _jsxs(View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: [logo ? (_jsx(
|
|
8
|
+
return (_jsxs(GradientSurface, { className: "flex-1", colors: background?.colors, end: background?.end, padding: "none", preset: background?.surface ?? "night-green", radius: "none", start: background?.start, style: { flex: 1, ...style }, children: [background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, _jsxs(View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: [logo ? (_jsx(ExpoImage, { contentFit: "contain", source: logo, style: { width: 140, height: 140, marginBottom: 40 } })) : null, loader ?? (_jsx(Spinner, { color: "rgba(255,255,255,0.9)", size: "large", variant: loadingVariant }))] })] }));
|
|
8
9
|
}
|
|
9
10
|
export default AppSplashView;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { KeyboardFormProps } from "../Form/Form.KeyboardForm.js";
|
|
2
2
|
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
3
|
+
import type { ImageSource } from "../utils/image.js";
|
|
3
4
|
import { ReactNode } from "react";
|
|
4
|
-
import { type ImageSourcePropType } from "react-native";
|
|
5
5
|
interface AuthFormProps {
|
|
6
6
|
title?: string;
|
|
7
7
|
description?: string;
|
|
8
|
-
logoSource?:
|
|
8
|
+
logoSource?: ImageSource;
|
|
9
9
|
onBack?: () => void;
|
|
10
10
|
FormNode: ReactNode;
|
|
11
11
|
background?: AppBarBackground;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type KeyboardFormProps } from "../Form/Form.KeyboardForm.js";
|
|
2
2
|
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
3
3
|
import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl.js";
|
|
4
|
+
import type { ImageSource } from "../utils/image.js";
|
|
4
5
|
import React, { ReactNode } from "react";
|
|
5
|
-
import { type ImageSourcePropType } from "react-native";
|
|
6
6
|
interface FormViewProps<T> {
|
|
7
7
|
name: string;
|
|
8
8
|
description?: string;
|
|
@@ -41,7 +41,7 @@ interface HeaderProps {
|
|
|
41
41
|
*/
|
|
42
42
|
background?: AppBarBackground;
|
|
43
43
|
/** @deprecated Pass `variant` prop instead. */
|
|
44
|
-
logoSource?:
|
|
44
|
+
logoSource?: ImageSource;
|
|
45
45
|
}
|
|
46
46
|
declare function Header({ variant, tone, actions, children, topSpacing, background, }: HeaderProps): React.JSX.Element;
|
|
47
47
|
declare function HeaderActions({ children }: {
|
|
@@ -17,8 +17,9 @@ interface ListViewContextValue<T> {
|
|
|
17
17
|
onBack?: () => void;
|
|
18
18
|
onLoadMore?: () => void;
|
|
19
19
|
loadingMore?: boolean;
|
|
20
|
+
hasMore: boolean;
|
|
20
21
|
}
|
|
21
|
-
export declare function ListViewProvider<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, children, }: {
|
|
22
|
+
export declare function ListViewProvider<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, hasMore, children, }: {
|
|
22
23
|
name: string;
|
|
23
24
|
description?: string;
|
|
24
25
|
items: T[];
|
|
@@ -34,6 +35,7 @@ export declare function ListViewProvider<T>({ name, description, items, isLoadin
|
|
|
34
35
|
onBack?: () => void;
|
|
35
36
|
onLoadMore?: () => void;
|
|
36
37
|
loadingMore?: boolean;
|
|
38
|
+
hasMore?: boolean;
|
|
37
39
|
children: ReactNode;
|
|
38
40
|
}): import("react").JSX.Element;
|
|
39
41
|
export declare function useListView<T>(): ListViewContextValue<T>;
|
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useState } from "react";
|
|
2
|
+
import { createContext, useContext, useMemo, useState } from "react";
|
|
3
3
|
const Context = createContext(null);
|
|
4
|
-
export function ListViewProvider({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, children, }) {
|
|
4
|
+
export function ListViewProvider({ name, description, items, isLoading = false, hasError = false, errorMessage, readonly = false, onRefresh, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore = false, hasMore = true, children, }) {
|
|
5
5
|
const [showRefreshing, setShowRefreshing] = useState(false);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
6
|
+
const value = useMemo(() => ({
|
|
7
|
+
name,
|
|
8
|
+
description,
|
|
9
|
+
items,
|
|
10
|
+
isLoading,
|
|
11
|
+
hasError,
|
|
12
|
+
errorMessage,
|
|
13
|
+
readonly,
|
|
14
|
+
showRefreshing,
|
|
15
|
+
setShowRefreshing,
|
|
16
|
+
onRefresh,
|
|
17
|
+
onRetry,
|
|
18
|
+
onPressItem,
|
|
19
|
+
onDeleteItem,
|
|
20
|
+
onSearch,
|
|
21
|
+
onBack,
|
|
22
|
+
onLoadMore,
|
|
23
|
+
loadingMore,
|
|
24
|
+
hasMore,
|
|
25
|
+
}), [
|
|
26
|
+
name,
|
|
27
|
+
description,
|
|
28
|
+
items,
|
|
29
|
+
isLoading,
|
|
30
|
+
hasError,
|
|
31
|
+
errorMessage,
|
|
32
|
+
readonly,
|
|
33
|
+
showRefreshing,
|
|
34
|
+
onRefresh,
|
|
35
|
+
onRetry,
|
|
36
|
+
onPressItem,
|
|
37
|
+
onDeleteItem,
|
|
38
|
+
onSearch,
|
|
39
|
+
onBack,
|
|
40
|
+
onLoadMore,
|
|
41
|
+
loadingMore,
|
|
42
|
+
hasMore,
|
|
43
|
+
]);
|
|
44
|
+
return _jsx(Context.Provider, { value: value, children: children });
|
|
25
45
|
}
|
|
26
46
|
export function useListView() {
|
|
27
47
|
const context = useContext(Context);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type SearchHistoryProps } from "../Display/Display.SearchHistory.js";
|
|
2
2
|
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
3
3
|
import { type SegmentedControlProps } from "../Navigation/Navigation.SegmentedControl.js";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import { IRowItem } from "./types/IListView.js";
|
|
5
|
+
import React, { ReactNode, type Ref } from "react";
|
|
6
|
+
import { FlatList, type FlatListProps, type ScrollViewProps, StyleProp, ViewStyle } from "react-native";
|
|
6
7
|
interface ListViewProps<T> {
|
|
7
8
|
name: string;
|
|
8
9
|
description?: string;
|
|
@@ -22,12 +23,13 @@ interface ListViewProps<T> {
|
|
|
22
23
|
onLoadMore?: () => void;
|
|
23
24
|
/** Show a footer spinner while the next page loads. */
|
|
24
25
|
loadingMore?: boolean;
|
|
26
|
+
hasMore?: boolean;
|
|
25
27
|
backgroundColor?: string;
|
|
26
28
|
withContainer?: boolean;
|
|
27
29
|
children: ReactNode;
|
|
28
30
|
}
|
|
29
31
|
export declare function refreshListData(onRefresh: (() => Promise<void>) | undefined, onRefreshError: ((error: unknown) => void) | undefined, setShowRefreshing: (value: boolean) => void): Promise<void>;
|
|
30
|
-
declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRefreshError, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
|
|
32
|
+
declare function ListViewRoot<T>({ name, description, items, isLoading, hasError, errorMessage, readonly, onRefresh, onRefreshError, onRetry, onPressItem, onDeleteItem, onSearch, onBack, onLoadMore, loadingMore, hasMore, backgroundColor, withContainer, children, }: ListViewProps<T>): React.JSX.Element;
|
|
31
33
|
interface HeaderProps {
|
|
32
34
|
/** AppBar display variant. `large` = big title (list/index). `center` = modal/detail. */
|
|
33
35
|
variant?: "default" | "large" | "center";
|
|
@@ -82,14 +84,20 @@ declare function FilterChips({ children }: {
|
|
|
82
84
|
children: ReactNode;
|
|
83
85
|
}): React.JSX.Element;
|
|
84
86
|
type ListScrollProps = Pick<ScrollViewProps, "keyboardShouldPersistTaps" | "keyboardDismissMode" | "testID">;
|
|
85
|
-
|
|
87
|
+
export type ListViewVirtualizationProps = Pick<FlatListProps<IRowItem<unknown>>, "initialNumToRender" | "maxToRenderPerBatch" | "windowSize" | "updateCellsBatchingPeriod" | "removeClippedSubviews" | "extraData" | "getItemLayout" | "onViewableItemsChanged" | "viewabilityConfig" | "onEndReachedThreshold" | "maintainVisibleContentPosition">;
|
|
88
|
+
interface ListContentOptions {
|
|
89
|
+
listProps?: ListViewVirtualizationProps;
|
|
90
|
+
listRef?: Ref<FlatList<IRowItem<unknown>>>;
|
|
91
|
+
contentContainerStyle?: StyleProp<ViewStyle>;
|
|
92
|
+
}
|
|
93
|
+
declare function Content({ children, withMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, listProps, listRef, contentContainerStyle, }: {
|
|
86
94
|
children?: (item: any) => ReactNode;
|
|
87
95
|
withMargin?: boolean;
|
|
88
|
-
} & ListScrollProps): React.JSX.Element;
|
|
89
|
-
declare function ContentList({ children, contentWithMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, }: {
|
|
96
|
+
} & ListScrollProps & ListContentOptions): React.JSX.Element;
|
|
97
|
+
declare function ContentList({ children, contentWithMargin, keyboardShouldPersistTaps, keyboardDismissMode, testID, listProps, listRef, contentContainerStyle, }: {
|
|
90
98
|
children?: (item: any) => ReactNode;
|
|
91
99
|
contentWithMargin: boolean;
|
|
92
|
-
} & ListScrollProps): React.JSX.Element;
|
|
100
|
+
} & ListScrollProps & ListContentOptions): React.JSX.Element;
|
|
93
101
|
declare function Footer({ children }: {
|
|
94
102
|
children: ReactNode;
|
|
95
103
|
}): React.JSX.Element | null;
|