diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a571de616..4363cd01c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,6 +21,14 @@ jobs: run: pnpm build:react - run: pnpm test + packaging: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: ./.github/actions/dependencies + - name: Validate packaging + run: pnpm --filter @deque/cauldron-react verify:packaging + screenshots: if: ${{ !contains(github.event.pull_request.labels.*.name, 'update-screenshots') }} runs-on: ubuntu-latest diff --git a/.storybook/main.ts b/.storybook/main.ts index ef6626b81..d44d5998a 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -24,9 +24,15 @@ const config: StorybookConfig = { config.resolve = config.resolve || {}; config.resolve.alias = { ...(config.resolve.alias || {}), - '@deque/cauldron-react': path.resolve( + // Consume the built ESM output. `$` matches the bare barrel import only, + // so the `/cauldron.css` short-form falls through to its own alias. + '@deque/cauldron-react$': path.resolve( process.cwd(), - 'packages/react/lib' + 'packages/react/lib/esm/index.js' + ), + '@deque/cauldron-react/cauldron.css': path.resolve( + process.cwd(), + 'packages/react/lib/cauldron.css' ), react: path.resolve(process.cwd(), 'node_modules/react'), 'react-dom': path.resolve(process.cwd(), 'node_modules/react-dom') diff --git a/docs/index.js b/docs/index.js index f6276251e..7cb1b57ea 100644 --- a/docs/index.js +++ b/docs/index.js @@ -36,7 +36,7 @@ import '@fontsource/pt-mono'; import '../packages/styles'; import '@deque/cauldron-react/cauldron.css'; import './index.css'; -import { useThemeContext } from '../packages/react/lib'; +import { useThemeContext } from '@deque/cauldron-react'; const CAULDRON_THEME_STORAGE_KEY = 'cauldron_theme'; diff --git a/packages/react/package.json b/packages/react/package.json index abdc51deb..1b42084bb 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -7,18 +7,36 @@ "publishConfig": { "access": "public" }, - "main": "lib/index.js", + "main": "lib/cjs/index.js", + "module": "lib/esm/index.js", "style": "lib/cauldron.css", - "types": "lib/index.d.ts", + "types": "lib/cjs/index.d.ts", + "exports": { + ".": { + "import": { + "types": "./lib/esm/index.d.ts", + "default": "./lib/esm/index.js" + }, + "require": { + "types": "./lib/cjs/index.d.ts", + "default": "./lib/cjs/index.js" + } + }, + "./cauldron.css": "./lib/cauldron.css", + "./lib/cauldron.css": "./lib/cauldron.css", + "./package.json": "./package.json" + }, + "sideEffects": false, "files": [ "lib/" ], "scripts": { "build": "pnpm build:lib && pnpm build:css", "prebuild:lib": "node scripts/buildIconTypes.js", - "build:lib": "rollup -c", + "build:lib": "rimraf lib && rollup -c && node scripts/addEsmDeclarationExtensions.js", "build:css": "postcss --output=lib/cauldron.css src/index.css", "typecheck": "tsc --noEmit --skipLibCheck", + "verify:packaging": "pnpm build && node scripts/verifyPackaging.js", "dev": "concurrently 'pnpm build:css --watch' 'rollup -c --watch'", "prepublishOnly": "NODE_ENV=production pnpm build", "test": "jest --maxWorkers=1 --coverage", @@ -38,6 +56,7 @@ "tslib": "^2.4.0" }, "devDependencies": { + "@arethetypeswrong/cli": "^0.18.4", "@babel/core": "^7.29.7", "@babel/plugin-proposal-export-default-from": "^7.29.7", "@babel/preset-env": "^7.29.7", @@ -73,6 +92,7 @@ "postcss-import": "^16.1.1", "postcss-loader": "^8.2.1", "prop-types": "^15.8.1", + "publint": "^0.3.21", "react": "^19", "react-dom": "^19", "rollup": "^2.23.0", diff --git a/packages/react/rollup.config.js b/packages/react/rollup.config.js index f0fef53ce..79ad3088b 100644 --- a/packages/react/rollup.config.js +++ b/packages/react/rollup.config.js @@ -4,62 +4,109 @@ import pkg from './package.json'; import svgr from '@svgr/rollup'; import dynamicImportVar from '@rollup/plugin-dynamic-import-vars'; -export default { - input: 'src/index.ts', - external: [ - ...Object.keys(pkg.dependencies), - ...Object.keys(pkg.peerDependencies), - // Note: We directly import only the specific language syntax needed - // directly in the Code component. This ensures it is still treated as - // an external dependency since it won't match the dependencies or - // peerDependencies when pulled from package.json. - /^react-syntax-highlighter/ - ], - output: { - dir: 'lib', - format: 'cjs', - exports: 'auto', - chunkFileNames: '[name].js' - }, - plugins: [ - typescript({ - tsconfig: './tsconfig.json', - exclude: [ - '**.test.ts', - '**.test.tsx', - '**.figma.tsx', - '**.stories.tsx', - './src/setupTests.ts', - './src/axe.ts' - ] - }), - commonjs(), - svgr({ - svgoConfig: { - plugins: [ - { - name: 'preset-default', - params: { - overrides: { - removeViewBox: false - } - } - }, - { - name: 'removeDimensions', - params: { - active: true - } - }, - { - name: 'addAttributesToSVGElement', - params: { - attributes: [{ height: 24 }, { width: 24 }] - } +const external = [ + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.peerDependencies), + // Note: We directly import only the specific language syntax needed + // directly in the Code component. This ensures it is still treated as + // an external dependency since it won't match the dependencies or + // peerDependencies when pulled from package.json. + /^react-syntax-highlighter/ +]; + +const svgrOptions = { + svgoConfig: { + plugins: [ + { + name: 'preset-default', + params: { + overrides: { + removeViewBox: false } - ] + } + }, + { + name: 'removeDimensions', + params: { + active: true + } + }, + { + name: 'addAttributesToSVGElement', + params: { + attributes: [{ height: 24 }, { width: 24 }] + } } - }), - dynamicImportVar() - ] + ] + } }; + +/** + * Writes a `package.json` into an output directory whose only job is to mark + * the module kind of the emitted `.js` files (e.g. `{"type": "module"}` for the + * ESM output). This lets us keep plain `.js` extensions in both builds while + * Node still resolves each one as the correct module system. + */ +function emitTypeMarker(type) { + return { + name: 'emit-type-marker', + generateBundle() { + this.emitFile({ + type: 'asset', + fileName: 'package.json', + source: `${JSON.stringify({ type }, null, 2)}\n` + }); + } + }; +} + +/** + * Each build compiles from source independently so that its `.d.ts` files land + * beside its `.js` files and are interpreted with the matching module kind — + * this keeps `@arethetypeswrong/cli` happy (no types/runtime "masquerading"). + */ +function build({ format, dir, type }) { + return { + input: 'src/index.ts', + external, + output: { + dir, + format, + // The public entry is the named-export barrel; per-module files expose + // their component as the `default` export (with `__esModule`) for interop. + exports: 'named', + // Preserve the source module graph (one output file per source module, + // mirroring src/) instead of bundling everything into index.js. Combined + // with "sideEffects": false, this is what lets a consumer's bundler drop + // unused components — e.g. a Button-only import excludes Code and its + // react-syntax-highlighter dependency. + preserveModules: true, + preserveModulesRoot: 'src', + entryFileNames: '[name].js' + }, + plugins: [ + typescript({ + tsconfig: './tsconfig.json', + declaration: true, + declarationDir: dir, + exclude: [ + '**.test.ts', + '**.test.tsx', + '**.figma.tsx', + '**.stories.tsx', + './src/setupTests.ts', + './src/axe.ts' + ] + }), + commonjs(), + svgr(svgrOptions), + dynamicImportVar(), + emitTypeMarker(type) + ] + }; +} + +export default [ + build({ format: 'cjs', dir: 'lib/cjs', type: 'commonjs' }), + build({ format: 'es', dir: 'lib/esm', type: 'module' }) +]; diff --git a/packages/react/scripts/addEsmDeclarationExtensions.js b/packages/react/scripts/addEsmDeclarationExtensions.js new file mode 100644 index 000000000..b2738139d --- /dev/null +++ b/packages/react/scripts/addEsmDeclarationExtensions.js @@ -0,0 +1,81 @@ +/** + * Adds explicit file extensions to relative imports in the ESM build's `.d.ts` + * files. + * + * TypeScript emits declarations using the source's classic `moduleResolution: + * node`, so relative specifiers are extensionless (`from './components/Button'`). + * The ESM output carries a `{"type":"module"}` marker, and under + * `moduleResolution: node16`/`nodenext` a consumer resolves those declarations + * with ESM rules — where extensionless relative imports are an error. The + * runtime `.js` already has correct extensions (Rollup adds them); this brings + * the `.d.ts` in line so types resolve cleanly for node16-from-ESM consumers. + * + * Only `lib/esm` is processed: the `lib/cjs` declarations are resolved with + * CommonJS rules, which infer the extension. + */ +const fs = require('node:fs'); +const path = require('node:path'); + +const esmDir = path.join(__dirname, '..', 'lib', 'esm'); + +// `from ''`, `import('')`, and `export ... from ''` all match. +const SPECIFIER = /(\bfrom\s*|\bimport\s*\(\s*)(['"])(\.\.?\/[^'"]*)\2/g; + +/** Resolve an extensionless relative specifier to its emitted `.js` path. */ +function withExtension(fromFileDir, specifier) { + if (/\.(js|mjs|cjs|json|css)$/.test(specifier)) { + return null; // already explicit + } + const resolved = path.resolve(fromFileDir, specifier); + if (fs.existsSync(`${resolved}.d.ts`)) { + return `${specifier}.js`; + } + if (fs.existsSync(path.join(resolved, 'index.d.ts'))) { + return `${specifier}/index.js`; + } + return null; // external or unresolved — leave untouched +} + +function processFile(file) { + const source = fs.readFileSync(file, 'utf8'); + const dir = path.dirname(file); + let changed = false; + + const output = source.replace( + SPECIFIER, + (match, prefix, quote, specifier) => { + const rewritten = withExtension(dir, specifier); + if (!rewritten) { + return match; + } + changed = true; + return `${prefix}${quote}${rewritten}${quote}`; + } + ); + + if (changed) { + fs.writeFileSync(file, output); + } + return changed; +} + +function walk(dir) { + let count = 0; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + count += walk(full); + } else if (entry.name.endsWith('.d.ts')) { + count += processFile(full) ? 1 : 0; + } + } + return count; +} + +if (!fs.existsSync(esmDir)) { + console.error(`Missing ESM build at ${esmDir}. Run the rollup build first.`); + process.exit(1); +} + +const changed = walk(esmDir); +console.log('Added ESM declaration extensions in %d file(s)', changed); diff --git a/packages/react/scripts/packaging-smoke/dual-resolution.mjs b/packages/react/scripts/packaging-smoke/dual-resolution.mjs new file mode 100644 index 000000000..3e962e5da --- /dev/null +++ b/packages/react/scripts/packaging-smoke/dual-resolution.mjs @@ -0,0 +1,27 @@ +// Dual-resolution wiring check. +// +// With the `exports` map, `import` resolves to the ESM build and `require` to +// the CJS build. They are therefore DISTINCT copies — the accepted, documented +// dual-package tradeoff (a runtime mixing both loads two copies; see the PR / +// changelog). This asserts both conditions resolve and expose the full public +// API, so the exports map is wired correctly for ESM and CJS consumers alike. +import assert from 'node:assert'; +import { createRequire } from 'node:module'; +import * as esm from '@deque/cauldron-react'; + +const require = createRequire(import.meta.url); +const cjs = require('@deque/cauldron-react'); + +for (const [label, api] of [ + ['import (ESM)', esm], + ['require (CJS)', cjs] +]) { + assert(api.Button, `${label}: expected \`Button\` export`); + assert(api.ThemeProvider, `${label}: expected \`ThemeProvider\` export`); + assert(api.ThemeContext, `${label}: expected \`ThemeContext\` export`); +} + +console.log( + 'dual-resolution OK: import→ESM and require→CJS both expose the API ' + + `(distinct copies: ${esm.ThemeContext !== cjs.ThemeContext})` +); diff --git a/packages/react/scripts/packaging-smoke/smoke.cjs b/packages/react/scripts/packaging-smoke/smoke.cjs new file mode 100644 index 000000000..6d7f1cb2d --- /dev/null +++ b/packages/react/scripts/packaging-smoke/smoke.cjs @@ -0,0 +1,15 @@ +// Smoke test: the packed tarball resolves under CommonJS `require`. +// Runs inside a throwaway consumer where the tarball is installed (not the +// workspace symlink), so this exercises the real published resolution. +const assert = require('node:assert'); + +const cauldron = require('@deque/cauldron-react'); + +assert(cauldron.Button, 'require: expected `Button` named export'); +assert(cauldron.Modal, 'require: expected `Modal` named export'); +assert( + typeof cauldron.Button === 'object' || typeof cauldron.Button === 'function', + 'require: `Button` is not a renderable component' +); + +console.log('require("@deque/cauldron-react") OK'); diff --git a/packages/react/scripts/packaging-smoke/smoke.mjs b/packages/react/scripts/packaging-smoke/smoke.mjs new file mode 100644 index 000000000..27f6d2714 --- /dev/null +++ b/packages/react/scripts/packaging-smoke/smoke.mjs @@ -0,0 +1,20 @@ +// Smoke test: the packed tarball resolves under native ESM `import`. +// Runs inside a throwaway consumer where the tarball is installed (not the +// workspace symlink), so this exercises the real published resolution. +import assert from 'node:assert'; + +// The barrel is named-exports only (no default). Under the ESM condition this +// is real ESM, so exercise named + namespace imports — a `default` import would +// (correctly) fail. +import * as cauldron from '@deque/cauldron-react'; +import { Button, Modal } from '@deque/cauldron-react'; + +assert(Button, 'import: expected `Button` named export'); +assert(Modal, 'import: expected `Modal` named export'); +assert(cauldron.Button, 'import: expected `Button` on the namespace'); +assert( + typeof Button === 'object' || typeof Button === 'function', + 'import: `Button` is not a renderable component' +); + +console.log('import "@deque/cauldron-react" OK'); diff --git a/packages/react/scripts/packaging-smoke/treeshake.entry.js b/packages/react/scripts/packaging-smoke/treeshake.entry.js new file mode 100644 index 000000000..78e4b54b3 --- /dev/null +++ b/packages/react/scripts/packaging-smoke/treeshake.entry.js @@ -0,0 +1,7 @@ +// Tree-shaking fixture: import ONLY Button. If the package is tree-shakeable, +// a production bundler must drop Code, react-syntax-highlighter, +// react-aria-components, and every other component from the output. +import { Button } from '@deque/cauldron-react'; + +// Reference it so it isn't dead-code-eliminated as an unused import. +export default Button; diff --git a/packages/react/scripts/packaging-smoke/treeshake.vite.config.js b/packages/react/scripts/packaging-smoke/treeshake.vite.config.js new file mode 100644 index 000000000..c57a1212a --- /dev/null +++ b/packages/react/scripts/packaging-smoke/treeshake.vite.config.js @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; + +// Bundle the Button-only entry as a library so we can inspect exactly what a +// consumer's production bundler (Vite delegates to Rollup) keeps after +// tree-shaking. Unminified so the assertion can match readable module paths. +export default defineConfig({ + build: { + minify: false, + lib: { + entry: 'treeshake.entry.js', + formats: ['es'], + fileName: 'treeshake.out' + }, + rollupOptions: { + external: ['react', 'react-dom', 'react/jsx-runtime'] + } + } +}); diff --git a/packages/react/scripts/verifyPackaging.js b/packages/react/scripts/verifyPackaging.js new file mode 100644 index 000000000..92793453a --- /dev/null +++ b/packages/react/scripts/verifyPackaging.js @@ -0,0 +1,198 @@ +/** + * Packaging validation harness for @deque/cauldron-react. + * + * Validates the *published* artifact rather than the workspace source: + * + * 1. Pack the package with `pnpm pack` (honors the `files` allowlist). + * 2. `publint` — lint the tarball for packaging mistakes. + * 3. `attw` — check that types resolve for every module condition. + * 4. Smoke test — install the tarball into a throwaway consumer and confirm + * it resolves under both `require(...)` and native `import`. + * 5. Exports resolution — confirm `import` resolves to the ESM build and + * `require` to the CJS build, both exposing the full public API. + * 6. Tree-shaking — bundle a Button-only consumer with Vite (Rollup) and + * assert the unused component graph (Code, react-syntax-highlighter, + * react-aria-components) is dropped. + * + * The consumers install from the tarball (not a workspace symlink), so + * resolution matches what a real consumer would get from npm. + * + * Prerequisite: `lib/` must already be built (`pnpm build`). Run via the + * `verify:packaging` package script, which builds first. + */ +const { execFileSync } = require('node:child_process'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); + +const packageRoot = path.join(__dirname, '..'); +const smokeFixtures = path.join(__dirname, 'packaging-smoke'); +const libDir = path.join(packageRoot, 'lib'); + +function step(message) { + console.log(`\n› ${message}`); +} + +function run(command, args, options = {}) { + console.log(`$ ${command} ${args.join(' ')}`); + execFileSync(command, args, { stdio: 'inherit', ...options }); +} + +if (!fs.existsSync(path.join(libDir, 'cjs', 'index.js'))) { + console.error( + 'Missing build output at lib/cjs/index.js. Run `pnpm build` before verifying packaging.' + ); + process.exit(1); +} + +const workDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cauldron-pkg-')); + +try { + step('Packing tarball'); + run('pnpm', ['pack', '--pack-destination', workDir], { cwd: packageRoot }); + + const tarball = fs + .readdirSync(workDir) + .filter((file) => file.endsWith('.tgz')) + .map((file) => path.join(workDir, file))[0]; + + if (!tarball) { + throw new Error(`pnpm pack did not produce a tarball in ${workDir}`); + } + console.log(`Packed ${path.basename(tarball)}`); + + step('Linting tarball with publint'); + run('pnpm', ['exec', 'publint', '--strict', tarball], { cwd: packageRoot }); + + step('Checking type resolution with @arethetypeswrong/cli'); + // The CSS export has no types — attw would report it as an unresolvable + // module, so exclude the stylesheet entrypoints from the type check. + run( + 'pnpm', + [ + 'exec', + 'attw', + tarball, + '--exclude-entrypoints', + 'cauldron.css', + 'lib/cauldron.css' + ], + { cwd: packageRoot } + ); + + step('Smoke testing require() + import from the packed tarball'); + const consumerDir = path.join(workDir, 'consumer'); + fs.mkdirSync(consumerDir); + fs.writeFileSync( + path.join(consumerDir, 'package.json'), + JSON.stringify( + { name: 'cauldron-packaging-smoke', version: '0.0.0', private: true }, + null, + 2 + ) + ); + fs.copyFileSync( + path.join(smokeFixtures, 'smoke.cjs'), + path.join(consumerDir, 'smoke.cjs') + ); + fs.copyFileSync( + path.join(smokeFixtures, 'smoke.mjs'), + path.join(consumerDir, 'smoke.mjs') + ); + fs.copyFileSync( + path.join(smokeFixtures, 'dual-resolution.mjs'), + path.join(consumerDir, 'dual-resolution.mjs') + ); + + // Install with npm into an isolated dir so resolution is hermetic and does + // not touch the pnpm workspace. react/react-dom satisfy the peer range. + run( + 'npm', + [ + 'install', + tarball, + 'react@^19', + 'react-dom@^19', + '--no-audit', + '--no-fund', + '--no-package-lock' + ], + { cwd: consumerDir } + ); + run('node', ['smoke.cjs'], { cwd: consumerDir }); + run('node', ['smoke.mjs'], { cwd: consumerDir }); + + step('Verifying exports resolution (import→ESM, require→CJS)'); + run('node', ['dual-resolution.mjs'], { cwd: consumerDir }); + + step('Verifying tree-shaking (Button-only import drops unused components)'); + const treeshakeDir = path.join(workDir, 'treeshake'); + fs.mkdirSync(treeshakeDir); + fs.writeFileSync( + path.join(treeshakeDir, 'package.json'), + JSON.stringify( + { + name: 'cauldron-treeshake', + version: '0.0.0', + private: true, + type: 'module' + }, + null, + 2 + ) + ); + fs.copyFileSync( + path.join(smokeFixtures, 'treeshake.entry.js'), + path.join(treeshakeDir, 'treeshake.entry.js') + ); + fs.copyFileSync( + path.join(smokeFixtures, 'treeshake.vite.config.js'), + path.join(treeshakeDir, 'vite.config.js') + ); + run( + 'npm', + [ + 'install', + tarball, + 'react@^19', + 'react-dom@^19', + 'vite@^7', + '--no-audit', + '--no-fund', + '--no-package-lock' + ], + { cwd: treeshakeDir } + ); + run('npx', ['vite', 'build'], { cwd: treeshakeDir }); + + // A Button-only bundle must not contain any of these — their presence means + // an unused component (and its heavy deps) failed to tree-shake. + const forbidden = [ + 'react-syntax-highlighter', + 'react-aria', + 'registerLanguage', + 'hljs', + 'lowlight' + ]; + const outDir = path.join(treeshakeDir, 'dist'); + const bundle = fs + .readdirSync(outDir) + .filter((file) => file.endsWith('.js')) + .map((file) => fs.readFileSync(path.join(outDir, file), 'utf8')) + .join('\n'); + const leaked = forbidden.filter((marker) => bundle.includes(marker)); + if (leaked.length > 0) { + throw new Error( + `Tree-shaking regressed: a Button-only bundle still contains ${leaked.join( + ', ' + )}.` + ); + } + console.log( + `Tree-shaking OK: Button-only bundle excludes ${forbidden.join(', ')}` + ); + + console.log('\n✓ Packaging validation passed'); +} finally { + fs.rmSync(workDir, { recursive: true, force: true }); +} diff --git a/packages/react/src/components/Code/index.tsx b/packages/react/src/components/Code/index.tsx index 6ed6ab23b..2e272df80 100644 --- a/packages/react/src/components/Code/index.tsx +++ b/packages/react/src/components/Code/index.tsx @@ -1,15 +1,39 @@ import React, { useRef, useState, useEffect } from 'react'; import { SyntaxHighlighterProps } from 'react-syntax-highlighter'; -import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light'; +// Fully-specified (`.js`) cjs subpaths: react-syntax-highlighter has no +// `exports` map, so the ESM build's `{"type":"module"}` marker makes strict +// bundlers (webpack 5) resolve these fully-specified — an extensionless +// specifier fails there. The cjs paths (not esm) are kept deliberately: they +// resolve under Node `require`, Node ESM interop, and bundlers alike, whereas +// the esm subpaths are bare ESM in a non-module package and break under Node. +import SyntaxHighlighterImport from 'react-syntax-highlighter/dist/cjs/light.js'; import classNames from 'classnames'; -import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'; -import css from 'react-syntax-highlighter/dist/cjs/languages/hljs/css'; -import xml from 'react-syntax-highlighter/dist/cjs/languages/hljs/xml'; -import yaml from 'react-syntax-highlighter/dist/cjs/languages/hljs/yaml'; +import jsImport from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript.js'; +import cssImport from 'react-syntax-highlighter/dist/cjs/languages/hljs/css.js'; +import xmlImport from 'react-syntax-highlighter/dist/cjs/languages/hljs/xml.js'; +import yamlImport from 'react-syntax-highlighter/dist/cjs/languages/hljs/yaml.js'; import type { ContentNode } from '../../types'; import { useId } from 'react-id-generator'; import CopyButton, { CopyButtonProps } from '../CopyButton'; +// Normalize a CommonJS default export. Under strict ESM (Next.js SSR, webpack, +// Node-native) a CJS module that sets `__esModule` is delivered double-wrapped +// (`{ __esModule, default }`), so the default import is the wrapper rather than +// the value — without this, `SyntaxHighlighter.registerLanguage` is undefined +// and module evaluation throws. Bundlers like Vite already unwrap, so this is a +// no-op there. +function interopDefault(mod: T): T { + return (mod as { __esModule?: boolean; default?: T })?.__esModule + ? (mod as { default: T }).default + : mod; +} + +const SyntaxHighlighter = interopDefault(SyntaxHighlighterImport); +const js = interopDefault(jsImport); +const css = interopDefault(cssImport); +const xml = interopDefault(xmlImport); +const yaml = interopDefault(yamlImport); + SyntaxHighlighter.registerLanguage('javascript', js); SyntaxHighlighter.registerLanguage('css', css); SyntaxHighlighter.registerLanguage('html', xml); diff --git a/packages/react/src/components/TopBar/TopBarMenu.test.tsx b/packages/react/src/components/TopBar/TopBarMenu.test.tsx index 12422b9e7..26a9f2f02 100644 --- a/packages/react/src/components/TopBar/TopBarMenu.test.tsx +++ b/packages/react/src/components/TopBar/TopBarMenu.test.tsx @@ -3,7 +3,7 @@ import { OptionsMenuList } from '../OptionsMenu'; import { fireEvent, render, screen } from '@testing-library/react'; import TopBarMenu from './TopBarMenu'; import { MenuBar, TopBar } from '../..'; -import { MenuItem } from '../../../lib'; +import { MenuItem } from '../../index'; import axe from '../../axe'; const [rightCode, leftCode, downCode] = [39, 37, 40]; diff --git a/packages/react/src/components/TopBar/topBar.test.tsx b/packages/react/src/components/TopBar/topBar.test.tsx index a47868dfe..1d1bd0aec 100644 --- a/packages/react/src/components/TopBar/topBar.test.tsx +++ b/packages/react/src/components/TopBar/topBar.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; -import { ThemeProvider } from '../../../lib'; +import { ThemeProvider } from '../../index'; import TopBar, { TopBarItem } from './'; import MenuBar from '../MenuBar/'; import axe from '../../axe'; diff --git a/packages/react/src/react-syntax-highlighter.d.ts b/packages/react/src/react-syntax-highlighter.d.ts new file mode 100644 index 000000000..b1a2795bc --- /dev/null +++ b/packages/react/src/react-syntax-highlighter.d.ts @@ -0,0 +1,21 @@ +/** + * `@types/react-syntax-highlighter` only declares the extensionless subpaths + * (e.g. `.../dist/cjs/light`). The `Code` component imports the fully-specified + * `.js` subpaths — required so strict-ESM bundlers can resolve them out of our + * ESM build — so re-declare those to reuse the real types. + */ +declare module 'react-syntax-highlighter/dist/cjs/light.js' { + export { default } from 'react-syntax-highlighter/dist/cjs/light'; +} +declare module 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript.js' { + export { default } from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript'; +} +declare module 'react-syntax-highlighter/dist/cjs/languages/hljs/css.js' { + export { default } from 'react-syntax-highlighter/dist/cjs/languages/hljs/css'; +} +declare module 'react-syntax-highlighter/dist/cjs/languages/hljs/xml.js' { + export { default } from 'react-syntax-highlighter/dist/cjs/languages/hljs/xml'; +} +declare module 'react-syntax-highlighter/dist/cjs/languages/hljs/yaml.js' { + export { default } from 'react-syntax-highlighter/dist/cjs/languages/hljs/yaml'; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5138d7b65..b8b84d264 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,7 +248,7 @@ importers: version: 4.0.0(webpack@5.106.2) terser-webpack-plugin: specifier: ^5.6.0 - version: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2) + version: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2(esbuild@0.27.7)(postcss@8.5.15)(webpack-cli@7.0.2)) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.19.17)(typescript@6.0.3) @@ -298,6 +298,9 @@ importers: specifier: ^2.4.0 version: 2.8.1 devDependencies: + '@arethetypeswrong/cli': + specifier: ^0.18.4 + version: 0.18.4 '@babel/core': specifier: ^7.29.7 version: 7.29.7 @@ -403,6 +406,9 @@ importers: prop-types: specifier: ^15.8.1 version: 15.8.1 + publint: + specifier: ^0.3.21 + version: 0.3.21 react: specifier: ^19 version: 19.2.6 @@ -446,6 +452,18 @@ packages: '@adobe/css-tools@4.4.0': resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} + '@andrewbranch/untar.js@1.0.3': + resolution: {integrity: sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw==} + + '@arethetypeswrong/cli@0.18.4': + resolution: {integrity: sha512-kNWo6LTzGAuLYPpJ7Sgo63whSUeeSuKMlYx6IBgzs4ONEG807gW4hSSENvpeCHzO2H2wIzG5EFl0OKBbqGBAyA==} + engines: {node: '>=20'} + hasBin: true + + '@arethetypeswrong/core@0.18.4': + resolution: {integrity: sha512-M5F0ePyN6h2Z6XxRiyIPqjGbltotXLjR0CKA0uKspsDu0QmgTNYvRb4RSQPMUs2ZXZHCCYpbaZbFbYOXLxCjUA==} + engines: {node: '>=20'} + '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -1110,6 +1128,13 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@braidai/lang@1.1.2': + resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1832,6 +1857,9 @@ packages: '@leichtgewicht/ip-codec@2.0.4': resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} + '@loaderkit/resolve@1.0.6': + resolution: {integrity: sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg==} + '@mdx-js/loader@3.1.1': resolution: {integrity: sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==} peerDependencies: @@ -2157,6 +2185,10 @@ packages: engines: {node: '>=18'} hasBin: true + '@publint/pack@0.1.5': + resolution: {integrity: sha512-edgyN2pP07uXiP4tJs0s8KVmU8M8i60YPbbI0/WDeok1mIJHRXz+CgD8I0nelwDkoCh3EWL/G5kGfbuHjsdbvw==} + engines: {node: '>=18'} + '@puppeteer/browsers@2.13.0': resolution: {integrity: sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==} engines: {node: '>=18'} @@ -2939,6 +2971,10 @@ packages: '@sinclair/typebox@0.34.49': resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + '@sinonjs/commons@1.8.6': resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} @@ -3753,6 +3789,10 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -3769,6 +3809,9 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -4154,6 +4197,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -4225,10 +4272,19 @@ packages: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@5.1.0: resolution: {integrity: sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==} engines: {node: '>=20'} @@ -4300,6 +4356,10 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -4376,10 +4436,12 @@ packages: conventional-changelog-atom@2.0.8: resolution: {integrity: sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-codemirror@2.0.8: resolution: {integrity: sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-config-spec@2.1.0: resolution: {integrity: sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ==} @@ -4391,26 +4453,32 @@ packages: conventional-changelog-core@4.2.4: resolution: {integrity: sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg==} engines: {node: '>=10'} + deprecated: Deprecated and no longer maintained. Please use conventional-changelog instead. conventional-changelog-ember@2.0.9: resolution: {integrity: sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-eslint@3.0.9: resolution: {integrity: sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-express@2.0.6: resolution: {integrity: sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-jquery@3.0.11: resolution: {integrity: sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-jshint@2.0.9: resolution: {integrity: sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==} engines: {node: '>=10'} + deprecated: This preset is deprecated. Please use conventional-changelog-conventionalcommits or conventional-changelog-angular instead. conventional-changelog-preset-loader@2.3.4: resolution: {integrity: sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==} @@ -4897,6 +4965,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + emojilib@2.4.0: + resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -5235,6 +5306,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -5432,7 +5506,7 @@ packages: git-raw-commits@2.0.11: resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} engines: {node: '>=10'} - deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. + deprecated: Deprecated and no longer maintained. Use @conventional-changelog/git-client instead. hasBin: true git-remote-origin-url@2.0.0: @@ -5442,7 +5516,7 @@ packages: git-semver-tags@4.1.1: resolution: {integrity: sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA==} engines: {node: '>=10'} - deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. + deprecated: Deprecated and no longer maintained. Use @conventional-changelog/git-client instead. hasBin: true gitconfiglocal@1.0.0: @@ -6450,6 +6524,17 @@ packages: markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + marked-terminal@7.3.0: + resolution: {integrity: sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==} + engines: {node: '>=16.0.0'} + peerDependencies: + marked: '>=1 <16' + + marked@9.1.6: + resolution: {integrity: sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==} + engines: {node: '>= 16'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -6747,6 +6832,10 @@ packages: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -6757,6 +6846,9 @@ packages: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -6801,6 +6893,10 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead + node-emoji@2.2.0: + resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} + engines: {node: '>=18'} + node-fetch@3.3.2: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6988,6 +7084,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.7.0: + resolution: {integrity: sha512-xg1eHpwYL/D/HEdWw2goFZP6vV0FH7W+PZ5rFkGjdIDLtxq7EkzBUeT3m+lndYCt8wKbmofUu1MUdMCXkCk9ZQ==} + pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -7009,6 +7108,15 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -7442,6 +7550,11 @@ packages: psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + publint@0.3.21: + resolution: {integrity: sha512-OqejcnMV6E9zel2oCrUOJEiiFkGiAAni0A6ibfQNh1k9Gu5z4F+Yso8lllam7AzmV6Do0vp7u3UpZNRBwuXaHQ==} + engines: {node: '>=18'} + hasBin: true + pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} @@ -7837,6 +7950,10 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -7996,6 +8113,10 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + skin-tone@2.0.0: + resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==} + engines: {node: '>=8'} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -8265,6 +8386,10 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -8360,6 +8485,13 @@ packages: thenby@1.4.1: resolution: {integrity: sha512-D5a/bO0KdalOE3q8MlrRmSxjbKZHT3MQmXkJP+r97Vw8MMwOZKOwUSEyTtK7eSMj2y0kyAjpYMRMZmmLw1FtNQ==} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thingies@1.21.0: resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} engines: {node: '>=10.18'} @@ -8388,6 +8520,10 @@ packages: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} @@ -8553,6 +8689,11 @@ packages: engines: {node: '>=12.20'} hasBin: true + typescript@5.6.1-rc: + resolution: {integrity: sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} @@ -8578,6 +8719,10 @@ packages: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} + unicode-emoji-modifier-base@1.0.0: + resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} + engines: {node: '>=4'} + unicode-match-property-ecmascript@2.0.0: resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} engines: {node: '>=4'} @@ -8694,6 +8839,10 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -9088,6 +9237,29 @@ snapshots: '@adobe/css-tools@4.4.0': {} + '@andrewbranch/untar.js@1.0.3': {} + + '@arethetypeswrong/cli@0.18.4': + dependencies: + '@arethetypeswrong/core': 0.18.4 + chalk: 4.1.2 + cli-table3: 0.6.5 + commander: 10.0.1 + marked: 9.1.6 + marked-terminal: 7.3.0(marked@9.1.6) + semver: 7.8.1 + + '@arethetypeswrong/core@0.18.4': + dependencies: + '@andrewbranch/untar.js': 1.0.3 + '@loaderkit/resolve': 1.0.6 + cjs-module-lexer: 1.4.3 + fflate: 0.8.3 + lru-cache: 11.5.1 + semver: 7.8.1 + typescript: 5.6.1-rc + validate-npm-package-name: 5.0.1 + '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -9929,6 +10101,11 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@braidai/lang@1.1.2': {} + + '@colors/colors@1.5.0': + optional: true + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -10571,6 +10748,10 @@ snapshots: '@leichtgewicht/ip-codec@2.0.4': {} + '@loaderkit/resolve@1.0.6': + dependencies: + '@braidai/lang': 1.1.2 + '@mdx-js/loader@3.1.1(acorn@8.16.0)(webpack@5.106.2)': dependencies: '@mdx-js/mdx': 3.1.0(acorn@8.16.0) @@ -10894,6 +11075,10 @@ snapshots: dependencies: playwright: 1.50.1 + '@publint/pack@0.1.5': + dependencies: + tinyexec: 1.2.4 + '@puppeteer/browsers@2.13.0': dependencies: debug: 4.4.3 @@ -12077,6 +12262,8 @@ snapshots: '@sinclair/typebox@0.34.49': {} + '@sindresorhus/is@4.6.0': {} + '@sinonjs/commons@1.8.6': dependencies: type-detect: 4.0.8 @@ -12147,7 +12334,7 @@ snapshots: magic-string: 0.30.21 storybook: 10.4.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@testing-library/dom@10.4.0)(@types/react@19.2.15)(prettier@3.8.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) style-loader: 4.0.0(webpack@5.106.2) - terser-webpack-plugin: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2) + terser-webpack-plugin: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2(esbuild@0.27.7)(postcss@8.5.15)(webpack-cli@7.0.2)) ts-dedent: 2.2.0 webpack: 5.106.2(esbuild@0.27.7)(postcss@8.5.15)(webpack-cli@7.0.2) webpack-dev-middleware: 6.1.3(webpack@5.106.2) @@ -12876,7 +13063,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@6.0.3) eslint: 8.57.0 eslint-scope: 5.1.1 - semver: 7.8.0 + semver: 7.8.1 transitivePeerDependencies: - supports-color - typescript @@ -13100,6 +13287,8 @@ snapshots: ansi-regex@6.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -13113,6 +13302,8 @@ snapshots: ansi-styles@6.2.1: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -13578,6 +13769,8 @@ snapshots: ansi-styles: 4.2.1 supports-color: 7.1.0 + chalk@5.6.2: {} + char-regex@1.0.2: {} character-entities-html4@2.1.0: {} @@ -13638,8 +13831,23 @@ snapshots: dependencies: restore-cursor: 5.1.0 + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + cli-spinners@2.9.2: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@5.1.0: dependencies: slice-ansi: 7.1.0 @@ -13711,6 +13919,8 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} + commander@11.1.0: {} commander@14.0.3: {} @@ -14353,6 +14563,8 @@ snapshots: emoji-regex@9.2.2: {} + emojilib@2.4.0: {} + encodeurl@2.0.0: {} end-of-stream@1.4.4: @@ -14951,6 +15163,8 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.2.1 + fflate@0.8.3: {} + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -16504,6 +16718,19 @@ snapshots: markdown-table@3.0.3: {} + marked-terminal@7.3.0(marked@9.1.6): + dependencies: + ansi-escapes: 7.0.0 + ansi-regex: 6.2.2 + chalk: 5.6.2 + cli-highlight: 2.1.11 + cli-table3: 0.6.5 + marked: 9.1.6 + node-emoji: 2.2.0 + supports-hyperlinks: 3.2.0 + + marked@9.1.6: {} + math-intrinsics@1.1.0: {} mdast-util-find-and-replace@3.0.2: @@ -17066,6 +17293,8 @@ snapshots: modify-values@1.0.1: {} + mri@1.2.0: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -17075,6 +17304,12 @@ snapshots: dns-packet: 5.6.0 thunky: 1.1.0 + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.12: {} natural-compare-lite@1.4.0: {} @@ -17108,6 +17343,13 @@ snapshots: node-domexception@1.0.0: {} + node-emoji@2.2.0: + dependencies: + '@sindresorhus/is': 4.6.0 + char-regex: 1.0.2 + emojilib: 2.4.0 + skin-tone: 2.0.0 + node-fetch@3.3.2: dependencies: data-uri-to-buffer: 4.0.1 @@ -17401,6 +17643,8 @@ snapshots: package-json-from-dist@1.0.1: {} + package-manager-detector@1.7.0: {} + pako@0.2.9: {} param-case@3.0.4: @@ -17434,6 +17678,14 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -17845,6 +18097,13 @@ snapshots: psl@1.9.0: {} + publint@0.3.21: + dependencies: + '@publint/pack': 0.1.5 + package-manager-detector: 1.7.0 + picocolors: 1.1.1 + sade: 1.8.1 + pump@3.0.0: dependencies: end-of-stream: 1.4.4 @@ -18487,6 +18746,10 @@ snapshots: dependencies: tslib: 2.8.1 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -18699,6 +18962,10 @@ snapshots: sisteransi@1.0.5: {} + skin-tone@2.0.0: + dependencies: + unicode-emoji-modifier-base: 1.0.0 + slash@3.0.0: {} slash@5.1.0: {} @@ -19033,6 +19300,11 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.1.0 + supports-preserve-symlinks-flag@1.0.0: {} svg-parser@2.0.4: {} @@ -19077,7 +19349,7 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.22.0 - terser-webpack-plugin@5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2): + terser-webpack-plugin@5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2(esbuild@0.27.7)(postcss@8.5.15)(webpack-cli@7.0.2)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 @@ -19111,6 +19383,14 @@ snapshots: thenby@1.4.1: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + thingies@1.21.0(tslib@2.8.1): dependencies: tslib: 2.8.1 @@ -19134,6 +19414,8 @@ snapshots: tinyexec@1.0.4: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -19312,6 +19594,8 @@ snapshots: typescript@5.0.4: {} + typescript@5.6.1-rc: {} + typescript@6.0.3: {} uglify-js@3.17.4: @@ -19330,6 +19614,8 @@ snapshots: unicode-canonical-property-names-ecmascript@2.0.1: {} + unicode-emoji-modifier-base@1.0.0: {} + unicode-match-property-ecmascript@2.0.0: dependencies: unicode-canonical-property-names-ecmascript: 2.0.1 @@ -19481,6 +19767,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + validate-npm-package-name@5.0.1: {} + vary@1.1.2: {} vfile-message@3.1.4: @@ -19676,7 +19964,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2) + terser-webpack-plugin: 5.6.0(esbuild@0.27.7)(postcss@8.5.15)(webpack@5.106.2(esbuild@0.27.7)(postcss@8.5.15)(webpack-cli@7.0.2)) watchpack: 2.5.1 webpack-sources: 3.3.4 optionalDependencies: diff --git a/webpack.config.mjs b/webpack.config.mjs index 2495dd26f..5964f2e6f 100644 --- a/webpack.config.mjs +++ b/webpack.config.mjs @@ -75,7 +75,16 @@ const config = { alias: { react: path.resolve(__dirname, './node_modules/react'), 'react-dom': path.resolve(__dirname, './node_modules/react-dom'), - '@deque/cauldron-react': path.resolve(__dirname, './packages/react/lib') + // Consume the built ESM output. `$` matches the bare barrel import only, + // so the `/cauldron.css` short-form falls through to its own alias below. + '@deque/cauldron-react$': path.resolve( + __dirname, + './packages/react/lib/esm/index.js' + ), + '@deque/cauldron-react/cauldron.css': path.resolve( + __dirname, + './packages/react/lib/cauldron.css' + ) }, fallback: { path: false