@sincpro/mobile-ui 0.6.0 → 0.7.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/Dialog/Confirmation.context.js +1 -6
- package/dist/Feedback/Feedback.Loading.d.ts +3 -7
- package/dist/Feedback/Feedback.Loading.js +2 -8
- package/dist/Feedback/Feedback.Spinner.d.ts +3 -0
- package/dist/Feedback/Feedback.Spinner.js +52 -2
- package/dist/Feedback/index.d.ts +0 -2
- package/dist/Feedback/index.js +0 -2
- package/dist/Form/Form.PasswordInput.js +4 -2
- package/dist/layouts/AuthContainer.d.ts +4 -1
- package/dist/layouts/AuthContainer.js +7 -5
- package/dist/views/AppSplashView.d.ts +18 -0
- package/dist/views/AppSplashView.js +9 -0
- package/dist/views/AuthFormView.d.ts +3 -1
- package/dist/views/AuthFormView.js +2 -2
- package/package.json +1 -1
|
@@ -56,12 +56,7 @@ export function ConfirmationProvider({ children }) {
|
|
|
56
56
|
export function useConfirmationContext() {
|
|
57
57
|
const context = useContext(ConfirmationContext);
|
|
58
58
|
if (!context) {
|
|
59
|
-
|
|
60
|
-
console.warn("useConfirmationContext called before ConfirmationProvider mounted");
|
|
61
|
-
return {
|
|
62
|
-
show: () => { },
|
|
63
|
-
hide: () => { },
|
|
64
|
-
};
|
|
59
|
+
return { show: () => { }, hide: () => { } };
|
|
65
60
|
}
|
|
66
61
|
return context;
|
|
67
62
|
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
+
import { type SpinnerVariant } from "../Feedback/Feedback.Spinner";
|
|
1
2
|
import type React from "react";
|
|
2
3
|
interface LoadingStateProps {
|
|
3
4
|
message?: string;
|
|
4
5
|
size?: "small" | "large";
|
|
6
|
+
variant?: SpinnerVariant;
|
|
5
7
|
style?: object;
|
|
6
8
|
className?: string;
|
|
7
9
|
}
|
|
8
|
-
|
|
9
|
-
* Full-screen centered loading state. Thin layout convenience over `Spinner` (the atom):
|
|
10
|
-
* `Spinner` is the inline indicator (ActivityIndicator + optional text); `LoadingState`
|
|
11
|
-
* is `Spinner` centered with `flex-1` for an empty screen/section. Use `Spinner` directly
|
|
12
|
-
* when you need an inline/footer indicator (e.g. pagination), `LoadingState` for a blank view.
|
|
13
|
-
*/
|
|
14
|
-
declare function LoadingState({ message, size, style, className, }: LoadingStateProps): React.JSX.Element;
|
|
10
|
+
declare function LoadingState({ message, size, variant, style, className, }: LoadingStateProps): React.JSX.Element;
|
|
15
11
|
export default LoadingState;
|
|
@@ -2,13 +2,7 @@ import { jsx as _jsx } from "nativewind/jsx-runtime";
|
|
|
2
2
|
import Spinner from "../Feedback/Feedback.Spinner";
|
|
3
3
|
import { cn } from "../theme/tw";
|
|
4
4
|
import { View } from "react-native";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* `Spinner` is the inline indicator (ActivityIndicator + optional text); `LoadingState`
|
|
8
|
-
* is `Spinner` centered with `flex-1` for an empty screen/section. Use `Spinner` directly
|
|
9
|
-
* when you need an inline/footer indicator (e.g. pagination), `LoadingState` for a blank view.
|
|
10
|
-
*/
|
|
11
|
-
function LoadingState({ message = "Cargando…", size = "small", style = {}, className, }) {
|
|
12
|
-
return (_jsx(View, { className: cn("flex-1 justify-center items-center", className), style: style, children: _jsx(Spinner, { className: "mb-5", size: size, text: message }) }));
|
|
5
|
+
function LoadingState({ message = "Cargando…", size = "small", variant = "spinner", style = {}, className, }) {
|
|
6
|
+
return (_jsx(View, { className: cn("flex-1 justify-center items-center", className), style: style, children: _jsx(Spinner, { className: "mb-5", size: size, text: message, variant: variant }) }));
|
|
13
7
|
}
|
|
14
8
|
export default LoadingState;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type React from "react";
|
|
2
2
|
import { type ViewStyle } from "react-native";
|
|
3
|
+
export type SpinnerVariant = "spinner" | "dots" | "ripple";
|
|
3
4
|
export interface SpinnerProps {
|
|
5
|
+
/** Visual style of the loading indicator. Defaults to `"spinner"`. */
|
|
6
|
+
variant?: SpinnerVariant;
|
|
4
7
|
size?: "small" | "large";
|
|
5
8
|
color?: string;
|
|
6
9
|
text?: string;
|
|
@@ -2,8 +2,58 @@ import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
|
2
2
|
import { theme } from "../theme";
|
|
3
3
|
import { cn } from "../theme/tw";
|
|
4
4
|
import { Typography } from "../Typography";
|
|
5
|
+
import { useEffect } from "react";
|
|
5
6
|
import { ActivityIndicator, View } from "react-native";
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withRepeat, withSequence, withTiming, } from "react-native-reanimated";
|
|
8
|
+
function DotsLoader({ color, size }) {
|
|
9
|
+
const dotSize = size === "large" ? 11 : 8;
|
|
10
|
+
const bounce = size === "large" ? 13 : 9;
|
|
11
|
+
const dot = {
|
|
12
|
+
width: dotSize,
|
|
13
|
+
height: dotSize,
|
|
14
|
+
borderRadius: dotSize / 2,
|
|
15
|
+
backgroundColor: color,
|
|
16
|
+
};
|
|
17
|
+
const y1 = useSharedValue(0);
|
|
18
|
+
const y2 = useSharedValue(0);
|
|
19
|
+
const y3 = useSharedValue(0);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const seq = withRepeat(withSequence(withTiming(-bounce, { duration: 280, easing: Easing.out(Easing.quad) }), withTiming(0, { duration: 280, easing: Easing.in(Easing.quad) }), withTiming(0, { duration: 200 })), -1, false);
|
|
22
|
+
y1.value = withDelay(0, seq);
|
|
23
|
+
y2.value = withDelay(160, seq);
|
|
24
|
+
y3.value = withDelay(320, seq);
|
|
25
|
+
}, []);
|
|
26
|
+
const s1 = useAnimatedStyle(() => ({ transform: [{ translateY: y1.value }] }));
|
|
27
|
+
const s2 = useAnimatedStyle(() => ({ transform: [{ translateY: y2.value }] }));
|
|
28
|
+
const s3 = useAnimatedStyle(() => ({ transform: [{ translateY: y3.value }] }));
|
|
29
|
+
return (_jsxs(View, { style: { flexDirection: "row", gap: 10, alignItems: "center" }, children: [_jsx(Animated.View, { style: [dot, s1] }), _jsx(Animated.View, { style: [dot, s2] }), _jsx(Animated.View, { style: [dot, s3] })] }));
|
|
30
|
+
}
|
|
31
|
+
function RippleLoader({ color, size }) {
|
|
32
|
+
const base = size === "large" ? 48 : 32;
|
|
33
|
+
const scale = useSharedValue(0.2);
|
|
34
|
+
const opacity = useSharedValue(0.85);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
scale.value = withRepeat(withTiming(2.6, { duration: 1400, easing: Easing.out(Easing.quad) }), -1, false);
|
|
37
|
+
opacity.value = withRepeat(withTiming(0, { duration: 1400, easing: Easing.in(Easing.quad) }), -1, false);
|
|
38
|
+
}, []);
|
|
39
|
+
const animStyle = useAnimatedStyle(() => ({
|
|
40
|
+
transform: [{ scale: scale.value }],
|
|
41
|
+
opacity: opacity.value,
|
|
42
|
+
}));
|
|
43
|
+
return (_jsx(View, { style: { width: base, height: base, alignItems: "center", justifyContent: "center" }, children: _jsx(Animated.View, { style: [
|
|
44
|
+
{
|
|
45
|
+
width: base,
|
|
46
|
+
height: base,
|
|
47
|
+
borderRadius: base / 2,
|
|
48
|
+
borderWidth: 2.5,
|
|
49
|
+
borderColor: color,
|
|
50
|
+
position: "absolute",
|
|
51
|
+
},
|
|
52
|
+
animStyle,
|
|
53
|
+
] }) }));
|
|
54
|
+
}
|
|
55
|
+
const Spinner = ({ variant = "spinner", size = "large", color = theme.primary, text, style, className, }) => {
|
|
56
|
+
const indicator = variant === "dots" ? (_jsx(DotsLoader, { color: color, size: size })) : variant === "ripple" ? (_jsx(RippleLoader, { color: color, size: size })) : (_jsx(ActivityIndicator, { color: color, size: size }));
|
|
57
|
+
return (_jsxs(View, { className: cn("items-center justify-center", className), style: style, children: [indicator, text && (_jsx(Typography.Text, { className: "mt-2.5 text-base", variant: "body", children: text }))] }));
|
|
8
58
|
};
|
|
9
59
|
export default Spinner;
|
package/dist/Feedback/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Banner from "../Feedback/Feedback.Banner";
|
|
2
|
-
import DomainSplashScreen from "../Feedback/Feedback.DomainSplashScreen";
|
|
3
2
|
import Empty from "../Feedback/Feedback.Empty";
|
|
4
3
|
import EmptyState from "../Feedback/Feedback.EmptyState";
|
|
5
4
|
import Error from "../Feedback/Feedback.Error";
|
|
@@ -23,6 +22,5 @@ export declare const Feedback: {
|
|
|
23
22
|
EmptyState: typeof EmptyState;
|
|
24
23
|
Error: typeof Error;
|
|
25
24
|
SplashScreen: typeof SplashScreen;
|
|
26
|
-
DomainSplashScreen: typeof DomainSplashScreen;
|
|
27
25
|
};
|
|
28
26
|
export default Feedback;
|
package/dist/Feedback/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Banner from "../Feedback/Feedback.Banner";
|
|
2
|
-
import DomainSplashScreen from "../Feedback/Feedback.DomainSplashScreen";
|
|
3
2
|
import Empty from "../Feedback/Feedback.Empty";
|
|
4
3
|
import EmptyState from "../Feedback/Feedback.EmptyState";
|
|
5
4
|
import Error from "../Feedback/Feedback.Error";
|
|
@@ -24,6 +23,5 @@ export const Feedback = {
|
|
|
24
23
|
EmptyState,
|
|
25
24
|
Error,
|
|
26
25
|
SplashScreen,
|
|
27
|
-
DomainSplashScreen,
|
|
28
26
|
};
|
|
29
27
|
export default Feedback;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { Display } from "../Display";
|
|
3
3
|
import InputField from "../Form/Form.InputField";
|
|
4
|
+
import { useTheme } from "../theme";
|
|
4
5
|
import { useState } from "react";
|
|
5
6
|
import { TouchableOpacity, View } from "react-native";
|
|
6
7
|
const PasswordField = ({ label, error, inputProps }) => {
|
|
8
|
+
const theme = useTheme();
|
|
7
9
|
const [showPassword, setShowPassword] = useState(false);
|
|
8
10
|
return (_jsxs(View, { className: "mb-4 relative", children: [_jsx(InputField, { error: error, inputProps: {
|
|
9
11
|
...inputProps,
|
|
10
12
|
secureTextEntry: !showPassword,
|
|
11
13
|
autoComplete: "off",
|
|
12
14
|
importantForAutofill: "no",
|
|
13
|
-
}, label: label }), _jsx(TouchableOpacity, { className: "absolute right-3 bottom-[25px]", onPress: () => setShowPassword(!showPassword), children: _jsx(
|
|
15
|
+
}, label: label }), _jsx(TouchableOpacity, { className: "absolute right-3 bottom-[25px]", hitSlop: 8, onPress: () => setShowPassword(!showPassword), children: _jsx(Display.Icon, { color: theme.text.primary, name: showPassword ? "eye-off-outline" : "eye-outline", size: 22, type: "ionicons" }) })] }));
|
|
14
16
|
};
|
|
15
17
|
export default PasswordField;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
|
|
1
2
|
import { ReactNode } from "react";
|
|
2
3
|
interface AuthContainerProps {
|
|
3
4
|
header: ReactNode;
|
|
4
5
|
children: ReactNode;
|
|
5
6
|
onBackPress?: () => void;
|
|
6
7
|
className?: string;
|
|
8
|
+
/** Gradient + pattern surface for the header area. Defaults to `night-green` preset. */
|
|
9
|
+
background?: AppBarBackground;
|
|
7
10
|
}
|
|
8
|
-
declare function AuthContainer({ header, children, onBackPress, className }: AuthContainerProps): import("react").JSX.Element;
|
|
11
|
+
declare function AuthContainer({ header, children, onBackPress, background, className, }: AuthContainerProps): import("react").JSX.Element;
|
|
9
12
|
export default AuthContainer;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
2
|
import { Display } from "../Display";
|
|
3
3
|
import GradientSurface from "../Display/Display.GradientSurface";
|
|
4
|
-
import {
|
|
4
|
+
import { Pattern } from "../Display/Display.Pattern";
|
|
5
|
+
import { useTheme } from "../theme";
|
|
5
6
|
import { cn } from "../theme/tw";
|
|
6
|
-
import {
|
|
7
|
+
import { Keyboard, TouchableOpacity, TouchableWithoutFeedback, useWindowDimensions, View, } from "react-native";
|
|
7
8
|
import { KeyboardAwareScrollView } from "react-native-keyboard-controller";
|
|
8
9
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
9
|
-
function AuthContainer({ header, children, onBackPress, className }) {
|
|
10
|
-
const screenHeight =
|
|
11
|
-
|
|
10
|
+
function AuthContainer({ header, children, onBackPress, background, className, }) {
|
|
11
|
+
const { height: screenHeight } = useWindowDimensions();
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
return (_jsxs(GradientSurface, { className: cn("flex-1", className), colors: background?.colors, end: background?.end ?? (background?.colors ? { x: 0, y: 1 } : undefined), preset: background?.surface ?? "night-green", radius: "none", start: background?.start ?? (background?.colors ? { x: 0, y: 0 } : undefined), style: { flex: 1 }, children: [background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, _jsx(SafeAreaView, { className: "flex-1", edges: ["top"], children: _jsxs(View, { className: "flex-1", children: [_jsx(TouchableWithoutFeedback, { onPress: Keyboard.dismiss, children: _jsxs(View, { className: "justify-center items-center relative", style: { height: screenHeight * 0.3 }, children: [onBackPress && (_jsx(TouchableOpacity, { className: "absolute top-4 left-4 p-2 z-[1]", onPress: onBackPress, children: _jsx(Display.Icon, { color: background?.textColor ?? theme.text.inverse, name: "arrow-back", size: 24, type: "ionicons" }) })), header] }) }), _jsx(View, { className: "flex-1 bg-bg-card rounded-t-3xl shadow-lg", style: { minHeight: screenHeight * 0.7 }, children: _jsx(KeyboardAwareScrollView, { bottomOffset: 50, bounces: false, className: "flex-1", contentContainerClassName: "flex-grow pb-10", keyboardShouldPersistTaps: "handled", showsVerticalScrollIndicator: false, children: _jsx(View, { className: "p-4", children: children }) }) })] }) })] }));
|
|
12
14
|
}
|
|
13
15
|
export default AuthContainer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type SpinnerVariant } from "../Feedback/Feedback.Spinner";
|
|
2
|
+
import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { type ImageSourcePropType, type ViewStyle } from "react-native";
|
|
5
|
+
export interface AppSplashViewProps {
|
|
6
|
+
/** Gradient + pattern background. Defaults to `night-green` preset. */
|
|
7
|
+
background?: AppBarBackground;
|
|
8
|
+
/** App logo shown centered above the loading indicator. */
|
|
9
|
+
logo?: ImageSourcePropType;
|
|
10
|
+
/** Built-in loading animation variant. Ignored when `loader` is provided. Defaults to `"dots"`. */
|
|
11
|
+
loadingVariant?: SpinnerVariant;
|
|
12
|
+
/** Fully custom loading element. Takes precedence over `loadingVariant`. */
|
|
13
|
+
loader?: ReactNode;
|
|
14
|
+
/** Override the outer container style. */
|
|
15
|
+
style?: ViewStyle;
|
|
16
|
+
}
|
|
17
|
+
export declare function AppSplashView({ background, logo, loadingVariant, loader, style, }: AppSplashViewProps): import("react").JSX.Element;
|
|
18
|
+
export default AppSplashView;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
+
import GradientSurface from "../Display/Display.GradientSurface";
|
|
3
|
+
import { Pattern } from "../Display/Display.Pattern";
|
|
4
|
+
import Spinner from "../Feedback/Feedback.Spinner";
|
|
5
|
+
import { Image, View } from "react-native";
|
|
6
|
+
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(Image, { source: logo, style: { width: 140, height: 140, resizeMode: "contain", marginBottom: 40 } })) : null, loader ?? (_jsx(Spinner, { color: "rgba(255,255,255,0.9)", size: "large", variant: loadingVariant }))] })] }));
|
|
8
|
+
}
|
|
9
|
+
export default AppSplashView;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
|
|
1
2
|
import { ReactNode } from "react";
|
|
2
3
|
import { type ImageSourcePropType } from "react-native";
|
|
3
4
|
interface AuthFormProps {
|
|
@@ -6,6 +7,7 @@ interface AuthFormProps {
|
|
|
6
7
|
logoSource?: ImageSourcePropType;
|
|
7
8
|
onBack?: () => void;
|
|
8
9
|
FormNode: ReactNode;
|
|
10
|
+
background?: AppBarBackground;
|
|
9
11
|
}
|
|
10
|
-
declare function AuthFormView({ title, description, logoSource, onBack, FormNode }: AuthFormProps): import("react").JSX.Element;
|
|
12
|
+
declare function AuthFormView({ title, description, logoSource, onBack, FormNode, background, }: AuthFormProps): import("react").JSX.Element;
|
|
11
13
|
export default AuthFormView;
|
|
@@ -5,7 +5,7 @@ import { Typography } from "../Typography";
|
|
|
5
5
|
import { View } from "react-native";
|
|
6
6
|
const Logo = Display.Logo;
|
|
7
7
|
const Text = Typography.Text;
|
|
8
|
-
function AuthFormView({ title, description, logoSource, onBack, FormNode }) {
|
|
8
|
+
function AuthFormView({ title, description, logoSource, onBack, FormNode, background, }) {
|
|
9
9
|
const renderTitle = () => {
|
|
10
10
|
if (!title)
|
|
11
11
|
return null;
|
|
@@ -16,6 +16,6 @@ function AuthFormView({ title, description, logoSource, onBack, FormNode }) {
|
|
|
16
16
|
return null;
|
|
17
17
|
return _jsx(Text, { variant: "body", children: description });
|
|
18
18
|
};
|
|
19
|
-
return (_jsx(AuthContainer, { header: _jsx(Logo, { size: "large", source: logoSource }), onBackPress: onBack, children: _jsxs(View, { className: "m-4", children: [_jsxs(View, { className: "mb-5", children: [renderTitle(), renderDescription()] }), FormNode] }) }));
|
|
19
|
+
return (_jsx(AuthContainer, { background: background, header: _jsx(Logo, { size: "large", source: logoSource }), onBackPress: onBack, children: _jsxs(View, { className: "m-4", children: [_jsxs(View, { className: "mb-5", children: [renderTitle(), renderDescription()] }), FormNode] }) }));
|
|
20
20
|
}
|
|
21
21
|
export default AuthFormView;
|
package/package.json
CHANGED