wallet-core/packages/taler-wallet-webextension/src/mui/Grid.tsx

242 lines
6.1 KiB
TypeScript
Raw Normal View History

2022-03-11 03:13:10 +01:00
import { css } from "@linaria/core";
import { h, Fragment, VNode, ComponentChildren, createContext } from "preact";
import { useContext } from "preact/hooks";
import { theme } from "./style";
2022-03-09 18:00:02 +01:00
2022-03-11 03:13:10 +01:00
type ResponsiveKeys = "xs" | "sm" | "md" | "lg" | "xl";
export type ResponsiveSize = {
xs: number;
sm: number;
md: number;
lg: number;
xl: number;
};
const root = css`
box-sizing: border-box;
`;
const containerStyle = css`
display: flex;
flex-wrap: wrap;
width: 100%;
`;
const itemStyle = css`
margin: 0;
`;
const zeroMinWidthStyle = css`
min-width: 0px;
`;
type GridSizes = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
type SpacingSizes = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
export interface Props {
columns?: number | Partial<ResponsiveSize>;
2022-03-09 18:00:02 +01:00
container?: boolean;
item?: boolean;
2022-03-11 03:13:10 +01:00
direction?: "column-reverse" | "column" | "row-reverse" | "row";
lg?: GridSizes | "auto" | "true";
md?: GridSizes | "auto" | "true";
sm?: GridSizes | "auto" | "true";
xl?: GridSizes | "auto" | "true";
xs?: GridSizes | "auto" | "true";
wrap?: "nowrap" | "wrap-reverse" | "wrap";
spacing?: SpacingSizes | Partial<ResponsiveSize>;
columnSpacing?: SpacingSizes | Partial<ResponsiveSize>;
rowSpacing?: SpacingSizes | Partial<ResponsiveSize>;
alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
justifyContent?:
| "flex-start"
| "flex-end"
| "center"
| "space-around"
| "space-between"
| "space-evenly";
zeroMinWidth?: boolean;
2022-03-09 18:00:02 +01:00
children: ComponentChildren;
2022-03-11 03:13:10 +01:00
}
theme.breakpoints.up;
function getOffset(val: number | string) {
if (typeof val === "number") `${val}px`;
return val;
}
const columnGapVariant = css`
${theme.breakpoints.up("xs")} {
width: calc(100% + var(--space-col-xs));
margin-left: calc(-1 * var(--space-col-xs));
& > div {
padding-left: var(--space-col-xs);
}
}
${theme.breakpoints.up("sm")} {
width: calc(100% + var(--space-col-sm));
margin-left: calc(-1 * var(--space-col-sm));
& > div {
padding-left: var(--space-col-sm);
}
}
${theme.breakpoints.up("md")} {
width: calc(100% + var(--space-col-md));
margin-left: calc(-1 * var(--space-col-md));
& > div {
padding-left: var(--space-col-md);
}
}
`;
const rowGapVariant = css`
${theme.breakpoints.up("xs")} {
margin-top: calc(-1 * var(--space-row-xs));
& > div {
padding-top: var(--space-row-xs);
}
}
${theme.breakpoints.up("sm")} {
margin-top: calc(-1 * var(--space-row-sm));
& > div {
padding-top: var(--space-row-sm);
}
}
${theme.breakpoints.up("md")} {
margin-top: calc(-1 * var(--space-row-md));
& > div {
padding-top: var(--space-row-md);
}
}
`;
const sizeVariant = css`
${theme.breakpoints.up("xs")} {
flex-basis: var(--relation-col-vs-xs);
flex-grow: 0;
max-width: var(--relation-col-vs-xs);
}
${theme.breakpoints.up("sm")} {
flex-basis: var(--relation-col-vs-sm);
flex-grow: 0;
max-width: var(--relation-col-vs-sm);
}
${theme.breakpoints.up("md")} {
flex-basis: var(--relation-col-vs-md);
flex-grow: 0;
max-width: var(--relation-col-vs-md);
}
`;
const GridContext = createContext<ResponsiveSize>(toResponsive(12));
function toResponsive(v: number | Partial<ResponsiveSize>): ResponsiveSize {
const p = typeof v === "number" ? { xs: v } : v;
const xs = p.xs || 12;
const sm = p.sm || xs;
const md = p.md || sm;
const lg = p.lg || md;
const xl = p.xl || lg;
return {
xs,
sm,
md,
lg,
xl,
};
}
export function Grid({
columns: cp,
container = false,
item = false,
direction = "row",
lg,
md,
sm,
xl,
xs,
wrap = "wrap",
spacing = 0,
columnSpacing: csp,
rowSpacing: rsp,
alignItems,
justifyContent,
zeroMinWidth = false,
children,
}: Props): VNode {
const cc = useContext(GridContext);
const columns = !cp ? cc : toResponsive(cp);
const rowSpacing = rsp ? toResponsive(rsp) : toResponsive(spacing);
const columnSpacing = csp ? toResponsive(csp) : toResponsive(spacing);
const ssize = toResponsive({ xs, md, lg, xl, sm } as any);
if (container) {
console.log(rowSpacing);
console.log(columnSpacing);
}
const spacingStyles = !container
? {}
: {
"--space-col-xs": getOffset(theme.spacing(columnSpacing.xs)),
"--space-col-sm": getOffset(theme.spacing(columnSpacing.sm)),
"--space-col-md": getOffset(theme.spacing(columnSpacing.md)),
"--space-col-lg": getOffset(theme.spacing(columnSpacing.lg)),
"--space-col-xl": getOffset(theme.spacing(columnSpacing.xl)),
"--space-row-xs": getOffset(theme.spacing(rowSpacing.xs)),
"--space-row-sm": getOffset(theme.spacing(rowSpacing.sm)),
"--space-row-md": getOffset(theme.spacing(rowSpacing.md)),
"--space-row-lg": getOffset(theme.spacing(rowSpacing.lg)),
"--space-row-xl": getOffset(theme.spacing(rowSpacing.xl)),
};
const relationStyles = !item
? {}
: {
"--relation-col-vs-sm": relation(columns, ssize, "sm"),
"--relation-col-vs-lg": relation(columns, ssize, "lg"),
"--relation-col-vs-xs": relation(columns, ssize, "xs"),
"--relation-col-vs-xl": relation(columns, ssize, "xl"),
"--relation-col-vs-md": relation(columns, ssize, "md"),
};
return (
<GridContext.Provider value={columns}>
<div
id={container ? "container" : "item"}
class={[
root,
container && containerStyle,
item && itemStyle,
zeroMinWidth && zeroMinWidthStyle,
sizeVariant,
container && columnGapVariant,
container && rowGapVariant,
].join(" ")}
style={{
...relationStyles,
...spacingStyles,
justifyContent,
alignItems,
}}
>
{children}
</div>
</GridContext.Provider>
);
}
function relation(
cols: ResponsiveSize,
values: ResponsiveSize,
size: ResponsiveKeys,
) {
const colsNum = typeof cols === "number" ? cols : cols[size] || 12;
return (
String(Math.round(((values[size] || 1) / colsNum) * 10e7) / 10e5) + "%"
);
2022-03-09 18:00:02 +01:00
}