/* This file is part of GNU Taler (C) 2022 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ import { css } from "@linaria/core"; import { h, JSX, VNode, ComponentChildren, createContext } from "preact"; import { useContext } from "preact/hooks"; // eslint-disable-next-line import/extensions import { theme } from "./style.js"; 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 extends JSX.HTMLAttributes { columns?: number | Partial; container?: boolean; item?: boolean; 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; columnSpacing?: SpacingSizes | Partial; rowSpacing?: SpacingSizes | Partial; alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline"; justifyContent?: | "flex-start" | "flex-end" | "center" | "space-around" | "space-between" | "space-evenly"; zeroMinWidth?: boolean; children: ComponentChildren; } theme.breakpoints.up; function getOffset(val: number | string): string | number { 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); } } ${theme.breakpoints.up("lg")} { width: calc(100% + var(--space-col-lg)); margin-left: calc(-1 * var(--space-col-lg)); & > div { padding-left: var(--space-col-lg); } } ${theme.breakpoints.up("xl")} { width: calc(100% + var(--space-col-xl)); margin-left: calc(-1 * var(--space-col-xl)); & > div { padding-left: var(--space-col-xl); } } `; 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); } } ${theme.breakpoints.up("lg")} { margin-top: calc(-1 * var(--space-row-lg)); & > div { padding-top: var(--space-row-lg); } } ${theme.breakpoints.up("xl")} { margin-top: calc(-1 * var(--space-row-xl)); & > div { padding-top: var(--space-row-xl); } } `; const sizeVariantXS = css` ${theme.breakpoints.up("xs")} { flex-basis: var(--relation-col-vs-xs); flex-grow: 0; max-width: var(--relation-col-vs-xs); } `; const sizeVariantSM = css` ${theme.breakpoints.up("sm")} { flex-basis: var(--relation-col-vs-sm); flex-grow: 0; max-width: var(--relation-col-vs-sm); } `; const sizeVariantMD = css` ${theme.breakpoints.up("md")} { flex-basis: var(--relation-col-vs-md); flex-grow: 0; max-width: var(--relation-col-vs-md); } `; const sizeVariantLG = css` ${theme.breakpoints.up("lg")} { flex-basis: var(--relation-col-vs-lg); flex-grow: 0; max-width: var(--relation-col-vs-lg); } `; const sizeVariantXL = css` ${theme.breakpoints.up("xl")} { flex-basis: var(--relation-col-vs-xl); flex-grow: 0; max-width: var(--relation-col-vs-xl); } `; const sizeVariantExpand = css` flex-basis: 0; flex-grow: 1; max-width: 100%; `; const sizeVariantAuto = css` flex-basis: auto; flex-grow: 0; flex-shrink: 0; max-width: none; width: auto; `; const GridContext = createContext>(toResponsive(12)); function toResponsive( v: number | Partial, ): Partial { const p = typeof v === "number" ? { xs: v } : v; const xs = p.xs; 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, onClick, ...rest }: 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); 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-xs": relation(columns, ssize, "xs"), "--relation-col-vs-sm": relation(columns, ssize, "sm"), "--relation-col-vs-md": relation(columns, ssize, "md"), "--relation-col-vs-lg": relation(columns, ssize, "lg"), "--relation-col-vs-xl": relation(columns, ssize, "xl"), }; return (
{children}
); } function relation( cols: Partial, values: Partial, size: ResponsiveKeys, ): string { const colsNum = typeof cols === "number" ? cols : cols[size] || 12; return ( String(Math.round(((values[size] || 1) / colsNum) * 10e7) / 10e5) + "%" ); }