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

Allow sorting of custom attributes, functions, and tagged template literals #155

Merged
merged 25 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added support for `prettier-plugin-marko` ([#151](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/151))
- Allow sorting of custom attributes, functions, and tagged template literals ([#155](https://github.com/tailwindlabs/prettier-plugin-tailwindcss/pull/155))

### Fixed

Expand Down
93 changes: 91 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ module.exports = {
}
```

## Resolving your Tailwind configuration
## Options

To ensure that the class sorting is taking into consideration any of your project's Tailwind customizations, it needs access to your [Tailwind configuration file](https://tailwindcss.com/docs/configuration) (`tailwind.config.js`).
### Customizing your Tailwind config path

To ensure that the class sorting takes into consideration any of your project's Tailwind customizations, it needs access to your [Tailwind configuration file](https://tailwindcss.com/docs/configuration) (`tailwind.config.js`).

By default the plugin will look for this file in the same directory as your Prettier configuration file. However, if your Tailwind configuration is somewhere else, you can specify this using the `tailwindConfig` option in your Prettier configuration.

Expand All @@ -38,6 +40,93 @@ module.exports = {

If a local configuration file cannot be found the plugin will fallback to the default Tailwind configuration.

## Sorting non-standard attributes

By default this plugin only sorts classes in the `class` attribute as well as any framework-specific equivalents like `class`, `className`, `:class`, `[ngClass]`, etc.

You can sort additional attributes using the `tailwindAttributes` option, which takes an array of attribute names:

```js
// prettier.config.js
module.exports = {
tailwindAttributes: ['myClassList'],
}
```

With this configuration, any classes found in the `myClassList` attribute will be sorted:

```jsx
function MyButton({ children }) {
return (
<button myClassList="rounded bg-blue-500 px-4 py-2 text-base text-white">
{children}
</button>
);
}
```

## Sorting classes in function calls

In addition to sorting classes in attributes, you can also sort classes in strings provided to function calls. This is useful when working with libraries like [clsx](https://github.com/lukeed/clsx) or [cva](https://cva.style/).

You can sort classes in function calls using the `tailwindFunctions` option, which takes a list of function names:

```js
// prettier.config.js
module.exports = {
tailwindFunctions: ['clsx'],
}
```

With this configuration, any classes in `clsx()` function calls will be sorted:

```jsx
import clsx from 'clsx'

function MyButton({ isHovering, children }) {
let classes = clsx(
'rounded bg-blue-500 px-4 py-2 text-base text-white',
{
'bg-blue-700 text-gray-100': isHovering,
},
)

return (
<button className={classes}>
{children}
</button>
)
}
```

## Sorting classes in template literals

This plugin also enables sorting of classes in tagged template literals.

You can sort classes in template literals using the `tailwindFunctions` option, which takes a list of function names:

```js
// prettier.config.js
module.exports = {
tailwindFunctions: ['tw'],
}
```

With this configuration, any classes in template literals tagged with `tw` will automatically be sorted:

```jsx
import { View, Text } from 'react-native'
import tw from 'twrnc'

function MyScreen() {
return (
<View style={tw`bg-white p-4 dark:bg-black`}>
<Text style={tw`text-md text-black dark:text-white`}>Hello World</Text>
</View>
)
}
```

## Compatibility with other Prettier plugins

This plugin uses Prettier APIs that can only be used by one plugin at a time, making it incompatible with other Prettier plugins implemented the same way. To solve this we've added explicit per-plugin workarounds that enable compatibility with the following Prettier plugins:
Expand Down
3 changes: 3 additions & 0 deletions prettier.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ module.exports = {
semi: false,
singleQuote: true,
trailingComma: 'all',
pluginSearchDirs: false,
plugins: ['@ianvs/prettier-plugin-sort-imports'],
importOrder: ['^@', '^[a-zA-Z0-9-]+', '^[./]'],
}
14 changes: 2 additions & 12 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,8 @@ import { createContext as createContextFallback } from 'tailwindcss/lib/lib/setu
import loadConfigFallback from 'tailwindcss/loadConfig'
import resolveConfigFallback from 'tailwindcss/resolveConfig'

/**
* @typedef {object} ContextContainer
* @property {any} context
* @property {() => any} generateRules
* @property {any} tailwindConfig
**/

/**
* @typedef {object} PluginOptions
* @property {string} [tailwindConfig]
* @property {string} filepath
**/
/** @typedef {import('./types').ContextContainer} ContextContainer **/
/** @typedef {import('./types').PluginOptions} PluginOptions **/

/**
* @template K
Expand Down