diff --git a/README.md b/README.md index 5a92629f..ff2f2309 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ The inject command can do more work by adding presets. Consult the individual pr - [semver-workflow](./docs/semver-workflow.md) - Add an opinionated Github workflow to automate NPM releases - [renovatebot](./docs/renovatebot.md) - Add opinionated Renovatebot config to make dependency management a breeze +- [ui](./docs/ui.md) - Add [@sanity/ui](https://github.com/sanity-io/ui) to build plugin UIs. - [ui-workshop](./docs/ui-workshop.md) - Add [@sanity/ui-workshop](https://github.com/sanity-io/ui-workshop) to make component testing a breeze ## Testing a plugin in Sanity Studio diff --git a/docs/ui.md b/docs/ui.md new file mode 100644 index 00000000..66b1a982 --- /dev/null +++ b/docs/ui.md @@ -0,0 +1,23 @@ +# Preset: ui + +## Usage + +### Inject into existing package + +`npx @sanity/plugin-kit inject --preset-only --preset ui` + +### Use to init plugin + +`npx @sanity/plugin-kit init --preset ui ` + +## What does it do? + +Sets up your package with [`@sanity/ui`](https://github.com/sanity-io/ui) to build plugin UIs. + +- Adds [`@sanity/ui`](https://github.com/sanity-io/ui) dependency. +- Add required dev and peer dependencies. + +## Manual steps after inject + +- Run `npm i` to install dependencies. +- Refer to @sanity/ui [README](https://github.com/sanity-io/ui) for more. diff --git a/src/configs/forced-package-versions.ts b/src/configs/forced-package-versions.ts index 7cdbfab0..2ddbe1fe 100644 --- a/src/configs/forced-package-versions.ts +++ b/src/configs/forced-package-versions.ts @@ -5,7 +5,9 @@ export const forcedDevPackageVersions = forcedPackageVersions export const forcedPeerPackageVersions = { react: '^18', 'react-dom': '^18', + 'react-is': '^18', '@types/react': '^18', '@types/react-dom': '^18', sanity: '^3', + 'styled-components': '^5.2', } diff --git a/src/npm/package.ts b/src/npm/package.ts index ded990c7..808dc547 100644 --- a/src/npm/package.ts +++ b/src/npm/package.ts @@ -421,7 +421,8 @@ export function sortKeys>(unordered: T): T { }, {} as T) } -function forceDependencyVersions( +/** @internal */ +export function forceDependencyVersions( deps: Record, versions = forcedPackageVersions ): Record { diff --git a/src/presets/presets.ts b/src/presets/presets.ts index 71751c3a..d53e12ce 100644 --- a/src/presets/presets.ts +++ b/src/presets/presets.ts @@ -1,6 +1,7 @@ import {InjectOptions} from '../actions/inject' import {semverWorkflowPreset} from './semver-workflow' import {renovatePreset} from './renovatebot' +import {ui} from './ui' import {uiWorkshop} from './ui-workshop' export interface Preset { @@ -9,7 +10,7 @@ export interface Preset { apply: (options: InjectOptions) => Promise } -const presets: Preset[] = [semverWorkflowPreset, renovatePreset, uiWorkshop] +const presets: Preset[] = [semverWorkflowPreset, renovatePreset, ui, uiWorkshop] const presetNames = presets.map((p) => p?.name) export function presetHelpList(padStart: number) { diff --git a/src/presets/ui.ts b/src/presets/ui.ts new file mode 100644 index 00000000..6a4197ed --- /dev/null +++ b/src/presets/ui.ts @@ -0,0 +1,68 @@ +import {Preset} from './presets' +import {InjectOptions} from '../actions/inject' +import {forceDependencyVersions, getPackage, sortKeys, writePackageJsonDirect} from '../npm/package' +import log from '../util/log' +import chalk from 'chalk' +import {resolveLatestVersions} from '../npm/resolveLatestVersions' +import {forcedDevPackageVersions, forcedPackageVersions} from '../configs/forced-package-versions' + +export const ui: Preset = { + name: 'ui', + description: '`@sanity/ui` and dependencies', + apply: applyPreset, +} + +async function applyPreset(options: InjectOptions) { + await addDependencies(options) + await addDevDependencies(options) + + log.info(chalk.green('ui preset injected')) +} + +async function addDependencies(options: InjectOptions) { + const pkg = await getPackage(options) + const newDeps = sortKeys( + forceDependencyVersions( + { + ...pkg.dependencies, + ...(await resolveDependencyList()), + }, + forcedPackageVersions + ) + ) + const newPkg = {...pkg} + newPkg.dependencies = newDeps + await writePackageJsonDirect(newPkg, options) + log.info('Updated dependencies.') +} + +async function addDevDependencies(options: InjectOptions) { + const pkg = await getPackage(options) + const newDeps = sortKeys( + forceDependencyVersions( + { + ...pkg.devDependencies, + ...(await resolveDevDependencyList()), + }, + forcedDevPackageVersions + ) + ) + const newPkg = {...pkg} + newPkg.devDependencies = newDeps + await writePackageJsonDirect(newPkg, options) + log.info('Updated devDependencies.') +} + +async function resolveDependencyList(): Promise> { + return resolveLatestVersions(['@sanity/icons', '@sanity/ui']) +} + +async function resolveDevDependencyList(): Promise> { + return resolveLatestVersions([ + // install the peer dependencies of `@sanity/ui` as dev dependencies + 'react', + 'react-dom', + 'react-is', + 'styled-components', + ]) +}