import hash from '@emotion/hash' ; import { useContext , useEffect , useRef } from 'react' ; import { ClassRef } from 'treat' ; import { isDev } from './env' ; import { escape } from './ponyfills/CSS' ; import { StyleInjectorContext } from './StyleInjectorContext' ; const specificitiesByShorthandProperty = new Map ( [ [ 'animation' , 1 ] , [ 'background' , 1 ] , [ 'border' , 1 ] , [ 'borderBottom' , 2 ] , [ 'borderColor' , 2 ] , [ 'borderImage' , 2 ] , [ 'borderLeft' , 2 ] , [ 'borderRadius' , 2 ] , [ 'borderRight' , 2 ] , [ 'borderStyle' , 2 ] , [ 'borderTop' , 2 ] , [ 'borderWidth' , 2 ] , [ 'columnRule' , 1 ] , [ 'columns' , 1 ] , [ 'flex' , 1 ] , [ 'flexFlow' , 1 ] , [ 'font' , 1 ] , [ 'gap' , 1 ] , [ 'grid' , 1 ] , [ 'gridArea' , 1 ] , [ 'gridColumn' , 2 ] , [ 'gridRow' , 2 ] , [ 'gridTemplate' , 1 ] , [ 'lineClamp' , 1 ] , [ 'listStyle' , 1 ] , [ 'margin' , 1 ] , [ 'mask' , 1 ] , [ 'maskBorder' , 2 ] , [ 'offset' , 1 ] , [ 'outline' , 1 ] , [ 'overflow' , 1 ] , [ 'padding' , 1 ] , [ 'placeContent' , 1 ] , [ 'placeItems' , 1 ] , [ 'placeSelf' , 1 ] , [ 'textDecoration' , 1 ] , [ 'textEmphasis' , 1 ] , [ 'transition' , 1 ] , ] ) ; const maxSpecificity = 3 ; function upperToHyphenLower ( match ) { return `-${ match . toLowerCase ( ) }` ; } function getClassName ( identName ) { return isDev ? `DYNAMIC_${ identName }` : `g${ hash ( identName ) }` ; } export function useDynamicStyling ( ) { const { ruleManager } = useContext ( StyleInjectorContext ) ; const ownUsageCountsByClassName = useRef < { [ key in ClassRef ] : number ; } > ( { } ) . current ; useEffect ( ( ) => ( ) : void => { for ( const className in ownUsageCountsByClassName ) { const usageCount = ownUsageCountsByClassName [ className ] ; ruleManager . decreaseUsage ( className , usageCount ) ; } } , [ ] ) ; return function getDynamicClassName ( identName , property , value , wrapRule ? ) : string { const className = getClassName ( identName ) ; ruleManager . increaseUsage ( className , ( ) => { const selector = `.${ isDev ? escape ( className ) : className }` . repeat ( specificitiesByShorthandProperty . get ( property ) || maxSpecificity ) ; const cssText = `${ selector }{${ `${ property . replace ( /[A-Z]/g , upperToHyphenLower ) }:${ typeof value === 'number' ? `${ value }px` : value }` }}` ; return wrapRule ? wrapRule ( cssText ) : cssText ; } ) ; ownUsageCountsByClassName [ className ] = ( ownUsageCountsByClassName [ className ] || 0 ) + 1 ; return className ; } ; }