{"version":3,"file":"AdaptiveContainer.mjs","sources":["../../../../src/lib/layouts/adaptive/AdaptiveContainer.tsx"],"sourcesContent":["/**\n * @fileoverview AdaptiveContainer Component\n *\n * An intelligent container component that provides container query support,\n * content density detection, and adaptive spacing. Acts as a foundation for\n * building responsive layouts without viewport-based breakpoints.\n *\n * @module layouts/adaptive/AdaptiveContainer\n * @version 1.0.0\n */\n\n/* eslint-disable react-refresh/only-export-components */\n\nimport {\n  Children,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  memo,\n  type CSSProperties,\n  type ReactNode,\n} from 'react';\nimport { ContainerContext, type ContainerContextValue } from '@/lib/contexts';\nimport type {\n  AdaptiveContainerProps,\n  BoxSpacing,\n  ContainerBreakpoints,\n  ContentDensity,\n  Dimensions,\n} from './types';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * Default container breakpoints.\n */\nconst DEFAULT_BREAKPOINTS: ContainerBreakpoints = {\n  xs: 320,\n  sm: 480,\n  md: 768,\n  lg: 1024,\n  xl: 1280,\n} as const;\n\n/**\n * Default padding.\n */\nconst DEFAULT_PADDING = 16;\n\n/**\n * Density thresholds (items per 10000 square pixels).\n */\nconst DENSITY_THRESHOLDS = {\n  minimal: 0.5,\n  low: 1,\n  medium: 2,\n  high: 4,\n  extreme: 8,\n} as const;\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n/* @refresh reset */\n\n/**\n * Hook to access container context.\n */\nexport function useContainerContext(): ContainerContextValue | null {\n  return useContext(ContainerContext);\n}\n\n// =============================================================================\n// HELPER FUNCTIONS\n// =============================================================================\n\n/**\n * Determines size category based on width and breakpoints.\n */\nfunction getSizeCategory(\n  width: number,\n  breakpoints: ContainerBreakpoints\n): keyof ContainerBreakpoints {\n  const { xs = 320, sm = 480, md = 768, lg = 1024, xl = 1280 } = breakpoints;\n\n  if (width < xs) return 'xs';\n  if (width < sm) return 'xs';\n  if (width < md) return 'sm';\n  if (width < lg) return 'md';\n  if (width < xl) return 'lg';\n  return 'xl';\n}\n\n/**\n * Calculates content density based on child count and container area.\n */\nfunction calculateDensity(childCount: number, dimensions: Dimensions): ContentDensity {\n  if (childCount === 0) return 'minimal';\n\n  const area = dimensions.width * dimensions.height;\n  if (area === 0) return 'minimal';\n\n  // Calculate items per 10000 square pixels\n  const densityRatio = (childCount / area) * 10000;\n\n  if (densityRatio <= DENSITY_THRESHOLDS.minimal) return 'minimal';\n  if (densityRatio <= DENSITY_THRESHOLDS.low) return 'low';\n  if (densityRatio <= DENSITY_THRESHOLDS.medium) return 'medium';\n  if (densityRatio <= DENSITY_THRESHOLDS.high) return 'high';\n  return 'extreme';\n}\n\n/**\n * Normalizes padding to BoxSpacing format.\n */\nfunction normalizePadding(padding: number | BoxSpacing): BoxSpacing {\n  if (typeof padding === 'number') {\n    return { top: padding, right: padding, bottom: padding, left: padding };\n  }\n  return padding;\n}\n\n/**\n * Generates CSS padding string from BoxSpacing.\n */\nfunction paddingToCSS(spacing: BoxSpacing): string {\n  return `${spacing.top}px ${spacing.right}px ${spacing.bottom}px ${spacing.left}px`;\n}\n\n// =============================================================================\n// ADAPTIVE CONTAINER COMPONENT\n// =============================================================================\n\n/**\n * AdaptiveContainer is an intelligent container component that provides\n * container-based responsive behavior and content density detection.\n * Memoized for performance optimization.\n *\n * @example\n * ```tsx\n * <AdaptiveContainer\n *   breakpoints={{ sm: 400, md: 600, lg: 800 }}\n *   detectDensity\n *   padding={24}\n *   maxWidth={1200}\n *   centered\n * >\n *   {({ sizeCategory, density }) => (\n *     <div>\n *       Current size: {sizeCategory}, Density: {density}\n *     </div>\n *   )}\n * </AdaptiveContainer>\n * ```\n */\nconst AdaptiveContainerComponent = ({\n  children,\n  breakpoints = DEFAULT_BREAKPOINTS,\n  detectDensity = true,\n  padding = DEFAULT_PADDING,\n  maxWidth,\n  centered = false,\n  className,\n  style,\n}: AdaptiveContainerProps): ReactNode => {\n  // Refs\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  // State\n  const [dimensions, setDimensions] = useState<Dimensions>({ width: 0, height: 0 });\n\n  // Normalize padding\n  const normalizedPadding = useMemo(() => normalizePadding(padding), [padding]);\n\n  // Calculate derived values\n  const sizeCategory = useMemo(\n    () => getSizeCategory(dimensions.width, breakpoints),\n    [dimensions.width, breakpoints]\n  );\n\n  const childCount = useMemo(() => Children.count(children), [children]);\n\n  const density = useMemo(\n    () => (detectDensity ? calculateDensity(childCount, dimensions) : 'medium'),\n    [detectDensity, childCount, dimensions]\n  );\n\n  const isNarrow = sizeCategory === 'xs' || sizeCategory === 'sm';\n  const isWide = sizeCategory === 'lg' || sizeCategory === 'xl';\n\n  // Observe container size\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container) return;\n\n    const observer = new ResizeObserver((entries) => {\n      const [entry] = entries;\n      if (entry !== undefined) {\n        setDimensions({\n          width: entry.contentRect.width,\n          height: entry.contentRect.height,\n        });\n      }\n    });\n\n    observer.observe(container);\n\n    return () => observer.disconnect();\n  }, []);\n\n  // Context value\n  const contextValue = useMemo<ContainerContextValue>(\n    () => ({\n      containerWidth: dimensions.width,\n      containerHeight: dimensions.height,\n      breakpoints: {\n        sm: breakpoints.sm ?? (DEFAULT_BREAKPOINTS.sm as number),\n        md: breakpoints.md ?? (DEFAULT_BREAKPOINTS.md as number),\n        lg: breakpoints.lg ?? (DEFAULT_BREAKPOINTS.lg as number),\n        xl: breakpoints.xl ?? (DEFAULT_BREAKPOINTS.xl as number),\n      },\n      matchesQuery: (query: keyof ContainerBreakpoints | number) => {\n        if (typeof query === 'number') {\n          return dimensions.width >= query;\n        }\n        const breakpointValue = breakpoints[query];\n        return breakpointValue !== undefined && dimensions.width >= breakpointValue;\n      },\n      isAbove: (query: keyof ContainerBreakpoints | number) => {\n        if (typeof query === 'number') {\n          return dimensions.width > query;\n        }\n        const breakpointValue = breakpoints[query];\n        return breakpointValue !== undefined && dimensions.width > breakpointValue;\n      },\n      isBelow: (query: keyof ContainerBreakpoints | number) => {\n        if (typeof query === 'number') {\n          return dimensions.width < query;\n        }\n        const breakpointValue = breakpoints[query];\n        return breakpointValue !== undefined && dimensions.width < breakpointValue;\n      },\n    }),\n    [dimensions, breakpoints]\n  );\n\n  // Container styles\n  const containerStyles = useMemo<CSSProperties>(() => {\n    const baseStyles: CSSProperties = {\n      width: '100%',\n      padding: paddingToCSS(normalizedPadding),\n      boxSizing: 'border-box',\n      // Enable container queries via CSS containment\n      containerType: 'inline-size',\n      ...style,\n    };\n\n    if (maxWidth !== undefined && maxWidth !== null) {\n      baseStyles.maxWidth = typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth;\n    }\n\n    if (centered === true) {\n      baseStyles.marginLeft = 'auto';\n      baseStyles.marginRight = 'auto';\n    }\n\n    // Adjust padding based on size category for better mobile experience\n    if (isNarrow) {\n      const reducedPadding = normalizePadding(\n        Math.max(8, (typeof padding === 'number' ? padding : 16) / 2)\n      );\n      baseStyles.padding = paddingToCSS(reducedPadding);\n    }\n\n    return baseStyles;\n  }, [normalizedPadding, maxWidth, centered, isNarrow, padding, style]);\n\n  // CSS custom properties for container queries\n  const cssVariables = useMemo<Record<string, string>>(\n    () => ({\n      '--container-width': `${dimensions.width}px`,\n      '--container-height': `${dimensions.height}px`,\n      '--container-density': density,\n      '--container-size': sizeCategory,\n    }),\n    [dimensions, density, sizeCategory]\n  );\n\n  return (\n    <ContainerContext.Provider value={contextValue}>\n      <div\n        ref={containerRef}\n        className={className}\n        style={{ ...containerStyles, ...cssVariables } as CSSProperties}\n        data-adaptive-container\n        data-size={sizeCategory}\n        data-density={density}\n        data-narrow={isNarrow}\n        data-wide={isWide}\n      >\n        {children}\n      </div>\n    </ContainerContext.Provider>\n  );\n};\n\nexport const AdaptiveContainer = memo(AdaptiveContainerComponent);\n\nAdaptiveContainer.displayName = 'AdaptiveContainer';\n\n// =============================================================================\n// CONTAINER QUERY HOOK\n// =============================================================================\n\n/**\n * Hook for container-based media query behavior.\n *\n * @param query - Size category or width threshold\n * @returns Whether the query matches\n *\n * @example\n * ```tsx\n * function ResponsiveComponent() {\n *   const isLarge = useContainerQuery('lg');\n *   const isWiderThan600 = useContainerQuery(600);\n *\n *   return isLarge ? <LargeLayout /> : <SmallLayout />;\n * }\n * ```\n */\nexport function useContainerQuery(query: keyof ContainerBreakpoints | number): boolean {\n  const context = useContainerContext();\n\n  if (context === undefined || context === null) {\n    // If not in a container context, fall back to viewport-based query\n    if (typeof query === 'number') {\n      return typeof window !== 'undefined' && window.innerWidth >= query;\n    }\n    return false;\n  }\n\n  if (typeof query === 'number') {\n    return context.containerWidth >= query;\n  }\n\n  const sizeOrder: (keyof ContainerBreakpoints)[] = ['xs', 'sm', 'md', 'lg', 'xl'];\n  const queryIndex = sizeOrder.indexOf(query);\n  const currentIndex = sizeOrder.indexOf(context.sizeCategory ?? 'md');\n\n  return currentIndex >= queryIndex;\n}\n\n/**\n * Hook for getting responsive values based on container size.\n *\n * @param values - Object mapping size categories to values\n * @returns The value for the current container size\n *\n * @example\n * ```tsx\n * function ResponsiveComponent() {\n *   const columns = useContainerValue({\n *     xs: 1,\n *     sm: 2,\n *     md: 3,\n *     lg: 4,\n *     xl: 6,\n *   });\n *\n *   return <Grid columns={columns}>{children}</Grid>;\n * }\n * ```\n */\nexport function useContainerValue<T>(\n  values: Partial<Record<keyof ContainerBreakpoints, T>>\n): T | undefined {\n  const context = useContainerContext();\n\n  if (context === undefined || context === null) {\n    // Return the smallest defined value as fallback\n    return values.xs ?? values.sm ?? values.md ?? values.lg ?? values.xl;\n  }\n\n  const sizeOrder: (keyof ContainerBreakpoints)[] = ['xs', 'sm', 'md', 'lg', 'xl'];\n  const currentIndex = sizeOrder.indexOf(context.sizeCategory ?? 'md');\n\n  // Find the closest defined value at or below current size\n  for (let i = currentIndex; i >= 0; i--) {\n    const size = sizeOrder[i];\n    if (size !== undefined && size in values) {\n      return values[size];\n    }\n  }\n\n  // Fall back to smallest defined value\n  for (const size of sizeOrder) {\n    if (size in values) {\n      return values[size];\n    }\n  }\n\n  return undefined;\n}\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n\nexport { ContainerContext };\nexport type { AdaptiveContainerProps, ContainerContextValue };\n"],"names":["DEFAULT_BREAKPOINTS","DEFAULT_PADDING","DENSITY_THRESHOLDS","useContainerContext","useContext","ContainerContext","getSizeCategory","width","breakpoints","xs","sm","md","lg","xl","calculateDensity","childCount","dimensions","area","densityRatio","normalizePadding","padding","paddingToCSS","spacing","AdaptiveContainerComponent","children","detectDensity","maxWidth","centered","className","style","containerRef","useRef","setDimensions","useState","normalizedPadding","useMemo","sizeCategory","Children","density","isNarrow","isWide","useEffect","container","observer","entries","entry","contextValue","query","breakpointValue","containerStyles","baseStyles","reducedPadding","cssVariables","jsx","AdaptiveContainer","memo","useContainerQuery","context","sizeOrder","queryIndex","useContainerValue","values","currentIndex","i","size"],"mappings":";;;AAwCA,MAAMA,IAA4C;AAAA,EAChD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN,GAKMC,IAAkB,IAKlBC,IAAqB;AAAA,EACzB,SAAS;AAAA,EACT,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAER;AAWO,SAASC,IAAoD;AAClE,SAAOC,EAAWC,CAAgB;AACpC;AASA,SAASC,EACPC,GACAC,GAC4B;AAC5B,QAAM,EAAE,IAAAC,IAAK,KAAK,IAAAC,IAAK,KAAK,IAAAC,IAAK,KAAK,IAAAC,IAAK,MAAM,IAAAC,IAAK,KAAA,IAASL;AAG/D,SADID,IAAQE,KACRF,IAAQG,IAAW,OACnBH,IAAQI,IAAW,OACnBJ,IAAQK,IAAW,OACnBL,IAAQM,IAAW,OAChB;AACT;AAKA,SAASC,EAAiBC,GAAoBC,GAAwC;AACpF,MAAID,MAAe,EAAG,QAAO;AAE7B,QAAME,IAAOD,EAAW,QAAQA,EAAW;AAC3C,MAAIC,MAAS,EAAG,QAAO;AAGvB,QAAMC,IAAgBH,IAAaE,IAAQ;AAE3C,SAAIC,KAAgBhB,EAAmB,UAAgB,YACnDgB,KAAgBhB,EAAmB,MAAY,QAC/CgB,KAAgBhB,EAAmB,SAAe,WAClDgB,KAAgBhB,EAAmB,OAAa,SAC7C;AACT;AAKA,SAASiB,EAAiBC,GAA0C;AAClE,SAAI,OAAOA,KAAY,WACd,EAAE,KAAKA,GAAS,OAAOA,GAAS,QAAQA,GAAS,MAAMA,EAAA,IAEzDA;AACT;AAKA,SAASC,EAAaC,GAA6B;AACjD,SAAO,GAAGA,EAAQ,GAAG,MAAMA,EAAQ,KAAK,MAAMA,EAAQ,MAAM,MAAMA,EAAQ,IAAI;AAChF;AA4BA,MAAMC,IAA6B,CAAC;AAAA,EAClC,UAAAC;AAAA,EACA,aAAAhB,IAAcR;AAAA,EACd,eAAAyB,IAAgB;AAAA,EAChB,SAAAL,IAAUnB;AAAA,EACV,UAAAyB;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,OAAAC;AACF,MAAyC;AAEvC,QAAMC,IAAeC,EAAuB,IAAI,GAG1C,CAACf,GAAYgB,CAAa,IAAIC,EAAqB,EAAE,OAAO,GAAG,QAAQ,GAAG,GAG1EC,IAAoBC,EAAQ,MAAMhB,EAAiBC,CAAO,GAAG,CAACA,CAAO,CAAC,GAGtEgB,IAAeD;AAAA,IACnB,MAAM7B,EAAgBU,EAAW,OAAOR,CAAW;AAAA,IACnD,CAACQ,EAAW,OAAOR,CAAW;AAAA,EAAA,GAG1BO,IAAaoB,EAAQ,MAAME,EAAS,MAAMb,CAAQ,GAAG,CAACA,CAAQ,CAAC,GAE/Dc,IAAUH;AAAA,IACd,MAAOV,IAAgBX,EAAiBC,GAAYC,CAAU,IAAI;AAAA,IAClE,CAACS,GAAeV,GAAYC,CAAU;AAAA,EAAA,GAGlCuB,IAAWH,MAAiB,QAAQA,MAAiB,MACrDI,IAASJ,MAAiB,QAAQA,MAAiB;AAGzD,EAAAK,EAAU,MAAM;AACd,UAAMC,IAAYZ,EAAa;AAC/B,QAAI,CAACY,EAAW;AAEhB,UAAMC,IAAW,IAAI,eAAe,CAACC,MAAY;AAC/C,YAAM,CAACC,CAAK,IAAID;AAChB,MAAIC,MAAU,UACZb,EAAc;AAAA,QACZ,OAAOa,EAAM,YAAY;AAAA,QACzB,QAAQA,EAAM,YAAY;AAAA,MAAA,CAC3B;AAAA,IAEL,CAAC;AAED,WAAAF,EAAS,QAAQD,CAAS,GAEnB,MAAMC,EAAS,WAAA;AAAA,EACxB,GAAG,CAAA,CAAE;AAGL,QAAMG,IAAeX;AAAA,IACnB,OAAO;AAAA,MACL,gBAAgBnB,EAAW;AAAA,MAC3B,iBAAiBA,EAAW;AAAA,MAC5B,aAAa;AAAA,QACX,IAAIR,EAAY,MAAOR,EAAoB;AAAA,QAC3C,IAAIQ,EAAY,MAAOR,EAAoB;AAAA,QAC3C,IAAIQ,EAAY,MAAOR,EAAoB;AAAA,QAC3C,IAAIQ,EAAY,MAAOR,EAAoB;AAAA,MAAA;AAAA,MAE7C,cAAc,CAAC+C,MAA+C;AAC5D,YAAI,OAAOA,KAAU;AACnB,iBAAO/B,EAAW,SAAS+B;AAE7B,cAAMC,IAAkBxC,EAAYuC,CAAK;AACzC,eAAOC,MAAoB,UAAahC,EAAW,SAASgC;AAAA,MAC9D;AAAA,MACA,SAAS,CAACD,MAA+C;AACvD,YAAI,OAAOA,KAAU;AACnB,iBAAO/B,EAAW,QAAQ+B;AAE5B,cAAMC,IAAkBxC,EAAYuC,CAAK;AACzC,eAAOC,MAAoB,UAAahC,EAAW,QAAQgC;AAAA,MAC7D;AAAA,MACA,SAAS,CAACD,MAA+C;AACvD,YAAI,OAAOA,KAAU;AACnB,iBAAO/B,EAAW,QAAQ+B;AAE5B,cAAMC,IAAkBxC,EAAYuC,CAAK;AACzC,eAAOC,MAAoB,UAAahC,EAAW,QAAQgC;AAAA,MAC7D;AAAA,IAAA;AAAA,IAEF,CAAChC,GAAYR,CAAW;AAAA,EAAA,GAIpByC,IAAkBd,EAAuB,MAAM;AACnD,UAAMe,IAA4B;AAAA,MAChC,OAAO;AAAA,MACP,SAAS7B,EAAaa,CAAiB;AAAA,MACvC,WAAW;AAAA;AAAA,MAEX,eAAe;AAAA,MACf,GAAGL;AAAA,IAAA;AAaL,QAV8BH,KAAa,SACzCwB,EAAW,WAAW,OAAOxB,KAAa,WAAW,GAAGA,CAAQ,OAAOA,IAGrEC,MAAa,OACfuB,EAAW,aAAa,QACxBA,EAAW,cAAc,SAIvBX,GAAU;AACZ,YAAMY,IAAiBhC;AAAA,QACrB,KAAK,IAAI,IAAI,OAAOC,KAAY,WAAWA,IAAU,MAAM,CAAC;AAAA,MAAA;AAE9D,MAAA8B,EAAW,UAAU7B,EAAa8B,CAAc;AAAA,IAClD;AAEA,WAAOD;AAAA,EACT,GAAG,CAAChB,GAAmBR,GAAUC,GAAUY,GAAUnB,GAASS,CAAK,CAAC,GAG9DuB,IAAejB;AAAA,IACnB,OAAO;AAAA,MACL,qBAAqB,GAAGnB,EAAW,KAAK;AAAA,MACxC,sBAAsB,GAAGA,EAAW,MAAM;AAAA,MAC1C,uBAAuBsB;AAAA,MACvB,oBAAoBF;AAAA,IAAA;AAAA,IAEtB,CAACpB,GAAYsB,GAASF,CAAY;AAAA,EAAA;AAGpC,SACE,gBAAAiB,EAAChD,EAAiB,UAAjB,EAA0B,OAAOyC,GAChC,UAAA,gBAAAO;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKvB;AAAA,MACL,WAAAF;AAAA,MACA,OAAO,EAAE,GAAGqB,GAAiB,GAAGG,EAAA;AAAA,MAChC,2BAAuB;AAAA,MACvB,aAAWhB;AAAA,MACX,gBAAcE;AAAA,MACd,eAAaC;AAAA,MACb,aAAWC;AAAA,MAEV,UAAAhB;AAAA,IAAA;AAAA,EAAA,GAEL;AAEJ,GAEa8B,IAAoBC,EAAKhC,CAA0B;AAEhE+B,EAAkB,cAAc;AAsBzB,SAASE,EAAkBT,GAAqD;AACrF,QAAMU,IAAUtD,EAAA;AAEhB,MAA6BsD,KAAY;AAEvC,WAAI,OAAOV,KAAU,WACZ,OAAO,SAAW,OAAe,OAAO,cAAcA,IAExD;AAGT,MAAI,OAAOA,KAAU;AACnB,WAAOU,EAAQ,kBAAkBV;AAGnC,QAAMW,IAA4C,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI,GACzEC,IAAaD,EAAU,QAAQX,CAAK;AAG1C,SAFqBW,EAAU,QAAQD,EAAQ,gBAAgB,IAAI,KAE5CE;AACzB;AAuBO,SAASC,EACdC,GACe;AACf,QAAMJ,IAAUtD,EAAA;AAEhB,MAA6BsD,KAAY;AAEvC,WAAOI,EAAO,MAAMA,EAAO,MAAMA,EAAO,MAAMA,EAAO,MAAMA,EAAO;AAGpE,QAAMH,IAA4C,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI,GACzEI,IAAeJ,EAAU,QAAQD,EAAQ,gBAAgB,IAAI;AAGnE,WAASM,IAAID,GAAcC,KAAK,GAAGA,KAAK;AACtC,UAAMC,IAAON,EAAUK,CAAC;AACxB,QAAIC,MAAS,UAAaA,KAAQH;AAChC,aAAOA,EAAOG,CAAI;AAAA,EAEtB;AAGA,aAAWA,KAAQN;AACjB,QAAIM,KAAQH;AACV,aAAOA,EAAOG,CAAI;AAKxB;"}