// Copyright (c) Meta Platforms, Inc. and affiliates.
'use client';
/**
* @file Step.tsx
* @input Uses React, stylex, theme tokens (including the motion duration token
* the connector fill animates on), StepperContext, and per-step theme selector
* state
* @output Exports Step component and StepProps
* @position Individual step item; used inside Stepper
*
* Every connector this file draws — the separated progress bars and the
* on-track segments alike — paints its accent fill as a scaled ::before rather
* than by swapping a background color, so a step the flow advances into grows
* its line along the track. See the CONNECTOR FILL block in the styles below
* for the axis/RTL/reduced-motion rules that go with it.
*
* Exactly one change animates: advancing a single step. Going back, jumping
* forward by more than one, and mounting mid-flow all land at once. The rule
* and the reasoning behind it sit above the styles; the arithmetic that keeps
* the one animated span reading as a single front — an on-track span is drawn
* by two steps, three where a content slot splits it — is in the component.
* Nothing about it is public API: Stepper hands each Step the step it came
* from through context, and the rest is derived. In a compact horizontal
* Stepper, each track node is presentational rather than clickable; navigation
* moves to the named previous/next controls in the summary row. The on-track
* layout keeps each indicator on the rail and does not repeat the active one
* beside the summary label. Each public content slot stays mounted and is
* hidden to preserve local state.
*
* SYNC: When modified, update these files to stay in sync:
* - /packages/core/src/Stepper/Stepper.doc.mjs
* - /packages/core/src/Stepper/Stepper.test.tsx
* - /packages/core/src/Stepper/index.ts
* - /apps/storybook/stories/Stepper.stories.tsx
* - /packages/cli/assets/templates/blocks/components/Stepper/ (showcase blocks)
* - /packages/cli/assets/templates/blocks/components/Step/ (showcase blocks)
*/
import { useLayoutEffect, type ReactNode } from 'react';
import { createPortal } from 'react-dom';
import * as stylex from "../style-runtime.js";
import "../theme/tokens.stylex.js";
import { colorVars, spacingVars, radiusVars, fontWeightVars, typeScaleVars, textSizeVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
import { focusOutlineStyles, mergeProps, isRenderable, themeProps } from "../utils/index.js";
import { interactionOverlayStyles } from "../utils/interactionOverlay.stylex.js";
import type { BaseProps } from "../BaseProps.js";
import { Icon } from "../Icon/index.js";
import { VisuallyHidden } from "../VisuallyHidden/index.js";
import { useTranslator } from "../i18n/index.js";
import { useStepperInternalContext } from "./StepperContext.js";
import "./stepper.stylex.js";
import { stepMarker } from "./stepper.stylex.js";
import type { StepStatus } from "./StepStatus.js";
/**
* Built-in indicator presets. Anything other than these strings passed to
* `indicator` is treated as a custom ReactNode (e.g. an ``).
* - 'auto': numbered badge for not-yet-reached steps, a check once completed
* (default)
* - 'number': always a numbered badge
* - 'none': no indicator — just the progress bar and label
*/
export type StepIndicatorPreset = 'auto' | 'number' | 'none';
export type StepDensity = 'compact' | 'balanced' | 'spacious';
export interface StepProps extends BaseProps {
/** Ref forwarded to the root element */
ref?: React.Ref;
/**
* Zero-based index of this step. Used to derive progress (completed /
* active / not-started) relative to the parent's `activeStep`.
*/
step: number;
/**
* Step label text.
*/
label: string;
/**
* Optional description shown below the label.
*/
description?: string;
/**
* Content rendered below the label and description. Useful in vertical
* steppers to show form fields or detailed content for each step. Compact
* horizontal steppers hide it without unmounting it, preserving local state.
*/
children?: ReactNode;
/**
* Semantic status for the step, mapped to the global Astryx semantic tokens
* (`accent`, `success`, `warning`, `error`). In the default `auto` indicator
* mode it sets both the indicator color and a matching glyph: `success` shows
* a green check-circle, `warning`/`error` show the shared Input status icons.
* `accent` is color-only. The current (in-progress) step always keeps its
* current-step indicator regardless of `status`. Never recolors the
* connector/track.
*
* Because the indicator glyphs are decorative (aria-hidden), the status also
* reaches assistive technology as text: visually hidden "completed" /
* "warning" / "error" next to the label, and composed into the accessible
* name of clickable steps.
*/
status?: StepStatus;
/**
* Disable interaction for this step.
* @default false
*/
isDisabled?: boolean;
/**
* Marks the step as optional, appending an "Optional" affordance after the
* label.
* @default false
*/
isOptional?: boolean;
/**
* Trailing content rendered at the end of the label row (e.g. a timestamp
* or status chip).
*/
endContent?: ReactNode;
/**
* What to show as the step indicator. Accepts a preset string or any
* ReactNode:
* - 'auto': numbered badge until completed, then a check (default)
* - 'number': always a numbered badge
* - 'none': no indicator, just the bar + label
* - ReactNode: any custom icon or element to render as the indicator
* @default 'auto'
*/
indicator?: StepIndicatorPreset | ReactNode;
/**
* Controls vertical padding of the step. Falls back to the stepper-level
* density when unset.
* - 'compact': minimal padding (4px block)
* - 'balanced': default (8px block)
* - 'spacious': generous (12px block, 12px inline)
*/
density?: StepDensity;
}
// --- Default progress icons (16px) ---
//
// The `completed` progress state and the current-step ring are drawn as local
//