Skip to content

refactor(badge): ♻️ move to ariakit system #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion example/src/AppRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const Drawer = createDrawerNavigator();

const AppRoot = () => {
return (
<Drawer.Navigator initialRouteName="ButtonScreen">
<Drawer.Navigator initialRouteName="BadgeScreen">
<Drawer.Screen
options={{ title: "Avatar" }}
name="AvatarScreen"
Expand Down
70 changes: 11 additions & 59 deletions example/src/modules/primitives/BadgeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,22 @@
import React from "react";
import {
Badge,
BadgeNew,
BadgeText,
BadgeWrapper,
Box,
Check,
Clock,
Close,
Icon,
useTheme,
} from "@adaptui/react-native-tailwind";

export const BadgeScreen = () => {
const tailwind = useTheme();
return (
<Box
style={tailwind.style("flex-1 justify-center items-center bg-white-900")}
>
<Badge style={tailwind.style("my-1")} themeColor="secondary">
<Box className="flex-1 justify-center items-center bg-white-900">
<BadgeNew size="lg" className="my-1" themeColor="secondary">
Scheduled
</Badge>
<Badge
style={tailwind.style("my-1")}
themeColor="primary"
size="lg"
variant="outline"
>
Assigned
</Badge>
<Badge
style={tailwind.style("my-1")}
themeColor="primary"
variant="subtle"
prefix={<Icon icon={<Clock />} />}
>
On Progress
</Badge>
<Badge
style={tailwind.style("my-1")}
size="md"
themeColor="secondary"
variant="outline"
>
Confirmed
</Badge>
<Badge
style={tailwind.style("my-1")}
themeColor="danger"
prefix={<Icon icon={<Close />} />}
>
Cancelled
</Badge>
<Badge
style={tailwind.style("my-1")}
themeColor="success"
prefix={<Icon icon={<Check />} />}
>
Completed
</Badge>

<Badge
style={tailwind.style("my-1")}
size="sm"
themeColor="success"
variant="outline"
>
Done
</Badge>
</BadgeNew>
<BadgeNew size="md" className="my-1 bg-teal-500" themeColor="secondary">
<>Badge</>
<BadgeWrapper className="bg-yellow-500" />
<BadgeText className="text-red-500" />
</BadgeNew>
</Box>
);
};
1 change: 1 addition & 0 deletions example/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@adaptui/react-native-tailwind": ["../src/index"]
}
Expand Down
18 changes: 18 additions & 0 deletions src/components/badge-new/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from "react";
import { View } from "react-native";

import { BadgeNewProps, useBadgeProps } from "./BadgeProps";
import { BadgeText } from "./BadgeText";
import { BadgeWrapper } from "./BadgeWrapper";

export const BadgeNew = React.forwardRef<View, BadgeNewProps>((props, ref) => {
const { wrapperProps, textProps } = useBadgeProps(props);

return (
<BadgeWrapper ref={ref} {...wrapperProps}>
<BadgeText {...textProps} />
</BadgeWrapper>
);
});

BadgeNew.displayName = "BadgeNew";
66 changes: 66 additions & 0 deletions src/components/badge-new/BadgeProps.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useMemo } from "react";

import { getComponentProps, RenderProp } from "../../utils/system";

import { BadgeTextProps } from "./BadgeText";
import {
BadgeUIState,
BadgeUIStateProps,
useBadgeUIState,
} from "./BadgeUIState";
import { BadgeWrapperProps } from "./BadgeWrapper";

const componentMap = {
BadgeWrapper: "wrapperProps",
BadgeText: "textProps",
};

export function useBadgeProps(props: BadgeNewProps): BadgePropsReturn {
let { size, themeColor, variant, children, ...restProps } = props;

const uiState = useBadgeUIState({
size,
themeColor,
variant,
});
let uiProps: BadgeUIProps = useMemo(() => ({ ...uiState }), [uiState]);

const { componentProps, finalChildren } = getComponentProps(
componentMap,
children,
uiProps,
);
const _finalChildren = componentProps?.textProps?.children || finalChildren;
const wrapperProps: BadgeWrapperProps = useMemo(
() => ({
...uiProps,
...restProps,
...componentProps.wrapperProps,
}),
[componentProps.wrapperProps, restProps, uiProps],
);

const textProps: BadgeTextProps = useMemo(
() => ({
...uiProps,
...componentProps.textProps,
children: _finalChildren,
}),
[componentProps.textProps, uiProps, _finalChildren],
);

return { uiProps, wrapperProps, textProps };
}

export type BadgeUIProps = BadgeUIState & {};

export type BadgeNewProps = Omit<BadgeWrapperProps, "children"> &
BadgeUIStateProps & {
children?: RenderProp<BadgeUIProps>;
};

export type BadgePropsReturn = {
uiProps: BadgeUIProps;
wrapperProps: BadgeWrapperProps;
textProps: BadgeTextProps;
};
46 changes: 46 additions & 0 deletions src/components/badge-new/BadgeText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
AdaptText,
AdaptTextOptions,
useAdaptText,
} from "../../primitives/text";
import { useTheme } from "../../theme";
import { cx } from "../../utils";
import {
As,
createComponentType,
createElement,
createHook,
Props,
} from "../../utils/system";

import { BadgeUIProps } from "./BadgeProps";

export const useBadgeText = createHook<BadgeTextOptions>(
({ size, themeColor, variant, ...props }) => {
const badgeStyles = useTheme("badge");
const className = cx(
size ? badgeStyles.size[size]?.text : "",
themeColor && variant
? badgeStyles.themeColor[themeColor]?.[variant]?.text
: "",
props.className,
);

props = useAdaptText({ ...props, className });

return props;
},
);

export const BadgeText = createComponentType<BadgeTextOptions>(props => {
const htmlProps = useBadgeText(props);

return createElement(AdaptText, htmlProps);
}, "BadgeText");

export type BadgeTextOptions<T extends As = typeof AdaptText> =
AdaptTextOptions<T> & Partial<BadgeUIProps> & {};

export type BadgeTextProps<T extends As = typeof AdaptText> = Props<
BadgeTextOptions<T>
>;
32 changes: 32 additions & 0 deletions src/components/badge-new/BadgeUIState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { GetThemeValue } from "../../utils/global-types";

export const useBadgeUIState = (props: BadgeUIStateProps): BadgeUIState => {
const { size = "md", themeColor = "base", variant = "solid" } = props;

return { size, themeColor, variant };
};

export type BadgeUIState = {
/**
* How large should the badge be?
*
* @default md
*/
size: keyof GetThemeValue<"badge", "size">;
/**
* How the badge should be themed?
*
* @default base
*/
themeColor: keyof GetThemeValue<"badge", "themeColor">;
/**
* How the badge should look?
*
* @default solid
*/
variant: keyof GetThemeValue<"badge", "themeColor", "base">;
};

export type BadgeUIStateProps = Partial<
Pick<BadgeUIState, "size" | "themeColor" | "variant">
> & {};
43 changes: 43 additions & 0 deletions src/components/badge-new/BadgeWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Box, BoxOptions, useBox } from "../../primitives/box";
import { useTheme } from "../../theme";
import { cx } from "../../utils";
import {
As,
createComponentType,
createElement,
createHook,
Props,
} from "../../utils/system";

import { BadgeUIProps } from "./BadgeProps";

export const useBadgeWrapper = createHook<BadgeWrapperOptions>(
({ size, themeColor, variant, ...props }) => {
const badgeStyles = useTheme("badge");
const className = cx(
badgeStyles.baseContainer,
size ? badgeStyles.size[size]?.container : "",
themeColor && variant
? badgeStyles.themeColor[themeColor]?.[variant]?.container
: "",
props.className,
);

props = useBox({ ...props, className });

return props;
},
);

export const BadgeWrapper = createComponentType<BadgeWrapperOptions>(props => {
const htmlProps = useBadgeWrapper(props);

return createElement(Box, htmlProps);
}, "BadgeWrapper");

export type BadgeWrapperOptions<T extends As = typeof Box> = BoxOptions<T> &
Partial<BadgeUIProps> & {};

export type BadgeWrapperProps<T extends As = typeof Box> = Props<
BadgeWrapperOptions<T>
>;
5 changes: 5 additions & 0 deletions src/components/badge-new/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./Badge";
export * from "./BadgeProps";
export * from "./BadgeText";
export * from "./BadgeUIState";
export * from "./BadgeWrapper";
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./avatar";
export * from "./avatar-group";
export * from "./badge";
export * from "./badge-new";
export * from "./button";
export * from "./checkbox";
export * from "./circular-progress";
Expand Down
34 changes: 28 additions & 6 deletions src/primitives/box/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { View, ViewProps as RNViewProps } from "react-native";
import { View } from "react-native";

import { createComponent } from "../../utils/createComponent";
import type { Dict } from "../../utils/types";
import { useTheme } from "../../theme";
import { styleAdapter } from "../../utils";
import {
As,
ComponentOptions,
createComponentType,
createElement,
createHook,
Props,
} from "../../utils/system";

export type LibraryBoxProps = Dict<unknown>;
export const useBox = createHook<BoxOptions>(
({ __TYPE__, className, ...props }) => {
const tailwind = useTheme();
const style = [tailwind.style(className), styleAdapter(props.style)];

export type BoxProps = RNViewProps & LibraryBoxProps;
return { ...props, style };
},
);

export const Box = createComponent<BoxProps>(View, { shouldMemo: true });
export const Box = createComponentType<BoxOptions>(props => {
const htmlProps = useBox(props);
return createElement(View, htmlProps);
}, "Box");

export type BoxOptions<T extends As = typeof View> = ComponentOptions<T> & {
className?: string;
};

export type BoxProps<T extends As = typeof View> = Props<BoxOptions<T>>;
29 changes: 29 additions & 0 deletions src/primitives/text/AdaptText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
As,
createComponent,
createElement,
createHook,
Props,
} from "../../utils/system";
import { BoxOptions, useBox } from "../box";

import { Text, TextOptions, useText } from "./Text";

export const useAdaptText = createHook<AdaptTextOptions>(props => {
props = useText(props);
props = useBox(props);

return props;
});

export const AdaptText = createComponent<AdaptTextOptions>(props => {
const htmlProps = useAdaptText(props);
return createElement(Text, htmlProps);
});

export type AdaptTextOptions<T extends As = typeof Text> = TextOptions<T> &
BoxOptions<T>;

export type AdaptTextProps<T extends As = typeof Text> = Props<
AdaptTextOptions<T>
>;
Loading