@trops/dash-core 0.1.604 → 0.1.606
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 +271 -39
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +271 -39
- 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
|
|
@@ -2804,13 +2825,42 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2804
2825
|
error = _useState6[0],
|
|
2805
2826
|
setError = _useState6[1];
|
|
2806
2827
|
var refresh = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
2807
|
-
var _window$mainApi, cMap, builtinWidgets, registryByName, list, installedFromCM, cmSourcePackages, fallbackInstalled, _t;
|
|
2828
|
+
var _window$mainApi, _window$mainApi2, classifyWidget, cMap, builtinWidgets, draftsByPackageDir, draftShortIdToId, allDrafts, _iterator4, _step4, d, shortId, registryByName, list, installedFromCM, cmSourcePackages, fallbackInstalled, _t, _t3;
|
|
2808
2829
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
2809
2830
|
while (1) switch (_context.prev = _context.next) {
|
|
2810
2831
|
case 0:
|
|
2811
2832
|
setIsLoading(true);
|
|
2812
2833
|
setError(null);
|
|
2813
2834
|
_context.prev = 1;
|
|
2835
|
+
classifyWidget = function classifyWidget(reg, fallbackName) {
|
|
2836
|
+
var name = (reg === null || reg === void 0 ? void 0 : reg.name) || fallbackName || "";
|
|
2837
|
+
var path = (reg === null || reg === void 0 ? void 0 : reg.path) || "";
|
|
2838
|
+
// 1. Match against drafts metadata by packageDir (canonical).
|
|
2839
|
+
if (path && draftsByPackageDir.has(path)) {
|
|
2840
|
+
return {
|
|
2841
|
+
kind: "draft",
|
|
2842
|
+
draftId: draftsByPackageDir.get(path).id
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
// 2. Fallback: the dir name follows `<base>-draft-<shortId>`;
|
|
2846
|
+
// pluck the shortId and look it up in the drafts list.
|
|
2847
|
+
var m = String(name).match(/-draft-([A-Za-z0-9]+)$/);
|
|
2848
|
+
if (m) {
|
|
2849
|
+
var _shortId = m[1].slice(0, 8);
|
|
2850
|
+
var draftId = draftShortIdToId.get(_shortId) || null;
|
|
2851
|
+
return {
|
|
2852
|
+
kind: "draft",
|
|
2853
|
+
draftId: draftId
|
|
2854
|
+
};
|
|
2855
|
+
}
|
|
2856
|
+
return {
|
|
2857
|
+
kind: "installed",
|
|
2858
|
+
draftId: null
|
|
2859
|
+
};
|
|
2860
|
+
}; // ── Installed widgets from ComponentManager + Registry ───
|
|
2861
|
+
// CM entries with _sourcePackage are registry-installed widgets.
|
|
2862
|
+
// Show each as an individual "installed" entry, enriched with
|
|
2863
|
+
// registry-level metadata (version, path, packageId).
|
|
2814
2864
|
// ── Built-in widgets from ComponentManager ──────────────
|
|
2815
2865
|
cMap = ComponentManager.componentMap() || {};
|
|
2816
2866
|
builtinWidgets = Object.keys(cMap).filter(function (key) {
|
|
@@ -2829,33 +2879,80 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2829
2879
|
version: null,
|
|
2830
2880
|
path: null,
|
|
2831
2881
|
source: "builtin",
|
|
2882
|
+
kind: "installed",
|
|
2883
|
+
draftId: null,
|
|
2832
2884
|
providers: config.providers || [],
|
|
2833
2885
|
workspace: config.workspace || null,
|
|
2834
2886
|
componentNames: [key],
|
|
2835
2887
|
scopedId: key
|
|
2836
2888
|
};
|
|
2837
|
-
}); // ──
|
|
2838
|
-
//
|
|
2839
|
-
//
|
|
2840
|
-
//
|
|
2889
|
+
}); // ── Drafts (in-progress widgets from the AI Builder) ─────
|
|
2890
|
+
// Drafts on disk look like installed packages — their dirs
|
|
2891
|
+
// sit under @ai-built/<name>-draft-<shortId>/ alongside real
|
|
2892
|
+
// installs. We surface them as `kind: "draft"` so consumers
|
|
2893
|
+
// (dashboard picker, Settings → Widgets) can render them
|
|
2894
|
+
// distinctly (Resume/Delete affordances) or filter them out.
|
|
2895
|
+
// The match is `packageDir`-based when available (canonical)
|
|
2896
|
+
// and falls back to a `-draft-` name-pattern check so legacy
|
|
2897
|
+
// drafts without the on-disk metadata still get classified.
|
|
2898
|
+
draftsByPackageDir = new Map();
|
|
2899
|
+
draftShortIdToId = new Map();
|
|
2900
|
+
if (!((_window$mainApi = window.mainApi) !== null && _window$mainApi !== void 0 && (_window$mainApi = _window$mainApi.drafts) !== null && _window$mainApi !== void 0 && _window$mainApi.list)) {
|
|
2901
|
+
_context.next = 6;
|
|
2902
|
+
break;
|
|
2903
|
+
}
|
|
2904
|
+
_context.prev = 2;
|
|
2905
|
+
_context.next = 3;
|
|
2906
|
+
return window.mainApi.drafts.list();
|
|
2907
|
+
case 3:
|
|
2908
|
+
_t = _context.sent;
|
|
2909
|
+
if (_t) {
|
|
2910
|
+
_context.next = 4;
|
|
2911
|
+
break;
|
|
2912
|
+
}
|
|
2913
|
+
_t = [];
|
|
2914
|
+
case 4:
|
|
2915
|
+
allDrafts = _t;
|
|
2916
|
+
_iterator4 = _createForOfIteratorHelper$M(allDrafts);
|
|
2917
|
+
try {
|
|
2918
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
2919
|
+
d = _step4.value;
|
|
2920
|
+
if (d !== null && d !== void 0 && d.packageDir) draftsByPackageDir.set(d.packageDir, d);
|
|
2921
|
+
if (d !== null && d !== void 0 && d.id) {
|
|
2922
|
+
shortId = String(d.id).replace(/^draft-/, "").slice(0, 8);
|
|
2923
|
+
if (shortId) draftShortIdToId.set(shortId, d.id);
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
} catch (err) {
|
|
2927
|
+
_iterator4.e(err);
|
|
2928
|
+
} finally {
|
|
2929
|
+
_iterator4.f();
|
|
2930
|
+
}
|
|
2931
|
+
_context.next = 6;
|
|
2932
|
+
break;
|
|
2933
|
+
case 5:
|
|
2934
|
+
_context.prev = 5;
|
|
2935
|
+
_context["catch"](2);
|
|
2936
|
+
case 6:
|
|
2841
2937
|
registryByName = {};
|
|
2842
|
-
if (!((_window$
|
|
2843
|
-
_context.next =
|
|
2938
|
+
if (!((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.widgets)) {
|
|
2939
|
+
_context.next = 8;
|
|
2844
2940
|
break;
|
|
2845
2941
|
}
|
|
2846
|
-
_context.next =
|
|
2942
|
+
_context.next = 7;
|
|
2847
2943
|
return window.mainApi.widgets.list();
|
|
2848
|
-
case
|
|
2944
|
+
case 7:
|
|
2849
2945
|
list = _context.sent;
|
|
2850
2946
|
(list || []).forEach(function (w) {
|
|
2851
2947
|
registryByName[w.packageId || w.name] = w;
|
|
2852
2948
|
});
|
|
2853
|
-
case
|
|
2949
|
+
case 8:
|
|
2854
2950
|
installedFromCM = Object.keys(cMap).filter(function (key) {
|
|
2855
2951
|
return cMap[key].type === "widget" && !!cMap[key]._sourcePackage;
|
|
2856
2952
|
}).map(function (key) {
|
|
2857
2953
|
var config = cMap[key];
|
|
2858
2954
|
var reg = registryByName[config._sourcePackage] || {};
|
|
2955
|
+
var classification = classifyWidget(reg, config._sourcePackage);
|
|
2859
2956
|
return {
|
|
2860
2957
|
name: key,
|
|
2861
2958
|
displayName: config.name || key,
|
|
@@ -2866,6 +2963,8 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2866
2963
|
version: reg.version || null,
|
|
2867
2964
|
path: reg.path || null,
|
|
2868
2965
|
source: "installed",
|
|
2966
|
+
kind: classification.kind,
|
|
2967
|
+
draftId: classification.draftId,
|
|
2869
2968
|
providers: config.providers || [],
|
|
2870
2969
|
workspace: config.workspace || null,
|
|
2871
2970
|
componentNames: [key],
|
|
@@ -2882,6 +2981,7 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2882
2981
|
fallbackInstalled = Object.values(registryByName).filter(function (w) {
|
|
2883
2982
|
return !cmSourcePackages.has(w.name);
|
|
2884
2983
|
}).map(function (w) {
|
|
2984
|
+
var classification = classifyWidget(w, w.name);
|
|
2885
2985
|
return {
|
|
2886
2986
|
name: w.name,
|
|
2887
2987
|
displayName: w.displayName || w.name,
|
|
@@ -2892,6 +2992,8 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2892
2992
|
version: w.version || null,
|
|
2893
2993
|
path: w.path || null,
|
|
2894
2994
|
source: "installed",
|
|
2995
|
+
kind: classification.kind,
|
|
2996
|
+
draftId: classification.draftId,
|
|
2895
2997
|
providers: w.providers || [],
|
|
2896
2998
|
workspace: w.workspace || null,
|
|
2897
2999
|
componentNames: w.componentNames || [],
|
|
@@ -2900,31 +3002,31 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2900
3002
|
};
|
|
2901
3003
|
});
|
|
2902
3004
|
setWidgets([].concat(_toConsumableArray(builtinWidgets), _toConsumableArray(installedFromCM), _toConsumableArray(fallbackInstalled)));
|
|
2903
|
-
_context.next =
|
|
3005
|
+
_context.next = 10;
|
|
2904
3006
|
break;
|
|
2905
|
-
case
|
|
2906
|
-
_context.prev =
|
|
2907
|
-
|
|
2908
|
-
setError(
|
|
3007
|
+
case 9:
|
|
3008
|
+
_context.prev = 9;
|
|
3009
|
+
_t3 = _context["catch"](1);
|
|
3010
|
+
setError(_t3.message || "Failed to load widgets");
|
|
2909
3011
|
setWidgets([]);
|
|
2910
|
-
case
|
|
2911
|
-
_context.prev =
|
|
3012
|
+
case 10:
|
|
3013
|
+
_context.prev = 10;
|
|
2912
3014
|
setIsLoading(false);
|
|
2913
|
-
return _context.finish(
|
|
2914
|
-
case
|
|
3015
|
+
return _context.finish(10);
|
|
3016
|
+
case 11:
|
|
2915
3017
|
case "end":
|
|
2916
3018
|
return _context.stop();
|
|
2917
3019
|
}
|
|
2918
|
-
}, _callee, null, [[1,
|
|
3020
|
+
}, _callee, null, [[1, 9, 10, 11], [2, 5]]);
|
|
2919
3021
|
})), []);
|
|
2920
3022
|
var uninstallWidget = React.useCallback(/*#__PURE__*/function () {
|
|
2921
3023
|
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(widgetName) {
|
|
2922
|
-
var _window$
|
|
2923
|
-
var widget, packageId, cMap, keysToRemove,
|
|
3024
|
+
var _window$mainApi3;
|
|
3025
|
+
var widget, packageId, cMap, keysToRemove, _t4;
|
|
2924
3026
|
return _regeneratorRuntime.wrap(function (_context2) {
|
|
2925
3027
|
while (1) switch (_context2.prev = _context2.next) {
|
|
2926
3028
|
case 0:
|
|
2927
|
-
if ((_window$
|
|
3029
|
+
if ((_window$mainApi3 = window.mainApi) !== null && _window$mainApi3 !== void 0 && _window$mainApi3.widgets) {
|
|
2928
3030
|
_context2.next = 1;
|
|
2929
3031
|
break;
|
|
2930
3032
|
}
|
|
@@ -2955,8 +3057,8 @@ var useInstalledWidgets = function useInstalledWidgets() {
|
|
|
2955
3057
|
break;
|
|
2956
3058
|
case 4:
|
|
2957
3059
|
_context2.prev = 4;
|
|
2958
|
-
|
|
2959
|
-
throw
|
|
3060
|
+
_t4 = _context2["catch"](1);
|
|
3061
|
+
throw _t4;
|
|
2960
3062
|
case 5:
|
|
2961
3063
|
case "end":
|
|
2962
3064
|
return _context2.stop();
|
|
@@ -5743,6 +5845,45 @@ function ThemeBroadcast(_ref) {
|
|
|
5743
5845
|
return null;
|
|
5744
5846
|
}
|
|
5745
5847
|
|
|
5848
|
+
/**
|
|
5849
|
+
* Writes the dashboard theme's cssVars to `:root` while mounted, and
|
|
5850
|
+
* restores the previous values on unmount / theme switch.
|
|
5851
|
+
*
|
|
5852
|
+
* ThemeWrapper writes the APP theme's cssVars at the top of the tree.
|
|
5853
|
+
* Without this helper, a dashboard that overrides the app theme with a
|
|
5854
|
+
* hex-channel theme (like "Slack Generic") would carry the right class
|
|
5855
|
+
* names (`bg-[var(--primary-900)]`) but the `--primary-900` variable
|
|
5856
|
+
* on :root would still be the APP theme's value — or undefined if the
|
|
5857
|
+
* app theme is named-family. Hex-themed surfaces then render with no
|
|
5858
|
+
* background. This effect closes that gap by promoting the dashboard
|
|
5859
|
+
* theme's cssVars to :root for the duration of its mount.
|
|
5860
|
+
*/
|
|
5861
|
+
function DashboardCssVarsBridge(_ref2) {
|
|
5862
|
+
var cssVars = _ref2.cssVars;
|
|
5863
|
+
React.useEffect(function () {
|
|
5864
|
+
if (!cssVars || typeof document === "undefined") return undefined;
|
|
5865
|
+
var root = document.documentElement;
|
|
5866
|
+
var previous = {};
|
|
5867
|
+
var keys = Object.keys(cssVars);
|
|
5868
|
+
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
|
|
5869
|
+
var key = _keys[_i];
|
|
5870
|
+
previous[key] = root.style.getPropertyValue(key);
|
|
5871
|
+
root.style.setProperty(key, cssVars[key]);
|
|
5872
|
+
}
|
|
5873
|
+
return function () {
|
|
5874
|
+
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
|
|
5875
|
+
var _key = _keys2[_i2];
|
|
5876
|
+
if (previous[_key]) {
|
|
5877
|
+
root.style.setProperty(_key, previous[_key]);
|
|
5878
|
+
} else {
|
|
5879
|
+
root.style.removeProperty(_key);
|
|
5880
|
+
}
|
|
5881
|
+
}
|
|
5882
|
+
};
|
|
5883
|
+
}, [cssVars]);
|
|
5884
|
+
return null;
|
|
5885
|
+
}
|
|
5886
|
+
|
|
5746
5887
|
/**
|
|
5747
5888
|
* DashboardThemeProvider
|
|
5748
5889
|
*
|
|
@@ -5753,9 +5894,10 @@ function ThemeBroadcast(_ref) {
|
|
|
5753
5894
|
* App chrome (navbar, tab bar, sidebar) stays OUTSIDE this wrapper
|
|
5754
5895
|
* and keeps the app theme.
|
|
5755
5896
|
*/
|
|
5756
|
-
var DashboardThemeProvider = function DashboardThemeProvider(
|
|
5757
|
-
var
|
|
5758
|
-
|
|
5897
|
+
var DashboardThemeProvider = function DashboardThemeProvider(_ref3) {
|
|
5898
|
+
var _contextValue$current;
|
|
5899
|
+
var themeKey = _ref3.themeKey,
|
|
5900
|
+
children = _ref3.children;
|
|
5759
5901
|
var parentContext = React.useContext(DashReact.ThemeContext);
|
|
5760
5902
|
var themes = parentContext.themes,
|
|
5761
5903
|
themeVariant = parentContext.themeVariant;
|
|
@@ -5787,6 +5929,8 @@ var DashboardThemeProvider = function DashboardThemeProvider(_ref2) {
|
|
|
5787
5929
|
value: contextValue,
|
|
5788
5930
|
children: [/*#__PURE__*/jsxRuntime.jsx(ThemeBroadcast, {
|
|
5789
5931
|
ctx: contextValue
|
|
5932
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashboardCssVarsBridge, {
|
|
5933
|
+
cssVars: contextValue === null || contextValue === void 0 || (_contextValue$current = contextValue.currentTheme) === null || _contextValue$current === void 0 ? void 0 : _contextValue$current.cssVars
|
|
5790
5934
|
}), children]
|
|
5791
5935
|
});
|
|
5792
5936
|
};
|
|
@@ -17622,6 +17766,12 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
|
|
|
17622
17766
|
// Filter widgets based on search, author, and provider
|
|
17623
17767
|
var getFilteredWidgets = function getFilteredWidgets() {
|
|
17624
17768
|
var filtered = widgets.filter(function (widget) {
|
|
17769
|
+
// Drafts are in-progress widgets — they appear in
|
|
17770
|
+
// Settings → Widgets (as a Draft chip with Resume/Delete
|
|
17771
|
+
// affordances) but never in the dashboard placement picker
|
|
17772
|
+
// since they're not finished products.
|
|
17773
|
+
if (widget.kind === "draft") return false;
|
|
17774
|
+
|
|
17625
17775
|
// Search filter
|
|
17626
17776
|
var searchLower = searchQuery.toLowerCase();
|
|
17627
17777
|
var matchesSearch = !searchQuery || (widget.name || "").toLowerCase().includes(searchLower) || (widget.description || "").toLowerCase().includes(searchLower) || (widget.key || "").toLowerCase().includes(searchLower) || (widget.packageName || "").toLowerCase().includes(searchLower) || (widget.packageTags || []).some(function (t) {
|
|
@@ -28976,6 +29126,36 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
|
|
|
28976
29126
|
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
29127
|
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
29128
|
|
|
29129
|
+
/**
|
|
29130
|
+
* Last-resort family for ANY channel whose value can't be resolved
|
|
29131
|
+
* (unknown name, missing palette entry, missing shade, …). Picked
|
|
29132
|
+
* because it's universally safelist-covered, has every shade from
|
|
29133
|
+
* 50..950, and is visually neutral — so a misconfigured theme
|
|
29134
|
+
* renders "muted" rather than blank/transparent.
|
|
29135
|
+
*
|
|
29136
|
+
* Slack Generic etc. exposed this: when a channel value was missing
|
|
29137
|
+
* or unrecognized, ThemeModel silently emitted `bg-undefined-700`
|
|
29138
|
+
* (not in any safelist) → Tailwind dropped the class → the
|
|
29139
|
+
* dropdown popover rendered transparent. Falling back here means
|
|
29140
|
+
* no token can be "missing" by the time `getStylesForItem` reads it.
|
|
29141
|
+
*/
|
|
29142
|
+
var FALLBACK_FAMILY = "gray";
|
|
29143
|
+
|
|
29144
|
+
/**
|
|
29145
|
+
* Resolve a channel value to a safelist-covered Tailwind family
|
|
29146
|
+
* name. Returns the original value when it's a hex (the caller
|
|
29147
|
+
* handles those via CSS variables) or a recognized palette family;
|
|
29148
|
+
* otherwise returns FALLBACK_FAMILY so the resulting class always
|
|
29149
|
+
* renders.
|
|
29150
|
+
*/
|
|
29151
|
+
function resolveChannelFamily(channelValue) {
|
|
29152
|
+
if (DashReact.isHexColor(channelValue)) return channelValue;
|
|
29153
|
+
if (typeof channelValue === "string" && channelValue.length > 0 && DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue]) {
|
|
29154
|
+
return channelValue;
|
|
29155
|
+
}
|
|
29156
|
+
return FALLBACK_FAMILY;
|
|
29157
|
+
}
|
|
29158
|
+
|
|
28979
29159
|
/**
|
|
28980
29160
|
* getNextLevel
|
|
28981
29161
|
* Need to generate the levels for tailwind
|
|
@@ -28994,6 +29174,11 @@ function invert(shade) {
|
|
|
28994
29174
|
* shade. Routes to the arbitrary-value syntax (`bg-[var(--type-shade)]`)
|
|
28995
29175
|
* when the channel's value is a hex.
|
|
28996
29176
|
*
|
|
29177
|
+
* Layer 1 fallback (audit follow-up to the Slack Generic bug): if
|
|
29178
|
+
* `channelValue` isn't a hex AND isn't a recognized Tailwind palette
|
|
29179
|
+
* family, fall back to FALLBACK_FAMILY so the emitted class is
|
|
29180
|
+
* always safelist-covered and never resolves to `bg-undefined-700`.
|
|
29181
|
+
*
|
|
28997
29182
|
* @param {"bg"|"text"|"border"} prefix
|
|
28998
29183
|
* @param {string} type channel name (primary | secondary | …)
|
|
28999
29184
|
* @param {number} shade tailwind shade (100..950)
|
|
@@ -29003,10 +29188,11 @@ function invert(shade) {
|
|
|
29003
29188
|
function classFor(prefix, type, shade, channelValue) {
|
|
29004
29189
|
var hover = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
29005
29190
|
var h = hover ? "hover:" : "";
|
|
29006
|
-
|
|
29191
|
+
var resolved = resolveChannelFamily(channelValue);
|
|
29192
|
+
if (DashReact.isHexColor(resolved)) {
|
|
29007
29193
|
return "".concat(h).concat(prefix, "-[var(--").concat(type, "-").concat(shade, ")]");
|
|
29008
29194
|
}
|
|
29009
|
-
return "".concat(h).concat(prefix, "-").concat(
|
|
29195
|
+
return "".concat(h).concat(prefix, "-").concat(resolved, "-").concat(shade);
|
|
29010
29196
|
}
|
|
29011
29197
|
|
|
29012
29198
|
/**
|
|
@@ -29019,8 +29205,10 @@ function classFor(prefix, type, shade, channelValue) {
|
|
|
29019
29205
|
* produce a `var(--{type}-{shade})` reference that resolves against
|
|
29020
29206
|
* the CSS custom properties ThemePreviewProvider writes to :root.
|
|
29021
29207
|
*
|
|
29022
|
-
*
|
|
29023
|
-
*
|
|
29208
|
+
* Layer 1 fallback: when the channel value or shade can't be
|
|
29209
|
+
* resolved, fall back to FALLBACK_FAMILY's shade so cssValue is
|
|
29210
|
+
* never null. Pairs with classFor's same fallback to guarantee
|
|
29211
|
+
* every (type, shade) tuple yields a renderable token.
|
|
29024
29212
|
*/
|
|
29025
29213
|
function cssValueFor(type, shade, channelValue) {
|
|
29026
29214
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -29033,12 +29221,17 @@ function cssValueFor(type, shade, channelValue) {
|
|
|
29033
29221
|
var _hex = shades[shade] || shades[String(shade)];
|
|
29034
29222
|
if (_hex) return _hex;
|
|
29035
29223
|
}
|
|
29036
|
-
return
|
|
29224
|
+
return fallbackCssValue(shade);
|
|
29037
29225
|
}
|
|
29038
29226
|
var family = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue];
|
|
29039
|
-
if (!family) return
|
|
29227
|
+
if (!family) return fallbackCssValue(shade);
|
|
29040
29228
|
var hex = family[shade] || family[String(shade)];
|
|
29041
|
-
return hex ||
|
|
29229
|
+
return hex || fallbackCssValue(shade);
|
|
29230
|
+
}
|
|
29231
|
+
function fallbackCssValue(shade) {
|
|
29232
|
+
var fallback = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[FALLBACK_FAMILY];
|
|
29233
|
+
if (!fallback) return null;
|
|
29234
|
+
return fallback[shade] || fallback[String(shade)] || null;
|
|
29042
29235
|
}
|
|
29043
29236
|
function gradientFor(direction, type, fromShade, viaShade, toShade, channelValue) {
|
|
29044
29237
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -35223,11 +35416,25 @@ var ChannelEditorModal = function ChannelEditorModal(_ref) {
|
|
|
35223
35416
|
var nearest = React.useMemo(function () {
|
|
35224
35417
|
return nearestSwatch(selectedHex, families);
|
|
35225
35418
|
}, [selectedHex, families]);
|
|
35419
|
+
|
|
35420
|
+
// Auto-switch the family tab when the underlying selected color
|
|
35421
|
+
// changes (user picked a different channel/shade or the theme
|
|
35422
|
+
// mutated). Track the last hex we synced for so we don't fight
|
|
35423
|
+
// the user's manual tab clicks — without this guard, every
|
|
35424
|
+
// re-render rebuilds `nearest` as a new object reference and the
|
|
35425
|
+
// effect snaps activeFamily back to the family containing the
|
|
35426
|
+
// current color, making it impossible to browse other families.
|
|
35427
|
+
var lastSyncedHexRef = React.useRef(null);
|
|
35226
35428
|
React.useEffect(function () {
|
|
35227
|
-
if (!isOpen)
|
|
35429
|
+
if (!isOpen) {
|
|
35430
|
+
lastSyncedHexRef.current = null;
|
|
35431
|
+
return;
|
|
35432
|
+
}
|
|
35433
|
+
if (lastSyncedHexRef.current === selectedHex) return;
|
|
35434
|
+
lastSyncedHexRef.current = selectedHex;
|
|
35228
35435
|
if (nearest) setActiveFamily(nearest.family);
|
|
35229
35436
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35230
|
-
}, [isOpen, nearest]);
|
|
35437
|
+
}, [isOpen, selectedHex, nearest]);
|
|
35231
35438
|
function expandChannel(channelKey) {
|
|
35232
35439
|
setActiveChannel(channelKey);
|
|
35233
35440
|
setActiveSlot("base");
|
|
@@ -48558,7 +48765,27 @@ var InstalledWidgetDetail = function InstalledWidgetDetail(_ref) {
|
|
|
48558
48765
|
className: "p-2 rounded bg-red-900/30 border border-red-700 text-xs text-red-400",
|
|
48559
48766
|
children: updateError
|
|
48560
48767
|
})
|
|
48561
|
-
}), widget.source !== "builtin" && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
48768
|
+
}), widget.source !== "builtin" && widget.kind === "draft" && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
48769
|
+
className: "flex-shrink-0 flex flex-row justify-end gap-2 px-6 py-4 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
|
|
48770
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
48771
|
+
title: "Resume",
|
|
48772
|
+
onClick: function onClick() {
|
|
48773
|
+
window.dispatchEvent(new CustomEvent("dash:open-widget-builder", {
|
|
48774
|
+
detail: {
|
|
48775
|
+
resumeDraftId: widget.draftId || null
|
|
48776
|
+
}
|
|
48777
|
+
}));
|
|
48778
|
+
},
|
|
48779
|
+
disabled: !widget.draftId,
|
|
48780
|
+
size: "sm"
|
|
48781
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
48782
|
+
title: "Delete",
|
|
48783
|
+
onClick: function onClick() {
|
|
48784
|
+
return onDelete(widget);
|
|
48785
|
+
},
|
|
48786
|
+
size: "sm"
|
|
48787
|
+
})]
|
|
48788
|
+
}), widget.source !== "builtin" && widget.kind !== "draft" && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
48562
48789
|
className: "flex-shrink-0 flex flex-row justify-end gap-2 px-6 py-4 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
|
|
48563
48790
|
children: [updateInfo && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
48564
48791
|
title: isUpdating ? "Updating..." : "Update Package to v".concat(updateInfo.latestVersion),
|
|
@@ -50025,7 +50252,12 @@ var WidgetsSection = function WidgetsSection(_ref) {
|
|
|
50025
50252
|
className: "flex items-center gap-2",
|
|
50026
50253
|
children: [widget.displayName || widget.name, widget.source === "builtin" && /*#__PURE__*/jsxRuntime.jsx(DashReact.Tag3, {
|
|
50027
50254
|
text: "Built-in"
|
|
50028
|
-
}),
|
|
50255
|
+
}), widget.kind === "draft" && /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
50256
|
+
className: "px-1.5 py-0.5 rounded-full text-[10px] font-medium bg-amber-900/40 text-amber-200 border border-amber-700/30",
|
|
50257
|
+
"data-testid": "widget-draft-chip-".concat(widget.name),
|
|
50258
|
+
title: "In-progress widget \u2014 open to Resume or Delete from the action menu",
|
|
50259
|
+
children: "Draft"
|
|
50260
|
+
}), widget.kind !== "draft" && updates.has(widget.name) && /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
50029
50261
|
className: "text-[10px] text-blue-400 font-medium",
|
|
50030
50262
|
"data-testid": "widget-update-badge-".concat(widget.name),
|
|
50031
50263
|
children: "Update"
|