diff --git a/examples/sage/bud.config.js b/examples/sage/bud.config.js index c2acce7da1..6a6dc444db 100644 --- a/examples/sage/bud.config.js +++ b/examples/sage/bud.config.js @@ -14,8 +14,9 @@ export default async bud => { .serve(3000) .proxy('http://example.test') - bud.wpjson - .useTailwindColors(true) + bud.wp.json + .useTailwindColors('extend') .useTailwindFontFamily() .useTailwindFontSize() + .useTailwindSpacing() } diff --git a/sources/@repo/yarn-plugin-bud/bundles/@yarnpkg/plugin-bud.js b/sources/@repo/yarn-plugin-bud/bundles/@yarnpkg/plugin-bud.js index f8ec856264..974225ff84 100644 --- a/sources/@repo/yarn-plugin-bud/bundles/@yarnpkg/plugin-bud.js +++ b/sources/@repo/yarn-plugin-bud/bundles/@yarnpkg/plugin-bud.js @@ -34,13 +34,13 @@ globstar while`,n,S,i,x,H),this.matchOne(n.slice(S),i.slice(x),o))return this.de |_.__/ \\__._|\\__._| `),Object.values(Ai).filter(n=>n.usage).forEach(n=>{n.usage.examples?.forEach(([i,o])=>{process.stdout.write(` \x1B[34m${o}\x1B[0m ${i} -`)})})}};Ei.paths=[["@bud"]];var Nt=Fe(nu());var Nr=class extends X{constructor(){super(...arguments);this.tsconfig=j("config/tsconfig.json")}async bundle({alias:i={},external:o=[],format:u="esm",outdir:c,outfile:f,source:h}){return this.cli.run(["esbuild","--alias:webpack=@roots/bud-support/webpack","--allow-overwrite","--bundle","--external:crypto","--external:module","--external:node:*","--external:@roots/*","--minify","--log-level=warning","--platform=node",...Object.entries(i).map(([g,_])=>`--alias:${g}=${_}`),...o.map(g=>`--external:${g}`),`--format=${u}`,f?`--outfile=${f}`:null,c?`--outdir=${c}`:null,h].filter(Boolean))}async execute(){if(await Promise.all([this.bundle({format:"cjs",outfile:"sources/@roots/filesystem/vendor/sdk/index.cjs",source:"node_modules/@aws-sdk/client-s3/dist-es/index.js"}),this.bundle({format:"esm",outfile:"sources/@roots/bud-support/vendor/highlight/index.js",source:"sources/@roots/bud-support/src/highlight/index.ts"}).then(async()=>{await Nt.writeAsync(j("sources/@roots/bud-support/vendor/highlight/index.d.ts"),"export declare const highlight: (code: string) => string;")}),this.bundle({external:["./runtime/getUrl.js"],format:"cjs",outfile:j("sources/@roots/bud-support/vendor/html-loader/index.cjs"),source:j("node_modules/html-loader/dist/index.js")}).then(async()=>{let o=j("sources/@roots/bud-support/vendor/html-loader/index.cjs"),u=await Nt.readAsync(o);await Nt.writeAsync(o,u.replace(/\.\/runtime\/getUrl\.js/g,"./runtime/getUrl.cjs")),await Nt.copyAsync(j("node_modules/html-loader/dist/runtime/getUrl.js"),j("sources/@roots/bud-support/vendor/html-loader/runtime/getUrl.cjs"),{overwrite:!0})}),this.bundle({external:["./lib/loader.js"],format:"cjs",outfile:"sources/@roots/bud-support/vendor/html-webpack-plugin/index.cjs",source:"node_modules/html-webpack-plugin/index.js"}).then(async()=>{let o=j("sources/@roots/bud-support/vendor/html-webpack-plugin/index.cjs"),u=await Nt.readAsync(o);await Nt.writeAsync(o,u.replace(/\.\/lib\/loader\.js/g,"./lib/loader.cjs"))}),Nt.copyAsync(j("node_modules/html-webpack-plugin/lib/loader.js"),j("sources/@roots/bud-support/vendor/html-webpack-plugin/lib/loader.cjs"),{overwrite:!0}),Nt.copyAsync(j("node_modules/html-webpack-plugin/typings.d.ts"),j("sources/@roots/bud-support/vendor/html-webpack-plugin/index.d.cts"),{overwrite:!0})]).catch(o=>{throw o}),await this.cli.run(["@bud","tsc","--build",this.tsconfig,"--force"]).catch(o=>{throw o})!==0)throw new Error("Build failed")}};Nr.paths=[["@bud","build"]],Nr.usage={category:"@bud",description:"Build packages",examples:[["build packages","yarn @bud build"]]};var $r=class extends X{async execute(){await this.cli.run(["exec","git","clean","-fxd"])}};$r.paths=[["@bud","clean"]],$r.usage={category:"@bud",description:"clean project artifacts",examples:[["clean project artifacts","yarn @bud clean"]]};var Mr=class extends X{async execute(){await this.cli.run(["workspace","@repo/yarn-plugin-bud","build"]).catch(n=>{throw n}).then(n=>{if(n!==0)throw new Error("Plugin could not be built.")})}};Mr.paths=[["@bud","plugin","build"]],Mr.usage={category:"@bud",examples:[["build @bud yarn plugin","yarn @bud plugin build"]]};var Fr=class extends X{async execute(){await this.cli.run(["workspace","@repo/markdown-kit","exec","node","contributors/index.js"]).catch(n=>{throw n})}};Fr.paths=[["@bud","contributors"]],Fr.usage={category:"@bud",description:"Aggregate contributor data",examples:[["update contributors","yarn @bud contributors"]]};var qr=class extends X{async execute(){await this.cli.run(["@bud","build"]),await this.cli.run(["@bud","docs","build"]),this.promised.push(this.cli.run(["@bud","tsc","--watch"]),this.cli.run(["@bud","test","unit"]),this.cli.run(["@bud","docs","dev"])),await Promise.all(this.promised)}};qr.paths=[["@bud","dev"]],qr.usage={category:"@bud",description:"develop project code",examples:[["run tsc, docusaurus & vitest in watch mode","yarn @bud dev"]]};var Hr=class extends X{async execute(){await this.cli.run(["@bud","build"]).then(n=>n!==0&&this.catch(new Error(`\`@bud build\` returned error code ${n}`))).catch(this.catch),await this.cli.run(["workspace","@repo/markdown-kit","run","build"]).then(n=>n!==0&&this.catch(new Error(`\`workspace @repo/markdown-kit run build\` returned error code ${n}`))).catch(this.catch),await Promise.all([this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/cli-examples/index.js"]).catch(this.catch),this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/releases/index.js"]).catch(this.catch),this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/readme/index.js"]).catch(this.catch)]),await this.cli.run(["@bud","docusaurus","build"]).then(n=>n!==0&&this.catch(new Error(`\`@bud docusaurus build\` returned error code ${n}`))).catch(this.catch)}};Hr.paths=[["@bud","docs"],["@bud","docs","build"]],Hr.usage={category:"@bud",description:"build docs and other markdown files",examples:[["build docs and readme","yarn @bud docs"]]};var Br=class extends X{async execute(){await this.cli.run(["@bud","docs","build"]),await this.cli.run(["@bud","docusaurus","start"])}};Br.paths=[["@bud","docs","dev"]],Br.usage={category:"@bud",description:"develop docs",examples:[["develop docs","yarn @bud docs dev"]]};var ki=class extends X{constructor(){super(...arguments);this.emoji={chore:"\u{1F9F9}",deps:"\u{1F4E6}",feat:"\u2728",fix:"\u{1FA79}",release:"\u{1F680}",test:"\u{1F9EA}"};this.validator=/^(chore|feat|fix|test|deps):(none|patch|minor|major)(.*)/;this.exit=(...i)=>{throw i.map(o=>this.context.stderr.write(`${o} +`)})})}};Ei.paths=[["@bud"]];var Nt=Fe(nu());var Nr=class extends X{constructor(){super(...arguments);this.tsconfig=j("config/tsconfig.json")}async bundle({alias:i={},external:o=[],format:u="esm",outdir:c,outfile:f,source:h}){return this.cli.run(["esbuild","--alias:webpack=@roots/bud-support/webpack","--allow-overwrite","--bundle","--external:crypto","--external:module","--external:node:*","--external:@roots/*","--minify","--log-level=warning","--platform=node",...Object.entries(i).map(([g,_])=>`--alias:${g}=${_}`),...o.map(g=>`--external:${g}`),`--format=${u}`,f?`--outfile=${f}`:null,c?`--outdir=${c}`:null,h].filter(Boolean))}async execute(){if(await Promise.all([this.bundle({format:"cjs",outfile:"sources/@roots/filesystem/vendor/sdk/index.cjs",source:"node_modules/@aws-sdk/client-s3/dist-es/index.js"}),this.bundle({format:"esm",outfile:"sources/@roots/bud-support/vendor/highlight/index.js",source:"sources/@roots/bud-support/src/highlight/index.ts"}).then(async()=>{await Nt.writeAsync(j("sources/@roots/bud-support/vendor/highlight/index.d.ts"),"export declare const highlight: (code: string) => string;")}),this.bundle({external:["./runtime/getUrl.js"],format:"cjs",outfile:j("sources/@roots/bud-support/vendor/html-loader/index.cjs"),source:j("node_modules/html-loader/dist/index.js")}).then(async()=>{let o=j("sources/@roots/bud-support/vendor/html-loader/index.cjs"),u=await Nt.readAsync(o);await Nt.writeAsync(o,u.replace(/\.\/runtime\/getUrl\.js/g,"./runtime/getUrl.cjs")),await Nt.copyAsync(j("node_modules/html-loader/dist/runtime/getUrl.js"),j("sources/@roots/bud-support/vendor/html-loader/runtime/getUrl.cjs"),{overwrite:!0})}),this.bundle({external:["./lib/loader.js"],format:"cjs",outfile:"sources/@roots/bud-support/vendor/html-webpack-plugin/index.cjs",source:"node_modules/html-webpack-plugin/index.js"}).then(async()=>{let o=j("sources/@roots/bud-support/vendor/html-webpack-plugin/index.cjs"),u=await Nt.readAsync(o);await Nt.writeAsync(o,u.replace(/\.\/lib\/loader\.js/g,"./lib/loader.cjs"))}),Nt.copyAsync(j("node_modules/html-webpack-plugin/lib/loader.js"),j("sources/@roots/bud-support/vendor/html-webpack-plugin/lib/loader.cjs"),{overwrite:!0}),Nt.copyAsync(j("node_modules/html-webpack-plugin/typings.d.ts"),j("sources/@roots/bud-support/vendor/html-webpack-plugin/index.d.cts"),{overwrite:!0})]).catch(o=>{throw o}),await this.cli.run(["@bud","tsc","--build",this.tsconfig,"--force"]).catch(o=>{throw o})!==0)throw new Error("Build failed")}};Nr.paths=[["@bud","build"]],Nr.usage={category:"@bud",description:"Build packages",examples:[["build packages","yarn @bud build"]]};var $r=class extends X{async execute(){await this.cli.run(["exec","git","clean","-fxd"])}};$r.paths=[["@bud","clean"]],$r.usage={category:"@bud",description:"clean project artifacts",examples:[["clean project artifacts","yarn @bud clean"]]};var Mr=class extends X{async execute(){await this.cli.run(["workspace","@repo/yarn-plugin-bud","build"]).catch(n=>{throw n}).then(n=>{if(n!==0)throw new Error("Plugin could not be built.")})}};Mr.paths=[["@bud","plugin","build"]],Mr.usage={category:"@bud",examples:[["build @bud yarn plugin","yarn @bud plugin build"]]};var Fr=class extends X{async execute(){await this.cli.run(["workspace","@repo/markdown-kit","exec","node","contributors/index.js"]).catch(n=>{throw n})}};Fr.paths=[["@bud","contributors"]],Fr.usage={category:"@bud",description:"Aggregate contributor data",examples:[["update contributors","yarn @bud contributors"]]};var qr=class extends X{async execute(){await this.cli.run(["@bud","build"]),await this.cli.run(["@bud","docs","build"]),this.promised.push(this.cli.run(["@bud","tsc","--watch"]),this.cli.run(["@bud","test","unit"]),this.cli.run(["@bud","docs","dev"])),await Promise.all(this.promised)}};qr.paths=[["@bud","dev"]],qr.usage={category:"@bud",description:"develop project code",examples:[["run tsc, docusaurus & vitest in watch mode","yarn @bud dev"]]};var Hr=class extends X{async execute(){await this.cli.run(["@bud","build"]).then(n=>n!==0&&this.catch(new Error(`\`@bud build\` returned error code ${n}`))).catch(this.catch),await this.cli.run(["workspace","@repo/markdown-kit","run","build"]).then(n=>n!==0&&this.catch(new Error(`\`workspace @repo/markdown-kit run build\` returned error code ${n}`))).catch(this.catch),await Promise.all([this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/cli-examples/index.js"]).catch(this.catch),this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/releases/index.js"]).catch(this.catch),this.cli.run(["workspace","@repo/markdown-kit","exec","node","compiled/readme/index.js"]).catch(this.catch)]),await this.cli.run(["@bud","docusaurus","build"]).then(n=>n!==0&&this.catch(new Error(`\`@bud docusaurus build\` returned error code ${n}`))).catch(this.catch)}};Hr.paths=[["@bud","docs"],["@bud","docs","build"]],Hr.usage={category:"@bud",description:"build docs and other markdown files",examples:[["build docs and readme","yarn @bud docs"]]};var Br=class extends X{async execute(){await this.cli.run(["@bud","docs","build"]),await this.cli.run(["@bud","docusaurus","start"])}};Br.paths=[["@bud","docs","dev"]],Br.usage={category:"@bud",description:"develop docs",examples:[["develop docs","yarn @bud docs dev"]]};var ki=class extends X{constructor(){super(...arguments);this.emoji={chore:"\u{1F9F9}",deps:"\u{1F4E6}",docs:"\u{1F4D5}",feat:"\u2728",fix:"\u{1FA79}",improve:"\u{1F528}",merge:"\u{1F500}",release:"\u{1F680}",test:"\u{1F9EA}"};this.validator=/^(chore|deps|docs|feat|fix|improve|merge|release|test):(none|patch|minor|major)(.*)/;this.exit=(...i)=>{throw i.map(o=>this.context.stderr.write(`${o} `)),new Error("Invalid commit message")}}async execute(){let i=await import("fs/promises"),o=await i.readFile("./.git/COMMIT_EDITMSG","utf8").catch(this.exit).then(u=>u.split(` `).filter(c=>!c.startsWith("#")).map(c=>c.trim()).join(` `)??"");o!==` `&&(this.validator.test(o)||this.exit(`Invalid commit message format `,`Message should follow the format: : -`,`Where is one of: chore, deps, feat, fix, release, test +`,`Where is one of: chore, deps, docs, feat, fix, improve, merge, release, test `,`And is one of: none, patch, minor, major `,"Example: feat:minor add new feature"),await i.writeFile("./.git/COMMIT_EDITMSG",o.replace(this.validator,(u,c,f,h)=>`${this.emoji[c]} ${c}(${f}):${h}`),"utf8").catch(this.exit))}};ki.paths=[["@bud","git-hooks","commit-msg"]];var yv=q("clipanion");var Wr=class extends X{constructor(){super(...arguments);this.fix=yv.Option.Boolean("--fix",!1)}async execute(){this.promised.push(this.cli.run(["@bud","eslint",this.fix?"--fix":void 0].filter(Boolean)).then(this.throwIfError).catch(this.catch),this.cli.run(["@bud","syncpack"]).then(this.throwIfError).catch(this.catch),this.cli.run(["@bud","prettier",this.fix?"--write":void 0].filter(Boolean)).then(this.throwIfError).catch(this.catch),this.cli.run(["@bud","package-check"]).then(this.throwIfError).catch(this.catch)),await Promise.all(this.promised)}};Wr.paths=[["@bud","lint"]],Wr.usage={category:"@bud",description:"Lint project"};var un=Fe(nu());var Ur=class extends X{async execute(){if(await un.removeAsync(j("storage/mocks")).catch(this.catch),await un.removeAsync(j("storage","packages")).catch(this.catch),await un.existsAsync(j("storage",".verdaccio-db.json"))){let i=await un.readAsync(j("storage",".verdaccio-db.json"),"json").catch(this.catch);i.list=[],await un.writeAsync(j("storage/.verdaccio-db.json"),i).catch(this.catch)}}};Ur.paths=[["@bud","registry","clean"]],Ur.usage={category:"@bud",description:"clean previously published packages",examples:[["clean previously published packages","yarn @bud registry clean"]]};var Jl=Fe(xr());var Gr=class extends X{async execute(){await this.cli.run(["@bud","pm2","start",j("node_modules","verdaccio","build","lib","cli","cli.js"),"-n","verdaccio","--","--config",j("config","verdaccio","config.yaml")]).catch(Jl.noop).finally(async()=>{await this.cli.run(["@bud","pm2","save"]).catch(Jl.noop)})}};Gr.paths=[["@bud","registry","start"]],Gr.usage={category:"@bud",description:"start verdaccio registry",examples:[["start verdaccio server","yarn @bud registry start"]]};var ef=Fe(xr());var jr=class extends X{async execute(){await this.cli.run(["@bud","pm2","stop","verdaccio"]).catch(ef.noop),await this.cli.run(["@bud","pm2","delete","verdaccio"]).catch(ef.noop)}};jr.paths=[["@bud","registry","stop"]],jr.usage={category:"@bud",description:"stop verdaccio registry",examples:[["stop verdaccio server","yarn @bud registry stop"]]};var ru=q("clipanion"),Di=Fe(xr());var Kr=class extends X{constructor(){super();this.registry=ru.Option.String("-r,--registry","http://localhost:4873",{description:"Release registry"});this.tag=ru.Option.String("-t,--tag",{description:"Release tag",required:!0});this.version=ru.Option.String("-v,--version",{description:"Release version",required:!1});this.catch=this.catch.bind(this),this.resetRegistry=this.resetRegistry.bind(this)}async catch(){await this.resetRegistry()}async execute(){this.registry.startsWith("http://localhost:4873")&&(await this.cli.run(["config","set","npmPublishRegistry","http://localhost:4873"]).then(this.throwIfError).catch(this.catch),await this.cli.run(["config","set","npmRegistryServer","http://localhost:4873"]).then(this.throwIfError).catch(this.catch)),this.version||(this.version=this.makeVersion()),await this.cli.run(["@bud","version",this.version]).then(this.throwIfError).catch(this.catch),await this.cli.run(["workspaces","foreach","--all","--no-private","npm","publish","--access","public","--tag",this.tag]).then(this.throwIfError).catch(this.catch),await this.resetRegistry(),this.context.stdout.write(` diff --git a/sources/@repo/yarn-plugin-bud/sources/command/git.commit-msg.ts b/sources/@repo/yarn-plugin-bud/sources/command/git.commit-msg.ts index 8455c7e2f8..9d7c623362 100644 --- a/sources/@repo/yarn-plugin-bud/sources/command/git.commit-msg.ts +++ b/sources/@repo/yarn-plugin-bud/sources/command/git.commit-msg.ts @@ -10,14 +10,17 @@ export class GitHookCommitMsg extends Command { public emoji = { chore: `๐Ÿงน`, deps: `๐Ÿ“ฆ`, + docs: `๐Ÿ“•`, feat: `โœจ`, fix: `๐Ÿฉน`, + improve: `๐Ÿ”จ`, + merge: `๐Ÿ”€`, release: `๐Ÿš€`, test: `๐Ÿงช`, } public validator = - /^(chore|feat|fix|test|deps):(none|patch|minor|major)(.*)/ + /^(chore|deps|docs|feat|fix|improve|merge|release|test):(none|patch|minor|major)(.*)/ public exit = (...messages: Array): never => { messages.map(message => this.context.stderr.write(`${message}\n`)) @@ -48,7 +51,7 @@ export class GitHookCommitMsg extends Command { this.exit( `Invalid commit message format\n`, `Message should follow the format: : \n`, - `Where is one of: chore, deps, feat, fix, release, test\n`, + `Where is one of: chore, deps, docs, feat, fix, improve, merge, release, test\n`, `And is one of: none, patch, minor, major\n`, `Example: feat:minor add new feature`, ) diff --git a/sources/@roots/bud-tailwindcss-theme-json/src/extension.ts b/sources/@roots/bud-tailwindcss-theme-json/src/extension.ts index b570e684ef..31b69fa88e 100644 --- a/sources/@roots/bud-tailwindcss-theme-json/src/extension.ts +++ b/sources/@roots/bud-tailwindcss-theme-json/src/extension.ts @@ -13,19 +13,27 @@ import WordPressJSONPlugin, { import * as tailwindAdapter from './tailwind/index.js' +interface Options { + color?: `extend` | boolean + fontFamily?: `extend` | boolean + fontSize?: `extend` | boolean + spacing?: `extend` | boolean +} + /** * Support Tailwind values in {@link Bud.wpjson} */ @label(`@roots/bud-tailwindcss-theme-json`) -@options({ - colors: false, - colorsExtendOnly: false, - fontFamilies: false, - fontFamiliesExtendOnly: false, - fontSizes: false, - fontSizesExtendOnly: false, +@options({ + color: false, + fontFamily: false, + fontSize: false, + spacing: false, }) export class TailwindThemeJSON extends Extension { + /** + * {@link Extension.apply} + */ @bind public override apply(compiler: Compiler) { compiler.hooks.thisCompilation.tap( @@ -44,14 +52,17 @@ export class TailwindThemeJSON extends Extension { if (this.app.isDevelopment) await this.app.tailwind.sourceConfig() - if (this.options.colors) { - data = this.tapColorsManifestObject(data) + if (this.options.color) { + data = this.tapTailwindColor(data) + } + if (this.options.fontFamily) { + data = this.tapTailwindFontFamily(data) } - if (this.options.fontFamilies) { - data = this.tapFontFamiliesManifestObject(data) + if (this.options.fontSize) { + data = this.tapTailwindFontSize(data) } - if (this.options.fontSizes) { - data = this.tapFontSizesManifestObject(data) + if (this.options.spacing) { + data = this.tapTailwindSpacing(data) } return data @@ -71,16 +82,15 @@ export class TailwindThemeJSON extends Extension { bud.wpjson.useTailwindColors = this.useTailwindColors bud.wpjson.useTailwindFontFamily = this.useTailwindFontFamily bud.wpjson.useTailwindFontSize = this.useTailwindFontSize + bud.wpjson.useTailwindSpacing = this.useTailwindSpacing } @bind - public tapColorsManifestObject( - options: SettingsAndStyles, - ): SettingsAndStyles { + public tapTailwindColor(options: SettingsAndStyles): SettingsAndStyles { const palette = tailwindAdapter.palette.transform({ ...this.app.tailwind.resolveThemeValue( `colors`, - this.options.colorsExtendOnly, + this.options.color === `extend`, ), }) @@ -98,13 +108,13 @@ export class TailwindThemeJSON extends Extension { } @bind - public tapFontFamiliesManifestObject( + public tapTailwindFontFamily( json: SettingsAndStyles, ): SettingsAndStyles { const fontFamilies = tailwindAdapter.fontFamily.transform({ ...this.app.tailwind.resolveThemeValue( `fontFamily`, - this.options.fontFamiliesExtendOnly, + this.options.fontFamily === `extend`, ), }) @@ -122,13 +132,13 @@ export class TailwindThemeJSON extends Extension { } @bind - public tapFontSizesManifestObject( + public tapTailwindFontSize( options: SettingsAndStyles, ): SettingsAndStyles { const fontSizes = tailwindAdapter.fontSize.transform({ ...this.app.tailwind.resolveThemeValue( `fontSize`, - this.options.fontSizeExtendOnly, + this.options.fontSize === `extend`, ), }) @@ -145,39 +155,71 @@ export class TailwindThemeJSON extends Extension { } } - /** - * Use tailwind colors in theme.json - */ @bind - public useTailwindColors(extendOnly: boolean = false): any { - this.app.wpjson.enable() - this.set(`colors`, true) - this.set(`colorsExtendOnly`, extendOnly) + public tapTailwindSpacing( + options: SettingsAndStyles, + ): SettingsAndStyles { + const spacingSizes = tailwindAdapter.spacing.transform({ + ...this.app.tailwind.resolveThemeValue( + `spacing`, + this.options.spacingSize === `extend`, + ), + }) - return this.app.wpjson + return { + ...(options ?? {}), + settings: { + ...(options?.settings ?? {}), + spacing: { + ...(options?.settings?.spacing ?? {}), + spacingSizes, + }, + }, + version: 2, + } } - /** - * Use tailwind fontFamily in theme.json - */ @bind - public useTailwindFontFamily(extendOnly: boolean = false): any { + public useTailwindColors(extend?: boolean): any { this.app.wpjson.enable() - this.set(`fontFamilies`, true) - this.set(`fontFamiliesExtendOnly`, extendOnly) + this.handleOption(`color`, extend) + return this.app.wpjson + } + @bind + public useTailwindFontFamily(extend?: boolean): any { + this.app.wpjson.enable() + this.handleOption(`fontFamily`, extend) return this.app.wpjson } - /** - * Use tailwind fontSize in theme.json - */ @bind - public useTailwindFontSize(extendOnly: boolean = false): any { + public useTailwindFontSize(extend?: `extend` | boolean): any { this.app.wpjson.enable() - this.set(`fontSizes`, true) - this.set(`fontSizesExtendOnly`, extendOnly) + this.handleOption(`fontSize`, extend) + return this.app.wpjson + } + @bind + public useTailwindSpacing(extend?: boolean): any { + this.app.wpjson.enable() + this.handleOption(`spacing`, extend) return this.app.wpjson } + + private handleOption(option: string, value: `extend` | boolean) { + switch (value) { + case `extend`: + this.set(option, `extend`) + break + case true: + this.set(option, `extend`) + break + case false: + this.set(option, false) + break + default: + this.set(option, true) + } + } } diff --git a/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/index.ts b/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/index.ts index c65eece508..9597575a4d 100644 --- a/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/index.ts +++ b/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/index.ts @@ -1,5 +1,6 @@ import * as fontFamily from './fontFamily.js' import * as fontSize from './fontSize.js' import * as palette from './palette.js' +import * as spacing from './spacing.js' -export {fontFamily, fontSize, palette} +export {fontFamily, fontSize, palette, spacing} diff --git a/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/spacing.ts b/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/spacing.ts new file mode 100644 index 0000000000..0015a4b527 --- /dev/null +++ b/sources/@roots/bud-tailwindcss-theme-json/src/tailwind/spacing.ts @@ -0,0 +1,34 @@ +import type {Theme} from '@roots/bud-wordpress-theme-json' + +export interface TailwindSize { + [key: string]: string +} +export type WordPressSpacingSizes = + Theme.SettingsAndStyles['settings']['spacing']['spacingSizes'] + +/** + * Make a theme.json {@link Theme.SettingsAndStyles['settings']['spacing']['spacingSizes'] | settings.spacing.spacingSizes} item from a key/value pair + * + * @param slug - spacing slug + * @param value - spacing value + * @returns WordPress theme.json color + */ +export interface transformEntry { + ([slug, value]: [string, string]): WordPressSpacingSizes[any] +} +export const transformEntry: transformEntry = ([slug, size]) => ({ + name: slug, + size, + slug, +}) + +/** + * Transform tailwindcss spacing to wordpress theme.json spacing + * + * @param sizes - from tailwindcss + */ +export interface transform { + (sizes: TailwindSize): undefined | WordPressSpacingSizes +} +export const transform: transform = sizes => + Object.entries(sizes)?.map(transformEntry) ?? undefined diff --git a/sources/@roots/bud-tailwindcss/src/extension/options.ts b/sources/@roots/bud-tailwindcss/src/extension/options.ts index 5701494920..4653d42dc1 100644 --- a/sources/@roots/bud-tailwindcss/src/extension/options.ts +++ b/sources/@roots/bud-tailwindcss/src/extension/options.ts @@ -216,13 +216,13 @@ class BudTailwindOptionsApi if (extendedOnly) { if (!this.config?.theme?.extend) throw new Error( - `@roots/bud-tailwindcss: cannot resolve extended theme value when no extended theme config is set.`, + `@roots/bud-tailwindcss: using \`extendOnly\` with ${key} but \`theme.extend\` is not defined in your tailwind config.`, ) const value = this.config.theme.extend[key] if (!value) { throw new Error( - `@roots/bud-tailwindcss: extend.${key} is not a valid tailwind theme key.`, + `@roots/bud-tailwindcss: using \`extendOnly\` with ${key} but \`theme.extend.${key}\` is not defined in your tailwind config.`, ) } diff --git a/sources/@roots/bud-tailwindcss/test/extension/__snapshots__/index.test.ts.snap b/sources/@roots/bud-tailwindcss/test/extension/__snapshots__/index.test.ts.snap index 35196b7fa3..5421e260b5 100644 --- a/sources/@roots/bud-tailwindcss/test/extension/__snapshots__/index.test.ts.snap +++ b/sources/@roots/bud-tailwindcss/test/extension/__snapshots__/index.test.ts.snap @@ -305,4 +305,4 @@ exports[`@roots/bud-tailwindcss extension > should resolve tailwind config value exports[`@roots/bud-tailwindcss extension > should throw when key does not exist 1`] = `[Error: @roots/bud-tailwindcss: foo is not a valid tailwind theme key.]`; -exports[`@roots/bud-tailwindcss extension > should throw when key does not exist in extended config (filter extends) 1`] = `[Error: @roots/bud-tailwindcss: extend.lineHeight is not a valid tailwind theme key.]`; +exports[`@roots/bud-tailwindcss extension > should throw when key does not exist in extended config (filter extends) 1`] = `[Error: @roots/bud-tailwindcss: using \`extendOnly\` with lineHeight but \`theme.extend.lineHeight\` is not defined in your tailwind config.]`; diff --git a/sources/@roots/bud-wordpress-theme-json/README.md b/sources/@roots/bud-wordpress-theme-json/README.md index 7332975480..a659b6187e 100644 --- a/sources/@roots/bud-wordpress-theme-json/README.md +++ b/sources/@roots/bud-wordpress-theme-json/README.md @@ -32,13 +32,15 @@ npm install @roots/bud-wordpress-theme-json --save-dev ## Usage -You can manage [WordPress' `theme.json` config file](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/) from the context of your bud config using **bud.wptheme**. +You can manage [WordPress' `theme.json` config file](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/) from the context of your bud config using **bud.wpjson**. + +If you are using this with the [@roots/bud-preset-wordpress](https://bud.js.org/extensions/bud-preset-wordpress) or [@roots/sage](https://bud.js.org/extensions/sage) preset you can also access the class using **bud.wp.json**. ### Enabling `theme.json` support In order to emit the file you will need to enable the feature: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson.enable(); ``` @@ -46,7 +48,7 @@ bud.wpjson.enable(); You can use `setOption` from the bud.js extensions API to set `theme.json` values: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson.setOption("customTemplates", []).enable(); ``` @@ -55,8 +57,8 @@ bud.wpjson.setOption("customTemplates", []).enable(); Most `theme.json` configuration centers around the `settings` property. You can modify these values using a fluent container interface exposed by `bud.wpjson.settings`. -```ts title="bud.config.mjs" -bud.wptheme +```ts title=bud.config.ts +bud.wpjson .settings((theme) => theme .set("typography.customFontSizes", true) @@ -71,49 +73,56 @@ bud.wptheme If you use [@roots/bud-tailwindcss](https://bud.js.org/extensions/bud-tailwindcss) in your project there are several opt-in config functions that allow you to generate `theme.json` values directly from your tailwind config. -#### wpjson.useTailwindColors() +#### wp.json.useTailwindColors() Convert `theme.colors` to a `theme.json` palette. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindColors().enable(); +```ts title=bud.config.ts +bud.wpjson.useTailwindColors(); ``` -#### wpjson.useTailwindFontSize() +#### wp.json.useTailwindFontSize() Emits values from `theme.fontSize` as the `typography.fontSizes` property of `theme.json`. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindFontSize().enable(); +```ts title=bud.config.ts +bud.wpjson.useTailwindFontSize(); ``` -#### wpjson.useTailwindFontFamily() +#### wp.json.useTailwindFontFamily() Emits values from `theme.fontFamily` as the `typography.fontFamilies` property of `theme.json`. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindFontFamily().enable(); +```ts title=bud.config.ts +bud.wpjson.useTailwindFontFamily(); +``` + +### wp.json.useTailwindSpacing() + +Emits values from `theme.spacing` as the `spacing` property of `theme.json`. + +```ts title=bud.config.ts +bud.wpjson.useTailwindFontFamily(); ``` #### Limiting values to those defined in `theme.extend` -You can pass `true` to any of the the above functions to limit the values emitted to those defined under tailwind's `theme.extend` key. +You can pass `'extend'` to any of the the tailwind helper functions to limit the values emitted to those defined under tailwind's `theme.extend` key. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindColors(true).enable(); +```ts title=bud.config.ts +bud.wpjson.useTailwindColors(`extend`); ``` ### In combination -You can use any of these methods in combination: +You can use these methods in combination: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson .useTailwindColors() .useTailwindFontSize() .useTailwindFontFamily() - .setOption("typography.fontWeight", false) - .enable(); + .setOption("typography.fontWeight", false); ``` ## Contributing diff --git a/sources/@roots/bud-wordpress-theme-json/docs/01-managing-theme-json.md b/sources/@roots/bud-wordpress-theme-json/docs/01-managing-theme-json.md index 742f54ca35..87b24e36b7 100644 --- a/sources/@roots/bud-wordpress-theme-json/docs/01-managing-theme-json.md +++ b/sources/@roots/bud-wordpress-theme-json/docs/01-managing-theme-json.md @@ -2,13 +2,15 @@ title: Usage --- -You can manage [WordPress' `theme.json` config file](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/) from the context of your bud config using **bud.wptheme**. +You can manage [WordPress' `theme.json` config file](https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-json/) from the context of your bud config using **bud.wpjson**. + +If you are using this with the [@roots/bud-preset-wordpress](https://bud.js.org/extensions/bud-preset-wordpress) or [@roots/sage](https://bud.js.org/extensions/sage) preset you can also access the class using **bud.wp.json**. ### Enabling `theme.json` support In order to emit the file you will need to enable the feature: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson.enable() ``` @@ -16,7 +18,7 @@ bud.wpjson.enable() You can use `setOption` from the bud.js extensions API to set `theme.json` values: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson.setOption('customTemplates', []).enable() ``` @@ -25,8 +27,8 @@ bud.wpjson.setOption('customTemplates', []).enable() Most `theme.json` configuration centers around the `settings` property. You can modify these values using a fluent container interface exposed by `bud.wpjson.settings`. -```ts title="bud.config.mjs" -bud.wptheme +```ts title=bud.config.ts +bud.wpjson .settings(theme => theme .set('typography.customFontSizes', true) @@ -41,47 +43,54 @@ bud.wptheme If you use [@roots/bud-tailwindcss](https://bud.js.org/extensions/bud-tailwindcss) in your project there are several opt-in config functions that allow you to generate `theme.json` values directly from your tailwind config. -#### wpjson.useTailwindColors() +#### wp.json.useTailwindColors() Convert `theme.colors` to a `theme.json` palette. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindColors().enable() +```ts title=bud.config.ts +bud.wpjson.useTailwindColors() ``` -#### wpjson.useTailwindFontSize() +#### wp.json.useTailwindFontSize() Emits values from `theme.fontSize` as the `typography.fontSizes` property of `theme.json`. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindFontSize().enable() +```ts title=bud.config.ts +bud.wpjson.useTailwindFontSize() ``` -#### wpjson.useTailwindFontFamily() +#### wp.json.useTailwindFontFamily() Emits values from `theme.fontFamily` as the `typography.fontFamilies` property of `theme.json`. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindFontFamily().enable() +```ts title=bud.config.ts +bud.wpjson.useTailwindFontFamily() +``` + +### wp.json.useTailwindSpacing() + +Emits values from `theme.spacing` as the `spacing` property of `theme.json`. + +```ts title=bud.config.ts +bud.wpjson.useTailwindFontFamily() ``` #### Limiting values to those defined in `theme.extend` -You can pass `true` to any of the the above functions to limit the values emitted to those defined under tailwind's `theme.extend` key. +You can pass `'extend'` to any of the the tailwind helper functions to limit the values emitted to those defined under tailwind's `theme.extend` key. -```ts title="bud.config.mjs" -bud.wpjson.useTailwindColors(true).enable() +```ts title=bud.config.ts +bud.wpjson.useTailwindColors(`extend`) ``` ### In combination -You can use any of these methods in combination: +You can use these methods in combination: -```ts title="bud.config.mjs" +```ts title=bud.config.ts bud.wpjson .useTailwindColors() .useTailwindFontSize() .useTailwindFontFamily() .setOption('typography.fontWeight', false) - .enable() ``` diff --git a/sources/@roots/bud-wordpress-theme-json/src/extension.ts b/sources/@roots/bud-wordpress-theme-json/src/extension.ts index 3f25798646..76b9aa2d01 100644 --- a/sources/@roots/bud-wordpress-theme-json/src/extension.ts +++ b/sources/@roots/bud-wordpress-theme-json/src/extension.ts @@ -148,39 +148,158 @@ class WordPressThemeJson extends Extension< /** * ## bud.wp.json.useTailwindColors * - * Source `theme.json` fontSize values from `tailwind.config.js` + * Source settings.color.palette values from tailwind config * - * @note * Requires {@link https://bud.js.org/extensions/bud-tailwindcss/ @roots/bud-tailwindcss} to be installed. + * + * @example + * ```ts + * bud.wp.json.useTailwindColors() + * bud.wp.json.useTailwindColors(true) + * ``` + * + * @example + * Limit to `theme.extend.colors` values + * + * ```ts + * bud.wp.json.useTailwindColors(`extend`) + * ``` + * + * @example + * Do not source values from tailwind config + * + * ```ts + * bud.wp.json.useTailwindColors(false) + * ``` */ public declare useTailwindColors?: ( - value?: boolean, + value?: `extend` | boolean, ) => WordPressThemeJson /** * ## bud.wp.json.useTailwindFontFamily * - * Source `theme.json` fontFamily values from `tailwind.config.js` + * Source settings.typography.fontFamilies values from tailwind config * - * @note * Requires {@link https://bud.js.org/extensions/bud-tailwindcss/ @roots/bud-tailwindcss} to be installed. + * + * @example + * ```ts + * bud.wp.json.useTailwindFontFamily() + * bud.wp.json.useTailwindFontFamily(true) + * ``` + * + * @example + * Limit to `theme.extend.fontFamily` values + * + * ```ts + * bud.wp.json.useTailwindFontFamily(`extend`) + * ``` + * + * @example + * Disable + * + * ```ts + * bud.wp.json.useTailwindFontFamily(false) + * ``` */ public declare useTailwindFontFamily?: ( - value?: boolean, + value?: `extend` | boolean, ) => WordPressThemeJson /** * ## bud.wp.json.useTailwindFontSize * - * Source `theme.json` fontSize values from `tailwind.config.js` + * Source settings.typography.fontSizes values from tailwind config * - * @note * Requires {@link https://bud.js.org/extensions/bud-tailwindcss/ @roots/bud-tailwindcss} to be installed. + * + * @example + * ```ts + * bud.wp.json.useTailwindFontSize() + * bud.wp.json.useTailwindFontSize(true) + * ``` + * + * @example + * Limit to `theme.extend.fontSize` values + * + * ```ts + * bud.wp.json.useTailwindFontSize(`extend`) + * ``` + * + * @example + * Disable + * + * ```ts + * bud.wp.json.useTailwindFontSize(false) + * ``` */ + public declare useTailwindFontSize?: ( - value?: boolean, + value?: `extend` | boolean, + ) => WordPressThemeJson + + /** + * ## bud.wp.json.useTailwindSpacing + * + * Source `theme.json` spacing values from `tailwind.config.js` + * + * Requires {@link https://bud.js.org/extensions/bud-tailwindcss/ @roots/bud-tailwindcss} to be installed. + * + * @example + * ```ts + * bud.wp.json.useTailwindSpacing() + * ``` + * + * @example + * Source theme.spacing values but limit to `extend` values + * + * ```ts + * bud.wp.json.useTailwindSpacing(`extend`) + * ``` + * + * @example + * Disable + * + * ```ts + * bud.wp.json.useTailwindSpacing(false) + * ``` + */ + public declare useTailwindSpacing?: ( + value?: `extend` | boolean, ) => WordPressThemeJson + /** + * ## bud.wp.json.settings + * + * Edit the `settings` key of theme.json + * + * @example + * ```ts + * bud.wp.json.settings({ + * color: { + * custom: false, + * customGradient: false, + * palette: [ + * { + * color: '#f7fafc', + * name: 'Gray', + * slug: 'gray' + * } + * ] + * }) + * ``` + * + * @example + * Edit existing values with a callback: + * + * ```ts + * bud.wp.json.settings((settings = {}) => ({ + * ...settings, + * color: {}, + * })) + * ``` + */ @bind public settings( input: diff --git a/tests/integration/sage.test.ts b/tests/integration/sage.test.ts index 4a7715ad4e..1844217bdf 100644 --- a/tests/integration/sage.test.ts +++ b/tests/integration/sage.test.ts @@ -5,7 +5,6 @@ import { testIsMinimized, testThemeJson, } from '@repo/test-kit/tests' -import {fs} from '@roots/bud-support/filesystem' import {beforeAll, describe, expect, it} from 'vitest' describe(`examples/sage`, () => { @@ -102,8 +101,6 @@ describe(`examples/sage`, () => { const json = sage.getAsset(`../theme.json`) if (typeof json === `string`) throw new Error(`expected object`) - testThemeJson(json) - expect(json).toMatchInlineSnapshot(` { "$schema": "https://schemas.wp.org/trunk/theme.json", @@ -129,6 +126,183 @@ describe(`examples/sage`, () => { }, "spacing": { "padding": true, + "spacingSizes": [ + { + "name": "0", + "size": "0px", + "slug": "0", + }, + { + "name": "1", + "size": "0.25rem", + "slug": "1", + }, + { + "name": "2", + "size": "0.5rem", + "slug": "2", + }, + { + "name": "3", + "size": "0.75rem", + "slug": "3", + }, + { + "name": "4", + "size": "1rem", + "slug": "4", + }, + { + "name": "5", + "size": "1.25rem", + "slug": "5", + }, + { + "name": "6", + "size": "1.5rem", + "slug": "6", + }, + { + "name": "7", + "size": "1.75rem", + "slug": "7", + }, + { + "name": "8", + "size": "2rem", + "slug": "8", + }, + { + "name": "9", + "size": "2.25rem", + "slug": "9", + }, + { + "name": "10", + "size": "2.5rem", + "slug": "10", + }, + { + "name": "11", + "size": "2.75rem", + "slug": "11", + }, + { + "name": "12", + "size": "3rem", + "slug": "12", + }, + { + "name": "14", + "size": "3.5rem", + "slug": "14", + }, + { + "name": "16", + "size": "4rem", + "slug": "16", + }, + { + "name": "20", + "size": "5rem", + "slug": "20", + }, + { + "name": "24", + "size": "6rem", + "slug": "24", + }, + { + "name": "28", + "size": "7rem", + "slug": "28", + }, + { + "name": "32", + "size": "8rem", + "slug": "32", + }, + { + "name": "36", + "size": "9rem", + "slug": "36", + }, + { + "name": "40", + "size": "10rem", + "slug": "40", + }, + { + "name": "44", + "size": "11rem", + "slug": "44", + }, + { + "name": "48", + "size": "12rem", + "slug": "48", + }, + { + "name": "52", + "size": "13rem", + "slug": "52", + }, + { + "name": "56", + "size": "14rem", + "slug": "56", + }, + { + "name": "60", + "size": "15rem", + "slug": "60", + }, + { + "name": "64", + "size": "16rem", + "slug": "64", + }, + { + "name": "72", + "size": "18rem", + "slug": "72", + }, + { + "name": "80", + "size": "20rem", + "slug": "80", + }, + { + "name": "96", + "size": "24rem", + "slug": "96", + }, + { + "name": "px", + "size": "1px", + "slug": "px", + }, + { + "name": "0.5", + "size": "0.125rem", + "slug": "0.5", + }, + { + "name": "1.5", + "size": "0.375rem", + "slug": "1.5", + }, + { + "name": "2.5", + "size": "0.625rem", + "slug": "2.5", + }, + { + "name": "3.5", + "size": "0.875rem", + "slug": "3.5", + }, + ], "units": [ "px", "%",