{"version":3,"file":"Layout.cjs","names":[],"sources":["../../../src/components/Layout/Layout.tsx"],"sourcesContent":["import type { CSSProperties, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { useBreakpoint } from \"@/hooks/use-breakpoint\";\nimport styles from \"./Layout.module.css\";\n\nexport type ContainerSize = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\";\n\nexport interface ContainerProps extends HTMLAttributes<HTMLDivElement> {\n    size?: ContainerSize;\n}\n\n/**\n * Page-level horizontal container with a max-width preset and responsive\n * side padding (`space-4` mobile / `space-6` tablet / `space-8` desktop).\n */\nexport function Container({ size = \"lg\", className, children, ...props }: ContainerProps) {\n    return (\n        <div className={cn(styles.container, styles[size], className)} {...props}>\n            {children}\n        </div>\n    );\n}\n\n/**\n * Responsive value — either a single value applied at all breakpoints, or\n * an object with `mobile` / `tablet` / `desktop` overrides. Apps can mix\n * any combination; `mobile` is the base, `tablet` / `desktop` cascade up.\n */\nexport type ResponsiveValue<T> =\n    | T\n    | {\n          mobile?: T;\n          tablet?: T;\n          desktop?: T;\n      };\n\nfunction isResponsiveObject<T>(value: ResponsiveValue<T>): value is {\n    mobile?: T;\n    tablet?: T;\n    desktop?: T;\n} {\n    return (\n        typeof value === \"object\" &&\n        value !== null &&\n        (\"mobile\" in value || \"tablet\" in value || \"desktop\" in value)\n    );\n}\n\nfunction pickResponsive<T>(\n    value: ResponsiveValue<T> | undefined,\n    device: \"mobile\" | \"tablet\" | \"desktop\",\n): T | undefined {\n    if (value === undefined) return undefined;\n    if (!isResponsiveObject(value)) return value;\n    if (device === \"desktop\") return value.desktop ?? value.tablet ?? value.mobile;\n    if (device === \"tablet\") return value.tablet ?? value.mobile ?? value.desktop;\n    return value.mobile ?? value.tablet ?? value.desktop;\n}\n\nexport type StackAlign = \"start\" | \"center\" | \"end\" | \"stretch\";\nexport type StackJustify = \"start\" | \"center\" | \"end\" | \"between\";\nexport type StackDirection = \"vertical\" | \"horizontal\";\n\nexport interface StackProps extends HTMLAttributes<HTMLDivElement> {\n    /** Direction. Accepts responsive object — e.g. `{ mobile: \"vertical\", desktop: \"horizontal\" }`. */\n    direction?: ResponsiveValue<StackDirection>;\n    /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. */\n    gap?: ResponsiveValue<number | string>;\n    align?: StackAlign;\n    justify?: StackJustify;\n    wrap?: boolean;\n    children?: ReactNode;\n}\n\nfunction resolveGap(gap: number | string | undefined): string | undefined {\n    if (gap === undefined) return undefined;\n    return typeof gap === \"number\" ? `${gap * 4}px` : gap;\n}\n\nfunction deviceFromBreakpoint(\n    isMobile: boolean,\n    isTablet: boolean,\n): \"mobile\" | \"tablet\" | \"desktop\" {\n    if (isMobile) return \"mobile\";\n    if (isTablet) return \"tablet\";\n    return \"desktop\";\n}\n\n/** Flex-based vertical or horizontal stack with a numeric `gap`. */\nexport function Stack({\n    direction = \"vertical\",\n    gap = 2,\n    align,\n    justify,\n    wrap = false,\n    className,\n    style,\n    children,\n    ...props\n}: StackProps) {\n    const { isMobile, isTablet } = useBreakpoint();\n    const device = deviceFromBreakpoint(isMobile, isTablet);\n    const finalDirection: StackDirection = pickResponsive(direction, device) ?? \"vertical\";\n    const finalGap = resolveGap(pickResponsive(gap, device));\n    const finalStyle: CSSProperties = { gap: finalGap, ...style };\n    const justifyClass =\n        justify === \"between\"\n            ? styles.justifyBetween\n            : justify === \"center\"\n              ? styles.justifyCenter\n              : justify === \"end\"\n                ? styles.justifyEnd\n                : justify === \"start\"\n                  ? styles.justifyStart\n                  : undefined;\n    return (\n        <div\n            className={cn(\n                styles.stack,\n                finalDirection === \"vertical\" ? styles.vertical : styles.horizontal,\n                align && styles[align],\n                justifyClass,\n                wrap && styles.wrap,\n                className,\n            )}\n            style={finalStyle}\n            {...props}\n        >\n            {children}\n        </div>\n    );\n}\n\nexport interface GridProps extends HTMLAttributes<HTMLDivElement> {\n    /** Number of columns or a custom `grid-template-columns` value. Accepts responsive object. */\n    columns?: ResponsiveValue<number | string>;\n    /** Gap as a CSS length. Numbers map to a multiple of the 4px scale. Accepts responsive object. */\n    gap?: ResponsiveValue<number | string>;\n    children?: ReactNode;\n}\n\nfunction resolveColumns(columns: number | string | undefined): string | undefined {\n    if (columns === undefined) return undefined;\n    return typeof columns === \"number\" ? `repeat(${columns}, minmax(0, 1fr))` : columns;\n}\n\n/** Simple CSS-Grid wrapper for equal-width or custom column layouts. */\nexport function Grid({ columns = 2, gap = 4, className, style, children, ...props }: GridProps) {\n    const { isMobile, isTablet } = useBreakpoint();\n    const device = deviceFromBreakpoint(isMobile, isTablet);\n    const templateColumns = resolveColumns(pickResponsive(columns, device));\n    const finalGap = resolveGap(pickResponsive(gap, device));\n    return (\n        <div\n            className={cn(styles.grid, className)}\n            style={{ gridTemplateColumns: templateColumns, gap: finalGap, ...style }}\n            {...props}\n        >\n            {children}\n        </div>\n    );\n}\n"],"mappings":"sJAeA,SAAgB,EAAU,CAAE,OAAO,KAAM,YAAW,WAAU,GAAG,GAAyB,CACtF,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,UAAW,EAAA,QAAO,GAAO,CAAS,EAAG,GAAI,EAC9D,UACA,CAAA,CAEb,CAeA,SAAS,EAAsB,EAI7B,CACE,OACI,OAAO,GAAU,YACjB,IACC,WAAY,GAAS,WAAY,GAAS,YAAa,EAEhE,CAEA,SAAS,EACL,EACA,EACa,CACT,OAAU,IAAA,GAId,OAHK,EAAmB,CAAK,EACzB,IAAW,UAAkB,EAAM,SAAW,EAAM,QAAU,EAAM,OACpE,IAAW,SAAiB,EAAM,QAAU,EAAM,QAAU,EAAM,QAC/D,EAAM,QAAU,EAAM,QAAU,EAAM,QAHN,CAI3C,CAiBA,SAAS,EAAW,EAAsD,CAClE,OAAQ,IAAA,GACZ,OAAO,OAAO,GAAQ,SAAW,GAAG,EAAM,EAAE,IAAM,CACtD,CAEA,SAAS,EACL,EACA,EAC+B,CAG/B,OAFI,EAAiB,SACjB,EAAiB,SACd,SACX,CAGA,SAAgB,EAAM,CAClB,YAAY,WACZ,MAAM,EACN,QACA,UACA,OAAO,GACP,YACA,QACA,WACA,GAAG,GACQ,CACX,GAAM,CAAE,WAAU,YAAa,EAAA,cAAc,EACvC,EAAS,EAAqB,EAAU,CAAQ,EAChD,EAAiC,EAAe,EAAW,CAAM,GAAK,WAEtE,EAA4B,CAAE,IADnB,EAAW,EAAe,EAAK,CAAM,CACb,EAAU,GAAG,CAAM,EACtD,EACF,IAAY,UACN,EAAA,QAAO,eACP,IAAY,SACV,EAAA,QAAO,cACP,IAAY,MACV,EAAA,QAAO,WACP,IAAY,QACV,EAAA,QAAO,aACP,IAAA,GAChB,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,MACP,IAAmB,WAAa,EAAA,QAAO,SAAW,EAAA,QAAO,WACzD,GAAS,EAAA,QAAO,GAChB,EACA,GAAQ,EAAA,QAAO,KACf,CACJ,EACA,MAAO,EACP,GAAI,EAEH,UACA,CAAA,CAEb,CAUA,SAAS,EAAe,EAA0D,CAC1E,OAAY,IAAA,GAChB,OAAO,OAAO,GAAY,SAAW,UAAU,EAAQ,mBAAqB,CAChF,CAGA,SAAgB,EAAK,CAAE,UAAU,EAAG,MAAM,EAAG,YAAW,QAAO,WAAU,GAAG,GAAoB,CAC5F,GAAM,CAAE,WAAU,YAAa,EAAA,cAAc,EACvC,EAAS,EAAqB,EAAU,CAAQ,EAChD,EAAkB,EAAe,EAAe,EAAS,CAAM,CAAC,EAChE,EAAW,EAAW,EAAe,EAAK,CAAM,CAAC,EACvD,OACI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EACpC,MAAO,CAAE,oBAAqB,EAAiB,IAAK,EAAU,GAAG,CAAM,EACvE,GAAI,EAEH,UACA,CAAA,CAEb"}