MCPcopy
hub / github.com/GitbookIO/gitbook / colorScale

Function colorScale

packages/colors/src/transformations.ts:176–257  ·  view source on GitHub ↗
(
    hex: string,
    {
        darkMode = false,
        background = darkMode ? DARK_BASE : LIGHT_BASE,
        foreground = darkMode ? LIGHT_BASE : DARK_BASE,
        mix,
    }: ColorScaleOptions = {}
)

Source from the content-addressed store, hash-verified

174 * @param {object} options
175 */
176export function colorScale(
177 hex: string,
178 {
179 darkMode = false,
180 background = darkMode ? DARK_BASE : LIGHT_BASE,
181 foreground = darkMode ? LIGHT_BASE : DARK_BASE,
182 mix,
183 }: ColorScaleOptions = {}
184) {
185 const baseColor = rgbToOklch(hexToRgbArray(hex));
186 const mixColor = mix?.color ? rgbToOklch(hexToRgbArray(mix.color)) : null;
187 const foregroundColor = rgbToOklch(hexToRgbArray(foreground));
188 const backgroundColor = rgbToOklch(hexToRgbArray(background));
189 let mapping = darkMode ? colorMixMapping.dark : colorMixMapping.light;
190
191 if (mixColor && mix?.ratio && mix.ratio > 0) {
192 // If defined, we mix in a (tiny) bit of the mix color with the base color.
193 baseColor.L = mixColor.L * mix.ratio + baseColor.L * (1 - mix.ratio);
194 baseColor.C = mixColor.C * mix.ratio + baseColor.C * (1 - mix.ratio);
195 baseColor.H = mix.color === DEFAULT_TINT_COLOR ? baseColor.H : mixColor.H;
196 }
197
198 if (
199 (darkMode && baseColor.L < backgroundColor.L) ||
200 (!darkMode && baseColor.L > backgroundColor.L)
201 ) {
202 // If the supplied color is outside of our lightness bounds, use the supplied color's lightness.
203 // This is mostly used to allow darker-than-dark backgrounds for brands that specifically want that look.
204 const difference = (backgroundColor.L - baseColor.L) / backgroundColor.L;
205 backgroundColor.L = baseColor.L;
206 // At the edges of the scale, the subtle lightness changes stop being perceptible. We need to amp up our mapping to still stand out.
207 const amplifier = 1;
208 mapping = mapping.map((step, index) =>
209 index < 9 ? step + step * amplifier * difference : step
210 );
211 }
212
213 const result = [];
214
215 for (let index = 0; index < mapping.length; index++) {
216 const step = mapping[index]!;
217 const targetL = foregroundColor.L * step + backgroundColor.L * (1 - step);
218
219 if (
220 index === 8 &&
221 !mix &&
222 (darkMode ? targetL - baseColor.L < 0.2 : baseColor.L - targetL < 0.2)
223 ) {
224 // Original colour is close enough to target, so let's use the original colour as step 9.
225 result.push(hex);
226 continue;
227 }
228
229 const chromaRatio = (() => {
230 switch (index) {
231 // Step 9 and 10 have max chroma, meaning they are fully saturated.
232 case 8:
233 case 9:

Callers 2

generateColorVariableFunction · 0.90
SiteDefaultIconFunction · 0.90

Calls 4

rgbToOklchFunction · 0.85
hexToRgbArrayFunction · 0.85
rgbArrayToHexFunction · 0.85
oklchToRgbFunction · 0.85

Tested by

no test coverage detected