@basiclines/rampa 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/dist/index.js +335 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -140,6 +140,35 @@ Available types:
|
|
|
140
140
|
| `--output` | `-O` | Output format: text, json, css | text |
|
|
141
141
|
| `--preview` | | Show colored squares | true |
|
|
142
142
|
|
|
143
|
+
### Accessibility
|
|
144
|
+
|
|
145
|
+
| Flag | Alias | Description | Default |
|
|
146
|
+
|------|-------|-------------|---------|
|
|
147
|
+
| `--accessibility` | `-A` | APCA contrast report | off |
|
|
148
|
+
|
|
149
|
+
The `-A` flag generates an accessibility report using the [APCA](https://github.com/Myndex/APCA) (Accessible Perceptual Contrast Algorithm) methodology. It analyzes all color pairs across all generated ramps and groups passing pairs by contrast level.
|
|
150
|
+
|
|
151
|
+
**Filter options:**
|
|
152
|
+
|
|
153
|
+
| Syntax | Example | Description |
|
|
154
|
+
|--------|---------|-------------|
|
|
155
|
+
| `-A` | `-A` | Show all passing pairs |
|
|
156
|
+
| `-A=<Lc>` | `-A=60` | Minimum Lc threshold |
|
|
157
|
+
| `-A=<label>` | `-A=body` | Filter by named level |
|
|
158
|
+
| `-A=<min>:<max>` | `-A=15:30` | Lc range filter |
|
|
159
|
+
| `-A=<label>:<label>` | `-A=nontext:bold` | Range using level names |
|
|
160
|
+
|
|
161
|
+
**Level labels:**
|
|
162
|
+
|
|
163
|
+
| Label | Lc Threshold | Use Case |
|
|
164
|
+
|-------|-------------|----------|
|
|
165
|
+
| `preferred` | 90 | Preferred body text |
|
|
166
|
+
| `body` | 75 | Body text |
|
|
167
|
+
| `large` | 60 | Large text |
|
|
168
|
+
| `bold` | 45 | Large/bold text |
|
|
169
|
+
| `minimum` | 30 | Minimum text |
|
|
170
|
+
| `nontext` | 15 | Non-text elements |
|
|
171
|
+
|
|
143
172
|
### Other
|
|
144
173
|
|
|
145
174
|
| Flag | Alias | Description |
|
|
@@ -251,6 +280,28 @@ Output:
|
|
|
251
280
|
rampa -C "#3b82f6" --no-preview | head -5
|
|
252
281
|
```
|
|
253
282
|
|
|
283
|
+
### Accessibility Report
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Full APCA contrast report
|
|
287
|
+
rampa -C "#3b82f6" --add=complementary -A
|
|
288
|
+
|
|
289
|
+
# Filter by minimum Lc threshold
|
|
290
|
+
rampa -C "#3b82f6" --add=complementary -A=body
|
|
291
|
+
|
|
292
|
+
# Filter by Lc range
|
|
293
|
+
rampa -C "#3b82f6" --add=complementary -A=15:30
|
|
294
|
+
|
|
295
|
+
# Filter using level labels
|
|
296
|
+
rampa -C "#3b82f6" --add=complementary -A=nontext:bold
|
|
297
|
+
|
|
298
|
+
# Accessibility report in JSON
|
|
299
|
+
rampa -C "#3b82f6" --add=complementary -A -O json
|
|
300
|
+
|
|
301
|
+
# Accessibility report in CSS (appended as comment)
|
|
302
|
+
rampa -C "#3b82f6" --add=complementary -A -O css
|
|
303
|
+
```
|
|
304
|
+
|
|
254
305
|
## Contextual Help
|
|
255
306
|
|
|
256
307
|
Run any flag without a value to see detailed help:
|
package/dist/index.js
CHANGED
|
@@ -9943,6 +9943,291 @@ ${dim}For accurate color previews, use a terminal with COLORTERM=truecolor.${res
|
|
|
9943
9943
|
return null;
|
|
9944
9944
|
}
|
|
9945
9945
|
|
|
9946
|
+
// node_modules/apca-w3/src/apca-w3.js
|
|
9947
|
+
var SA98G = {
|
|
9948
|
+
mainTRC: 2.4,
|
|
9949
|
+
get mainTRCencode() {
|
|
9950
|
+
return 1 / this.mainTRC;
|
|
9951
|
+
},
|
|
9952
|
+
sRco: 0.2126729,
|
|
9953
|
+
sGco: 0.7151522,
|
|
9954
|
+
sBco: 0.072175,
|
|
9955
|
+
normBG: 0.56,
|
|
9956
|
+
normTXT: 0.57,
|
|
9957
|
+
revTXT: 0.62,
|
|
9958
|
+
revBG: 0.65,
|
|
9959
|
+
blkThrs: 0.022,
|
|
9960
|
+
blkClmp: 1.414,
|
|
9961
|
+
scaleBoW: 1.14,
|
|
9962
|
+
scaleWoB: 1.14,
|
|
9963
|
+
loBoWoffset: 0.027,
|
|
9964
|
+
loWoBoffset: 0.027,
|
|
9965
|
+
deltaYmin: 0.0005,
|
|
9966
|
+
loClip: 0.1,
|
|
9967
|
+
mFactor: 1.9468554433171,
|
|
9968
|
+
get mFactInv() {
|
|
9969
|
+
return 1 / this.mFactor;
|
|
9970
|
+
},
|
|
9971
|
+
mOffsetIn: 0.0387393816571401,
|
|
9972
|
+
mExpAdj: 0.283343396420869,
|
|
9973
|
+
get mExp() {
|
|
9974
|
+
return this.mExpAdj / this.blkClmp;
|
|
9975
|
+
},
|
|
9976
|
+
mOffsetOut: 0.312865795870758
|
|
9977
|
+
};
|
|
9978
|
+
function APCAcontrast(txtY, bgY, places = -1) {
|
|
9979
|
+
const icp = [0, 1.1];
|
|
9980
|
+
if (isNaN(txtY) || isNaN(bgY) || Math.min(txtY, bgY) < icp[0] || Math.max(txtY, bgY) > icp[1]) {
|
|
9981
|
+
return 0;
|
|
9982
|
+
}
|
|
9983
|
+
let SAPC = 0;
|
|
9984
|
+
let outputContrast = 0;
|
|
9985
|
+
let polCat = "BoW";
|
|
9986
|
+
txtY = txtY > SA98G.blkThrs ? txtY : txtY + Math.pow(SA98G.blkThrs - txtY, SA98G.blkClmp);
|
|
9987
|
+
bgY = bgY > SA98G.blkThrs ? bgY : bgY + Math.pow(SA98G.blkThrs - bgY, SA98G.blkClmp);
|
|
9988
|
+
if (Math.abs(bgY - txtY) < SA98G.deltaYmin) {
|
|
9989
|
+
return 0;
|
|
9990
|
+
}
|
|
9991
|
+
if (bgY > txtY) {
|
|
9992
|
+
SAPC = (Math.pow(bgY, SA98G.normBG) - Math.pow(txtY, SA98G.normTXT)) * SA98G.scaleBoW;
|
|
9993
|
+
outputContrast = SAPC < SA98G.loClip ? 0 : SAPC - SA98G.loBoWoffset;
|
|
9994
|
+
} else {
|
|
9995
|
+
polCat = "WoB";
|
|
9996
|
+
SAPC = (Math.pow(bgY, SA98G.revBG) - Math.pow(txtY, SA98G.revTXT)) * SA98G.scaleWoB;
|
|
9997
|
+
outputContrast = SAPC > -SA98G.loClip ? 0 : SAPC + SA98G.loWoBoffset;
|
|
9998
|
+
}
|
|
9999
|
+
if (places < 0) {
|
|
10000
|
+
return outputContrast * 100;
|
|
10001
|
+
} else if (places == 0) {
|
|
10002
|
+
return Math.round(Math.abs(outputContrast) * 100) + "<sub>" + polCat + "</sub>";
|
|
10003
|
+
} else if (Number.isInteger(places)) {
|
|
10004
|
+
return (outputContrast * 100).toFixed(places);
|
|
10005
|
+
} else {
|
|
10006
|
+
return 0;
|
|
10007
|
+
}
|
|
10008
|
+
}
|
|
10009
|
+
function sRGBtoY(rgb10 = [0, 0, 0]) {
|
|
10010
|
+
function simpleExp(chan) {
|
|
10011
|
+
return Math.pow(chan / 255, SA98G.mainTRC);
|
|
10012
|
+
}
|
|
10013
|
+
return SA98G.sRco * simpleExp(rgb10[0]) + SA98G.sGco * simpleExp(rgb10[1]) + SA98G.sBco * simpleExp(rgb10[2]);
|
|
10014
|
+
}
|
|
10015
|
+
|
|
10016
|
+
// src/accessibility/apca.ts
|
|
10017
|
+
var APCA_LEVELS = [
|
|
10018
|
+
{ id: "preferred-body", name: "Preferred body text", minLc: 90 },
|
|
10019
|
+
{ id: "body", name: "Body text", minLc: 75 },
|
|
10020
|
+
{ id: "large", name: "Large text", minLc: 60 },
|
|
10021
|
+
{ id: "large-bold", name: "Large/bold text", minLc: 45 },
|
|
10022
|
+
{ id: "min-text", name: "Minimum text", minLc: 30 },
|
|
10023
|
+
{ id: "non-text", name: "Non-text", minLc: 15 }
|
|
10024
|
+
];
|
|
10025
|
+
var LEVEL_ALIASES = {
|
|
10026
|
+
preferred: 90,
|
|
10027
|
+
body: 75,
|
|
10028
|
+
large: 60,
|
|
10029
|
+
bold: 45,
|
|
10030
|
+
minimum: 30,
|
|
10031
|
+
nontext: 15
|
|
10032
|
+
};
|
|
10033
|
+
function resolveValue2(val) {
|
|
10034
|
+
const num9 = parseFloat(val);
|
|
10035
|
+
if (!isNaN(num9) && num9 >= 0)
|
|
10036
|
+
return num9;
|
|
10037
|
+
const label = val.toLowerCase().trim();
|
|
10038
|
+
if (label in LEVEL_ALIASES)
|
|
10039
|
+
return LEVEL_ALIASES[label];
|
|
10040
|
+
return null;
|
|
10041
|
+
}
|
|
10042
|
+
function parseAccessibilityFilter(value) {
|
|
10043
|
+
const raw = value ?? "";
|
|
10044
|
+
if (!value || value === "" || value === "true")
|
|
10045
|
+
return { min: 0, max: Infinity, raw };
|
|
10046
|
+
if (value.includes(":")) {
|
|
10047
|
+
const [startStr, endStr] = value.split(":");
|
|
10048
|
+
const start = resolveValue2(startStr);
|
|
10049
|
+
const end = resolveValue2(endStr);
|
|
10050
|
+
if (start === null || end === null) {
|
|
10051
|
+
const validLabels2 = Object.keys(LEVEL_ALIASES).join(", ");
|
|
10052
|
+
console.error(`Error: Invalid accessibility range "${value}". Use Lc numbers or labels: ${validLabels2}`);
|
|
10053
|
+
process.exit(1);
|
|
10054
|
+
}
|
|
10055
|
+
const lo = Math.min(start, end);
|
|
10056
|
+
const hi = Math.max(start, end);
|
|
10057
|
+
return { min: lo, max: hi, raw: value };
|
|
10058
|
+
}
|
|
10059
|
+
const resolved = resolveValue2(value);
|
|
10060
|
+
if (resolved !== null)
|
|
10061
|
+
return { min: resolved, max: Infinity, raw: value };
|
|
10062
|
+
const validLabels = Object.keys(LEVEL_ALIASES).join(", ");
|
|
10063
|
+
console.error(`Error: Invalid accessibility filter "${value}". Use a Lc number, label, or range (e.g. 15:30). Labels: ${validLabels}`);
|
|
10064
|
+
process.exit(1);
|
|
10065
|
+
}
|
|
10066
|
+
function computeApca(fgHex, bgHex) {
|
|
10067
|
+
const [fgR, fgG, fgB] = chroma_js_default(fgHex).rgb();
|
|
10068
|
+
const [bgR, bgG, bgB] = chroma_js_default(bgHex).rgb();
|
|
10069
|
+
return APCAcontrast(sRGBtoY([fgR, fgG, fgB]), sRGBtoY([bgR, bgG, bgB]));
|
|
10070
|
+
}
|
|
10071
|
+
function getPassingLevels(lc) {
|
|
10072
|
+
const absLc = Math.abs(lc);
|
|
10073
|
+
return APCA_LEVELS.filter((level) => absLc >= level.minLc);
|
|
10074
|
+
}
|
|
10075
|
+
|
|
10076
|
+
// src/accessibility/report.ts
|
|
10077
|
+
function collectColors(ramps) {
|
|
10078
|
+
const refs = [];
|
|
10079
|
+
for (const ramp of ramps) {
|
|
10080
|
+
for (let i2 = 0;i2 < ramp.colors.length; i2++) {
|
|
10081
|
+
refs.push({ ramp: ramp.name, index: i2, color: ramp.colors[i2] });
|
|
10082
|
+
}
|
|
10083
|
+
}
|
|
10084
|
+
return refs;
|
|
10085
|
+
}
|
|
10086
|
+
function deduplicateColors(colors2) {
|
|
10087
|
+
if (colors2.length <= 2)
|
|
10088
|
+
return colors2;
|
|
10089
|
+
const keep = new Set;
|
|
10090
|
+
keep.add(0);
|
|
10091
|
+
keep.add(colors2.length - 1);
|
|
10092
|
+
for (let i2 = 1;i2 < colors2.length; i2++) {
|
|
10093
|
+
const prev = colors2[i2 - 1];
|
|
10094
|
+
const curr = colors2[i2];
|
|
10095
|
+
if (curr.ramp !== prev.ramp) {
|
|
10096
|
+
keep.add(i2);
|
|
10097
|
+
keep.add(i2 - 1);
|
|
10098
|
+
continue;
|
|
10099
|
+
}
|
|
10100
|
+
const de = chroma_js_default.deltaE(curr.color, prev.color);
|
|
10101
|
+
if (de >= 3) {
|
|
10102
|
+
keep.add(i2);
|
|
10103
|
+
}
|
|
10104
|
+
}
|
|
10105
|
+
return colors2.filter((_3, i2) => keep.has(i2));
|
|
10106
|
+
}
|
|
10107
|
+
var DEFAULT_FILTER = { min: 0, max: Infinity, raw: "" };
|
|
10108
|
+
function generateAccessibilityReport(ramps, filter = DEFAULT_FILTER) {
|
|
10109
|
+
const allColors = collectColors(ramps);
|
|
10110
|
+
const colors2 = deduplicateColors(allColors);
|
|
10111
|
+
const totalPairs = colors2.length * (colors2.length - 1) / 2;
|
|
10112
|
+
const levelMap = new Map;
|
|
10113
|
+
for (const level of APCA_LEVELS) {
|
|
10114
|
+
levelMap.set(level.id, []);
|
|
10115
|
+
}
|
|
10116
|
+
let passingPairs = 0;
|
|
10117
|
+
for (let i2 = 0;i2 < colors2.length; i2++) {
|
|
10118
|
+
for (let j = i2 + 1;j < colors2.length; j++) {
|
|
10119
|
+
const a2 = colors2[i2];
|
|
10120
|
+
const b2 = colors2[j];
|
|
10121
|
+
const lcAB = computeApca(a2.color, b2.color);
|
|
10122
|
+
const lcBA = computeApca(b2.color, a2.color);
|
|
10123
|
+
const bestAbsLc = Math.max(Math.abs(lcAB), Math.abs(lcBA));
|
|
10124
|
+
const passing = getPassingLevels(bestAbsLc);
|
|
10125
|
+
if (passing.length > 0) {
|
|
10126
|
+
passingPairs++;
|
|
10127
|
+
const pair = {
|
|
10128
|
+
colorA: a2,
|
|
10129
|
+
colorB: b2,
|
|
10130
|
+
lcAB: Math.round(lcAB * 100) / 100,
|
|
10131
|
+
lcBA: Math.round(lcBA * 100) / 100
|
|
10132
|
+
};
|
|
10133
|
+
const highest = passing[0];
|
|
10134
|
+
levelMap.get(highest.id).push(pair);
|
|
10135
|
+
}
|
|
10136
|
+
}
|
|
10137
|
+
}
|
|
10138
|
+
const levels = APCA_LEVELS.filter((level) => level.minLc >= filter.min && level.minLc <= filter.max).map((level) => {
|
|
10139
|
+
const pairs = filter.max < Infinity ? levelMap.get(level.id).filter((p) => {
|
|
10140
|
+
const bestAbsLc = Math.max(Math.abs(p.lcAB), Math.abs(p.lcBA));
|
|
10141
|
+
return bestAbsLc >= filter.min && bestAbsLc <= filter.max;
|
|
10142
|
+
}) : levelMap.get(level.id);
|
|
10143
|
+
return { id: level.id, name: level.name, minLc: level.minLc, pairs };
|
|
10144
|
+
});
|
|
10145
|
+
return {
|
|
10146
|
+
totalPairs,
|
|
10147
|
+
passingPairs,
|
|
10148
|
+
levels,
|
|
10149
|
+
filter
|
|
10150
|
+
};
|
|
10151
|
+
}
|
|
10152
|
+
|
|
10153
|
+
// src/formatters/accessibility-json.ts
|
|
10154
|
+
function formatAccessibilityJson(report) {
|
|
10155
|
+
return {
|
|
10156
|
+
totalPairs: report.totalPairs,
|
|
10157
|
+
passingPairs: report.passingPairs,
|
|
10158
|
+
filter: report.filter.raw ? { value: report.filter.raw, min: report.filter.min, max: report.filter.max === Infinity ? null : report.filter.max } : null,
|
|
10159
|
+
levels: report.levels.map((level) => ({
|
|
10160
|
+
id: level.id,
|
|
10161
|
+
name: level.name,
|
|
10162
|
+
minLc: level.minLc,
|
|
10163
|
+
count: level.pairs.length,
|
|
10164
|
+
pairs: level.pairs.map((pair) => ({
|
|
10165
|
+
colorA: { ramp: pair.colorA.ramp, index: pair.colorA.index, color: pair.colorA.color },
|
|
10166
|
+
colorB: { ramp: pair.colorB.ramp, index: pair.colorB.index, color: pair.colorB.color },
|
|
10167
|
+
lcAB: pair.lcAB,
|
|
10168
|
+
lcBA: pair.lcBA
|
|
10169
|
+
}))
|
|
10170
|
+
}))
|
|
10171
|
+
};
|
|
10172
|
+
}
|
|
10173
|
+
|
|
10174
|
+
// src/formatters/accessibility-text.ts
|
|
10175
|
+
function formatLc(lc) {
|
|
10176
|
+
const str = lc.toString();
|
|
10177
|
+
return lc >= 0 ? ` ${str}` : str;
|
|
10178
|
+
}
|
|
10179
|
+
function pairSquares(pair) {
|
|
10180
|
+
const [rA, gA, bA] = chroma_js_default(pair.colorA.color).rgb();
|
|
10181
|
+
const [rB, gB, bB] = chroma_js_default(pair.colorB.color).rgb();
|
|
10182
|
+
return `${coloredSquare(rA, gA, bA)}${coloredSquare(rB, gB, bB)}`;
|
|
10183
|
+
}
|
|
10184
|
+
function formatAccessibilityText(report, options = {}) {
|
|
10185
|
+
const lines = [];
|
|
10186
|
+
const showPreview = options.preview ?? false;
|
|
10187
|
+
lines.push("");
|
|
10188
|
+
lines.push("# Accessibility Report (APCA)");
|
|
10189
|
+
lines.push(`${report.passingPairs} of ${report.totalPairs} pairs pass at least one level`);
|
|
10190
|
+
lines.push("");
|
|
10191
|
+
const filteredPairCount = report.levels.reduce((sum, l2) => sum + l2.pairs.length, 0);
|
|
10192
|
+
if (filteredPairCount === 0) {
|
|
10193
|
+
const filterDesc = report.filter.raw ? `filter: ${report.filter.raw}` : "current filter";
|
|
10194
|
+
lines.push(`No pairs match the ${filterDesc}`);
|
|
10195
|
+
lines.push("");
|
|
10196
|
+
return lines.join(`
|
|
10197
|
+
`);
|
|
10198
|
+
}
|
|
10199
|
+
for (const level of report.levels) {
|
|
10200
|
+
if (level.pairs.length === 0)
|
|
10201
|
+
continue;
|
|
10202
|
+
lines.push(`## ${level.name} (Lc ≥ ${level.minLc}) — ${level.pairs.length} pairs`);
|
|
10203
|
+
const maxColorA = Math.max(...level.pairs.map((p) => p.colorA.color.length));
|
|
10204
|
+
const maxColorB = Math.max(...level.pairs.map((p) => p.colorB.color.length));
|
|
10205
|
+
const maxLcAB = Math.max(...level.pairs.map((p) => formatLc(p.lcAB).length));
|
|
10206
|
+
const maxLcBA = Math.max(...level.pairs.map((p) => formatLc(p.lcBA).length));
|
|
10207
|
+
const maxRefA = Math.max(...level.pairs.map((p) => `${p.colorA.ramp}[${p.colorA.index}]`.length));
|
|
10208
|
+
const maxRefB = Math.max(...level.pairs.map((p) => `${p.colorB.ramp}[${p.colorB.index}]`.length));
|
|
10209
|
+
for (const pair of level.pairs) {
|
|
10210
|
+
const colA = pair.colorA.color.padEnd(maxColorA);
|
|
10211
|
+
const colB = pair.colorB.color.padEnd(maxColorB);
|
|
10212
|
+
const lcA = formatLc(pair.lcAB).padStart(maxLcAB);
|
|
10213
|
+
const lcB = formatLc(pair.lcBA).padStart(maxLcBA);
|
|
10214
|
+
const refA = `${pair.colorA.ramp}[${pair.colorA.index}]`.padEnd(maxRefA);
|
|
10215
|
+
const refB = `${pair.colorB.ramp}[${pair.colorB.index}]`.padEnd(maxRefB);
|
|
10216
|
+
const preview = showPreview ? `${pairSquares(pair)} ` : "";
|
|
10217
|
+
lines.push(` ${preview}${colA} ↔ ${colB} Lc ${lcA} / ${lcB} ${refA} ↔ ${refB}`);
|
|
10218
|
+
}
|
|
10219
|
+
lines.push("");
|
|
10220
|
+
}
|
|
10221
|
+
return lines.join(`
|
|
10222
|
+
`);
|
|
10223
|
+
}
|
|
10224
|
+
function formatAccessibilityCss(report) {
|
|
10225
|
+
return `
|
|
10226
|
+
/*
|
|
10227
|
+
` + formatAccessibilityText(report) + `*/
|
|
10228
|
+
`;
|
|
10229
|
+
}
|
|
10230
|
+
|
|
9946
10231
|
// src/index.ts
|
|
9947
10232
|
if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
9948
10233
|
showHelp();
|
|
@@ -9995,6 +10280,10 @@ HARMONIES
|
|
|
9995
10280
|
OUTPUT
|
|
9996
10281
|
${cyan}-O, --output <format>${reset} ${dim}Output format (default: text)${reset}
|
|
9997
10282
|
${cyan}--preview / --no-preview${reset} ${dim}Show colored squares (default: true)${reset}
|
|
10283
|
+
${cyan}-A, --accessibility [filter]${reset} ${dim}Show APCA contrast report${reset}
|
|
10284
|
+
|
|
10285
|
+
${dim}Filters: preferred, body, large, bold, minimum, nontext${reset}
|
|
10286
|
+
${dim}or a custom Lc value (e.g. 60)${reset}
|
|
9998
10287
|
|
|
9999
10288
|
${dim}Formats: text, json, css${reset}
|
|
10000
10289
|
|
|
@@ -10009,6 +10298,8 @@ EXAMPLES
|
|
|
10009
10298
|
${cyan}rampa -C "#3b82f6" --add=shift:45 --add=shift:90${reset}
|
|
10010
10299
|
${cyan}rampa -C "#3b82f6" -O css${reset}
|
|
10011
10300
|
${cyan}rampa -C "#3b82f6" --tint-color="#FF0000" --tint-opacity=15${reset}
|
|
10301
|
+
${cyan}rampa -C "#3b82f6" -A${reset}
|
|
10302
|
+
${cyan}rampa -C "#3b82f6" --add=complementary -O json -A${reset}
|
|
10012
10303
|
`;
|
|
10013
10304
|
console.log(help.trim());
|
|
10014
10305
|
process.exit(0);
|
|
@@ -10148,6 +10439,25 @@ Examples:
|
|
|
10148
10439
|
rampa -C "#3b82f6" --output=json
|
|
10149
10440
|
rampa -C "#3b82f6" --output=css
|
|
10150
10441
|
rampa -C "#3b82f6" -O json --add=complementary
|
|
10442
|
+
`,
|
|
10443
|
+
accessibility: `
|
|
10444
|
+
-A, --accessibility [filter] Show APCA contrast report
|
|
10445
|
+
|
|
10446
|
+
Filters (optional):
|
|
10447
|
+
preferred Lc ≥ 90 Preferred body text
|
|
10448
|
+
body Lc ≥ 75 Body text
|
|
10449
|
+
large Lc ≥ 60 Large text
|
|
10450
|
+
bold Lc ≥ 45 Large/bold text
|
|
10451
|
+
minimum Lc ≥ 30 Minimum text
|
|
10452
|
+
nontext Lc ≥ 15 Non-text
|
|
10453
|
+
<number> Custom Lc threshold (e.g. 60)
|
|
10454
|
+
|
|
10455
|
+
Examples:
|
|
10456
|
+
rampa -C "#3b82f6" -A
|
|
10457
|
+
rampa -C "#3b82f6" -A body
|
|
10458
|
+
rampa -C "#3b82f6" -A=large
|
|
10459
|
+
rampa -C "#3b82f6" --accessibility=75
|
|
10460
|
+
rampa -C "#3b82f6" -O json -A preferred
|
|
10151
10461
|
`
|
|
10152
10462
|
};
|
|
10153
10463
|
function showFlagHelp(flag) {
|
|
@@ -10190,7 +10500,7 @@ var validFormats = ["hex", "hsl", "rgb", "oklch"];
|
|
|
10190
10500
|
var main = defineCommand({
|
|
10191
10501
|
meta: {
|
|
10192
10502
|
name: "rampa",
|
|
10193
|
-
version: "1.
|
|
10503
|
+
version: "1.3.0",
|
|
10194
10504
|
description: "Generate mathematically accurate color palettes from a base color"
|
|
10195
10505
|
},
|
|
10196
10506
|
args: {
|
|
@@ -10271,6 +10581,11 @@ var main = defineCommand({
|
|
|
10271
10581
|
alias: ["O", "o"],
|
|
10272
10582
|
description: "Output format: text, json, css (default: text)",
|
|
10273
10583
|
default: "text"
|
|
10584
|
+
},
|
|
10585
|
+
accessibility: {
|
|
10586
|
+
type: "string",
|
|
10587
|
+
alias: ["A", "a"],
|
|
10588
|
+
description: "Show APCA contrast report. Optional: filter by level name or Lc value"
|
|
10274
10589
|
}
|
|
10275
10590
|
},
|
|
10276
10591
|
run({ args }) {
|
|
@@ -10510,10 +10825,23 @@ var main = defineCommand({
|
|
|
10510
10825
|
colors: formattedShiftedColors
|
|
10511
10826
|
});
|
|
10512
10827
|
}
|
|
10828
|
+
const accessibilityEnabled = args.accessibility !== undefined;
|
|
10829
|
+
const accessibilityFilter = accessibilityEnabled ? parseAccessibilityFilter(args.accessibility) : undefined;
|
|
10513
10830
|
if (outputType === "json") {
|
|
10514
|
-
|
|
10831
|
+
if (accessibilityEnabled) {
|
|
10832
|
+
const report = generateAccessibilityReport(ramps, accessibilityFilter);
|
|
10833
|
+
const output = { ramps: JSON.parse(formatJson(ramps)).ramps, accessibility: formatAccessibilityJson(report) };
|
|
10834
|
+
console.log(JSON.stringify(output, null, 2));
|
|
10835
|
+
} else {
|
|
10836
|
+
console.log(formatJson(ramps));
|
|
10837
|
+
}
|
|
10515
10838
|
} else if (outputType === "css") {
|
|
10516
|
-
|
|
10839
|
+
let output = formatCss2(ramps);
|
|
10840
|
+
if (accessibilityEnabled) {
|
|
10841
|
+
const report = generateAccessibilityReport(ramps, accessibilityFilter);
|
|
10842
|
+
output += formatAccessibilityCss(report);
|
|
10843
|
+
}
|
|
10844
|
+
console.log(output);
|
|
10517
10845
|
} else {
|
|
10518
10846
|
const canShowPreview = args.preview && supportsTruecolor();
|
|
10519
10847
|
if (args.preview && !canShowPreview) {
|
|
@@ -10540,6 +10868,10 @@ var main = defineCommand({
|
|
|
10540
10868
|
}
|
|
10541
10869
|
});
|
|
10542
10870
|
});
|
|
10871
|
+
if (accessibilityEnabled) {
|
|
10872
|
+
const report = generateAccessibilityReport(ramps, accessibilityFilter);
|
|
10873
|
+
console.log(formatAccessibilityText(report, { preview: canShowPreview }));
|
|
10874
|
+
}
|
|
10543
10875
|
}
|
|
10544
10876
|
}
|
|
10545
10877
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basiclines/rampa",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Generate mathematically accurate color palettes from a base color",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,8 +40,9 @@
|
|
|
40
40
|
"author": "ismael.fyi",
|
|
41
41
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"
|
|
43
|
+
"apca-w3": "^0.1.9",
|
|
44
44
|
"chroma-js": "^3.1.2",
|
|
45
|
+
"citty": "^0.1.6",
|
|
45
46
|
"culori": "^4.0.1"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|