@tokens-studio/graph-engine
Version:
An execution engine to handle Token Studios generators and resolvers
96 lines • 3.86 kB
JavaScript
import { Black, White, toColor, toColorObject } from './lib/utils.js';
import { ColorSchema, NumberSchema, StringSchema } from '../../schemas/index.js';
import { ContrastAlgorithm } from '../../types/index.js';
import { Node } from '../../programmatic/node.js';
import { flattenAlpha } from './lib/flattenAlpha.js';
export const contrastCheck = (foreground, background, algorithm) => {
return Math.abs(foreground.contrast(background, algorithm));
};
export default class NodeDefinition extends Node {
static title = 'Contrasting Alpha';
static type = 'studio.tokens.color.contrastingAlpha';
static description = 'Reduce alpha until you are close to the threshold.';
constructor(props) {
super(props);
// Inputs
this.addInput('foreground', {
type: {
...ColorSchema,
default: Black
}
});
this.addInput('background', {
type: {
...ColorSchema,
default: White
}
});
this.addInput('algorithm', {
type: {
...StringSchema,
enum: Object.values(ContrastAlgorithm),
default: ContrastAlgorithm.APCA
}
});
this.addInput('threshold', {
type: {
...NumberSchema,
default: 60
}
});
this.addInput('precision', {
type: {
...NumberSchema,
default: 5
}
});
// Outputs
this.addOutput('alpha', {
type: NumberSchema
});
this.addOutput('color', {
type: ColorSchema
});
this.addOutput('contrast', {
type: NumberSchema
});
}
execute() {
const { algorithm, foreground, background, threshold, precision } = this.getAllInputs();
const binarySearchAlpha = (low, high, fg, bg, targetContrast, iterations) => {
if (iterations == 0 || high - low < 0.01) {
// Adding a minimum delta to prevent infinite recursion
fg.alpha = high; // Default to higher alpha if exact match isn't found
return high; // Ensure we are returning the alpha that provides sufficient contrast
}
const mid = (low + high) / 2;
fg.alpha = mid;
// Convert blended color back to Color object and then to hex string
const solidColor = flattenAlpha(fg, bg);
currentContrast = contrastCheck(solidColor, bg, algorithm);
if (currentContrast >= targetContrast) {
return binarySearchAlpha(low, mid, fg, bg, targetContrast, iterations - 1);
}
else {
return binarySearchAlpha(mid, high, fg, bg, targetContrast, iterations - 1);
}
};
const foregroundColor = toColor(foreground);
const backgroundColor = toColor(background);
let currentContrast = contrastCheck(foregroundColor, backgroundColor, algorithm);
if (currentContrast <= threshold) {
this.outputs.alpha.set(1);
this.outputs.color.set(toColorObject(foregroundColor));
this.outputs.contrast.set(currentContrast);
return;
}
const finalAlpha = binarySearchAlpha(0, 1, foregroundColor, backgroundColor, threshold, precision);
foregroundColor.alpha = finalAlpha;
const finalColor = flattenAlpha(foregroundColor, backgroundColor);
const finalContrast = Math.abs(finalColor.contrast(backgroundColor, algorithm));
this.outputs.alpha.set(finalAlpha);
this.outputs.color.set(toColorObject(finalColor));
this.outputs.contrast.set(finalContrast);
}
}
//# sourceMappingURL=contrastingAlpha.js.map