Skip to content

Commit 392e3a4

Browse files
committed
use @container
1 parent e48be48 commit 392e3a4

File tree

2 files changed

+189
-182
lines changed

2 files changed

+189
-182
lines changed

src/index.ts

Lines changed: 76 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,85 @@
11
import plugin from 'tailwindcss/plugin'
2-
// @ts-expect-error
3-
import { normalize } from 'tailwindcss/lib/util/dataTypes'
42

5-
export = plugin(function containerQueries({ matchUtilities, matchVariant, theme }) {
6-
let values: Record<string, string> = theme('containers') ?? {}
3+
export = plugin(
4+
function containerQueries({ matchUtilities, matchVariant, theme }) {
5+
let values: Record<string, string> = theme('containers') ?? {}
76

8-
function parseValue(value: string): {
9-
raw: string
10-
sortable: boolean
11-
minX: number
12-
maxX: number
13-
minY: number
14-
maxY: number
15-
} | null {
16-
// _ -> space
17-
value = normalize(value)
7+
function parseValue(value: string) {
8+
let numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
9+
if (numericValue === null) return null
1810

19-
// If just a number then it's a min-width
20-
let numericValue = value.match(/^(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
21-
if (numericValue !== null) {
22-
value = `(min-width: ${value})`
11+
return parseFloat(value)
2312
}
2413

25-
// Support for shorthand syntax(es)
26-
// Pending change on extractor ignoring @[min-w:stuff]
27-
// value = value.replace(/^min-w:(.*)$/, '(min-width:\1)')
28-
// value = value.replace(/^max-h:(.*)$/, '(max-width:\1)')
29-
// value = value.replace(/^min-y:(.*)$/, '(min-height:\1)')
30-
// value = value.replace(/^max-h:(.*)$/, '(max-height:\1)')
31-
32-
// If it doesn't start / end with parens then it's not valid (for now)
33-
if (!value.startsWith('(') || !value.endsWith(')')) {
34-
return null
35-
}
36-
37-
// Parse the value into {minX, minY, maxX, maxY, raw} values
38-
// This will make suring simpler
39-
let minX = value.match(/min-width:\s*(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
40-
let maxX = value.match(/max-width:\s*(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
41-
let minY = value.match(/min-height:\s*(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
42-
let maxY = value.match(/max-height:\s*(\d+\.\d+|\d+|\.\d+)\D+/)?.[1] ?? null
43-
44-
let minXf = minX === null ? Number.MIN_SAFE_INTEGER : parseFloat(minX)
45-
let maxXf = maxX === null ? Number.MAX_SAFE_INTEGER : parseFloat(maxX)
46-
let minYf = minY === null ? Number.MIN_SAFE_INTEGER : parseFloat(minY)
47-
let maxYf = maxY === null ? Number.MAX_SAFE_INTEGER : parseFloat(maxY)
48-
49-
return {
50-
raw: value,
51-
sortable: minX !== null || maxX !== null || minY !== null || maxY !== null,
52-
minX: minXf,
53-
maxX: maxXf,
54-
minY: minYf,
55-
maxY: maxYf,
56-
}
57-
}
58-
59-
matchUtilities(
60-
{
61-
container: (value, { modifier }) => {
62-
return {
63-
'container-type': value,
64-
'container-name': modifier,
65-
}
14+
matchUtilities(
15+
{
16+
'@container': (value, { modifier }) => {
17+
return {
18+
'container-type': value,
19+
'container-name': modifier,
20+
}
21+
},
6622
},
67-
},
68-
{
69-
values: {
70-
DEFAULT: 'inline',
71-
block: 'block',
72-
inline: 'inline',
23+
{
24+
values: {
25+
DEFAULT: 'inline-size',
26+
normal: 'normal',
27+
},
28+
modifiers: 'any',
29+
}
30+
)
31+
32+
matchVariant(
33+
'@',
34+
(value = '', { modifier }) => {
35+
let parsed = parseValue(value)
36+
37+
return parsed !== null ? `@container ${modifier ?? ''} (min-width: ${value})` : []
7338
},
74-
modifiers: 'any',
75-
}
76-
)
77-
78-
matchVariant(
79-
'@',
80-
(value = '', { modifier }) => {
81-
let parsed = parseValue(value)
82-
83-
return parsed !== null ? `@container ${modifier ?? ''} ${parsed.raw}` : []
84-
},
85-
{
86-
values,
87-
sort(aVariant, bVariant) {
88-
let a = parseValue(aVariant.value)
89-
let b = parseValue(bVariant.value)
90-
91-
if (a === null || b === null) return 0
92-
93-
let aLabel = aVariant.modifier ?? ''
94-
let bLabel = bVariant.modifier ?? ''
95-
96-
// Put "raw" values at the end
97-
if (a.sortable === false && b.sortable === false) {
98-
return 0
99-
} else if (a.sortable === false) {
100-
return 1
101-
} else if (b.sortable === false) {
102-
return -1
103-
}
104-
105-
// Order by min width / height and max width / height
106-
let order = a.minX - b.minX || a.minY - b.minY || b.maxX - a.maxX || b.maxY - a.maxY
107-
if (order !== 0) {
108-
return order
109-
}
110-
111-
// Explicitly move empty labels to the end
112-
if (aLabel === '' && bLabel !== '') {
113-
return 1
114-
} else if (aLabel !== '' && bLabel === '') {
115-
return -1
116-
}
117-
118-
// Sort labels alphabetically in the English locale
119-
// We are intentionally overriding the locale because we do not want the sort to
120-
// be affected by the machine's locale (be it a developer or CI environment)
121-
return aLabel.localeCompare(bLabel, 'en', { numeric: true })
39+
{
40+
values,
41+
sort(aVariant, zVariant) {
42+
let a = parseFloat(aVariant.value)
43+
let z = parseFloat(zVariant.value)
44+
45+
if (a === null || z === null) return 0
46+
47+
// Sort values themselves regardless of unit
48+
if (a - z !== 0) return a - z
49+
50+
let aLabel = aVariant.modifier ?? ''
51+
let zLabel = zVariant.modifier ?? ''
52+
53+
// Explicitly move empty labels to the end
54+
if (aLabel === '' && zLabel !== '') {
55+
return 1
56+
} else if (aLabel !== '' && zLabel === '') {
57+
return -1
58+
}
59+
60+
// Sort labels alphabetically in the English locale
61+
// We are intentionally overriding the locale because we do not want the sort to
62+
// be affected by the machine's locale (be it a developer or CI environment)
63+
return aLabel.localeCompare(zLabel, 'en', { numeric: true })
64+
},
65+
}
66+
)
67+
},
68+
{
69+
theme: {
70+
containers: {
71+
xs: '20rem',
72+
sm: '24rem',
73+
md: '28rem',
74+
lg: '32rem',
75+
xl: '36rem',
76+
'2xl': '42rem',
77+
'3xl': '48rem',
78+
'4xl': '56rem',
79+
'5xl': '64rem',
80+
'6xl': '72rem',
81+
'7xl': '80rem',
12282
},
123-
}
124-
)
125-
})
83+
},
84+
}
85+
)

0 commit comments

Comments
 (0)