// Copyright (c) Meta Platforms, Inc. and affiliates. /** * @file Section.tsx * @input Uses container utility, StyleX * @output Exports Section component and SectionProps * @position Core section container component * * SYNC: When modified, update these files to stay in sync: * - /packages/core/src/Section/Section.doc.mjs (props table, features) * - /packages/core/src/Section/index.ts (exports if types change) * - /apps/storybook/stories/Section.stories.tsx (storybook stories) * - /packages/cli/assets/templates/blocks/components/Section/ (showcase blocks) */ import type { ReactNode } from 'react'; import * as stylex from "../style-runtime.js"; import "../theme/tokens.stylex.js"; import { colorVars } from "../theme/tokens.stylex.js"; import type { BaseProps } from "../BaseProps.js"; import { container } from "../Layout/container.stylex.js"; import type { SpacingToken } from "../Layout/container.stylex.js"; import { paddingStyles, paddingInlineStyles, paddingInlineStartStyles, paddingInlineEndStyles, paddingBlockStyles, paddingBlockStartStyles, paddingBlockEndStyles, containerPaddingInlineVarStyles, containerPaddingInlineStartVarStyles, containerPaddingInlineEndVarStyles, containerPaddingBlockStartVarStyles, containerPaddingBlockEndVarStyles, sectionPaddingPropagationStyles, spacingStepToToken } from "../Layout/padding.stylex.js"; import type { SizeValue, SpacingStep } from "../utils/types.js"; import { mergeProps } from "../utils/index.js"; import { themeProps } from "../utils/themeProps.js"; import type { SectionVariantMap } from "./index.js"; /** * Visual variant for the section. * Extensible via module augmentation of SectionVariantMap. */ export type SectionVariant = keyof SectionVariantMap; const variantStyles = { section: { kWkggS: "x10xzikg", $$css: true as const }, transparent: { kWkggS: "xjbqb8w", $$css: true as const }, muted: { kWkggS: "xwmxj5m", $$css: true as const } }; // Styles for escaping parent container padding when nested const nestedStyles = { outer: { keTefX: "xojxgvx", k71WvV: "x1fcf3bl", keoZOQ: "xkibk3", k1K539: "xlayyun", $$css: true as const }, inner: { "--container-padding-inline-start": "xrhngw9", "--container-padding-inline-end": "xjsfl84", "--container-padding-block-start": "x1047aw6", "--container-padding-block-end": "xax9j7h", kZKoxP: "x5yr21d", $$css: true as const } }; // Divider styles for each side const dividerStyles = { top: { kEafiO: "x178xt8z", kPef9Z: "x13fuv20", kLZC3w: "x1pc3f07", $$css: true as const }, bottom: { kt9PQ7: "xso031l", kfdmCh: "x1q0q8m5", kL6WhQ: "xw8gpjh", $$css: true as const }, start: { k2ei4v: "xpilrb4", kVhnKS: "x1t7ytsu", kGJrpR: "x1j92z86", $$css: true as const }, end: { ke9TFa: "x1lun4ml", k8ry5P: "x18b5jzi", kBCPoo: "x1gejf6u", $$css: true as const } }; // Dynamic styles for sizing props const dynamicStyles = { sizing: (width: SizeValue | null, height: SizeValue | null, maxWidth: SizeValue | null, minHeight: SizeValue | null) => [{ kzqmXN: width != null ? "x5lhr3w" : width, kZKoxP: height != null ? "x16ye13r" : height, ks0D6T: maxWidth != null ? "xf68679" : maxWidth, kAzted: minHeight != null ? "x82snj4" : minHeight, $$css: true as const }, { "--x-width": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(width), "--x-height": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(height), "--x-maxWidth": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(maxWidth), "--x-minHeight": (val => typeof val === "number" ? val + "px" : val != null ? val : undefined)(minHeight) }] }; export interface SectionProps extends BaseProps { ref?: React.Ref; /** * Visual variant of the section. * - 'section': Surface background color * - 'transparent': Fully transparent background * - 'muted': Muted background color * @default 'section' */ variant?: SectionVariant; /** * Width of the section. * Numbers are treated as pixels, strings are used as-is. */ width?: SizeValue; /** * Height of the section. * Numbers are treated as pixels, strings are used as-is. */ height?: SizeValue; /** * Maximum width of the section. * Numbers are treated as pixels, strings are used as-is. */ maxWidth?: SizeValue; /** * Minimum height of the section. * Numbers are treated as pixels, strings are used as-is. */ minHeight?: SizeValue; /** * Content to render inside the section. * Should typically be Layout child components. */ children?: ReactNode; /** * Which sides should have divider borders. * Use 'start'/'end' for horizontal (respects RTL). * @example * ``` * dividers={['top', 'bottom']} * ``` */ dividers?: ('top' | 'bottom' | 'start' | 'end')[]; /** * Internal padding of the section using the spacing scale. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. * @default 4 (16px) */ padding?: SpacingStep; /** * Inline (horizontal) padding override. When set, overrides only the inline * axis padding while preserving block padding from `padding` or the * container theme default. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingInline?: SpacingStep; /** * Inline-start padding override. Logical: the left edge in LTR, the right * edge in RTL. Takes precedence over `paddingInline` and `padding` on that * edge only; every other edge is left alone. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingInlineStart?: SpacingStep; /** * Inline-end padding override. Logical: the right edge in LTR, the left * edge in RTL. Takes precedence over `paddingInline` and `padding` on that * edge only; every other edge is left alone. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingInlineEnd?: SpacingStep; /** * Block (vertical) padding override. When set, overrides only the block * axis padding while preserving inline padding from `padding` or the * container theme default. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingBlock?: SpacingStep; /** * Block-start (top) padding override. Takes precedence over `paddingBlock` * and `padding` on that edge only; the block-end edge and both inline edges * are left alone. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingBlockStart?: SpacingStep; /** * Block-end (bottom) padding override. Takes precedence over `paddingBlock` * and `padding` on that edge only; the block-start edge and both inline * edges are left alone. * Accepts numeric spacing steps: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10. */ paddingBlockEnd?: SpacingStep; } /** * A section container with background variants. * * Applies section-specific appearance based on the variant prop * and sets CSS variables for child layout components. * * @compositionHint Use inside Card to create visually distinct regions. * Sections automatically escape parent container padding for edge-to-edge fills. * * @example * ``` *
* Content in muted section} * /> *
* ``` */ export function Section({ variant = 'section', width, height, maxWidth, minHeight, children, dividers, padding, paddingInline, paddingInlineStart, paddingInlineEnd, paddingBlock, paddingBlockStart, paddingBlockEnd, xstyle, className, style, ref, ...props }: SectionProps) { // When no explicit padding prop, use theme default (set via container tokens) const useThemeDefault = padding == null; const effectivePadding = padding ?? 4; const paddingToken = spacingStepToToken[effectivePadding] as SpacingToken; const outerStylex = stylex.props(nestedStyles.outer, dynamicStyles.sizing(width ?? null, height ?? null, maxWidth ?? null, minHeight ?? null), xstyle); return
} className={[outerStylex.className, className].filter(Boolean).join(' ') || undefined} style={style && outerStylex.style ? { ...outerStylex.style, ...style } : style || outerStylex.style} {...props}>
{children}
; } Section.displayName = 'Section';