@trops/dash-core 0.1.574 → 0.1.575

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.
@@ -34,6 +34,7 @@ var require$$1$5 = require('http2');
34
34
  var require$$2$5 = require('node-forge');
35
35
  var require$$0$a = require('css');
36
36
  var require$$1$6 = require('node-vibrant/node');
37
+ var dashReact = require('@trops/dash-react');
37
38
  var require$$3$3 = require('ws');
38
39
 
39
40
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -51573,6 +51574,65 @@ var require$$8 = /*@__PURE__*/getAugmentedNamespace(colorUtils);
51573
51574
  * and color-harmony-based generation from a user-selected base color.
51574
51575
  */
51575
51576
 
51577
+ // Color harmony helpers — inlined so dash-core can ship the new
51578
+ // "From Colors" generator without first publishing matching
51579
+ // exports from @trops/dash-react. Same math as the planned dash-react
51580
+ // counterparts; can be replaced with a re-export once both ship in
51581
+ // the same cycle.
51582
+ function rotateHex(hex, deltaH) {
51583
+ const rgb = dashReact.hexToRgb(hex);
51584
+ if (!rgb) return null;
51585
+ const { h, s, l } = dashReact.rgbToHsl(rgb);
51586
+ const newH = (((h + deltaH) % 360) + 360) % 360;
51587
+ return dashReact.rgbToHex(dashReact.hslToRgb({ h: newH, s, l }));
51588
+ }
51589
+ function complementHex(hex) {
51590
+ return rotateHex(hex, 180);
51591
+ }
51592
+ function analogousHexes(hex) {
51593
+ const a = rotateHex(hex, -30);
51594
+ const b = rotateHex(hex, 30);
51595
+ return a && b ? [a, b] : null;
51596
+ }
51597
+ function triadicHexes(hex) {
51598
+ const a = rotateHex(hex, 120);
51599
+ const b = rotateHex(hex, 240);
51600
+ return a && b ? [a, b] : null;
51601
+ }
51602
+ function splitComplementaryHexes(hex) {
51603
+ const a = rotateHex(hex, 150);
51604
+ const b = rotateHex(hex, 210);
51605
+ return a && b ? [a, b] : null;
51606
+ }
51607
+ function tetradicHexes(hex) {
51608
+ const a = rotateHex(hex, 90);
51609
+ const b = rotateHex(hex, 180);
51610
+ const c = rotateHex(hex, 270);
51611
+ return a && b && c ? [a, b, c] : null;
51612
+ }
51613
+ function monochromaticHexes(hex, count = 3) {
51614
+ const rgb = dashReact.hexToRgb(hex);
51615
+ if (!rgb) return null;
51616
+ const { h, s } = dashReact.rgbToHsl(rgb);
51617
+ const out = [];
51618
+ for (let i = 0; i < count; i++) {
51619
+ const t = count === 1 ? 0.5 : i / (count - 1);
51620
+ const l = 0.15 + t * 0.7;
51621
+ const sAdj = s * (1 - 0.3 * Math.abs(t - 0.5) * 2);
51622
+ out.push(dashReact.rgbToHex(dashReact.hslToRgb({ h, s: sAdj, l })));
51623
+ }
51624
+ return out;
51625
+ }
51626
+ function adjustHsl(hex, dH = 0, dS = 0, dL = 0) {
51627
+ const rgb = dashReact.hexToRgb(hex);
51628
+ if (!rgb) return null;
51629
+ const hsl = dashReact.rgbToHsl(rgb);
51630
+ const h = (((hsl.h + dH) % 360) + 360) % 360;
51631
+ const s = Math.max(0, Math.min(1, hsl.s + dS));
51632
+ const l = Math.max(0, Math.min(1, hsl.l + dL));
51633
+ return dashReact.rgbToHex(dashReact.hslToRgb({ h, s, l }));
51634
+ }
51635
+
51576
51636
  // Color wheel mapping for Tailwind palettes (approximate hue angles)
51577
51637
  const COLOR_WHEEL = {
51578
51638
  red: 0,
@@ -51772,10 +51832,25 @@ function generateRandomTheme() {
51772
51832
 
51773
51833
  /**
51774
51834
  * Generate a theme using color harmony rules from a base color.
51775
- * @param {string} baseColor - A Tailwind color name (e.g. "blue")
51776
- * @param {"complementary"|"analogous"|"triadic"|"split-complementary"} strategy
51777
- */
51778
- function generateHarmonyTheme(baseColor, strategy = "complementary") {
51835
+ * Accepts either a Tailwind color name OR a hex string. Hex bases
51836
+ * run through dash-react's harmony math and emit hex channels for
51837
+ * every output; named bases use the legacy COLOR_WHEEL mapping.
51838
+ *
51839
+ * @param {string} baseColor - Tailwind color name (e.g. "blue") OR hex
51840
+ * @param {"complementary"|"analogous"|"triadic"|"split-complementary"|"tetradic"|"monochromatic"} strategy
51841
+ * @param {{ dH?: number, dS?: number, dL?: number }} [hslNudge] - optional
51842
+ * HSL offsets applied to every generated channel after the harmony
51843
+ * math. dH in degrees; dS/dL as fractions in [-1..1].
51844
+ */
51845
+ function generateHarmonyTheme(
51846
+ baseColor,
51847
+ strategy = "complementary",
51848
+ hslNudge = null,
51849
+ ) {
51850
+ if (typeof baseColor === "string" && dashReact.isHexColor(baseColor)) {
51851
+ return generateHexHarmonyTheme(baseColor, strategy, hslNudge);
51852
+ }
51853
+
51779
51854
  const baseHue = COLOR_WHEEL[baseColor];
51780
51855
  if (baseHue === undefined) {
51781
51856
  return generateRandomTheme();
@@ -51815,17 +51890,109 @@ function generateHarmonyTheme(baseColor, strategy = "complementary") {
51815
51890
  }
51816
51891
 
51817
51892
  /**
51818
- * Generate a theme from three independently chosen colors.
51819
- * @param {string} primary - A Tailwind color name
51820
- * @param {string} secondary - A Tailwind color name
51821
- * @param {string} tertiary - A Tailwind color name
51893
+ * Hex-mode harmony generation. Always emits hex channels; supports
51894
+ * all the named harmony strategies plus Monochromatic and Tetradic.
51895
+ * The neutral channel is derived from the base by desaturating
51896
+ * almost fully, keeping the same hue family for a cohesive feel.
51822
51897
  */
51823
- function generateCustomTheme(primary, secondary, tertiary) {
51824
- const neutral = pick(NEUTRAL_COLORS);
51898
+ function generateHexHarmonyTheme(baseHex, strategy, hslNudge) {
51899
+ const base = dashReact.normalizeHex(baseHex);
51900
+ if (!base) return generateRandomTheme();
51901
+
51902
+ let primary = base;
51903
+ let secondary;
51904
+ let tertiary;
51905
+ let neutral;
51906
+
51907
+ switch (strategy) {
51908
+ case "complementary": {
51909
+ secondary = complementHex(base);
51910
+ const ana = analogousHexes(base);
51911
+ tertiary = ana ? ana[1] : base;
51912
+ break;
51913
+ }
51914
+ case "analogous": {
51915
+ const ana = analogousHexes(base);
51916
+ if (ana) {
51917
+ secondary = ana[0];
51918
+ tertiary = ana[1];
51919
+ }
51920
+ break;
51921
+ }
51922
+ case "triadic": {
51923
+ const tri = triadicHexes(base);
51924
+ if (tri) {
51925
+ secondary = tri[0];
51926
+ tertiary = tri[1];
51927
+ }
51928
+ break;
51929
+ }
51930
+ case "split-complementary": {
51931
+ const split = splitComplementaryHexes(base);
51932
+ if (split) {
51933
+ secondary = split[0];
51934
+ tertiary = split[1];
51935
+ }
51936
+ break;
51937
+ }
51938
+ case "tetradic": {
51939
+ const tet = tetradicHexes(base);
51940
+ if (tet) {
51941
+ secondary = tet[0];
51942
+ tertiary = tet[1];
51943
+ neutral = tet[2];
51944
+ }
51945
+ break;
51946
+ }
51947
+ case "monochromatic": {
51948
+ const mono = monochromaticHexes(base, 3);
51949
+ if (mono) {
51950
+ primary = mono[1];
51951
+ secondary = mono[0];
51952
+ tertiary = mono[2];
51953
+ }
51954
+ break;
51955
+ }
51956
+ default: {
51957
+ secondary = complementHex(base);
51958
+ const ana = analogousHexes(base);
51959
+ tertiary = ana ? ana[1] : base;
51960
+ }
51961
+ }
51962
+
51963
+ // Neutral defaults to a near-grey of the same hue (desaturated).
51964
+ if (!neutral) {
51965
+ neutral = adjustHsl(base, 0, -0.85, 0);
51966
+ }
51967
+
51968
+ // Apply optional HSL nudge uniformly to all channels.
51969
+ if (hslNudge) {
51970
+ const { dH = 0, dS = 0, dL = 0 } = hslNudge;
51971
+ primary = adjustHsl(primary, dH, dS, dL) || primary;
51972
+ secondary = adjustHsl(secondary, dH, dS, dL) || secondary;
51973
+ tertiary = adjustHsl(tertiary, dH, dS, dL) || tertiary;
51974
+ neutral = adjustHsl(neutral, dH, dS, dL) || neutral;
51975
+ }
51976
+
51825
51977
  const name = generateThemeName$1(primary, secondary);
51826
51978
  return buildRawTheme(name, primary, secondary, tertiary, neutral);
51827
51979
  }
51828
51980
 
51981
+ /**
51982
+ * Generate a theme from four independently chosen channel values.
51983
+ * Each channel may be a Tailwind name or a hex string.
51984
+ */
51985
+ function generateCustomTheme(
51986
+ primary,
51987
+ secondary,
51988
+ tertiary,
51989
+ neutral = null,
51990
+ ) {
51991
+ const resolvedNeutral = neutral || pick(NEUTRAL_COLORS);
51992
+ const name = generateThemeName$1(primary, secondary);
51993
+ return buildRawTheme(name, primary, secondary, tertiary, resolvedNeutral);
51994
+ }
51995
+
51829
51996
  /**
51830
51997
  * All available chromatic colors for the "From Color" picker.
51831
51998
  */
@@ -51839,6 +52006,8 @@ const HARMONY_STRATEGIES = [
51839
52006
  { value: "analogous", label: "Analogous" },
51840
52007
  { value: "triadic", label: "Triadic" },
51841
52008
  { value: "split-complementary", label: "Split Complementary" },
52009
+ { value: "tetradic", label: "Tetradic" },
52010
+ { value: "monochromatic", label: "Monochromatic" },
51842
52011
  { value: "custom", label: "Custom" },
51843
52012
  ];
51844
52013