Skip to content

Instantly share code, notes, and snippets.

@reverie
Created April 28, 2020 19:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reverie/347b27992e1c39fcd50bbffb68958b88 to your computer and use it in GitHub Desktop.
Save reverie/347b27992e1c39fcd50bbffb68958b88 to your computer and use it in GitHub Desktop.
typescript/tailwind Stack component
import React from "react";
import classNames from "classnames";
// See https://tailwindcss.com/docs/margin/
type MarginSize = "2" | "4" | "8";
// See https://tailwindcss.com/docs/responsive-design/
type ScreenSize = "sm" | "md";
type Config = {
vertical?: boolean;
margin?: MarginSize;
};
type SizeConfig = Partial<Record<ScreenSize, Config>>;
interface Props {
children: React.ReactNode;
className?: string;
margin?: MarginSize;
vertical?: boolean;
sizes?: SizeConfig;
}
const Stack = (props: Props) => {
const { className, margin = "2", vertical = false, sizes = {} } = props;
const cls = classNames(
"flex",
"items-center",
vertical ? "flex-col" : "flex-row",
Object.keys(sizes).map((size) => {
const { vertical } = (sizes as any)[size];
return `${size}:${vertical ? "flex-col" : "flex-row"}`;
}),
className
);
const childCls = classNames(
"first:ml-0", // these first: styles aren't working for some reason
"first:mt-0",
vertical ? "mt-" + margin : "ml-" + margin,
Object.keys(sizes).map((size) => {
const { vertical, margin } = sizes[size as ScreenSize] as Config;
return [
`${size}:${vertical ? "ml-0" : "mt-0"}`,
`${size}:${vertical ? "mt" : "ml"}-${margin}`,
];
})
);
const children = React.Children.toArray(props.children);
const nonEmptyChildren = children.filter((el) => el ?? false);
return (
<div className={cls}>
{nonEmptyChildren.map((child, index) => (
<div className={index ? childCls : ""}>{child}</div>
))}
</div>
);
};
export default Stack;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment