{
  "absorbed": [
    "SpaceCompact"
  ],
  "example": "import { Flex } from \"@godxjp/ui/layout\";\nimport { Button } from \"@godxjp/ui/general\";\n\n<Flex direction=\"row\" gap=\"sm\" align=\"center\" justify=\"between\" wrap>\n  <SearchSummary />\n  <Flex direction=\"row\" gap=\"xs\" align=\"center\" wrap>\n    <Button variant=\"outline\">リセット</Button>\n    <Button>適用</Button>\n  </Flex>\n</Flex>",
  "group": "layout",
  "importPath": "@godxjp/ui/layout",
  "name": "Flex",
  "props": [
    {
      "defaultValue": "false",
      "description": "Weld the children into one control — antd Space.Compact (v32 folded `SpaceCompact` in here). Each child gets its own flex-item wrapper, inner corner radii are zeroed and the shared border collapses to one hairline; each child keeps its own focus ring, name and `size`. `direction` picks the axis (\"row\" default, \"col\"); `gap`/`wrap`/`pad` and the other layout knobs do not apply (a seam has no gap). Named (aria-label/-labelledby, e.g. by a wrapping FormField) it becomes role=\"group\".",
      "name": "attached",
      "type": "boolean"
    },
    {
      "defaultValue": "false",
      "description": "`attached` only. The joined row fills its parent's inline size (antd `block`, renamed to match Button.fullWidth). Field children grow to fill it; a Button keeps its content width (gh#1062).",
      "name": "fullWidth",
      "type": "boolean"
    },
    {
      "description": "`attached` only. Scoped control density for the whole joined row (antd Space.Compact `size`). Each child still carries its OWN `size` prop.",
      "name": "density",
      "type": "\"compact\" | \"default\" | \"comfortable\""
    },
    {
      "description": "Floating child actions shown on parent hover/focus-within; always visible on touch.",
      "name": "reveal",
      "type": "\"hover\""
    },
    {
      "description": "Negative inline inset on the token scale.",
      "name": "bleed",
      "type": "GapProp"
    },
    {
      "description": "Lightweight surface, without Card structure.",
      "name": "surface",
      "type": "\"muted\" | \"popover\" | \"warning\""
    },
    {
      "description": "false prevents shrinking.",
      "name": "shrink",
      "type": "boolean"
    },
    {
      "description": "Grow into remaining flex space.",
      "name": "grow",
      "type": "boolean"
    },
    {
      "description": "Semantic element. A list keeps its marker and indentation unless marker=\"none\" says otherwise.",
      "name": "as",
      "type": "\"div\" | \"span\" | \"ul\" | \"ol\" | \"li\""
    },
    {
      "defaultValue": "as=\"ul\" → \"disc\", as=\"ol\" → \"decimal\"",
      "description": "Marker for a LIST element; ignored by every other tag. marker=\"none\" emits NO data-list, so the list keeps its <ul>/<ol>, its <li> semantics and its gap token, and loses the bullet AND the --space-5 indent — that is the container a short entity list needs: <Flex as=\"ul\" marker=\"none\" direction=\"col\" gap=\"none\"> with <ListRow as=\"li\"> rows. Before it, the bullet was unconditional and .ui-flex[data-list] > li { display: list-item } outranked [data-slot=\"list-row\"] { display: flex }, so rows fell out of flex layout (94.58px tall instead of 69.98px) and the only move left was a raw <ul>, which carries no gap token (gh#714). disc/decimal stay available so an <ol> can be bulleted, or a <ul> numbered, without a list-style-type in a className.",
      "name": "marker",
      "type": "\"disc\" | \"decimal\" | \"none\""
    },
    {
      "description": "Responsive axis; omitted steps inherit.",
      "name": "direction",
      "type": "\"row\" | \"col\" | {base?: \"row\" | \"col\"; sm?: \"row\" | \"col\"; md?: \"row\" | \"col\"; lg?: \"row\" | \"col\"; xl?: \"row\" | \"col\"}"
    },
    {
      "defaultValue": "\"md\"",
      "description": "Token gap between children, shared with other layout primitives. \"none\" is a DELIBERATE zero for two lines that read as one block — a name over its role, a weekday over its date, a tab bar with no seam — not a way to opt out of the token scale.",
      "name": "gap",
      "type": "\"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\""
    },
    {
      "description": "ESCAPE HATCH: a gap in pixels, off every step of the scale. Real designs land on 2px, 5px, 6px, 10px, 14px — rounding to the nearest named step drifts the layout, and writing the literal in a className is blocked by ui-audit. Spend the ten named steps FIRST: `gap={3}` is 12px and follows the user's --scaling, gapRaw does not. It wins over `gap` (which then emits no class, so the two cannot fight over specificity) and leaves data-gap-raw on the DOM, so every escape stays countable.",
      "name": "gapRaw",
      "type": "number"
    },
    {
      "description": "Inner padding on the token scale — one step for all four sides, or an object keyed by LOGICAL side. Exists because a missing padding prop produced 42 of 51 ui-audit errors in one real consumer (gh#408): `<Flex className=\"p-3\">` was the only move left.",
      "name": "pad",
      "type": "number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }"
    },
    {
      "description": "Raw-pixel padding for values off the scale, same contract and same price as gapRaw: it leaves data-pad-raw on the DOM so each escape is countable. Overrides `pad` PER SIDE, not as a whole.",
      "name": "padRaw",
      "type": "number | { inline?, block?, inlineStart?, inlineEnd?, blockStart?, blockEnd? }"
    },
    {
      "defaultValue": "false",
      "description": "Take the space the siblings leave — the ELASTIC column of a `fixed | elastic | fixed` row (name · meter · figures). Also sets min-inline-size: 0, which is what lets a truncating child ellipse instead of pushing the row wider. Without this axis the only move was className=\"flex-1 min-w-0\", which ui-audit blocks (gh#405 §2).",
      "name": "fill",
      "type": "boolean"
    },
    {
      "description": "A FIXED column: number = px, string = any CSS length. Comes with flex: none — a width a sibling can still squeeze is a suggestion, and stacked rows would start at different x offsets. Leaves data-width-raw on the DOM so the measurement stays countable, like gapRaw/padRaw.",
      "name": "width",
      "type": "number | string"
    },
    {
      "description": "CENTRE this box and CAP it at a page measure (--page-measure-narrow 42rem / -medium 48rem / -wide 72rem): margin-inline:auto + inline-size:100% + max-inline-size. THE public answer to \"full-bleed outside, measured column inside\" — a marketing <section> paints edge to edge and its inner Flex measure=\"wide\" holds the content on the page measure. Deliberately NOT on PageContainer: that owns page padding and a header/toolbar/footer scaffold, so a full-bleed page cannot consume it, and the refusal left the centred column owned by nobody — three showcases each hand-wrote the same four declarations (gh#839). It adds NO gutter: the page inset is pad={{ inline: 6 }}, and one band with two padding owners drifts. A MAX, so nothing binds below the cap at 390px. An explicit `width` wins. Do not give a READING column \"wide\" — prose stays narrow/medium, which bracket Bringhurst's 45-75 characters. Omitted emits no attribute at all.",
      "name": "measure",
      "type": "\"narrow\" | \"medium\" | \"wide\""
    },
    {
      "description": "Cross-axis alignment, emitted as a data attribute for the layout CSS.",
      "name": "align",
      "type": "\"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\""
    },
    {
      "description": "Main-axis distribution, emitted as a data attribute for the layout CSS.",
      "name": "justify",
      "type": "\"start\" | \"center\" | \"end\" | \"between\" | \"around\" | \"evenly\""
    },
    {
      "defaultValue": "false",
      "description": "Allows children to wrap onto additional flex lines.",
      "name": "wrap",
      "type": "boolean"
    },
    {
      "description": "Drop this region below a canonical breakpoint step (sm 40rem, md 48rem, lg 64rem, xl 80rem). THE public way to make a region responsive without a page-local media query — a public header hides its anchor navigation with hideBelow=\"md\". Omitted by default, so no attribute is emitted and no rule matches. display:none also removes it from the a11y tree, so keep its destinations reachable elsewhere (a footer nav) at that width.",
      "name": "hideBelow",
      "type": "\"sm\" | \"md\" | \"lg\" | \"xl\""
    },
    {
      "description": "Inverse of hideBelow — drop the region FROM that step upwards, i.e. keep it only on the narrow side (a compact-only affordance).",
      "name": "hideFrom",
      "type": "\"sm\" | \"md\" | \"lg\" | \"xl\""
    },
    {
      "description": "ESCAPE HATCH: the same drop, at a width in PIXELS off every step of the scale — the gapRaw/padRaw contract on the breakpoint axis (gh#528). An off-scale breakpoint is a LOCAL EXCEPTION, not a new tier: sm/md/lg/xl are shared with collapseBelow and --master-detail-collapse-below, so two regions asked to fold at the same step really do fold together, while a raw width folds one region only. Spend the four steps first; reach here when the canonical design specifies a width the scale has not got (a nav that becomes a hamburger at 900px). It leaves data-hide-below-raw on the DOM so every escape stays countable, and prints one deduped media rule per distinct width (a media query cannot read a var()). It wins over hideBelow, which then emits nothing.",
      "name": "hideBelowRaw",
      "type": "number"
    },
    {
      "description": "Inverse of hideBelowRaw, same contract and same price (data-hide-from-raw). THE SEAM: hideBelowRaw hides while width < N and hideFromRaw hides while width >= N — the same comparisons as the token steps, so the pair is exact complements and at exactly N the hideBelowRaw region is the visible one. Never hand-roll this with an inclusive max-width: `<= N` paired with `>= N` hides BOTH at exactly N, the 1px hole a consumer measured on a hand-rolled max-[900px]: pair.",
      "name": "hideFromRaw",
      "type": "number"
    }
  ],
  "related": [
    "Flex `direction='col'` — the standard pattern for ordinary vertical block spacing; use explicit `align`, `justify`, or `wrap` props when you need more control.",
    "Flex `direction='row'` — the standard pattern for simple horizontal groups; add `wrap` and `align='center'` for the typical row with wrapped centered items.",
    "ResponsiveGrid — use for equal-width, multi-column tile layouts. Flex arranges children on one flex axis and does not provide column-count behavior.",
    "PageContainer — page scaffold and padding context. Flex is an inner layout primitive used inside page sections, cards, dialogs, and toolbars. PageContainer `measure` bounds an APP page (header and body together, narrow | medium); Flex `measure` bounds ONE centred column inside a full-bleed band, and is the only one that reaches the marketing `wide` step."
  ],
  "rules": [
    2,
    40
  ],
  "storyPath": "layout/flex.tsx",
  "tagline": "Token-spaced flex primitive with explicit direction, alignment, justification, and wrapping controls — and, with `attached`, a row of controls welded into ONE visual unit (antd Space.Compact).",
  "usage": [
    "DO import from `@godxjp/ui/layout` and reach for Flex when the axis, alignment, justification, or wrap behavior is part of the component contract: `import { Flex } from \"@godxjp/ui/layout\"`.",
    "DO keep spacing on the `gap` prop instead of raw `gap-*`, `space-*`, or padding utilities. Flex uses the same token scale as other layout primitives, so spacing remains tied to the design system.",
    "DO use `direction=\"row\"` with `wrap` for responsive control rows, chip clusters, and action groups that need more control than simple row composition.",
    "DO use `direction=\"col\"` for vertical groupings that need explicit `align` or `justify` behavior. For pure vertical stacking without alignment control, `direction=\"col\"` is sufficient.",
    "DON'T override the axis with `className` after choosing a direction prop. Keep the layout intent in props so catalog guidance and data attributes stay accurate.",
    "FULL-BLEED BAND: a marketing/landing section is a `<section>` carrying the edge-to-edge paint (background, border, halo) around ONE `<Flex direction=\"col\" measure=\"wide\" pad={{ inline: 6, block: 20 }}>`. The measure centres and caps the column, `pad` owns the gutter and the band rhythm (`block: 20` = 80px, `block: 24` = 96px — the two band steps). Never a page-local `max-width: 1200px` + `margin-inline: auto` class, and never an inline style saying the same thing: that four-declaration idiom is what this prop replaced (gh#839).",
    "Flex is a plain div with React.HTMLAttributes<HTMLDivElement>; pass `id`, `role`, `aria-*`, `data-*`, and structural className values as needed, but do not use it as a semantic form or button wrapper. When the parent only accepts phrasing content — a TabsTrigger, PopoverTrigger or Button, all of which render a <button> — pass `as=\"span\"` rather than reaching for a raw `<span className=\"flex …\">`.",
    "SEMANTIC LIST: a list of rows is `<Flex as=\"ul\" marker=\"none\" direction=\"col\" gap=\"none\">` with `<ListRow as=\"li\">` children — never a raw `<ul>` (no gap token), never `<div role=\"list\">` + `<div role=\"listitem\">` (ARIA re-describing markup HTML already has), and never a wrapper around each row: the divider is `:not(:last-child)` among SIBLINGS, so a row alone in its own wrapper loses it silently. `ui-audit` flags all three as `no-hand-rolled-list`.",
    "NAMED FLEX = GROUP: a role-less div may not carry a naming attribute (axe aria-allowed-attr), so a Flex given `aria-label`/`aria-labelledby` — e.g. by FormField wrapping a composite range/年月 field — automatically renders `role='group'`, folds `aria-errormessage` into `aria-describedby`, and drops the widget-only `aria-required`/`aria-invalid`. Passing an explicit `role` opts out of all of this and the caller owns the attribute set.",
    "ATTACHED: DO reach for it when two or more controls must read as ONE field — a number + a unit (\"毎 [2] [週 ▾] ごと\"), a currency Select welded to an amount Input, a search field with an attached filter Select. `ResponsiveGrid columns={2}` puts them in separate cells (which collapses to ONE column on a narrow form card); `Flex attached` keeps them fused on one line regardless of the grid.",
    "ATTACHED: ONE label for the pair vs per-control: wrap the WHOLE `Flex attached` in a single `FormField label=\"…\"` when the pair reads as one field (\"繰り返し間隔\" over a number+unit row) — a role-less `<div>` cannot carry a cloned `aria-label`/`aria-labelledby` (axe `aria-allowed-attr`), so a NAMED `Flex attached` with no explicit `role` promotes itself to `role=\"group\"` automatically, the same contract `Flex` already honours for a range/年月 pair. Give each CHILD its own `aria-label` instead only when the two controls are independently meaningful outside the row (rare — prefer the one-label pattern for a welded control).",
    "ATTACHED: DON'T reach for `className=\"rounded-none\"` / `[&>*:not(:first-child)]` utilities to join controls yourself — `ui-audit`'s `no-utility-layout` rule blocks exactly that, and it is precisely the corner-radius seam this component owns.",
    "ATTACHED: DO set `size` on each CHILD individually, not on `Flex attached` — the row has no size prop of its own by design (see `density`); every control already owns its own `size` axis (`xs|sm|md|lg`).",
    "ATTACHED: DO use `fullWidth` inside a narrow form card so the joined row spans the field column, exactly like a lone Input would.",
    "ATTACHED: `fullWidth` is antd `Space.Compact block` (gh#1062): in a row, a FIELD child (Input and its affix/Password/Search forms, NumberInput, Textarea, TagInput, the Date/Time pickers, and the Select/Cascader/TreeSelect/SearchSelect trigger) grows to fill the row, and every other child — a Button, an icon button — keeps its content width. So `[Input][+ Add]` is a full-width field with its submit at content width, and two fields (NumberInput + Select) share the row evenly between them. Deviation from antd, written down: antd grows only its Input family (`width: 100%`); Select/InputNumber/DatePicker keep their own width there. Here every field grows, so two fields never leave an empty tail. `direction=\"col\"` + `fullWidth` stacks full-width children as before.",
    "ATTACHED: DON'T expect corner-radius welding on `direction=\"col\"` yet — the shared border still collapses, but each child keeps all four of its own corners rounded until a block-axis radius knob exists on the Input/trigger families (documented gap, not a silent one)."
  ],
  "useCases": [
    "Toolbar internals where controls should sit in a row, wrap on narrow widths, and stay vertically centered.",
    "Card headers that need title content on the left and actions on the right via `justify='between'` without hand-rolling flex utility classes.",
    "Empty-state or loading blocks that center content on both axes using `align='center'` and `justify='center'`.",
    "Form sub-sections where a vertical group needs stretched children or centered helper content beyond what a plain column Flex provides.",
    "Badge, chip, or tag clusters where wrapping is required but the caller also needs explicit gap control.",
    "Low-level layout composition inside custom components where raw flex classes would duplicate the primitive.",
    "ATTACHED: a recurring-issue interval row, \"毎 [NumberInput] [Select 週/月/日 ▾] ごと\", fused on one line inside a FormField, inside a 2-column ResponsiveGrid form card that collapses to one column.",
    "ATTACHED: A currency amount: [Select 通貨 ▾][NumberInput 金額] welded so the currency reads as part of the amount field, not a separate control beside it.",
    "ATTACHED: A filtered search bar: [Select scope][SearchInput query] as one visual field, `fullWidth` inside a page toolbar."
  ]
}
