Skip to content

Commit

Permalink
fix: consolidate getThemeStyles types and logic into a single file (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
anthony9187 authored Sep 25, 2024
1 parent dd89dd9 commit d120264
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 178 deletions.
177 changes: 0 additions & 177 deletions packages/solid/utils/getThemeStyles.js

This file was deleted.

170 changes: 169 additions & 1 deletion packages/solid/utils/getThemeStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,177 @@
* SPDX-License-Identifier: Apache-2.0
*/

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
/**
* TS really doesn't enjoy the amount of object manipulation we're doing
* here and I don't have time to fight with it
*/

/**
* This method accepts an element style config and returns a fully formed style object,
* which can be directly assigned to a solid element.
*
* the element style config is make up of the following properties:
* - `themeKeys` - key/value pairs defining a solid style property,
* and the componentConfig property it should receive.
* - `base` - the default styles of a component
* - `toneModes` - any tone/mode/toneMode styles that a component has
* - `themeStyles` - the componentConfig provided by the theme
* - `toneModeFallbackMap`(optional) - an override to the defaultToneModeFallbackMap found below
*
* each method below has a comment explaining it, this is a rough overview of the steps this method goes through:
*
* 1. generate the base component styles, merging the style file values and themeStyle values(priority to the themeStyle values)
* 2. generate the tones and modes included in the toneModes object, again with priority to the themeStyles
* 3. generate styles for any tones and modes not included in the toneModes object using the fallback map
* 4. return the object to the style file
*/

import type { ComponentStyleConfig } from '../types/types.js';
import objectFromEntries from './objectFromEntries.js';

// TODO types, sub components
// TODO these are configurable per component, move to theme?
const defaultModeKeys = ['focus', 'disabled'];
const defaultToneKeys = ['brand', 'inverse', 'neutral'];

export declare function makeComponentStyles<T>(
export function makeComponentStyles<T>(
{ themeKeys, base, themeStyles, tones, modes, modeKeys, toneKeys }: ComponentStyleConfig,
debug?: boolean
): T;

export function makeComponentStyles(
{
themeKeys,
base,
themeStyles,
modes = {},
tones = {},
modeKeys = defaultModeKeys,
toneKeys = defaultToneKeys
},
debug = false
) {
/**
* creates the object of tone styles
*
* for each key in the tone object, pass its set of styles to mapModeConfigToSolidStyle for formatting
*/
const makeToneStyles = (tones, themeComponentStyles, modeStyles) => {
const toneStyles = toneKeys.map(tone => {
const styles = {};

// get list of style keys across both style file and theme component config
// TODO a better way to do this
const styleList = new Set(
// eslint-disable-next-line prefer-spread
[].concat.apply([], [tones?.[tone] ?? {}, themeComponentStyles?.[tone] ?? {}].map(Object.keys))
);

// combine style file tones and theme component config tones, ignoring tone modes(added below)
styleList.forEach(styleKey => {
// if the style isn't a mode
if (!modeKeys.includes(styleKey)) {
styles[styleKey] = themeComponentStyles?.[tone]?.[styleKey] ?? tones?.[tone]?.[styleKey];
}
});

/**
* merge tone modes with the following priority(lowest to highest):
* - base.mode
* - style file tone.mode
* - theme component config tone.mode
*/
modeKeys.forEach(mode => {
styles[mode] = {
...modeStyles[mode], // fallbacks from base.mode
...tones?.[tone]?.[mode], // component configured tone.mode
...themeComponentStyles?.[tone]?.[mode] // theme configure tone.mode
};
});

return [tone, styles];
});
return objectFromEntries(toneStyles);
};

/**
* creates the object of mode(state-controlled) styles
*
* for each key in the mode object, pass its set of styles to mapModeConfigToSolidStyle for formatting
*/
const makeModeStyles = (modes, themeComponentStyles) => {
const modeStyles = modeKeys.map(mode => {
return [mode, { ...modes?.[mode], ...themeComponentStyles?.[mode] }];
});
const modeObject = objectFromEntries(modeStyles);
return modeObject;
};

/**
* creates a base style object
*
* if a property has a themeable value(has a corresponding themeKey in the themeKeys object) check the
* componentConfig for a base value. if one exists use it, otherwise use the value from the defaults object
*/
const makeBaseStyles = (base, themeComponentStyles) => {
const baseStyles = {
...base,
...themeComponentStyles.base
};
return baseStyles;
};

/**
* uses the themeKey map to assign themed values to solid style properties
* `themeKeys` is globally available
*/
const mapThemeKeysToSolid = stylesToMap =>
objectFromEntries(
Object.entries(themeKeys)
.filter(([_, themeKey]) => stylesToMap[themeKey])
.map(([solidKey, themeKey]) => [solidKey, stylesToMap[themeKey]])
);

const convertComponentConfig = themeStyles => {
const convertedThemeStyles = objectFromEntries(
// iterate through each variant
Object.entries(themeStyles).map(([variantName, styles]) => {
// within each variant, assign the theme value to the correct solid style property for each theme key
const convertedStyles = mapThemeKeysToSolid(styles);
// repeat the above for each mode within a variant
Object.entries(styles)
.filter(([styleName, _]) => modeKeys.includes(styleName))
.forEach(([modeName, modeStyles]) => {
convertedStyles[modeName] = mapThemeKeysToSolid(modeStyles);
});
return [variantName, convertedStyles];
})
);
return convertedThemeStyles;
};

const generateSolidStylesFromLookupObject = (base, modes, tones) => {
const themeComponentStyles = convertComponentConfig(themeStyles);
debug && console.log(themeComponentStyles);

const baseStyles = makeBaseStyles(base, themeComponentStyles);
debug && console.log(baseStyles);

const modeStyles = makeModeStyles(modes, themeComponentStyles);
debug && console.log(modeStyles);

const toneStyles = makeToneStyles(tones, themeComponentStyles, modeStyles);
debug && console.log(toneStyles);

return {
base: {
...baseStyles,
...modeStyles
},
tones: toneStyles
};
};
return generateSolidStylesFromLookupObject(base, modes, tones);
}

0 comments on commit d120264

Please sign in to comment.