Improve docs + container props on Grid + Flex
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
---
|
||||
'@backstage/ui': minor
|
||||
---
|
||||
|
||||
**BREAKING**: Alert no longer accepts a `surface` prop
|
||||
|
||||
The Alert component's background is now driven entirely by its `status` prop. The `surface` prop has been removed.
|
||||
|
||||
```diff
|
||||
- <Alert surface="1" status="info" />
|
||||
+ <Alert status="info" />
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
**BREAKING**: Replaced `Surface` / `onSurface` system with new `ContainerBg` background system
|
||||
|
||||
The old `Surface` type (`'0'`–`'3'`, `'auto'`) and its associated props (`surface`, `onSurface`) have been replaced by a new `ContainerBg` type with semantic neutral levels (`'neutral-1'` through `'neutral-3'`) and intents (`'danger'`, `'warning'`, `'success'`). Containers are capped at `neutral-3`; the `neutral-4` level is reserved for leaf component CSS only. Leaf components like Button no longer need an explicit prop — they receive a `data-on-bg` attribute matching the parent container's bg, and CSS handles the visual step-up.
|
||||
The old `Surface` type (`'0'`–`'3'`, `'auto'`) and its associated props (`surface`, `onSurface`) have been replaced by `ContainerBg` — a union of `'neutral-1'` | `'neutral-2'` | `'neutral-3'` | `'danger'` | `'warning'` | `'success'`. There is no `neutral-4` value; containers are capped at `neutral-3`. Leaf components like Button no longer accept a bg prop — they inherit the parent container's bg via a `data-on-bg` attribute, and CSS handles the visual step-up to the next neutral level.
|
||||
|
||||
New `useBg` hook and `BgProvider` replace the deleted `useSurface` hook and `SurfaceProvider`.
|
||||
|
||||
@@ -26,7 +26,7 @@ Rename the `surface` prop to `bg` on container components and update values:
|
||||
+ <Grid.Root bg="neutral-1">
|
||||
```
|
||||
|
||||
Remove `onSurface` from leaf components — it is now fully automatic:
|
||||
Remove `onSurface` from leaf components — they now always inherit from the parent container and can no longer override the value:
|
||||
|
||||
```diff
|
||||
- <Button onSurface="1" variant="secondary">
|
||||
@@ -39,13 +39,6 @@ Remove `onSurface` from leaf components — it is now fully automatic:
|
||||
+ <ToggleButton>
|
||||
```
|
||||
|
||||
Alert no longer accepts a `surface` prop (its background is driven by `status`):
|
||||
|
||||
```diff
|
||||
- <Alert surface="1" status="info" />
|
||||
+ <Alert status="info" />
|
||||
```
|
||||
|
||||
Update type imports:
|
||||
|
||||
```diff
|
||||
@@ -72,10 +65,10 @@ Update CSS selectors targeting surface data attributes:
|
||||
- [data-surface='1'] { ... }
|
||||
+ [data-bg='neutral-1'] { ... }
|
||||
|
||||
- [data-on-surface='2'] { ... }
|
||||
- [data-on-surface='1'] { ... }
|
||||
+ [data-on-bg='neutral-1'] { ... }
|
||||
```
|
||||
|
||||
Note: Container components use `data-bg` for their own background level. Leaf components now use `data-on-bg` which reflects the parent container's bg (not an auto-incremented value).
|
||||
Note: Container components use `data-bg` (values: `neutral-1` through `neutral-3`, plus intents). Leaf components use `data-on-bg`, which reflects the parent container's bg directly (no auto-increment).
|
||||
|
||||
**Affected components:** Box, Button, ButtonIcon, ButtonLink, ToggleButton, Card, Alert, Flex, Grid
|
||||
**Affected components:** Box, Button, ButtonIcon, ButtonLink, ToggleButton, Card, Flex, Grid
|
||||
|
||||
@@ -282,21 +282,16 @@ export const BgAutoIncrement = meta.story({
|
||||
render: args => (
|
||||
<Flex direction="column">
|
||||
<div style={{ maxWidth: '600px', marginBottom: '16px' }}>
|
||||
Nested Flex components automatically increment their neutral background
|
||||
level. No explicit bg prop is needed on inner Flex components.
|
||||
Flex is a layout primitive and is transparent to the bg system by
|
||||
default. Only an explicit bg prop establishes a new bg level. Nested
|
||||
Flex components without a bg prop inherit the parent context unchanged.
|
||||
</div>
|
||||
<Flex {...args} bg="neutral-1" direction="column">
|
||||
<div>Neutral 1 (explicit)</div>
|
||||
<Flex {...args} direction="column">
|
||||
<div>Auto (becomes neutral-2)</div>
|
||||
<Flex {...args} direction="column">
|
||||
<div>Auto (becomes neutral-3)</div>
|
||||
<Flex {...args} direction="column">
|
||||
<div>Auto (becomes neutral-4)</div>
|
||||
<Flex {...args} direction="column">
|
||||
<div>Auto (stays neutral-4 - capped)</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex {...args} bg="neutral-2" direction="column">
|
||||
<div>Neutral 2 (explicit)</div>
|
||||
<Flex {...args} bg="neutral-3" direction="column">
|
||||
<div>Neutral 3 (explicit, capped)</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
@@ -24,8 +24,11 @@ import { BgProvider, useBg } from '../../hooks/useBg';
|
||||
|
||||
/** @public */
|
||||
export const Flex = forwardRef<HTMLDivElement, FlexProps>((props, ref) => {
|
||||
// Resolve the bg this Flex creates for its children
|
||||
const { bg: resolvedBg } = useBg({ mode: 'container', bg: props.bg });
|
||||
// Only establish bg context when an explicit bg prop is provided.
|
||||
// Flex is a layout primitive — it should be transparent to the bg system by default.
|
||||
const { bg: resolvedBg } = useBg(
|
||||
props.bg !== undefined ? { mode: 'container', bg: props.bg } : undefined,
|
||||
);
|
||||
|
||||
const { classNames, dataAttributes, utilityClasses, style, cleanedProps } =
|
||||
useStyles(FlexDefinition, {
|
||||
|
||||
@@ -182,15 +182,16 @@ export const BgAutoIncrement = meta.story({
|
||||
render: args => (
|
||||
<Flex direction="column">
|
||||
<div style={{ maxWidth: '600px', marginBottom: '16px' }}>
|
||||
Nested Grid components automatically increment their neutral background.
|
||||
Each nested Grid.Item inherits and increments from its parent's bg.
|
||||
Grid is a layout primitive and is transparent to the bg system by
|
||||
default. Only an explicit bg prop establishes a new bg level. Nested
|
||||
grids without a bg prop inherit the parent context unchanged.
|
||||
</div>
|
||||
<Grid.Root {...args} bg="neutral-1">
|
||||
<Grid.Item>Neutral 1 (Grid.Root)</Grid.Item>
|
||||
<Grid.Item>
|
||||
<Grid.Root {...args}>
|
||||
<Grid.Item>Nested: Auto (becomes neutral-2)</Grid.Item>
|
||||
<Grid.Item>Nested: Auto (becomes neutral-2)</Grid.Item>
|
||||
<Grid.Root {...args} bg="neutral-2">
|
||||
<Grid.Item>Nested: neutral-2 (explicit)</Grid.Item>
|
||||
<Grid.Item>Nested: neutral-2 (explicit)</Grid.Item>
|
||||
</Grid.Root>
|
||||
</Grid.Item>
|
||||
</Grid.Root>
|
||||
|
||||
@@ -23,8 +23,11 @@ import styles from './Grid.module.css';
|
||||
import { BgProvider, useBg } from '../../hooks/useBg';
|
||||
|
||||
const GridRoot = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
||||
// Resolve the bg this Grid creates for its children
|
||||
const { bg: resolvedBg } = useBg({ mode: 'container', bg: props.bg });
|
||||
// Only establish bg context when an explicit bg prop is provided.
|
||||
// Grid is a layout primitive — it should be transparent to the bg system by default.
|
||||
const { bg: resolvedBg } = useBg(
|
||||
props.bg !== undefined ? { mode: 'container', bg: props.bg } : undefined,
|
||||
);
|
||||
|
||||
const { classNames, dataAttributes, utilityClasses, style, cleanedProps } =
|
||||
useStyles(GridDefinition, {
|
||||
@@ -59,8 +62,11 @@ const GridRoot = forwardRef<HTMLDivElement, GridProps>((props, ref) => {
|
||||
});
|
||||
|
||||
const GridItem = forwardRef<HTMLDivElement, GridItemProps>((props, ref) => {
|
||||
// Resolve the bg this GridItem creates for its children
|
||||
const { bg: resolvedBg } = useBg({ mode: 'container', bg: props.bg });
|
||||
// Only establish bg context when an explicit bg prop is provided.
|
||||
// GridItem is a layout slot — it should be transparent to the bg system by default.
|
||||
const { bg: resolvedBg } = useBg(
|
||||
props.bg !== undefined ? { mode: 'container', bg: props.bg } : undefined,
|
||||
);
|
||||
|
||||
const { classNames, dataAttributes, utilityClasses, style, cleanedProps } =
|
||||
useStyles(GridItemDefinition, {
|
||||
|
||||
@@ -21,7 +21,6 @@ import type { ToggleButtonProps } from './types';
|
||||
import { useStyles } from '../../hooks/useStyles';
|
||||
import { ToggleButtonDefinition } from './definition';
|
||||
import styles from './ToggleButton.module.css';
|
||||
import { useBg } from '../../hooks/useBg';
|
||||
|
||||
/** @public */
|
||||
export const ToggleButton = forwardRef(
|
||||
@@ -36,14 +35,11 @@ export const ToggleButton = forwardRef(
|
||||
|
||||
const { children, className, iconStart, iconEnd, ...rest } = cleanedProps;
|
||||
|
||||
const { bg } = useBg({ mode: 'leaf' });
|
||||
|
||||
return (
|
||||
<AriaToggleButton
|
||||
className={clsx(classNames.root, styles[classNames.root], className)}
|
||||
ref={ref}
|
||||
{...dataAttributes}
|
||||
{...(bg ? { 'data-on-bg': bg } : {})}
|
||||
{...rest}
|
||||
>
|
||||
{renderProps => {
|
||||
|
||||
@@ -62,11 +62,9 @@ const BgContext = createVersionedContext<{
|
||||
* Increments a neutral bg level by one, capping at 'neutral-3'.
|
||||
* Intent backgrounds (danger, warning, success) pass through unchanged.
|
||||
*
|
||||
* Only used by container components for auto-increment. The 'neutral-4'
|
||||
* level is reserved for leaf components and is never set on containers.
|
||||
* The 'neutral-4' level is reserved for leaf component CSS and is never
|
||||
* set on containers.
|
||||
*
|
||||
* @param bg - The current bg value
|
||||
* @returns The incremented bg value
|
||||
* @internal
|
||||
*/
|
||||
function incrementNeutralBg(
|
||||
@@ -81,44 +79,29 @@ function incrementNeutralBg(
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the bg value for a container component.
|
||||
* Resolves the bg for a container component.
|
||||
*
|
||||
* - If an explicit bg prop is provided, use that.
|
||||
* - If no bg prop is provided but there is a parent context, auto-increment from parent.
|
||||
* - If no bg prop and no context, return undefined (no bg).
|
||||
* Uses the explicit `bg` prop if provided. Otherwise auto-increments from
|
||||
* the parent context, capping at `neutral-3`. Returns undefined when there
|
||||
* is no prop and no parent context.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function resolveBgForContainer(
|
||||
contextBg: ContainerBg | undefined,
|
||||
function resolveContainerBg(
|
||||
context: BgContextValue,
|
||||
propBg: ContainerBg | undefined,
|
||||
): ContainerBg | undefined {
|
||||
): BgContextValue {
|
||||
// Explicit bg prop takes priority
|
||||
if (propBg !== undefined) {
|
||||
return propBg;
|
||||
return { bg: propBg };
|
||||
}
|
||||
|
||||
// No explicit bg: auto-increment from context if available
|
||||
if (contextBg === undefined) {
|
||||
return undefined;
|
||||
if (context.bg === undefined) {
|
||||
return { bg: undefined };
|
||||
}
|
||||
|
||||
return incrementNeutralBg(contextBg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the bg value for a leaf component.
|
||||
*
|
||||
* Returns the parent context bg unchanged. The leaf component's CSS
|
||||
* handles the visual step-up (e.g. on neutral-1 surface → use neutral-2 tokens).
|
||||
* If no context, returns undefined.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function resolveBgForLeaf(
|
||||
contextBg: ContainerBg | undefined,
|
||||
): ContainerBg | undefined {
|
||||
return contextBg;
|
||||
return { bg: incrementNeutralBg(context.bg) };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,9 +120,6 @@ export const BgProvider = ({ bg, children }: BgProviderProps) => {
|
||||
/**
|
||||
* Hook to access and resolve the current bg context.
|
||||
*
|
||||
* All bg resolution logic lives here — callers only need to specify the mode
|
||||
* and (for containers) the explicit bg prop value.
|
||||
*
|
||||
* - **Container mode** — uses explicit `bg` if provided, otherwise auto-increments
|
||||
* from parent context. Caps at `neutral-3`.
|
||||
* - **Leaf mode** — returns the parent context bg unchanged. No prop needed.
|
||||
@@ -157,15 +137,17 @@ export const useBg = (options?: UseBgOptions): BgContextValue => {
|
||||
return context;
|
||||
}
|
||||
|
||||
// Leaf mode: return the parent context bg unchanged.
|
||||
// The leaf component's CSS handles the visual step-up.
|
||||
if (options.mode === 'leaf') {
|
||||
return context;
|
||||
}
|
||||
|
||||
// Resolve responsive prop value to a scalar for the current breakpoint
|
||||
const resolvedPropBg =
|
||||
const propBg =
|
||||
options.bg !== undefined
|
||||
? resolveResponsiveValue(options.bg, breakpoint)
|
||||
: undefined;
|
||||
|
||||
if (options.mode === 'leaf') {
|
||||
return { bg: resolveBgForLeaf(context.bg) };
|
||||
}
|
||||
|
||||
return { bg: resolveBgForContainer(context.bg, resolvedPropBg) };
|
||||
return resolveContainerBg(context, propBg);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user