/**
* Box-model style helpers shared by layout primitives and design-system
* components. Color values resolve through the semantic token contract
* (`resolveColorToken`), so `
` works identically
* under every design system's active theme.
*/
import { resolveColorToken, type BackgroundValue } from '../contract.js';
export type SpacingValue = number | {
x?: number;
y?: number;
top?: number;
right?: number;
bottom?: number;
left?: number;
};
export interface BoxProps {
width?: number | string;
height?: number | string;
flex?: number;
background?: BackgroundValue;
borderRadius?: number;
padding?: SpacingValue;
margin?: SpacingValue;
}
export function resolveSpacing(
value: SpacingValue | undefined,
prefix: 'padding' | 'margin'
): Record {
if (value === undefined) return {};
if (typeof value === 'number') {
return {
[`${prefix}Top`]: value,
[`${prefix}Right`]: value,
[`${prefix}Bottom`]: value,
[`${prefix}Left`]: value,
};
}
const style: Record = {};
if (value.top !== undefined) style[`${prefix}Top`] = value.top;
else if (value.y !== undefined) style[`${prefix}Top`] = value.y;
if (value.bottom !== undefined) style[`${prefix}Bottom`] = value.bottom;
else if (value.y !== undefined) style[`${prefix}Bottom`] = value.y;
if (value.right !== undefined) style[`${prefix}Right`] = value.right;
else if (value.x !== undefined) style[`${prefix}Right`] = value.x;
if (value.left !== undefined) style[`${prefix}Left`] = value.left;
else if (value.x !== undefined) style[`${prefix}Left`] = value.x;
return style;
}
export function resolveBoxStyle(props: BoxProps): Record {
const style: Record = {};
if (props.width !== undefined) style.width = props.width;
if (props.height !== undefined) style.height = props.height;
if (props.flex !== undefined) {
// Lynx (like React Native) expands `flex: n` shorthand to
// `flex: n n auto`, where `flexBasis: 'auto'` means "size to content
// first" — which collapses the layout chain. Write the long-form so
// `` etc. actually fill remaining space.
style.flexGrow = props.flex;
style.flexShrink = 1;
style.flexBasis = 0;
style.minHeight = 0;
}
if (props.background !== undefined) style.backgroundColor = resolveColorToken(props.background);
if (props.borderRadius !== undefined) style.borderRadius = props.borderRadius;
Object.assign(style, resolveSpacing(props.padding, 'padding'));
Object.assign(style, resolveSpacing(props.margin, 'margin'));
return style;
}