From 9c41ce8400c5539d60c49389e212496f9f2149a2 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Mon, 11 Nov 2024 16:11:44 +0100 Subject: [PATCH] Plugin API: Allow custom utilities to start with `@` (#14793) Closes #14791 Add support to the JS Plugin interop layer for utilities that _start with_ `@`. This ensures no breaking when trying to load plugins that contribute utilities like `@container` from `@tailwindcss/container-queries` (even though the `@container` utility is now part of core). ## Test Plan Added the `@tailwindcss/container-queries` plugin to to the Vite example: ![Screenshot 2024-10-25 at 11.18.19.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/0Y77ilPI2WoJfMLFiAEw/3761c0a8-8c54-42eb-a1fd-213c4215c024.png) However, in order for the Vite example to load the extension, I also had to apply the following patch: ![Screenshot 2024-10-25 at 11.18.54.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/0Y77ilPI2WoJfMLFiAEw/bd151684-ff7b-4805-b305-71ac0378c610.png) I think this is related to our dev system though, the compiled plugin file is going to be a flat file with no requires in our public release. --------- Co-authored-by: Adam Wathan --- CHANGELOG.md | 1 + .../tailwindcss/src/compat/plugin-api.test.ts | 44 +++++++++++++++++++ packages/tailwindcss/src/compat/plugin-api.ts | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9915642962a7..b18f6887eb81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure spacing utilities with no value (e.g. `px` or `translate-y`) don't generate CSS ([#14911](https://github.com/tailwindlabs/tailwindcss/pull/14911)) - Don't override user-agent background color for input elements in Preflight ([#14913](https://github.com/tailwindlabs/tailwindcss/pull/14913)) - Don't attempt to convert CSS variables (which should already be percentages) to percentages when used as opacity modifiers ([#14916](https://github.com/tailwindlabs/tailwindcss/pull/14916)) +- Ensure custom utilities registered with the plugin API can start with `@` ([#14793](https://github.com/tailwindlabs/tailwindcss/pull/14793)) - _Upgrade (experimental)_: Install `@tailwindcss/postcss` next to `tailwindcss` ([#14830](https://github.com/tailwindlabs/tailwindcss/pull/14830)) - _Upgrade (experimental)_: Remove whitespace around `,` separator when print arbitrary values ([#14838](https://github.com/tailwindlabs/tailwindcss/pull/14838)) - _Upgrade (experimental)_: Fix crash during upgrade when content globs escape root of project ([#14896](https://github.com/tailwindlabs/tailwindcss/pull/14896)) diff --git a/packages/tailwindcss/src/compat/plugin-api.test.ts b/packages/tailwindcss/src/compat/plugin-api.test.ts index 73745e837412..6a3062ad224f 100644 --- a/packages/tailwindcss/src/compat/plugin-api.test.ts +++ b/packages/tailwindcss/src/compat/plugin-api.test.ts @@ -2943,6 +2943,50 @@ describe('matchUtilities()', () => { ).toEqual('') }) + test('custom functional utilities can start with @', async () => { + async function run(candidates: string[]) { + let compiled = await compile( + css` + @plugin "my-plugin"; + @tailwind utilities; + `, + + { + async loadModule(id, base) { + return { + base, + module: ({ matchUtilities }: PluginAPI) => { + matchUtilities( + { '@w': (value) => ({ width: value }) }, + { + values: { + 1: '1px', + }, + }, + ) + }, + } + }, + }, + ) + + return compiled.build(candidates) + } + + expect(optimizeCss(await run(['@w-1','hover:@w-1'])).trim()) + .toMatchInlineSnapshot(` + ".\\@w-1 { + width: 1px; + } + + @media (hover: hover) { + .hover\\:\\@w-1:hover { + width: 1px; + } + }" + `) + }) + test('custom functional utilities can return an array of rules', async () => { let compiled = await compile( css` diff --git a/packages/tailwindcss/src/compat/plugin-api.ts b/packages/tailwindcss/src/compat/plugin-api.ts index 04fb8d43a59d..e348da5c0c5c 100644 --- a/packages/tailwindcss/src/compat/plugin-api.ts +++ b/packages/tailwindcss/src/compat/plugin-api.ts @@ -75,7 +75,7 @@ export type PluginAPI = { prefix(className: string): string } -const IS_VALID_UTILITY_NAME = /^[a-z][a-zA-Z0-9/%._-]*$/ +const IS_VALID_UTILITY_NAME = /^[a-z@][a-zA-Z0-9/%._-]*$/ export function buildPluginApi( designSystem: DesignSystem,