@rojaostudio/ds-core 1.1.0-next.5 → 1.1.0-next.7

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.
@@ -5,8 +5,7 @@ var rojao = {
5
5
  brand: {
6
6
  primary: "navy-900",
7
7
  secondary: "navy-900",
8
- accent: "flare-700",
9
- heading: "flare-700"
8
+ accent: "flare-700"
10
9
  },
11
10
  surface: "zinc",
12
11
  text: "zinc",
@@ -705,6 +705,26 @@ function ramp(c, custom) {
705
705
  return { base: hex, scale: buildScale(hex) };
706
706
  }
707
707
  var on = (bg) => onColor(bg);
708
+ var AA = 4.5;
709
+ var readsOn = (fg, bgs) => bgs.every((bg) => contrastRatio(fg, bg) >= AA);
710
+ function readableFrom(base, scale, bgs, toward, fallback) {
711
+ var _a;
712
+ if (readsOn(base, bgs)) return base;
713
+ const lb = relativeLuminance(base);
714
+ const steps = SCALE_STEPS.map((s2) => scale[s2]).filter((c) => !!c && isHex(c)).filter((c) => toward === "darker" ? relativeLuminance(c) < lb : relativeLuminance(c) > lb).sort((a, b) => Math.abs(relativeLuminance(a) - lb) - Math.abs(relativeLuminance(b) - lb));
715
+ const step2 = steps.find((c) => readsOn(c, bgs));
716
+ if (step2) return step2;
717
+ const [h, s, l0] = hexToHsl((_a = steps[steps.length - 1]) != null ? _a : base);
718
+ for (let l = l0; toward === "darker" ? l >= 0 : l <= 100; l += toward === "darker" ? -2 : 2) {
719
+ const c = hslToHex(h, s, l);
720
+ if (readsOn(c, bgs)) return c;
721
+ }
722
+ return fallback;
723
+ }
724
+ var defaultWarn = (m) => {
725
+ var _a;
726
+ return (_a = globalThis.console) == null ? void 0 : _a.warn(m);
727
+ };
708
728
  var ROLES = [
709
729
  ["colors/primary/light", "d", "b"],
710
730
  ["colors/primary/default", "d", "b"],
@@ -813,7 +833,9 @@ var ROLES = [
813
833
  var TINT_DEFAULT = 200;
814
834
  var lighterStep = (s) => s - 100 ;
815
835
  var roleVar = (role) => `--${role.replaceAll("/", "-")}`;
816
- function generateRdsTheme(def) {
836
+ function generateRdsTheme(def, opts = {}) {
837
+ var _a, _b;
838
+ const warn = (_a = opts.warn) != null ? _a : defaultWarn;
817
839
  const b = def.brand;
818
840
  const own = def.palettes;
819
841
  const P = ramp(b.primary, own);
@@ -823,7 +845,15 @@ function generateRdsTheme(def) {
823
845
  const L = palette("blue");
824
846
  const red = palette("red"), green = palette("green"), orange = palette("orange");
825
847
  const teal = palette("teal"), purple = palette("purple");
826
- const heading = b.heading ? ramp(b.heading, own).base : P.base;
848
+ const lightBgs = [WHITE, N[100]];
849
+ let heading;
850
+ if (b.heading) {
851
+ heading = ramp(b.heading, own).base;
852
+ if (!readsOn(heading, lightBgs)) {
853
+ const worst = Math.min(...lightBgs.map((bg) => contrastRatio(heading, bg)));
854
+ warn(`generateRdsTheme(${def.name}): heading ${heading} is ${worst.toFixed(2)}:1 on surface/card or surface/page (AA asks 4.5:1). Kept as given.`);
855
+ }
856
+ } else heading = readableFrom(P.base, P.scale, lightBgs, "darker", BLACK);
827
857
  const invert = b.invert ? ramp(b.invert, own).base : WHITE;
828
858
  const l = {
829
859
  "colors/primary/light": P.scale[500],
@@ -860,13 +890,12 @@ function generateRdsTheme(def) {
860
890
  "border/strong-hover": N[600],
861
891
  "surface/tint/default": A.scale[TINT_DEFAULT],
862
892
  "surface/tint/strong": A.scale[300],
863
- "text/on/tint": BLACK,
864
893
  // Light selection fill (pressed Toggle, choice tile): one step lighter than the default tint
865
894
  // (200 → 100, 100 → 50).
866
895
  "surface/tint/subtle": A.scale[lighterStep(TINT_DEFAULT)],
867
896
  "surface/action/default": L[100],
868
897
  "surface/action/strong": L[200],
869
- "text/on/action-tonal": P.scale[700],
898
+ "text/on/action-tonal": readableFrom(P.scale[700], P.scale, [L[100]], "darker", BLACK),
870
899
  "surface/lift/action": P.scale[50],
871
900
  "surface/lift/action-strong": L[100],
872
901
  "surface/band/action": L[100],
@@ -927,7 +956,8 @@ function generateRdsTheme(def) {
927
956
  ["colors/state/neutral", "text/on/neutral"],
928
957
  ["surface/cover", "text/on/cover"],
929
958
  ["surface/lift/action", "text/on/lift-action"],
930
- ["colors/primary/dark", "text/on/primary-strong"]
959
+ ["colors/primary/dark", "text/on/primary-strong"],
960
+ ["surface/tint/default", "text/on/tint"]
931
961
  ]) l[text] = on(l[fill]);
932
962
  l["logo/primary"] = l["colors/primary/default"];
933
963
  l["logo/signature"] = l["colors/primary/default"];
@@ -945,7 +975,7 @@ function generateRdsTheme(def) {
945
975
  "border/default": N[800],
946
976
  "border/strong": N[500],
947
977
  "border/strong-hover": N[400],
948
- "text/heading": N[50],
978
+ "text/heading": readableFrom(N[50], N, [N[900]], "lighter", WHITE),
949
979
  "text/body": N[100],
950
980
  "text/muted": N[300],
951
981
  "text/subtle": N[400],
@@ -972,15 +1002,13 @@ function generateRdsTheme(def) {
972
1002
  "colors/accent/mark": A.scale[300],
973
1003
  "surface/tint/default": A.scale[900],
974
1004
  "surface/tint/strong": A.scale[800],
975
- "text/on/tint": WHITE,
976
1005
  // No step below 900 in dark: subtle is the default tint.
977
1006
  "surface/tint/subtle": A.scale[900],
978
1007
  "surface/action/default": L[900],
979
1008
  "surface/action/strong": L[800],
980
- "text/on/action-tonal": P.scale[200],
1009
+ "text/on/action-tonal": readableFrom(P.scale[200], P.scale, [L[900]], "lighter", WHITE),
981
1010
  "surface/lift/action": P.scale[800],
982
1011
  "surface/lift/action-strong": P.scale[700],
983
- "text/on/lift-action": WHITE,
984
1012
  "colors/state/error-strong": red[400],
985
1013
  "colors/state/success-strong": green[300],
986
1014
  "colors/state/warning-strong": orange[400],
@@ -1014,12 +1042,17 @@ function generateRdsTheme(def) {
1014
1042
  ["colors/secondary/default", "text/on/secondary"],
1015
1043
  ["colors/accent/default", "text/on/accent"],
1016
1044
  ["colors/accent/mark", "text/on/accent-mark"],
1017
- ["colors/primary/dark", "text/on/primary-strong"]
1045
+ ["colors/primary/dark", "text/on/primary-strong"],
1046
+ ["surface/tint/default", "text/on/tint"],
1047
+ ["surface/lift/action", "text/on/lift-action"]
1018
1048
  ]) d[text] = on(d[fill]);
1019
1049
  const plate = l["colors/primary/default"];
1020
1050
  const ink = on(plate);
1021
1051
  const inkA = ink === WHITE ? white : black;
1022
1052
  const antiInk = ink === WHITE ? black : white;
1053
+ const lp = relativeLuminance(plate);
1054
+ const plateCard = (_b = SCALE_STEPS.map((st) => P.scale[st]).filter((c) => !!c && isHex(c) && c.toLowerCase() !== plate.toLowerCase()).sort((a, b2) => Math.abs(relativeLuminance(a) - lp) - Math.abs(relativeLuminance(b2) - lp)).find((c) => contrastRatio(ink, c) >= AA)) != null ? _b : plate;
1055
+ const onPrimaryStrong = contrastRatio(plate, P.scale[100]) >= AA ? plate : on(P.scale[100]);
1023
1056
  const br = {
1024
1057
  "colors/primary/light": P.scale[300],
1025
1058
  "colors/primary/default": ink,
@@ -1033,7 +1066,7 @@ function generateRdsTheme(def) {
1033
1066
  "text/body": ink,
1034
1067
  "text/link": contrastRatio(l["colors/accent/invert"], plate) >= 4.5 ? l["colors/accent/invert"] : ink,
1035
1068
  "surface/page": plate,
1036
- "surface/card": l["colors/primary/light"],
1069
+ "surface/card": plateCard,
1037
1070
  "surface/panel": plate,
1038
1071
  "border/default": inkA(20),
1039
1072
  "surface/tint/default": inkA(10),
@@ -1055,7 +1088,7 @@ function generateRdsTheme(def) {
1055
1088
  "surface/lift/action": inkA(10),
1056
1089
  "text/on/lift-action": ink,
1057
1090
  "surface/lift/action-strong": inkA(20),
1058
- "text/on/primary-strong": plate,
1091
+ "text/on/primary-strong": onPrimaryStrong,
1059
1092
  "text/subtle": inkA(60),
1060
1093
  "surface/muted": inkA(10),
1061
1094
  "surface/muted-strong": inkA(20),
@@ -1065,9 +1098,9 @@ function generateRdsTheme(def) {
1065
1098
  };
1066
1099
  const out = { light: {}, dark: {}, brand: {} };
1067
1100
  const pick = (src, role) => {
1068
- var _a;
1101
+ var _a2;
1069
1102
  const table = src === "l" ? l : src === "d" ? d : br;
1070
- const v = (_a = table[role]) != null ? _a : l[role];
1103
+ const v = (_a2 = table[role]) != null ? _a2 : l[role];
1071
1104
  if (v === void 0) throw new Error(`rdsTheme: no value for "${role}"`);
1072
1105
  return v;
1073
1106
  };
@@ -1078,23 +1111,55 @@ function generateRdsTheme(def) {
1078
1111
  }
1079
1112
  return out;
1080
1113
  }
1114
+ var RDS_SCOPE_SELECTORS = [
1115
+ ":root",
1116
+ ".ds-scope",
1117
+ "[data-rds-scope]",
1118
+ ".dark",
1119
+ "[data-rds-mode]",
1120
+ ".ds-plate",
1121
+ "[data-rds-plate]"
1122
+ ];
1123
+ var RDS_TOKEN_SCOPE = RDS_SCOPE_SELECTORS.join(", ");
1124
+ var split = (list) => list.split(",").map((s) => s.trim()).filter(Boolean);
1125
+ var rootAnchored = (sel) => /^(:root|html)(?![\w-])/i.test(sel);
1126
+ var subject = (sel) => {
1127
+ var _a;
1128
+ return (_a = sel.trim().split(/\s*[>+~]\s*|\s+/).pop()) != null ? _a : sel;
1129
+ };
1130
+ var COVERING = /\.(ds-scope|dark|ds-plate)(?![\w-])|\[\s*data-rds-(scope|mode|plate)\s*([~|^$*]?=[^\]]*)?\]/;
1131
+ var covered = (sel) => {
1132
+ const s = subject(sel);
1133
+ return /^(:root|html)(?![\w-])/i.test(s) || COVERING.test(s);
1134
+ };
1081
1135
  function emitRdsCss(theme, opts = {}) {
1082
1136
  var _a, _b, _c;
1083
- const scope = (_a = opts.scope) != null ? _a : ":root, .ds-scope";
1084
- const dark = (_b = opts.dark) != null ? _b : ".dark";
1085
- const plate = (_c = opts.plate) != null ? _c : ".ds-plate";
1086
- const block2 = (sel, map, only) => {
1137
+ const scopes = split((_a = opts.scope) != null ? _a : ":root, .ds-scope, [data-rds-scope]");
1138
+ const darks = split((_b = opts.dark) != null ? _b : '.dark, [data-rds-mode="dark"]');
1139
+ const plates = split((_c = opts.plate) != null ? _c : ".ds-plate, [data-rds-plate]");
1140
+ const block2 = (sels, map, only) => {
1087
1141
  const lines = Object.entries(map).filter(([k, v]) => !only || only[k] !== v).map(([k, v]) => ` ${k}: ${k === "--type-font-mono" ? `"${v}", monospace` : v};`);
1088
- return `${sel} {
1142
+ return `${sels.join(", ")} {
1089
1143
  ${lines.join("\n")}
1090
1144
  }`;
1091
1145
  };
1092
- const scopes = scope.split(",").map((s) => s.trim());
1093
- const darkSel = scopes.map((s) => s === ":root" ? `:root${dark}, ${dark}` : `${s}${dark}, ${dark} ${s}`).join(", ");
1146
+ const darkSels = scopes.flatMap(
1147
+ (s) => darks.flatMap((d) => {
1148
+ if (rootAnchored(d)) return s === ":root" ? [d] : [`${d} ${s}`];
1149
+ return s === ":root" ? [`:root${d}`, d] : [`${s}${d}`, `${d} ${s}`];
1150
+ })
1151
+ );
1152
+ if (!opts.allowUncovered) {
1153
+ const bad = [...new Set([...scopes, ...darkSels, ...plates].filter((sel) => !covered(sel)))];
1154
+ if (bad.length)
1155
+ throw new Error(
1156
+ `emitRdsCss: ${bad.map((b) => `"${b}"`).join(", ")} ${bad.length > 1 ? "are" : "is"} not covered by the component tokens of @rojaostudio/ds, redeclared only on ${RDS_TOKEN_SCOPE}. The components inside would keep the colours resolved at :root. Anchor the selector at the root (':root[data-theme="dark"]', as next-themes sets it on <html>), or add the attribute the tokens cover: data-rds-scope on a scope ('.my-scope[data-rds-scope]'), data-rds-mode on a dark element ('[data-rds-mode="dark"]'), data-rds-plate on a plate. Pass allowUncovered: true only for a theme without the components.`
1157
+ );
1158
+ }
1094
1159
  return [
1095
- block2(scope, __spreadValues(__spreadValues({}, theme.light), theme.vars)),
1096
- block2(darkSel, theme.dark, theme.light),
1097
- block2(plate, theme.brand, theme.light)
1160
+ block2(scopes, __spreadValues(__spreadValues({}, theme.light), theme.vars)),
1161
+ block2(darkSels, theme.dark, theme.light),
1162
+ block2(plates, theme.brand, theme.light)
1098
1163
  ].join("\n\n") + "\n";
1099
1164
  }
1100
1165
  function rdsContrast(theme, mode, fg, bg) {
@@ -1102,9 +1167,41 @@ function rdsContrast(theme, mode, fg, bg) {
1102
1167
  if (!/^#[0-9a-f]{6}$/i.test(a) || !/^#[0-9a-f]{6}$/i.test(c)) return null;
1103
1168
  return contrastRatio(a, c);
1104
1169
  }
1170
+ var RDS_CONTRAST_PAIRS = [
1171
+ ["text/heading", "surface/page"],
1172
+ ["text/heading", "surface/card"],
1173
+ ["text/body", "surface/page"],
1174
+ ["text/body", "surface/card"],
1175
+ ["text/muted", "surface/card"],
1176
+ ["text/link", "surface/card"],
1177
+ ["text/on/primary", "colors/primary/default"],
1178
+ ["text/on/secondary", "colors/secondary/default"],
1179
+ ["text/on/accent", "colors/accent/default"],
1180
+ ["text/on/accent-mark", "colors/accent/mark"],
1181
+ ["text/on/tint", "surface/tint/default"],
1182
+ ["text/on/action-tonal", "surface/action/default"],
1183
+ ["text/on/lift-action", "surface/lift/action"],
1184
+ ["text/on/primary-strong", "colors/primary/dark"],
1185
+ ["text/on/cover", "surface/cover"],
1186
+ ["text/on/error", "colors/state/error"],
1187
+ ["text/on/success", "colors/state/success"],
1188
+ ["text/on/info", "colors/state/info"],
1189
+ ["text/on/warning", "colors/state/warning"],
1190
+ ["text/on/neutral", "colors/state/neutral"],
1191
+ ["text/error", "surface/error"]
1192
+ ];
1193
+ function rdsContrastReport(theme) {
1194
+ const out = [];
1195
+ for (const mode of ["light", "dark", "brand"])
1196
+ for (const [fg, bg] of RDS_CONTRAST_PAIRS) {
1197
+ const ratio = rdsContrast(theme, mode, fg, bg);
1198
+ if (ratio !== null && ratio < AA) out.push({ mode, fg, bg, ratio: Math.round(ratio * 100) / 100 });
1199
+ }
1200
+ return out;
1201
+ }
1105
1202
  var isColourRef = (v) => /^[a-z][a-z0-9-]*\/[a-z]?\d+$/i.test(v);
1106
- function rdsThemeFromTable(table) {
1107
- var _a;
1203
+ function rdsThemeFromTable(table, opts = {}) {
1204
+ var _a, _b;
1108
1205
  const out = { light: {}, dark: {}, brand: {} };
1109
1206
  const problems = [];
1110
1207
  for (const mode of ["light", "dark", "brand"]) {
@@ -1138,6 +1235,12 @@ function rdsThemeFromTable(table) {
1138
1235
  }
1139
1236
  if (problems.length) throw new Error(`rdsThemeFromTable(${table.name}):
1140
1237
  ${problems.join("\n ")}`);
1238
+ const fails = rdsContrastReport(out);
1239
+ if (fails.length)
1240
+ ((_b = opts.warn) != null ? _b : defaultWarn)(
1241
+ `rdsThemeFromTable(${table.name}): ${fails.length} text pair(s) below 4.5:1
1242
+ ` + fails.map((f) => `${f.mode}: ${f.fg} on ${f.bg} ${f.ratio}:1`).join("\n ")
1243
+ );
1141
1244
  return out;
1142
1245
  }
1143
1246
 
@@ -1365,4 +1468,4 @@ Brand's own variables (same value in every mode): ${own.map((v) => `\`${v}\``).j
1365
1468
  `;
1366
1469
  }
1367
1470
 
1368
- export { ROLES, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
1471
+ export { RDS_CONTRAST_PAIRS, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, ROLES, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
@@ -7,6 +7,10 @@ type RdsTheme = Record<RdsMode, Record<string, string>> & {
7
7
  /** The brand's own variables (Figma `brand` collection, `<brand>/<name>`), one value for every mode. */
8
8
  vars?: Record<string, string>;
9
9
  };
10
+ type RdsThemeOptions = {
11
+ /** Where the warnings go (an explicit BrandDef.heading that fails AA). Default console.warn. */
12
+ warn?: (message: string) => void;
13
+ };
10
14
  /**
11
15
  * Roles of the [RDS] theme collection, in Figma order: [name, dark source, brand source].
12
16
  * The light mode always reads the plain base token. In dark and brand, Figma points either to the
@@ -15,22 +19,57 @@ type RdsTheme = Record<RdsMode, Record<string, string>> & {
15
19
  declare const ROLES: ReadonlyArray<readonly [string, "l" | "d", "l" | "d" | "b"]>;
16
20
  /** CSS custom property of a role: the Figma path with hyphens (the [RDS] codeSyntax rule). */
17
21
  declare const roleVar: (role: string) => string;
18
- declare function generateRdsTheme(def: BrandDef): RdsTheme;
22
+ declare function generateRdsTheme(def: BrandDef, opts?: RdsThemeOptions): RdsTheme;
23
+ /**
24
+ * The selectors on which @rojaostudio/ds redeclares its component tokens (styles/rds/components.css and
25
+ * foundation.css). A component token holds `var(--theme-role)`, and a custom property is resolved on the element
26
+ * where it is declared: a theme scope that none of these match would repaint the roles but not the components
27
+ * inside it, which keep the colours resolved at :root. The attributes are the generic way in: put
28
+ * `data-rds-scope` on a scope element, `data-rds-mode="dark"` on a dark one, `data-rds-plate` on a plate.
29
+ */
30
+ declare const RDS_SCOPE_SELECTORS: readonly [":root", ".ds-scope", "[data-rds-scope]", ".dark", "[data-rds-mode]", ".ds-plate", "[data-rds-plate]"];
31
+ /** RDS_SCOPE_SELECTORS as one selector list, as the component token layer is emitted. */
32
+ declare const RDS_TOKEN_SCOPE: string;
19
33
  type RdsCssOptions = {
20
- /** Scope of the light mode. Default `:root, .ds-scope`. */
34
+ /** Scope of the light mode. Default `:root, .ds-scope, [data-rds-scope]`. */
21
35
  scope?: string;
22
- /** Selector of the dark mode, combined with the scope. Default `.dark`. */
36
+ /**
37
+ * Selector of the dark mode, combined with each scope. Default `.dark, [data-rds-mode="dark"]`. A selector
38
+ * anchored at the root (`:root[data-theme="dark"]`, `html.dark`) is used as is: the theme switches on <html>,
39
+ * as next-themes does.
40
+ */
23
41
  dark?: string;
24
- /** Selector of the brand plate (a section painted with the primary). Default `.ds-plate`. */
42
+ /** Selector of the brand plate (a section painted with the primary). Default `.ds-plate, [data-rds-plate]`. */
25
43
  plate?: string;
44
+ /**
45
+ * Skip the check that every selector is covered by the component tokens of @rojaostudio/ds (RDS_SCOPE_SELECTORS).
46
+ * Only for a theme read by your own CSS, without the components.
47
+ */
48
+ allowUncovered?: boolean;
26
49
  };
27
50
  /**
28
51
  * The theme as CSS. Dark and plate only carry what differs from light: they inherit the rest
29
52
  * through the cascade, like the [RDS] modes that point back to the plain token.
53
+ *
54
+ * Throws when a selector would leave the components of @rojaostudio/ds on the root colours (see
55
+ * RDS_SCOPE_SELECTORS), unless `allowUncovered`.
30
56
  */
31
57
  declare function emitRdsCss(theme: RdsTheme, opts?: RdsCssOptions): string;
32
58
  /** Contrast of a role pair in one mode (alpha colours are not measured: they depend on what is below). */
33
59
  declare function rdsContrast(theme: RdsTheme, mode: RdsMode, fg: string, bg: string): number | null;
60
+ /**
61
+ * The main text pairs of the theme: [text role, the surface it sits on]. Measured in every mode; a pair with an
62
+ * alpha colour is skipped (its contrast depends on what is below).
63
+ */
64
+ declare const RDS_CONTRAST_PAIRS: ReadonlyArray<readonly [string, string]>;
65
+ type RdsContrastFailure = {
66
+ mode: RdsMode;
67
+ fg: string;
68
+ bg: string;
69
+ ratio: number;
70
+ };
71
+ /** The pairs of RDS_CONTRAST_PAIRS that fail WCAG AA (4.5:1), mode by mode. Empty means every pair passes. */
72
+ declare function rdsContrastReport(theme: RdsTheme): RdsContrastFailure[];
34
73
  /**
35
74
  * A brand as drawn in the [RDS] Base Tokens file: for each theme mode, every role points to a primitive of the
36
75
  * [RDS] Primitives library by name ("accyan/400"), and `primitives` holds the colour Figma resolves for each.
@@ -44,8 +83,12 @@ type RdsBrandTable = {
44
83
  /** The brand's own variables of the `brand` collection, by Figma path ("marca/ciano") → primitive or value. */
45
84
  vars?: Record<string, string>;
46
85
  };
47
- /** The theme of a brand table. Fails on a missing role or an unknown primitive, listing them all. */
48
- declare function rdsThemeFromTable(table: RdsBrandTable): RdsTheme;
86
+ /**
87
+ * The theme of a brand table. Fails on a missing role or an unknown primitive, listing them all. The contrast of
88
+ * the main text pairs (rdsContrastReport) is only reported, through `opts.warn`: the table is the brand as drawn
89
+ * in Figma, kept one to one even where a pair fails.
90
+ */
91
+ declare function rdsThemeFromTable(table: RdsBrandTable, opts?: RdsThemeOptions): RdsTheme;
49
92
 
50
93
  /**
51
94
  * emitCss.ts — formata o output do generateTheme num theme.css legível.
@@ -149,4 +192,4 @@ declare function isNeutralBrand(def: {
149
192
  palettes?: PaletteDefs;
150
193
  }): boolean;
151
194
 
152
- export { BrandDef, type ClaudeMdOptions, type ClaudeMdTarget, ROLES as RDS_ROLES, type RdsBrandTable, type RdsCssOptions, type RdsMode, type RdsTheme, SCALE_STEPS, type Scale, type ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
195
+ 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, SCALE_STEPS, type Scale, type ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
package/dist/generate.js CHANGED
@@ -1,3 +1,3 @@
1
- export { ROLES as RDS_ROLES, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-UD53AUQQ.js';
1
+ export { RDS_CONTRAST_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-Y25PXY26.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_ROLES, RdsBrandTable, RdsCssOptions, RdsMode, RdsTheme, SCALE_STEPS, Scale, ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsThemeFromTable, refToHex, relativeLuminance, roleVar } from './generate.js';
2
+ export { ClaudeMdOptions, ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsBrandTable, RdsContrastFailure, RdsCssOptions, RdsMode, RdsTheme, RdsThemeOptions, SCALE_STEPS, Scale, ScaleStep, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, 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
- export { recipes } from './chunk-3QTDO2HW.js';
2
- export { ROLES as RDS_ROLES, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-UD53AUQQ.js';
1
+ export { recipes } from './chunk-PV6GFEAM.js';
2
+ export { RDS_CONTRAST_PAIRS, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, SCALE_STEPS, brandTones, buildScale, contrastRatio, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, onColor, rdsContrast, rdsContrastReport, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-Y25PXY26.js';
3
3
  export { primitives, tokens } from './chunk-FRWRLCYM.js';
4
4
  import './chunk-ORMEWXMH.js';
package/dist/recipes.d.ts CHANGED
@@ -15,7 +15,11 @@ import { a as BrandDef } from './recipe.schema-Cq7e82nx.js';
15
15
  * ele não descreve marca de ninguém, descreve ponto de partida.
16
16
  */
17
17
 
18
- /** rojao — navy + flare accent on zinc, Inter. The `rojao` brand of the Figma [RDS] (2.0). */
18
+ /**
19
+ * rojao — navy + flare accent on zinc, Inter. The `rojao` brand of the Figma [RDS] (2.0).
20
+ * text/heading is the primary (navy) on light, as in the [RDS] base collection: the logo pairs are navy and
21
+ * orange, white and orange. The orange title is the Heading's tone=accent, not the default.
22
+ */
19
23
  declare const rojao: BrandDef;
20
24
  declare const recipes: {
21
25
  readonly rojao: BrandDef;
package/dist/recipes.js CHANGED
@@ -1,2 +1,2 @@
1
- export { recipes, rojao } from './chunk-3QTDO2HW.js';
1
+ export { recipes, rojao } from './chunk-PV6GFEAM.js';
2
2
  import './chunk-ORMEWXMH.js';
package/dist/themes.js CHANGED
@@ -1,4 +1,4 @@
1
- import { generateTheme } from './chunk-UD53AUQQ.js';
1
+ import { generateTheme } from './chunk-Y25PXY26.js';
2
2
  import './chunk-FRWRLCYM.js';
3
3
  import { __spreadValues, __objRest } from './chunk-ORMEWXMH.js';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rojaostudio/ds-core",
3
- "version": "1.1.0-next.5",
3
+ "version": "1.1.0-next.7",
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)",