diff --git a/.gitignore b/.gitignore index 34c6b93..bfbeaa9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ node_modules dist yarn.lock package-lock.json +.idea +.yarn +.pnp* \ No newline at end of file diff --git a/README.md b/README.md index ad19156..4d7d9a0 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ -# @tailwindcss/container-queries +# Tailwind Container Queries 2D -A plugin for Tailwind CSS v3.2+ that provides utilities for container queries. +[![npm](https://img.shields.io/npm/v/tailwind-container-queries-2d.svg)](https://www.npmjs.com/package/tailwind-container-queries-2d) +[![npm](https://img.shields.io/npm/dt/tailwind-container-queries-2d.svg)](https://www.npmjs.com/package/tailwind-container-queries-2d) + +A plugin for Tailwind CSS v3.2+ that provides utilities for container queries both for width and height values. ## Installation Install the plugin from npm: ```sh -npm install @tailwindcss/container-queries +npm install tailwind-container-queries-2d ``` Then add the plugin to your `tailwind.config.js` file: @@ -19,7 +22,7 @@ module.exports = { // ... }, plugins: [ - require('@tailwindcss/container-queries'), + require('tailwind-container-queries-2d'), // ... ], } @@ -27,39 +30,59 @@ module.exports = { ## Usage -Start by marking an element as a container using the `@container` class, and then applying styles based on the size of that container using the container variants like `@md:`, `@lg:`, and `@xl:`: +Start by marking an element as a container using the `@container` class. You can now apply styles based on the container’s width or height using the new `@w-*` and `@h-*` modifiers, in addition to the width-based container breakpoints like `@md:`, `@lg:`, and `@xl:`. + +### Applying Width and Height Breakpoints + +With this version, you can target styles based on either the width or height of the container. Use `@w-*` for width-based breakpoints and `@h-*` for height-based breakpoints. This allows for more granular control over responsive design. + +#### Width-Based Breakpoints +For width-based styles, use the `@w-` prefix: ```html
-
- +
+
``` -By default we provide [container sizes](#configuration) from `@xs` (`20rem`) to `@7xl` (`80rem`). +#### Height-Based Breakpoints +For height-based styles, use the `@h-` prefix: + +```html +
+
+ +
+
+``` + +By default we provide [container sizes](#configuration) from `@5xs` (`4rem`) to `@7xl` (`80rem`). ### Named containers -You can optionally name containers using a `@container/{name}` class, and then include that name in the container variants using classes like `@lg/{name}:underline`: +You can optionally name containers using the `@container/{name}` class and use that name in container variants. With the new width- and height-based prefixes, you can specify named containers as well, such as `@w-lg/{name}` and `@h-lg/{name}`: ```html
-
- +
+ +
``` ### Arbitrary container sizes -In addition to using one of the [container sizes](#configuration) provided by default, you can also create one-off sizes using any arbitrary value: +In addition to using one of the [container sizes](#configuration) provided by default, you can also create one-off sizes using any arbitrary value for the container width or height: ```html
-
- +
+ +
``` @@ -79,7 +102,7 @@ If you have configured Tailwind to use a prefix, make sure to prefix both the `@ ```html
-
+
@@ -90,7 +113,11 @@ If you have configured Tailwind to use a prefix, make sure to prefix both the `@ By default we ship with the following configured values: | Name | CSS | -| ------ | -------------------------------------------- | +| ------ |----------------------------------------------| +| `@5xs` | `@container (min-width: 4rem /* 64px */)` | +| `@4xs` | `@container (min-width: 8rem /* 128px */)` | +| `@3xs` | `@container (min-width: 12rem /* 192px */)` | +| `@2xs` | `@container (min-width: 16rem /* 256px */)` | | `@xs` | `@container (min-width: 20rem /* 320px */)` | | `@sm` | `@container (min-width: 24rem /* 384px */)` | | `@md` | `@container (min-width: 28rem /* 448px */)` | @@ -111,9 +138,16 @@ module.exports = { theme: { extend: { containers: { - '2xs': '16rem', + '8xl': '88rem', }, }, }, } ``` + +## Credits + +This plugin is based on the original work in [tailwindcss/container-queries](https://github.com/tailwindlabs/tailwindcss-container-queries) by [Tailwind Labs](https://github.com/tailwindlabs). + +Special thanks to [@kieranm](https://github.com/kieranm) for the [initial PR](https://github.com/tailwindlabs/tailwindcss-container-queries/pull/7) that inspired height-based queries. + diff --git a/package.json b/package.json index 4d103fb..8571a10 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,34 @@ { - "name": "@tailwindcss/container-queries", - "version": "0.1.1", + "name": "tailwind-container-queries-2d", + "version": "1.0.5", "main": "dist/index.js", "types": "dist/index.d.ts", "license": "MIT", - "repository": "https://github.com/tailwindlabs/tailwindcss-container-queries", + "author": "Alexandre Brajeux", + "description": "Tailwind CSS plugin to enable tailwind container queries for both width and height", + "keywords": [ + "tailwindcss", + "tailwind", + "css", + "container-queries", + "container", + "queries", + "2d", + "width", + "height", + "responsive" + ], + "contributors": [ + { + "name": "Kieran McHugh", + "url": "https://github.com/kieranm" + }, + { + "name": "Alexandre Brajeux", + "url": "https://https://github.com/abrajeux" + } + ], + "repository": "https://github.com/abrajeux/tailwindcss-container-queries-2d", "publishConfig": { "access": "public" }, diff --git a/src/index.ts b/src/index.ts index 84b9869..390b5ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,73 +1,84 @@ import plugin from 'tailwindcss/plugin' -export = plugin( +export default plugin( function containerQueries({ matchUtilities, matchVariant, theme }) { - let values: Record = theme('containers') ?? {} + const values: Record = theme('containers') ?? {} function parseValue(value: string) { - let numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null + const numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null if (numericValue === null) return null return parseFloat(value) } + const cbFor = + (selector: string) => + (value = '', extra: { modifier: string | null }) => { + const parsed = parseValue(value) + + return parsed !== null ? `@container ${extra.modifier ?? ''} (${selector}: ${value})` : [] + } + + const options = { + values, + sort( + aVariant: { value: string; modifier: string | null }, + zVariant: { value: string; modifier: string | null } + ) { + const a = parseFloat(aVariant.value) + const z = parseFloat(zVariant.value) + + if (a === null || z === null) return 0 + + // Sort values themselves regardless of unit + if (a - z !== 0) return a - z + + const aLabel = aVariant.modifier ?? '' + const zLabel = zVariant.modifier ?? '' + + // Explicitly move empty labels to the end + if (aLabel === '' && zLabel !== '') { + return 1 + } else if (aLabel !== '' && zLabel === '') { + return -1 + } + + // Sort labels alphabetically in the English locale + // We are intentionally overriding the locale because we do not want the sort to + // be affected by the machine's locale (be it a developer or CI environment) + return aLabel.localeCompare(zLabel, 'en', { numeric: true }) + } + } + matchUtilities( { '@container': (value, { modifier }) => { return { 'container-type': value, - 'container-name': modifier, + 'container-name': modifier } - }, + } }, { values: { - DEFAULT: 'inline-size', - normal: 'normal', + DEFAULT: 'size', + 'inline-size': 'inline-size', + normal: 'normal' }, - modifiers: 'any', + modifiers: 'any' } ) - matchVariant( - '@', - (value = '', { modifier }) => { - let parsed = parseValue(value) - - return parsed !== null ? `@container ${modifier ?? ''} (min-width: ${value})` : [] - }, - { - values, - sort(aVariant, zVariant) { - let a = parseFloat(aVariant.value) - let z = parseFloat(zVariant.value) - - if (a === null || z === null) return 0 - - // Sort values themselves regardless of unit - if (a - z !== 0) return a - z - - let aLabel = aVariant.modifier ?? '' - let zLabel = zVariant.modifier ?? '' - - // Explicitly move empty labels to the end - if (aLabel === '' && zLabel !== '') { - return 1 - } else if (aLabel !== '' && zLabel === '') { - return -1 - } - - // Sort labels alphabetically in the English locale - // We are intentionally overriding the locale because we do not want the sort to - // be affected by the machine's locale (be it a developer or CI environment) - return aLabel.localeCompare(zLabel, 'en', { numeric: true }) - }, - } - ) + matchVariant('@w', cbFor('min-width'), options) + matchVariant('@h', cbFor('min-height'), options) }, { theme: { containers: { + '5xs': '4rem', + '4xs': '8rem', + '3xs': '12rem', + '2xs': '16rem', xs: '20rem', sm: '24rem', md: '28rem', @@ -78,8 +89,8 @@ export = plugin( '4xl': '56rem', '5xl': '64rem', '6xl': '72rem', - '7xl': '80rem', - }, - }, + '7xl': '80rem' + } + } } )