@trops/dash-core 0.1.604 → 0.1.605
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.esm.js +132 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +132 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2567,6 +2567,27 @@ var ThemeWrapper = function ThemeWrapper(_ref) {
|
|
|
2567
2567
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2568
2568
|
}, [chosenTheme, themeVariant, themeName, themesForApplication, rawThemes]);
|
|
2569
2569
|
|
|
2570
|
+
// Broadcast the app-level theme to a SEPARATE global so
|
|
2571
|
+
// components rendered OUTSIDE the React theme tree
|
|
2572
|
+
// (WidgetBuilderModal, AppUpdatesModal — they live as siblings
|
|
2573
|
+
// of DashboardStage in dash-electron's Dash.js render) can fall
|
|
2574
|
+
// back to it when no dashboard-specific override is in play.
|
|
2575
|
+
//
|
|
2576
|
+
// We can't share the same global with DashboardThemeProvider's
|
|
2577
|
+
// per-workspace broadcast because React commits child effects
|
|
2578
|
+
// BEFORE parent effects — ThemeWrapper would always run last
|
|
2579
|
+
// and silently overwrite the workspace theme. Two separate
|
|
2580
|
+
// globals avoid the race: consumers read
|
|
2581
|
+
// `__dashThemeContext` (workspace) first, fall back to
|
|
2582
|
+
// `__dashAppThemeContext` (app-level) when no workspace is open.
|
|
2583
|
+
React.useEffect(function () {
|
|
2584
|
+
if (typeof window === "undefined") return undefined;
|
|
2585
|
+
if (contextValue !== null && contextValue !== void 0 && contextValue.currentTheme) {
|
|
2586
|
+
window.__dashAppThemeContext = contextValue;
|
|
2587
|
+
window.dispatchEvent(new Event("dash:theme-changed"));
|
|
2588
|
+
}
|
|
2589
|
+
}, [contextValue]);
|
|
2590
|
+
|
|
2570
2591
|
// Write the active theme's CSS custom properties to :root so any
|
|
2571
2592
|
// hex-channel tokens (`bg-[var(--primary-700)]` etc. emitted by
|
|
2572
2593
|
// ThemeModel) resolve app-wide. Without this, saving a hex theme
|
|
@@ -5743,6 +5764,45 @@ function ThemeBroadcast(_ref) {
|
|
|
5743
5764
|
return null;
|
|
5744
5765
|
}
|
|
5745
5766
|
|
|
5767
|
+
/**
|
|
5768
|
+
* Writes the dashboard theme's cssVars to `:root` while mounted, and
|
|
5769
|
+
* restores the previous values on unmount / theme switch.
|
|
5770
|
+
*
|
|
5771
|
+
* ThemeWrapper writes the APP theme's cssVars at the top of the tree.
|
|
5772
|
+
* Without this helper, a dashboard that overrides the app theme with a
|
|
5773
|
+
* hex-channel theme (like "Slack Generic") would carry the right class
|
|
5774
|
+
* names (`bg-[var(--primary-900)]`) but the `--primary-900` variable
|
|
5775
|
+
* on :root would still be the APP theme's value — or undefined if the
|
|
5776
|
+
* app theme is named-family. Hex-themed surfaces then render with no
|
|
5777
|
+
* background. This effect closes that gap by promoting the dashboard
|
|
5778
|
+
* theme's cssVars to :root for the duration of its mount.
|
|
5779
|
+
*/
|
|
5780
|
+
function DashboardCssVarsBridge(_ref2) {
|
|
5781
|
+
var cssVars = _ref2.cssVars;
|
|
5782
|
+
React.useEffect(function () {
|
|
5783
|
+
if (!cssVars || typeof document === "undefined") return undefined;
|
|
5784
|
+
var root = document.documentElement;
|
|
5785
|
+
var previous = {};
|
|
5786
|
+
var keys = Object.keys(cssVars);
|
|
5787
|
+
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
|
|
5788
|
+
var key = _keys[_i];
|
|
5789
|
+
previous[key] = root.style.getPropertyValue(key);
|
|
5790
|
+
root.style.setProperty(key, cssVars[key]);
|
|
5791
|
+
}
|
|
5792
|
+
return function () {
|
|
5793
|
+
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
|
|
5794
|
+
var _key = _keys2[_i2];
|
|
5795
|
+
if (previous[_key]) {
|
|
5796
|
+
root.style.setProperty(_key, previous[_key]);
|
|
5797
|
+
} else {
|
|
5798
|
+
root.style.removeProperty(_key);
|
|
5799
|
+
}
|
|
5800
|
+
}
|
|
5801
|
+
};
|
|
5802
|
+
}, [cssVars]);
|
|
5803
|
+
return null;
|
|
5804
|
+
}
|
|
5805
|
+
|
|
5746
5806
|
/**
|
|
5747
5807
|
* DashboardThemeProvider
|
|
5748
5808
|
*
|
|
@@ -5753,9 +5813,10 @@ function ThemeBroadcast(_ref) {
|
|
|
5753
5813
|
* App chrome (navbar, tab bar, sidebar) stays OUTSIDE this wrapper
|
|
5754
5814
|
* and keeps the app theme.
|
|
5755
5815
|
*/
|
|
5756
|
-
var DashboardThemeProvider = function DashboardThemeProvider(
|
|
5757
|
-
var
|
|
5758
|
-
|
|
5816
|
+
var DashboardThemeProvider = function DashboardThemeProvider(_ref3) {
|
|
5817
|
+
var _contextValue$current;
|
|
5818
|
+
var themeKey = _ref3.themeKey,
|
|
5819
|
+
children = _ref3.children;
|
|
5759
5820
|
var parentContext = React.useContext(DashReact.ThemeContext);
|
|
5760
5821
|
var themes = parentContext.themes,
|
|
5761
5822
|
themeVariant = parentContext.themeVariant;
|
|
@@ -5787,6 +5848,8 @@ var DashboardThemeProvider = function DashboardThemeProvider(_ref2) {
|
|
|
5787
5848
|
value: contextValue,
|
|
5788
5849
|
children: [/*#__PURE__*/jsxRuntime.jsx(ThemeBroadcast, {
|
|
5789
5850
|
ctx: contextValue
|
|
5851
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashboardCssVarsBridge, {
|
|
5852
|
+
cssVars: contextValue === null || contextValue === void 0 || (_contextValue$current = contextValue.currentTheme) === null || _contextValue$current === void 0 ? void 0 : _contextValue$current.cssVars
|
|
5790
5853
|
}), children]
|
|
5791
5854
|
});
|
|
5792
5855
|
};
|
|
@@ -28976,6 +29039,36 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
|
|
|
28976
29039
|
function ownKeys$H(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
28977
29040
|
function _objectSpread$H(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$H(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$H(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
28978
29041
|
|
|
29042
|
+
/**
|
|
29043
|
+
* Last-resort family for ANY channel whose value can't be resolved
|
|
29044
|
+
* (unknown name, missing palette entry, missing shade, …). Picked
|
|
29045
|
+
* because it's universally safelist-covered, has every shade from
|
|
29046
|
+
* 50..950, and is visually neutral — so a misconfigured theme
|
|
29047
|
+
* renders "muted" rather than blank/transparent.
|
|
29048
|
+
*
|
|
29049
|
+
* Slack Generic etc. exposed this: when a channel value was missing
|
|
29050
|
+
* or unrecognized, ThemeModel silently emitted `bg-undefined-700`
|
|
29051
|
+
* (not in any safelist) → Tailwind dropped the class → the
|
|
29052
|
+
* dropdown popover rendered transparent. Falling back here means
|
|
29053
|
+
* no token can be "missing" by the time `getStylesForItem` reads it.
|
|
29054
|
+
*/
|
|
29055
|
+
var FALLBACK_FAMILY = "gray";
|
|
29056
|
+
|
|
29057
|
+
/**
|
|
29058
|
+
* Resolve a channel value to a safelist-covered Tailwind family
|
|
29059
|
+
* name. Returns the original value when it's a hex (the caller
|
|
29060
|
+
* handles those via CSS variables) or a recognized palette family;
|
|
29061
|
+
* otherwise returns FALLBACK_FAMILY so the resulting class always
|
|
29062
|
+
* renders.
|
|
29063
|
+
*/
|
|
29064
|
+
function resolveChannelFamily(channelValue) {
|
|
29065
|
+
if (DashReact.isHexColor(channelValue)) return channelValue;
|
|
29066
|
+
if (typeof channelValue === "string" && channelValue.length > 0 && DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue]) {
|
|
29067
|
+
return channelValue;
|
|
29068
|
+
}
|
|
29069
|
+
return FALLBACK_FAMILY;
|
|
29070
|
+
}
|
|
29071
|
+
|
|
28979
29072
|
/**
|
|
28980
29073
|
* getNextLevel
|
|
28981
29074
|
* Need to generate the levels for tailwind
|
|
@@ -28994,6 +29087,11 @@ function invert(shade) {
|
|
|
28994
29087
|
* shade. Routes to the arbitrary-value syntax (`bg-[var(--type-shade)]`)
|
|
28995
29088
|
* when the channel's value is a hex.
|
|
28996
29089
|
*
|
|
29090
|
+
* Layer 1 fallback (audit follow-up to the Slack Generic bug): if
|
|
29091
|
+
* `channelValue` isn't a hex AND isn't a recognized Tailwind palette
|
|
29092
|
+
* family, fall back to FALLBACK_FAMILY so the emitted class is
|
|
29093
|
+
* always safelist-covered and never resolves to `bg-undefined-700`.
|
|
29094
|
+
*
|
|
28997
29095
|
* @param {"bg"|"text"|"border"} prefix
|
|
28998
29096
|
* @param {string} type channel name (primary | secondary | …)
|
|
28999
29097
|
* @param {number} shade tailwind shade (100..950)
|
|
@@ -29003,10 +29101,11 @@ function invert(shade) {
|
|
|
29003
29101
|
function classFor(prefix, type, shade, channelValue) {
|
|
29004
29102
|
var hover = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
29005
29103
|
var h = hover ? "hover:" : "";
|
|
29006
|
-
|
|
29104
|
+
var resolved = resolveChannelFamily(channelValue);
|
|
29105
|
+
if (DashReact.isHexColor(resolved)) {
|
|
29007
29106
|
return "".concat(h).concat(prefix, "-[var(--").concat(type, "-").concat(shade, ")]");
|
|
29008
29107
|
}
|
|
29009
|
-
return "".concat(h).concat(prefix, "-").concat(
|
|
29108
|
+
return "".concat(h).concat(prefix, "-").concat(resolved, "-").concat(shade);
|
|
29010
29109
|
}
|
|
29011
29110
|
|
|
29012
29111
|
/**
|
|
@@ -29019,8 +29118,10 @@ function classFor(prefix, type, shade, channelValue) {
|
|
|
29019
29118
|
* produce a `var(--{type}-{shade})` reference that resolves against
|
|
29020
29119
|
* the CSS custom properties ThemePreviewProvider writes to :root.
|
|
29021
29120
|
*
|
|
29022
|
-
*
|
|
29023
|
-
*
|
|
29121
|
+
* Layer 1 fallback: when the channel value or shade can't be
|
|
29122
|
+
* resolved, fall back to FALLBACK_FAMILY's shade so cssValue is
|
|
29123
|
+
* never null. Pairs with classFor's same fallback to guarantee
|
|
29124
|
+
* every (type, shade) tuple yields a renderable token.
|
|
29024
29125
|
*/
|
|
29025
29126
|
function cssValueFor(type, shade, channelValue) {
|
|
29026
29127
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -29033,12 +29134,17 @@ function cssValueFor(type, shade, channelValue) {
|
|
|
29033
29134
|
var _hex = shades[shade] || shades[String(shade)];
|
|
29034
29135
|
if (_hex) return _hex;
|
|
29035
29136
|
}
|
|
29036
|
-
return
|
|
29137
|
+
return fallbackCssValue(shade);
|
|
29037
29138
|
}
|
|
29038
29139
|
var family = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue];
|
|
29039
|
-
if (!family) return
|
|
29140
|
+
if (!family) return fallbackCssValue(shade);
|
|
29040
29141
|
var hex = family[shade] || family[String(shade)];
|
|
29041
|
-
return hex ||
|
|
29142
|
+
return hex || fallbackCssValue(shade);
|
|
29143
|
+
}
|
|
29144
|
+
function fallbackCssValue(shade) {
|
|
29145
|
+
var fallback = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[FALLBACK_FAMILY];
|
|
29146
|
+
if (!fallback) return null;
|
|
29147
|
+
return fallback[shade] || fallback[String(shade)] || null;
|
|
29042
29148
|
}
|
|
29043
29149
|
function gradientFor(direction, type, fromShade, viaShade, toShade, channelValue) {
|
|
29044
29150
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -35223,11 +35329,25 @@ var ChannelEditorModal = function ChannelEditorModal(_ref) {
|
|
|
35223
35329
|
var nearest = React.useMemo(function () {
|
|
35224
35330
|
return nearestSwatch(selectedHex, families);
|
|
35225
35331
|
}, [selectedHex, families]);
|
|
35332
|
+
|
|
35333
|
+
// Auto-switch the family tab when the underlying selected color
|
|
35334
|
+
// changes (user picked a different channel/shade or the theme
|
|
35335
|
+
// mutated). Track the last hex we synced for so we don't fight
|
|
35336
|
+
// the user's manual tab clicks — without this guard, every
|
|
35337
|
+
// re-render rebuilds `nearest` as a new object reference and the
|
|
35338
|
+
// effect snaps activeFamily back to the family containing the
|
|
35339
|
+
// current color, making it impossible to browse other families.
|
|
35340
|
+
var lastSyncedHexRef = React.useRef(null);
|
|
35226
35341
|
React.useEffect(function () {
|
|
35227
|
-
if (!isOpen)
|
|
35342
|
+
if (!isOpen) {
|
|
35343
|
+
lastSyncedHexRef.current = null;
|
|
35344
|
+
return;
|
|
35345
|
+
}
|
|
35346
|
+
if (lastSyncedHexRef.current === selectedHex) return;
|
|
35347
|
+
lastSyncedHexRef.current = selectedHex;
|
|
35228
35348
|
if (nearest) setActiveFamily(nearest.family);
|
|
35229
35349
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35230
|
-
}, [isOpen, nearest]);
|
|
35350
|
+
}, [isOpen, selectedHex, nearest]);
|
|
35231
35351
|
function expandChannel(channelKey) {
|
|
35232
35352
|
setActiveChannel(channelKey);
|
|
35233
35353
|
setActiveSlot("base");
|