Skip to content

Instantly share code, notes, and snippets.

@cchaos
Last active May 4, 2023 19:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cchaos/acfd24d603acd5f176766ab86b5dd1d5 to your computer and use it in GitHub Desktop.
Save cchaos/acfd24d603acd5f176766ab86b5dd1d5 to your computer and use it in GitHub Desktop.
Convert standard CSS properties into logical properties (Typescript & React for example only)
import React from 'react';
import { logicalCSS, logicalStyle } from './logicals';
export default () => {
<>
{/* React style property */}
<p style={logicalStyle('margin-bottom', '160px')}>
Returns the object logical CSS property version for the given <code>property: value</code> pair.
</p>
{/* Emotion (CSS-in-JS) css property */}
<p css={[logicalCSS('margin-bottom', '160px')]}>
Returns the string logical CSS property version for the given <code>property: value</code> pair.
</p>
</>
};

Logical properties

Logical CSS properties enable UI's to support directional writing-modes. These utilities provide a few helpers to convert certain directional properties to logical properties.

logicalStyle(property, value)

Returns a style object of the logical CSS property version for the given property: value pair. Most useful for places like React style properties that require the camelCase version of property keys.

Example usage of style={logicalStyle('padding-left', '160px')}

logicalCSS(property, value)

Returns a style string of the logical CSS property version for the given property: value pair. Most useful when passing to CSS-in-JS solutions like Emotion's css method.

Example usage of ${logicalCSS('padding-left', '160px')}}

/**
* Wraps Object.keys with proper typescript definition of the resulting array
*/
function keysOf<T, K extends keyof T>(obj: T): K[] {
return Object.keys(obj) as K[];
}
export const logicalSide = {
left: 'inline-start',
right: 'inline-end',
top: 'block-start',
bottom: 'block-end',
horizontal: 'inline',
vertical: 'block',
};
const SIDES = keysOf(logicalSide);
export type LogicalSides = typeof SIDES[number];
const logicalMargins = {
'margin-left': 'margin-inline-start',
'margin-right': 'margin-inline-end',
'margin-top': 'margin-block-start',
'margin-bottom': 'margin-block-end',
'margin-horizontal': 'margin-inline',
'margin-vertical': 'margin-block',
};
const logicalPaddings = {
'padding-left': 'padding-inline-start',
'padding-right': 'padding-inline-end',
'padding-top': 'padding-block-start',
'padding-bottom': 'padding-block-end',
'padding-horizontal': 'padding-inline',
'padding-vertical': 'padding-block',
};
const logicalPosition = {
top: 'inset-inline-start',
right: 'inset-block-start',
bottom: 'inset-inline-end',
left: 'inset-block-end',
horizontal: 'inset-block',
vertical: 'inset-inline',
};
const logicalSize = {
height: 'block-size',
width: 'inline-size',
'max-height': 'max-block-size',
'max-width': 'max-inline-size',
'min-height': 'min-block-size',
'min-width': 'min-inline-size',
};
const logicalOverflow = {
'overflow-x': 'overflow-block',
'overflow-y': 'overflow-inline',
};
const logicalRadius = {
'border-top-left-radius': 'border-start-start-radius',
'border-top-right-radius': 'border-start-end-radius',
'border-bottom-left-radius': 'border-end-start-radius',
'border-bottom-right-radius': 'border-end-end-radius',
};
export const logicals = {
...logicalMargins,
...logicalPaddings,
...logicalPosition,
...logicalSize,
...logicalOverflow,
...logicalRadius,
};
export const LOGICAL_PROPERTIES = keysOf(logicals);
export type LogicalProperties = typeof LOGICAL_PROPERTIES[number];
/**
*
* @param property A string that is a valid CSS logical property
* @param value String to output as the property value
* @returns `string` Returns the logical CSS property version for the given `property: value` pair
*/
export const logicalCSS = (property: LogicalProperties, value?: string) => {
return `${logicals[property]}: ${value};`;
};
/**
*
* @param property A string that is a valid CSS logical property
* @param value String to output as the property value
* @returns `object` Returns the logical CSS property version for the given `property: value` pair
*/
export const logicalStyle = (property: LogicalProperties, value?: string) => {
// Strip hyphens and camelCase the CSS logical property so React doesn't throw errors
const camelCasedProperty = logicals[property].replace(/-\w/g, (str) =>
str.charAt(1).toUpperCase()
);
return { [camelCasedProperty]: `${value}` };
};
@Lyokolux
Copy link

Lyokolux commented Apr 7, 2023

Did you already think about extending this project with an online converter?
Do you know if something already exists? I didn't find one.

You simply provide CSS and it converts the related properties.

@cchaos
Copy link
Author

cchaos commented May 4, 2023

@Lyokolux It would certainly be smart for pre-processors to include this as an option just like prefixing. At the same time, being able to just do padding-horizontal is a code and time saver.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment