@tpitre/story-ui 4.5.2 → 4.6.0
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/cli/index.js +5 -0
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +19 -5
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStoryStream.js +19 -5
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +182 -24
- package/dist/story-generator/selfHealingLoop.d.ts.map +1 -1
- package/dist/story-generator/selfHealingLoop.js +48 -17
- package/dist/story-generator/storyTracker.d.ts +12 -0
- package/dist/story-generator/storyTracker.d.ts.map +1 -1
- package/dist/story-generator/storyTracker.js +42 -0
- package/dist/story-generator/storyValidator.d.ts.map +1 -1
- package/dist/story-generator/storyValidator.js +0 -4
- package/dist/story-generator/validateStory.d.ts.map +1 -1
- package/dist/story-generator/validateStory.js +128 -0
- package/dist/templates/StoryUI/StoryUIPanel.css +1623 -0
- package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -1
- package/dist/templates/StoryUI/StoryUIPanel.js +46 -69
- package/dist/templates/StoryUI/StoryUIPanel.mdx +84 -0
- package/package.json +3 -2
- package/templates/StoryUI/StoryUIPanel.css +152 -54
- package/templates/StoryUI/StoryUIPanel.tsx +51 -75
|
@@ -881,101 +881,77 @@ function StoryUIPanel({ mcpPort }: StoryUIPanelProps) {
|
|
|
881
881
|
return () => clearInterval(intervalId);
|
|
882
882
|
}, []);
|
|
883
883
|
|
|
884
|
-
// Detect Storybook theme
|
|
884
|
+
// Detect Storybook MANAGER theme (not preview background)
|
|
885
|
+
// This ensures Story UI follows Storybook's overall theme, not the story preview background toggle
|
|
885
886
|
useEffect(() => {
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
//
|
|
891
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
892
|
-
const globals = urlParams.get('globals') || '';
|
|
893
|
-
const hasStorybookLightBg = globals.includes('backgrounds.value:light');
|
|
894
|
-
const hasStorybookDarkBg = globals.includes('backgrounds.value:dark') ||
|
|
895
|
-
globals.includes('backgrounds.value:%23') || // Hex colors starting with #
|
|
896
|
-
globals.includes('backgrounds.value:!hex');
|
|
897
|
-
|
|
898
|
-
// Check parent frame URL if we're in an iframe (Storybook 8+)
|
|
899
|
-
let parentHasDarkBg = false;
|
|
900
|
-
let parentHasLightBg = false;
|
|
901
|
-
let parentHasDarkClass = false;
|
|
887
|
+
const detectManagerTheme = () => {
|
|
888
|
+
let managerIsDark = false;
|
|
889
|
+
|
|
890
|
+
// Strategy 1: Check parent frame for Storybook manager theme (Storybook 8+)
|
|
891
|
+
// The manager theme is set in .storybook/manager.tsx via addons.setConfig({ theme: themes.dark })
|
|
902
892
|
try {
|
|
903
893
|
if (window.parent !== window) {
|
|
904
|
-
const parentUrl = new URL(window.parent.location.href);
|
|
905
|
-
const parentGlobals = parentUrl.searchParams.get('globals') || '';
|
|
906
|
-
parentHasLightBg = parentGlobals.includes('backgrounds.value:light');
|
|
907
|
-
parentHasDarkBg = parentGlobals.includes('backgrounds.value:dark') ||
|
|
908
|
-
parentGlobals.includes('backgrounds.value:%23');
|
|
909
|
-
// Check parent document for Storybook dark theme classes
|
|
910
894
|
const parentBody = window.parent.document.body;
|
|
911
895
|
const parentHtml = window.parent.document.documentElement;
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
896
|
+
|
|
897
|
+
// Check for Storybook's dark theme class (most reliable)
|
|
898
|
+
if (parentBody.classList.contains('sb-dark') ||
|
|
899
|
+
parentHtml.classList.contains('sb-dark') ||
|
|
900
|
+
parentHtml.getAttribute('data-theme') === 'dark' ||
|
|
901
|
+
parentBody.getAttribute('data-theme') === 'dark') {
|
|
902
|
+
managerIsDark = true;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Check Storybook manager sidebar/header background color as fallback
|
|
906
|
+
// The manager UI elements use the theme colors, not the preview background
|
|
907
|
+
const managerEl = window.parent.document.querySelector('.sb-sidebar, [class*="sidebar"], .sb-bar');
|
|
908
|
+
if (managerEl && !managerIsDark) {
|
|
909
|
+
const bgColor = window.getComputedStyle(managerEl).backgroundColor;
|
|
910
|
+
const rgb = bgColor.match(/\d+/g);
|
|
911
|
+
if (rgb && rgb.length >= 3) {
|
|
912
|
+
const luminance = (0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2])) / 255;
|
|
913
|
+
managerIsDark = luminance < 0.5;
|
|
924
914
|
}
|
|
925
915
|
}
|
|
926
916
|
}
|
|
927
917
|
} catch {
|
|
928
|
-
// Cross-origin access not allowed,
|
|
918
|
+
// Cross-origin access not allowed, fall back to system preference
|
|
929
919
|
}
|
|
930
920
|
|
|
931
|
-
//
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
if (rgb && rgb.length >= 3) {
|
|
936
|
-
const luminance = (0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2])) / 255;
|
|
937
|
-
isBackgroundDark = luminance < 0.5;
|
|
921
|
+
// Strategy 2: If not in iframe or can't detect, use system preference
|
|
922
|
+
if (!managerIsDark) {
|
|
923
|
+
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
924
|
+
managerIsDark = systemPrefersDark;
|
|
938
925
|
}
|
|
939
926
|
|
|
940
|
-
|
|
941
|
-
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
942
|
-
|
|
943
|
-
// Explicit light mode takes precedence - if user selected "light" in Storybook, respect that
|
|
944
|
-
const hasExplicitLightMode = hasStorybookLightBg || parentHasLightBg;
|
|
945
|
-
|
|
946
|
-
// Explicit dark mode indicators
|
|
947
|
-
const hasExplicitDarkMode =
|
|
948
|
-
body.classList.contains('sb-dark') ||
|
|
949
|
-
html.classList.contains('dark') ||
|
|
950
|
-
html.getAttribute('data-theme') === 'dark' ||
|
|
951
|
-
body.getAttribute('data-theme') === 'dark' ||
|
|
952
|
-
hasStorybookDarkBg ||
|
|
953
|
-
parentHasDarkBg;
|
|
954
|
-
|
|
955
|
-
// Determine dark mode: explicit light mode forces light, otherwise check dark indicators
|
|
956
|
-
const isDark = hasExplicitLightMode
|
|
957
|
-
? false
|
|
958
|
-
: (hasExplicitDarkMode || parentHasDarkClass || isBackgroundDark || systemPrefersDark);
|
|
959
|
-
dispatch({ type: 'SET_DARK_MODE', payload: isDark });
|
|
927
|
+
dispatch({ type: 'SET_DARK_MODE', payload: managerIsDark });
|
|
960
928
|
};
|
|
961
|
-
detectTheme();
|
|
962
929
|
|
|
963
|
-
|
|
964
|
-
window.addEventListener('popstate', detectTheme);
|
|
930
|
+
detectManagerTheme();
|
|
965
931
|
|
|
966
|
-
// Poll for changes
|
|
967
|
-
const intervalId = setInterval(
|
|
932
|
+
// Poll for changes (manager theme changes are rare but possible)
|
|
933
|
+
const intervalId = setInterval(detectManagerTheme, 1000);
|
|
968
934
|
|
|
969
|
-
|
|
970
|
-
observer.observe(document.body, { attributes: true, attributeFilter: ['class', 'data-theme', 'style'] });
|
|
971
|
-
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme', 'style'] });
|
|
935
|
+
// Listen for system preference changes
|
|
972
936
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
973
|
-
mediaQuery.addEventListener('change',
|
|
937
|
+
mediaQuery.addEventListener('change', detectManagerTheme);
|
|
938
|
+
|
|
939
|
+
// Observe parent document for theme changes if accessible
|
|
940
|
+
let parentObserver: MutationObserver | null = null;
|
|
941
|
+
try {
|
|
942
|
+
if (window.parent !== window) {
|
|
943
|
+
parentObserver = new MutationObserver(detectManagerTheme);
|
|
944
|
+
parentObserver.observe(window.parent.document.body, { attributes: true, attributeFilter: ['class', 'data-theme'] });
|
|
945
|
+
parentObserver.observe(window.parent.document.documentElement, { attributes: true, attributeFilter: ['class', 'data-theme'] });
|
|
946
|
+
}
|
|
947
|
+
} catch {
|
|
948
|
+
// Cross-origin, ignore
|
|
949
|
+
}
|
|
950
|
+
|
|
974
951
|
return () => {
|
|
975
|
-
window.removeEventListener('popstate', detectTheme);
|
|
976
952
|
clearInterval(intervalId);
|
|
977
|
-
|
|
978
|
-
|
|
953
|
+
mediaQuery.removeEventListener('change', detectManagerTheme);
|
|
954
|
+
parentObserver?.disconnect();
|
|
979
955
|
};
|
|
980
956
|
}, []);
|
|
981
957
|
|