Merge pull request #32575 from backstage/fix/nextjs16-css-modules

Fix CSS Module purity errors for Next.js 16 compatibility
This commit is contained in:
Charles de Dreuille
2026-01-30 14:54:43 +00:00
committed by GitHub
19 changed files with 7786 additions and 345 deletions
-8
View File
@@ -1,8 +0,0 @@
{
"extends": ["next/core-web-vitals", "next/typescript"],
"rules": {
"notice/notice": "off",
"react/forbid-elements": "off",
"jsx-a11y/alt-text": "off"
}
}
+16
View File
@@ -0,0 +1,16 @@
import { defineConfig, globalIgnores } from 'eslint/config';
import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
const eslintConfig = defineConfig([
...nextCoreWebVitals,
globalIgnores(['.next/**', 'dist/**', 'node_modules/**']),
{
rules: {
'notice/notice': 'off',
'react/forbid-elements': 'off',
'jsx-a11y/alt-text': 'off',
},
},
]);
export default eslintConfig;
+2 -2
View File
@@ -5,7 +5,7 @@
"scripts": {
"prebuild": "yarn sync:css",
"build": "next build",
"lint": "next lint",
"lint": "eslint .",
"prestart": "yarn sync:css",
"start": "next dev",
"sync:changelog": "node scripts/sync-changelog.mjs",
@@ -47,7 +47,7 @@
"@types/react": "19.2.10",
"@types/react-dom": "19.2.3",
"chokidar": "^3.6.0",
"eslint": "^8",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"lightningcss": "^1.28.2",
"typescript": "^5",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env node
/* eslint-disable no-restricted-syntax */
import fs from 'fs';
import path from 'path';
+6 -6
View File
@@ -6,7 +6,7 @@ const chokidar = require('chokidar');
// Configuration
const config = {
UIPath: '../../packages/ui',
publicPath: '../public',
outputPath: '../src/css',
files: [
{
source: 'css/styles.css',
@@ -24,13 +24,13 @@ const config = {
class CSSSync {
constructor() {
this.UIPath = path.resolve(__dirname, config.UIPath);
this.publicPath = path.resolve(__dirname, config.publicPath);
this.outputPath = path.resolve(__dirname, config.outputPath);
this.isWatching = process.argv.includes('--watch');
}
async syncFile(fileConfig) {
const sourcePath = path.join(this.UIPath, fileConfig.source);
const destPath = path.join(this.publicPath, fileConfig.destination);
const destPath = path.join(this.outputPath, fileConfig.destination);
try {
// Check if source file exists
@@ -76,9 +76,9 @@ class CSSSync {
);
if (successCount > 0) {
console.log('\n📁 Available CSS files in public/:');
console.log('\n📁 Available CSS files in src/css/:');
config.files.forEach(file => {
const destPath = path.join(this.publicPath, file.destination);
const destPath = path.join(this.outputPath, file.destination);
if (fs.existsSync(destPath)) {
const stats = fs.statSync(destPath);
const size = (stats.size / 1024).toFixed(2);
@@ -129,7 +129,7 @@ class CSSSync {
async run() {
console.log('🎨 BUI CSS Sync Tool\n');
console.log(`📂 BUI path: ${this.UIPath}`);
console.log(`📂 Public path: ${this.publicPath}\n`);
console.log(`📂 Output path: ${this.outputPath}\n`);
// Initial sync
await this.syncAll();
+2 -2
View File
@@ -8,8 +8,8 @@ import { MobileBottomNav } from '@/components/MobileBottomNav';
import styles from './layout.module.css';
import '../css/globals.css';
import '/public/theme-backstage.css';
import '/public/theme-spotify.css';
import '../css/theme-backstage.css';
import '../css/theme-spotify.css';
export const metadata: Metadata = {
title: 'Backstage UI',
@@ -1,6 +1,6 @@
'use client';
import { useEffect, useState, useCallback } from 'react';
import { useEffect, useState, useCallback, useSyncExternalStore } from 'react';
import CodeMirror from '@uiw/react-codemirror';
import { sass } from '@codemirror/lang-sass';
import styles from './styles.module.css';
@@ -14,6 +14,10 @@ const defaultTheme = `:root {
--bui-bg-solid: #000;
}`;
// Stable server snapshots for useSyncExternalStore
const serverIsClient = false;
const serverDefaultTheme = defaultTheme;
const myTheme = createTheme({
theme: 'light',
settings: {
@@ -46,12 +50,41 @@ const myTheme = createTheme({
});
export const CustomTheme = () => {
const [isClient, setIsClient] = useState(false);
const [open, setOpen] = useState(true);
const [customTheme, setCustomTheme] = useState<string | undefined>(undefined);
const { selectedThemeName } = usePlayground();
const [savedMessage, setSavedMessage] = useState<string>('Save');
// SSR-safe client detection
const isClient = useSyncExternalStore(
() => () => {},
() => true,
() => serverIsClient,
);
// SSR-safe localStorage access for custom theme
const customThemeFromStorage = useSyncExternalStore(
callback => {
window.addEventListener('storage', callback);
return () => window.removeEventListener('storage', callback);
},
() => {
const stored = localStorage.getItem('customThemeCss');
if (!stored) {
localStorage.setItem('customThemeCss', defaultTheme);
return defaultTheme;
}
return stored;
},
() => serverDefaultTheme,
);
const [customTheme, setCustomTheme] = useState(customThemeFromStorage);
// Sync from storage when it changes
useEffect(() => {
setCustomTheme(customThemeFromStorage);
}, [customThemeFromStorage]);
const updateStyleElement = (theme: string) => {
let styleElement = document.getElementById(
'custom-theme-style',
@@ -66,16 +99,11 @@ export const CustomTheme = () => {
styleElement.textContent = theme;
};
// Apply custom theme to DOM
useEffect(() => {
if (selectedThemeName === 'custom') {
let storedTheme = localStorage.getItem('customThemeCss');
if (!storedTheme) {
storedTheme = defaultTheme;
localStorage.setItem('customThemeCss', storedTheme);
}
setCustomTheme(storedTheme);
updateStyleElement(storedTheme);
} else {
if (selectedThemeName === 'custom' && customTheme && isClient) {
updateStyleElement(customTheme);
} else if (isClient) {
const styleElement = document.getElementById(
'custom-theme-style',
) as HTMLStyleElement;
@@ -83,11 +111,7 @@ export const CustomTheme = () => {
styleElement.remove();
}
}
}, [selectedThemeName]);
useEffect(() => {
setIsClient(true);
}, []);
}, [selectedThemeName, customTheme, isClient]);
const handleSave = () => {
if (customTheme) {
@@ -1,6 +1,6 @@
'use client';
import { useEffect, useState } from 'react';
import { useEffect, useState, useLayoutEffect } from 'react';
import { usePathname } from 'next/navigation';
import styles from './TableOfContents.module.css';
@@ -17,6 +17,29 @@ export function TableOfContents() {
const [indicatorHeight, setIndicatorHeight] = useState<number>(0);
const pathname = usePathname();
// Update indicator position when activeId changes
useLayoutEffect(() => {
if (!activeId) return;
// Use requestAnimationFrame to defer setState call
const rafId = requestAnimationFrame(() => {
const activeElement = document.querySelector(
`[data-toc-id="${activeId}"]`,
) as HTMLElement;
if (activeElement) {
const list = activeElement.closest('ul');
if (list) {
const listRect = list.getBoundingClientRect();
const elementRect = activeElement.getBoundingClientRect();
setIndicatorTop(elementRect.top - listRect.top);
setIndicatorHeight(elementRect.height);
}
}
});
return () => cancelAnimationFrame(rafId);
}, [activeId, headings]);
useEffect(() => {
// Extract all H2 and H3 headings from the document
const elements = Array.from(
@@ -29,18 +52,6 @@ export function TableOfContents() {
level: parseInt(element.tagName.substring(1)),
}));
setHeadings(headingData);
// Set initial active heading (first visible heading or first heading)
if (headingData.length > 0) {
const viewportTop = window.scrollY + 100; // offset for header
const visibleHeading = elements.find(element => {
const rect = element.getBoundingClientRect();
return rect.top + window.scrollY >= viewportTop - 200;
});
setActiveId(visibleHeading?.id || headingData[0].id);
}
// Set up IntersectionObserver to track visible headings
const observerOptions = {
rootMargin: '-80px 0px -80% 0px',
@@ -62,29 +73,26 @@ export function TableOfContents() {
elements.forEach(element => observer.observe(element));
// Initialize headings and active ID after observer is set up
requestAnimationFrame(() => {
setHeadings(headingData);
// Set initial active heading (first visible heading or first heading)
if (headingData.length > 0) {
const viewportTop = window.scrollY + 100; // offset for header
const visibleHeading = elements.find(element => {
const rect = element.getBoundingClientRect();
return rect.top + window.scrollY >= viewportTop - 200;
});
setActiveId(visibleHeading?.id || headingData[0].id);
}
});
return () => {
elements.forEach(element => observer.unobserve(element));
};
}, [pathname]);
// Update indicator position when activeId changes
useEffect(() => {
if (activeId) {
const activeElement = document.querySelector(
`[data-toc-id="${activeId}"]`,
) as HTMLElement;
if (activeElement) {
const list = activeElement.closest('ul');
if (list) {
const listRect = list.getBoundingClientRect();
const elementRect = activeElement.getBoundingClientRect();
setIndicatorTop(elementRect.top - listRect.top);
setIndicatorHeight(elementRect.height);
}
}
}
}, [activeId, headings]);
const handleClick = (id: string) => {
const element = document.getElementById(id);
if (element) {
File diff suppressed because it is too large Load Diff
+243
View File
@@ -0,0 +1,243 @@
@font-face {
font-family: CircularSpTitle;
font-weight: 900;
font-display: swap;
unicode-range: U+0, U+D, U+20-7E, U+A0-17E, U+18F, U+192, U+1A0-1A1, U+1AF-1B0,
U+1B5-1B6, U+1C4-1C6, U+1F1-1F3, U+1FA-1FF, U+218-21B, U+237, U+259,
U+2BB-2BC, U+2C6-2C7, U+2C9, U+2D8-2DD, U+300-301, U+303, U+309, U+323,
U+394, U+3A9, U+3BC, U+3C0, U+1E80-1E85, U+1E8A-1E8B, U+1EA0-1EF9, U+1FD6,
U+2007-2008, U+200B, U+2010-2011, U+2013-2014, U+2018-201A, U+201C-201E,
U+2020-2022, U+2026, U+2030, U+2032-2033, U+2039-203A, U+2042, U+2044,
U+2051, U+2070, U+2074-2079, U+2080-2089, U+20AB-20AC, U+2113, U+2117,
U+2122, U+2126, U+2160-2169, U+216C-216F, U+2190-2193, U+2196-2199, U+21A9,
U+21B0-21B5, U+21C6, U+2202, U+2206, U+220F, U+2211-2212, U+2215,
U+2219-221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+22C5, U+24C5,
U+25A0-25A1, U+25AF, U+25B2-25B3, U+25CA-25CB, U+25CF, U+262E, U+2713,
U+2715, U+2780-2788, U+E000, U+E002, U+F6C3, U+FB00-FB04, U+FEFF, U+FF0C,
U+FF0E, U+FF1A-FF1B, U+FFFF;
src: url(https://encore.scdn.co/fonts/CircularSpTitle-Black-4588c99025b967475c31695b0743dd1a.woff2)
format('woff2'),
url(https://encore.scdn.co/fonts/CircularSpTitle-Black-506746f387a26f25aa3d023b3e501d34.woff)
format('woff');
}
@font-face {
font-family: CircularSpTitle;
font-weight: 700;
font-display: swap;
unicode-range: U+0, U+D, U+20-7E, U+A0-17E, U+18F, U+192, U+1A0-1A1, U+1AF-1B0,
U+1B5-1B6, U+1C4-1C6, U+1F1-1F3, U+1FA-1FF, U+218-21B, U+237, U+259,
U+2BB-2BC, U+2C6-2C7, U+2C9, U+2D8-2DD, U+300-301, U+303, U+309, U+323,
U+394, U+3A9, U+3BC, U+3C0, U+1E80-1E85, U+1E8A-1E8B, U+1EA0-1EF9, U+1FD6,
U+2007-2008, U+200B, U+2010-2011, U+2013-2014, U+2018-201A, U+201C-201E,
U+2020-2022, U+2026, U+2030, U+2032-2033, U+2039-203A, U+2042, U+2044,
U+2051, U+2070, U+2074-2079, U+2080-2089, U+20AB-20AC, U+2113, U+2117,
U+2122, U+2126, U+2160-2169, U+216C-216F, U+2190-2193, U+2196-2199, U+21A9,
U+21B0-21B5, U+21C6, U+2202, U+2206, U+220F, U+2211-2212, U+2215,
U+2219-221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+22C5, U+24C5,
U+25A0-25A1, U+25AF, U+25B2-25B3, U+25CA-25CB, U+25CF, U+262E, U+2713,
U+2715, U+2780-2788, U+E000, U+E002, U+F6C3, U+FB00-FB04, U+FEFF, U+FF0C,
U+FF0E, U+FF1A-FF1B, U+FFFF;
src: url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-b2586b06a2e1522e9d879d84c2792a58.woff2)
format('woff2'),
url(https://encore.scdn.co/fonts/CircularSpTitle-Bold-1624fb2df28c20d7203d7fb86ce8b481.woff)
format('woff');
}
@font-face {
font-family: CircularSp;
font-weight: 700;
font-display: swap;
unicode-range: U+0, U+D, U+20-7E, U+A0-17E, U+18F, U+192, U+1A0-1A1, U+1AF-1B0,
U+1B5-1B6, U+1C4-1C6, U+1F1-1F3, U+1FA-1FF, U+218-21B, U+237, U+259,
U+2BB-2BC, U+2C6-2C7, U+2C9, U+2D8-2DD, U+300-301, U+303, U+309, U+323,
U+394, U+3A9, U+3BC, U+3C0, U+1E80-1E85, U+1E8A-1E8B, U+1EA0-1EF9, U+1FD6,
U+2007-2008, U+200B, U+2010-2011, U+2013-2014, U+2018-201A, U+201C-201E,
U+2020-2022, U+2026, U+2030, U+2032-2033, U+2039-203A, U+2042, U+2044,
U+2051, U+2070, U+2074-2079, U+2080-2089, U+20AB-20AC, U+2113, U+2117,
U+2122, U+2126, U+2160-2169, U+216C-216F, U+2190-2193, U+2196-2199, U+21A9,
U+21B0-21B5, U+21C6, U+2202, U+2206, U+220F, U+2211-2212, U+2215,
U+2219-221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+22C5, U+24C5,
U+25A0-25A1, U+25AF, U+25B2-25B3, U+25CA-25CB, U+25CF, U+262E, U+2713,
U+2715, U+2780-2788, U+E000, U+E002, U+F6C3, U+FB00-FB04, U+FEFF, U+FF0C,
U+FF0E, U+FF1A-FF1B, U+FFFF;
src: url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)
format('woff2'),
url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)
format('woff');
}
@font-face {
font-family: CircularSp;
font-weight: 400;
font-display: swap;
unicode-range: U+0, U+D, U+20-7E, U+A0-17E, U+18F, U+192, U+1A0-1A1, U+1AF-1B0,
U+1B5-1B6, U+1C4-1C6, U+1F1-1F3, U+1FA-1FF, U+218-21B, U+237, U+259,
U+2BB-2BC, U+2C6-2C7, U+2C9, U+2D8-2DD, U+300-301, U+303, U+309, U+323,
U+394, U+3A9, U+3BC, U+3C0, U+1E80-1E85, U+1E8A-1E8B, U+1EA0-1EF9, U+1FD6,
U+2007-2008, U+200B, U+2010-2011, U+2013-2014, U+2018-201A, U+201C-201E,
U+2020-2022, U+2026, U+2030, U+2032-2033, U+2039-203A, U+2042, U+2044,
U+2051, U+2070, U+2074-2079, U+2080-2089, U+20AB-20AC, U+2113, U+2117,
U+2122, U+2126, U+2160-2169, U+216C-216F, U+2190-2193, U+2196-2199, U+21A9,
U+21B0-21B5, U+21C6, U+2202, U+2206, U+220F, U+2211-2212, U+2215,
U+2219-221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+22C5, U+24C5,
U+25A0-25A1, U+25AF, U+25B2-25B3, U+25CA-25CB, U+25CF, U+262E, U+2713,
U+2715, U+2780-2788, U+E000, U+E002, U+F6C3, U+FB00-FB04, U+FEFF, U+FF0C,
U+FF0E, U+FF1A-FF1B, U+FFFF;
src: url(https://encore.scdn.co/fonts/CircularSp-Book-a00e99ef9996a3a157fb6b746856d04f.woff2)
format('woff2'),
url(https://encore.scdn.co/fonts/CircularSp-Book-3f73da7d35bd81c706bce7bbb84964de.woff)
format('woff');
}
@font-face {
font-family: CircularSp;
font-weight: 700;
font-display: swap;
unicode-range: U+0, U+D, U+20-7E, U+A0-17E, U+18F, U+192, U+1A0-1A1, U+1AF-1B0,
U+1B5-1B6, U+1C4-1C6, U+1F1-1F3, U+1FA-1FF, U+218-21B, U+237, U+259,
U+2BB-2BC, U+2C6-2C7, U+2C9, U+2D8-2DD, U+300-301, U+303, U+309, U+323,
U+394, U+3A9, U+3BC, U+3C0, U+1E80-1E85, U+1E8A-1E8B, U+1EA0-1EF9, U+1FD6,
U+2007-2008, U+200B, U+2010-2011, U+2013-2014, U+2018-201A, U+201C-201E,
U+2020-2022, U+2026, U+2030, U+2032-2033, U+2039-203A, U+2042, U+2044,
U+2051, U+2070, U+2074-2079, U+2080-2089, U+20AB-20AC, U+2113, U+2117,
U+2122, U+2126, U+2160-2169, U+216C-216F, U+2190-2193, U+2196-2199, U+21A9,
U+21B0-21B5, U+21C6, U+2202, U+2206, U+220F, U+2211-2212, U+2215,
U+2219-221A, U+221E, U+222B, U+2248, U+2260, U+2264-2265, U+22C5, U+24C5,
U+25A0-25A1, U+25AF, U+25B2-25B3, U+25CA-25CB, U+25CF, U+262E, U+2713,
U+2715, U+2780-2788, U+E000, U+E002, U+F6C3, U+FB00-FB04, U+FEFF, U+FF0C,
U+FF0E, U+FF1A-FF1B, U+FFFF;
src: url(https://encore.scdn.co/fonts/CircularSp-Bold-602e7aefc706aa36c6ec1324b9bbc461.woff2)
format('woff2'),
url(https://encore.scdn.co/fonts/CircularSp-Bold-856afe2da4ba4e61239b129e2c16d633.woff)
format('woff');
}
[data-theme-name='spotify'] {
--bui-font-text: CircularSp, CircularSp-Arab, CircularSp-Hebr, CircularSp-Cyrl,
CircularSp-Grek, CircularSp-Deva;
--bui-font-title: CircularSpTitle, CircularSp-Arab, CircularSp-Hebr,
CircularSp-Cyrl, CircularSp-Grek, CircularSp-Deva;
--bui-font-regular: CircularSp, CircularSp-Arab, CircularSp-Hebr,
CircularSp-Cyrl, CircularSp-Grek, CircularSp-Deva;
& .bui-Button {
border-radius: var(--bui-radius-3);
padding-inline: var(--bui-space-3);
}
& .bui-ButtonIcon {
padding: 0;
}
& .bui-MenuPopup {
box-sizing: border-box;
max-width: 21.25rem;
}
& .bui-MenuSubmenuTrigger,
& .bui-MenuItem {
height: auto;
min-height: 2rem;
}
& .bui-Text {
font-family: var(--bui-font-text);
}
& .bui-Heading {
font-family: var(--bui-font-title);
}
& .bui-TableRow {
border-radius: var(--bui-radius-4);
border: none;
}
& .bui-TableRow:hover td:first-child {
border-top-left-radius: var(--bui-radius-2);
border-bottom-left-radius: var(--bui-radius-2);
}
& .bui-TableRow:hover td:last-child {
border-top-right-radius: var(--bui-radius-2);
border-bottom-right-radius: var(--bui-radius-2);
}
& .bui-TableBody:before,
& .bui-TableBody:after {
line-height: var(--bui-space-1);
content: '';
display: block;
}
& .bui-TableHeader .bui-TableRow {
border-bottom: 1px solid var(--bui-border);
}
& .bui-TableHead {
font-size: var(--bui-font-size-2);
color: var(--bui-fg-secondary);
font-weight: var(--bui-font-weight-regular);
}
& .bui-HeaderToolbar {
padding-top: var(--bui-space-2);
padding-inline: var(--bui-space-2);
}
& .bui-HeaderToolbarWrapper {
border-radius: var(--bui-radius-3);
padding-inline: var(--bui-space-3);
border: none;
}
& .bui-HeaderToolbarControls {
right: calc(var(--bui-space-3) - 1px);
}
& .bui-HeaderTabsWrapper {
margin-top: var(--bui-space-2);
margin-inline: var(--bui-space-2);
border-radius: var(--bui-radius-3);
padding-inline: var(--bui-space-1);
border: none;
}
& .bui-Input {
border-radius: var(--bui-radius-3);
}
& .bui-Tag {
border-radius: var(--bui-radius-full);
}
}
[data-theme-mode='light'][data-theme-name='spotify'] {
--bui-bg-solid: #1ed760;
--bui-bg-solid-hover: #3be477;
--bui-bg-solid-pressed: #1abc54;
--bui-bg-solid-disabled: #0f6c30;
--bui-fg-primary: var(--bui-black);
--bui-fg-secondary: var(--bui-gray-7);
--bui-fg-solid: var(--bui-black);
--bui-fg-solid-disabled: #62ab7c;
--bui-border: var(--bui-gray-3);
--bui-border-hover: #0000004d;
--bui-border-pressed: #00000080;
--bui-border-disabled: #0000001a;
--bui-border-danger: #f87a7a;
--bui-border-warning: #e36d05;
--bui-border-success: #53db83;
--bui-ring: #0003;
& .bui-HeaderToolbarWrapper,
& .bui-HeaderTabsWrapper {
border: 1px solid var(--bui-border);
}
}
[data-theme-mode='dark'][data-theme-name='spotify'] {
--bui-bg-surface-0: var(--bui-black);
--bui-bg-solid: #1ed760;
--bui-bg-solid-hover: #3be477;
--bui-bg-solid-pressed: #1abc54;
--bui-bg-solid-disabled: #0f6c30;
--bui-bg-danger: #3b1219;
--bui-bg-warning: #302008;
--bui-bg-success: #132d21;
--bui-fg-primary: var(--bui-white);
--bui-fg-secondary: var(--bui-gray-7);
--bui-fg-link: var(--bui-white);
--bui-fg-link-hover: var(--bui-white);
--bui-fg-disabled: var(--bui-gray-5);
--bui-fg-solid: var(--bui-black);
--bui-fg-solid-disabled: #072f15;
--bui-fg-tint: var(--bui-white);
--bui-fg-tint-disabled: var(--bui-gray-5);
--bui-fg-danger: #e22b2b;
--bui-fg-warning: #e36d05;
--bui-fg-success: #1db954;
--bui-border: var(--bui-gray-3);
--bui-border-hover: #fff6;
--bui-border-pressed: #ffffff80;
--bui-border-disabled: #fff3;
--bui-border-danger: #f87a7a;
--bui-border-warning: #e36d05;
--bui-border-success: #53db83;
--bui-ring: #fff3;
}
+68 -44
View File
@@ -4,6 +4,7 @@ import {
ReactNode,
useState,
useEffect,
useSyncExternalStore,
} from 'react';
import { components } from './data';
@@ -31,6 +32,14 @@ const PlaygroundContext = createContext<{
setSelectedThemeName: () => {},
});
// Stable server snapshots (outside component to avoid recreating)
const defaultThemeSet = new Set<Theme>(['light']);
const defaultThemeName: ThemeName = 'backstage';
// Cache for theme Sets to avoid creating new objects on every getSnapshot call
let cachedThemeValue: string | null = null;
let cachedThemeSet: Set<Theme> = defaultThemeSet;
// Create a provider component
export const PlaygroundProvider = ({ children }: { children: ReactNode }) => {
// Check if running in a browser environment
@@ -40,57 +49,72 @@ export const PlaygroundProvider = ({ children }: { children: ReactNode }) => {
const [selectedComponents, setSelectedComponents] = useState<string[]>(
components.map(component => component.slug),
);
const [selectedTheme, setSelectedTheme] = useState<Set<Theme>>(
new Set(['light']),
);
const [selectedThemeName, setSelectedThemeName] =
useState<ThemeName>('backstage');
// Load saved theme from localStorage after hydration
useEffect(() => {
if (isBrowser) {
const savedThemeString = localStorage.getItem('theme-mode');
if (savedThemeString) {
// Parse the comma-separated string back into a Set
const themeArray = savedThemeString
.split(',')
.filter(Boolean) as Theme[];
setSelectedTheme(new Set(themeArray));
// Use useSyncExternalStore for SSR-safe localStorage access
const selectedTheme = useSyncExternalStore(
callback => {
window.addEventListener('storage', callback);
return () => window.removeEventListener('storage', callback);
},
() => {
const saved = localStorage.getItem('theme-mode');
// Return cached Set if value hasn't changed
if (saved === cachedThemeValue) {
return cachedThemeSet;
}
// Update cache with new value
cachedThemeValue = saved;
if (saved) {
const themeArray = saved.split(',').filter(Boolean) as Theme[];
cachedThemeSet = new Set(themeArray);
} else {
setSelectedTheme(new Set(['light']));
cachedThemeSet = defaultThemeSet;
}
}
}, [isBrowser]);
// Load saved theme name from localStorage after hydration
return cachedThemeSet;
},
() => defaultThemeSet, // Stable server snapshot
);
const selectedThemeName = useSyncExternalStore(
callback => {
window.addEventListener('storage', callback);
return () => window.removeEventListener('storage', callback);
},
() => {
const saved = localStorage.getItem('theme-name') as ThemeName;
return saved || defaultThemeName;
},
() => defaultThemeName, // Stable server snapshot
);
// Keep setter functions that update both state and localStorage
const setSelectedTheme = (keys: Set<Theme>) => {
const value = Array.from(keys).join(',');
localStorage.setItem('theme-mode', value);
// Invalidate cache
cachedThemeValue = null;
window.dispatchEvent(new Event('storage'));
};
const setSelectedThemeName = (name: ThemeName) => {
localStorage.setItem('theme-name', name);
window.dispatchEvent(new Event('storage'));
};
// Sync to DOM attributes when values change
useEffect(() => {
if (isBrowser) {
const savedThemeName = localStorage.getItem('theme-name') as ThemeName;
if (savedThemeName) {
setSelectedThemeName(savedThemeName);
}
}
}, [isBrowser]);
document.documentElement.setAttribute(
'data-theme-mode',
Array.from(selectedTheme).join(','),
);
}, [selectedTheme]);
useEffect(() => {
if (isBrowser) {
document.documentElement.setAttribute(
'data-theme-mode',
Array.from(selectedTheme).join(','),
);
localStorage.setItem('theme-mode', Array.from(selectedTheme).join(','));
}
}, [selectedTheme, isBrowser]);
useEffect(() => {
if (isBrowser) {
document.documentElement.setAttribute(
'data-theme-name',
selectedThemeName || 'backstage',
);
localStorage.setItem('theme-name', selectedThemeName || 'backstage');
}
}, [selectedThemeName, isBrowser]);
document.documentElement.setAttribute('data-theme-name', selectedThemeName);
}, [selectedThemeName]);
return (
<PlaygroundContext.Provider
+2 -1
View File
@@ -30,7 +30,8 @@
".next/types/**/*.ts",
"dist/types/**/*.ts",
"src/types/**/*.d.ts",
"dist/dev/types/**/*.ts"
"dist/dev/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules"]
}
+152 -204
View File
@@ -375,7 +375,7 @@ __metadata:
languageName: node
linkType: hard
"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.9.1":
"@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1":
version: 4.9.1
resolution: "@eslint-community/eslint-utils@npm:4.9.1"
dependencies:
@@ -386,34 +386,80 @@ __metadata:
languageName: node
linkType: hard
"@eslint-community/regexpp@npm:^4.12.2, @eslint-community/regexpp@npm:^4.6.1":
"@eslint-community/regexpp@npm:^4.12.1, @eslint-community/regexpp@npm:^4.12.2":
version: 4.12.2
resolution: "@eslint-community/regexpp@npm:4.12.2"
checksum: 10/049b280fddf71dd325514e0a520024969431dc3a8b02fa77476e6820e9122f28ab4c9168c11821f91a27982d2453bcd7a66193356ea84e84fb7c8d793be1ba0c
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^2.1.4":
version: 2.1.4
resolution: "@eslint/eslintrc@npm:2.1.4"
"@eslint/config-array@npm:^0.21.1":
version: 0.21.1
resolution: "@eslint/config-array@npm:0.21.1"
dependencies:
ajv: "npm:^6.12.4"
debug: "npm:^4.3.2"
espree: "npm:^9.6.0"
globals: "npm:^13.19.0"
ignore: "npm:^5.2.0"
import-fresh: "npm:^3.2.1"
js-yaml: "npm:^4.1.0"
"@eslint/object-schema": "npm:^2.1.7"
debug: "npm:^4.3.1"
minimatch: "npm:^3.1.2"
strip-json-comments: "npm:^3.1.1"
checksum: 10/7a3b14f4b40fc1a22624c3f84d9f467a3d9ea1ca6e9a372116cb92507e485260359465b58e25bcb6c9981b155416b98c9973ad9b796053fd7b3f776a6946bce8
checksum: 10/6eaa0435972f735ce52d581f355a0b616e50a9b8a73304a7015398096e252798b9b3b968a67b524eefb0fdeacc57c4d960f0ec6432abe1c1e24be815b88c5d18
languageName: node
linkType: hard
"@eslint/js@npm:8.57.1":
version: 8.57.1
resolution: "@eslint/js@npm:8.57.1"
checksum: 10/7562b21be10c2adbfa4aa5bb2eccec2cb9ac649a3569560742202c8d1cb6c931ce634937a2f0f551e078403a1c1285d6c2c0aa345dafc986149665cd69fe8b59
"@eslint/config-helpers@npm:^0.4.2":
version: 0.4.2
resolution: "@eslint/config-helpers@npm:0.4.2"
dependencies:
"@eslint/core": "npm:^0.17.0"
checksum: 10/3f2b4712d8e391c36ec98bc200f7dea423dfe518e42956569666831b89ede83b33120c761dfd3ab6347d8e8894a6d4af47254a18d464a71c6046fd88065f6daf
languageName: node
linkType: hard
"@eslint/core@npm:^0.17.0":
version: 0.17.0
resolution: "@eslint/core@npm:0.17.0"
dependencies:
"@types/json-schema": "npm:^7.0.15"
checksum: 10/f9a428cc651ec15fb60d7d60c2a7bacad4666e12508320eafa98258e976fafaa77d7be7be91519e75f801f15f830105420b14a458d4aab121a2b0a59bc43517b
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^3.3.1":
version: 3.3.3
resolution: "@eslint/eslintrc@npm:3.3.3"
dependencies:
ajv: "npm:^6.12.4"
debug: "npm:^4.3.2"
espree: "npm:^10.0.1"
globals: "npm:^14.0.0"
ignore: "npm:^5.2.0"
import-fresh: "npm:^3.2.1"
js-yaml: "npm:^4.1.1"
minimatch: "npm:^3.1.2"
strip-json-comments: "npm:^3.1.1"
checksum: 10/b586a364ff15ce1b68993aefc051ca330b1fece15fb5baf4a708d00113f9a14895cffd84a5f24c5a97bd4b4321130ab2314f90aa462a250f6b859c2da2cba1f3
languageName: node
linkType: hard
"@eslint/js@npm:9.39.2":
version: 9.39.2
resolution: "@eslint/js@npm:9.39.2"
checksum: 10/6b7f676746f3111b5d1b23715319212ab9297868a0fa9980d483c3da8965d5841673aada2d5653e85a3f7156edee0893a7ae7035211b4efdcb2848154bb947f2
languageName: node
linkType: hard
"@eslint/object-schema@npm:^2.1.7":
version: 2.1.7
resolution: "@eslint/object-schema@npm:2.1.7"
checksum: 10/946ef5d6235b4d1c0907c6c6e6429c8895f535380c562b7705c131f63f2e961b06e8785043c86a293da48e0a60c6286d98ba395b8b32ea55561fe6e4417cb7e4
languageName: node
linkType: hard
"@eslint/plugin-kit@npm:^0.4.1":
version: 0.4.1
resolution: "@eslint/plugin-kit@npm:0.4.1"
dependencies:
"@eslint/core": "npm:^0.17.0"
levn: "npm:^0.4.1"
checksum: 10/c5947d0ffeddca77d996ac1b886a66060c1a15ed1d5e425d0c7e7d7044a4bd3813fc968892d03950a7831c9b89368a2f7b281e45dd3c74a048962b74bf3a1cb4
languageName: node
linkType: hard
@@ -455,14 +501,20 @@ __metadata:
languageName: node
linkType: hard
"@humanwhocodes/config-array@npm:^0.13.0":
version: 0.13.0
resolution: "@humanwhocodes/config-array@npm:0.13.0"
"@humanfs/core@npm:^0.19.1":
version: 0.19.1
resolution: "@humanfs/core@npm:0.19.1"
checksum: 10/270d936be483ab5921702623bc74ce394bf12abbf57d9145a69e8a0d1c87eb1c768bd2d93af16c5705041e257e6d9cc7529311f63a1349f3678abc776fc28523
languageName: node
linkType: hard
"@humanfs/node@npm:^0.16.6":
version: 0.16.7
resolution: "@humanfs/node@npm:0.16.7"
dependencies:
"@humanwhocodes/object-schema": "npm:^2.0.3"
debug: "npm:^4.3.1"
minimatch: "npm:^3.0.5"
checksum: 10/524df31e61a85392a2433bf5d03164e03da26c03d009f27852e7dcfdafbc4a23f17f021dacf88e0a7a9fe04ca032017945d19b57a16e2676d9114c22a53a9d11
"@humanfs/core": "npm:^0.19.1"
"@humanwhocodes/retry": "npm:^0.4.0"
checksum: 10/b3633d3dce898592cac515ba5e6693c78e6be92863541d3eaf2c009b10f52b2fa62ff6e6e06f240f2447ddbe7b5f1890bc34e9308470675c876eee207553a08d
languageName: node
linkType: hard
@@ -473,10 +525,10 @@ __metadata:
languageName: node
linkType: hard
"@humanwhocodes/object-schema@npm:^2.0.3":
version: 2.0.3
resolution: "@humanwhocodes/object-schema@npm:2.0.3"
checksum: 10/05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3
"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2":
version: 0.4.3
resolution: "@humanwhocodes/retry@npm:0.4.3"
checksum: 10/0b32cfd362bea7a30fbf80bb38dcaf77fee9c2cae477ee80b460871d03590110ac9c77d654f04ec5beaf71b6f6a89851bdf6c1e34ccdf2f686bd86fcd97d9e61
languageName: node
linkType: hard
@@ -1005,7 +1057,7 @@ __metadata:
languageName: node
linkType: hard
"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8":
"@nodelib/fs.walk@npm:^1.2.3":
version: 1.2.8
resolution: "@nodelib/fs.walk@npm:1.2.8"
dependencies:
@@ -1305,7 +1357,7 @@ __metadata:
languageName: node
linkType: hard
"@types/estree@npm:*, @types/estree@npm:^1.0.0":
"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6":
version: 1.0.8
resolution: "@types/estree@npm:1.0.8"
checksum: 10/25a4c16a6752538ffde2826c2cc0c6491d90e69cd6187bef4a006dd2c3c45469f049e643d7e516c515f21484dc3d48fd5c870be158a5beb72f5baf3dc43e4099
@@ -1321,6 +1373,13 @@ __metadata:
languageName: node
linkType: hard
"@types/json-schema@npm:^7.0.15":
version: 7.0.15
resolution: "@types/json-schema@npm:7.0.15"
checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7
languageName: node
linkType: hard
"@types/json5@npm:^0.0.29":
version: 0.0.29
resolution: "@types/json5@npm:0.0.29"
@@ -1587,7 +1646,7 @@ __metadata:
languageName: node
linkType: hard
"@ungap/structured-clone@npm:^1.0.0, @ungap/structured-clone@npm:^1.2.0":
"@ungap/structured-clone@npm:^1.0.0":
version: 1.3.0
resolution: "@ungap/structured-clone@npm:1.3.0"
checksum: 10/80d6910946f2b1552a2406650051c91bbd1f24a6bf854354203d84fe2714b3e8ce4618f49cc3410494173a1c1e8e9777372fe68dce74bd45faf0a7a1a6ccf448
@@ -1745,7 +1804,7 @@ __metadata:
languageName: node
linkType: hard
"acorn@npm:^8.0.0, acorn@npm:^8.9.0":
"acorn@npm:^8.0.0, acorn@npm:^8.15.0":
version: 8.15.0
resolution: "acorn@npm:8.15.0"
bin:
@@ -2277,7 +2336,7 @@ __metadata:
languageName: node
linkType: hard
"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.6":
"cross-spawn@npm:^7.0.6":
version: 7.0.6
resolution: "cross-spawn@npm:7.0.6"
dependencies:
@@ -2439,7 +2498,7 @@ __metadata:
"@uiw/react-codemirror": "npm:^4.23.7"
chokidar: "npm:^3.6.0"
clsx: "npm:^2.1.1"
eslint: "npm:^8"
eslint: "npm:^9"
eslint-config-next: "npm:16.1.6"
html-react-parser: "npm:^5.2.5"
lightningcss: "npm:^1.28.2"
@@ -2464,15 +2523,6 @@ __metadata:
languageName: node
linkType: hard
"doctrine@npm:^3.0.0":
version: 3.0.0
resolution: "doctrine@npm:3.0.0"
dependencies:
esutils: "npm:^2.0.2"
checksum: 10/b4b28f1df5c563f7d876e7461254a4597b8cabe915abe94d7c5d1633fed263fcf9a85e8d3836591fc2d040108e822b0d32758e5ec1fe31c590dc7e08086e3e48
languageName: node
linkType: hard
"dom-serializer@npm:^2.0.0":
version: 2.0.0
resolution: "dom-serializer@npm:2.0.0"
@@ -2933,17 +2983,17 @@ __metadata:
languageName: node
linkType: hard
"eslint-scope@npm:^7.2.2":
version: 7.2.2
resolution: "eslint-scope@npm:7.2.2"
"eslint-scope@npm:^8.4.0":
version: 8.4.0
resolution: "eslint-scope@npm:8.4.0"
dependencies:
esrecurse: "npm:^4.3.0"
estraverse: "npm:^5.2.0"
checksum: 10/5c660fb905d5883ad018a6fea2b49f3cb5b1cbf2cd4bd08e98646e9864f9bc2c74c0839bed2d292e90a4a328833accc197c8f0baed89cbe8d605d6f918465491
checksum: 10/e8e611701f65375e034c62123946e628894f0b54aa8cb11abe224816389abe5cd74cf16b62b72baa36504f22d1a958b9b8b0169b82397fe2e7997674c0d09b06
languageName: node
linkType: hard
"eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3":
"eslint-visitor-keys@npm:^3.4.3":
version: 3.4.3
resolution: "eslint-visitor-keys@npm:3.4.3"
checksum: 10/3f357c554a9ea794b094a09bd4187e5eacd1bc0d0653c3adeb87962c548e6a1ab8f982b86963ae1337f5d976004146536dcee5d0e2806665b193fbfbf1a9231b
@@ -2957,71 +3007,72 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:^8":
version: 8.57.1
resolution: "eslint@npm:8.57.1"
"eslint@npm:^9":
version: 9.39.2
resolution: "eslint@npm:9.39.2"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.2.0"
"@eslint-community/regexpp": "npm:^4.6.1"
"@eslint/eslintrc": "npm:^2.1.4"
"@eslint/js": "npm:8.57.1"
"@humanwhocodes/config-array": "npm:^0.13.0"
"@eslint-community/eslint-utils": "npm:^4.8.0"
"@eslint-community/regexpp": "npm:^4.12.1"
"@eslint/config-array": "npm:^0.21.1"
"@eslint/config-helpers": "npm:^0.4.2"
"@eslint/core": "npm:^0.17.0"
"@eslint/eslintrc": "npm:^3.3.1"
"@eslint/js": "npm:9.39.2"
"@eslint/plugin-kit": "npm:^0.4.1"
"@humanfs/node": "npm:^0.16.6"
"@humanwhocodes/module-importer": "npm:^1.0.1"
"@nodelib/fs.walk": "npm:^1.2.8"
"@ungap/structured-clone": "npm:^1.2.0"
"@humanwhocodes/retry": "npm:^0.4.2"
"@types/estree": "npm:^1.0.6"
ajv: "npm:^6.12.4"
chalk: "npm:^4.0.0"
cross-spawn: "npm:^7.0.2"
cross-spawn: "npm:^7.0.6"
debug: "npm:^4.3.2"
doctrine: "npm:^3.0.0"
escape-string-regexp: "npm:^4.0.0"
eslint-scope: "npm:^7.2.2"
eslint-visitor-keys: "npm:^3.4.3"
espree: "npm:^9.6.1"
esquery: "npm:^1.4.2"
eslint-scope: "npm:^8.4.0"
eslint-visitor-keys: "npm:^4.2.1"
espree: "npm:^10.4.0"
esquery: "npm:^1.5.0"
esutils: "npm:^2.0.2"
fast-deep-equal: "npm:^3.1.3"
file-entry-cache: "npm:^6.0.1"
file-entry-cache: "npm:^8.0.0"
find-up: "npm:^5.0.0"
glob-parent: "npm:^6.0.2"
globals: "npm:^13.19.0"
graphemer: "npm:^1.4.0"
ignore: "npm:^5.2.0"
imurmurhash: "npm:^0.1.4"
is-glob: "npm:^4.0.0"
is-path-inside: "npm:^3.0.3"
js-yaml: "npm:^4.1.0"
json-stable-stringify-without-jsonify: "npm:^1.0.1"
levn: "npm:^0.4.1"
lodash.merge: "npm:^4.6.2"
minimatch: "npm:^3.1.2"
natural-compare: "npm:^1.4.0"
optionator: "npm:^0.9.3"
strip-ansi: "npm:^6.0.1"
text-table: "npm:^0.2.0"
peerDependencies:
jiti: "*"
peerDependenciesMeta:
jiti:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10/5504fa24879afdd9f9929b2fbfc2ee9b9441a3d464efd9790fbda5f05738858530182029f13323add68d19fec749d3ab4a70320ded091ca4432b1e9cc4ed104c
checksum: 10/53ff0e9c8264e7e8d40d50fdc0c0df0b701cfc5289beedfb686c214e3e7b199702f894bbd1bb48653727bb1ecbd1147cf5f555a4ae71e1daf35020cdc9072d9f
languageName: node
linkType: hard
"espree@npm:^9.6.0, espree@npm:^9.6.1":
version: 9.6.1
resolution: "espree@npm:9.6.1"
"espree@npm:^10.0.1, espree@npm:^10.4.0":
version: 10.4.0
resolution: "espree@npm:10.4.0"
dependencies:
acorn: "npm:^8.9.0"
acorn: "npm:^8.15.0"
acorn-jsx: "npm:^5.3.2"
eslint-visitor-keys: "npm:^3.4.1"
checksum: 10/255ab260f0d711a54096bdeda93adff0eadf02a6f9b92f02b323e83a2b7fc258797919437ad331efec3930475feb0142c5ecaaf3cdab4befebd336d47d3f3134
eslint-visitor-keys: "npm:^4.2.1"
checksum: 10/9b355b32dbd1cc9f57121d5ee3be258fab87ebeb7c83fc6c02e5af1a74fc8c5ba79fe8c663e69ea112c3e84a1b95e6a2067ac4443ee7813bb85ac7581acb8bf9
languageName: node
linkType: hard
"esquery@npm:^1.4.2":
version: 1.6.0
resolution: "esquery@npm:1.6.0"
"esquery@npm:^1.5.0":
version: 1.7.0
resolution: "esquery@npm:1.7.0"
dependencies:
estraverse: "npm:^5.1.0"
checksum: 10/c587fb8ec9ed83f2b1bc97cf2f6854cc30bf784a79d62ba08c6e358bf22280d69aee12827521cf38e69ae9761d23fb7fde593ce315610f85655c139d99b05e5a
checksum: 10/4afaf3089367e1f5885caa116ef386dffd8bfd64da21fd3d0e56e938d2667cfb2e5400ab4a825aa70e799bb3741e5b5d63c0b94d86e2d4cf3095c9e64b2f5a15
languageName: node
linkType: hard
@@ -3192,12 +3243,12 @@ __metadata:
languageName: node
linkType: hard
"file-entry-cache@npm:^6.0.1":
version: 6.0.1
resolution: "file-entry-cache@npm:6.0.1"
"file-entry-cache@npm:^8.0.0":
version: 8.0.0
resolution: "file-entry-cache@npm:8.0.0"
dependencies:
flat-cache: "npm:^3.0.4"
checksum: 10/099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b
flat-cache: "npm:^4.0.0"
checksum: 10/afe55c4de4e0d226a23c1eae62a7219aafb390859122608a89fa4df6addf55c7fd3f1a2da6f5b41e7cdff496e4cf28bbd215d53eab5c817afa96d2b40c81bfb0
languageName: node
linkType: hard
@@ -3220,14 +3271,13 @@ __metadata:
languageName: node
linkType: hard
"flat-cache@npm:^3.0.4":
version: 3.2.0
resolution: "flat-cache@npm:3.2.0"
"flat-cache@npm:^4.0.0":
version: 4.0.1
resolution: "flat-cache@npm:4.0.1"
dependencies:
flatted: "npm:^3.2.9"
keyv: "npm:^4.5.3"
rimraf: "npm:^3.0.2"
checksum: 10/02381c6ece5e9fa5b826c9bbea481d7fd77645d96e4b0b1395238124d581d10e56f17f723d897b6d133970f7a57f0fab9148cbbb67237a0a0ffe794ba60c0c70
keyv: "npm:^4.5.4"
checksum: 10/58ce851d9045fffc7871ce2bd718bc485ad7e777bf748c054904b87c351ff1080c2c11da00788d78738bfb51b71e4d5ea12d13b98eb36e3358851ffe495b62dc
languageName: node
linkType: hard
@@ -3288,13 +3338,6 @@ __metadata:
languageName: node
linkType: hard
"fs.realpath@npm:^1.0.0":
version: 1.0.0
resolution: "fs.realpath@npm:1.0.0"
checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96
languageName: node
linkType: hard
"fsevents@npm:~2.3.2":
version: 2.3.3
resolution: "fsevents@npm:2.3.3"
@@ -3431,20 +3474,6 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^7.1.3":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
fs.realpath: "npm:^1.0.0"
inflight: "npm:^1.0.4"
inherits: "npm:2"
minimatch: "npm:^3.1.1"
once: "npm:^1.3.0"
path-is-absolute: "npm:^1.0.0"
checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b
languageName: node
linkType: hard
"globals@npm:16.4.0":
version: 16.4.0
resolution: "globals@npm:16.4.0"
@@ -3452,12 +3481,10 @@ __metadata:
languageName: node
linkType: hard
"globals@npm:^13.19.0":
version: 13.24.0
resolution: "globals@npm:13.24.0"
dependencies:
type-fest: "npm:^0.20.2"
checksum: 10/62c5b1997d06674fc7191d3e01e324d3eda4d65ac9cc4e78329fa3b5c4fd42a0e1c8722822497a6964eee075255ce21ccf1eec2d83f92ef3f06653af4d0ee28e
"globals@npm:^14.0.0":
version: 14.0.0
resolution: "globals@npm:14.0.0"
checksum: 10/03939c8af95c6df5014b137cac83aa909090c3a3985caef06ee9a5a669790877af8698ab38007e4c0186873adc14c0b13764acc754b16a754c216cc56aa5f021
languageName: node
linkType: hard
@@ -3485,13 +3512,6 @@ __metadata:
languageName: node
linkType: hard
"graphemer@npm:^1.4.0":
version: 1.4.0
resolution: "graphemer@npm:1.4.0"
checksum: 10/6dd60dba97007b21e3a829fab3f771803cc1292977fe610e240ea72afd67e5690ac9eeaafc4a99710e78962e5936ab5a460787c2a1180f1cb0ccfac37d29f897
languageName: node
linkType: hard
"has-bigints@npm:^1.0.2":
version: 1.1.0
resolution: "has-bigints@npm:1.1.0"
@@ -3754,23 +3774,6 @@ __metadata:
languageName: node
linkType: hard
"inflight@npm:^1.0.4":
version: 1.0.6
resolution: "inflight@npm:1.0.6"
dependencies:
once: "npm:^1.3.0"
wrappy: "npm:1"
checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67
languageName: node
linkType: hard
"inherits@npm:2":
version: 2.0.4
resolution: "inherits@npm:2.0.4"
checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521
languageName: node
linkType: hard
"inline-style-parser@npm:0.2.7":
version: 0.2.7
resolution: "inline-style-parser@npm:0.2.7"
@@ -4000,13 +4003,6 @@ __metadata:
languageName: node
linkType: hard
"is-path-inside@npm:^3.0.3":
version: 3.0.3
resolution: "is-path-inside@npm:3.0.3"
checksum: 10/abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9
languageName: node
linkType: hard
"is-plain-obj@npm:^4.0.0":
version: 4.1.0
resolution: "is-plain-obj@npm:4.1.0"
@@ -4153,7 +4149,7 @@ __metadata:
languageName: node
linkType: hard
"js-yaml@npm:^4.1.0":
"js-yaml@npm:^4.1.1":
version: 4.1.1
resolution: "js-yaml@npm:4.1.1"
dependencies:
@@ -4226,7 +4222,7 @@ __metadata:
languageName: node
linkType: hard
"keyv@npm:^4.5.3":
"keyv@npm:^4.5.4":
version: 4.5.4
resolution: "keyv@npm:4.5.4"
dependencies:
@@ -4959,7 +4955,7 @@ __metadata:
languageName: node
linkType: hard
"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
"minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
dependencies:
@@ -5341,15 +5337,6 @@ __metadata:
languageName: node
linkType: hard
"once@npm:^1.3.0":
version: 1.4.0
resolution: "once@npm:1.4.0"
dependencies:
wrappy: "npm:1"
checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68
languageName: node
linkType: hard
"oniguruma-parser@npm:^0.12.1":
version: 0.12.1
resolution: "oniguruma-parser@npm:0.12.1"
@@ -5456,13 +5443,6 @@ __metadata:
languageName: node
linkType: hard
"path-is-absolute@npm:^1.0.0":
version: 1.0.1
resolution: "path-is-absolute@npm:1.0.1"
checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8
languageName: node
linkType: hard
"path-key@npm:^3.1.0":
version: 3.1.1
resolution: "path-key@npm:3.1.1"
@@ -5874,17 +5854,6 @@ __metadata:
languageName: node
linkType: hard
"rimraf@npm:^3.0.2":
version: 3.0.2
resolution: "rimraf@npm:3.0.2"
dependencies:
glob: "npm:^7.1.3"
bin:
rimraf: bin.js
checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5
languageName: node
linkType: hard
"run-parallel@npm:^1.1.9":
version: 1.2.0
resolution: "run-parallel@npm:1.2.0"
@@ -6473,13 +6442,6 @@ __metadata:
languageName: node
linkType: hard
"text-table@npm:^0.2.0":
version: 0.2.0
resolution: "text-table@npm:0.2.0"
checksum: 10/4383b5baaeffa9bb4cda2ac33a4aa2e6d1f8aaf811848bf73513a9b88fd76372dc461f6fd6d2e9cb5100f48b473be32c6f95bd983509b7d92bb4d92c10747452
languageName: node
linkType: hard
"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.15":
version: 0.2.15
resolution: "tinyglobby@npm:0.2.15"
@@ -6550,13 +6512,6 @@ __metadata:
languageName: node
linkType: hard
"type-fest@npm:^0.20.2":
version: 0.20.2
resolution: "type-fest@npm:0.20.2"
checksum: 10/8907e16284b2d6cfa4f4817e93520121941baba36b39219ea36acfe64c86b9dbc10c9941af450bd60832c8f43464974d51c0957f9858bc66b952b66b6914cbb9
languageName: node
linkType: hard
"type-fest@npm:^4.31.0":
version: 4.41.0
resolution: "type-fest@npm:4.41.0"
@@ -7027,13 +6982,6 @@ __metadata:
languageName: node
linkType: hard
"wrappy@npm:1":
version: 1.0.2
resolution: "wrappy@npm:1.0.2"
checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5
languageName: node
linkType: hard
"yallist@npm:^3.0.2":
version: 3.1.1
resolution: "yallist@npm:3.1.1"