@evidence-dev/tailwind
Version:
158 lines (138 loc) • 5.12 kB
JavaScript
import chroma from 'chroma-js';
import { isComputedColor, isRequiredColor } from './constants.js';
import { BUILTIN_COLORS } from '../../schemas/colors.js';
/** @typedef {import('../../schemas/types.js').ThemeColors} ThemeColors */
/**
* @param {import('./types.js').ThemeColorsWithRequired} colors
* @returns {import('ts-essentials').DeepRequired<ThemeColors>}
*/
export const computeShades = (colors) => {
const computed = {};
/**
* Compute base colors
*/
const base100Light = colors['base-100'].light;
const base100Dark = colors['base-100'].dark;
// Compute base-200 from base-100
const base200Light = colors['base-200']?.light ?? darken(base100Light, 0.15);
const base200Dark = colors['base-200']?.dark ?? brighten(base100Dark, 0.15);
computed['base-200'] = {
light: base200Light,
dark: base200Dark
};
// Compute base-300 from base-200
const base300Light = colors['base-300']?.light ?? darken(base200Light, 0.65);
const base300Dark = colors['base-300']?.dark ?? brighten(base200Dark, 0.65);
computed['base-300'] = {
light: base300Light,
dark: base300Dark
};
// Compute base-heading from base-100
const baseHeadingLight = colors['base-heading']?.light ?? computeContentShade(base100Light);
const baseHeadingDark = colors['base-heading']?.dark ?? computeContentShade(base100Dark);
computed['base-heading'] = {
light: baseHeadingLight,
dark: baseHeadingDark
};
// Compute base-content from base-heading
const baseContentLight = colors['base-content']?.light ?? brighten(baseHeadingLight, 0.9);
const baseContentDark = colors['base-content']?.dark ?? darken(baseHeadingDark, 0.9);
computed['base-content'] = {
light: baseContentLight,
dark: baseContentDark
};
// Compute base-content-muted from base-content
const baseContentMutedLight =
colors['base-content-muted']?.light ?? brighten(baseContentLight, 1.65);
const baseContentMutedDark = colors['base-content-muted']?.dark ?? darken(baseContentDark, 1.65);
computed['base-content-muted'] = {
light: baseContentMutedLight,
dark: baseContentMutedDark
};
/**
* Compute -content colors
*/
// Compute primary-content from primary
const primaryContentLight =
colors['primary-content']?.light ?? computeContentShade(colors.primary.light);
const primaryContentDark =
colors['primary-content']?.dark ?? computeContentShade(colors.primary.dark);
computed['primary-content'] = {
light: primaryContentLight,
dark: primaryContentDark
};
// Compute accent-content from accent
const accentContentLight =
colors['accent-content']?.light ?? computeContentShade(colors.accent.light);
const accentContentDark =
colors['accent-content']?.dark ?? computeContentShade(colors.accent.dark);
computed['accent-content'] = {
light: accentContentLight,
dark: accentContentDark
};
// Compute info-content from info
const infoContentLight = colors['info-content']?.light ?? computeContentShade(colors.info.light);
const infoContentDark = colors['info-content']?.dark ?? computeContentShade(colors.info.dark);
computed['info-content'] = {
light: infoContentLight,
dark: infoContentDark
};
// Compute positive-content from positive
const positiveContentLight =
colors['positive-content']?.light ?? computeContentShade(colors.positive.light);
const positiveContentDark =
colors['positive-content']?.dark ?? computeContentShade(colors.positive.dark);
computed['positive-content'] = {
light: positiveContentLight,
dark: positiveContentDark
};
const warningContentLight =
colors['warning-content']?.light ?? computeContentShade(colors.warning.light);
const warningContentDark =
colors['warning-content']?.dark ?? computeContentShade(colors.warning.dark);
computed['warning-content'] = {
light: warningContentLight,
dark: warningContentDark
};
// Compute negative-content from negative
const negativeContentLight =
colors['negative-content']?.light ?? computeContentShade(colors.negative.light);
const negativeContentDark =
colors['negative-content']?.dark ?? computeContentShade(colors.negative.dark);
computed['negative-content'] = {
light: negativeContentLight,
dark: negativeContentDark
};
return BUILTIN_COLORS.reduce((acc, color) => {
if (isRequiredColor(color)) {
acc[color] = colors[color];
} else if (isComputedColor(color)) {
acc[color] = computed[color];
}
return acc;
}, /** @type {import('ts-essentials').DeepRequired<ThemeColors>} */ ({}));
};
/**
* @param {string} color
* @returns {boolean}
*/
const isDark = (color) => chroma.contrast(color, 'black') < chroma.contrast(color, 'white');
/**
* @param {string} color
* @returns {string}
*/
const computeContentShade = (color) => {
const hue = chroma(color).get('hsl.h');
const saturation = chroma(color).get('hsl.s');
return chroma.hsl(hue, saturation / 2, isDark(color) ? 0.975 : 0.025).hex();
};
/**
* @param {string} color
* @param {number} amount
*/
const darken = (color, amount) => chroma(color).darken(amount).hex();
/**
* @param {string} color
* @param {number} amount
*/
const brighten = (color, amount) => chroma(color).brighten(amount).hex();