@@ -29,6 +29,43 @@ import * as ValueParser from './value-parser'
2929const IS_VALID_STATIC_UTILITY_NAME = / ^ - ? [ a - z ] [ a - z A - Z 0 - 9 / % . _ - ] * $ /
3030const IS_VALID_FUNCTIONAL_UTILITY_NAME = / ^ - ? [ a - z ] [ a - z A - Z 0 - 9 / % . _ - ] * - \* $ /
3131
32+ const DEFAULT_SPACING_SUGGESTIONS = [
33+ '0' ,
34+ '0.5' ,
35+ '1' ,
36+ '1.5' ,
37+ '2' ,
38+ '2.5' ,
39+ '3' ,
40+ '3.5' ,
41+ '4' ,
42+ '5' ,
43+ '6' ,
44+ '7' ,
45+ '8' ,
46+ '9' ,
47+ '10' ,
48+ '11' ,
49+ '12' ,
50+ '14' ,
51+ '16' ,
52+ '20' ,
53+ '24' ,
54+ '28' ,
55+ '32' ,
56+ '36' ,
57+ '40' ,
58+ '44' ,
59+ '48' ,
60+ '52' ,
61+ '56' ,
62+ '60' ,
63+ '64' ,
64+ '72' ,
65+ '80' ,
66+ '96' ,
67+ ]
68+
3269type CompileFn < T extends Candidate [ 'kind' ] > = (
3370 value : Extract < Candidate , { kind : T } > ,
3471) => AstNode [ ] | undefined | null
@@ -476,44 +513,7 @@ export function createUtilities(theme: Theme) {
476513
477514 suggest ( name , ( ) => [
478515 {
479- values : theme . get ( [ '--spacing' ] )
480- ? [
481- '0' ,
482- '0.5' ,
483- '1' ,
484- '1.5' ,
485- '2' ,
486- '2.5' ,
487- '3' ,
488- '3.5' ,
489- '4' ,
490- '5' ,
491- '6' ,
492- '7' ,
493- '8' ,
494- '9' ,
495- '10' ,
496- '11' ,
497- '12' ,
498- '14' ,
499- '16' ,
500- '20' ,
501- '24' ,
502- '28' ,
503- '32' ,
504- '36' ,
505- '40' ,
506- '44' ,
507- '48' ,
508- '52' ,
509- '56' ,
510- '60' ,
511- '64' ,
512- '72' ,
513- '80' ,
514- '96' ,
515- ]
516- : [ ] ,
516+ values : theme . get ( [ '--spacing' ] ) ? DEFAULT_SPACING_SUGGESTIONS : [ ] ,
517517 supportsNegative,
518518 supportsFractions,
519519 valueThemeKeys : themeKeys ,
@@ -4731,11 +4731,20 @@ export function createCssUtility(node: AtRule) {
47314731 // If you then use `foo-1/2`, this is invalid, because the modifier is not used.
47324732
47334733 return ( designSystem : DesignSystem ) => {
4734- let valueThemeKeys = new Set < `--${string } `> ( )
4735- let valueLiterals = new Set < string > ( )
4736-
4737- let modifierThemeKeys = new Set < `--${string } `> ( )
4738- let modifierLiterals = new Set < string > ( )
4734+ let storage = {
4735+ '--value' : {
4736+ usedSpacingInteger : false ,
4737+ usedSpacingNumber : false ,
4738+ themeKeys : new Set < `--${string } `> ( ) ,
4739+ literals : new Set < string > ( ) ,
4740+ } ,
4741+ '--modifier' : {
4742+ usedSpacingInteger : false ,
4743+ usedSpacingNumber : false ,
4744+ themeKeys : new Set < `--${string } `> ( ) ,
4745+ literals : new Set < string > ( ) ,
4746+ } ,
4747+ }
47394748
47404749 // Pre-process the AST to make it easier to work with.
47414750 //
@@ -4762,6 +4771,41 @@ export function createCssUtility(node: AtRule) {
47624771 // `\\*` or not inserting whitespace) then most of these can go away.
47634772 ValueParser . walk ( declarationValueAst , ( fn ) => {
47644773 if ( fn . kind !== 'function' ) return
4774+
4775+ // Track usage of `--spacing(…)`
4776+ if (
4777+ fn . value === '--spacing' &&
4778+ // Quick bail check if we already know that `--value` and `--modifier` are
4779+ // using the full `--spacing` theme scale.
4780+ ! ( storage [ '--modifier' ] . usedSpacingNumber && storage [ '--value' ] . usedSpacingNumber )
4781+ ) {
4782+ ValueParser . walk ( fn . nodes , ( node ) => {
4783+ if ( node . kind !== 'function' ) return
4784+ if ( node . value !== '--value' && node . value !== '--modifier' ) return
4785+ const key = node . value
4786+
4787+ for ( let arg of node . nodes ) {
4788+ if ( arg . kind !== 'word' ) continue
4789+
4790+ if ( arg . value === 'integer' ) {
4791+ storage [ key ] . usedSpacingInteger ||= true
4792+ } else if ( arg . value === 'number' ) {
4793+ storage [ key ] . usedSpacingNumber ||= true
4794+
4795+ // Once both `--value` and `--modifier` are using the full
4796+ // `number` spacing scale, then there's no need to continue
4797+ if (
4798+ storage [ '--modifier' ] . usedSpacingNumber &&
4799+ storage [ '--value' ] . usedSpacingNumber
4800+ ) {
4801+ return ValueParser . ValueWalkAction . Stop
4802+ }
4803+ }
4804+ }
4805+ } )
4806+ return ValueParser . ValueWalkAction . Continue
4807+ }
4808+
47654809 if ( fn . value !== '--value' && fn . value !== '--modifier' ) return
47664810
47674811 let args = segment ( ValueParser . toCss ( fn . nodes ) , ',' )
@@ -4796,23 +4840,13 @@ export function createCssUtility(node: AtRule) {
47964840 node . value [ 0 ] === node . value [ node . value . length - 1 ]
47974841 ) {
47984842 let value = node . value . slice ( 1 , - 1 )
4799-
4800- if ( fn . value === '--value' ) {
4801- valueLiterals . add ( value )
4802- } else if ( fn . value === '--modifier' ) {
4803- modifierLiterals . add ( value )
4804- }
4843+ storage [ fn . value ] . literals . add ( value )
48054844 }
48064845
48074846 // Track theme keys
48084847 else if ( node . kind === 'word' && node . value [ 0 ] === '-' && node . value [ 1 ] === '-' ) {
48094848 let value = node . value . replace ( / - \* .* $ / g, '' ) as `--${string } `
4810-
4811- if ( fn . value === '--value' ) {
4812- valueThemeKeys . add ( value )
4813- } else if ( fn . value === '--modifier' ) {
4814- modifierThemeKeys . add ( value )
4815- }
4849+ storage [ fn . value ] . themeKeys . add ( value )
48164850 }
48174851 }
48184852 } )
@@ -4949,20 +4983,33 @@ export function createCssUtility(node: AtRule) {
49494983 } )
49504984
49514985 designSystem . utilities . suggest ( name . slice ( 0 , - 2 ) , ( ) => {
4952- let values = [ ]
4953- for ( let value of valueLiterals ) {
4954- values . push ( value )
4955- }
4956- for ( let value of designSystem . theme . keysInNamespaces ( valueThemeKeys ) ) {
4957- values . push ( value )
4958- }
4986+ let values : string [ ] = [ ]
4987+ let modifiers : string [ ] = [ ]
4988+
4989+ for ( let [ target , { literals, usedSpacingNumber, usedSpacingInteger, themeKeys } ] of [
4990+ [ values , storage [ '--value' ] ] ,
4991+ [ modifiers , storage [ '--modifier' ] ] ,
4992+ ] as const ) {
4993+ // Suggest literal values. E.g.: `--value('literal')`
4994+ for ( let value of literals ) {
4995+ target . push ( value )
4996+ }
49594997
4960- let modifiers = [ ]
4961- for ( let modifier of modifierLiterals ) {
4962- modifiers . push ( modifier )
4963- }
4964- for ( let value of designSystem . theme . keysInNamespaces ( modifierThemeKeys ) ) {
4965- modifiers . push ( value )
4998+ // Suggest `--spacing(…)` values. E.g.: `--spacing(--value(integer))`
4999+ if ( usedSpacingNumber ) {
5000+ target . push ( ...DEFAULT_SPACING_SUGGESTIONS )
5001+ } else if ( usedSpacingInteger ) {
5002+ for ( let value of DEFAULT_SPACING_SUGGESTIONS ) {
5003+ if ( isPositiveInteger ( value ) ) {
5004+ target . push ( value )
5005+ }
5006+ }
5007+ }
5008+
5009+ // Suggest theme values. E.g.: `--value(--color-*)`
5010+ for ( let value of designSystem . theme . keysInNamespaces ( themeKeys ) ) {
5011+ target . push ( value )
5012+ }
49665013 }
49675014
49685015 return [ { values, modifiers } ] satisfies SuggestionGroup [ ]
0 commit comments