@rojaostudio/ds-core 1.1.0-next.14 → 1.1.0-next.16

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 CHANGED
@@ -44,7 +44,7 @@ Components, styles and the React Native target live in
44
44
 
45
45
  | Entry | What's in it |
46
46
  |---|---|
47
- | `@rojaostudio/ds-core/generate` | `generateRdsTheme`, `rdsThemeFromTable`, `emitRdsCss`, `emitClaudeMd`, `generateTheme`/`emitCss` (1.x), `buildScale`, `contrastRatio` |
47
+ | `@rojaostudio/ds-core/generate` | `generateRdsTheme`, `rdsThemeFromTable`, `emitRdsCss`, `emitClaudeMd`, `rdsBrandColors`, `deriveAccent`, `generateTheme`/`emitCss` (1.x), `buildScale`, `contrastRatio` |
48
48
  | `@rojaostudio/ds-core/tokens` | `primitives` — the raw palettes and scales |
49
49
  | `@rojaostudio/ds-core/recipes` | the reference brand definition |
50
50
  | `@rojaostudio/ds-core/themes` | the preset catalogue: a starting palette per niche |
@@ -753,6 +753,23 @@ function oneLine(v, max = 200) {
753
753
  return s;
754
754
  }
755
755
 
756
+ // generate/derive.ts
757
+ var RAD2 = Math.PI / 180;
758
+ var DEG2 = 180 / Math.PI;
759
+ var ACCENT_TURN = 150;
760
+ var ACCENT_L = 0.72;
761
+ var ACCENT_C_MIN = 0.14;
762
+ var ACCENT_C_MAX = 0.22;
763
+ var NEUTRAL_C = 0.04;
764
+ var NEUTRAL_ACCENT_HUE = 55;
765
+ function deriveAccent(primary) {
766
+ if (!isHex(primary)) throw new Error(`deriveAccent: ${JSON.stringify(String(primary).slice(0, 40))} is not a #rrggbb colour`);
767
+ const [, C, h] = hexToOklch(primary);
768
+ const hue = C < NEUTRAL_C ? NEUTRAL_ACCENT_HUE : ((h * DEG2 + ACCENT_TURN) % 360 + 360) % 360;
769
+ const chroma = Math.min(ACCENT_C_MAX, Math.max(ACCENT_C_MIN, C));
770
+ return oklchToHex(ACCENT_L, chroma, hue * RAD2).toLowerCase();
771
+ }
772
+
756
773
  // generate/rdsTheme.ts
757
774
  var palettes = primitives.color;
758
775
  var WHITE = "#ffffff";
@@ -999,10 +1016,12 @@ var ROLES = [
999
1016
  ["surface/inverse", "d", "d"],
1000
1017
  ["text/on-inverse", "d", "d"],
1001
1018
  ["text/on-inverse-subtle", "d", "d"],
1002
- ["text/on/success-strong", "d", "d"]
1019
+ ["text/on/success-strong", "d", "d"],
1020
+ ["text/selected", "d", "b"]
1003
1021
  ];
1004
1022
  var SUCCESS_STRONG_ON = { light: WHITE, dark: BLACK };
1005
1023
  var coal = palettes.coal;
1024
+ var selectedOn = (primary, scale, tints, fallback) => readableFrom(primary, scale, tints, awayFrom(tints[0]), fallback);
1006
1025
  var inverseOf = (primary) => contrastRatio(WHITE, primary) >= AA ? primary : coal[900];
1007
1026
  function inverseSubtle(fill) {
1008
1027
  for (let p = 70; p < 100; p += 5) if (contrastRatio(over(white(p), fill), fill) >= AA) return white(p);
@@ -1023,6 +1042,28 @@ var awayFrom = (bg) => contrastRatio(bg, BLACK) >= contrastRatio(bg, WHITE) ? "d
1023
1042
  var TINT_DEFAULT = 200;
1024
1043
  var lighterStep = (s) => s - 100 ;
1025
1044
  var roleVar = (role) => `--${role.replaceAll("/", "-")}`;
1045
+ function brandRamps(b, own) {
1046
+ const P = ramp(b.primary, own);
1047
+ const S = b.secondary ? ramp(b.secondary, own) : P;
1048
+ const A = b.accent ? ramp(b.accent, own) : ramp(deriveAccent(P.base.toLowerCase()));
1049
+ return { P, S, A };
1050
+ }
1051
+ function rdsBrandColors(def) {
1052
+ const where = `rdsBrandColors(${preview(def == null ? void 0 : def.name)})`;
1053
+ if (!(def == null ? void 0 : def.brand) || typeof def.brand !== "object") throw new Error(`${where}: brand is missing`);
1054
+ checkPalettes(def.palettes, where);
1055
+ const { P, S, A } = brandRamps(def.brand, def.palettes);
1056
+ const out = {
1057
+ primary: P.base.toLowerCase(),
1058
+ secondary: S.base.toLowerCase(),
1059
+ accent: A.base.toLowerCase(),
1060
+ source: { secondary: def.brand.secondary ? "recipe" : "primary", accent: def.brand.accent ? "recipe" : "derived" }
1061
+ };
1062
+ const c = collector(where);
1063
+ for (const k of ["primary", "secondary", "accent"]) c.color(k, out[k]);
1064
+ c.done();
1065
+ return out;
1066
+ }
1026
1067
  function generateRdsTheme(def, opts = {}) {
1027
1068
  var _a, _b, _c, _d;
1028
1069
  const warn = (_a = opts.warn) != null ? _a : defaultWarn;
@@ -1031,9 +1072,7 @@ function generateRdsTheme(def, opts = {}) {
1031
1072
  checkPalettes(def.palettes, where);
1032
1073
  const b = def.brand;
1033
1074
  const own = def.palettes;
1034
- const P = ramp(b.primary, own);
1035
- const S = b.secondary ? ramp(b.secondary, own) : P;
1036
- const A = b.accent ? ramp(b.accent, own) : P;
1075
+ const { P, S, A } = brandRamps(b, own);
1037
1076
  const N = def.text && ((own == null ? void 0 : own[def.text]) || palettes[def.text] && typeof palettes[def.text] !== "string") ? palette(def.text, own) : palette("zinc");
1038
1077
  const L = palette("blue");
1039
1078
  const red = palette("red"), green = palette("green"), orange = palette("orange");
@@ -1182,6 +1221,7 @@ function generateRdsTheme(def, opts = {}) {
1182
1221
  l["logo/accent"] = l["colors/accent/logo"];
1183
1222
  l["logo/accent-2"] = l["colors/secondary/default"];
1184
1223
  l["logo/accent-3"] = l["colors/accent/default"];
1224
+ l["text/selected"] = selectedOn(l["colors/primary/default"], K, [l["surface/tint/default"], l["surface/tint/subtle"]], BLACK);
1185
1225
  const d = __spreadProps(__spreadValues({
1186
1226
  "surface/page": N[900],
1187
1227
  "surface/panel": N[900],
@@ -1287,6 +1327,7 @@ function generateRdsTheme(def, opts = {}) {
1287
1327
  [d["colors/accent/hover"]] = stateFills(A.scale, d["colors/accent/default"], d["text/on/accent"], [d["colors/accent/hover"]]);
1288
1328
  d["border/error"] = readableFrom(red[400], red, [d["surface/card"]], awayFrom(d["surface/card"]), WHITE, NON_TEXT);
1289
1329
  d["chart/series/1"] = readableFrom(P.scale[400], P.scale, [d["surface/card"]], awayFrom(d["surface/card"]), WHITE, NON_TEXT);
1330
+ d["text/selected"] = selectedOn(d["colors/primary/default"], K, [d["surface/tint/default"], d["surface/tint/subtle"]], WHITE);
1290
1331
  const ink0 = on(P.base);
1291
1332
  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);
1292
1333
  const ink = on(plate);
@@ -1346,7 +1387,9 @@ function generateRdsTheme(def, opts = {}) {
1346
1387
  "surface/muted-strong": ov(20),
1347
1388
  "border/strong": fieldBorder,
1348
1389
  "border/strong-hover": fieldAlpha + 20 < 100 ? inkA(fieldAlpha + 20) : ink,
1349
- "text/on/primary-subtle": inkA(30)
1390
+ "text/on/primary-subtle": inkA(30),
1391
+ // The selected item on the plate: the ink, which the plate's overlays (ov) are drawn to carry at AA.
1392
+ "text/selected": ink
1350
1393
  };
1351
1394
  for (const role of ["colors/primary/dark", "colors/primary/light"])
1352
1395
  br[role] = carry(P.scale, br["colors/primary/default"], br["text/on/primary-strong"], br[role]);
@@ -1541,6 +1584,8 @@ var RDS_CONTRAST_PAIRS = [
1541
1584
  ["text/muted", "surface/tint/default"],
1542
1585
  ["text/on/tint", "surface/tint/subtle"],
1543
1586
  ["text/action", "surface/action/strong"],
1587
+ ["text/selected", "surface/tint/default"],
1588
+ ["text/selected", "surface/tint/subtle"],
1544
1589
  ["text/muted", "surface/page"],
1545
1590
  ["text/muted", "surface/panel"],
1546
1591
  ["text/subtle", "surface/card"],
@@ -1597,7 +1642,9 @@ function laterFallback(role, mode, primary) {
1597
1642
  var isColourRef = (v) => /^[a-z][a-z0-9-]*\/[a-z]?\d+$/i.test(v);
1598
1643
  var ADDED_ROLES = {
1599
1644
  // Figma: light → base colors/state/error, dark → base dark/colors/state/error-strong, brand → base dark/text/error.
1600
- "border/error": { light: "colors/state/error", dark: "colors/state/error-strong", brand: "text/error" }
1645
+ "border/error": { light: "colors/state/error", dark: "colors/state/error-strong", brand: "text/error" },
1646
+ // Figma: colors/primary/default of each mode (base colors/primary/default, dark/…, brand/…).
1647
+ "text/selected": { light: "colors/primary/default", dark: "colors/primary/default", brand: "colors/primary/default" }
1601
1648
  };
1602
1649
  function rdsThemeFromTable(table, opts = {}) {
1603
1650
  var _a, _b, _c;
@@ -1933,4 +1980,4 @@ Brand's own variables (same value in every mode): ${own.map((v) => `\`${v}\``).j
1933
1980
  return text;
1934
1981
  }
1935
1982
 
1936
- export { RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, 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, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
1983
+ export { RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, ROLES, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, deriveAccent, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsBrandColors, rdsContrast, rdsContrastReport, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar };
@@ -20,6 +20,26 @@ type RdsThemeOptions = {
20
20
  declare const ROLES: ReadonlyArray<readonly [string, "l" | "d" | "p", "l" | "d" | "b" | "p"]>;
21
21
  /** CSS custom property of a role: the Figma path with hyphens (the [RDS] codeSyntax rule). */
22
22
  declare const roleVar: (role: string) => string;
23
+ /** The brand colours a theme is drawn from, as #rrggbb, and where each came from (rdsBrandColors). */
24
+ type RdsBrandColors = {
25
+ primary: string;
26
+ secondary: string;
27
+ accent: string;
28
+ /**
29
+ * Where the secondary and the accent came from: the recipe, or, when it names none, the primary itself (the
30
+ * secondary) or a colour derived from the primary (the accent).
31
+ */
32
+ source: {
33
+ secondary: "recipe" | "primary";
34
+ accent: "recipe" | "derived";
35
+ };
36
+ };
37
+ /**
38
+ * The primary, secondary and accent generateRdsTheme draws the theme from: the recipe's own (palette refs resolved),
39
+ * or, where the recipe names none, the primary as secondary and the accent derived from it. For a generator to show
40
+ * them in its fields.
41
+ */
42
+ declare function rdsBrandColors(def: BrandDef): RdsBrandColors;
23
43
  declare function generateRdsTheme(def: BrandDef, opts?: RdsThemeOptions): RdsTheme;
24
44
  /**
25
45
  * The selectors on which @rojaostudio/ds redeclares its component tokens (styles/rds/components.css and
@@ -134,6 +154,9 @@ type RdsBrandTable = {
134
154
  */
135
155
  declare function rdsThemeFromTable(table: RdsBrandTable, opts?: RdsThemeOptions): RdsTheme;
136
156
 
157
+ /** The accent (highlight) of a primary hex (#rrggbb). See the rule above. */
158
+ declare function deriveAccent(primary: string): string;
159
+
137
160
  /**
138
161
  * validate.ts — what the emitters accept from the outside (a recipe, a brand table, a theme object).
139
162
  *
@@ -261,4 +284,4 @@ declare function isNeutralBrand(def: {
261
284
  palettes?: PaletteDefs;
262
285
  }): boolean;
263
286
 
264
- export { BrandDef, type ClaudeMdOptions, type ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, 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, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
287
+ export { BrandDef, type ClaudeMdOptions, type ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, type RdsBrandColors, type RdsBrandTable, type RdsContrastFailure, type RdsCssOptions, type RdsMode, type RdsTheme, type RdsThemeOptions, RdsValidationError, SCALE_STEPS, type Scale, type ScaleStep, brandTones, buildScale, contrastRatio, deriveAccent, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsBrandColors, rdsContrast, rdsContrastReport, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, roleVar };
package/dist/generate.js CHANGED
@@ -1,3 +1,3 @@
1
- export { RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, 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, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-QJN6R2DB.js';
1
+ export { RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, deriveAccent, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsBrandColors, rdsContrast, rdsContrastReport, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-EQWIHPLK.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_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, 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, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, roleVar } from './generate.js';
2
+ export { ClaudeMdOptions, ClaudeMdTarget, RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsBrandColors, RdsBrandTable, RdsContrastFailure, RdsCssOptions, RdsMode, RdsTheme, RdsThemeOptions, RdsValidationError, SCALE_STEPS, Scale, ScaleStep, brandTones, buildScale, contrastRatio, deriveAccent, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsBrandColors, rdsContrast, rdsContrastReport, rdsPrintMode, 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, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, 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, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-QJN6R2DB.js';
2
+ export { RDS_CONTRAST_PAIRS, RDS_MEDIA_TYPE, RDS_NON_TEXT_PAIRS, RDS_PRINT_ON_WHITE, RDS_PRINT_TRANSPARENT, RDS_PRINT_WHITE, ROLES as RDS_ROLES, RDS_SCOPE_SELECTORS, RDS_TOKEN_SCOPE, RdsValidationError, SCALE_STEPS, brandTones, buildScale, contrastRatio, deriveAccent, emitClaudeMd, emitCss, emitRdsCss, generateRdsTheme, generateTheme, hexToHsl, hslToHex, isHex, isNeutralBrand, isSafeColor, isSafeFont, isSafeVarName, onColor, rdsBrandColors, rdsContrast, rdsContrastReport, rdsPrintMode, rdsThemeFromTable, refToHex, relativeLuminance, resolveTheme, roleVar } from './chunk-EQWIHPLK.js';
3
3
  export { primitives, tokens } from './chunk-FRWRLCYM.js';
4
4
  import './chunk-ORMEWXMH.js';
package/dist/themes.js CHANGED
@@ -1,4 +1,4 @@
1
- import { generateTheme } from './chunk-QJN6R2DB.js';
1
+ import { generateTheme } from './chunk-EQWIHPLK.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.14",
3
+ "version": "1.1.0-next.16",
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)",