{"version":3,"file":"Page.mjs","sources":["../../../../src/lib/ui/layout/Page.tsx"],"sourcesContent":["/**\n * @file Page Layout Component\n * @description Standard page wrapper (title, metadata, padding)\n * Uses theme tokens for consistent styling\n */\n\nimport React, { type ReactNode, useEffect, memo, useMemo, type CSSProperties } from 'react';\nimport { colorTokens, tokens } from '../../theme/tokens';\n\n/**\n * Page component props\n */\nexport interface PageProps {\n  /** Page title (shown in browser tab and header) */\n  title?: string;\n\n  /** Page description for metadata */\n  description?: string;\n\n  /** Page content */\n  children: ReactNode;\n\n  /** Additional CSS class */\n  className?: string;\n\n  /** Custom page styles */\n  style?: React.CSSProperties;\n\n  /** Whether to show the title in page */\n  showTitle?: boolean;\n\n  /** Header actions (buttons, etc.) */\n  actions?: ReactNode;\n\n  /** Max width constraint */\n  maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';\n\n  /** Padding size */\n  padding?: 'none' | 'sm' | 'md' | 'lg';\n\n  /** Loading state */\n  isLoading?: boolean;\n\n  /** Back button handler */\n  onBack?: () => void;\n}\n\n/**\n * Max width values\n */\nconst maxWidthMap = {\n  sm: '640px',\n  md: '768px',\n  lg: '1024px',\n  xl: '1280px',\n  '2xl': '1536px',\n  full: '100%',\n};\n\n/**\n * Padding values\n */\nconst paddingMap = {\n  none: '0',\n  sm: '1rem',\n  md: '1.5rem',\n  lg: '2rem',\n};\n\n// ============================================================================\n// STATIC STYLES - Extracted outside component to prevent re-creation\n// ============================================================================\n\nconst headerStyle: CSSProperties = {\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'space-between',\n  marginBottom: '1.5rem',\n};\n\nconst headerLeftStyle: CSSProperties = {\n  display: 'flex',\n  alignItems: 'center',\n  gap: '0.75rem',\n};\n\nconst backButtonStyle: CSSProperties = {\n  display: 'flex',\n  alignItems: 'center',\n  justifyContent: 'center',\n  width: '2rem',\n  height: '2rem',\n  border: 'none',\n  background: 'none',\n  cursor: 'pointer',\n  borderRadius: tokens.radius.md,\n  color: colorTokens.text.secondary,\n};\n\nconst titleStyle: CSSProperties = {\n  fontSize: tokens.fontSize['2xl'],\n  fontWeight: tokens.fontWeight.semibold,\n  margin: 0,\n  color: colorTokens.text.primary,\n};\n\nconst actionsContainerStyle: CSSProperties = {\n  display: 'flex',\n  gap: '0.5rem',\n};\n\n/**\n * Page component - memoized for performance\n */\nexport const Page = memo(\n  ({\n    title,\n    description,\n    children,\n    className = '',\n    style,\n    showTitle = true,\n    actions,\n    maxWidth = 'xl',\n    padding = 'md',\n    isLoading = false,\n    onBack,\n  }: PageProps): React.ReactElement => {\n    // Update document title\n    useEffect(() => {\n      if (title !== undefined && title !== '') {\n        const baseTitle = 'App'; // Could come from config\n        document.title = `${title} | ${baseTitle}`;\n      }\n    }, [title]);\n\n    // Update meta description\n    useEffect(() => {\n      if (description !== undefined && description !== '') {\n        const metaDesc = document.querySelector('meta[name=\"description\"]');\n        if (metaDesc) {\n          metaDesc.setAttribute('content', description);\n        }\n      }\n    }, [description]);\n\n    // Memoize container style\n    const containerStyle = useMemo<CSSProperties>(\n      () => ({\n        maxWidth: maxWidthMap[maxWidth],\n        margin: '0 auto',\n        padding: paddingMap[padding],\n        opacity: isLoading ? 0.7 : 1,\n        transition: 'opacity 0.2s',\n        ...style,\n      }),\n      [maxWidth, padding, isLoading, style]\n    );\n\n    return (\n      <div className={className} style={containerStyle}>\n        {/* Page Header */}\n        {(showTitle === true && title !== undefined && title !== '') ||\n        actions !== undefined ||\n        onBack !== undefined ? (\n          <header style={headerStyle}>\n            <div style={headerLeftStyle}>\n              {onBack !== undefined && (\n                <button onClick={onBack} style={backButtonStyle} aria-label=\"Go back\">\n                  <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n                    <path\n                      fillRule=\"evenodd\"\n                      d=\"M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z\"\n                      clipRule=\"evenodd\"\n                    />\n                  </svg>\n                </button>\n              )}\n\n              {showTitle === true && title !== undefined && title !== '' && (\n                <h1 style={titleStyle}>{title}</h1>\n              )}\n            </div>\n\n            {actions !== undefined && <div style={actionsContainerStyle}>{actions}</div>}\n          </header>\n        ) : null}\n\n        {/* Page Content */}\n        <main>{children}</main>\n      </div>\n    );\n  }\n);\n\nPage.displayName = 'Page';\n"],"names":["maxWidthMap","paddingMap","headerStyle","headerLeftStyle","backButtonStyle","tokens","colorTokens","titleStyle","actionsContainerStyle","Page","memo","title","description","children","className","style","showTitle","actions","maxWidth","padding","isLoading","onBack","useEffect","metaDesc","containerStyle","useMemo","jsxs","jsx"],"mappings":"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"}