Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functional utility syntax #15455

Open
wants to merge 9 commits into
base: next
Choose a base branch
from

Conversation

RobinMalfait
Copy link
Member

@RobinMalfait RobinMalfait commented Dec 19, 2024

This PR adds support for functional utilities constructed via CSS.

Registering functional utilities in CSS

To register a functional utility in CSS, use the @utility potato-* syntax, where the -* signals that this is a functional utility:

@utility tab-* {
  tab-size: value(--tab-size-*);
}

Resolving values

The special value(…) function is used to resolve the utility value.

Resolving against @theme values

To resolve the value against a set of theme keys, use value(--theme-key-*):

@theme {
  --tab-size-1: 1;
  --tab-size-2: 2;
  --tab-size-4: 4;
  --tab-size-github: 8;
}

@utility tab-* {
  /* tab-1, tab-2, tab-4, tab-github */
  tab-size: value(--tab-size-*);
}

Bare values

To resolve the value as a bare value, use value({type}), where {type} is the data type you want to validate the bare value as:

@utility tab-* {
  /* tab-1, tab-76, tab-971 */
  tab-size: value(integer);
}

Arbitrary values

To support arbitrary values, use value([{type}]) (notice the square brackets) to tell Tailwind which types are supported as an arbitrary value:

@utility tab-* {
  /* tab-[1], tab-[76], tab-[971] */
  tab-size: value([integer]);
}

Supporting theme values, bare values, and arbitrary values together

All three forms of the value(…) function can be used within a rule as multiple declarations, and any declarations that fail to resolve will be omitted in the output:

@theme {
  --tab-size-github: 8;
}

@utility tab-* {
  tab-size: value([integer]);
  tab-size: value(integer);
  tab-size: value(--tab-size-*);
}

This makes it possible to treat the value differently in each case if necessary, for example translating a bare integer to a percentage:

@utility opacity-* {
  opacity: value([percentage]);
  opacity: calc(value(integer) * 1%);
  opacity: value(--opacity-*);
}

The value(…) function can also take multiple arguments and resolve them left to right if you don't need to treat the return value differently in different cases:

@theme {
  --tab-size-github: 8;
}

@utility tab-* {
  tab-size: value(--tab-size-*, integer, [integer]);
}

@utility opacity-* {
  opacity: calc(value(integer) * 1%);
  opacity: value(--opacity-*, [percentage]);
}

Negative values

To support negative values, register separate positive and negative utilities into separate declarations:

@utility inset-* {
  inset: calc(var(--spacing) * value([percentage], [length]));
}

@utility -inset-* {
  inset: calc(var(--spacing) * value([percentage], [length]) * -1);
}

Modifiers

Modifiers are handled using the modifier(…) function which works exactly like the value(…) function but operates on a modifier if present:

@utility text-* {
  font-size: value(--font-size-*, [length]);
  line-height: modifier(--line-height-*, [length], [*]);
}

If a modifier isn't present, any declaration depending on a modifier is just not included in the output.

Fractions

To handle fractions, we rely on the CSS ratio data type. If this is used with value(…), it's a signal to Tailwind to treat the value + modifier as a single value:

/* The CSS `ratio` type is our signal to treat the value + modifier as a fraction */
@utility aspect-* {
  /* aspect-square, aspect-3/4, aspect-[7/9] */
  aspect-ratio: value(--aspect-ratio-*, ratio, [ratio]);
}

@RobinMalfait RobinMalfait marked this pull request as ready for review December 20, 2024 12:24
@RobinMalfait RobinMalfait requested a review from a team as a code owner December 20, 2024 12:25
@RobinMalfait RobinMalfait force-pushed the feat/functional-utility-syntax branch from bf7dc05 to 13e75f4 Compare December 20, 2024 14:23
@imjeehoo
Copy link

imjeehoo commented Dec 20, 2024

In Resolving against @theme values, is tab-3 valid by somehow inferring from tab-1 or is it typo of tab-4?

@thecrypticace
Copy link
Contributor

it was a typo — fixed.

- If you are using a bare value or modifier that is a number, then we
  make sure that it is a valid multiplier of `0.25`
- If you are using a bare value or modifier that is a percentage, then
  we make sure that it is a valid positive integer.
- If you are using a fraction, then we make sure that both the numerator
  and denominator are positive integers.
- If the bare value resolves to a non-ratio value, and if a modifier is
  used, then we need to make sure that the modifier resolves as well.
  E.g.: `example-1/2.3` this won't resolve to a `ratio` because the
  denominator is invalid. This will resolve to an `integer` or `number`
  for the value of `1`, but then we need to make sure that `2.3` is a
  valid modifier.
@RobinMalfait RobinMalfait force-pushed the feat/functional-utility-syntax branch from c91ccb7 to 4eba187 Compare December 22, 2024 23:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants