diff --git a/packages/preset-mini/src/_variants/pseudo.test.ts b/packages/preset-mini/src/_variants/pseudo.test.ts index c7af8a8489..aa565f3e0b 100644 --- a/packages/preset-mini/src/_variants/pseudo.test.ts +++ b/packages/preset-mini/src/_variants/pseudo.test.ts @@ -48,3 +48,35 @@ test('pseudo variant order', async () => { .disabled\\\\:foo-1:disabled{text:foo-1;}" `) }) + +// https://github.com/unocss/unocss/issues/2733 +test('focus-visible:', async () => { + const uno = createGenerator({ + variants: [ + variantPseudoClassesAndElements(), + ], + rules: [ + [/^foo-(\d)$/, ([_, a]) => ({ text: `foo-${a}` })], + ], + }) + + const result = await uno.generate([ + 'focus-visible:foo-1', + 'focus:foo-2', + ]) + + expect(result.matched) + .toMatchInlineSnapshot(` + Set { + "focus-visible:foo-1", + "focus:foo-2", + } + `) + + expect(result.css) + .toMatchInlineSnapshot(` + "/* layer: default */ + .focus\\\\:foo-2:focus{text:foo-2;} + .focus-visible\\\\:foo-1:focus-visible{text:foo-1;}" + `) +}) diff --git a/packages/preset-mini/src/_variants/pseudo.ts b/packages/preset-mini/src/_variants/pseudo.ts index a543feee5c..a6ecf6cf8d 100644 --- a/packages/preset-mini/src/_variants/pseudo.ts +++ b/packages/preset-mini/src/_variants/pseudo.ts @@ -86,8 +86,16 @@ const PseudoClassFunctions = [ 'has', ] -const PseudoClassesStr = Object.entries(PseudoClasses).filter(([, pseudo]) => !pseudo.startsWith('::')).map(([key]) => key).join('|') -const PseudoClassesColonStr = Object.entries(PseudoClassesColon).filter(([, pseudo]) => !pseudo.startsWith('::')).map(([key]) => key).join('|') +const PseudoClassesStr = Object.entries(PseudoClasses) + .filter(([, pseudo]) => !pseudo.startsWith('::')) + .map(([key]) => key) + .sort((a, b) => b.length - a.length) + .join('|') +const PseudoClassesColonStr = Object.entries(PseudoClassesColon) + .filter(([, pseudo]) => !pseudo.startsWith('::')) + .map(([key]) => key) + .sort((a, b) => b.length - a.length) + .join('|') const PseudoClassFunctionsStr = PseudoClassFunctions.join('|') function taggedPseudoClassMatcher(tag: string, parent: string, combinator: string): VariantObject { @@ -194,8 +202,15 @@ const excludedPseudo = [ '::-webkit-scrollbar-track-piece', '::file-selector-button', ] -const PseudoClassesAndElementsStr = Object.entries(PseudoClasses).map(([key]) => key).join('|') -const PseudoClassesAndElementsColonStr = Object.entries(PseudoClassesColon).map(([key]) => key).join('|') + +const PseudoClassesAndElementsStr = Object.entries(PseudoClasses) + .map(([key]) => key) + .sort((a, b) => b.length - a.length) + .join('|') +const PseudoClassesAndElementsColonStr = Object.entries(PseudoClassesColon) + .map(([key]) => key) + .sort((a, b) => b.length - a.length) + .join('|') export function variantPseudoClassesAndElements(): VariantObject { let PseudoClassesAndElementsRE: RegExp diff --git a/test/assets/output/preset-mini-targets.css b/test/assets/output/preset-mini-targets.css index 34ed91a770..4f215f0f76 100644 --- a/test/assets/output/preset-mini-targets.css +++ b/test/assets/output/preset-mini-targets.css @@ -798,6 +798,7 @@ unocss .scope-\[unocss\]\:block{display:block;} .outline-revert-layer{outline-style:revert-layer;} .outline-unset{outline-style:unset;} .outline-none{outline:2px solid transparent;outline-offset:2px;} +.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px;} .appearance-none{-webkit-appearance:none;appearance:none;} .order-\$variable{order:var(--variable);} .order-first{order:-9999;} diff --git a/test/assets/preset-mini-targets.ts b/test/assets/preset-mini-targets.ts index 67011863f4..2b98341430 100644 --- a/test/assets/preset-mini-targets.ts +++ b/test/assets/preset-mini-targets.ts @@ -935,6 +935,7 @@ export const presetMiniTargets: string[] = [ 'first-line:bg-green-400', 'first-letter:bg-green-400', 'group-hover:group-focus:text-center', + 'focus-visible:outline-none', 'hover:!p-1', 'hover:not-first:checked:bg-red/10', 'hover:p-5',