@rojaostudio/ds-core 1.1.0-next.10 → 1.1.0-next.12
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/dist/{chunk-LP6UA4EW.js → chunk-NVYJME6V.js} +148 -46
- package/dist/generate.d.ts +15 -4
- package/dist/generate.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/themes.js +1 -1
- package/package.json +1 -1
|
@@ -874,6 +874,16 @@ function stateFills(scale, fill, text, preferred) {
|
|
|
874
874
|
return (_a = ok[i]) != null ? _a : p;
|
|
875
875
|
});
|
|
876
876
|
}
|
|
877
|
+
var carry = (scale, fill, text, value) => contrastRatio(text, value) >= AA ? value : stateFills(scale, fill, text, [value])[0];
|
|
878
|
+
function over(top, below) {
|
|
879
|
+
const ch = (h, i) => parseInt(h.slice(1 + 2 * i, 3 + 2 * i), 16);
|
|
880
|
+
const a = top.length === 9 ? ch(top, 3) / 255 : 1;
|
|
881
|
+
return `#${[0, 1, 2].map((i) => Math.round(ch(top, i) * a + ch(below, i) * (1 - a)).toString(16).padStart(2, "0")).join("")}`;
|
|
882
|
+
}
|
|
883
|
+
var PLATE_MIN = 6;
|
|
884
|
+
function distinct(a, b) {
|
|
885
|
+
return contrastRatio(a, b) >= 1.5 || Math.abs(hexToHsl(a)[1] - hexToHsl(b)[1]) >= 40;
|
|
886
|
+
}
|
|
877
887
|
var defaultWarn = (m) => {
|
|
878
888
|
var _a;
|
|
879
889
|
return (_a = globalThis.console) == null ? void 0 : _a.warn(m);
|
|
@@ -903,7 +913,7 @@ var ROLES = [
|
|
|
903
913
|
["text/on/accent", "d", "d"],
|
|
904
914
|
["text/on/tint", "d", "b"],
|
|
905
915
|
["colors/state/error", "l", "l"],
|
|
906
|
-
["colors/state/error-strong", "
|
|
916
|
+
["colors/state/error-strong", "p", "p"],
|
|
907
917
|
["surface/tint/strong", "d", "b"],
|
|
908
918
|
["text/on/error", "l", "l"],
|
|
909
919
|
["surface/action/default", "d", "b"],
|
|
@@ -989,7 +999,7 @@ var TINT_DEFAULT = 200;
|
|
|
989
999
|
var lighterStep = (s) => s - 100 ;
|
|
990
1000
|
var roleVar = (role) => `--${role.replaceAll("/", "-")}`;
|
|
991
1001
|
function generateRdsTheme(def, opts = {}) {
|
|
992
|
-
var _a, _b;
|
|
1002
|
+
var _a, _b, _c, _d;
|
|
993
1003
|
const warn = (_a = opts.warn) != null ? _a : defaultWarn;
|
|
994
1004
|
const where = `generateRdsTheme(${preview(def == null ? void 0 : def.name)})`;
|
|
995
1005
|
if (!(def == null ? void 0 : def.brand) || typeof def.brand !== "object") throw new Error(`${where}: brand is missing`);
|
|
@@ -1003,13 +1013,13 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1003
1013
|
const L = palette("blue");
|
|
1004
1014
|
const red = palette("red"), green = palette("green"), orange = palette("orange");
|
|
1005
1015
|
const teal = palette("teal"), purple = palette("purple");
|
|
1006
|
-
const lightBgs = [WHITE, N[100]];
|
|
1016
|
+
const lightBgs = [WHITE, N[100], N[200], A.scale[200]];
|
|
1007
1017
|
let heading;
|
|
1008
1018
|
if (b.heading) {
|
|
1009
1019
|
heading = ramp(b.heading, own).base;
|
|
1010
1020
|
if (!readsOn(heading, lightBgs)) {
|
|
1011
1021
|
const worst = Math.min(...lightBgs.map((bg) => contrastRatio(heading, bg)));
|
|
1012
|
-
warn(`generateRdsTheme(${def.name}): heading ${heading} is ${worst.toFixed(2)}:1 on surface/card
|
|
1022
|
+
warn(`generateRdsTheme(${def.name}): heading ${heading} is ${worst.toFixed(2)}:1 on surface/card, surface/page, surface/muted-strong or colors/accent/highlight (AA asks 4.5:1). Kept as given.`);
|
|
1013
1023
|
}
|
|
1014
1024
|
} else heading = readableFrom(P.base, P.scale, lightBgs, "darker", BLACK);
|
|
1015
1025
|
const invert = b.invert ? ramp(b.invert, own).base : WHITE;
|
|
@@ -1101,6 +1111,16 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1101
1111
|
"logo/inverse-signature": WHITE,
|
|
1102
1112
|
"social/ink": BLACK
|
|
1103
1113
|
};
|
|
1114
|
+
const single = !b.secondary;
|
|
1115
|
+
const K = single ? N : P.scale;
|
|
1116
|
+
if (single) {
|
|
1117
|
+
const steps = [900, 800, 700, 600, 500];
|
|
1118
|
+
const k = Math.max(0, steps.findIndex((s) => distinct(N[s], l["colors/secondary/default"])));
|
|
1119
|
+
l["colors/primary/default"] = N[steps[Math.min(k, 2)]];
|
|
1120
|
+
l["colors/primary/dark"] = N[steps[Math.min(k, 2) + 1]];
|
|
1121
|
+
l["colors/primary/active"] = N[steps[Math.min(k, 2) + 2]];
|
|
1122
|
+
l["colors/primary/light"] = N[500];
|
|
1123
|
+
}
|
|
1104
1124
|
for (const [fill, text] of [
|
|
1105
1125
|
["colors/primary/default", "text/on/primary"],
|
|
1106
1126
|
["colors/secondary/default", "text/on/secondary"],
|
|
@@ -1113,10 +1133,12 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1113
1133
|
["colors/state/neutral", "text/on/neutral"],
|
|
1114
1134
|
["surface/cover", "text/on/cover"],
|
|
1115
1135
|
["surface/lift/action", "text/on/lift-action"],
|
|
1116
|
-
["colors/primary/
|
|
1136
|
+
["colors/primary/default", "text/on/primary-strong"],
|
|
1117
1137
|
["surface/tint/default", "text/on/tint"]
|
|
1118
1138
|
]) l[text] = on(l[fill]);
|
|
1119
|
-
|
|
1139
|
+
for (const role of ["colors/primary/dark", "colors/primary/light"])
|
|
1140
|
+
l[role] = carry(K, l["colors/primary/default"], l["text/on/primary-strong"], l[role]);
|
|
1141
|
+
[l["colors/primary/active"]] = stateFills(K, l["colors/primary/default"], l["text/on/primary"], [l["colors/primary/active"]]);
|
|
1120
1142
|
[l["colors/secondary/hover"], l["colors/secondary/active"]] = stateFills(
|
|
1121
1143
|
S.scale,
|
|
1122
1144
|
l["colors/secondary/default"],
|
|
@@ -1125,9 +1147,9 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1125
1147
|
);
|
|
1126
1148
|
[l["colors/accent/hover"]] = stateFills(A.scale, l["colors/accent/default"], l["text/on/accent"], [l["colors/accent/hover"]]);
|
|
1127
1149
|
l["border/error"] = readableFrom(l["colors/state/error"], red, [l["surface/card"]], awayFrom(l["surface/card"]), BLACK, NON_TEXT);
|
|
1128
|
-
l["chart/series/1"] = readableFrom(P.scale[600], P.scale, [l["surface/card"]], awayFrom(l["surface/card"]), BLACK, NON_TEXT);
|
|
1129
|
-
l["logo/primary"] = l["
|
|
1130
|
-
l["logo/signature"] = l["
|
|
1150
|
+
l["chart/series/1"] = readableFrom(P.scale[600], P.scale, [l["surface/card"], l["surface/page"]], awayFrom(l["surface/card"]), BLACK, NON_TEXT);
|
|
1151
|
+
l["logo/primary"] = readableFrom(P.base, P.scale, [l["surface/card"], l["surface/page"], l["surface/panel"]], "darker", BLACK, NON_TEXT);
|
|
1152
|
+
l["logo/signature"] = l["logo/primary"];
|
|
1131
1153
|
l["logo/accent"] = l["colors/accent/logo"];
|
|
1132
1154
|
l["logo/accent-2"] = l["colors/secondary/default"];
|
|
1133
1155
|
l["logo/accent-3"] = l["colors/accent/default"];
|
|
@@ -1176,7 +1198,6 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1176
1198
|
"text/on/action-tonal": readableFrom(P.scale[200], P.scale, [L[900]], "lighter", WHITE),
|
|
1177
1199
|
"surface/lift/action": P.scale[800],
|
|
1178
1200
|
"surface/lift/action-strong": P.scale[700],
|
|
1179
|
-
"colors/state/error-strong": red[400],
|
|
1180
1201
|
"colors/state/success-strong": green[300],
|
|
1181
1202
|
"colors/state/warning-strong": orange[400],
|
|
1182
1203
|
"surface/error": red[900],
|
|
@@ -1203,16 +1224,29 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1203
1224
|
"colors/state/neutral-strong": N[400],
|
|
1204
1225
|
"text/on/primary-subtle": black(30)
|
|
1205
1226
|
};
|
|
1227
|
+
if (single) {
|
|
1228
|
+
const steps = [200, 300, 100, 400];
|
|
1229
|
+
const s = (_b = steps.find((st) => distinct(N[st], d["colors/secondary/default"]))) != null ? _b : 200;
|
|
1230
|
+
d["colors/primary/default"] = N[s];
|
|
1231
|
+
d["colors/primary/dark"] = N[s === 100 ? 50 : s - 100];
|
|
1232
|
+
d["colors/primary/active"] = N[s + 100];
|
|
1233
|
+
d["colors/primary/light"] = N[s + 200];
|
|
1234
|
+
}
|
|
1235
|
+
d["surface/tint/default"] = readableFrom(d["surface/tint/default"], A.scale, [d["text/body"], d["text/muted"], d["colors/primary/default"]], "darker", N[900]);
|
|
1236
|
+
d["surface/tint/subtle"] = d["surface/tint/default"];
|
|
1237
|
+
d["colors/accent/highlight"] = readableFrom(d["colors/accent/highlight"], A.scale, [d["text/heading"]], "darker", N[900]);
|
|
1206
1238
|
for (const [fill, text] of [
|
|
1207
1239
|
["colors/primary/default", "text/on/primary"],
|
|
1208
1240
|
["colors/secondary/default", "text/on/secondary"],
|
|
1209
1241
|
["colors/accent/default", "text/on/accent"],
|
|
1210
1242
|
["colors/accent/mark", "text/on/accent-mark"],
|
|
1211
|
-
["colors/primary/
|
|
1243
|
+
["colors/primary/default", "text/on/primary-strong"],
|
|
1212
1244
|
["surface/tint/default", "text/on/tint"],
|
|
1213
1245
|
["surface/lift/action", "text/on/lift-action"]
|
|
1214
1246
|
]) d[text] = on(d[fill]);
|
|
1215
|
-
|
|
1247
|
+
for (const role of ["colors/primary/dark", "colors/primary/light"])
|
|
1248
|
+
d[role] = carry(K, d["colors/primary/default"], d["text/on/primary-strong"], d[role]);
|
|
1249
|
+
[d["colors/primary/active"]] = stateFills(K, d["colors/primary/default"], d["text/on/primary"], [d["colors/primary/active"]]);
|
|
1216
1250
|
[d["colors/secondary/hover"], d["colors/secondary/active"]] = stateFills(
|
|
1217
1251
|
S.scale,
|
|
1218
1252
|
d["colors/secondary/default"],
|
|
@@ -1220,16 +1254,25 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1220
1254
|
[d["colors/secondary/hover"], d["colors/secondary/active"]]
|
|
1221
1255
|
);
|
|
1222
1256
|
[d["colors/accent/hover"]] = stateFills(A.scale, d["colors/accent/default"], d["text/on/accent"], [d["colors/accent/hover"]]);
|
|
1223
|
-
d["border/error"] = readableFrom(
|
|
1257
|
+
d["border/error"] = readableFrom(red[400], red, [d["surface/card"]], awayFrom(d["surface/card"]), WHITE, NON_TEXT);
|
|
1224
1258
|
d["chart/series/1"] = readableFrom(P.scale[400], P.scale, [d["surface/card"]], awayFrom(d["surface/card"]), WHITE, NON_TEXT);
|
|
1225
|
-
const
|
|
1259
|
+
const ink0 = on(P.base);
|
|
1260
|
+
const plate = contrastRatio(ink0, P.base) >= PLATE_MIN ? P.base : readableFrom(P.base, P.scale, [ink0], ink0 === WHITE ? "darker" : "lighter", ink0 === WHITE ? BLACK : WHITE, PLATE_MIN);
|
|
1226
1261
|
const ink = on(plate);
|
|
1227
1262
|
const inkA = ink === WHITE ? white : black;
|
|
1228
1263
|
const antiInk = ink === WHITE ? black : white;
|
|
1229
1264
|
const lp = relativeLuminance(plate);
|
|
1230
1265
|
const isPlate = (c) => c.toLowerCase() === plate.toLowerCase();
|
|
1231
|
-
const plateCard = P.scale[800] && !isPlate(P.scale[800]) && contrastRatio(ink, P.scale[800]) >=
|
|
1232
|
-
const
|
|
1266
|
+
const plateCard = P.scale[800] && !isPlate(P.scale[800]) && contrastRatio(ink, P.scale[800]) >= PLATE_MIN ? P.scale[800] : (_c = SCALE_STEPS.map((st) => P.scale[st]).filter((c) => !!c && isHex(c) && !isPlate(c)).sort((a, b2) => Math.abs(relativeLuminance(a) - lp) - Math.abs(relativeLuminance(b2) - lp)).find((c) => contrastRatio(ink, c) >= PLATE_MIN)) != null ? _c : plate;
|
|
1267
|
+
const plateBgs = [plate, plateCard];
|
|
1268
|
+
const ov = plateBgs.every((bg) => contrastRatio(ink, over(inkA(20), bg)) >= AA) ? inkA : ink === WHITE ? black : white;
|
|
1269
|
+
const under = [...plateBgs, ...plateBgs.map((bg) => over(ov(10), bg))];
|
|
1270
|
+
const quiet = (pct, min = AA, bgs = under) => {
|
|
1271
|
+
for (let p = pct; p < 100; p += 5) if (bgs.every((bg) => contrastRatio(over(inkA(p), bg), bg) >= min)) return inkA(p);
|
|
1272
|
+
return ink;
|
|
1273
|
+
};
|
|
1274
|
+
const fieldBorder = quiet(60, NON_TEXT, plateBgs);
|
|
1275
|
+
const fieldAlpha = fieldBorder.length === 9 ? Math.round(parseInt(fieldBorder.slice(7), 16) / 255 * 100) : 100;
|
|
1233
1276
|
const br = {
|
|
1234
1277
|
"colors/primary/light": P.scale[300],
|
|
1235
1278
|
"colors/primary/default": ink,
|
|
@@ -1246,33 +1289,37 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1246
1289
|
"surface/card": plateCard,
|
|
1247
1290
|
"surface/panel": plate,
|
|
1248
1291
|
"border/default": inkA(20),
|
|
1249
|
-
"surface/tint/default":
|
|
1250
|
-
"surface/tint/strong":
|
|
1251
|
-
"surface/tint/subtle":
|
|
1292
|
+
"surface/tint/default": ov(10),
|
|
1293
|
+
"surface/tint/strong": ov(20),
|
|
1294
|
+
"surface/tint/subtle": ov(5),
|
|
1252
1295
|
"text/on/action-tonal": ink,
|
|
1253
1296
|
"text/on/primary": plate,
|
|
1254
1297
|
"text/on/secondary": plate,
|
|
1255
1298
|
"text/on/tint": ink,
|
|
1256
|
-
"surface/action/default":
|
|
1257
|
-
"surface/action/strong":
|
|
1299
|
+
"surface/action/default": ov(10),
|
|
1300
|
+
"surface/action/strong": ov(20),
|
|
1258
1301
|
"focus/ring": ink,
|
|
1259
1302
|
"focus/ring-inset": plate,
|
|
1260
1303
|
"surface/disabled": inkA(10),
|
|
1261
1304
|
"text/disabled": inkA(40),
|
|
1262
|
-
"text/muted":
|
|
1305
|
+
"text/muted": quiet(70),
|
|
1263
1306
|
"text/disabled-invert": antiInk(40),
|
|
1264
1307
|
"text/action": ink,
|
|
1265
|
-
"surface/lift/action":
|
|
1308
|
+
"surface/lift/action": ov(10),
|
|
1266
1309
|
"text/on/lift-action": ink,
|
|
1267
|
-
"surface/lift/action-strong":
|
|
1268
|
-
|
|
1269
|
-
"text/
|
|
1270
|
-
"
|
|
1271
|
-
"surface/muted
|
|
1272
|
-
"
|
|
1273
|
-
"border/strong
|
|
1310
|
+
"surface/lift/action-strong": ov(20),
|
|
1311
|
+
// The label of the neutral Button on the plate, whose fill is the ink: the plate colour.
|
|
1312
|
+
"text/on/primary-strong": plate,
|
|
1313
|
+
"text/subtle": quiet(60),
|
|
1314
|
+
"surface/muted": ov(10),
|
|
1315
|
+
"surface/muted-strong": ov(20),
|
|
1316
|
+
"border/strong": fieldBorder,
|
|
1317
|
+
"border/strong-hover": fieldAlpha + 20 < 100 ? inkA(fieldAlpha + 20) : ink,
|
|
1274
1318
|
"text/on/primary-subtle": inkA(30)
|
|
1275
1319
|
};
|
|
1320
|
+
for (const role of ["colors/primary/dark", "colors/primary/light"])
|
|
1321
|
+
br[role] = carry(P.scale, br["colors/primary/default"], br["text/on/primary-strong"], br[role]);
|
|
1322
|
+
br["colors/primary/dark"] = readableFrom(br["colors/primary/dark"], P.scale, [plateCard], awayFrom(plateCard), ink, NON_TEXT);
|
|
1276
1323
|
[br["colors/primary/active"]] = stateFills(P.scale, br["colors/primary/default"], br["text/on/primary"], [br["colors/primary/active"]]);
|
|
1277
1324
|
[br["colors/secondary/hover"], br["colors/secondary/active"]] = stateFills(
|
|
1278
1325
|
S.scale,
|
|
@@ -1280,11 +1327,24 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1280
1327
|
br["text/on/secondary"],
|
|
1281
1328
|
[br["colors/secondary/hover"], br["colors/secondary/active"]]
|
|
1282
1329
|
);
|
|
1283
|
-
const brandError = readableFrom(red[300], red,
|
|
1330
|
+
const brandError = readableFrom(red[300], red, plateBgs.slice().reverse(), awayFrom(plateCard), ink, NON_TEXT);
|
|
1331
|
+
const lightPlate = ink === BLACK;
|
|
1332
|
+
const plateOwn = {};
|
|
1333
|
+
for (const [st, rampOf] of [["error", red], ["success", green], ["info", L], ["warning", orange], ["neutral", N]]) {
|
|
1334
|
+
const from = lightPlate ? l : d;
|
|
1335
|
+
const soft = [`surface/${st}`, ...st === "error" ? ["surface/error-strong"] : []];
|
|
1336
|
+
for (const s of soft) plateOwn[s] = from[s];
|
|
1337
|
+
plateOwn[`text/${st}`] = readableFrom(from[`text/${st}`], rampOf, [...under, ...soft.map((s) => from[s])], awayFrom(plate), ink);
|
|
1338
|
+
}
|
|
1339
|
+
plateOwn["colors/accent/highlight"] = (_d = [d["colors/accent/highlight"], l["colors/accent/highlight"]].find((c) => contrastRatio(ink, c) >= AA)) != null ? _d : readableFrom(l["colors/accent/highlight"], A.scale, [ink], lightPlate ? "lighter" : "darker", ink === WHITE ? BLACK : WHITE);
|
|
1340
|
+
plateOwn["chart/series/1"] = readableFrom(d["chart/series/1"], P.scale, plateBgs, awayFrom(plate), ink, NON_TEXT);
|
|
1341
|
+
plateOwn["colors/state/neutral-strong"] = readableFrom(d["colors/state/neutral-strong"], N, plateBgs, awayFrom(plate), ink, NON_TEXT);
|
|
1342
|
+
for (const logo of ["logo/primary", "logo/signature", "logo/accent", "logo/mono", "social/ink"]) plateOwn[logo] = ink;
|
|
1343
|
+
const fixed = { "colors/state/error-strong": red[700] };
|
|
1284
1344
|
const out = { light: {}, dark: {}, brand: {} };
|
|
1285
1345
|
const pick = (src, role) => {
|
|
1286
1346
|
var _a2;
|
|
1287
|
-
const table = src === "l" ? l : src === "d" ? d : br;
|
|
1347
|
+
const table = src === "l" ? l : src === "d" ? d : src === "p" ? fixed : br;
|
|
1288
1348
|
const v = (_a2 = table[role]) != null ? _a2 : l[role];
|
|
1289
1349
|
if (v === void 0) throw new Error(`rdsTheme: no value for "${role}"`);
|
|
1290
1350
|
return v;
|
|
@@ -1295,6 +1355,7 @@ function generateRdsTheme(def, opts = {}) {
|
|
|
1295
1355
|
out.brand[roleVar(role)] = pick(brandSrc, role);
|
|
1296
1356
|
}
|
|
1297
1357
|
out.brand[roleVar("border/error")] = brandError;
|
|
1358
|
+
for (const [role, v] of Object.entries(plateOwn)) out.brand[roleVar(role)] = v;
|
|
1298
1359
|
assertSafeTheme(out, where);
|
|
1299
1360
|
return out;
|
|
1300
1361
|
}
|
|
@@ -1385,15 +1446,56 @@ var RDS_CONTRAST_PAIRS = [
|
|
|
1385
1446
|
["text/on/info", "colors/state/info"],
|
|
1386
1447
|
["text/on/warning", "colors/state/warning"],
|
|
1387
1448
|
["text/on/neutral", "colors/state/neutral"],
|
|
1388
|
-
["text/error", "surface/error"]
|
|
1449
|
+
["text/error", "surface/error"],
|
|
1450
|
+
// The pairs the components join (packages/ds, styles/rds/components.css): the label of the neutral Button and
|
|
1451
|
+
// Badge on its fill and hovers, the brand ink as text (colors/primary/default) on the card, the pressed outline Button,
|
|
1452
|
+
// the Badge highlight, the selected entry, quiet text and state text where they are placed.
|
|
1453
|
+
["text/on/primary-strong", "colors/primary/default"],
|
|
1454
|
+
["text/on/primary-strong", "colors/primary/light"],
|
|
1455
|
+
["text/on/primary-strong", "colors/primary/active"],
|
|
1456
|
+
["colors/primary/default", "surface/card"],
|
|
1457
|
+
["colors/primary/default", "surface/tint/default"],
|
|
1458
|
+
["text/heading", "surface/muted-strong"],
|
|
1459
|
+
["text/heading", "colors/accent/highlight"],
|
|
1460
|
+
["text/body", "surface/tint/default"],
|
|
1461
|
+
["text/muted", "surface/tint/default"],
|
|
1462
|
+
["text/on/tint", "surface/tint/subtle"],
|
|
1463
|
+
["text/action", "surface/action/strong"],
|
|
1464
|
+
["text/muted", "surface/page"],
|
|
1465
|
+
["text/muted", "surface/panel"],
|
|
1466
|
+
["text/subtle", "surface/card"],
|
|
1467
|
+
["text/subtle", "surface/panel"],
|
|
1468
|
+
["text/error", "surface/card"],
|
|
1469
|
+
["text/error", "surface/page"],
|
|
1470
|
+
["text/error", "surface/error-strong"],
|
|
1471
|
+
["text/success", "surface/success"],
|
|
1472
|
+
["text/success", "surface/card"],
|
|
1473
|
+
["text/info", "surface/info"],
|
|
1474
|
+
["text/warning", "surface/warning"],
|
|
1475
|
+
["text/neutral", "surface/neutral"]
|
|
1476
|
+
];
|
|
1477
|
+
var RDS_NON_TEXT_PAIRS = [
|
|
1478
|
+
["border/strong", "surface/card"],
|
|
1479
|
+
["border/strong", "surface/page"],
|
|
1480
|
+
["border/error", "surface/card"],
|
|
1481
|
+
["focus/ring", "surface/page"],
|
|
1482
|
+
["focus/ring", "surface/card"],
|
|
1483
|
+
["logo/primary", "surface/card"],
|
|
1484
|
+
["logo/primary", "surface/page"],
|
|
1485
|
+
["logo/primary", "surface/panel"],
|
|
1486
|
+
["chart/series/1", "surface/card"],
|
|
1487
|
+
["chart/series/1", "surface/page"],
|
|
1488
|
+
["colors/state/neutral-strong", "surface/panel"],
|
|
1489
|
+
["colors/state/neutral-strong", "surface/card"]
|
|
1389
1490
|
];
|
|
1390
1491
|
function rdsContrastReport(theme) {
|
|
1391
1492
|
const out = [];
|
|
1392
1493
|
for (const mode of ["light", "dark", "brand"])
|
|
1393
|
-
for (const [
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1494
|
+
for (const [pairs, min] of [[RDS_CONTRAST_PAIRS, AA], [RDS_NON_TEXT_PAIRS, NON_TEXT]])
|
|
1495
|
+
for (const [fg, bg] of pairs) {
|
|
1496
|
+
const ratio = rdsContrast(theme, mode, fg, bg);
|
|
1497
|
+
if (ratio !== null && ratio < min) out.push({ mode, fg, bg, ratio: Math.round(ratio * 100) / 100, min });
|
|
1498
|
+
}
|
|
1397
1499
|
return out;
|
|
1398
1500
|
}
|
|
1399
1501
|
var isColourRef = (v) => /^[a-z][a-z0-9-]*\/[a-z]?\d+$/i.test(v);
|
|
@@ -1470,8 +1572,8 @@ function rdsThemeFromTable(table, opts = {}) {
|
|
|
1470
1572
|
const fails = rdsContrastReport(out);
|
|
1471
1573
|
if (fails.length)
|
|
1472
1574
|
warn(
|
|
1473
|
-
`${where}: ${fails.length}
|
|
1474
|
-
` + fails.map((f) => `${f.mode}: ${f.fg} on ${f.bg} ${f.ratio}:1`).join("\n ")
|
|
1575
|
+
`${where}: ${fails.length} pair(s) below WCAG (4.5:1 text, 3:1 non-text)
|
|
1576
|
+
` + fails.map((f) => `${f.mode}: ${f.fg} on ${f.bg} ${f.ratio}:1 (min ${f.min}:1)`).join("\n ")
|
|
1475
1577
|
);
|
|
1476
1578
|
return out;
|
|
1477
1579
|
}
|
|
@@ -1553,10 +1655,10 @@ var CSS_FILE = /^[a-z0-9_@./-]+\.css$/i;
|
|
|
1553
1655
|
var CSS_URL = /^https?:\/\/[^\s"'`<>()\\]+$/i;
|
|
1554
1656
|
var INSTALL = /^(?:pnpm add|yarn add|bun add|npm install|npm i) @rojaostudio\/ds(?:@[a-z0-9][a-z0-9.+-]*)?$/;
|
|
1555
1657
|
var ROLE_DOCS = [
|
|
1556
|
-
{ role: "colors/primary/default", use: "
|
|
1557
|
-
{ role: "text/on/primary", use: "text/icon on the
|
|
1558
|
-
{ role: "colors/primary/active", use: "pressed
|
|
1559
|
-
{ role: "colors/secondary/default", use: "
|
|
1658
|
+
{ role: "colors/primary/default", use: "neutral ink fill: neutral Button and Badge, bars, Tooltip" },
|
|
1659
|
+
{ role: "text/on/primary", use: "text/icon on the neutral ink fill" },
|
|
1660
|
+
{ role: "colors/primary/active", use: "pressed neutral ink fill" },
|
|
1661
|
+
{ role: "colors/secondary/default", use: "action fill: the default Button, checkbox, switch (with `--text-on-secondary`)" },
|
|
1560
1662
|
{ role: "colors/accent/default", use: "highlight \u2014 sparingly (with `--text-on-accent`)" },
|
|
1561
1663
|
{ role: "surface/page", use: "page background" },
|
|
1562
1664
|
{ role: "surface/card", use: "cards" },
|
|
@@ -1665,7 +1767,7 @@ ${themeImport}
|
|
|
1665
1767
|
- ${opts.cssUrl ? `The theme is served from \`${opts.cssUrl}\`.` : `\`${cssFile}\` is the brand theme, generated \u2014 a file **you own**; commit it. Regenerate it
|
|
1666
1768
|
with \`npx rojao-ds init\` instead of editing it by hand.`}
|
|
1667
1769
|
- Dark mode: \`class="dark"\` on \`<html>\` (or any element). Light AND dark are first-class.
|
|
1668
|
-
- Brand plate: \`class="ds-plate"\` on a section paints it with the
|
|
1770
|
+
- Brand plate: \`class="ds-plate"\` on a section paints it with the brand color; the roles inside
|
|
1669
1771
|
flip so text and components stay legible.
|
|
1670
1772
|
|
|
1671
1773
|
## Components first
|
|
@@ -1700,7 +1802,7 @@ Brand's own variables (same value in every mode): ${own.map((v) => `\`${v}\``).j
|
|
|
1700
1802
|
- **Font:** \`font-family: var(${f.font})\` \u2014 never substitute.
|
|
1701
1803
|
|
|
1702
1804
|
## Rules (do / don't)
|
|
1703
|
-
- \u2705 Primary action = \`Button\` (
|
|
1805
|
+
- \u2705 Primary action = \`Button\` (tone action paints \`--colors-secondary-default\` + \`--text-on-secondary\`).
|
|
1704
1806
|
- \u2705 Page uses \`--surface-page\`; cards \`--surface-card\`; body text \`--text-body\`.
|
|
1705
1807
|
- \u2705 \`--colors-accent-default\` is the highlight \u2014 use it sparingly.
|
|
1706
1808
|
- \u2705 Spacing, radius and type come ONLY from the foundation tokens above.
|
|
@@ -1718,4 +1820,4 @@ Brand's own variables (same value in every mode): ${own.map((v) => `\`${v}\``).j
|
|
|
1718
1820
|
return text;
|
|
1719
1821
|
}
|
|
1720
1822
|
|
|
1721
|
-
export { RDS_CONTRAST_PAIRS, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, ROLES, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
|
|
1823
|
+
export { RDS_CONTRAST_PAIRS, RDS_NON_TEXT_PAIRS, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, ROLES, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
|
package/dist/generate.d.ts
CHANGED
|
@@ -14,9 +14,10 @@ type RdsThemeOptions = {
|
|
|
14
14
|
/**
|
|
15
15
|
* Roles of the [RDS] theme collection, in Figma order: [name, dark source, brand source].
|
|
16
16
|
* The light mode always reads the plain base token. In dark and brand, Figma points either to the
|
|
17
|
-
* mode's own variant (`d` = base dark/…, `b` = base brand/…) or back to another one (`l` = plain)
|
|
17
|
+
* mode's own variant (`d` = base dark/…, `b` = base brand/…) or back to another one (`l` = plain), or straight
|
|
18
|
+
* to a primitive of the [RDS] Primitives library (`p`: the same colour for every brand, see FIXED in the generator).
|
|
18
19
|
*/
|
|
19
|
-
declare const ROLES: ReadonlyArray<readonly [string, "l" | "d", "l" | "d" | "b"]>;
|
|
20
|
+
declare const ROLES: ReadonlyArray<readonly [string, "l" | "d" | "p", "l" | "d" | "b" | "p"]>;
|
|
20
21
|
/** CSS custom property of a role: the Figma path with hyphens (the [RDS] codeSyntax rule). */
|
|
21
22
|
declare const roleVar: (role: string) => string;
|
|
22
23
|
declare function generateRdsTheme(def: BrandDef, opts?: RdsThemeOptions): RdsTheme;
|
|
@@ -62,13 +63,23 @@ declare function rdsContrast(theme: RdsTheme, mode: RdsMode, fg: string, bg: str
|
|
|
62
63
|
* alpha colour is skipped (its contrast depends on what is below).
|
|
63
64
|
*/
|
|
64
65
|
declare const RDS_CONTRAST_PAIRS: ReadonlyArray<readonly [string, string]>;
|
|
66
|
+
/**
|
|
67
|
+
* What is not text but has to be seen (WCAG 1.4.11, 3:1): the border of a field and of a field in error, the focus
|
|
68
|
+
* ring, the brand's logo and its chart series, on the surfaces they are placed on.
|
|
69
|
+
*/
|
|
70
|
+
declare const RDS_NON_TEXT_PAIRS: ReadonlyArray<readonly [string, string]>;
|
|
71
|
+
/** A pair below its minimum: 4.5:1 for text (RDS_CONTRAST_PAIRS), 3:1 for the rest (RDS_NON_TEXT_PAIRS). */
|
|
65
72
|
type RdsContrastFailure = {
|
|
66
73
|
mode: RdsMode;
|
|
67
74
|
fg: string;
|
|
68
75
|
bg: string;
|
|
69
76
|
ratio: number;
|
|
77
|
+
min: number;
|
|
70
78
|
};
|
|
71
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* The pairs of RDS_CONTRAST_PAIRS below WCAG AA (4.5:1) and of RDS_NON_TEXT_PAIRS below 3:1, mode by mode. Empty
|
|
81
|
+
* means every pair passes. A pair with an alpha colour is skipped (rdsContrast).
|
|
82
|
+
*/
|
|
72
83
|
declare function rdsContrastReport(theme: RdsTheme): RdsContrastFailure[];
|
|
73
84
|
/**
|
|
74
85
|
* A brand as drawn in the [RDS] Base Tokens file: for each theme mode, every role points to a primitive of the
|
|
@@ -218,4 +229,4 @@ declare function isNeutralBrand(def: {
|
|
|
218
229
|
palettes?: PaletteDefs;
|
|
219
230
|
}): boolean;
|
|
220
231
|
|
|
221
|
-
export { BrandDef, type ClaudeMdOptions, type ClaudeMdTarget, RDS_CONTRAST_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, type RdsBrandTable, type RdsContrastFailure, type RdsCssOptions, type RdsMode, type RdsTheme, type RdsThemeOptions, RdsValidationError, SCALE_STEPS, type Scale, type ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
|
|
232
|
+
export { BrandDef, type ClaudeMdOptions, type ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_NON_TEXT_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, type RdsBrandTable, type RdsContrastFailure, type RdsCssOptions, type RdsMode, type RdsTheme, type RdsThemeOptions, RdsValidationError, SCALE_STEPS, type Scale, type ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
|
package/dist/generate.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { RDS_CONTRAST_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-
|
|
1
|
+
export { RDS_CONTRAST_PAIRS, RDS_NON_TEXT_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-NVYJME6V.js';
|
|
2
2
|
import './chunk-FRWRLCYM.js';
|
|
3
3
|
import './chunk-ORMEWXMH.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { G as GenResult, R as ResolvedTheme, T as TokenMap, g as generateTheme, r as resolveTheme } from './generateTheme-CUfNpsKs.js';
|
|
2
|
-
export { ClaudeMdOptions, ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsBrandTable, RdsContrastFailure, RdsCssOptions, RdsMode, RdsTheme, RdsThemeOptions, RdsValidationError, SCALE_STEPS, Scale, ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, roleVar } from './generate.js';
|
|
2
|
+
export { ClaudeMdOptions, ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_NON_TEXT_PAIRS, RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsBrandTable, RdsContrastFailure, RdsCssOptions, RdsMode, RdsTheme, RdsThemeOptions, RdsValidationError, SCALE_STEPS, Scale, ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, roleVar } from './generate.js';
|
|
3
3
|
export { A as Archetype, B as BrandColors, a as BrandDef, C as ColorRef, D as DarkStrategy, F as FontDef, P as PaletteRef, S as ScaleToken, T as TextStyle, b as TextStyleName, c as TypeScale } from './recipe.schema-Cq7e82nx.js';
|
|
4
4
|
export { primitives, tokens } from './tokens.js';
|
|
5
5
|
export { RecipeName, recipes } from './recipes.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { recipes } from './chunk-PV6GFEAM.js';
|
|
2
|
-
export { RDS_CONTRAST_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-
|
|
2
|
+
export { RDS_CONTRAST_PAIRS, RDS_NON_TEXT_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-NVYJME6V.js';
|
|
3
3
|
export { primitives, tokens } from './chunk-FRWRLCYM.js';
|
|
4
4
|
import './chunk-ORMEWXMH.js';
|
package/dist/themes.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rojaostudio/ds-core",
|
|
3
|
-
"version": "1.1.0-next.
|
|
3
|
+
"version": "1.1.0-next.12",
|
|
4
4
|
"description": "O motor do Rojão DS — tokens, derivação de tema e emissores. Sem React, sem Tailwind, sem CSS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Rojão Studio (https://rojao.studio)",
|