Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
cgjohn committed Dec 5, 2024
2 parents 3471b82 + 99bb6d0 commit e73c094
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 18 deletions.
28 changes: 27 additions & 1 deletion packages/mobile-app/app/(tabs)/balances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
HStack,
Icon,
IconButton,
Tabs,
Text,
VStack,
} from "@ironfish/tackle-box";
Expand Down Expand Up @@ -31,7 +32,32 @@ export default function Balances() {
flexGrow={1}
borderTopLeftRadius={20}
borderTopRightRadius={20}
/>
>
<Tabs.Root defaultValue="assets">
<Tabs.List>
<Tabs.Trigger value="assets">Assets</Tabs.Trigger>
<Tabs.Trigger value="transactions">Transactions</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="assets">
<VStack>
<Text>Assets</Text>
<Text>Assets</Text>
<Text>Assets</Text>
<Text>Assets</Text>
<Text>Assets</Text>
</VStack>
</Tabs.Content>
<Tabs.Content value="transactions">
<VStack>
<Text>Transactions</Text>
<Text>Transactions</Text>
<Text>Transactions</Text>
<Text>Transactions</Text>
<Text>Transactions</Text>
</VStack>
</Tabs.Content>
</Tabs.Root>
</Box>
</SafeAreaGradient>
);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/mobile-app/app/onboarding/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function OnboardingCreate() {
<Text textAlign="center" size="xl">
Protect your account
</Text>
<Text textAlign="center" muted>
<Text textAlign="center" color="textSecondary">
Enabling biometric security or a PIN, your wallet becomes
exclusively accessible to you, providing a unique layer of
protection.
Expand All @@ -44,7 +44,7 @@ export default function OnboardingCreate() {
<HStack alignItems="center" gap={4}>
<Icon name="face-id" />
<Text>
Face ID <Text muted>(Recommended)</Text>
Face ID <Text color="textSecondary">(Recommended)</Text>
</Text>
</HStack>
<Icon name="chevron-right" />
Expand Down
50 changes: 43 additions & 7 deletions packages/tackle-box/lib/components/Box/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReactNode, useMemo } from "react";
import { css, html } from "react-strict-dom";
import { css } from "react-strict-dom";
import { type Colors, getColorValue } from "@/vars/colors.stylex";
import { StyleObj, UnitValue } from "@/utils/types";
import {
Expand All @@ -13,6 +13,12 @@ import {
type BorderRadiusArgs,
type BorderWidthArgs,
} from "./utils";
import {
Polymorphic,
PolymorphicComponentProps,
RSDElementTypes,
} from "../Polymorphic/Polymorphic";

const styles = css.create({
base: {
boxSizing: "border-box",
Expand Down Expand Up @@ -82,7 +88,7 @@ export type BoxProps = BorderRadiusArgs &
style?: StyleObj;
} & MarginPadding;

export function Box({
export function Box<TAsProp extends RSDElementTypes = "div">({
children,
height = "auto",
width = "100%",
Expand All @@ -100,9 +106,38 @@ export function Box({
borderLeftWidth,
flexGrow,
style,
...marginPadding
}: BoxProps) {
const { margin, padding } = useMarginPaddingValues(marginPadding);
m,
mx,
my,
mt,
mr,
mb,
ml,
p,
px,
py,
pt,
pr,
pb,
pl,
...rest
}: PolymorphicComponentProps<TAsProp, BoxProps>) {
const { margin, padding } = useMarginPaddingValues({
m,
mx,
my,
mt,
mr,
mb,
ml,
p,
px,
py,
pt,
pr,
pb,
pl,
});

const borderRadiusValues = useMemo(() => {
return computeBorderRadius({
Expand Down Expand Up @@ -137,7 +172,7 @@ export function Box({
]);

return (
<html.div
<Polymorphic
style={[
styles.base,
styles.dimensions(height, width),
Expand All @@ -152,8 +187,9 @@ export function Box({
styles.flexGrow(flexGrow),
style,
]}
{...rest}
>
{children}
</html.div>
</Polymorphic>
);
}
2 changes: 1 addition & 1 deletion packages/tackle-box/lib/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function ButtonContent({
}) {
return (
<HStack gap={8} justifyContent="center">
<Text>{title}</Text>
<Text color="inherit">{title}</Text>
{rightIcon && <Icon name={rightIcon} />}
</HStack>
);
Expand Down
48 changes: 48 additions & 0 deletions packages/tackle-box/lib/components/Polymorphic/Polymorphic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ComponentPropsWithoutRef, PropsWithChildren } from "react";
import { html } from "react-strict-dom";

/**
* Union of possible react-strict-dom elements. E.g. html.div, html.p would equal "div" | "p"
*/
export type RSDElementTypes = keyof typeof html;

/**
* Gets the React.ElementType for a given react-strict-dom element.
*/
type RSDElement<T extends RSDElementTypes> = (typeof html)[T];

/**
* Gets the props for a given react-strict-dom element.
*/
type RSDElementProps<T extends RSDElementTypes> = ComponentPropsWithoutRef<
RSDElement<T>
>;

/**
* Props for the `as` prop that can be used to change the returned element type.
*/
type AsProp<TAsProp extends RSDElementTypes> = {
as?: TAsProp;
};

/**
* Utility to create props for polymorphic components.
*/
export type PolymorphicComponentProps<
TAsProp extends RSDElementTypes,
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
TProps extends Record<string, unknown> = {},
> = PropsWithChildren<
AsProp<TAsProp> & TProps & Omit<RSDElementProps<TAsProp>, keyof TProps>
>;

export function Polymorphic<TAsProp extends RSDElementTypes = "div">({
as,
children,
...rest
}: PolymorphicComponentProps<TAsProp>) {
const elementType: RSDElementTypes = as ?? "div";
const Component = html[elementType];

return <Component {...rest}>{children}</Component>;
}
99 changes: 99 additions & 0 deletions packages/tackle-box/lib/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Box } from "@/components/Box/Box";
import { HStack } from "@/components/Stack/Stack";
import { createContext, ReactNode, useContext, useState } from "react";
import { css, html } from "react-strict-dom";
import { Text } from "@/components/Text/Text";

const TabsContext = createContext<{
activeTab: string;
setActiveTab: (tab: string) => void;
}>({
activeTab: "",
setActiveTab: () => {},
});

function useTabsContext() {
return useContext(TabsContext);
}

type RootProps = {
children: ReactNode;
defaultValue?: string;
};

function Root({ children, defaultValue }: RootProps) {
const [activeTab, setActiveTab] = useState(defaultValue ?? "");

return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
{children}
</TabsContext.Provider>
);
}

type ListProps = {
children: ReactNode;
};

function List({ children }: ListProps) {
return (
<HStack justifyContent="center" borderBottomWidth={1} borderColor="divider">
{children}
</HStack>
);
}

type TriggerProps = {
children: ReactNode;
value: string;
};

const triggerStyles = css.create({
wrapper: {
borderWidth: 0,
paddingLeft: 16,
paddingRight: 16,
},
});

function Trigger({ children, value }: TriggerProps) {
const context = useTabsContext();
const isActive = context.activeTab === value;

return (
<html.button
onClick={() => context.setActiveTab(value)}
style={triggerStyles.wrapper}
>
<Box
borderBottomWidth={2}
borderColor={isActive ? "textPrimary" : "transparent"}
py={4}
>
<Text color={isActive ? "textPrimary" : "textSecondary"}>
{children}
</Text>
</Box>
</html.button>
);
}

type ContentProps = {
children: ReactNode;
value: string;
};

function Content({ children, value }: ContentProps) {
const context = useTabsContext();

return context.activeTab === value ? <>{children}</> : null;
}

const Tabs = {
Root,
List,
Trigger,
Content,
};

export { Tabs };
14 changes: 7 additions & 7 deletions packages/tackle-box/lib/components/Text/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { colors } from "@/vars/colors.stylex";
import { Colors, getColorValue } from "@/vars/colors.stylex";
import { ReactNode } from "react";
import { css, html } from "react-strict-dom";

Expand Down Expand Up @@ -37,31 +37,31 @@ const styles = css.create({
textAlign: (textAlign: "left" | "center" | "right") => ({
textAlign,
}),
muted: {
color: colors.textSecondary,
},
color: (color?: string) => ({
color,
}),
});

type Props = {
children?: ReactNode;
size?: Sizes;
textAlign?: "left" | "center" | "right";
muted?: boolean;
color?: Colors | "inherit";
};

export function Text({
children,
size = "md",
textAlign = "left",
muted,
color = "textPrimary",
}: Props) {
return (
<html.span
style={[
styles.base,
styles[size],
styles.textAlign(textAlign),
muted && styles.muted,
styles.color(color === "inherit" ? "inherit" : getColorValue(color)),
]}
>
{children}
Expand Down
1 change: 1 addition & 0 deletions packages/tackle-box/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export { HStack, VStack } from "@/components/Stack/Stack";
export { Text } from "@/components/Text/Text";
export { TextInput } from "@/components/TextInput/TextInput";
export { Icon } from "@/components/Icon/Icon";
export { Tabs } from "@/components/Tabs/Tabs";
export { css } from "react-strict-dom";
1 change: 1 addition & 0 deletions packages/tackle-box/lib/vars/colors.stylex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const palette = css.defineVars({
black: "#101010",
white: "#FFFFFF",
pink: "#FFC0CB",
transparent: "transparent",
});

// Theme tokens
Expand Down

0 comments on commit e73c094

Please sign in to comment.