cleaned up bg props

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-02-11 09:58:39 +00:00
parent ad510a5519
commit c67fb17302
12 changed files with 48 additions and 72 deletions
+2
View File
@@ -10,3 +10,5 @@ The Alert component's background is now driven entirely by its `status` prop. Th
- <Alert surface="1" status="info" />
+ <Alert status="info" />
```
**Affected components:** Alert
+1 -1
View File
@@ -86,6 +86,6 @@ Update CSS selectors targeting surface data attributes:
+ [data-on-bg='neutral-1'] { ... }
```
Note: Provider components use `data-bg` (values: `neutral-1` through `neutral-3`, plus intents). Consumer components use `data-on-bg`, which reflects the parent container's bg directly (no auto-increment).
Note: Provider components use `data-bg` (values: `neutral-1` through `neutral-3`, plus intents). Consumer components use `data-on-bg`, which reflects the parent container's `bg` directly.
**Affected components:** Box, Button, ButtonIcon, ButtonLink, ToggleButton, Card, Flex, Grid
+2 -2
View File
@@ -25,7 +25,7 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
BoxDefinition,
props,
);
const { classes, as, bgChildren } = ownProps;
const { classes, as, childrenWithBgProvider } = ownProps;
return createElement(
as,
@@ -36,7 +36,7 @@ export const Box = forwardRef<HTMLDivElement, BoxProps>((props, ref) => {
...dataAttributes,
...restProps,
},
bgChildren,
childrenWithBgProvider,
);
});
+1 -1
View File
@@ -27,7 +27,7 @@ export const BoxDefinition = defineComponent<BoxOwnProps>()({
classNames: {
root: 'bui-Box',
},
bg: { provider: true },
bg: 'provider',
propDefs: {
as: { default: 'div' },
bg: { dataAttribute: true },
@@ -29,7 +29,7 @@ export const ButtonDefinition = defineComponent<ButtonOwnProps>()({
content: 'bui-ButtonContent',
spinner: 'bui-ButtonSpinner',
},
bg: { consumer: true },
bg: 'consumer',
propDefs: {
size: { dataAttribute: true, default: 'small' },
variant: { dataAttribute: true, default: 'primary' },
@@ -29,7 +29,7 @@ export const ButtonIconDefinition = defineComponent<ButtonIconOwnProps>()({
content: 'bui-ButtonIconContent',
spinner: 'bui-ButtonIconSpinner',
},
bg: { consumer: true },
bg: 'consumer',
propDefs: {
size: { dataAttribute: true, default: 'small' },
variant: { dataAttribute: true, default: 'primary' },
@@ -28,7 +28,7 @@ export const ButtonLinkDefinition = defineComponent<ButtonLinkOwnProps>()({
root: 'bui-ButtonLink',
content: 'bui-ButtonLinkContent',
},
bg: { consumer: true },
bg: 'consumer',
propDefs: {
size: { dataAttribute: true, default: 'small' },
variant: { dataAttribute: true, default: 'primary' },
@@ -21,7 +21,6 @@
display: flex;
flex-direction: column;
gap: var(--bui-space-3);
background-color: var(--bui-bg-neutral-1);
border-radius: var(--bui-radius-3);
padding-block: var(--bui-space-3);
color: var(--bui-fg-primary);
@@ -30,18 +29,6 @@
width: 100%;
}
.bui-Card[data-on-bg='neutral-1'] {
background-color: var(--bui-bg-neutral-2);
}
.bui-Card[data-on-bg='neutral-2'] {
background-color: var(--bui-bg-neutral-3);
}
.bui-Card[data-on-bg='neutral-3'] {
background-color: var(--bui-bg-neutral-4);
}
.bui-CardBody {
flex: 1;
min-height: 0;
+11 -4
View File
@@ -28,6 +28,7 @@ import type {
CardBodyProps,
CardFooterProps,
} from './types';
import { Box } from '../Box/Box';
/**
* Card component.
@@ -39,12 +40,18 @@ export const Card = forwardRef<HTMLDivElement, CardProps>((props, ref) => {
CardDefinition,
props,
);
const { classes, bgChildren } = ownProps;
const { classes, children } = ownProps;
return (
<div ref={ref} className={classes.root} {...dataAttributes} {...restProps}>
{bgChildren}
</div>
<Box
bg="neutral-auto"
ref={ref}
className={classes.root}
{...dataAttributes}
{...restProps}
>
{children}
</Box>
);
});
@@ -32,7 +32,6 @@ export const CardDefinition = defineComponent<CardOwnProps>()({
classNames: {
root: 'bui-Card',
},
bg: { provider: true, consumer: true, defaultBg: 'neutral-auto' },
propDefs: {
children: {},
className: {},
+15 -28
View File
@@ -27,21 +27,6 @@ export interface PropDefConfig<T> {
export type UtilityPropKey = keyof typeof utilityClassMap;
/**
* Configuration for how a component participates in the bg system.
*
* - `provider` — calls `useBgProvider`, sets `data-bg`, wraps children in `BgProvider`
* - `consumer` — calls `useBgConsumer`, sets `data-on-bg`
* - `defaultBg` — default bg value when no `bg` prop is provided (e.g. `'neutral-auto'`)
*
* A component can be provider-only, consumer-only, or both.
*/
export interface BgConfig {
provider?: boolean;
consumer?: boolean;
defaultBg?: string;
}
export interface ComponentConfig<
P extends Record<string, any>,
S extends Record<string, string>,
@@ -51,19 +36,22 @@ export interface ComponentConfig<
propDefs: { [K in keyof P]: PropDefConfig<P[K]> };
// readonly for compatibility with const inference from factory
utilityProps?: readonly UtilityPropKey[];
bg?: BgConfig;
/**
* How this component participates in the bg system.
*
* - `'provider'` — calls `useBgProvider`, sets `data-bg`, wraps children in `BgProvider`
* - `'consumer'` — calls `useBgConsumer`, sets `data-on-bg`
*/
bg?: 'provider' | 'consumer';
}
/**
* Type constraint that validates bg props are present in the props type.
* - Provider-only components must include 'bg' in their props
* - Provider+consumer components (e.g. Card) don't need a bg prop (they auto-increment)
* - Consumer-only components don't need a bg prop
* - Provider components must include 'bg' in their props
* - Consumer components don't need a bg prop
*/
export type BgPropsConstraint<P, Bg> = Bg extends { provider: true }
? Bg extends { consumer: true }
? {} // provider+consumer: bg prop is optional (auto-increment via defaultBg)
: 'bg' extends keyof P
export type BgPropsConstraint<P, Bg> = Bg extends 'provider'
? 'bg' extends keyof P
? {}
: {
__error: 'Bg provider components must include bg in props type.';
@@ -93,11 +81,10 @@ type ResolvedOwnProps<
[K in keyof PropDefs & keyof P]: ResolvePropType<P[K], PropDefs[K]>;
};
type ChildrenProps<Bg extends BgConfig | undefined> = Bg extends {
provider: true;
}
? { bgChildren: ReactNode; children?: never }
: { children: ReactNode; bgChildren?: never };
type ChildrenProps<Bg extends 'provider' | 'consumer' | undefined> =
Bg extends 'provider'
? { childrenWithBgProvider: ReactNode; children?: never }
: { children: ReactNode; childrenWithBgProvider?: never };
type DataAttributeKeys<PropDefs> = {
[K in keyof PropDefs]: PropDefs[K] extends { dataAttribute: true }
@@ -36,14 +36,10 @@ export function useDefinition<
): UseDefinitionResult<D, P> {
const { breakpoint } = useBreakpoint();
// Resolve the effective bg value: use the bg prop if provided,
// otherwise fall back to the defaultBg from the bg config
const effectiveBg = definition.bg?.provider
? props.bg ?? definition.bg.defaultBg
: undefined;
// Provider: resolve bg and provide context for children
const providerBg = useBgProvider(effectiveBg);
const providerBg = useBgProvider(
definition.bg === 'provider' ? props.bg : undefined,
);
// Consumer: read parent context bg
const consumerBg = useBgConsumer();
@@ -74,7 +70,7 @@ export function useDefinition<
ownPropsResolved[key] = finalValue;
// Skip data-bg for bg prop when the provider path handles it
if (key === 'bg' && definition.bg?.provider) continue;
if (key === 'bg' && definition.bg === 'provider') continue;
if ((config as any).dataAttribute) {
// eslint-disable-next-line no-restricted-syntax
@@ -83,17 +79,13 @@ export function useDefinition<
}
}
// Provider-only: set data-bg (provider+consumer components use data-on-bg instead)
if (
definition.bg?.provider &&
!definition.bg?.consumer &&
providerBg.bg !== undefined
) {
// Provider: set data-bg from the resolved provider bg
if (definition.bg === 'provider' && providerBg.bg !== undefined) {
dataAttributes['data-bg'] = String(providerBg.bg);
}
// Consumer: set data-on-bg from the parent context
if (definition.bg?.consumer && consumerBg.bg !== undefined) {
if (definition.bg === 'consumer' && consumerBg.bg !== undefined) {
dataAttributes['data-on-bg'] = String(consumerBg.bg);
}
@@ -117,10 +109,10 @@ export function useDefinition<
}
let children: ReactNode | undefined;
let bgChildren: ReactNode | undefined;
let childrenWithBgProvider: ReactNode | undefined;
if (definition.bg?.provider) {
bgChildren = providerBg.bg ? (
if (definition.bg === 'provider') {
childrenWithBgProvider = providerBg.bg ? (
<BgProvider bg={providerBg.bg}>{props.children}</BgProvider>
) : (
props.children
@@ -133,7 +125,9 @@ export function useDefinition<
ownProps: {
classes,
...ownPropsResolved,
...(definition.bg?.provider ? { bgChildren } : { children }),
...(definition.bg === 'provider'
? { childrenWithBgProvider }
: { children }),
},
restProps,
dataAttributes,