diff --git a/packages/__docs__/package.json b/packages/__docs__/package.json index 4abd2bcb5e..dc26426034 100644 --- a/packages/__docs__/package.json +++ b/packages/__docs__/package.json @@ -122,7 +122,6 @@ "moment": "^2.30.1", "react": "18.3.1", "react-dom": "18.3.1", - "react-window": "^2.2.3", "semver": "^7.7.2", "uuid": "^11.1.0", "webpack-merge": "^6.0.1" diff --git a/packages/__docs__/src/Icons/IconsGallery.tsx b/packages/__docs__/src/Icons/IconsGallery.tsx index 1eef93b2d7..e39d323eed 100644 --- a/packages/__docs__/src/Icons/IconsGallery.tsx +++ b/packages/__docs__/src/Icons/IconsGallery.tsx @@ -22,9 +22,8 @@ * SOFTWARE. */ -import { useState, memo, useCallback, useMemo, useRef, useEffect } from 'react' +import { useState, memo, useCallback, useMemo, useRef } from 'react' import type { ChangeEvent } from 'react' -import { Grid } from 'react-window' import { Heading } from '@instructure/ui-heading' import { TextInput } from '@instructure/ui-text-input' @@ -41,12 +40,9 @@ import { LucideIcons, CustomIcons } from '@instructure/ui-icons' import { XInstUIIcon } from '@instructure/ui-icons' import { Flex } from '@instructure/ui-flex' -type IconSource = 'lucide' | 'custom' - type IconInfo = { name: string component: React.ComponentType - source: IconSource importPath: string } @@ -60,13 +56,11 @@ const allIcons: IconInfo[] = [ ...Object.entries(LucideIcons).map(([name, component]) => ({ name, component: component as React.ComponentType, - source: 'lucide' as const, importPath: '@instructure/ui-icons' })), ...Object.entries(CustomIcons).map(([name, component]) => ({ name, component: component as React.ComponentType, - source: 'custom' as const, importPath: '@instructure/ui-icons' })) ] @@ -95,10 +89,9 @@ const IconTile = memo( display: 'flex', alignItems: 'center', flexDirection: 'column', - width: '100%', - padding: '0.5rem', - boxSizing: 'border-box', - overflow: 'hidden' + minWidth: '14em', + flexBasis: '14em', + flexGrow: 1, }} >
{ const [searchQuery, setSearchQuery] = useState('') - const [searchInput, setSearchInput] = useState('') const [selectedIcon, setSelectedIcon] = useState(null) const [rtl, setRtl] = useState(false) - const [containerWidth, setContainerWidth] = useState(() => - typeof window !== 'undefined' ? window.innerWidth : 900 - ) const searchTimeoutId = useRef(null) - const resizeTimeoutId = useRef(null) - const containerRef = useRef(null) - // Debounced search - const handleSearchChange = useCallback((_e: ChangeEvent, value: string) => { - setSearchInput(value) + const handleSearchChange = (_e: ChangeEvent, value: string) => { + // Instant update when extending query (typing adds characters) + if (value.startsWith(searchQuery)) { + setSearchQuery(value) + return + } + // Debounce when deleting (reveals more icons = heavier re-render) if (searchTimeoutId.current) { clearTimeout(searchTimeoutId.current) } searchTimeoutId.current = setTimeout(() => { setSearchQuery(value) - }, 300) - }, []) + }, 500) + } const handleBidirectionToggle = useCallback((e: ChangeEvent) => { setRtl(e.target.checked) @@ -214,70 +192,12 @@ const IconsGallery = () => { const filteredIcons = useMemo(() => { if (!searchQuery) return allIcons - return allIcons.filter((icon) => - icon.name.toLowerCase().includes(searchQuery.toLowerCase()) - ) + const query = searchQuery.toLowerCase() + return allIcons.filter((icon) => icon.name.toLowerCase().includes(query)) }, [searchQuery]) - // Update container width on resize with debouncing - useEffect(() => { - const updateWidth = () => { - if (containerRef.current) { - setContainerWidth(containerRef.current.offsetWidth) - } else { - setContainerWidth(window.innerWidth) - } - } - - const handleResize = () => { - if (resizeTimeoutId.current) { - clearTimeout(resizeTimeoutId.current) - } - - resizeTimeoutId.current = setTimeout(() => { - updateWidth() - }, 150) - } - - // Initial measurement - updateWidth() - - window.addEventListener('resize', handleResize) - return () => { - window.removeEventListener('resize', handleResize) - if (resizeTimeoutId.current) { - clearTimeout(resizeTimeoutId.current) - } - } - }, []) - - // Calculate column count and tile width based on container width - const columnCount = getColumnCountForWidth(containerWidth) - const tileWidth = Math.floor(containerWidth / columnCount) - const gridWidth = tileWidth * columnCount - const rowCount = Math.ceil(filteredIcons.length / columnCount) - const gridHeight = rowCount * TILE_HEIGHT - - // Memoized cell renderer to prevent unnecessary re-renders - const CellRenderer = useCallback( - ({ columnIndex, rowIndex, style }: any) => { - const index = rowIndex * columnCount + columnIndex - if (index >= filteredIcons.length) { - return
- } - - const icon = filteredIcons[index] - return ( -
- -
- ) - }, - [columnCount, filteredIcons, rtl, handleIconClick] - ) - return ( -
+
{ > Icon Name} /> @@ -302,28 +221,22 @@ const IconsGallery = () => {
- + {filteredIcons.map((icon) => ( + + ))}
{selectedIcon && ( diff --git a/packages/__docs__/src/Icons/index.tsx b/packages/__docs__/src/Icons/index.tsx index 9c5c343a23..0f7ddc522f 100644 --- a/packages/__docs__/src/Icons/index.tsx +++ b/packages/__docs__/src/Icons/index.tsx @@ -31,7 +31,7 @@ const IconsGallery = lazy(() => import('./IconsGallery')) const IconsPage = () => { return ( - + { const [selectedFormat, setSelectedFormat] = useState('react') @@ -243,8 +234,6 @@ const LegacyIconsGallery = ({ glyphs }: LegacyIconsGalleryProps) => { ) }, [glyphs, searchQuery]) - const rowCount = Math.ceil(filteredGlyphs.length / COLUMN_COUNT) - return (
{
- { - const index = rowIndex * COLUMN_COUNT + columnIndex - if (index >= filteredGlyphs.length) { - return
- } - - const glyph = filteredGlyphs[index] - return ( -
- -
- ) - }} - cellProps={EMPTY_CELL_PROPS} - columnCount={COLUMN_COUNT} - columnWidth={TILE_WIDTH} - rowCount={rowCount} - rowHeight={TILE_HEIGHT} - style={{ - height: '600px', - width: `${GRID_WIDTH}px`, - overflowX: 'hidden' - }} - /> + {filteredGlyphs.map((glyph) => ( + + ))}
{selectedGlyph && ( , iconName: string, viewBox: string = '0 0 24 24' ): React.ComponentType { @@ -52,21 +53,6 @@ export function wrapCustomIcon( // For the AI gradient, coordinates span the viewBox width const viewBoxWidth = parseFloat(viewBox.split(' ')[2]) || 24 - const renderPaths = (gradientId?: string) => - iconNode.map(([tagName, attrs], index) => { - if (!gradientId) { - return React.createElement(tagName, { key: index, ...attrs }) - } - const elementProps: Record = { key: index } - for (const [k, v] of Object.entries(attrs)) { - elementProps[k] = - (k === 'fill' || k === 'stroke') && v === 'currentColor' - ? `url(#${gradientId})` - : v - } - return React.createElement(tagName, elementProps) - }) - const WrappedIcon = (props: InstUIIconProps) => { const { size, @@ -152,7 +138,7 @@ export function wrapCustomIcon( - {renderPaths(gradientId)} + ) @@ -165,7 +151,7 @@ export function wrapCustomIcon( {...strokeWidthProp} style={{ color: styles.resolvedColor }} > - {renderPaths()} + ) diff --git a/packages/ui-scripts/lib/icons/build-icons.js b/packages/ui-scripts/lib/icons/build-icons.js index cb25072b22..496d08b660 100644 --- a/packages/ui-scripts/lib/icons/build-icons.js +++ b/packages/ui-scripts/lib/icons/build-icons.js @@ -94,7 +94,6 @@ export default { const glyphs = getGlyphData( svgSourceDir, - config.deprecated, config.bidirectional, config.react.componentBaseName ) @@ -102,7 +101,7 @@ export default { // generate svg index generateSvgIndex(glyphs, config.destination) // - output: ui-icons/src/generated/svg/index.js - // - fields: variant, glyphName, src (svg), deprecated + // - fields: variant, glyphName, src (svg) // generate react components generateReactComponents(glyphs, config.destination) diff --git a/packages/ui-scripts/lib/icons/generate-custom-index.ts b/packages/ui-scripts/lib/icons/generate-custom-index.ts index 44f65b1409..9e04b759fe 100644 --- a/packages/ui-scripts/lib/icons/generate-custom-index.ts +++ b/packages/ui-scripts/lib/icons/generate-custom-index.ts @@ -24,7 +24,7 @@ import fs from 'fs' import path from 'path' -import * as svgson from 'svgson' +import { svg2jsx } from './svg2jsx.js' const HEADER = `/* * The MIT License (MIT) @@ -52,23 +52,30 @@ const HEADER = `/* ` /** - * Parse SVG into iconNode format: [[tagName, attributes], ...] + * Extract viewBox and convert inner SVG content to JSX with dynamic color. */ -function svgToIconNode(svgContent: string): { - iconNode: Array<[string, Record]> +function svgToJsxPaths(svgContent: string): { + jsxContent: string viewBox?: string } { - const iconNode: Array<[string, Record]> = [] - const parsed = svgson.parseSync(svgContent, { camelcase: true }) + // Extract viewBox from the root tag + const svgTagMatch = svgContent.match(//) + const viewBoxMatch = svgTagMatch?.[1].match(/viewBox\s*=\s*"([^"]*)"/) + const viewBox = viewBoxMatch?.[1] || undefined - function extract(node: svgson.INode): void { - if (node.type !== 'element') return - iconNode.push([node.name, { ...node.attributes }]) - node.children.forEach(extract) - } - parsed.children.forEach(extract) + // Strip the wrapper to get inner content + const inner = svgContent + .replace(/]*>/, '') + .replace(/<\/svg\s*>/, '') + .trim() + + // Convert SVG attributes to JSX + let jsxContent = svg2jsx(inner) + + // Make currentColor values dynamic via the color prop + jsxContent = jsxContent.replace(/="currentColor"/g, '={color}') - return { iconNode, viewBox: parsed.attributes.viewBox || undefined } + return { jsxContent, viewBox } } /** @@ -91,20 +98,23 @@ export default function generateCustomIndex() { } const svgFiles = fs.readdirSync(svgDir).filter((f) => f.endsWith('.svg')) - const exports: string[] = [] + const iconBlocks: string[] = [] for (const fileName of svgFiles) { const svgContent = fs.readFileSync(path.join(svgDir, fileName), 'utf-8') const iconName = fileNameToIconName(fileName) try { - const { iconNode, viewBox } = svgToIconNode(svgContent) - const viewBoxArg = viewBox ? `, '${viewBox}'` : '' - - exports.push( - `export const ${iconName}InstUIIcon = wrapCustomIcon(${JSON.stringify( - iconNode - )} as IconNode, '${iconName}'${viewBoxArg})` + const { jsxContent, viewBox } = svgToJsxPaths(svgContent) + const viewBoxArg = viewBox ? `'${viewBox}'` : "'0 0 24 24'" + + iconBlocks.push( + `const ${iconName}Paths = ({ color = 'currentColor' }: { color?: string }) => (\n` + + ` <>\n` + + ` ${jsxContent}\n` + + ` \n` + + `)\n` + + `export const ${iconName}InstUIIcon = wrapCustomIcon(${iconName}Paths, '${iconName}', ${viewBoxArg})` ) } catch (err) { throw new Error(`Error processing ${fileName}: ${err}`) @@ -114,20 +124,21 @@ export default function generateCustomIndex() { // Output goes to src/generated/custom/ so the import is relative to that: // ../../custom/wrapCustomIcon resolves to src/custom/wrapCustomIcon const content = `${HEADER} -import type { IconNode } from 'lucide-react' import { wrapCustomIcon } from '../../custom/wrapCustomIcon' // Custom icons with InstUI theming -// wrapCustomIcon(iconNode, displayName, viewBox?) -${exports.join('\n')} +// Each icon is a JSX component that accepts a color prop +${iconBlocks.join('\n\n')} ` - const outputPath = path.join(process.cwd(), 'src/generated/custom/index.ts') - fs.mkdirSync(path.dirname(outputPath), { recursive: true }) + const outputDir = path.join(process.cwd(), 'src/generated/custom') + fs.mkdirSync(outputDir, { recursive: true }) + + const outputPath = path.join(outputDir, 'index.tsx') fs.writeFileSync(outputPath, content, 'utf-8') // eslint-disable-next-line no-console console.log( - `Generated src/generated/custom/index.ts with ${exports.length} / ${svgFiles.length} custom icons` + `Generated src/generated/custom/index.tsx with ${iconBlocks.length} / ${svgFiles.length} custom icons` ) } diff --git a/packages/ui-scripts/lib/icons/generate-legacy-icons-data.js b/packages/ui-scripts/lib/icons/generate-legacy-icons-data.js index 635c6ea8eb..bf24746a67 100644 --- a/packages/ui-scripts/lib/icons/generate-legacy-icons-data.js +++ b/packages/ui-scripts/lib/icons/generate-legacy-icons-data.js @@ -26,12 +26,10 @@ import getGlyphData from './get-glyph-data.js' export default function generateLegacyIconsData() { const svgDir = path.join(process.cwd(), 'svg/') - const deprecatedMap = {} const bidirectionalList = [] const glyphsRaw = getGlyphData( svgDir, - deprecatedMap, bidirectionalList, 'Icon' ) @@ -39,17 +37,14 @@ export default function generateLegacyIconsData() { // Group by glyphName to merge Line and Solid variants return Object.values( glyphsRaw.reduce( - (acc, { name, glyphName, variant, src, bidirectional, deprecated }) => { - if (!deprecated) { - const existing = acc[glyphName] || { name, glyphName, bidirectional } - const updated = { ...existing } + (acc, { name, glyphName, variant, src, bidirectional }) => { + const existing = acc[glyphName] || { name, glyphName, bidirectional } + const updated = { ...existing } - if (variant === 'Line') updated.lineSrc = src - if (variant === 'Solid') updated.solidSrc = src + if (variant === 'Line') updated.lineSrc = src + if (variant === 'Solid') updated.solidSrc = src - return { ...acc, [glyphName]: updated } - } - return acc + return { ...acc, [glyphName]: updated } }, {} ) diff --git a/packages/ui-scripts/lib/icons/generate-react-components.js b/packages/ui-scripts/lib/icons/generate-react-components.js index 0af79a604a..9058ac7dae 100644 --- a/packages/ui-scripts/lib/icons/generate-react-components.js +++ b/packages/ui-scripts/lib/icons/generate-react-components.js @@ -50,7 +50,7 @@ const NOTICE_HEADER = `/* ` async function generateIconComponent(glyph) { - const { name, variant, glyphName, deprecated, bidirectional, src } = glyph + const { name, variant, glyphName, bidirectional, src } = glyph const source = src.match( /]*?(?:viewBox="(\b[^"]*)")?>([\s\S]*?)<\/svg>/ @@ -66,7 +66,6 @@ class ${name}${variant} extends Component { static glyphName = '${glyphName}' static variant = '${variant}' static displayName = '${name}${variant}' - ${deprecated ? `static deprecated = true` : ''} static allowedProps: Array = [ ...SVGIcon.allowedProps ] ref: Element | null = null @@ -82,13 +81,6 @@ class ${name}${variant} extends Component { } render () { - ${ - deprecated - ? `if (process.env.NODE_ENV !== 'production') { - console.warn('<${name}${variant} /> is deprecated. Please use <${deprecated}${variant} /> instead.') - }` - : '' - } return ( g[1].toUpperCase()) +} + // this is a custom svg to jsx converter function which should be able to handle all of our svgs with some assumptions: // - the root tag is always // - there are no inline styles @@ -34,24 +54,6 @@ export function svg2jsx(svgString) { let jsxString = svgString - // Convert attribute names - const convertAttrName = (name) => { - // Specific SVG attributes that often need direct camelCase even with colons - if (name === 'xlink:href') return 'xlinkHref' - if (name === 'xml:space') return 'xmlSpace' - if (name === 'xml:lang') return 'xmlLang' - - // General kebab-case to camelCase, excluding data-*, aria-*, and xmlns attributes - if ( - name.startsWith('data-') || - name.startsWith('aria-') || - name.startsWith('xmlns') - ) { - return name - } - return name.replace(/-([a-z])/g, (g) => g[1].toUpperCase()) - } - // Process tags and attributes jsxString = jsxString.replace( /<([a-zA-Z0-9:]+)([^>]*?)(\/?)>/g, @@ -61,7 +63,7 @@ export function svg2jsx(svgString) { attrsStr.replace( /([a-zA-Z0-9:_-]+)\s*=\s*(["'])(.*?)\2/g, (attrMatch, name, quote, value) => { - const newName = convertAttrName(name) + const newName = convertSvgAttrName(name) // Escape curly braces within attribute values for JSX const escapedValue = value .replace(/{/g, '{') diff --git a/packages/ui-scripts/package.json b/packages/ui-scripts/package.json index 24e2cffcbd..d21ed82eca 100644 --- a/packages/ui-scripts/package.json +++ b/packages/ui-scripts/package.json @@ -48,7 +48,6 @@ }, "devDependencies": { "fantasticon": "^3.0.0", - "svgo": "^3.3.2", - "svgson": "^5.3.1" + "svgo": "^3.3.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46f04b363e..7ea05f5f84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -449,9 +449,6 @@ importers: react-dom: specifier: 18.3.1 version: 18.3.1(react@18.3.1) - react-window: - specifier: ^2.2.3 - version: 2.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) semver: specifier: ^7.7.2 version: 7.7.3 @@ -3813,9 +3810,6 @@ importers: svgo: specifier: ^3.3.2 version: 3.3.2 - svgson: - specifier: ^5.3.1 - version: 5.3.1 packages/ui-select: dependencies: @@ -8442,10 +8436,6 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - deep-rename-keys@0.2.1: - resolution: {integrity: sha512-RHd9ABw4Fvk+gYDWqwOftG849x0bYOySl/RgX0tLI9i27ZIeSO91mLZJEp7oPHOMFqHvpgu21YptmDt0FYD/0A==} - engines: {node: '>=0.10.0'} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -8924,9 +8914,6 @@ packages: eventemitter2@6.4.7: resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} - eventemitter3@2.0.3: - resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==} - eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -9846,9 +9833,6 @@ packages: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-buffer@2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} @@ -10316,10 +10300,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} - kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -11666,12 +11646,6 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react-window@2.2.3: - resolution: {integrity: sha512-gTRqQYC8ojbiXyd9duYFiSn2TJw0ROXCgYjenOvNKITWzK0m0eCvkUsEUM08xvydkMh7ncp+LE0uS3DeNGZxnQ==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -11772,10 +11746,6 @@ packages: resolution: {integrity: sha512-crQ7Xk1m/F2IiwBx5oTqk/c0hjoumrEz+a36+ZoVupskQRE/q7pAwHKsTNeiZ31sbSTELvVlVv4h1W0Xo5szKg==} engines: {node: '>= 0.8.0'} - rename-keys@1.2.0: - resolution: {integrity: sha512-U7XpAktpbSgHTRSNRrjKSrjYkZKuhUukfoBlXWXUExCAqhzh1TU3BDRAfJmarcl5voKS+pbKU9MvyLWKZ4UEEg==} - engines: {node: '>= 0.8.0'} - renderkid@3.0.0: resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} @@ -12415,9 +12385,6 @@ packages: svgpath@2.6.0: resolution: {integrity: sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==} - svgson@5.3.1: - resolution: {integrity: sha512-qdPgvUNWb40gWktBJnbJRelWcPzkLed/ShhnRsjbayXz8OtdPOzbil9jtiZdrYvSDumAz/VNQr6JaNfPx/gvPA==} - symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} @@ -13220,16 +13187,10 @@ packages: resolution: {integrity: sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==} engines: {node: '>=4'} - xml-lexer@0.2.2: - resolution: {integrity: sha512-G0i98epIwiUEiKmMcavmVdhtymW+pCAohMRgybyIME9ygfVu8QheIi+YoQh3ngiThsT0SQzJT4R0sKDEv8Ou0w==} - xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} - xml-reader@2.4.3: - resolution: {integrity: sha512-xWldrIxjeAMAu6+HSf9t50ot1uL5M+BtOidRCWHXIeewvSeIpscWCsp4Zxjk8kHHhdqFBrfK8U0EJeCcnyQ/gA==} - xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -17223,11 +17184,6 @@ snapshots: deep-is@0.1.4: {} - deep-rename-keys@0.2.1: - dependencies: - kind-of: 3.2.2 - rename-keys: 1.2.0 - deepmerge@4.3.1: {} default-browser-id@5.0.0: {} @@ -17825,8 +17781,6 @@ snapshots: eventemitter2@6.4.7: {} - eventemitter3@2.0.3: {} - eventemitter3@4.0.7: {} eventemitter3@5.0.1: {} @@ -18952,8 +18906,6 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-buffer@1.1.6: {} - is-buffer@2.0.5: {} is-callable@1.2.7: {} @@ -19428,10 +19380,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - kind-of@3.2.2: - dependencies: - is-buffer: 1.1.6 - kind-of@6.0.3: {} klaw-sync@6.0.0: @@ -21070,11 +21018,6 @@ snapshots: react-refresh@0.17.0: {} - react-window@2.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -21211,8 +21154,6 @@ snapshots: dependencies: parse-git-config: 1.1.1 - rename-keys@1.2.0: {} - renderkid@3.0.0: dependencies: css-select: 4.3.0 @@ -21972,11 +21913,6 @@ snapshots: svgpath@2.6.0: {} - svgson@5.3.1: - dependencies: - deep-rename-keys: 0.2.1 - xml-reader: 2.4.3 - symbol-tree@3.2.4: {} tapable@2.3.0: {} @@ -22901,17 +22837,8 @@ snapshots: xdg-basedir@3.0.0: {} - xml-lexer@0.2.2: - dependencies: - eventemitter3: 2.0.3 - xml-name-validator@5.0.0: {} - xml-reader@2.4.3: - dependencies: - eventemitter3: 2.0.3 - xml-lexer: 0.2.2 - xmlchars@2.2.0: {} xtend@4.0.2: {}