Skip to content

feat: Add max-width container query support #35

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: Add max-width container query support
- Allow configuration of max-width container queries using object syntax
- Support both string values (min-width) and object values with max/min properties
- Sort max-width queries in descending order
- Maintain backward compatibility with original string-based configuration
- Add proper TypeScript type definitions
  • Loading branch information
phucbm committed Apr 23, 2025
commit 1eb376533ecee74007ebfcef6887fe7a754aaed3
56 changes: 51 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
import plugin from 'tailwindcss/plugin'

type ContainerValue = string | { min?: string; max?: string }
type QueryType = 'min-width' | 'max-width'

export = plugin(
function containerQueries({ matchUtilities, matchVariant, theme }) {
let values: Record<string, string> = theme('containers') ?? {}
let values: Record<string, ContainerValue> = theme('containers') ?? {}

// Process the container values to support both string and object formats
let processedValues: Record<string, string> = {}
let queryTypes: Record<string, QueryType> = {}

// Transform the theme values into a format we can use
for (const [key, value] of Object.entries(values)) {
if (typeof value === 'string') {
// String value - use as min-width (original behavior)
processedValues[key] = value
queryTypes[key] = 'min-width'
} else if (typeof value === 'object' && value !== null) {
// Object with min/max properties
if (value.min) {
processedValues[key] = value.min
queryTypes[key] = 'min-width'
} else if (value.max) {
processedValues[key] = value.max
queryTypes[key] = 'max-width'
}
}
}

function parseValue(value: string) {
let numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
Expand Down Expand Up @@ -34,18 +59,39 @@ export = plugin(
(value = '', { modifier }) => {
let parsed = parseValue(value)

return parsed !== null ? `@container ${modifier ?? ''} (min-width: ${value})` : []
// Find the key for this value to determine query type
const key = Object.keys(processedValues).find(k => processedValues[k] === value)
const queryType = key ? queryTypes[key] : 'min-width'

return parsed !== null ? `@container ${modifier ?? ''} (${queryType}: ${value})` : []
},
{
values,
values: processedValues,
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
// Find keys to determine query types
const aKey = Object.keys(processedValues).find(k => processedValues[k] === aVariant.value)
const zKey = Object.keys(processedValues).find(k => processedValues[k] === zVariant.value)

const aType = aKey ? queryTypes[aKey] : 'min-width'
const zType = zKey ? queryTypes[zKey] : 'min-width'

// If they have different types, sort max-width first
if (aType !== zType) {
return aType === 'max-width' ? -1 : 1
}

// For max-width queries, we want descending order
if (aType === 'max-width') {
if (a - z !== 0) return z - a
} else {
// Original sort logic for min-width
if (a - z !== 0) return a - z
}

let aLabel = aVariant.modifier ?? ''
let zLabel = zVariant.modifier ?? ''
Expand Down