@trops/dash-core 0.1.574 → 0.1.576

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/index.js CHANGED
@@ -34676,11 +34676,8 @@ var ThemePickerGridPane = function ThemePickerGridPane(_ref) {
34676
34676
  }
34677
34677
  return /*#__PURE__*/jsxRuntime.jsx(ThemePane, {
34678
34678
  children: /*#__PURE__*/jsxRuntime.jsx("div", {
34679
- className: "flex flex-row rounded overflow-clip justify-center items-center align-center w-full",
34680
- children: /*#__PURE__*/jsxRuntime.jsx("div", {
34681
- className: "grid grid-cols-3 gap-4 w-full h-full overflow-y-scroll scrollbar scrollbar-thumb-gray-700 scrollbar-thin scrollbar-track-transparent",
34682
- children: renderCurrentThemes()
34683
- })
34679
+ className: "grid grid-cols-3 gap-4 w-full flex-1 min-h-0 overflow-y-auto pr-2 scrollbar scrollbar-thumb-gray-700 scrollbar-thin scrollbar-track-transparent",
34680
+ children: renderCurrentThemes()
34684
34681
  })
34685
34682
  });
34686
34683
  };
@@ -36930,6 +36927,205 @@ var PanelThemeStudio = function PanelThemeStudio(_ref) {
36930
36927
  * Utility for generating themes via presets, random generation,
36931
36928
  * and color-harmony-based generation from a user-selected base color.
36932
36929
  */
36930
+ // All color math is inlined here (no @trops/dash-react import). This
36931
+ // file is reachable from Electron's main process via
36932
+ // `electron/controller/paletteToThemeMapper.js`. Importing dash-react
36933
+ // from a main-process reachable file pulls dash-react's renderer
36934
+ // bundle into the main bundle — that bundle has top-level browser
36935
+ // API access (`window.ResizeObserver` in CodeEditorVS) which throws
36936
+ // when required under Node. Keeping this module pure-JS / no-deps
36937
+ // breaks the chain.
36938
+
36939
+ var HEX_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
36940
+ function isHexColor(value) {
36941
+ return typeof value === "string" && HEX_RE.test(value.trim());
36942
+ }
36943
+ function normalizeHex(input) {
36944
+ if (typeof input !== "string") return null;
36945
+ var s = input.trim().toLowerCase();
36946
+ if (!s.startsWith("#")) s = "#".concat(s);
36947
+ if (!HEX_RE.test(s)) return null;
36948
+ if (s.length === 4) s = "#".concat(s[1]).concat(s[1]).concat(s[2]).concat(s[2]).concat(s[3]).concat(s[3]);else if (s.length === 5) s = "#".concat(s[1]).concat(s[1]).concat(s[2]).concat(s[2]).concat(s[3]).concat(s[3]);else if (s.length === 9) s = s.slice(0, 7);
36949
+ return s;
36950
+ }
36951
+ function hexToRgb(hex) {
36952
+ var n = normalizeHex(hex);
36953
+ if (!n) return null;
36954
+ var v = parseInt(n.slice(1), 16);
36955
+ return {
36956
+ r: v >> 16 & 0xff,
36957
+ g: v >> 8 & 0xff,
36958
+ b: v & 0xff
36959
+ };
36960
+ }
36961
+ function rgbToHex(_ref) {
36962
+ var r = _ref.r,
36963
+ g = _ref.g,
36964
+ b = _ref.b;
36965
+ var c = function c(x) {
36966
+ return Math.max(0, Math.min(255, Math.round(x)));
36967
+ };
36968
+ var h = function h(x) {
36969
+ return c(x).toString(16).padStart(2, "0");
36970
+ };
36971
+ return "#".concat(h(r)).concat(h(g)).concat(h(b));
36972
+ }
36973
+ function rgbToHsl(_ref2) {
36974
+ var r = _ref2.r,
36975
+ g = _ref2.g,
36976
+ b = _ref2.b;
36977
+ var R = r / 255,
36978
+ G = g / 255,
36979
+ B = b / 255;
36980
+ var max = Math.max(R, G, B),
36981
+ min = Math.min(R, G, B);
36982
+ var l = (max + min) / 2;
36983
+ var h = 0,
36984
+ s = 0;
36985
+ if (max !== min) {
36986
+ var d = max - min;
36987
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
36988
+ switch (max) {
36989
+ case R:
36990
+ h = (G - B) / d + (G < B ? 6 : 0);
36991
+ break;
36992
+ case G:
36993
+ h = (B - R) / d + 2;
36994
+ break;
36995
+ default:
36996
+ h = (R - G) / d + 4;
36997
+ }
36998
+ h *= 60;
36999
+ }
37000
+ return {
37001
+ h: h,
37002
+ s: s,
37003
+ l: l
37004
+ };
37005
+ }
37006
+ function hslToRgb(_ref3) {
37007
+ var h = _ref3.h,
37008
+ s = _ref3.s,
37009
+ l = _ref3.l;
37010
+ if (s === 0) {
37011
+ var v = l * 255;
37012
+ return {
37013
+ r: v,
37014
+ g: v,
37015
+ b: v
37016
+ };
37017
+ }
37018
+ var c = (1 - Math.abs(2 * l - 1)) * s;
37019
+ var x = c * (1 - Math.abs(h / 60 % 2 - 1));
37020
+ var m = l - c / 2;
37021
+ var rp, gp, bp;
37022
+ if (h < 60) {
37023
+ rp = c;
37024
+ gp = x;
37025
+ bp = 0;
37026
+ } else if (h < 120) {
37027
+ rp = x;
37028
+ gp = c;
37029
+ bp = 0;
37030
+ } else if (h < 180) {
37031
+ rp = 0;
37032
+ gp = c;
37033
+ bp = x;
37034
+ } else if (h < 240) {
37035
+ rp = 0;
37036
+ gp = x;
37037
+ bp = c;
37038
+ } else if (h < 300) {
37039
+ rp = x;
37040
+ gp = 0;
37041
+ bp = c;
37042
+ } else {
37043
+ rp = c;
37044
+ gp = 0;
37045
+ bp = x;
37046
+ }
37047
+ return {
37048
+ r: (rp + m) * 255,
37049
+ g: (gp + m) * 255,
37050
+ b: (bp + m) * 255
37051
+ };
37052
+ }
37053
+
37054
+ // Color harmony helpers — pure JS, no DOM/window access.
37055
+ function rotateHex(hex, deltaH) {
37056
+ var rgb = hexToRgb(hex);
37057
+ if (!rgb) return null;
37058
+ var _rgbToHsl = rgbToHsl(rgb),
37059
+ h = _rgbToHsl.h,
37060
+ s = _rgbToHsl.s,
37061
+ l = _rgbToHsl.l;
37062
+ var newH = ((h + deltaH) % 360 + 360) % 360;
37063
+ return rgbToHex(hslToRgb({
37064
+ h: newH,
37065
+ s: s,
37066
+ l: l
37067
+ }));
37068
+ }
37069
+ function complementHex(hex) {
37070
+ return rotateHex(hex, 180);
37071
+ }
37072
+ function analogousHexes(hex) {
37073
+ var a = rotateHex(hex, -30);
37074
+ var b = rotateHex(hex, 30);
37075
+ return a && b ? [a, b] : null;
37076
+ }
37077
+ function triadicHexes(hex) {
37078
+ var a = rotateHex(hex, 120);
37079
+ var b = rotateHex(hex, 240);
37080
+ return a && b ? [a, b] : null;
37081
+ }
37082
+ function splitComplementaryHexes(hex) {
37083
+ var a = rotateHex(hex, 150);
37084
+ var b = rotateHex(hex, 210);
37085
+ return a && b ? [a, b] : null;
37086
+ }
37087
+ function tetradicHexes(hex) {
37088
+ var a = rotateHex(hex, 90);
37089
+ var b = rotateHex(hex, 180);
37090
+ var c = rotateHex(hex, 270);
37091
+ return a && b && c ? [a, b, c] : null;
37092
+ }
37093
+ function monochromaticHexes(hex) {
37094
+ var count = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
37095
+ var rgb = hexToRgb(hex);
37096
+ if (!rgb) return null;
37097
+ var _rgbToHsl2 = rgbToHsl(rgb),
37098
+ h = _rgbToHsl2.h,
37099
+ s = _rgbToHsl2.s;
37100
+ var out = [];
37101
+ for (var i = 0; i < count; i++) {
37102
+ var t = count === 1 ? 0.5 : i / (count - 1);
37103
+ var l = 0.15 + t * 0.7;
37104
+ var sAdj = s * (1 - 0.3 * Math.abs(t - 0.5) * 2);
37105
+ out.push(rgbToHex(hslToRgb({
37106
+ h: h,
37107
+ s: sAdj,
37108
+ l: l
37109
+ })));
37110
+ }
37111
+ return out;
37112
+ }
37113
+ function adjustHsl(hex) {
37114
+ var dH = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
37115
+ var dS = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
37116
+ var dL = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
37117
+ var rgb = hexToRgb(hex);
37118
+ if (!rgb) return null;
37119
+ var hsl = rgbToHsl(rgb);
37120
+ var h = ((hsl.h + dH) % 360 + 360) % 360;
37121
+ var s = Math.max(0, Math.min(1, hsl.s + dS));
37122
+ var l = Math.max(0, Math.min(1, hsl.l + dL));
37123
+ return rgbToHex(hslToRgb({
37124
+ h: h,
37125
+ s: s,
37126
+ l: l
37127
+ }));
37128
+ }
36933
37129
 
36934
37130
  // Color wheel mapping for Tailwind palettes (approximate hue angles)
36935
37131
  var COLOR_WHEEL = {
@@ -37097,11 +37293,22 @@ function generateRandomTheme() {
37097
37293
 
37098
37294
  /**
37099
37295
  * Generate a theme using color harmony rules from a base color.
37100
- * @param {string} baseColor - A Tailwind color name (e.g. "blue")
37101
- * @param {"complementary"|"analogous"|"triadic"|"split-complementary"} strategy
37296
+ * Accepts either a Tailwind color name OR a hex string. Hex bases
37297
+ * run through dash-react's harmony math and emit hex channels for
37298
+ * every output; named bases use the legacy COLOR_WHEEL mapping.
37299
+ *
37300
+ * @param {string} baseColor - Tailwind color name (e.g. "blue") OR hex
37301
+ * @param {"complementary"|"analogous"|"triadic"|"split-complementary"|"tetradic"|"monochromatic"} strategy
37302
+ * @param {{ dH?: number, dS?: number, dL?: number }} [hslNudge] - optional
37303
+ * HSL offsets applied to every generated channel after the harmony
37304
+ * math. dH in degrees; dS/dL as fractions in [-1..1].
37102
37305
  */
37103
37306
  function generateHarmonyTheme(baseColor) {
37104
37307
  var strategy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "complementary";
37308
+ var hslNudge = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
37309
+ if (typeof baseColor === "string" && isHexColor(baseColor)) {
37310
+ return generateHexHarmonyTheme(baseColor, strategy, hslNudge);
37311
+ }
37105
37312
  var baseHue = COLOR_WHEEL[baseColor];
37106
37313
  if (baseHue === undefined) {
37107
37314
  return generateRandomTheme();
@@ -37137,17 +37344,114 @@ function generateHarmonyTheme(baseColor) {
37137
37344
  }
37138
37345
 
37139
37346
  /**
37140
- * Generate a theme from three independently chosen colors.
37141
- * @param {string} primary - A Tailwind color name
37142
- * @param {string} secondary - A Tailwind color name
37143
- * @param {string} tertiary - A Tailwind color name
37347
+ * Hex-mode harmony generation. Always emits hex channels; supports
37348
+ * all the named harmony strategies plus Monochromatic and Tetradic.
37349
+ * The neutral channel is derived from the base by desaturating
37350
+ * almost fully, keeping the same hue family for a cohesive feel.
37144
37351
  */
37145
- function generateCustomTheme(primary, secondary, tertiary) {
37146
- var neutral = pick(NEUTRAL_COLORS);
37352
+ function generateHexHarmonyTheme(baseHex, strategy, hslNudge) {
37353
+ var base = normalizeHex(baseHex);
37354
+ if (!base) return generateRandomTheme();
37355
+ var primary = base;
37356
+ var secondary;
37357
+ var tertiary;
37358
+ var neutral;
37359
+ switch (strategy) {
37360
+ case "complementary":
37361
+ {
37362
+ secondary = complementHex(base);
37363
+ var ana = analogousHexes(base);
37364
+ tertiary = ana ? ana[1] : base;
37365
+ break;
37366
+ }
37367
+ case "analogous":
37368
+ {
37369
+ var _ana = analogousHexes(base);
37370
+ if (_ana) {
37371
+ secondary = _ana[0];
37372
+ tertiary = _ana[1];
37373
+ }
37374
+ break;
37375
+ }
37376
+ case "triadic":
37377
+ {
37378
+ var tri = triadicHexes(base);
37379
+ if (tri) {
37380
+ secondary = tri[0];
37381
+ tertiary = tri[1];
37382
+ }
37383
+ break;
37384
+ }
37385
+ case "split-complementary":
37386
+ {
37387
+ var split = splitComplementaryHexes(base);
37388
+ if (split) {
37389
+ secondary = split[0];
37390
+ tertiary = split[1];
37391
+ }
37392
+ break;
37393
+ }
37394
+ case "tetradic":
37395
+ {
37396
+ var tet = tetradicHexes(base);
37397
+ if (tet) {
37398
+ secondary = tet[0];
37399
+ tertiary = tet[1];
37400
+ neutral = tet[2];
37401
+ }
37402
+ break;
37403
+ }
37404
+ case "monochromatic":
37405
+ {
37406
+ var mono = monochromaticHexes(base, 3);
37407
+ if (mono) {
37408
+ primary = mono[1];
37409
+ secondary = mono[0];
37410
+ tertiary = mono[2];
37411
+ }
37412
+ break;
37413
+ }
37414
+ default:
37415
+ {
37416
+ secondary = complementHex(base);
37417
+ var _ana2 = analogousHexes(base);
37418
+ tertiary = _ana2 ? _ana2[1] : base;
37419
+ }
37420
+ }
37421
+
37422
+ // Neutral defaults to a near-grey of the same hue (desaturated).
37423
+ if (!neutral) {
37424
+ neutral = adjustHsl(base, 0, -0.85, 0);
37425
+ }
37426
+
37427
+ // Apply optional HSL nudge uniformly to all channels.
37428
+ if (hslNudge) {
37429
+ var _hslNudge$dH = hslNudge.dH,
37430
+ dH = _hslNudge$dH === void 0 ? 0 : _hslNudge$dH,
37431
+ _hslNudge$dS = hslNudge.dS,
37432
+ dS = _hslNudge$dS === void 0 ? 0 : _hslNudge$dS,
37433
+ _hslNudge$dL = hslNudge.dL,
37434
+ dL = _hslNudge$dL === void 0 ? 0 : _hslNudge$dL;
37435
+ primary = adjustHsl(primary, dH, dS, dL) || primary;
37436
+ secondary = adjustHsl(secondary, dH, dS, dL) || secondary;
37437
+ tertiary = adjustHsl(tertiary, dH, dS, dL) || tertiary;
37438
+ neutral = adjustHsl(neutral, dH, dS, dL) || neutral;
37439
+ }
37147
37440
  var name = generateThemeName(primary, secondary);
37148
37441
  return buildRawTheme(name, primary, secondary, tertiary, neutral);
37149
37442
  }
37150
37443
 
37444
+ /**
37445
+ * Generate a theme from four independently chosen channel values.
37446
+ * Each channel may be a Tailwind name or a hex string.
37447
+ */
37448
+ function generateCustomTheme(primary, secondary, tertiary) {
37449
+ var neutral = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
37450
+ var resolvedNeutral = neutral || pick(NEUTRAL_COLORS);
37451
+ var name = generateThemeName(primary, secondary);
37452
+ return buildRawTheme(name, primary, secondary, tertiary, resolvedNeutral);
37453
+ }
37454
+
37151
37455
  /**
37152
37456
  * All available chromatic colors for the "From Color" picker.
37153
37457
  */
@@ -37168,6 +37472,12 @@ var HARMONY_STRATEGIES = [{
37168
37472
  }, {
37169
37473
  value: "split-complementary",
37170
37474
  label: "Split Complementary"
37475
+ }, {
37476
+ value: "tetradic",
37477
+ label: "Tetradic"
37478
+ }, {
37479
+ value: "monochromatic",
37480
+ label: "Monochromatic"
37171
37481
  }, {
37172
37482
  value: "custom",
37173
37483
  label: "Custom"
@@ -37266,87 +37576,165 @@ var PresetGallery = function PresetGallery(_ref3) {
37266
37576
 
37267
37577
  // ─── Color Harmony Picker ────────────────────────────────────────────────
37268
37578
 
37269
- var ColorSwatchGrid$1 = function ColorSwatchGrid(_ref4) {
37579
+ /**
37580
+ * Render a swatch for a generated palette channel. Hex values render
37581
+ * inline; named Tailwind families fall back to `bg-{name}-500` which
37582
+ * is in the safelist.
37583
+ */
37584
+ var PaletteSwatch = function PaletteSwatch(_ref4) {
37270
37585
  var value = _ref4.value,
37271
- onChange = _ref4.onChange,
37272
37586
  label = _ref4.label;
37587
+ var isHex = DashReact.isHexColor(value);
37273
37588
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
37274
- className: "flex flex-col gap-2",
37275
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37276
- className: "text-xs opacity-50",
37589
+ className: "flex flex-col items-center gap-1 flex-1",
37590
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37591
+ className: "h-10 w-full rounded ".concat(isHex ? "" : "bg-".concat(value, "-500")),
37592
+ style: isHex ? {
37593
+ backgroundColor: value
37594
+ } : undefined
37595
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
37596
+ className: "text-xs opacity-60 truncate w-full text-center",
37277
37597
  children: label
37598
+ })]
37599
+ });
37600
+ };
37601
+
37602
+ /**
37603
+ * Compact hex picker reused inline by the wizard. Category chips +
37604
+ * a curated grid of swatches + a custom-hex input below. Same
37605
+ * primitives as ChannelEditorModal but laid out for a narrower
37606
+ * column.
37607
+ */
37608
+ var InlineHexPicker = function InlineHexPicker(_ref5) {
37609
+ var selectedHex = _ref5.selectedHex,
37610
+ onPick = _ref5.onPick;
37611
+ var families = DashReact.getColorFamilies();
37612
+ var _useState = React.useState(families[0]),
37613
+ _useState2 = _slicedToArray(_useState, 2),
37614
+ activeFamily = _useState2[0],
37615
+ setActiveFamily = _useState2[1];
37616
+ var swatches = DashReact.getCuratedColorGrid(activeFamily);
37617
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37618
+ className: "flex flex-col gap-2",
37619
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37620
+ className: "flex flex-row gap-2 flex-wrap",
37621
+ children: families.map(function (family) {
37622
+ var isActive = activeFamily === family;
37623
+ return /*#__PURE__*/jsxRuntime.jsx("button", {
37624
+ type: "button",
37625
+ onClick: function onClick() {
37626
+ return setActiveFamily(family);
37627
+ },
37628
+ className: "px-2 py-0.5 rounded-full text-xs font-medium ".concat(isActive ? "bg-blue-600 text-white" : "bg-gray-700 text-gray-300 hover:bg-gray-600"),
37629
+ children: family
37630
+ }, family);
37631
+ })
37278
37632
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
37279
- className: "grid grid-cols-6 gap-2",
37280
- children: AVAILABLE_COLORS.map(function (color) {
37281
- return /*#__PURE__*/jsxRuntime.jsx("div", {
37282
- className: "h-8 rounded cursor-pointer transition-all bg-".concat(color, "-500 ").concat(value === color ? "ring-2 ring-white scale-110" : "opacity-70 hover:opacity-100"),
37283
- title: color,
37633
+ className: "grid grid-cols-12 gap-1",
37634
+ children: swatches.map(function (hex) {
37635
+ var isSelected = selectedHex && hex.toLowerCase() === selectedHex.toLowerCase();
37636
+ return /*#__PURE__*/jsxRuntime.jsx("button", {
37637
+ type: "button",
37284
37638
  onClick: function onClick() {
37285
- return onChange(color);
37286
- }
37287
- }, color);
37639
+ return onPick(hex);
37640
+ },
37641
+ style: {
37642
+ backgroundColor: hex
37643
+ },
37644
+ className: "h-6 rounded transition-transform hover:scale-110 ".concat(isSelected ? "border-2 border-yellow-400 scale-110" : ""),
37645
+ "aria-label": "Pick ".concat(hex),
37646
+ title: hex
37647
+ }, hex);
37288
37648
  })
37649
+ }), /*#__PURE__*/jsxRuntime.jsx(CustomHexColorPane, {
37650
+ onApply: onPick,
37651
+ label: "Or paste a hex value"
37289
37652
  })]
37290
37653
  });
37291
37654
  };
37292
- var PreviewSwatch = function PreviewSwatch(_ref5) {
37293
- var color = _ref5.color,
37294
- strategy = _ref5.strategy,
37295
- customColors = _ref5.customColors;
37296
- var colors;
37297
- if (strategy === "custom" && customColors) {
37298
- colors = [customColors.primary, customColors.secondary, customColors.tertiary];
37299
- } else {
37300
- var theme = generateHarmonyTheme(color, strategy);
37301
- colors = [theme.primary, theme.secondary, theme.tertiary];
37302
- }
37303
- return /*#__PURE__*/jsxRuntime.jsx("div", {
37304
- className: "flex flex-row gap-2",
37305
- children: colors.map(function (c, i) {
37306
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
37307
- className: "flex flex-col items-center gap-1 flex-1",
37308
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
37309
- className: "h-10 w-full rounded bg-".concat(c, "-500")
37310
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
37311
- className: "text-[10px] opacity-40",
37312
- children: c
37313
- })]
37314
- }, i);
37315
- })
37655
+
37656
+ /**
37657
+ * HSL nudge slider — single-axis. Display label + numeric value.
37658
+ */
37659
+ var HslSlider = function HslSlider(_ref6) {
37660
+ var label = _ref6.label,
37661
+ value = _ref6.value,
37662
+ min = _ref6.min,
37663
+ max = _ref6.max,
37664
+ step = _ref6.step,
37665
+ _onChange = _ref6.onChange,
37666
+ _ref6$unit = _ref6.unit,
37667
+ unit = _ref6$unit === void 0 ? "" : _ref6$unit;
37668
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
37669
+ className: "flex flex-col gap-1",
37670
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
37671
+ className: "flex flex-row items-center justify-between",
37672
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37673
+ className: "text-xs opacity-60",
37674
+ children: label
37675
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
37676
+ className: "text-xs opacity-50 font-mono",
37677
+ children: [value > 0 ? "+".concat(value) : value, unit]
37678
+ })]
37679
+ }), /*#__PURE__*/jsxRuntime.jsx("input", {
37680
+ type: "range",
37681
+ min: min,
37682
+ max: max,
37683
+ step: step,
37684
+ value: value,
37685
+ onChange: function onChange(e) {
37686
+ return _onChange(parseFloat(e.target.value));
37687
+ },
37688
+ className: "w-full accent-blue-500"
37689
+ })]
37316
37690
  });
37317
37691
  };
37318
- var ColorHarmonyPicker = function ColorHarmonyPicker(_ref6) {
37319
- var onGenerate = _ref6.onGenerate,
37320
- _ref6$inline = _ref6.inline,
37321
- inline = _ref6$inline === void 0 ? false : _ref6$inline;
37322
- var _useState = React.useState("blue"),
37323
- _useState2 = _slicedToArray(_useState, 2),
37324
- selectedColor = _useState2[0],
37325
- setSelectedColor = _useState2[1];
37326
- var _useState3 = React.useState("rose"),
37692
+ var ColorHarmonyPicker = function ColorHarmonyPicker(_ref7) {
37693
+ var onGenerate = _ref7.onGenerate,
37694
+ _ref7$inline = _ref7.inline,
37695
+ inline = _ref7$inline === void 0 ? false : _ref7$inline;
37696
+ // Default to a brand-blue hex so the wizard opens in hex mode.
37697
+ var _useState3 = React.useState("#3b82f6"),
37327
37698
  _useState4 = _slicedToArray(_useState3, 2),
37328
- secondaryColor = _useState4[0],
37329
- setSecondaryColor = _useState4[1];
37330
- var _useState5 = React.useState("amber"),
37699
+ selectedColor = _useState4[0],
37700
+ setSelectedColor = _useState4[1];
37701
+ var _useState5 = React.useState("complementary"),
37331
37702
  _useState6 = _slicedToArray(_useState5, 2),
37332
- tertiaryColor = _useState6[0],
37333
- setTertiaryColor = _useState6[1];
37334
- var _useState7 = React.useState("complementary"),
37703
+ strategy = _useState6[0],
37704
+ setStrategy = _useState6[1];
37705
+ // HSL nudge — applied to every generated channel after harmony math.
37706
+ var _useState7 = React.useState(0),
37335
37707
  _useState8 = _slicedToArray(_useState7, 2),
37336
- strategy = _useState8[0],
37337
- setStrategy = _useState8[1];
37338
- var isCustom = strategy === "custom";
37708
+ dH = _useState8[0],
37709
+ setDH = _useState8[1];
37710
+ var _useState9 = React.useState(0),
37711
+ _useState0 = _slicedToArray(_useState9, 2),
37712
+ dS = _useState0[0],
37713
+ setDS = _useState0[1];
37714
+ var _useState1 = React.useState(0),
37715
+ _useState10 = _slicedToArray(_useState1, 2),
37716
+ dL = _useState10[0],
37717
+ setDL = _useState10[1];
37718
+
37719
+ // Generate the current theme from inputs. Memoized through useEffect
37720
+ // for the inline-preview path; explicit handler for the button path.
37721
+ function buildTheme() {
37722
+ return generateHarmonyTheme(selectedColor, strategy, {
37723
+ dH: dH,
37724
+ dS: dS,
37725
+ dL: dL
37726
+ });
37727
+ }
37339
37728
  React.useEffect(function () {
37340
37729
  if (inline) {
37341
- var theme = isCustom ? generateCustomTheme(selectedColor, secondaryColor, tertiaryColor) : generateHarmonyTheme(selectedColor, strategy);
37342
- onGenerate(theme);
37730
+ onGenerate(buildTheme());
37343
37731
  }
37344
37732
  // eslint-disable-next-line react-hooks/exhaustive-deps
37345
- }, [selectedColor, secondaryColor, tertiaryColor, strategy, inline]);
37733
+ }, [selectedColor, strategy, dH, dS, dL, inline]);
37346
37734
  function handleGenerate() {
37347
- var theme = isCustom ? generateCustomTheme(selectedColor, secondaryColor, tertiaryColor) : generateHarmonyTheme(selectedColor, strategy);
37348
- onGenerate(theme);
37735
+ onGenerate(buildTheme());
37349
37736
  }
37737
+ var previewTheme = buildTheme();
37350
37738
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
37351
37739
  className: inline ? "flex flex-col gap-4" : "flex flex-col gap-4 p-6 overflow-y-auto flex-1 min-h-0",
37352
37740
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
@@ -37359,7 +37747,9 @@ var ColorHarmonyPicker = function ColorHarmonyPicker(_ref6) {
37359
37747
  children: "Harmony"
37360
37748
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
37361
37749
  className: "flex flex-row gap-2 flex-wrap",
37362
- children: HARMONY_STRATEGIES.map(function (s) {
37750
+ children: HARMONY_STRATEGIES.filter(function (s) {
37751
+ return s.value !== "custom";
37752
+ }).map(function (s) {
37363
37753
  return /*#__PURE__*/jsxRuntime.jsx("button", {
37364
37754
  type: "button",
37365
37755
  className: "px-3 py-1.5 rounded text-xs transition-all ".concat(strategy === s.value ? "bg-blue-600 text-white" : "bg-white/10 opacity-70 hover:opacity-100"),
@@ -37370,37 +37760,71 @@ var ColorHarmonyPicker = function ColorHarmonyPicker(_ref6) {
37370
37760
  }, s.value);
37371
37761
  })
37372
37762
  })]
37373
- }), isCustom ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
37374
- children: [/*#__PURE__*/jsxRuntime.jsx(ColorSwatchGrid$1, {
37375
- value: selectedColor,
37376
- onChange: setSelectedColor,
37377
- label: "Primary"
37378
- }), /*#__PURE__*/jsxRuntime.jsx(ColorSwatchGrid$1, {
37379
- value: secondaryColor,
37380
- onChange: setSecondaryColor,
37381
- label: "Secondary"
37382
- }), /*#__PURE__*/jsxRuntime.jsx(ColorSwatchGrid$1, {
37383
- value: tertiaryColor,
37384
- onChange: setTertiaryColor,
37385
- label: "Tertiary"
37763
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37764
+ className: "flex flex-col gap-2",
37765
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37766
+ className: "text-xs opacity-50",
37767
+ children: "Base Color"
37768
+ }), /*#__PURE__*/jsxRuntime.jsx(InlineHexPicker, {
37769
+ selectedHex: DashReact.isHexColor(selectedColor) ? selectedColor : null,
37770
+ onPick: function onPick(hex) {
37771
+ return setSelectedColor(hex);
37772
+ }
37773
+ })]
37774
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37775
+ className: "flex flex-col gap-3",
37776
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37777
+ className: "text-xs opacity-50",
37778
+ children: "Fine-tune (HSL nudge)"
37779
+ }), /*#__PURE__*/jsxRuntime.jsx(HslSlider, {
37780
+ label: "Hue",
37781
+ value: dH,
37782
+ min: -180,
37783
+ max: 180,
37784
+ step: 1,
37785
+ unit: "\xB0",
37786
+ onChange: setDH
37787
+ }), /*#__PURE__*/jsxRuntime.jsx(HslSlider, {
37788
+ label: "Saturation",
37789
+ value: Math.round(dS * 100),
37790
+ min: -100,
37791
+ max: 100,
37792
+ step: 1,
37793
+ unit: "%",
37794
+ onChange: function onChange(v) {
37795
+ return setDS(v / 100);
37796
+ }
37797
+ }), /*#__PURE__*/jsxRuntime.jsx(HslSlider, {
37798
+ label: "Lightness",
37799
+ value: Math.round(dL * 100),
37800
+ min: -100,
37801
+ max: 100,
37802
+ step: 1,
37803
+ unit: "%",
37804
+ onChange: function onChange(v) {
37805
+ return setDL(v / 100);
37806
+ }
37386
37807
  })]
37387
- }) : /*#__PURE__*/jsxRuntime.jsx(ColorSwatchGrid$1, {
37388
- value: selectedColor,
37389
- onChange: setSelectedColor,
37390
- label: "Base Color"
37391
37808
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37392
37809
  className: "flex flex-col gap-2",
37393
37810
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
37394
37811
  className: "text-xs opacity-50",
37395
- children: "Preview"
37396
- }), /*#__PURE__*/jsxRuntime.jsx(PreviewSwatch, {
37397
- color: selectedColor,
37398
- strategy: strategy,
37399
- customColors: isCustom ? {
37400
- primary: selectedColor,
37401
- secondary: secondaryColor,
37402
- tertiary: tertiaryColor
37403
- } : null
37812
+ children: "Generated Palette"
37813
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
37814
+ className: "flex flex-row gap-2",
37815
+ children: [/*#__PURE__*/jsxRuntime.jsx(PaletteSwatch, {
37816
+ value: previewTheme.primary,
37817
+ label: "Primary"
37818
+ }), /*#__PURE__*/jsxRuntime.jsx(PaletteSwatch, {
37819
+ value: previewTheme.secondary,
37820
+ label: "Secondary"
37821
+ }), /*#__PURE__*/jsxRuntime.jsx(PaletteSwatch, {
37822
+ value: previewTheme.tertiary,
37823
+ label: "Tertiary"
37824
+ }), /*#__PURE__*/jsxRuntime.jsx(PaletteSwatch, {
37825
+ value: previewTheme.neutral,
37826
+ label: "Neutral"
37827
+ })]
37404
37828
  })]
37405
37829
  }), !inline && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
37406
37830
  title: "Generate Theme",
@@ -37412,12 +37836,12 @@ var ColorHarmonyPicker = function ColorHarmonyPicker(_ref6) {
37412
37836
 
37413
37837
  // ─── Wizard Components ──────────────────────────────────────────────────
37414
37838
 
37415
- var MethodCard = function MethodCard(_ref7) {
37416
- var icon = _ref7.icon,
37417
- title = _ref7.title,
37418
- subtitle = _ref7.subtitle,
37419
- selected = _ref7.selected,
37420
- onClick = _ref7.onClick;
37839
+ var MethodCard = function MethodCard(_ref8) {
37840
+ var icon = _ref8.icon,
37841
+ title = _ref8.title,
37842
+ subtitle = _ref8.subtitle,
37843
+ selected = _ref8.selected,
37844
+ onClick = _ref8.onClick;
37421
37845
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
37422
37846
  className: "flex flex-col gap-1.5 p-3 rounded-lg cursor-pointer transition-all bg-white/5 hover:bg-white/10 ".concat(selected ? "ring-2 ring-blue-500 bg-white/10" : "hover:ring-1 hover:ring-white/20"),
37423
37847
  onClick: onClick,
@@ -37436,9 +37860,9 @@ var MethodCard = function MethodCard(_ref7) {
37436
37860
  })]
37437
37861
  });
37438
37862
  };
37439
- var RandomPreview = function RandomPreview(_ref8) {
37440
- var theme = _ref8.theme,
37441
- onRegenerate = _ref8.onRegenerate;
37863
+ var RandomPreview = function RandomPreview(_ref9) {
37864
+ var theme = _ref9.theme,
37865
+ onRegenerate = _ref9.onRegenerate;
37442
37866
  var colors = theme ? [theme.primary, theme.secondary, theme.tertiary] : [];
37443
37867
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
37444
37868
  className: "flex flex-col gap-4",
@@ -37465,20 +37889,20 @@ var RandomPreview = function RandomPreview(_ref8) {
37465
37889
  })]
37466
37890
  });
37467
37891
  };
37468
- var ThemeQuickCreate = function ThemeQuickCreate(_ref9) {
37469
- var wizardName = _ref9.wizardName,
37470
- setWizardName = _ref9.setWizardName,
37471
- wizardMethod = _ref9.wizardMethod,
37472
- setWizardMethod = _ref9.setWizardMethod,
37473
- wizardTheme = _ref9.wizardTheme,
37474
- setWizardTheme = _ref9.setWizardTheme,
37475
- onComplete = _ref9.onComplete,
37476
- _ref9$onExtract = _ref9.onExtract,
37477
- onExtract = _ref9$onExtract === void 0 ? null : _ref9$onExtract,
37478
- _ref9$onMapToTheme = _ref9.onMapToTheme,
37479
- onMapToTheme = _ref9$onMapToTheme === void 0 ? null : _ref9$onMapToTheme,
37480
- _ref9$initialMethod = _ref9.initialMethod,
37481
- initialMethod = _ref9$initialMethod === void 0 ? null : _ref9$initialMethod;
37892
+ var ThemeQuickCreate = function ThemeQuickCreate(_ref0) {
37893
+ var wizardName = _ref0.wizardName,
37894
+ setWizardName = _ref0.setWizardName,
37895
+ wizardMethod = _ref0.wizardMethod,
37896
+ setWizardMethod = _ref0.setWizardMethod,
37897
+ wizardTheme = _ref0.wizardTheme,
37898
+ setWizardTheme = _ref0.setWizardTheme,
37899
+ onComplete = _ref0.onComplete,
37900
+ _ref0$onExtract = _ref0.onExtract,
37901
+ onExtract = _ref0$onExtract === void 0 ? null : _ref0$onExtract,
37902
+ _ref0$onMapToTheme = _ref0.onMapToTheme,
37903
+ onMapToTheme = _ref0$onMapToTheme === void 0 ? null : _ref0$onMapToTheme,
37904
+ _ref0$initialMethod = _ref0.initialMethod,
37905
+ initialMethod = _ref0$initialMethod === void 0 ? null : _ref0$initialMethod;
37482
37906
  var canCreate = wizardName.trim().length > 0 && wizardTheme !== null;
37483
37907
  var showMethodPicker = initialMethod === null;
37484
37908
  React.useEffect(function () {
@@ -66190,6 +66614,10 @@ function computeDashboardPreflight(_ref) {
66190
66614
 
66191
66615
  ComponentManager.registerContainerTypes(LayoutContainer, LayoutGridContainer);
66192
66616
 
66617
+ Object.defineProperty(exports, 'FontAwesomeIcon', {
66618
+ enumerable: true,
66619
+ get: function () { return DashReact.FontAwesomeIcon; }
66620
+ });
66193
66621
  Object.defineProperty(exports, 'ThemeContext', {
66194
66622
  enumerable: true,
66195
66623
  get: function () { return DashReact.ThemeContext; }