diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000..654c6d4 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets). + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md). diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..ec98e35 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/initial-1-0-0.md b/.changeset/initial-1-0-0.md new file mode 100644 index 0000000..b2298be --- /dev/null +++ b/.changeset/initial-1-0-0.md @@ -0,0 +1,5 @@ +--- +"@textcortex/slidewise": major +--- + +First versioned release. Marks the public API surface (`SlidewiseEditor`, `SlidewiseFileEditor`, `parsePptx`, `serializeDeck`, `Deck`, `migrate`) as the v1 contract that hosts can pin against. Earlier 0.x builds were unpublished. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9fe35f7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-test: + name: Typecheck, test, build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm exec tsc -b + + - name: Test + run: pnpm test + + - name: Build library bundle + run: pnpm run build:lib diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..768d587 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: Release + +# On every push to main: if there are pending changesets, open (or update) a +# "Version Packages" PR that consumes them and bumps package.json + writes +# CHANGELOG. When that PR is merged there are no pending changesets, so the +# action publishes to the registry instead. +# +# Required secrets: +# NPM_TOKEN — automation token with publish access for @textcortex scope. +# If absent, the publish step is skipped (the Version Packages +# PR still gets opened). +on: + push: + branches: + - main + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: write + pull-requests: write + id-token: write + +jobs: + release: + name: Version or publish + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # changesets needs full history to compute changelog deltas. + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm exec tsc -b + + - name: Test + run: pnpm test + + - name: Build library bundle + run: pnpm run build:lib + + - name: Create release PR or publish + uses: changesets/action@v1 + with: + # Bump versions and update CHANGELOG when a Version Packages PR is + # opened/updated; publish to the registry when it merges. + version: pnpm run version-packages + publish: pnpm run release + commit: "chore(release): version packages" + title: "chore(release): version packages" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index ad155ed..c4707bb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,112 @@ -# SlideWise -PPTX + React = ❤️ +# Slidewise + +Embeddable React PPTX editor. PPTX import + canvas editor + PPTX export, in +one component. + +```bash +pnpm add @textcortex/slidewise +``` + +Peer dependencies: `react >=19`, `react-dom >=19`. + +## Quick start + +`SlidewiseFileEditor` wraps the editor with PPTX load/save plumbing — give it +async `loadBlob` and `saveBlob` callbacks and it handles parsing, dirty +tracking, and serialisation. + +```tsx +import { + SlidewiseFileEditor, + type SlidewiseFileEditorApi, +} from "@textcortex/slidewise"; +import "@textcortex/slidewise/style.css"; +import { useRef } from "react"; + +export function PresentationsRoute({ fileId }: { fileId: string }) { + const apiRef = useRef(null); + + return ( + (apiRef.current = api)} + loadBlob={async () => { + const res = await fetch(`/api/files/${fileId}`); + return res.blob(); + }} + saveBlob={async (pptx) => { + await fetch(`/api/files/${fileId}`, { method: "PUT", body: pptx }); + }} + /> + ); +} +``` + +The host owns transport and conflict detection; Slidewise owns parsing, +editing, and serialisation. Call `apiRef.current.save()` to trigger a save +from outside the editor's top bar; call `apiRef.current.isDirty()` to gate +"unsaved changes" UI. + +## Lower-level entry point + +If your host already has a `Deck` in memory (e.g. you're storing the JSON +shape in your own database rather than `.pptx` blobs), mount +`SlidewiseEditor` directly: + +```tsx +import { SlidewiseEditor, type Deck } from "@textcortex/slidewise"; +import "@textcortex/slidewise/style.css"; + + setDeck(next)} + onSave={(next) => persist(next)} +/>; +``` + +## Working with decks programmatically + +Slidewise persists slides as a versioned JSON `Deck`. The schema is the +canonical contract — undo/redo, exports, AI features, and persistence all +key off it. + +```ts +import { + parsePptx, + serializeDeck, + migrate, + CURRENT_DECK_VERSION, + type Deck, +} from "@textcortex/slidewise"; + +const deck: Deck = await parsePptx(blob); // import +const pptx: Blob = await serializeDeck(deck); // export +const safe: Deck = migrate(unknownDeckJson); // normalise an external deck +``` + +`migrate()` runs every external deck (PPTX import, JSON import, localStorage +hydration, host props) through the schema migration chain so the rest of the +editor only sees current-shape decks. It throws if the input was written by a +newer Slidewise than the host has installed — pin the version range you can +support. + +## Releasing + +Versioning and publishing run through +[changesets](https://github.com/changesets/changesets). + +```bash +pnpm changeset # describe the impact of your change +pnpm version-packages # bump versions + update CHANGELOG (CI usually does this) +pnpm release # build + publish (CI does this on merge) +``` + +CI (`.github/workflows/release.yml`) opens a "Version Packages" PR whenever +there are pending changesets and publishes to npm when that PR merges. + +## Repo layout + +- `src/SlidewiseEditor.tsx` / `src/SlidewiseFileEditor.tsx` — public entry components +- `src/components/editor/` — top bar, slide rail, canvas, panels +- `src/lib/pptx/` — PPTX import (`pptxToDeck`) and export (`deckToPptx`) +- `src/lib/schema/` — `Deck` schema versioning + migrator +- `src/lib/types.ts` — `Deck` / `Slide` / `SlideElement` shapes (the contract) diff --git a/package.json b/package.json index 23e3cae..e852624 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,9 @@ { - "name": "slidewise", + "name": "@textcortex/slidewise", "version": "0.2.0", + "description": "Embeddable React PPTX editor.", + "license": "UNLICENSED", + "private": false, "type": "module", "main": "./dist/index.mjs", "module": "./dist/index.mjs", @@ -15,6 +18,18 @@ "./fonts.css": "./src/fonts.css" }, "sideEffects": ["**/*.css"], + "repository": { + "type": "git", + "url": "git+https://github.com/textcortex/SlideWise.git" + }, + "homepage": "https://github.com/textcortex/SlideWise#readme", + "bugs": { + "url": "https://github.com/textcortex/SlideWise/issues" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, "scripts": { "dev": "vite", "build": "tsc -b && vite build", @@ -22,7 +37,10 @@ "preview": "vite preview", "test": "vitest run", "test:watch": "vitest", - "lint": "eslint ." + "lint": "eslint .", + "changeset": "changeset", + "version-packages": "changeset version", + "release": "pnpm run build:lib && changeset publish" }, "peerDependencies": { "react": ">=19", @@ -37,11 +55,10 @@ "lucide-react": "^1.11.0", "nanoid": "^5.1.9", "pptxgenjs": "^4.0.1", - "react": "19.2.4", - "react-dom": "19.2.4", "zustand": "^5.0.12" }, "devDependencies": { + "@changesets/cli": "^2.27.10", "@tailwindcss/vite": "^4", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", @@ -53,6 +70,8 @@ "eslint-plugin-react-refresh": "^0.4.20", "globals": "^16.2.0", "jsdom": "^29.1.1", + "react": "19.2.4", + "react-dom": "19.2.4", "tailwindcss": "^4", "typescript": "^5", "typescript-eslint": "^8.42.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4386e49..dcea101 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,16 +32,13 @@ importers: pptxgenjs: specifier: ^4.0.1 version: 4.0.1 - react: - specifier: 19.2.4 - version: 19.2.4 - react-dom: - specifier: 19.2.4 - version: 19.2.4(react@19.2.4) zustand: specifier: ^5.0.12 version: 5.0.12(@types/react@19.2.14)(react@19.2.4) devDependencies: + '@changesets/cli': + specifier: ^2.27.10 + version: 2.31.0(@types/node@22.19.17) '@tailwindcss/vite': specifier: ^4 version: 4.2.4(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)) @@ -75,6 +72,12 @@ importers: jsdom: specifier: ^29.1.1 version: 29.1.1 + react: + specifier: 19.2.4 + version: 19.2.4 + react-dom: + specifier: 19.2.4 + version: 19.2.4(react@19.2.4) tailwindcss: specifier: ^4 version: 4.2.4 @@ -202,6 +205,61 @@ packages: resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true + '@changesets/apply-release-plan@7.1.1': + resolution: {integrity: sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==} + + '@changesets/assemble-release-plan@6.0.10': + resolution: {integrity: sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/cli@2.31.0': + resolution: {integrity: sha512-AhI4enNTgHu2IZr6K4WZyf0EPch4XVMn1yOMFmCD9gsfBGqMYaHXls5HyDv6/CL5axVQABz68eG30eCtbr2wFg==} + hasBin: true + + '@changesets/config@3.1.4': + resolution: {integrity: sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.4': + resolution: {integrity: sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==} + + '@changesets/get-release-plan@4.0.16': + resolution: {integrity: sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.3': + resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.7': + resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} engines: {node: '>=20.19.0'} @@ -467,6 +525,15 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -483,9 +550,27 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@nodable/entities@2.1.0': resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@rolldown/pluginutils@1.0.0-rc.3': resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} @@ -757,6 +842,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@22.19.17': resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} @@ -875,6 +963,10 @@ packages: ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -887,6 +979,9 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -897,6 +992,10 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -913,6 +1012,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -923,6 +1026,10 @@ packages: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -943,6 +1050,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -996,10 +1106,18 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -1013,6 +1131,10 @@ packages: resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} engines: {node: '>=10.13.0'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@8.0.0: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} @@ -1074,6 +1196,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -1097,9 +1224,16 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -1113,6 +1247,9 @@ packages: resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} hasBin: true + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1126,6 +1263,14 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1151,6 +1296,14 @@ packages: react-dom: optional: true + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1160,6 +1313,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -1172,6 +1329,10 @@ packages: resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -1186,6 +1347,14 @@ packages: https@1.0.0: resolution: {integrity: sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==} + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1225,9 +1394,21 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -1241,6 +1422,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -1273,6 +1458,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} @@ -1356,6 +1544,10 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1363,6 +1555,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lru-cache@11.3.5: resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} @@ -1385,6 +1580,14 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -1402,6 +1605,10 @@ packages: motion-utils@12.36.0: resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1428,14 +1635,40 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -1458,16 +1691,28 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + postcss@8.5.12: resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==} engines: {node: ^10 || ^12 || >=14} @@ -1479,6 +1724,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -1490,6 +1740,12 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue@6.0.2: resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} @@ -1509,6 +1765,10 @@ packages: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -1524,14 +1784,28 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.60.2: resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -1562,10 +1836,24 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1575,6 +1863,14 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -1600,6 +1896,10 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1622,6 +1922,10 @@ packages: resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} hasBin: true + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + tough-cookie@6.0.1: resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} engines: {node: '>=16'} @@ -1662,6 +1966,10 @@ packages: resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -1959,6 +2267,149 @@ snapshots: dependencies: css-tree: 3.2.1 + '@changesets/apply-release-plan@7.1.1': + dependencies: + '@changesets/config': 3.1.4 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.4 + + '@changesets/assemble-release-plan@6.0.10': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.4 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/cli@2.31.0(@types/node@22.19.17)': + dependencies: + '@changesets/apply-release-plan': 7.1.1 + '@changesets/assemble-release-plan': 6.0.10 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.4 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/get-release-plan': 4.0.16 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@22.19.17) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.4 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.4': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.4 + '@changesets/logger': 0.1.1 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.4': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.4 + + '@changesets/get-release-plan@4.0.16': + dependencies: + '@changesets/assemble-release-plan': 6.0.10 + '@changesets/config': 3.1.4 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.7 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.3': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.7': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.3 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + '@csstools/color-helpers@6.0.2': {} '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': @@ -2129,6 +2580,13 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@inquirer/external-editor@1.0.3(@types/node@22.19.17)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 22.19.17 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2148,8 +2606,36 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.29.2 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.29.2 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + '@nodable/entities@2.1.0': {} + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.60.2': @@ -2361,6 +2847,8 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/node@12.20.55': {} + '@types/node@22.19.17': dependencies: undici-types: 6.21.0 @@ -2530,6 +3018,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + ansi-regex@5.0.1: {} ansi-styles@4.3.0: @@ -2538,6 +3028,10 @@ snapshots: ansi-styles@5.2.0: {} + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} aria-query@5.3.0: @@ -2546,6 +3040,8 @@ snapshots: aria-query@5.3.2: {} + array-union@2.1.0: {} + assertion-error@2.0.1: {} balanced-match@1.0.2: {} @@ -2554,6 +3050,10 @@ snapshots: baseline-browser-mapping@2.10.23: {} + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -2567,6 +3067,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.23 @@ -2586,6 +3090,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chardet@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2630,8 +3136,14 @@ snapshots: dequal@2.0.3: {} + detect-indent@6.1.0: {} + detect-libc@2.1.2: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -2643,6 +3155,11 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + entities@8.0.0: {} es-module-lexer@2.1.0: {} @@ -2746,6 +3263,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -2764,8 +3283,18 @@ snapshots: expect-type@1.3.0: {} + extendable-error@0.1.7: {} + fast-deep-equal@3.1.3: {} + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -2781,6 +3310,10 @@ snapshots: path-expression-matcher: 1.5.0 strnum: 2.2.3 + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -2789,6 +3322,15 @@ snapshots: dependencies: flat-cache: 4.0.1 + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -2810,11 +3352,27 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + fsevents@2.3.3: optional: true gensync@1.0.0-beta.2: {} + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -2823,6 +3381,15 @@ snapshots: globals@16.4.0: {} + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + graceful-fs@4.2.11: {} has-flag@4.0.0: {} @@ -2835,6 +3402,12 @@ snapshots: https@1.0.0: {} + human-id@4.1.3: {} + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.2: {} ignore@7.0.5: {} @@ -2862,8 +3435,16 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: {} + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-windows@1.0.2: {} + isarray@1.0.0: {} isexe@2.0.0: {} @@ -2872,6 +3453,11 @@ snapshots: js-tokens@4.0.0: {} + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -2912,6 +3498,10 @@ snapshots: json5@2.2.3: {} + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + jszip@3.10.1: dependencies: lie: 3.3.0 @@ -2981,12 +3571,18 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + lodash.startcase@4.4.0: {} + lru-cache@11.3.5: {} lru-cache@5.1.1: @@ -3005,6 +3601,13 @@ snapshots: mdn-data@2.27.1: {} + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + min-indent@1.0.1: {} minimatch@10.2.5: @@ -3021,6 +3624,8 @@ snapshots: motion-utils@12.36.0: {} + mri@1.2.0: {} + ms@2.1.3: {} nanoid@3.3.11: {} @@ -3042,14 +3647,36 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + outdent@0.5.0: {} + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-map@2.1.0: {} + + p-try@2.2.0: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + pako@1.0.11: {} parent-module@1.0.1: @@ -3066,12 +3693,18 @@ snapshots: path-key@3.1.1: {} + path-type@4.0.0: {} + pathe@2.0.3: {} picocolors@1.1.1: {} + picomatch@2.3.2: {} + picomatch@4.0.4: {} + pify@4.0.1: {} + postcss@8.5.12: dependencies: nanoid: 3.3.11 @@ -3087,6 +3720,8 @@ snapshots: prelude-ls@1.2.1: {} + prettier@2.8.8: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -3097,6 +3732,10 @@ snapshots: punycode@2.3.1: {} + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + queue@6.0.2: dependencies: inherits: 2.0.4 @@ -3112,6 +3751,13 @@ snapshots: react@19.2.4: {} + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -3131,6 +3777,10 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + + reusify@1.1.0: {} + rollup@4.60.2: dependencies: '@types/estree': 1.0.8 @@ -3162,8 +3812,14 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.2 fsevents: 2.3.3 + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + safe-buffer@5.1.2: {} + safer-buffer@2.1.2: {} + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -3184,8 +3840,19 @@ snapshots: siginfo@2.0.0: {} + signal-exit@4.1.0: {} + + slash@3.0.0: {} + source-map-js@1.2.1: {} + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + sprintf-js@1.0.3: {} + stackback@0.0.2: {} std-env@4.1.0: {} @@ -3194,6 +3861,12 @@ snapshots: dependencies: safe-buffer: 5.1.2 + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -3212,6 +3885,8 @@ snapshots: tapable@2.3.3: {} + term-size@2.2.1: {} + tinybench@2.9.0: {} tinyexec@1.1.2: {} @@ -3229,6 +3904,10 @@ snapshots: dependencies: tldts-core: 7.0.30 + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + tough-cookie@6.0.1: dependencies: tldts: 7.0.30 @@ -3264,6 +3943,8 @@ snapshots: undici@7.25.0: {} + universalify@0.1.2: {} + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 diff --git a/src/SlidewiseEditor.css b/src/SlidewiseEditor.css index 0c20884..9f50d2d 100644 --- a/src/SlidewiseEditor.css +++ b/src/SlidewiseEditor.css @@ -1,3 +1,10 @@ +/* + * Slidewise editor stylesheet. Shipped with the library and loaded inside + * host applications, so every rule must be nested under `.slidewise-editor` + * to avoid colliding with host styles. At-rules (@font-face, @media, …) are + * fine at the top level. The `library CSS scope` test in + * src/lib/__tests__/css-scope.test.ts enforces this. + */ @import "./fonts.css"; .slidewise-editor { diff --git a/src/index.ts b/src/index.ts index 3fdfe87..5176ec5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,8 @@ export { export { parsePptx, serializeDeck } from "./lib/pptx"; export type { ParseDiagnostics, ParseResult } from "./lib/pptx/types"; +export { migrate, CURRENT_DECK_VERSION } from "./lib/schema/migrate"; + export type { Deck, Slide, diff --git a/src/lib/__tests__/css-scope.test.ts b/src/lib/__tests__/css-scope.test.ts new file mode 100644 index 0000000..098cb11 --- /dev/null +++ b/src/lib/__tests__/css-scope.test.ts @@ -0,0 +1,133 @@ +import { describe, it, expect } from "vitest"; +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +const here = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(here, "..", "..", ".."); + +/** + * Slidewise ships as a library. Hosts mount it inside their own DOM, with + * their own global stylesheets (Tailwind preflight, normalize.css, app + * resets). Every rule we ship must therefore live under `.slidewise-editor` + * — anything at the document root would override host styles when our CSS + * loads, or get overridden when host CSS loads, depending on order. + * + * This test scans the source CSS for top-level selectors and rejects + * anything that escapes the scope. Allowed at top level: at-rules + * (`@font-face`, `@import`, `@media`, `@supports`, …) and selectors that + * begin with `.slidewise-editor`. + */ +describe("library CSS scope", () => { + it("every rule in SlidewiseEditor.css is scoped under .slidewise-editor", () => { + const css = readFileSync( + resolve(repoRoot, "src", "SlidewiseEditor.css"), + "utf8" + ); + const violations = findUnscopedSelectors(css); + if (violations.length) { + throw new Error( + `Found ${violations.length} unscoped top-level selector(s) in SlidewiseEditor.css. ` + + `Every rule must be nested under .slidewise-editor so the lib does not collide ` + + `with host styles. Offenders:\n ${violations.join("\n ")}` + ); + } + expect(violations).toEqual([]); + }); +}); + +/** + * Walk the CSS at brace depth 0, find each rule's selector list, and report + * any selector that does not start with `.slidewise-editor`. Strips comments + * and string contents first so braces inside them don't confuse the scan. + */ +function findUnscopedSelectors(rawCss: string): string[] { + const css = stripCommentsAndStrings(rawCss); + const violations: string[] = []; + let depth = 0; + let buf = ""; + + for (let i = 0; i < css.length; i++) { + const ch = css[i]; + if (ch === "{") { + if (depth === 0) { + const selector = buf.trim(); + if (selector && !isAllowedTopLevel(selector)) { + for (const sel of splitSelectorList(selector)) { + const s = sel.trim(); + if (!s) continue; + if (!s.startsWith(".slidewise-editor")) { + violations.push(s); + } + } + } + buf = ""; + } + depth++; + continue; + } + if (ch === "}") { + depth = Math.max(0, depth - 1); + if (depth === 0) buf = ""; + continue; + } + if (depth === 0) buf += ch; + } + + return violations; +} + +function isAllowedTopLevel(selector: string): boolean { + // At-rules (@font-face, @media, @supports, @keyframes, @import, …) are + // global by design and don't override host styles unless they nest + // unscoped rules — which the recursion catches at depth > 0 if it ever + // matters. @font-face etc. only register names; they don't paint. + return selector.startsWith("@"); +} + +function splitSelectorList(selector: string): string[] { + // CSS selectors are separated by commas at the top level (commas inside + // parens — :is(), :not(), :where() — are not separators). Track paren + // depth as we split. + const out: string[] = []; + let depth = 0; + let cur = ""; + for (const ch of selector) { + if (ch === "(") depth++; + else if (ch === ")") depth = Math.max(0, depth - 1); + if (ch === "," && depth === 0) { + out.push(cur); + cur = ""; + } else { + cur += ch; + } + } + if (cur.trim()) out.push(cur); + return out; +} + +function stripCommentsAndStrings(css: string): string { + let out = ""; + let i = 0; + while (i < css.length) { + if (css[i] === "/" && css[i + 1] === "*") { + const end = css.indexOf("*/", i + 2); + i = end < 0 ? css.length : end + 2; + continue; + } + if (css[i] === '"' || css[i] === "'") { + const quote = css[i]; + let j = i + 1; + while (j < css.length && css[j] !== quote) { + if (css[j] === "\\") j += 2; + else j++; + } + out += quote + " ".repeat(Math.max(0, j - i - 1)) + quote; + i = j + 1; + continue; + } + out += css[i]; + i++; + } + return out; +} diff --git a/src/lib/pptx/__tests__/roundtrip.test.ts b/src/lib/pptx/__tests__/roundtrip.test.ts index 2f9b65d..b9de66a 100644 --- a/src/lib/pptx/__tests__/roundtrip.test.ts +++ b/src/lib/pptx/__tests__/roundtrip.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect } from "vitest"; import { parsePptx, serializeDeck } from "../index"; +import { CURRENT_DECK_VERSION } from "@/lib/schema/migrate"; import type { Deck } from "@/lib/types"; const baseElement = { @@ -9,6 +10,7 @@ const baseElement = { function makeDeck(slideElements: Deck["slides"][number]["elements"]): Deck { return { + version: CURRENT_DECK_VERSION, title: "Round-trip fixture", slides: [ { @@ -110,6 +112,7 @@ describe("pptx round-trip", () => { it("preserves slide background colour", async () => { const deck: Deck = { + version: CURRENT_DECK_VERSION, title: "Bg", slides: [ { id: "s", background: "#FAEEDC", elements: [] }, @@ -124,6 +127,7 @@ describe("pptx round-trip", () => { it("preserves multiple slides with mixed elements", async () => { const deck: Deck = { + version: CURRENT_DECK_VERSION, title: "Multi", slides: [ { diff --git a/src/lib/pptx/pptxToDeck.ts b/src/lib/pptx/pptxToDeck.ts index ab4205e..51858fd 100644 --- a/src/lib/pptx/pptxToDeck.ts +++ b/src/lib/pptx/pptxToDeck.ts @@ -15,6 +15,7 @@ import type { UnknownElement, } from "@/lib/types"; import { SLIDE_W, SLIDE_H } from "@/lib/types"; +import { CURRENT_DECK_VERSION } from "@/lib/schema/migrate"; import { emuToPx, pointsToPx } from "./units"; import type { ParseDiagnostics } from "./types"; @@ -179,7 +180,7 @@ export async function parsePptx(blob: Blob | ArrayBuffer): Promise { diagnostics.warnings.push("PPTX contained no slides; created an empty one."); } - const deck: Deck = { title, slides }; + const deck: Deck = { version: CURRENT_DECK_VERSION, title, slides }; if (diagnostics.warnings.length) { console.info("[slidewise/pptx] parse diagnostics:", diagnostics); } diff --git a/src/lib/schema/__tests__/migrate.test.ts b/src/lib/schema/__tests__/migrate.test.ts new file mode 100644 index 0000000..c0e7c88 --- /dev/null +++ b/src/lib/schema/__tests__/migrate.test.ts @@ -0,0 +1,70 @@ +import { describe, it, expect } from "vitest"; +import { migrate, CURRENT_DECK_VERSION } from "../migrate"; + +describe("schema/migrate", () => { + it("stamps the current version on an unversioned (v0) deck", () => { + const v0 = { + title: "Pre-versioning deck", + slides: [{ id: "s1", background: "#FFFFFF", elements: [] }], + }; + const out = migrate(v0); + expect(out.version).toBe(CURRENT_DECK_VERSION); + expect(out.title).toBe("Pre-versioning deck"); + expect(out.slides).toHaveLength(1); + }); + + it("passes a current-version deck through unchanged in shape", () => { + const current = { + version: CURRENT_DECK_VERSION, + title: "Current", + slides: [{ id: "s1", background: "#FFFFFF", elements: [] }], + }; + const out = migrate(current); + expect(out.version).toBe(CURRENT_DECK_VERSION); + expect(out.title).toBe("Current"); + expect(out.slides[0].id).toBe("s1"); + }); + + it("throws on a deck written by a newer Slidewise", () => { + const future = { + version: CURRENT_DECK_VERSION + 5, + title: "From the future", + slides: [], + }; + expect(() => migrate(future)).toThrow(/newer than this build/); + }); + + it("rejects non-object input", () => { + expect(() => migrate(null)).toThrow(); + expect(() => migrate("not a deck")).toThrow(); + expect(() => migrate(42)).toThrow(); + }); + + it("rejects a deck whose slides is not an array", () => { + expect(() => migrate({ title: "x", slides: "nope" })).toThrow( + /slides is not an array/ + ); + }); + + it("rejects a deck with an invalid version field", () => { + expect(() => + migrate({ version: -1, title: "x", slides: [] }) + ).toThrow(/non-negative integer/); + expect(() => + migrate({ version: 1.5, title: "x", slides: [] }) + ).toThrow(/non-negative integer/); + expect(() => + migrate({ version: "1", title: "x", slides: [] }) + ).toThrow(/non-negative integer/); + }); + + it("does not mutate the input deck", () => { + const v0 = { + title: "Original", + slides: [{ id: "s1", background: "#FFFFFF", elements: [] }], + }; + const before = JSON.stringify(v0); + migrate(v0); + expect(JSON.stringify(v0)).toBe(before); + }); +}); diff --git a/src/lib/schema/migrate.ts b/src/lib/schema/migrate.ts new file mode 100644 index 0000000..8d95103 --- /dev/null +++ b/src/lib/schema/migrate.ts @@ -0,0 +1,102 @@ +import type { Deck } from "@/lib/types"; + +/** + * Slidewise deck schema version. Bump this whenever the persisted shape of a + * Deck changes in a way old hosts cannot read transparently — adding a new + * required field, renaming a key, restructuring an element type, etc. + * + * Bumping always pairs with a migrator at `MIGRATIONS[oldVersion]` that takes + * a deck shaped at the previous version and returns one shaped at this one. + * Migrations are run forward in order, so a v0 deck becomes v1 then v2 etc. + * + * Never delete an old migrator — published decks in the wild may still be at + * any historical version, and they all need a path forward. + */ +export const CURRENT_DECK_VERSION = 1; + +/** + * One forward migration. Receives a deck shaped at version `from` and returns + * a deck shaped at version `from + 1`. Inputs are typed as `any` because the + * old shape is not the current `Deck` type — that is the whole point of the + * migration. + */ +type Migrator = (deck: any) => any; + +/** + * Map of migrations keyed by the version they migrate _from_. To migrate a + * v3 deck to current, we run MIGRATIONS[3] then MIGRATIONS[4] etc. until we + * reach CURRENT_DECK_VERSION. + */ +const MIGRATIONS: Record = { + // v0 → v1: pre-versioning decks (no `version` field). Same structural + // shape as v1, so the migrator is identity — the version stamp happens + // at the end of `migrate()`. + 0: (deck) => deck, + // Future entries look like: + // 1: (deck) => ({ ...deck, slides: deck.slides.map(addNewField) }), +}; + +/** + * Normalise an external deck (from PPTX import, JSON import, localStorage, + * a host prop, etc.) to the current schema. Stamps the current version on + * its way out so downstream code can rely on `deck.version`. + * + * Throws if the input is missing the basic shape, or if its `version` is + * higher than `CURRENT_DECK_VERSION` — that means the deck was written by + * a newer Slidewise and the host should upgrade rather than silently render + * a degraded version. + */ +export function migrate(input: unknown): Deck { + if (!isObject(input)) { + throw new Error("[slidewise] migrate: input is not an object"); + } + if (!Array.isArray((input as { slides?: unknown }).slides)) { + throw new Error("[slidewise] migrate: deck.slides is not an array"); + } + + // Decks written before versioning existed have no `version` field; treat + // them as v0. Anything else must be a finite non-negative integer. + const rawVersion = (input as { version?: unknown }).version; + let version: number; + if (rawVersion === undefined) { + version = 0; + } else if ( + typeof rawVersion === "number" && + Number.isInteger(rawVersion) && + rawVersion >= 0 + ) { + version = rawVersion; + } else { + throw new Error( + `[slidewise] migrate: deck.version is not a non-negative integer (got ${String( + rawVersion + )})` + ); + } + + if (version > CURRENT_DECK_VERSION) { + throw new Error( + `[slidewise] migrate: deck version ${version} is newer than this build supports (max ${CURRENT_DECK_VERSION}). Upgrade Slidewise.` + ); + } + + let working: any = input; + while (version < CURRENT_DECK_VERSION) { + const step = MIGRATIONS[version]; + if (!step) { + throw new Error( + `[slidewise] migrate: no migrator registered for version ${version} → ${ + version + 1 + }` + ); + } + working = step(working); + version += 1; + } + + return { ...working, version: CURRENT_DECK_VERSION } as Deck; +} + +function isObject(v: unknown): v is Record { + return typeof v === "object" && v !== null && !Array.isArray(v); +} diff --git a/src/lib/seed.ts b/src/lib/seed.ts index a2acdf2..e2f0297 100644 --- a/src/lib/seed.ts +++ b/src/lib/seed.ts @@ -1,5 +1,6 @@ import { nanoid } from "nanoid"; -import type { Slide, SlideElement } from "./types"; +import type { Deck, Slide, SlideElement } from "./types"; +import { CURRENT_DECK_VERSION } from "./schema/migrate"; const id = () => nanoid(8); @@ -769,7 +770,8 @@ const slide6: Slide = { ], }; -export const seedDeck = { +export const seedDeck: Deck = { + version: CURRENT_DECK_VERSION, title: "EldoraUI - Open-Source React Component Library", slides: [slide1, slide2, slide3, slide4, slide5, slide6], }; diff --git a/src/lib/store.ts b/src/lib/store.ts index 2161aa9..f7c0361 100644 --- a/src/lib/store.ts +++ b/src/lib/store.ts @@ -8,6 +8,7 @@ import type { ShapeKind, } from "./types"; import { SLIDE_W, SLIDE_H } from "./types"; +import { migrate } from "./schema/migrate"; type Tool = | "select" @@ -89,9 +90,13 @@ function snap(state: EditorState): HistorySnapshot { } export function createEditorStore(initialDeck: Deck): EditorStore { - const firstSlideId = initialDeck.slides[0]?.id ?? ""; + // Run external decks through the migrator so the store always holds a + // current-shape Deck — even when the host hands us something written by + // an older Slidewise. + const deck = migrate(initialDeck); + const firstSlideId = deck.slides[0]?.id ?? ""; return createStore((set, get) => ({ - deck: initialDeck, + deck, currentSlideId: firstSlideId, selectedIds: [], tool: "select", @@ -345,9 +350,10 @@ export function createEditorStore(initialDeck: Deck): EditorStore { }, setDeck: (deck) => { + const migrated = migrate(deck); set({ - deck, - currentSlideId: deck.slides[0]?.id ?? "", + deck: migrated, + currentSlideId: migrated.slides[0]?.id ?? "", selectedIds: [], history: [], future: [], diff --git a/src/lib/types.ts b/src/lib/types.ts index 890a92d..417cbda 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -169,6 +169,13 @@ export interface Slide { } export interface Deck { + /** + * Schema version this deck conforms to. Stamped by `migrate()` and by + * internal Deck constructors (seed, PPTX import). Hosts should not set + * this manually — pass an external deck through `migrate()` and read the + * version off the result. + */ + version: number; title: string; slides: Slide[]; }