Skip to content
Draft
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
29 changes: 29 additions & 0 deletions example/src/modules/primitives/BadgeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
import React from "react";
// import {
// useAnimatedStyle,
// useSharedValue,
// withSpring,
// } from "react-native-reanimated";
import {
// AdaptAnimatedBox,
// AnimatedBox,
BadgeNew,
BadgeText,
BadgeWrapper,
Box,
Button,
SpinnerNew,
} from "@adaptui/react-native-tailwind";

export const BadgeScreen = () => {
// const x = useSharedValue(1);
// const animatedStyles = useAnimatedStyle(() => {
// return {
// transform: [
// { scale: withSpring(x.value) },
// { translateX: withSpring(x.value * 37) },
// { translateY: withSpring(x.value * 23) },
// ],
// };
// });
return (
<Box className="flex-1 justify-center items-center bg-white-900">
{/* <AnimatedBox
className="h-10 w-10 bg-grayDark-200 rounded-md border-red-200"
style={animatedStyles}
/>
<AdaptAnimatedBox
className="h-10 w-10 bg-grayDark-200 rounded-md border-[1.5px] border-red-200"
style={animatedStyles}
/> */}
<Button onPress={() => (x.value = Math.random())}>Animate</Button>
<SpinnerNew track="visible" />
<BadgeNew size="lg" className="my-1" themeColor="secondary">
Scheduled
</BadgeNew>
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from "./radio";
export * from "./select";
export * from "./slider";
export * from "./spinner";
export * from "./spinner-new";
export * from "./switch";
export * from "./tag";
export * from "./tooltip";
129 changes: 129 additions & 0 deletions src/components/spinner-new/Spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { useEffect } from "react";
import {
Easing,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from "react-native-reanimated";

import {
AnimatedBox,
AnimatedBoxOptions,
useAnimatedBox,
} from "../../primitives/animated-box";
import { useTheme } from "../../theme";
import { cx, styleAdapter } from "../../utils";
import { GetThemeValue } from "../../utils/global-types";
import {
As,
createComponentType,
createElement,
createHook,
Props,
} from "../../utils/system";

export const useSpinner = createHook<SpinnerOptions>(
({
size = "md",
themeColor = "base",
track = "transparent",
label = "Loading...",
...props
}) => {
const tailwind = useTheme();
const spinnerTheme = useTheme("spinner");

const spinnerLoopAnimation = useSharedValue(0);
useEffect(() => {
spinnerLoopAnimation.value = withRepeat(
withTiming(360, {
duration: 1000,
easing: Easing.linear,
}),
-1,
false,
);
}, [spinnerLoopAnimation]);
const spinnerLoadingStyle = useAnimatedStyle(() => {
return {
transform: [
{
rotate: `${spinnerLoopAnimation.value}deg`,
},
],
};
});

const style = [
tailwind.style(
cx(
spinnerTheme.base,
spinnerTheme.themeColor[themeColor],
track === "visible"
? spinnerTheme.track[track]?.[themeColor]
: spinnerTheme.track.transparent,
spinnerTheme.size[size],
),
),
{ borderWidth: spinnerTheme.borderWidth },
styleAdapter(props.style),
spinnerLoadingStyle,
];

props = {
...props,
accessibilityLabel: label,
style,
// Web Prop
"data-testid": "testid-spinner",
};
props = useAnimatedBox(props);

return props;
},
);

export const SpinnerNew = createComponentType<SpinnerOptions>(props => {
const htmlProps = useSpinner(props);

return createElement(AnimatedBox, htmlProps);
}, "Spinner");

export type SpinnerOptions<T extends As = typeof AnimatedBox> = Omit<
AnimatedBoxOptions<T>,
"size"
> & {
/**
* How large should the spinner be?
*
* @default md
*/
size?: keyof GetThemeValue<"spinner", "size">;

/**
* How the spinner should be themed?
*
* @default base
*/
themeColor?: keyof GetThemeValue<"spinner", "themeColor">;

/**
* How the spinner should be displayed?
*
* @default transparent
*/
track?: keyof GetThemeValue<"spinner", "track">;

/**
* For accessibility, it is important to add a fallback loading text.
* This text will be visible to screen readers.
*
* @default Loading...
*/
label?: string;
};

export type SpinnerNewProps<T extends As = typeof AnimatedBox> = Props<
SpinnerOptions<T>
>;
1 change: 1 addition & 0 deletions src/components/spinner-new/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Spinner";
41 changes: 41 additions & 0 deletions src/primitives/animated-box/AdaptAnimatedBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useTheme } from "../../theme";
import { styleAdapter } from "../../utils";
import {
As,
createComponent,
createElement,
createHook,
Props,
} from "../../utils/system";
import { useBox } from "../box";

import { AnimatedBox, AnimatedBoxOptions, useAnimatedBox } from "./AnimatedBox";

export const useAdaptAnimatedBox = createHook<AdaptAnimatedBoxOptions>(
({ __TYPE__, className, ...props }) => {
const tailwind = useTheme();
const style = [tailwind.style(className), styleAdapter(props.style)];

props = useAnimatedBox(props);
props = useBox(props);

return { ...props, style };
},
);

export const AdaptAnimatedBox = createComponent<AdaptAnimatedBoxOptions>(
props => {
const htmlProps = useAdaptAnimatedBox(props);

return createElement(AnimatedBox, htmlProps);
},
);

export type AdaptAnimatedBoxOptions<T extends As = typeof AnimatedBox> =
AnimatedBoxOptions<T> & {
className?: string;
};

export type AdaptAnimatedBoxProps<T extends As = typeof AnimatedBox> = Props<
AdaptAnimatedBoxOptions<T>
>;
27 changes: 25 additions & 2 deletions src/primitives/animated-box/AnimatedBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
import Animated from "react-native-reanimated";

import { createComponent } from "../../utils";
import {
As,
ComponentOptions,
createComponent,
createElement,
createHook,
Props,
} from "../../utils/system";
import { Box } from "../box";

// @ts-ignore
const RNAnimatedBox = Animated.createAnimatedComponent(Box);

export const AnimatedBox = createComponent(RNAnimatedBox, { shouldMemo: true });
export const useAnimatedBox = createHook<AnimatedBoxOptions>(
({ __TYPE__, ...props }) => {
return props;
},
);

export const AnimatedBox = createComponent<AnimatedBoxOptions>(props => {
const htmlProps = useAnimatedBox(props);
return createElement(RNAnimatedBox, htmlProps);
});

export type AnimatedBoxOptions<T extends As = typeof RNAnimatedBox> =
ComponentOptions<T>;

export type AnimatedBoxProps<T extends As = typeof RNAnimatedBox> = Props<
AnimatedBoxOptions<T>
>;
1 change: 1 addition & 0 deletions src/primitives/animated-box/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./AdaptAnimatedBox";
export * from "./AnimatedBox";
4 changes: 3 additions & 1 deletion src/utils/styleAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import {
StyleSheet,
ViewStyle,
} from "react-native";
import Animated from "react-native-reanimated";

import { runIfFn } from "./react";

export const styleAdapter = (
style:
| StyleProp<ViewStyle>
| ((state: PressableStateCallbackType) => StyleProp<ViewStyle>),
| ((state: PressableStateCallbackType) => StyleProp<ViewStyle>)
| StyleProp<Animated.AnimateStyle<StyleProp<ViewStyle>>>,
touchState?: PressableStateCallbackType,
): ViewStyle | Falsy | RegisteredStyle<ViewStyle> => {
const _style = touchState ? runIfFn(style, touchState) : style;
Expand Down