diff --git a/.github /release.yml b/.github/release.yml similarity index 100% rename from .github /release.yml rename to .github/release.yml diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml new file mode 100644 index 0000000..906afaa --- /dev/null +++ b/.github/workflows/build-lint-test.yml @@ -0,0 +1,31 @@ +name: Build, lint, and test + +on: [push] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build typescript + run: npm run tsc + + - name: Run ESLint + run: npm run lint + + # TODO Uncomment when tests are added + # - name: Run tests + # run: npm test + + - name: Build package + run: npm run build diff --git a/.github /workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml similarity index 100% rename from .github /workflows/enforce-labels.yml rename to .github/workflows/enforce-labels.yml diff --git a/examples/studio-i18n/package-lock.json b/examples/studio-i18n/package-lock.json index a4c99e8..47d78da 100644 --- a/examples/studio-i18n/package-lock.json +++ b/examples/studio-i18n/package-lock.json @@ -27,15 +27,15 @@ } }, ".yalc/@q42/sanity-plugin-page-tree": { - "version": "1.1.1", + "version": "1.2.2", "license": "MIT", "dependencies": { - "@sanity/icons": "^2.11.7", + "@sanity/icons": "^2.7.0", "@sanity/incompatible-plugin": "^1.0.4", - "@sanity/ui": "^2.0.16", + "@sanity/ui": "^2.0.1", "@sanity/uuid": "^3.0.2", "lodash": "^4.17.21", - "next-sanity": "8.5.5", + "next-sanity": "^7.1.0", "sanity-plugin-utils": "^1.6.4" }, "engines": { @@ -67,6 +67,43 @@ "node": ">=18.0.0" } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/preview-kit": { + "version": "5.0.20", + "resolved": "https://registry.npmjs.org/@sanity/preview-kit/-/preview-kit-5.0.20.tgz", + "integrity": "sha512-UYNDCyLPMZ5QfPi3oBryPV6rJXvgocZ8ilH8rJsuR3hgRrVrSdV2bnYSrMRVdIQtd32PeFPnJqxtYNu6aXc4HA==", + "dependencies": { + "@sanity/preview-kit-compat": "1.4.4", + "@vercel/stega": "0.1.0", + "lru-cache": "10.2.0", + "mendoza": "3.0.4", + "react-fast-compare": "3.2.2", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@sanity/client": "^6.12.4", + "react": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/preview-kit-compat": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@sanity/preview-kit-compat/-/preview-kit-compat-1.4.4.tgz", + "integrity": "sha512-CYO/qFIc2fqV8cpAIYay43SfPIs/SFzT8ke+XgXYlzwXmShdDnKXNttfLDUWvxk6+nJiPRgzRN9kokC8ineP2g==", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@sanity/client": "^6.12.3", + "react": "^18.2.0" + } + }, ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/ui": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/@sanity/ui/-/ui-2.0.16.tgz", @@ -89,6 +126,14 @@ "styled-components": "^5.2 || ^6" } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/webhook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sanity/webhook/-/webhook-4.0.0.tgz", + "integrity": "sha512-IRjtj17tHSmxHWZvgRnLZbWj8J8G4jqOWOYC25eV4EcfVn1yZCs0x+km6+PSiJgOphSX6Nm1+X6UJOT+GnWIFw==", + "engines": { + "node": ">=18.0.0" + } + }, ".yalc/@q42/sanity-plugin-page-tree/node_modules/framer-motion": { "version": "11.0.8", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.8.tgz", @@ -112,6 +157,47 @@ } } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/mendoza": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/mendoza/-/mendoza-3.0.4.tgz", + "integrity": "sha512-kGlLhn1HF57oUK9DzJpqiqxHS9KJ0JcFRtNKBM8l970nepx3/GKs1uAIlBfq5mjmndk7IGa4vQ2ofcqMKMPTiA==", + "engines": { + "node": ">=14.18" + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/next-sanity": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/next-sanity/-/next-sanity-7.1.4.tgz", + "integrity": "sha512-bq/VkejvPgV95mi5fxR01rALG1QURe0nO2g3HyUuiZRyTd0teFgYvCVf1b5PBndKhD15Cd3UK/WwcLKRxxEr3A==", + "dependencies": { + "@sanity/client": "^6.12.4", + "@sanity/preview-kit": "5.0.20", + "@sanity/visual-editing": "1.2.2", + "@sanity/webhook": "4.0.0", + "groq": "^3.19" + }, + "engines": { + "node": ">=18.17" + }, + "peerDependencies": { + "@sanity/client": "^6.12.4", + "@sanity/icons": "^2.8", + "@sanity/types": "^3.25", + "@sanity/ui": "^1.8 || ^2.0.0-beta || ^2.0", + "next": "^14.1", + "react": "^18.2", + "sanity": "^3.25", + "styled-components": "^5.2 || ^6.0" + } + }, ".yalc/sanity-plugin-page-tree": { "version": "1.0.0", "extraneous": true, @@ -4073,51 +4159,6 @@ } } }, - "node_modules/@sanity/preview-kit": { - "version": "5.0.41", - "resolved": "https://registry.npmjs.org/@sanity/preview-kit/-/preview-kit-5.0.41.tgz", - "integrity": "sha512-Q5xeSK7vmlNkyqzuTFyiaDeeHGRxhS2WLtNPV6iElPfXrP6albnxyh0DL0ciBsa5WQJYcRBvBHYr9SQiWz4mmw==", - "dependencies": { - "@sanity/preview-kit-compat": "1.4.15", - "@vercel/stega": "0.1.0", - "lru-cache": "10.2.0", - "mendoza": "3.0.6", - "react-fast-compare": "3.2.2", - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "react": "^18.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@sanity/preview-kit-compat": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@sanity/preview-kit-compat/-/preview-kit-compat-1.4.15.tgz", - "integrity": "sha512-wau2+T0Mqt9wK8QmY87aHjIvP5+HF7qme/hnbCUvC+ofLztdulr7KLSORwO28XlcBVBkmFFLgCwyYjnwBgUA8w==", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "react": "^18.2.0" - } - }, - "node_modules/@sanity/preview-kit/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/@sanity/preview-url-secret": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/@sanity/preview-url-secret/-/preview-url-secret-1.6.7.tgz", @@ -4312,12 +4353,31 @@ } } }, - "node_modules/@sanity/webhook": { - "version": "4.0.2-bc", - "resolved": "https://registry.npmjs.org/@sanity/webhook/-/webhook-4.0.2-bc.tgz", - "integrity": "sha512-I/Qq+ppPMkdZ2lQ3iHJ1HylBkEy+imn5qCOWEJefdVIyWdYPpNmTAH09exU6K6M1HRMM7Au4oOdijx3kruZEWA==", + "node_modules/@sanity/visual-editing": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@sanity/visual-editing/-/visual-editing-1.2.2.tgz", + "integrity": "sha512-iR1stYfPPhBJLjwKY3MBgr0DcRADgnRaTJvZ3nUJ2puGVniPoSxJ9Zj4PkspferU8997RKKtupN9m9spFYskXg==", + "dependencies": { + "@vercel/stega": "0.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-is": "18.2.0", + "scroll-into-view-if-needed": "^3.1.0" + }, "engines": { - "node": ">=18.17" + "node": ">=18" + }, + "peerDependencies": { + "@remix-run/react": ">= 2", + "next": ">= 13" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "next": { + "optional": true + } } }, "node_modules/@swc/helpers": { @@ -9436,74 +9496,6 @@ } } }, - "node_modules/next-sanity": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/next-sanity/-/next-sanity-8.5.5.tgz", - "integrity": "sha512-1sDK1h0mS+E/WR6JUaEKnHX3l1hV3MZF1WThcFm51ENcim6QOCjMGf5AcDf+T+JSTB6Zhoib+5GoXH3drFJzNA==", - "dependencies": { - "@portabletext/react": "^3.0.17", - "@sanity/client": "^6.15.11", - "@sanity/preview-kit": "5.0.41", - "@sanity/visual-editing": "1.8.7", - "@sanity/webhook": "4.0.2-bc", - "groq": "^3.19", - "history": "^5.3.0" - }, - "engines": { - "node": ">=18.17" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "@sanity/icons": "^2.8", - "@sanity/types": "^3.25", - "@sanity/ui": "^1.8 || ^2.0.0-beta || ^2.0", - "next": "^14.1", - "react": "^18.2", - "sanity": "^3.25", - "styled-components": "^5.2 || ^6.0" - } - }, - "node_modules/next-sanity/node_modules/@sanity/visual-editing": { - "version": "1.8.7", - "resolved": "https://registry.npmjs.org/@sanity/visual-editing/-/visual-editing-1.8.7.tgz", - "integrity": "sha512-jUWa11VYvg7Ws/mCRXwBz0X/CmqPFG2dAfvSahqQ3x5LzIcXFaJ3BU0b+9xcEXr0wIEO+/l+eMsEQVAtBhezPw==", - "dependencies": { - "@sanity/preview-url-secret": "^1.6.7", - "@vercel/stega": "0.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-is": "18.2.0", - "scroll-into-view-if-needed": "^3.1.0", - "valibot": "0.30.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@remix-run/react": ">= 2", - "@sanity/client": "^6.15.11", - "@sveltejs/kit": ">= 2", - "next": ">= 13", - "svelte": ">= 4" - }, - "peerDependenciesMeta": { - "@remix-run/react": { - "optional": true - }, - "@sanity/client": { - "optional": true - }, - "@sveltejs/kit": { - "optional": true - }, - "next": { - "optional": true - }, - "svelte": { - "optional": true - } - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -12480,11 +12472,6 @@ "uuidv7": "cli.js" } }, - "node_modules/valibot": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.30.0.tgz", - "integrity": "sha512-5POBdbSkM+3nvJ6ZlyQHsggisfRtyT4tVTo1EIIShs6qCdXJnyWU5TJ68vr8iTg5zpOLjXLRiBqNx+9zwZz/rA==" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/examples/studio/package-lock.json b/examples/studio/package-lock.json index 842e4af..99dd8c9 100644 --- a/examples/studio/package-lock.json +++ b/examples/studio/package-lock.json @@ -26,15 +26,15 @@ } }, ".yalc/@q42/sanity-plugin-page-tree": { - "version": "1.1.1", + "version": "1.2.2", "license": "MIT", "dependencies": { - "@sanity/icons": "^2.11.7", + "@sanity/icons": "^2.7.0", "@sanity/incompatible-plugin": "^1.0.4", - "@sanity/ui": "^2.0.16", + "@sanity/ui": "^2.0.1", "@sanity/uuid": "^3.0.2", "lodash": "^4.17.21", - "next-sanity": "8.5.5", + "next-sanity": "^7.1.0", "sanity-plugin-utils": "^1.6.4" }, "engines": { @@ -66,6 +66,43 @@ "node": ">=18.0.0" } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/preview-kit": { + "version": "5.0.20", + "resolved": "https://registry.npmjs.org/@sanity/preview-kit/-/preview-kit-5.0.20.tgz", + "integrity": "sha512-UYNDCyLPMZ5QfPi3oBryPV6rJXvgocZ8ilH8rJsuR3hgRrVrSdV2bnYSrMRVdIQtd32PeFPnJqxtYNu6aXc4HA==", + "dependencies": { + "@sanity/preview-kit-compat": "1.4.4", + "@vercel/stega": "0.1.0", + "lru-cache": "10.2.0", + "mendoza": "3.0.4", + "react-fast-compare": "3.2.2", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@sanity/client": "^6.12.4", + "react": "^18.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/preview-kit-compat": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@sanity/preview-kit-compat/-/preview-kit-compat-1.4.4.tgz", + "integrity": "sha512-CYO/qFIc2fqV8cpAIYay43SfPIs/SFzT8ke+XgXYlzwXmShdDnKXNttfLDUWvxk6+nJiPRgzRN9kokC8ineP2g==", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@sanity/client": "^6.12.3", + "react": "^18.2.0" + } + }, ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/ui": { "version": "2.0.16", "resolved": "https://registry.npmjs.org/@sanity/ui/-/ui-2.0.16.tgz", @@ -88,6 +125,14 @@ "styled-components": "^5.2 || ^6" } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/@sanity/webhook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sanity/webhook/-/webhook-4.0.0.tgz", + "integrity": "sha512-IRjtj17tHSmxHWZvgRnLZbWj8J8G4jqOWOYC25eV4EcfVn1yZCs0x+km6+PSiJgOphSX6Nm1+X6UJOT+GnWIFw==", + "engines": { + "node": ">=18.0.0" + } + }, ".yalc/@q42/sanity-plugin-page-tree/node_modules/framer-motion": { "version": "11.0.8", "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.8.tgz", @@ -111,6 +156,47 @@ } } }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/mendoza": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/mendoza/-/mendoza-3.0.4.tgz", + "integrity": "sha512-kGlLhn1HF57oUK9DzJpqiqxHS9KJ0JcFRtNKBM8l970nepx3/GKs1uAIlBfq5mjmndk7IGa4vQ2ofcqMKMPTiA==", + "engines": { + "node": ">=14.18" + } + }, + ".yalc/@q42/sanity-plugin-page-tree/node_modules/next-sanity": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/next-sanity/-/next-sanity-7.1.4.tgz", + "integrity": "sha512-bq/VkejvPgV95mi5fxR01rALG1QURe0nO2g3HyUuiZRyTd0teFgYvCVf1b5PBndKhD15Cd3UK/WwcLKRxxEr3A==", + "dependencies": { + "@sanity/client": "^6.12.4", + "@sanity/preview-kit": "5.0.20", + "@sanity/visual-editing": "1.2.2", + "@sanity/webhook": "4.0.0", + "groq": "^3.19" + }, + "engines": { + "node": ">=18.17" + }, + "peerDependencies": { + "@sanity/client": "^6.12.4", + "@sanity/icons": "^2.8", + "@sanity/types": "^3.25", + "@sanity/ui": "^1.8 || ^2.0.0-beta || ^2.0", + "next": "^14.1", + "react": "^18.2", + "sanity": "^3.25", + "styled-components": "^5.2 || ^6.0" + } + }, ".yalc/sanity-plugin-page-tree": { "version": "1.0.0", "extraneous": true, @@ -4120,51 +4206,6 @@ } } }, - "node_modules/@sanity/preview-kit": { - "version": "5.0.41", - "resolved": "https://registry.npmjs.org/@sanity/preview-kit/-/preview-kit-5.0.41.tgz", - "integrity": "sha512-Q5xeSK7vmlNkyqzuTFyiaDeeHGRxhS2WLtNPV6iElPfXrP6albnxyh0DL0ciBsa5WQJYcRBvBHYr9SQiWz4mmw==", - "dependencies": { - "@sanity/preview-kit-compat": "1.4.15", - "@vercel/stega": "0.1.0", - "lru-cache": "10.2.0", - "mendoza": "3.0.6", - "react-fast-compare": "3.2.2", - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "react": "^18.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, - "node_modules/@sanity/preview-kit-compat": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@sanity/preview-kit-compat/-/preview-kit-compat-1.4.15.tgz", - "integrity": "sha512-wau2+T0Mqt9wK8QmY87aHjIvP5+HF7qme/hnbCUvC+ofLztdulr7KLSORwO28XlcBVBkmFFLgCwyYjnwBgUA8w==", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "react": "^18.2.0" - } - }, - "node_modules/@sanity/preview-kit/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/@sanity/preview-url-secret": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/@sanity/preview-url-secret/-/preview-url-secret-1.6.7.tgz", @@ -4360,12 +4401,31 @@ } } }, - "node_modules/@sanity/webhook": { - "version": "4.0.2-bc", - "resolved": "https://registry.npmjs.org/@sanity/webhook/-/webhook-4.0.2-bc.tgz", - "integrity": "sha512-I/Qq+ppPMkdZ2lQ3iHJ1HylBkEy+imn5qCOWEJefdVIyWdYPpNmTAH09exU6K6M1HRMM7Au4oOdijx3kruZEWA==", + "node_modules/@sanity/visual-editing": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@sanity/visual-editing/-/visual-editing-1.2.2.tgz", + "integrity": "sha512-iR1stYfPPhBJLjwKY3MBgr0DcRADgnRaTJvZ3nUJ2puGVniPoSxJ9Zj4PkspferU8997RKKtupN9m9spFYskXg==", + "dependencies": { + "@vercel/stega": "0.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-is": "18.2.0", + "scroll-into-view-if-needed": "^3.1.0" + }, "engines": { - "node": ">=18.17" + "node": ">=18" + }, + "peerDependencies": { + "@remix-run/react": ">= 2", + "next": ">= 13" + }, + "peerDependenciesMeta": { + "@remix-run/react": { + "optional": true + }, + "next": { + "optional": true + } } }, "node_modules/@swc/helpers": { @@ -9263,74 +9323,6 @@ } } }, - "node_modules/next-sanity": { - "version": "8.5.5", - "resolved": "https://registry.npmjs.org/next-sanity/-/next-sanity-8.5.5.tgz", - "integrity": "sha512-1sDK1h0mS+E/WR6JUaEKnHX3l1hV3MZF1WThcFm51ENcim6QOCjMGf5AcDf+T+JSTB6Zhoib+5GoXH3drFJzNA==", - "dependencies": { - "@portabletext/react": "^3.0.17", - "@sanity/client": "^6.15.11", - "@sanity/preview-kit": "5.0.41", - "@sanity/visual-editing": "1.8.7", - "@sanity/webhook": "4.0.2-bc", - "groq": "^3.19", - "history": "^5.3.0" - }, - "engines": { - "node": ">=18.17" - }, - "peerDependencies": { - "@sanity/client": "^6.15.11", - "@sanity/icons": "^2.8", - "@sanity/types": "^3.25", - "@sanity/ui": "^1.8 || ^2.0.0-beta || ^2.0", - "next": "^14.1", - "react": "^18.2", - "sanity": "^3.25", - "styled-components": "^5.2 || ^6.0" - } - }, - "node_modules/next-sanity/node_modules/@sanity/visual-editing": { - "version": "1.8.7", - "resolved": "https://registry.npmjs.org/@sanity/visual-editing/-/visual-editing-1.8.7.tgz", - "integrity": "sha512-jUWa11VYvg7Ws/mCRXwBz0X/CmqPFG2dAfvSahqQ3x5LzIcXFaJ3BU0b+9xcEXr0wIEO+/l+eMsEQVAtBhezPw==", - "dependencies": { - "@sanity/preview-url-secret": "^1.6.7", - "@vercel/stega": "0.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-is": "18.2.0", - "scroll-into-view-if-needed": "^3.1.0", - "valibot": "0.30.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@remix-run/react": ">= 2", - "@sanity/client": "^6.15.11", - "@sveltejs/kit": ">= 2", - "next": ">= 13", - "svelte": ">= 4" - }, - "peerDependenciesMeta": { - "@remix-run/react": { - "optional": true - }, - "@sanity/client": { - "optional": true - }, - "@sveltejs/kit": { - "optional": true - }, - "next": { - "optional": true - }, - "svelte": { - "optional": true - } - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -12459,11 +12451,6 @@ "uuidv7": "cli.js" } }, - "node_modules/valibot": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.30.0.tgz", - "integrity": "sha512-5POBdbSkM+3nvJ6ZlyQHsggisfRtyT4tVTo1EIIShs6qCdXJnyWU5TJ68vr8iTg5zpOLjXLRiBqNx+9zwZz/rA==" - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 46ef7b5..5aefa70 100644 --- a/package.json +++ b/package.json @@ -72,9 +72,11 @@ "test:watch": "TZ=UTC vitest", "format": "prettier --write --cache --ignore-unknown .", "link-watch": "plugin-kit link-watch", - "lint": "eslint ./src/**/* --ext=.ts,.tsx --max-warnings 0", + "lint": "eslint ./src/** --ext=.ts,.tsx --max-warnings 0", "prepublishOnly": "run-s build", "watch": "pkg-utils watch --strict", + "tsc": "tsc --noEmit", + "tsc:watch": "tsc --noEmit --watch", "prepare": "npm run build" }, "dependencies": { diff --git a/src/client.ts b/src/client.ts index 7a91d91..2358900 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,8 @@ -import { PageTreeConfig, PageMetadata } from './types'; +import { SanityClient } from 'sanity'; + import { getAllPageMetadata } from './helpers/page-tree'; import { getRawPageMetadataQuery } from './queries'; -import { SanityClient } from 'sanity'; +import { PageMetadata, PageTreeConfig } from './types'; export type { PageMetadata } from './types'; diff --git a/src/components/PageTreeEditor.tsx b/src/components/PageTreeEditor.tsx index 3b2eed6..82d1478 100644 --- a/src/components/PageTreeEditor.tsx +++ b/src/components/PageTreeEditor.tsx @@ -9,12 +9,12 @@ import styled from 'styled-components'; import { findPageTreeItemById, flatMapPageTree } from '../helpers/page-tree'; import { generateDraftId } from '../helpers/uuid'; import { usePageTreeConfig } from '../hooks/usePageTreeConfig'; -import { PageTreeItem } from '../types'; +import { NestedPageTreeItem, PageTreeItem } from '../types'; import { PageTreeViewItem } from './PageTreeViewItem'; export type PageTreeEditorProps = { - pageTree: PageTreeItem[]; - onItemClick?: (page: PageTreeItem) => void; + pageTree: NestedPageTreeItem[]; + onItemClick?: (page: NestedPageTreeItem) => void; disabledItemIds?: string[]; initialOpenItemIds?: string[]; allowedPageTypes?: string[]; @@ -59,8 +59,8 @@ export const PageTreeEditor = ({ const query = pageTreeState.query.toLowerCase(); - const filter = (pages: PageTreeItem[]): PageTreeItem[] => - pages.reduce((filteredPages: PageTreeItem[], page) => { + const filter = (pages: NestedPageTreeItem[]): NestedPageTreeItem[] => + pages.reduce((filteredPages: NestedPageTreeItem[], page) => { let shouldInclude = true; if (page.children) { @@ -71,18 +71,22 @@ export const PageTreeEditor = ({ } } - if ( - shouldInclude && - (page.title?.toLowerCase().includes(query) || page.slug?.current?.toLowerCase().includes(query)) - ) { - filteredPages.push(page); + if (shouldInclude) { + const slugSourceFieldValue = config.titleFieldName ? page[config.titleFieldName] : undefined; + const matchesSlug = page.slug?.current?.toLowerCase().includes(query); + const matchesTitle = + typeof slugSourceFieldValue === 'string' ? slugSourceFieldValue.toLowerCase().includes(query) : false; + + if (matchesSlug || matchesTitle) { + filteredPages.push(page); + } } return filteredPages; }, []); return filter(pageTree); - }, [pageTree, pageTreeState.query]); + }, [pageTree, pageTreeState.query, config.titleFieldName]); /** * Toggle page tree item. If item is opened, close it and all its children. If it is closed, just open it. diff --git a/src/components/PageTreeInput.tsx b/src/components/PageTreeInput.tsx index 1792753..192eb30 100644 --- a/src/components/PageTreeInput.tsx +++ b/src/components/PageTreeInput.tsx @@ -1,15 +1,15 @@ -import { Stack, Flex, Spinner, Card, Dialog, Box, Text } from '@sanity/ui'; +import { Box, Card, Dialog, Flex, Spinner, Stack, Text } from '@sanity/ui'; import { useMemo, useState } from 'react'; -import { ReferenceValue, set, useFormValue, SanityDocument, ObjectInputProps } from 'sanity'; +import { ObjectInputProps, ReferenceValue, SanityDocument, set, useFormValue } from 'sanity'; import styled from 'styled-components'; -import { PageTreeEditor } from './PageTreeEditor'; import { findPageTreeItemById, flatMapPageTree } from '../helpers/page-tree'; import { useOptimisticState } from '../hooks/useOptimisticState'; import { usePageTree } from '../hooks/usePageTree'; import { PageTreeConfigProvider } from '../hooks/usePageTreeConfig'; import { PageTreeConfig, PageTreeItem } from '../types'; import { getSanityDocumentId } from '../utils/sanity'; +import { PageTreeEditor } from './PageTreeEditor'; export const PageTreeInput = ( props: ObjectInputProps & { diff --git a/src/components/PageTreeViewItem.tsx b/src/components/PageTreeViewItem.tsx index 4d0e819..93c8de3 100644 --- a/src/components/PageTreeViewItem.tsx +++ b/src/components/PageTreeViewItem.tsx @@ -5,18 +5,18 @@ import { useMemo, useState } from 'react'; import { usePaneRouter } from 'sanity/structure'; import styled from 'styled-components'; -import { getLanguageFromConfig } from '../helpers/config'; +import { getLanguageFieldName, getRootPageSlug } from '../helpers/config'; import { flatMapPageTree } from '../helpers/page-tree'; import { usePageTreeConfig } from '../hooks/usePageTreeConfig'; -import { PageTreeItem } from '../types'; +import { NestedPageTreeItem } from '../types'; import { PageTreeViewItemActions } from './PageTreeViewItemActions'; import { PageTreeViewItemStatus } from './PageTreeViewItemStatus'; export type PageTreeViewItemProps = { parentPath?: string; - page: PageTreeItem; - onToggle: (page: PageTreeItem) => void; - onClick?: (page: PageTreeItem) => void; + page: NestedPageTreeItem; + onToggle: (page: NestedPageTreeItem) => void; + onClick?: (page: NestedPageTreeItem) => void; openItemIds: string[]; disabledItemIds?: string[]; forceOpen?: boolean; @@ -55,8 +55,8 @@ export const PageTreeViewItem = ({ navigateIntent('edit', { id: page._id, type: page._type }); }; - const path = parentPath ? `${parentPath}/${page.slug?.current}` : getLanguageFromConfig(config) ?? '/'; - const hasChildren = !!page.children; + const path = parentPath ? `${parentPath}/${page.slug?.current}` : getLanguageFieldName(config) ?? '/'; + const hasChildren = page.children.length > 0; const currentPageNumber = routerPanesState[groupIndex + 1]?.[0]?.id; const isSelected = currentPageNumber === page._id; @@ -110,7 +110,7 @@ export const PageTreeViewItem = ({ onClick={onItemClick}> - {parentPath ? page.slug?.current : page.language ?? '/'} + {parentPath ? page.slug?.current : getRootPageSlug(page, config)} {!isDisabled && (isHovered || hasActionOpen) && ( - {page.children?.length && ( + {hasChildren && ( {page.children.map(childPage => ( (); const onAdd = async (type: string) => { - const language = getLanguageFromConfig(config); + const language = getLanguageFieldName(config); const doc = await client.create({ _id: generateDraftId(), _type: type, diff --git a/src/helpers/config.ts b/src/helpers/config.ts index 2296be5..ce87c3f 100644 --- a/src/helpers/config.ts +++ b/src/helpers/config.ts @@ -1,7 +1,14 @@ -import { PageTreeConfig } from '../types'; +import { PageTreeConfig, RawPageMetadata } from '../types'; -export const getLanguageFromConfig = (config: PageTreeConfig) => { - return config.documentInternationalization - ? config.documentInternationalization.languageFieldName ?? 'language' - : undefined; +export const getLanguageFieldName = (config: PageTreeConfig) => + config.documentInternationalization?.languageFieldName ?? 'language'; + +export const getRootPageSlug = (page: RawPageMetadata, config: PageTreeConfig) => { + if (!config.documentInternationalization) return '/'; + + const language = page[getLanguageFieldName(config)]; + if (typeof language != 'string') { + throw new Error(`Language field is not a string: ${language}`); + } + return `${language}`; }; diff --git a/src/helpers/page-tree.ts b/src/helpers/page-tree.ts index 37feff2..591a837 100644 --- a/src/helpers/page-tree.ts +++ b/src/helpers/page-tree.ts @@ -1,6 +1,7 @@ -import { groupBy, isNil, omit, orderBy, sortBy } from 'lodash'; +import { groupBy, omit, orderBy, sortBy } from 'lodash'; import { + NestedPageTreeItem, PageMetadata, PageTreeConfig, PageTreeItem, @@ -8,7 +9,7 @@ import { RawPageMetadataWithPublishedState, } from '../types'; import { getSanityDocumentId } from '../utils/sanity'; -import { getLanguageFromConfig } from './config'; +import { getLanguageFieldName, getRootPageSlug } from './config'; export const DRAFTS_PREFIX = 'drafts.'; @@ -30,7 +31,7 @@ export const getAllPageMetadata = (config: PageTreeConfig, pages: RawPageMetadat /** * Finds a page from an array of page tree items by the given page id. */ -export const findPageTreeItemById = (pages: PageTreeItem[], id: string): PageTreeItem | undefined => { +export const findPageTreeItemById = (pages: NestedPageTreeItem[], id: string): NestedPageTreeItem | undefined => { for (const page of pages) { if (page._id === id) return page; @@ -44,13 +45,16 @@ export const findPageTreeItemById = (pages: PageTreeItem[], id: string): PageTre /** * Maps pages to page tree containing recursive nested children. */ -export const mapRawPageMetadatasToPageTree = (config: PageTreeConfig, pages: RawPageMetadata[]): PageTreeItem[] => { +export const mapRawPageMetadatasToPageTree = ( + config: PageTreeConfig, + pages: RawPageMetadata[], +): NestedPageTreeItem[] => { const pagesWithPublishedState = getPublishedAndDraftRawPageMetadata(config, pages); const orderedPages = orderBy(mapPageTreeItems(config, pagesWithPublishedState), 'path'); const { documentInternationalization } = config; if (documentInternationalization) { - const languageField = documentInternationalization.languageFieldName ?? 'language'; + const languageField = getLanguageFieldName(config); return sortBy(orderedPages, p => { let index = documentInternationalization.supportedLanguages.indexOf((p[languageField] as string)?.toLowerCase()); @@ -66,8 +70,10 @@ export const mapRawPageMetadatasToPageTree = (config: PageTreeConfig, pages: Raw /** * Recursively flattens page tree to flat array of pages. */ -export const flatMapPageTree = (pages: PageTreeItem[]): Omit[] => - pages.flatMap(page => (page.children ? [omit(page, 'children'), ...flatMapPageTree(page.children)] : page)); +export const flatMapPageTree = (pages: NestedPageTreeItem[]): PageTreeItem[] => + pages.flatMap(page => + page.children ? [omit(page, 'children') as PageTreeItem, ...flatMapPageTree(page.children)] : page, + ); /** * Maps pages to page tree containing recursive nested children and pahts. @@ -77,20 +83,19 @@ const mapPageTreeItems = ( pagesWithPublishedState: RawPageMetadataWithPublishedState[], parentId?: string, parentPath: string = '', -): PageTreeItem[] => { +): NestedPageTreeItem[] => { const getChildPages = (parentId: string | undefined) => pagesWithPublishedState.filter(page => page.parent?._ref === parentId); return getChildPages(parentId).map(page => { - const language = getLanguageFromConfig(config); const pagePath = parentPath ? `${parentPath === '/' ? '' : parentPath}/${page.slug?.current}` - : `/${language ? page[language] : ''}`; + : getRootPageSlug(page, config); const children = orderBy(mapPageTreeItems(config, pagesWithPublishedState, page._id, pagePath), 'path'); return { ...page, - ...(children.length ? { children } : {}), + children, path: pagePath, }; }); diff --git a/src/index.ts b/src/index.ts index 3ae4afc..a85d0f1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ -import { StructureBuilder, DocumentList } from 'sanity/structure'; -import { PageTreeDocumentListOptions } from './types'; +import { DocumentList, StructureBuilder } from 'sanity/structure'; + import { createPageTreeView } from './components/PageTreeView'; +import { PageTreeDocumentListOptions } from './types'; -export { definePageType } from './schema/definePageType'; export { PageTreeField } from './components/PageTreeField'; export { PageTreeInput } from './components/PageTreeInput'; - +export { definePageType } from './schema/definePageType'; export type { PageTreeConfig, PageTreeDocumentListOptions } from './types'; /** diff --git a/src/next.ts b/src/next.ts index 375154e..37d1c07 100644 --- a/src/next.ts +++ b/src/next.ts @@ -1,7 +1,8 @@ -import { PageTreeConfig, PageMetadata } from './types'; +import { FilteredResponseQueryOptions, SanityClient } from 'next-sanity'; + import { getAllPageMetadata } from './helpers/page-tree'; import { getRawPageMetadataQuery } from './queries'; -import { FilteredResponseQueryOptions, SanityClient } from 'next-sanity'; +import { PageMetadata, PageTreeConfig } from './types'; export type { PageMetadata } from './types'; diff --git a/src/queries/index.ts b/src/queries/index.ts index 66fece6..7b74a6d 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -1,4 +1,4 @@ -import { getLanguageFromConfig } from '../helpers/config'; +import { getLanguageFieldName } from '../helpers/config'; import { PageTreeConfig } from '../types'; export const getRawPageMetadataQuery = (config: PageTreeConfig) => `*[_type in [${Object.values(config.pageSchemaTypes) @@ -10,7 +10,7 @@ export const getRawPageMetadataQuery = (config: PageTreeConfig) => `*[_type in [ parent, slug, title, - ${getLanguageFromConfig(config) ?? ''} + ${getLanguageFieldName(config) ?? ''} }`; export const getDocumentTypeQuery = (documentId: string) => `*[_id == "${documentId}"]{ diff --git a/src/schema/definePageType.ts b/src/schema/definePageType.ts index 87e6908..a0e2b9d 100644 --- a/src/schema/definePageType.ts +++ b/src/schema/definePageType.ts @@ -1,12 +1,11 @@ -import { compact, get } from 'lodash'; +import { compact } from 'lodash'; import { defineField, defineType, DocumentDefinition, SlugOptions } from 'sanity'; import { PageTreeField } from '../components/PageTreeField'; import { SlugField } from '../components/SlugField'; import { PageTreeConfig } from '../types'; -import { slugValidator } from '../validators/slug-validator'; - import { allowedParentValidator } from '../validators/parent-validator'; +import { slugValidator } from '../validators/slug-validator'; type Options = { isRoot?: boolean; diff --git a/src/types.ts b/src/types.ts index f5c0910..d9897bc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -17,7 +17,7 @@ export type PageMetadata = { export type RawPageMetadata = { // For user customizable language/title fields - [key: string]: any; + [key: string]: unknown; _id: string; _type: string; _updatedAt: string; @@ -31,10 +31,13 @@ export type RawPageMetadataWithPublishedState = RawPageMetadata & { }; export type PageTreeItem = RawPageMetadataWithPublishedState & { - children?: PageTreeItem[]; path: string; }; +export type NestedPageTreeItem = PageTreeItem & { + children: NestedPageTreeItem[]; +}; + /** * @public */ diff --git a/src/validators/parent-validator.ts b/src/validators/parent-validator.ts index e3e1f6e..8ec849e 100644 --- a/src/validators/parent-validator.ts +++ b/src/validators/parent-validator.ts @@ -1,7 +1,7 @@ import { Reference, ValidationContext } from 'sanity'; import { getDocumentTypeQuery } from '../queries'; -import { RawPageMetadata, PageTreeConfig, SanityRef } from '../types'; +import { PageTreeConfig, RawPageMetadata, SanityRef } from '../types'; /** * Validates that the slug is unique within the parent page and therefore that entire the path is unique.