Skip to content

Commit

Permalink
Add Box, HStack, VStack
Browse files Browse the repository at this point in the history
  • Loading branch information
dgca committed Nov 15, 2024
1 parent 3252f82 commit 9368b38
Show file tree
Hide file tree
Showing 16 changed files with 328 additions and 119 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
27 changes: 25 additions & 2 deletions packages/mobile-app/app/(tabs)/ui.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useColorScheme, View, Text } from "react-native";
import { Button, Box } from "@ironfish/tackle-box";
import { Button, Box, HStack, VStack } from "@ironfish/tackle-box";
import { useState } from "react";

export default function UiKit() {
Expand All @@ -16,9 +16,32 @@ export default function UiKit() {
>
<Text>Count: {count}</Text>
<Button title="Press me" onClick={() => setCount(count + 1)} />
<Box>
<Box height="auto" bg="pink" borderWidth={2} borderColor="gray">
<Button title="Press me" onClick={() => setCount(count + 1)} />
<Button disabled title="Press me" onClick={() => setCount(count + 1)} />
</Box>

<HStack
gap={4}
height="auto"
bg="pink"
borderWidth={8}
borderColor="gray"
>
<Button title="Press me" onClick={() => setCount(count + 1)} />
<Button disabled title="Press me" onClick={() => setCount(count + 1)} />
</HStack>

<VStack
gap={4}
height="auto"
bg="pink"
borderWidth={4}
borderColor="black"
>
<Button title="Press me" onClick={() => setCount(count + 1)} />
<Button disabled title="Press me" onClick={() => setCount(count + 1)} />
</VStack>
</View>
);
}
3 changes: 2 additions & 1 deletion packages/mobile-app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true
"strict": true,
"moduleResolution": "bundler"
}
}
101 changes: 93 additions & 8 deletions packages/tackle-box/lib/components/Box/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,99 @@
import { ReactElement } from "react";
import { html } from "react-strict-dom";
import { ReactNode } from "react";
import { css, html } from "react-strict-dom";
import { palette, type PaletteColors } from "../../vars/colors.stylex";
import { StyleObj, UnitValue } from "../../utils/types";
import {
useMarginPaddingValues,
type MarginPadding,
} from "../../utils/useMarginPaddingValues";

type Props = {
children?: ReactElement;
};
const styles = css.create({
base: {
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
alignItems: "stretch",
justifyContent: "flex-start",
},
backgroundColor: (color?: PaletteColors) => ({
backgroundColor: color ? palette[color] : undefined,
}),
dimensions: (height: UnitValue, width: UnitValue) => ({
height,
width,
}),
margin: (
top: UnitValue,
right: UnitValue,
bottom: UnitValue,
left: UnitValue,
) => ({
marginTop: top,
marginRight: right,
marginBottom: bottom,
marginLeft: left,
}),
padding: (
top: UnitValue,
right: UnitValue,
bottom: UnitValue,
left: UnitValue,
) => ({
paddingTop: top,
paddingRight: right,
paddingBottom: bottom,
paddingLeft: left,
}),
borderRadius: (radius: number) => ({
borderRadius: radius,
}),
borderColor: (color?: PaletteColors) => ({
borderColor: color ? palette[color] : undefined,
}),
borderWidth: (width?: number) => ({
borderWidth: width ?? 0,
}),
});

export type BoxProps = {
children?: ReactNode;
height?: UnitValue;
width?: UnitValue;
borderRadius?: "full" | number;
bg?: PaletteColors;
borderColor?: PaletteColors;
borderWidth?: number;
style?: StyleObj;
} & MarginPadding;

export function Box({
children,
height = "auto",
width = "100%",
bg,
borderColor,
borderRadius = 0,
borderWidth = 0,
style,
...marginPadding
}: BoxProps) {
const { margin, padding } = useMarginPaddingValues(marginPadding);

export function Box({ children }: Props) {
return (
<html.div>
<html.span>{children}</html.span>
<html.div
style={[
styles.base,
styles.dimensions(height, width),
styles.margin(...margin),
styles.padding(...padding),
styles.borderRadius(borderRadius === "full" ? 9999 : borderRadius),
styles.backgroundColor(bg),
styles.borderColor(borderColor),
styles.borderWidth(borderWidth),
style,
]}
>
{children}
</html.div>
);
}
1 change: 1 addition & 0 deletions packages/tackle-box/lib/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const styles = css.create({
":active": colors.grayDark,
},
borderWidth: 0,
boxSizing: "border-box",
color: colors.white,
textAlign: "center",
paddingTop: 14,
Expand Down
38 changes: 38 additions & 0 deletions packages/tackle-box/lib/components/Stack/Stack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { css } from "react-strict-dom";
import { Box, type BoxProps } from "../Box/Box";
import { applyBaseSpacing } from "../../utils/applyBaseSpacing";

const styles = css.create({
horizontal: {
flexDirection: "row",
},
vertical: {
flexDirection: "column",
},
gap: (gap: number) => ({
gap,
}),
});

type StackProps = BoxProps & {
gap?: number;
};

export function HStack({ gap = 0, children, ...rest }: StackProps) {
return (
<Box
style={[styles.horizontal, styles.gap(applyBaseSpacing(gap))]}
{...rest}
>
{children}
</Box>
);
}

export function VStack({ gap = 0, children, ...rest }: StackProps) {
return (
<Box style={[styles.vertical, styles.gap(applyBaseSpacing(gap))]} {...rest}>
{children}
</Box>
);
}
1 change: 1 addition & 0 deletions packages/tackle-box/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Button } from "./components/Button/Button";
export { Box } from "./components/Box/Box";
export { HStack, VStack } from "./components/Stack/Stack";
11 changes: 11 additions & 0 deletions packages/tackle-box/lib/utils/applyBaseSpacing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { BASE_SPACING_UNIT } from "../vars/constants";

import { UnitValue } from "./types";

export function applyBaseSpacing<TValue extends UnitValue>(
value: TValue,
): TValue {
return (
typeof value === "number" ? value * BASE_SPACING_UNIT : value
) as TValue;
}
7 changes: 7 additions & 0 deletions packages/tackle-box/lib/utils/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { css, Styles } from "react-strict-dom";

export type UnitValue = number | string;

export type StyleObj = Styles<{ [key: string]: unknown }>;

export type VarKeys<T> = T extends css.VarGroup<infer U> ? keyof U : never;
119 changes: 119 additions & 0 deletions packages/tackle-box/lib/utils/useMarginPaddingValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { useMemo } from "react";
import { UnitValue } from "./types";
import { applyBaseSpacing } from "./applyBaseSpacing";

export type MarginPadding = {
m?: UnitValue;
mx?: UnitValue;
my?: UnitValue;
mt?: UnitValue;
mr?: UnitValue;
mb?: UnitValue;
ml?: UnitValue;
p?: UnitValue;
px?: UnitValue;
py?: UnitValue;
pt?: UnitValue;
pr?: UnitValue;
pb?: UnitValue;
pl?: UnitValue;
};

type TopRightBottomLeft = [UnitValue, UnitValue, UnitValue, UnitValue];

export function useMarginPaddingValues({
m,
mx,
my,
mt,
mr,
mb,
ml,
p,
px,
py,
pt,
pr,
pb,
pl,
}: MarginPadding) {
const margin: TopRightBottomLeft = useMemo(() => {
let top: UnitValue = 0;
let right: UnitValue = 0;
let bottom: UnitValue = 0;
let left: UnitValue = 0;

if (m) {
top = bottom = left = right = m;
}

if (mx) {
left = right = mx;
}

if (my) {
top = bottom = my;
}

if (mt) {
top = mt;
}

if (mr) {
right = mr;
}

if (mb) {
bottom = mb;
}

if (ml) {
left = ml;
}

return [top, right, bottom, left].map(
applyBaseSpacing,
) as TopRightBottomLeft;
}, [m, mb, ml, mr, mt, mx, my]);

const padding: TopRightBottomLeft = useMemo(() => {
let top: UnitValue = 0;
let right: UnitValue = 0;
let bottom: UnitValue = 0;
let left: UnitValue = 0;

if (p) {
top = bottom = left = right = p;
}

if (px) {
left = right = px;
}

if (py) {
top = bottom = py;
}

if (pt) {
top = pt;
}

if (pr) {
right = pr;
}

if (pb) {
bottom = pb;
}

if (pl) {
left = pl;
}

return [top, right, bottom, left].map(
applyBaseSpacing,
) as TopRightBottomLeft;
}, [p, pb, pl, pr, pt, px, py]);

return { margin, padding };
}
15 changes: 15 additions & 0 deletions packages/tackle-box/lib/vars/colors.stylex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { css } from "react-strict-dom";
import { VarKeys } from "../utils/types";

export const palette = css.defineVars({
black: "#000000",
white: "#FFFFFF",
gray: "#7F7F7F",
pink: "#FFC0CB",
});

export type Foo = keyof typeof palette;

export const foo: Foo = "black";

export type PaletteColors = VarKeys<typeof palette>;
1 change: 1 addition & 0 deletions packages/tackle-box/lib/vars/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BASE_SPACING_UNIT = 4;
Loading

0 comments on commit 9368b38

Please sign in to comment.