* ensure we normalize the arbitrary modifiers
This applies the same rules as arbitrary values. The `_` can be used in
place of a space. If you _do_ want an underscore, you can escape it with
`\_` (`\\_` in JavaScript).
* update changelog
* disable color opacity plugins by default for the `oxide` engine
* update tests to reflect this change in the `oxide` engine
* update changelog
* reflect changes in integration tests
* Revert "add caption-side utilities (#10470)"
This reverts commit f395cc4ae5c90eab90a722f42c7fda6ba8ece94e.
* Revert "Add support for configuring default `font-variation-settings` for a `font-family` (#10515)"
This reverts commit 8bd2846b5b906904a49e9ffec9c317e560f2eaa6.
* Revert "feat: add hyphens (#10071)"
This reverts commit f58a43fd75e8344b4c2cd0d34fa7b563b1f3ef3a.
* Revert "Add logical properties support for inline direction"
* Revert "Add `delay-0` and `duration-0` by default"
* Revert "Support using variables as arbitrary values without `var()`"
* Revert "Add `line-height` modifier support to `font-size` utilities"
* drop empty lines when diffing output
* replace expected css with optimized lightningcss output
Lightning CSS generates a more optimal CSS output.
Right now the tests are setup in a way that both the generated css and
expected css are run through `lightningcss` to make sure that the output
is concistent for the `stable` and `oxide` engines. But this also means
that the expected output _could_ be larger (aka not optimized) and still
matches (after it runs through lightningcss).
By replacing this with the more optimal output we achieve a few things:
1. This better reflects reality since we will be using `lightningcss`.
2. This gets rid of unnecessary css.
3. Removed code!
* Run test suite against both engines
* make eslint happy
* only run `stable` tests on Node 12
* use normal expectation instead of snapshot file
When we run the tests only against `stable` (for node 12), then the
snapshots exists for the `Oxide` build. They are marked as `obsolete`
and will cause the `npm run test` script to fail. Sadly.
Inlined them for now, but ideally we make those tests more blackbox-y so
that we test that we get source maps and that we can map the sourcemap
back to the input files (without looking at the actual annotations).
* properly indent inline css
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
* ensure we use `npm@7` for older versions of Node.js
This is important so that we can guarantee that `workspaces` are
supported which we depend on right now (just for install purposes).
* tmp: trigger CI build (GitHub is doing funky things and not working right now)
* drop Node.js 12 from Node.js CI workflow
* focus on Node.js 16 for now
* Revert "tmp: trigger CI build (GitHub is doing funky things and not working right now)"
This reverts commit a3deed472da498f8a52404b2e8ccbc16f0e93101.
* WIP
* Add support for logical properties in inline direction
* Add scroll-margin/scroll-padding utilities
* Update CHANGELOG
* Rename inset-s/e to start/end
* Update sort order in test
* Use logical properties for space/divide in Oxide
* run non-oxide and OXIDE tests
+ fix oxide version tests
* drop oxide specific test job
The normal `npm run test` will already include the non-oxide and oxide
version when running tests.
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
* temporarily disable workflows
* add oxide
Our Rust related parts
* use oxide
- Setup the codebase to be able to use the Rust parts based on an
environment variable: `OXIDE=1`.
- Setup some tests that run both the non-Rust and Rust version in the
same test.
- Sort the candidates in a consistent way, to guarantee the order for
now (especially in tests).
- Reflect sorting related changes in tests.
- Ensure tests run in both the Rust and non-Rust version. (Some tests
are explicitly skipped when using the Rust version since we haven't
implemented those features yet. These include: custom prefix,
transformers and extractors).
- `jest`
-`OXIDE=1 jest`
* remove into_par_iter where it doesn't make sense
* cargo fmt
* wip
* enable tracing based on `DEBUG` env
* improve CI for the Oxide build
* sort test output
This happened because the sorting happens in this branch, but changes
happened on the `master` branch.
* add failing tests
I noticed that some of the tests were failing, and while looking at
them, it happened because the tests were structured like this:
```html
<div
class="
backdrop-filter
backdrop-filter-none
backdrop-blur-lg
backdrop-brightness-50
backdrop-contrast-0
backdrop-grayscale
backdrop-hue-rotate-90
backdrop-invert
backdrop-opacity-75
backdrop-saturate-150
backdrop-sepia
"
></div>
```
This means that the class names themselves eventually end up like this: `backdrop-filter-none\n`
-> (Notice the `\n`)
/cc @thecrypticace
* fix range to include `\n`
* Include only unique values for tests
Really, what we care about most is that the list contains every expected candidate. Not necessarily how many times it shows up because while many candidates will show up A LOT in a source text we’ll unique them before passing them back to anything that needs them
* Fix failing tests
* Don’t match empty arbitrary values
* skip tests in oxide mode regarding custom separators in arbitrary variants
* re-enable workflows
* use `@tailwindcss/oxide` dependency
* publish `tailwindcss@oxide`
* drop prepublishOnly
I don't think we actually need this anymore (or even want because this
is trying to do things in CI that we don't want to happen. Aka, build
the Oxide Rust code, it is already a dependency).
* WIP
* Defer to existing CLI for Oxide
* Include new compiled typescript stuff when publishing
* Move TS to ./src/oxide
* Update scripts
* Clean up tests for TS
* copy `cli` to `oxide/cli`
* make CLI files TypeScript files
* drop --postcss flag
* setup lightningcss
* Remove autoprefixer and cssnano from oxide CLI
* cleanup Rust code a little bit
- Drop commented out code
- Drop 500 fixture templates
* sort test output
* re-add `prepublishOnly` script
* bump SWC dependencies in package-lock.json
* pin `@swc` dependencies
* ensure to install and build oxide
* update all GitHub Workflows to reflect Oxide required changes
* sort `content-resolution` integration tests
* add `Release Insiders — Oxide`
* setup turbo repo + remote caching
* use `npx` to invoke `turbo`
* setup unique/proper package names for integration tests
* add missing `isomorphic-fetch` dependency
* setup integration tests to use `turborepo`
* scope tailwind tasks to root workspace
* re-enable `node_modules` cache for integration tests
* re-enable `node_modules` cache for main CI workflow
* split cache for `main` and `oxide` node_modules
* fix indent
* split install dependencies so that they can be cached individually
* improve GitHub actions caching
* use correct path for oxide node_modules (crates/node)
* ensure that `cargo install` always succeeds
cargo install X, on CI will fail if it already exists.
* figure out integration tests with turbo
* tmp: use `npm` instead of `turbo`
* disable `fail-fast`
This will allow us to run integration tests so that it still caches the
succesful ones.
* YAML OH YAML, Y U WHITESPACE SENSITIVE
* copy the oxide-ci workflow to release-oxide
* make `oxide-ci` a normal CI workflow
Without publishing
* try to cache cargo and node_modules for the oxide build
* configure turbo to run scripts in the root
* explicitly skip failing test for the Oxide version
* run oxide tests in CI
* only use build script for root package
* sync package-lock.json
* do not cache node_modules for each individual integration
* look for hoisted `.bin`
* use turbo for caching build tailwind css in integration tests
* Robin...
* try to use the local binary first
* skip installing integration test dependencies
Should already be installed due to workspace usage
* Robin...
* drop `output.clean`
* explicitly add `mini-css-extract-plugin`
* drop oxide-ci, this is tested by proxy
* ensure oxide build is used in integration tests
This will ensure the `@tailwindcss/oxide` dependency is available
(whether we use it or not).
* setup Oxide shim in insiders release
* add browserslist dependency
* use `install:all` script name
Just using `install` as a script name will be called when running
`npm install`.
Now that we marked the repo as a `workspace`, `npm install` will run
install in all workspaces which is... not ideal.
* tmp: enable insiders release in PRs
Just to check if everything works before merging. Can be removed once
tested.
* don't cache node_modules?
I feel there is some catch 22 going on here.
We require `npm install` to build the `oxide/crates/node` version.
But we also require `oxide/crates/node` for the `npm install` becaus of
the dependency: `"@tailwindcss/oxide": "file:oxide/creates/node"`
* try to use `oxide/crates/node` as part of the workspace
* let's think about this
Let's try and cache the `node_modules` and share as much as possible.
However, some scripts still need to be installed specific to the OS.
Running `npm install` locally doesn't throw away your `node_modules`,
so if we just cache `node_modules` but also run `npm install` that
should keep as much as possible and still improve install times since
`node_modules` is already there.
I think.
* ensure generated `index.js` and `index.d.ts` files are considered outputs
* use `npx napi` instead of `napi` directly
* include all `package-lock.json` files
* normalize caching further in all workflows
* drop nested `package-lock.json` files
* `npm uninstall mini-css-extract-plugin && npm install mini-css-extract-plugin --save-dev`
* bump webpack-5 integration tests dependencies
* only release insiders on `master` branch
* tmp: let's figure out release insiders oxide
* fix little typo
* use Node 18 for Oxide Insiders
* syncup package-lock.json
* let's try node 16
Node 18 currently fails on `Build x86_64-unknown-linux-gnu (OXIDE)`
Workflow.
Install Node.JS output:
```
Environment details
Warning: /__t/node/18.13.0/x64/bin/node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /__t/node/18.13.0/x64/bin/node)
Warning: node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
```
* bump some Node versions
* only release oxide insiders on `master` branch
* don't cache `npm`
* bump napi-rs
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
* Support using variables as arbitrary values without var()
* Update changelog
* Add tests for variable fallback values
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
* Improve type checking for formal syntax
* Add test
* Change order of test class name
* fix failing tests
* prefer `position` over `size` for backwards compatibility reasons
Previously `bg-[10px_10%]` generated `background-position: 10px 10%` before we introduced the fallback plugins.
Therefore we should prefer `position` over `size` as the default for backwards compatibility.
* update changelog
* ensure correct order
Thanks Prettier!
* update changelog
Co-authored-by: lzt1008 <lzt1008@live.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: liangzhengtai <liangzhengtai_i@didiglobal.com>
* use test with non-any type plugin
* choose backgroundSize over backgroundPosition
Ensure that `backgroundColor` can take any value
* add tests to verify fallback plugins
* implement fallback plugins
Whenever an arbitrary value results in css from multiple plugins we
first try to resolve a falback plugin.
The fallback mechanism works like this:
- If A has type `any` and B has type `color`, then B should win.
> This is because `A` will match *anything*, but the more precise type
should win instead. E.g.: `backgroundColor` has the type `any` so
`bg-[100px_200px]` would match both the `backgroundColor` and
`backgroundSize` but `backgroundSize` matched because of a specific
type and not because of the `any` type.
- If A has type `length` and B has type `[length, { disambiguate: true }]`, then B should win.
> This is because `B` marked the `length` as the plugin that should
win in case a clash happens.
* Add any type to a handful of plugins
Needs tests tho
* Add any type to `border-{x,y,t,r,b,l}` plugins
* Add test for any type
* Split on multiple lines
* fixup
* add tests for implicit `any` types
* rename `disambiguate` to `preferOnConflict`
* update tests to reflect `any` types a bit better
* update changelog
* annotate any-type test with a bit more information
Just for future debugging reasons!
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
* ensure the `percentage` data type is validated correctly
When checking for our data types, we have to make sure that each part is
correct, this wasn't happening for the `percentage` data type, which
meant that `top_right_50%` was a valid percentage value because it ended
in `%` which is not correct.
Because of this, the generated code was non-existent because we got a
warning:
The class `bg-[top_right_50%]` is ambiguous and matches multiple utilities.
Use `bg-[length:top_right_50%]` for `background-size: top right 50%`
Use `bg-[position:top_right_50%]` for `background-position: top right 50%`
If this is content and not a class, replace it with `bg-[top_right_50%]` to silence this warning.
But this is not correct because this can never be a valid background
size due to the `top right` section.
This fixes it by validating each part individually, and now we get
generated css.
* update changelog
* add prettier-plugin-tailwindcss
This will use the prettier plugin in our tests as well, yay consistency!
* ensure that both `group` and `peer` can't be used in `@apply`
This was only configured for `group`
* expose `sortClassList` on the context
This function will be used by the `prettier-plugin-tailwindcss` plugin,
this way the sorting happens within Tailwind CSS itself adn the
`prettier-plugin-tailwindcss` plugin doesn't have to use internal /
private APIs.
The signature looks like this:
```ts
function sortClassList(classes: string[]): string[]
```
E.g.:
```js
let sortedClasses = context.sortClassList(['p-1', 'm-1', 'container'])
```
* update changelog
* add sort test for utilities with the important modifier e.g.: `!p-4`
* remove `any` data type for decoration color plugin
The main reason for the `any` type is so that we don't have to parse the
value and can assume that this plugin handles "any" value you give it.
This is useful because `decoration-[var(--something)]` would be
correctly translated to the correct decoration property. However, we
introduce another plugin with the same `decoration` prefix.
This means that now both `textDecorationColor` and
`textDecorationThickness` have the same base utility name: `decoration`.
- `textDecorationColor` had ['color', 'any']
- `textDecorationThickness` had ['length', 'percentage']
This means that `3px` fit both in the `length` data type of the
`textDecorationThickness` plugin and in the `any` data type of the
`textDecorationColor` plugin.
Removing the `any` fixes this.
TL;DR: Only have `any` when there are no conflicting utility names.
* remove utility that doesn't generate css
Having `decoration-[var(--abc)]` is ambiguous because there are multiple
plugins that have a `decoration` utility name. In order for this to work
you have to prefix it with the type: `decoration-[color:var(--abc)]`
which is already tested in this file.
* fix modifiers for arbitrary properties
The main issue was that we are splitting on the separator and popping
the last section of to know the _base_ utility. However, in this case it
would be something like `markers]` which is incorrect.
Instead we only split by the separator and ignore the separtor if it
exists between square brackets.
* add tests for modifiers + arbitrary values that contain the separator
* remove unused `withRule`
* ensure all ::before and ::after elements have content
* update --tw-content for the content plugin
* simplify `before` and `after` variants
* update tests, to reflect changes
* make new `format` and `wrap` API's private for now
* allow returning a format string from `addVariant` callback
* add `content: var(--tw-content)` for before/after variants
* update tests to add `content: var(--tw-content)`
* update changelog
* use String.raw for css escapes
This will allow us to write code like:
```css
.mobile\:font-bold {}
```
Instead of
```css
.mobile\\:font-bold {}
```
Which resembles "real" css way better in our tests.
* use String.raw in integration tests as well
* fix incorrect comment
Probably messed this up in another PR, so just a bit of cleaning.
* implement a formatVariantSelector function
This will be used to eventually simplify the addVariant API.
The idea is that it can take a list of strings that define a certain
format. Then it squashes everything to a single format how you would
expect it.
E.g.:
Input:
- '&:hover'
- '&:focus'
- '.dark &'
- ':merge(.group):hover &'
- ':merge(.group):focus &'
Output:
- ':merge(.group):focus:hover .dark &:focus:hover'
The API here is:
- `&`, this means "The parent" or "The previous selector" (you can
think of it like if you are using nested selectors)
- `:merge(.group)`, this means insert a `.group` if it doesn't exist
yet, but if it does exist already, then merge the new value with the
old value. This allows us to merge group-focus, group-hover into a
single `.group:focus:hover ...`
* add new `format`, `withRule` and `wrap` API for addVariant
* implement backwards compatibility
This will ensure that the backwards compatibility for `modifySelectors`
and direct mutations to the `container` will still work.
We will try to capture the changes made to the `rule.selector`, we will
also "backup" the existing selector. This allows us to diff the old and
new selectors and determine what actually happened.
Once we know this, we can restore the selector to the "old" selector and
add the diffed string e.g.: `.foo &`, to the `collectedFormats` as if
you called `format()` directly. This is a bunch of extra work, but it
allows us to be backwards compatible.
In the future we could also warn if you are using `modifySelectors`, but
it is going to be a little bit tricky, because usually that's
implemented by plugin authors and therefore you don't have direct
control over this. Maybe we can figure out the plugin this is used in
and change the warning somehow?
* fix incorrect test
This was clearly a bug, keyframes should not include escaped variants at
all. The reason this is here in the first place is because the nodes in
a keyframe are also "rule" nodes.
* swap the order of pseudo states
The current implementation had a strange side effect, that resulted in
incorrect class definitions. When you are combining the `:hover` and
`:focus` event, then there is no difference between `:hover:focus` and
`:focus:hover`.
However, when you use `:hover::file-selector-button` or `::file-selector-button:hover`,
then there is a big difference. In the first place, you can hover over the full file input
to apply changes to the `File selector button`.
In the second scenario you have to hover over the `File selector button` itself to apply changes.
You can think of it as function calls:
- focus(hover(text-center))
What you would expect is something like this:
`.focus\:hover\:text-center:hover:focus`, where `hover` is on the
inside, and `focus` is on the outside. However in the current
implementation this is implemented as
`.focus\:hover\:text-cener:focus:hover`
* add more variant tests for the new API
* update parallel variants tests to make use of new API
* implement core variants with new API
* simplify/cleanup existing plugin utils
We can get rid of this because we drastically simplified the new
addVariant API.
* add addVariant shorthand signature
The current API looks like this:
```js
addVariant('name', ({ format, wrap }) => {
// Wrap in an atRule
wrap(postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: reduce)' }))
// "Mutate" the selector, for example prepend `.dark`
format('.dark &')
})
```
It is also pretty common to have this:
```js
addVariant('name', ({ format }) => format('.dark &'))
```
So we simplified this to:
```js
addVariant('name', '.dark &')
```
It is also pretty common to have this:
```js
addVariant('name', ({ wrap }) => wrap(postcss.atRule({ name: 'media', params: '(prefers-reduced-motion: reduce)' })))
```
So we simplified this to:
```js
addVariant('name', '@media (prefers-reduced-motion: reduce)')
```
* improve fontVariantNumeric implementation
We will use `@defaults`, so that only the resets are injected for the
utilities we actually use.
* fix typo
* allow for nested addVariant shorthand
This will allow to write something like:
```js
addVariant('name', `
@supports (hover: hover) {
@media (print) {
&:hover
}
}
`)
// Or as a one-liner
addVariant('name', '@supports (hover: hover) { @media (print) { &:hover } }')
```
* update changelog
* simplify `inset` plugin
* run `prettier` on stub file
* simplify `align` utility
* improve arbitrary support for outline
This will allow us to use `outline-[OUTLINE,OPTIONAL_OFFSET]`
Input:
```html
outline-[2px_solid_black]
```
Output:
```css
.outline-\[2px_solid_black\] {
outline: 2px solid black;
outline-offset: 0;
}
```
---
Input:
```html
outline-[2px_solid_black,2px]
```
Output:
```css
.outline-\[2px_solid_black\2c 2px\] {
outline: 2px solid black;
outline-offset: 2px;
}
```
* remove default `type`
* simplify createUtilityPlugin, use types directly
* find first matching type when coercing the value
* introduce css data types
Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
These data types will be used to "guess" the type of an arbitrary value
if there is some ambiguity going on. For example:
```
bg-[#0088cc] -> This is a `color` -> `background-color`
bg-[url('...')] -> This is a `url` -> `background-image`
```
If you are using css variables, then there is no way of knowing which
type it is referring to, in that case you can be explicit:
```
bg-[color:var(--value)] -> This is a `color` -> `background-color`
bg-[url:var(--value)] -> This is a `url` -> `background-image`
```
When you explicitly pass a data type, then we bypass the type system and
assume you are right. This is nice in a way because now we don't have to
run all of the guessing type code. On the other hand, you can introduce
runtime issues that we are not able to detect:
```
:root {
--value: 12px;
}
/* Later... */
bg-[color:var(--value)] -> Assumes `color` -> *eventually* -> `background-color: 12px`
```
* add a bunch of new tests for advanced arbitrary values
If you use a typehint like `w-[length:12px]`, then currently that
wouldn't generate anything because we don't have a matchUtilities for
`w` with a `length` type. To fix this, we can detect if this is
unnecessary, if it is we still generate the expected outcome. (In this
case `width: 12px`) but we also warn to the user that we detected this.
Currently we detect this by checking if there is only a single plugin
registered for handling the prefix (e.g.: `w-`). We can probably improve
this by also checking all the types that all plugins are handling for
the resolved plugins.
* refactor dropShadow plugin, use `matchUtilities`
* replace `_` with ` ` for arbitrary values
* remove custom `asList` function
* do not replace escaped underscores with spaces
* move `./tests/jit` to `./tests`
* make tests consistent
Abstracted a `run` function and some syntax highlighting helpers for
`html`, `css` and `javascript`.