@mastra/playground-ui 24.0.0-alpha.3 → 24.0.0-alpha.4
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/CHANGELOG.md +18 -0
- package/dist/index.cjs.js +207 -34
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.css +34 -0
- package/dist/index.es.js +207 -36
- package/dist/index.es.js.map +1 -1
- package/dist/src/ds/components/ThemeProvider/index.d.ts +2 -0
- package/dist/src/ds/components/ThemeProvider/storage-adapter.d.ts +7 -0
- package/dist/src/ds/components/ThemeProvider/theme-context.d.ts +9 -0
- package/dist/src/ds/components/ThemeProvider/theme-provider.d.ts +9 -0
- package/dist/src/ds/components/ThemeProvider/theme-provider.stories.d.ts +7 -0
- package/dist/src/ds/components/ThemeToggle/index.d.ts +2 -0
- package/dist/src/ds/components/ThemeToggle/theme-toggle.d.ts +21 -0
- package/dist/src/ds/components/ThemeToggle/theme-toggle.stories.d.ts +7 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/store/playground-store.d.ts +0 -9
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @mastra/playground-ui
|
|
2
2
|
|
|
3
|
+
## 24.0.0-alpha.4
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added shared `ThemeProvider`, `useTheme`, and `ThemeToggle` to unify theme management. ([#15838](https://github.com/mastra-ai/mastra/pull/15838))
|
|
8
|
+
|
|
9
|
+
**Added**
|
|
10
|
+
- `ThemeProvider` applies the resolved theme class to `<html>` and persists the choice under the shared `mastra-theme` localStorage key, with a one-time migration from previously stored preferences.
|
|
11
|
+
- `useTheme()` works without a `<ThemeProvider>` ancestor: it returns a read-only fallback that tracks the OS color scheme and exposes a no-op `setTheme`, so theme-aware leaf components (e.g. `CodeDiff`, `CodeEditor`) keep working when embedded standalone.
|
|
12
|
+
- `ThemeToggle` renders a system/light/dark pill and supports both controlled and uncontrolled usage.
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [[`8a71261`](https://github.com/mastra-ai/mastra/commit/8a71261e3954ae617c6f8e25767b951f99438ab2), [`021a60f`](https://github.com/mastra-ai/mastra/commit/021a60f1f3e0135a70ef23c58be7a9b3aaffe6b4)]:
|
|
17
|
+
- @mastra/core@1.29.0-alpha.4
|
|
18
|
+
- @mastra/client-js@1.15.0-alpha.4
|
|
19
|
+
- @mastra/react@0.2.30-alpha.4
|
|
20
|
+
|
|
3
21
|
## 24.0.0-alpha.3
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -18,8 +18,6 @@ const codemirrorThemeDracula = require('@uiw/codemirror-theme-dracula');
|
|
|
18
18
|
const ReactCodeMirror = require('@uiw/react-codemirror');
|
|
19
19
|
const autocomplete = require('@codemirror/autocomplete');
|
|
20
20
|
const sonner = require('sonner');
|
|
21
|
-
const zustand = require('zustand');
|
|
22
|
-
const middleware = require('zustand/middleware');
|
|
23
21
|
const react = require('@mastra/react');
|
|
24
22
|
const AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
25
23
|
const CheckboxPrimitive = require('@radix-ui/react-checkbox');
|
|
@@ -50,6 +48,8 @@ const isToday = require('date-fns/isToday');
|
|
|
50
48
|
const search = require('@codemirror/search');
|
|
51
49
|
const recharts = require('recharts');
|
|
52
50
|
const reactResizablePanels = require('react-resizable-panels');
|
|
51
|
+
const zustand = require('zustand');
|
|
52
|
+
const middleware = require('zustand/middleware');
|
|
53
53
|
const reactQuery = require('@tanstack/react-query');
|
|
54
54
|
const observability = require('@mastra/core/observability');
|
|
55
55
|
|
|
@@ -5180,33 +5180,117 @@ function CopyButton({
|
|
|
5180
5180
|
] });
|
|
5181
5181
|
}
|
|
5182
5182
|
|
|
5183
|
-
const
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5183
|
+
const DEFAULT_KEY = "mastra-theme";
|
|
5184
|
+
const LEGACY_ZUSTAND_KEY = "mastra-playground-store";
|
|
5185
|
+
const isTheme = (value) => value === "dark" || value === "light" || value === "system";
|
|
5186
|
+
const readLegacyZustand = (storage) => {
|
|
5187
|
+
try {
|
|
5188
|
+
const raw = storage.getItem(LEGACY_ZUSTAND_KEY);
|
|
5189
|
+
if (!raw) return void 0;
|
|
5190
|
+
const parsed = JSON.parse(raw);
|
|
5191
|
+
const theme = parsed?.state?.theme;
|
|
5192
|
+
return isTheme(theme) ? theme : void 0;
|
|
5193
|
+
} catch {
|
|
5194
|
+
return void 0;
|
|
5195
|
+
}
|
|
5196
|
+
};
|
|
5197
|
+
const createLocalStorageAdapter = (key = DEFAULT_KEY) => ({
|
|
5198
|
+
get() {
|
|
5199
|
+
if (typeof window === "undefined") return null;
|
|
5200
|
+
try {
|
|
5201
|
+
const raw = window.localStorage.getItem(key);
|
|
5202
|
+
if (isTheme(raw)) return raw;
|
|
5203
|
+
const migrated = readLegacyZustand(window.localStorage);
|
|
5204
|
+
if (migrated) {
|
|
5205
|
+
window.localStorage.setItem(key, migrated);
|
|
5206
|
+
return migrated;
|
|
5207
|
+
}
|
|
5208
|
+
return null;
|
|
5209
|
+
} catch {
|
|
5210
|
+
return null;
|
|
5193
5211
|
}
|
|
5194
|
-
|
|
5195
|
-
)
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
}
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5212
|
+
},
|
|
5213
|
+
set(value) {
|
|
5214
|
+
if (typeof window === "undefined") return;
|
|
5215
|
+
try {
|
|
5216
|
+
window.localStorage.setItem(key, value);
|
|
5217
|
+
} catch {
|
|
5218
|
+
}
|
|
5219
|
+
},
|
|
5220
|
+
subscribe(listener) {
|
|
5221
|
+
if (typeof window === "undefined") return () => {
|
|
5222
|
+
};
|
|
5223
|
+
const handler = (event) => {
|
|
5224
|
+
if (event.key !== key) return;
|
|
5225
|
+
if (event.newValue === null) {
|
|
5226
|
+
listener(null);
|
|
5227
|
+
return;
|
|
5228
|
+
}
|
|
5229
|
+
if (isTheme(event.newValue)) listener(event.newValue);
|
|
5230
|
+
};
|
|
5231
|
+
window.addEventListener("storage", handler);
|
|
5232
|
+
return () => window.removeEventListener("storage", handler);
|
|
5233
|
+
}
|
|
5234
|
+
});
|
|
5235
|
+
|
|
5236
|
+
const ThemeContext = React.createContext(null);
|
|
5237
|
+
|
|
5238
|
+
const SYSTEM_QUERY = "(prefers-color-scheme: dark)";
|
|
5239
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
5240
|
+
const getSystemTheme = () => {
|
|
5241
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return "dark";
|
|
5242
|
+
return window.matchMedia(SYSTEM_QUERY).matches ? "dark" : "light";
|
|
5243
|
+
};
|
|
5244
|
+
const subscribeSystemTheme = (callback) => {
|
|
5245
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
|
|
5246
|
+
};
|
|
5247
|
+
const query = window.matchMedia(SYSTEM_QUERY);
|
|
5248
|
+
query.addEventListener("change", callback);
|
|
5249
|
+
return () => query.removeEventListener("change", callback);
|
|
5250
|
+
};
|
|
5251
|
+
const applyThemeClass = (target, resolved) => {
|
|
5252
|
+
target.classList.remove(resolved === "dark" ? "light" : "dark");
|
|
5253
|
+
target.classList.add(resolved);
|
|
5254
|
+
};
|
|
5255
|
+
const ThemeProvider = ({ children, defaultTheme = "system", storageKey, target }) => {
|
|
5256
|
+
const adapter = React.useMemo(() => createLocalStorageAdapter(storageKey), [storageKey]);
|
|
5257
|
+
const previousTargetRef = React.useRef(null);
|
|
5258
|
+
const [theme, setThemeState] = React.useState(() => adapter.get() ?? defaultTheme);
|
|
5259
|
+
const systemTheme = React.useSyncExternalStore(subscribeSystemTheme, getSystemTheme, () => "dark");
|
|
5260
|
+
React.useEffect(() => adapter.subscribe((next) => setThemeState(next ?? defaultTheme)), [adapter, defaultTheme]);
|
|
5261
|
+
const resolvedTheme = theme === "system" ? systemTheme : theme;
|
|
5262
|
+
useIsomorphicLayoutEffect(() => {
|
|
5263
|
+
const el = target ?? (typeof window === "undefined" ? null : window.document.documentElement);
|
|
5264
|
+
if (previousTargetRef.current && previousTargetRef.current !== el) {
|
|
5265
|
+
previousTargetRef.current.classList.remove("dark", "light");
|
|
5266
|
+
}
|
|
5267
|
+
if (el) applyThemeClass(el, resolvedTheme);
|
|
5268
|
+
previousTargetRef.current = el;
|
|
5269
|
+
}, [resolvedTheme, target]);
|
|
5270
|
+
const value = React.useMemo(
|
|
5271
|
+
() => ({
|
|
5272
|
+
theme,
|
|
5273
|
+
resolvedTheme,
|
|
5274
|
+
systemTheme,
|
|
5275
|
+
setTheme: (next) => {
|
|
5276
|
+
setThemeState(next);
|
|
5277
|
+
adapter.set(next);
|
|
5278
|
+
}
|
|
5279
|
+
}),
|
|
5280
|
+
[theme, resolvedTheme, systemTheme, adapter]
|
|
5281
|
+
);
|
|
5282
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value, children });
|
|
5283
|
+
};
|
|
5284
|
+
const noop = () => {
|
|
5285
|
+
};
|
|
5286
|
+
const useTheme = () => {
|
|
5287
|
+
const ctx = React.useContext(ThemeContext);
|
|
5288
|
+
const systemTheme = React.useSyncExternalStore(subscribeSystemTheme, getSystemTheme, () => "dark");
|
|
5289
|
+
return React.useMemo(
|
|
5290
|
+
() => ctx ?? { theme: "system", resolvedTheme: systemTheme, systemTheme, setTheme: noop },
|
|
5291
|
+
[ctx, systemTheme]
|
|
5292
|
+
);
|
|
5293
|
+
};
|
|
5210
5294
|
|
|
5211
5295
|
function buildDarkTheme$2() {
|
|
5212
5296
|
const baseTheme = codemirrorThemeDracula.draculaInit({
|
|
@@ -5397,7 +5481,7 @@ function buildLightTheme$2() {
|
|
|
5397
5481
|
return [editorTheme, language.syntaxHighlighting(highlightStyle)];
|
|
5398
5482
|
}
|
|
5399
5483
|
const useCodemirrorTheme$3 = () => {
|
|
5400
|
-
const isDark =
|
|
5484
|
+
const isDark = useTheme().resolvedTheme === "dark";
|
|
5401
5485
|
return React.useMemo(() => isDark ? buildDarkTheme$2() : buildLightTheme$2(), [isDark]);
|
|
5402
5486
|
};
|
|
5403
5487
|
const CodeEditor = React.forwardRef(
|
|
@@ -8408,6 +8492,81 @@ const Switch = React__namespace.forwardRef(({ className, ...props }, ref) => /*
|
|
|
8408
8492
|
));
|
|
8409
8493
|
Switch.displayName = SwitchPrimitives__namespace.Root.displayName;
|
|
8410
8494
|
|
|
8495
|
+
const DEFAULT_OPTIONS = [
|
|
8496
|
+
{ value: "system", label: "System", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Monitor, {}) },
|
|
8497
|
+
{ value: "light", label: "Light", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, {}) },
|
|
8498
|
+
{ value: "dark", label: "Dark", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, {}) }
|
|
8499
|
+
];
|
|
8500
|
+
const ITEM_WIDTH = 28;
|
|
8501
|
+
const ITEM_GAP = 2;
|
|
8502
|
+
const ThemeToggle = ({
|
|
8503
|
+
value,
|
|
8504
|
+
onChange,
|
|
8505
|
+
options = DEFAULT_OPTIONS,
|
|
8506
|
+
className,
|
|
8507
|
+
"aria-label": ariaLabel = "Theme",
|
|
8508
|
+
...rest
|
|
8509
|
+
}) => {
|
|
8510
|
+
const { theme, setTheme } = useTheme();
|
|
8511
|
+
const current = value ?? theme;
|
|
8512
|
+
const commit = onChange ?? setTheme;
|
|
8513
|
+
const effectiveCurrent = options.some((option) => option.value === current) ? current : options[0]?.value ?? "system";
|
|
8514
|
+
const handleChange = (next) => {
|
|
8515
|
+
const match = options.find((opt) => opt.value === next);
|
|
8516
|
+
if (match) commit(match.value);
|
|
8517
|
+
};
|
|
8518
|
+
const activeIndex = Math.max(
|
|
8519
|
+
0,
|
|
8520
|
+
options.findIndex((option) => option.value === effectiveCurrent)
|
|
8521
|
+
);
|
|
8522
|
+
const indicatorOffset = activeIndex * (ITEM_WIDTH + ITEM_GAP);
|
|
8523
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8524
|
+
RadioGroupPrimitive__namespace.Root,
|
|
8525
|
+
{
|
|
8526
|
+
...rest,
|
|
8527
|
+
value: effectiveCurrent,
|
|
8528
|
+
onValueChange: handleChange,
|
|
8529
|
+
orientation: "horizontal",
|
|
8530
|
+
"aria-label": ariaLabel,
|
|
8531
|
+
className: cn(
|
|
8532
|
+
"relative inline-flex w-fit items-center gap-0.5 rounded-full border border-border1 bg-surface3 p-0.5",
|
|
8533
|
+
className
|
|
8534
|
+
),
|
|
8535
|
+
children: [
|
|
8536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8537
|
+
"span",
|
|
8538
|
+
{
|
|
8539
|
+
"aria-hidden": "true",
|
|
8540
|
+
className: cn(
|
|
8541
|
+
"pointer-events-none absolute inset-y-0.5 left-0.5 rounded-full bg-surface5 motion-reduce:transition-none",
|
|
8542
|
+
transitions.transform
|
|
8543
|
+
),
|
|
8544
|
+
style: { width: ITEM_WIDTH, transform: `translateX(${indicatorOffset}px)` }
|
|
8545
|
+
}
|
|
8546
|
+
),
|
|
8547
|
+
options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8548
|
+
RadioGroupPrimitive__namespace.Item,
|
|
8549
|
+
{
|
|
8550
|
+
value: option.value,
|
|
8551
|
+
"aria-label": option.label,
|
|
8552
|
+
style: { width: ITEM_WIDTH },
|
|
8553
|
+
className: cn(
|
|
8554
|
+
"relative inline-flex h-6 cursor-pointer items-center justify-center rounded-full",
|
|
8555
|
+
"[&_svg]:size-3.5 text-icon3 hover:text-icon6 data-[state=checked]:text-icon6",
|
|
8556
|
+
"focus-visible:outline-hidden",
|
|
8557
|
+
"active:scale-90 motion-reduce:transition-none",
|
|
8558
|
+
transitions.colors,
|
|
8559
|
+
transitions.transform
|
|
8560
|
+
),
|
|
8561
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "pointer-events-none inline-flex items-center justify-center", children: option.icon })
|
|
8562
|
+
},
|
|
8563
|
+
option.value
|
|
8564
|
+
))
|
|
8565
|
+
]
|
|
8566
|
+
}
|
|
8567
|
+
);
|
|
8568
|
+
};
|
|
8569
|
+
|
|
8411
8570
|
function Truncate({
|
|
8412
8571
|
children,
|
|
8413
8572
|
untilChar,
|
|
@@ -10295,7 +10454,7 @@ function buildSideDialogLightTheme() {
|
|
|
10295
10454
|
return [editorTheme, language.syntaxHighlighting(highlightStyle)];
|
|
10296
10455
|
}
|
|
10297
10456
|
const useCodemirrorTheme$2 = () => {
|
|
10298
|
-
const isDark =
|
|
10457
|
+
const isDark = useTheme().resolvedTheme === "dark";
|
|
10299
10458
|
return React.useMemo(() => isDark ? buildSideDialogDarkTheme() : buildSideDialogLightTheme(), [isDark]);
|
|
10300
10459
|
};
|
|
10301
10460
|
function SideDialogCodeSection({ codeStr = "", title, icon, simplified = false }) {
|
|
@@ -10935,7 +11094,7 @@ function buildDiffLightTheme() {
|
|
|
10935
11094
|
function CodeDiff({ codeA, codeB }) {
|
|
10936
11095
|
const containerRef = React.useRef(null);
|
|
10937
11096
|
const viewRef = React.useRef(null);
|
|
10938
|
-
const isDark =
|
|
11097
|
+
const isDark = useTheme().resolvedTheme === "dark";
|
|
10939
11098
|
const theme = React.useMemo(() => isDark ? buildDiffDarkTheme() : buildDiffLightTheme(), [isDark]);
|
|
10940
11099
|
React.useEffect(() => {
|
|
10941
11100
|
if (!containerRef.current) return;
|
|
@@ -12925,7 +13084,7 @@ function buildLightTheme$1() {
|
|
|
12925
13084
|
return [editorTheme, language.syntaxHighlighting(highlightStyle)];
|
|
12926
13085
|
}
|
|
12927
13086
|
const useCodemirrorTheme$1 = () => {
|
|
12928
|
-
const isDark =
|
|
13087
|
+
const isDark = useTheme().resolvedTheme === "dark";
|
|
12929
13088
|
return React.useMemo(() => isDark ? buildDarkTheme$1() : buildLightTheme$1(), [isDark]);
|
|
12930
13089
|
};
|
|
12931
13090
|
function DataCodeSection({
|
|
@@ -13240,7 +13399,7 @@ function buildLightTheme() {
|
|
|
13240
13399
|
return [editorTheme, language.syntaxHighlighting(highlightStyle)];
|
|
13241
13400
|
}
|
|
13242
13401
|
const useCodemirrorTheme = () => {
|
|
13243
|
-
const isDark =
|
|
13402
|
+
const isDark = useTheme().resolvedTheme === "dark";
|
|
13244
13403
|
return React.useMemo(() => isDark ? buildDarkTheme() : buildLightTheme(), [isDark]);
|
|
13245
13404
|
};
|
|
13246
13405
|
function DataDetailsPanelCodeSection({
|
|
@@ -15006,6 +15165,18 @@ function generateDefaultValues(schema) {
|
|
|
15006
15165
|
return generateObjectDefaults(schema.properties, 0);
|
|
15007
15166
|
}
|
|
15008
15167
|
|
|
15168
|
+
const usePlaygroundStore = zustand.create()(
|
|
15169
|
+
middleware.persist(
|
|
15170
|
+
(set) => ({
|
|
15171
|
+
requestContext: {},
|
|
15172
|
+
setRequestContext: (requestContext) => set({ requestContext })
|
|
15173
|
+
}),
|
|
15174
|
+
{
|
|
15175
|
+
name: "mastra-playground-store"
|
|
15176
|
+
}
|
|
15177
|
+
)
|
|
15178
|
+
);
|
|
15179
|
+
|
|
15009
15180
|
const DATE_PRESETS = [
|
|
15010
15181
|
{ label: "Last 24 hours", value: "24h" },
|
|
15011
15182
|
{ label: "Last 3 days", value: "3d" },
|
|
@@ -19447,6 +19618,8 @@ exports.TextFieldBlock = TextFieldBlock;
|
|
|
19447
19618
|
exports.Textarea = Textarea;
|
|
19448
19619
|
exports.Th = Th;
|
|
19449
19620
|
exports.Thead = Thead;
|
|
19621
|
+
exports.ThemeProvider = ThemeProvider;
|
|
19622
|
+
exports.ThemeToggle = ThemeToggle;
|
|
19450
19623
|
exports.ThreadDeleteButton = ThreadDeleteButton;
|
|
19451
19624
|
exports.ThreadItem = ThreadItem;
|
|
19452
19625
|
exports.ThreadLink = ThreadLink;
|
|
@@ -19582,7 +19755,6 @@ exports.useCopyToClipboard = useCopyToClipboard;
|
|
|
19582
19755
|
exports.useEntityNames = useEntityNames;
|
|
19583
19756
|
exports.useEnvironments = useEnvironments;
|
|
19584
19757
|
exports.useInView = useInView;
|
|
19585
|
-
exports.useIsDarkMode = useIsDarkMode;
|
|
19586
19758
|
exports.useJSONSchemaForm = useJSONSchemaForm;
|
|
19587
19759
|
exports.useJSONSchemaFormField = useJSONSchemaFormField;
|
|
19588
19760
|
exports.useJSONSchemaFormNestedContext = useJSONSchemaFormNestedContext;
|
|
@@ -19603,6 +19775,7 @@ exports.useServiceNames = useServiceNames;
|
|
|
19603
19775
|
exports.useSpanDetail = useSpanDetail;
|
|
19604
19776
|
exports.useTableKeyboardNavigation = useTableKeyboardNavigation;
|
|
19605
19777
|
exports.useTags = useTags;
|
|
19778
|
+
exports.useTheme = useTheme;
|
|
19606
19779
|
exports.useTokenUsageByAgentMetrics = useTokenUsageByAgentMetrics;
|
|
19607
19780
|
exports.useTotalTokensKpiMetrics = useTotalTokensKpiMetrics;
|
|
19608
19781
|
exports.useTraceFilterPersistence = useTraceFilterPersistence;
|