UNPKG

@radix-ui/themes

Version:

[![Radix Themes Logo](https://radix-ui.com/social/themes.png)](https://radix-ui.com/themes)

156 lines (128 loc) 4.55 kB
import { breakpoints } from '../props/prop-def.js'; import type { Responsive, Union } from '../props/prop-def.js'; import { hasOwnProperty } from './has-own-property.js'; import { isResponsiveObject } from './is-responsive-object.js'; interface GetResponsiveStylesOptions { className: string; customProperties: `--${string}`[]; value: Responsive<Union> | Responsive<string> | undefined; propValues: string[] | readonly string[]; parseValue?: (value: string) => string | undefined; } function getResponsiveStyles({ className, customProperties, ...args }: GetResponsiveStylesOptions) { const responsiveClassNames = getResponsiveClassNames({ allowArbitraryValues: true, className, ...args, }); const responsiveCustomProperties = getResponsiveCustomProperties({ customProperties, ...args }); return [responsiveClassNames, responsiveCustomProperties] as const; } interface GetResponsiveClassNamesOptions { allowArbitraryValues?: boolean; className: string; value: Responsive<Union> | Responsive<string> | undefined; propValues: string[] | readonly string[]; parseValue?: (value: string) => string | undefined; } function getResponsiveClassNames({ allowArbitraryValues, value, className, propValues, parseValue = (value) => value, }: GetResponsiveClassNamesOptions): string | undefined { const classNames: string[] = []; if (!value) { return undefined; } if (typeof value === 'string' && propValues.includes(value)) { return getBaseClassName(className, value, parseValue); } if (isResponsiveObject(value)) { const object = value; for (const bp in object) { // Make sure we are not iterating over keys that aren't breakpoints if (!hasOwnProperty(object, bp) || !breakpoints.includes(bp)) { continue; } const value = object[bp]; if (value !== undefined) { if (propValues.includes(value)) { const baseClassName = getBaseClassName(className, value, parseValue); const bpClassName = bp === 'initial' ? baseClassName : `${bp}:${baseClassName}`; classNames.push(bpClassName); } else if (allowArbitraryValues) { const bpClassName = bp === 'initial' ? className : `${bp}:${className}`; classNames.push(bpClassName); } } } return classNames.join(' '); } if (allowArbitraryValues) { return className; } } function getBaseClassName( className: string, value: string, parseValue: (value: string) => string | undefined ): string { const delimiter = className ? '-' : ''; const matchedValue = parseValue(value); const isNegative = matchedValue?.startsWith('-'); const minus = isNegative ? '-' : ''; const absoluteValue = isNegative ? matchedValue?.substring(1) : matchedValue; return `${minus}${className}${delimiter}${absoluteValue}`; } interface GetResponsiveCustomPropertiesOptions { customProperties: `--${string}`[]; value: Responsive<Union> | Responsive<string> | undefined; propValues: string[] | readonly string[]; parseValue?: (value: string) => string | undefined; } function getResponsiveCustomProperties({ customProperties, value, propValues, parseValue = (value) => value, }: GetResponsiveCustomPropertiesOptions) { let styles: Record<string, string | undefined> = {}; // Don't generate custom properties if the value is not arbitrary if (!value || (typeof value === 'string' && propValues.includes(value))) { return undefined; } if (typeof value === 'string') { styles = Object.fromEntries(customProperties.map((prop) => [prop, value])); } if (isResponsiveObject(value)) { const object = value; for (const bp in object) { // Make sure we are not iterating over keys that aren't breakpoints if (!hasOwnProperty(object, bp) || !breakpoints.includes(bp)) { continue; } const value = object[bp]; // Don't generate a custom property if the value is not arbitrary if (propValues.includes(value)) { continue; } for (const customProperty of customProperties) { const bpProperty = bp === 'initial' ? customProperty : `${customProperty}-${bp}`; styles = { [bpProperty]: value, ...styles, }; } } } for (const key in styles) { const value = styles[key]; if (value !== undefined) { styles[key] = parseValue(value); } } return styles; } export { getResponsiveStyles, getResponsiveCustomProperties, getResponsiveClassNames };