@uinamic/colors
Version:
CSS color token generator centered on HSL lightness (HSL 기반 명도 중심 CSS 색상 토큰 생성기)
214 lines (206 loc) • 7.59 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// src/colorMap.js
var defaultColorHSLMap = {
red: [0, 100, 50],
blue: [240, 100, 50],
yellow: [60, 100, 50],
orange: [39, 100, 50],
green: [120, 100, 40],
purple: [270, 100, 60],
pink: [340, 100, 88],
teal: [180, 100, 45],
gray: [0, 0, 50],
darkgray: [0, 0, 30],
lightgray: [0, 0, 70],
coral: [16, 100, 65],
mint: [160, 100, 50],
cyan: [190, 100, 60],
violet: [290, 76, 72],
indigo: [225, 100, 45],
amber: [45, 100, 50]
};
// src/index.js
var import_fs = __toESM(require("fs"), 1);
// src/logic/spectrum.js
function getFullSpectrumFromCenter(centerL, limit2 = 5) {
const splitRange = centerL <= 22 || centerL >= 78;
const getLimit = getDynamicLimit(splitRange, limit2);
const maxL = 100 - getLimit;
const isLowRange = centerL <= 50;
const lowRange = isLowRange ? centerL - getLimit : maxL - centerL;
const highRange = isLowRange ? maxL - centerL : centerL - getLimit;
if (splitRange) {
const lowRange2 = isLowRange ? centerL - getLimit : maxL - centerL;
const highRange2 = lowRange2 * 4;
const result = calculateSpectrum(centerL, lowRange2, highRange2, isLowRange);
return result;
} else {
const result = calculateSpectrum(centerL, lowRange, highRange, isLowRange);
return result;
}
}
function getDynamicLimit(splitRange, defaultLimit = 5) {
if (splitRange) return 3;
return defaultLimit;
}
function calculateSpectrum(centerL, lowRange, highRange, isLowRange) {
let lowBias = Math.floor(lowRange * 0.1);
lowBias += (lowRange - lowBias) % 4;
const lowDelta = lowRange - lowBias;
let highBias = Math.floor(highRange * 0.1);
highBias += (highRange - highBias) % 4;
const highDelta = highRange - highBias;
let lowSteps;
let lowValues;
let highSteps;
let highValues;
if (isLowRange) {
lowSteps = smartLowBias(lowBias).map((w) => lowDelta / 4 + w);
lowValues = accumulateReverse(centerL, lowSteps);
highSteps = smartHighBias(highBias).map((w) => highDelta / 4 + w).reverse();
highValues = accumulate(centerL, highSteps);
} else {
lowSteps = smartLowBias(lowBias).map((w) => lowDelta / 4 + w).reverse();
lowValues = accumulate(centerL, lowSteps);
highSteps = smartHighBias(highBias).map((w) => highDelta / 4 + w);
highValues = accumulateReverse(centerL, highSteps);
}
const spectrum = [.../* @__PURE__ */ new Set([...lowValues, ...highValues])].sort((a, b) => a - b);
return spectrum;
}
function smartLowBias(total) {
const result = [0, 0, 0, 0];
for (let i = 0; i < total; i++) {
const index = 3 - i % 4;
result[index]++;
}
return result;
}
function smartHighBias(n) {
const result = [0, 0, 0, 0];
const weights = [3, 2, 1, 0];
for (let i = 0; i < n; i++) {
const idx = weights[i % 4];
result[idx]++;
}
return result;
}
function accumulate(start, steps) {
return steps.reduce(
(acc, curr) => {
const last = acc[acc.length - 1];
return [...acc, +(last + curr).toFixed(1)];
},
[start]
);
}
function accumulateReverse(end, steps) {
return steps.reduceRight(
(acc, curr) => {
const next = acc[0];
return [+(next - curr).toFixed(1), ...acc];
},
[end]
);
}
// src/logic/writeCss.js
function writeCss(map, spectrumFn, options = {}) {
const { format: format2 = "css", prefix: prefix2 = "--color-", limit: limit2 = 5 } = options;
const baseColors = [` ${prefix2}black: hsl(0, 0%, 0%);`, ` ${prefix2}white: hsl(0, 0%, 100%);`];
const baseColorsBlock = baseColors.join("\n");
const groupBlocks = [];
const groupFlatJson = {};
for (const [name2, [h, s, l]] of Object.entries(map)) {
const ramp = spectrumFn(l, limit2);
const group = ramp.map((lightness, i) => {
const level = (i + 1) * 100;
const key = `${name2}-${level}`;
const value = `hsl(${h}, ${s}%, ${lightness}%)`;
if (format2 === "json") {
groupFlatJson[key] = value;
return null;
}
return ` ${prefix2}${key}: ${value};`;
}).filter(Boolean);
groupBlocks.push(group.join("\n"));
}
if (format2 === "json") {
return JSON.stringify(groupFlatJson, null, 2);
}
if (format2 === "scss") {
return [baseColorsBlock, "", ...groupBlocks].join("\n\n");
}
return `:root {
${baseColorsBlock}
${groupBlocks.join("\n\n")}
}`;
}
// src/index.js
function generateColorTokens(map = defaultColorHSLMap, options = {}) {
const { format: format2 = "css", name: name2 = "uinamic-color", path: outputPath = "./theme", prefix: prefix2 = "color", limit: limit2 = 5 } = options;
const resolvedPrefix = format2 === "scss" ? `$${prefix2}-` : `--${prefix2}-`;
const content = writeCss(map, getFullSpectrumFromCenter, {
format: format2,
prefix: resolvedPrefix,
limit: limit2
});
const ext = format2 === "json" ? "json" : format2 === "scss" ? "scss" : "css";
const filePath2 = `${outputPath}/${name2}.${ext}`;
import_fs.default.mkdirSync(outputPath, { recursive: true });
import_fs.default.writeFileSync(filePath2, content, "utf-8");
return content;
}
// src/cli.js
var import_fs2 = __toESM(require("fs"), 1);
var import_path = __toESM(require("path"), 1);
var args = process.argv.slice(2);
var outputIndex = args.indexOf("--path");
var outputDir = outputIndex !== -1 ? args[outputIndex + 1] : "./theme";
var nameIndex = args.indexOf("--name");
var name = nameIndex !== -1 ? args[nameIndex + 1] : "uinamic-color";
var formatIndex = args.indexOf("--format");
var format = formatIndex !== -1 ? args[formatIndex + 1] : "css";
var prefixIndex = args.indexOf("--prefix");
var prefix;
var limitIndex = args.indexOf("--limit");
var limit = limitIndex !== -1 ? Number(args[limitIndex + 1]) : void 0;
if (format === "scss") {
const set = prefixIndex !== -1 ? args[prefixIndex + 1] : "color";
prefix = set ? `${set}` : "color";
} else {
const set = prefixIndex !== -1 ? args[prefixIndex + 1] : "color";
prefix = set ? `${set}` : "colo-";
}
if (!import_fs2.default.existsSync(outputDir)) {
import_fs2.default.mkdirSync(outputDir, { recursive: true });
}
var filePath = import_path.default.join(outputDir, `${name}.${format === "json" ? "json" : format === "scss" ? "scss" : "css"}`);
var css = generateColorTokens(
defaultColorHSLMap,
{ format, prefix, name, path: outputDir, limit }
// 동적으로 받아온 값 전달
);
import_fs2.default.writeFileSync(filePath, css, "utf-8");
console.log(`\u2705 Generated ${filePath}`);