apphouse
Version:
Component library for React that uses observable state management and theme-able components.
199 lines (186 loc) • 5.81 kB
text/typescript
import { CSSProperties } from 'glamor';
import { camelCase } from './string/camelCase';
import { colorsLookupTable } from '../themes/colors.lookup';
import { Theme } from '../themes/Theme';
import {
getStyleTokenReferenceType,
getValueReferenceStringFromObject,
hasColorReference
} from '../themes/utils/tokens.utils';
import { isSelector } from './CSS';
import {
CssPropertyStyle,
StyleTokenReference
} from '../themes/style.interface';
/**
* Get styles for focus events
* @param keyboard styles for keyboard focus
* @param mouse styles for mouse focus
* @returns
*/
export function createFocusPseudoclassicSelector(
keyboard: CSSProperties
): CSSProperties {
return {
':focus': {
outline: 'none',
...keyboard,
':focus-visible': {
outline: 'none',
...keyboard
},
':not(:focus-visible)': {
outline: 'none'
// ...mouse
}
}
};
}
export const parseCssPropertyStyle = (value: CssPropertyStyle[]): string => {
const v = value?.map((style) => {
if (style.isSelector) {
if (Array.isArray(style.value)) {
return `"${style.property}": {${parseCssPropertyStyle(style.value)}}`;
}
return '';
} else {
const property = camelCase(style?.property);
return `"${property || ''}": "${style?.value || ''}"`;
}
});
return `${v.join(', ')}`;
};
export const toCss = (value: CssPropertyStyle[]): object => {
if (!value) {
return {};
}
try {
return JSON.parse(`{${parseCssPropertyStyle(value)}}`);
} catch (error) {
console.log({ error, value });
return {};
}
};
export class StyleUtils {
/**
* Convert Css Properties into CssPropertyStyle[]
* @param value style in the format of CssProperties (css in JS)
* @param lookup a lookup table to convert css properties to css property styles, if available
* @param namespace to better create the style, we can namespace the style this is the value that
* that will be used to create the base component
* @returns CssPropertyStyle[]
*/
static toCssPropertyStyle = (
value: CSSProperties,
lookup: { [id: string]: string },
namespace?: string
): CssPropertyStyle[] => {
const convert = (v: CSSProperties): CssPropertyStyle[] => {
return Object.keys(v).map((k) => {
const currentValue = v[k];
const isColorKey = hasColorReference(k);
if (isColorKey) {
const itemInLookup: any = namespace
? colorsLookupTable[namespace]
: undefined;
let colorReference: string | undefined;
if (itemInLookup) {
colorReference = itemInLookup[k];
}
const color = colorReference
? `theme.${colorReference}`
: currentValue;
const cssPropertyValue: CssPropertyStyle = {
property: k,
value: color,
isSelector: isSelector(k),
reference: colorReference
? {
type: 'color',
value: color,
key: color
}
: null
};
return cssPropertyValue;
}
if (
typeof currentValue !== 'string' &&
typeof currentValue !== 'number'
) {
const cssPropertyValue: CssPropertyStyle = {
property: k,
value: convert(currentValue),
isSelector: isSelector(k),
reference: null
};
return cssPropertyValue;
} else {
const referenceValue = getValueReferenceStringFromObject(
currentValue,
lookup,
namespace
);
const reference: StyleTokenReference | null =
referenceValue && lookup[referenceValue]
? {
type: getStyleTokenReferenceType(referenceValue),
value: currentValue,
key: referenceValue
}
: null;
const cssPropertyValue: CssPropertyStyle = {
property: k,
value: referenceValue || currentValue,
isSelector: isSelector(k),
reference: reference
};
return cssPropertyValue;
}
});
};
const css = convert(value);
return css;
};
// static toSnippetFromStyle = (style: Style): CssSnippet => {
// const snippet = new CssSnippet({
// id: style.id,
// value: style.code,
// map: {}, // TODO: add map
// baseComponent: style.baseComponent,
// description: style.variant,
// previewWithTag: style.previewWithTag,
// permission: "private", // assuming private here but, TODO
// });
// return snippet;
// };
/**
* Convert a themed or tokenized style to a css style with raw values
* @param style with color or design tokens
* @returns css style with raw values
*/
static toRawStyle = (style: CSSProperties, theme: Theme): CSSProperties => {
const rawStyle: CSSProperties = {};
Object.keys(style).forEach((property) => {
const value = style[property];
let rawValue = value;
if (typeof value === 'string') {
if (value.startsWith('theme.')) {
// value is a color token
// get the value from the theme
Object.keys(theme.palette).forEach((paletteId) => {
const palette = theme.palette[paletteId];
if (palette.id === paletteId) {
// palette is the one we are looking for
const colorKey = value.replace('theme.', '');
const color = palette.colors[colorKey];
rawValue = color;
}
});
}
}
rawStyle[property] = rawValue;
});
return rawStyle;
};
}