Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7576,7 +7576,6 @@ exports[`getClassList 1`] = `
"max-w-min",
"max-w-none",
"max-w-px",
"max-w-screen",
"max-w-svh",
"max-w-svw",
"mb-0",
Expand Down
11 changes: 11 additions & 0 deletions packages/tailwindcss/src/canonicalize-candidates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,17 @@ describe.each([['default'], ['with-variant'], ['important'], ['prefix']])('%s',
await expectCanonicalization(input, candidate, expected)
})

test('`[overflow-wrap:break-word]` → `wrap-break-word`', async () => {
let candidate = '[overflow-wrap:break-word]'
let expected = 'wrap-break-word'

let input = css`
@import 'tailwindcss';
`

await expectCanonicalization(input, candidate, expected)
})

test('`break-words` → `break-words` with custom implementation', async () => {
let candidate = 'break-words'
let expected = 'break-words'
Expand Down
18 changes: 18 additions & 0 deletions packages/tailwindcss/src/compat/legacy-utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,42 @@ export function registerLegacyUtilities(designSystem: DesignSystem) {
['l', 'left'],
['tl', 'top left'],
]) {
designSystem.utilities.suggest(`bg-gradient-to-${value}`, () => [])
designSystem.utilities.static(`bg-gradient-to-${value}`, () => [
decl('--tw-gradient-position', `to ${direction} in oklab`),
decl('background-image', `linear-gradient(var(--tw-gradient-stops))`),
])
}

// Legacy `background-position` utilities for compatibility with v4.0 and earlier
designSystem.utilities.suggest('bg-left-top', () => [])
designSystem.utilities.static('bg-left-top', () => [decl('background-position', 'left top')])
designSystem.utilities.suggest('bg-right-top', () => [])
designSystem.utilities.static('bg-right-top', () => [decl('background-position', 'right top')])
designSystem.utilities.suggest('bg-left-bottom', () => [])
designSystem.utilities.static('bg-left-bottom', () => [
decl('background-position', 'left bottom'),
])
designSystem.utilities.suggest('bg-right-bottom', () => [])
designSystem.utilities.static('bg-right-bottom', () => [
decl('background-position', 'right bottom'),
])

// Legacy `object-position` utilities for compatibility with v4.0 and earlier
designSystem.utilities.suggest('object-left-top', () => [])
designSystem.utilities.static('object-left-top', () => [decl('object-position', 'left top')])
designSystem.utilities.suggest('object-right-top', () => [])
designSystem.utilities.static('object-right-top', () => [decl('object-position', 'right top')])
designSystem.utilities.suggest('object-left-bottom', () => [])
designSystem.utilities.static('object-left-bottom', () => [
decl('object-position', 'left bottom'),
])
designSystem.utilities.suggest('object-right-bottom', () => [])
designSystem.utilities.static('object-right-bottom', () => [
decl('object-position', 'right bottom'),
])

designSystem.utilities.suggest('max-w-screen', () => [])
designSystem.utilities.functional('max-w-screen', (candidate) => {
if (!candidate.value) return
if (candidate.value.kind === 'arbitrary') return
Expand All @@ -47,18 +57,22 @@ export function registerLegacyUtilities(designSystem: DesignSystem) {
return [decl('max-width', value)]
})

designSystem.utilities.suggest('overflow-ellipsis', () => [])
designSystem.utilities.static(`overflow-ellipsis`, () => [decl('text-overflow', `ellipsis`)])

designSystem.utilities.suggest('decoration-slice', () => [])
designSystem.utilities.static(`decoration-slice`, () => [
decl('-webkit-box-decoration-break', `slice`),
decl('box-decoration-break', `slice`),
])

designSystem.utilities.suggest('decoration-clone', () => [])
designSystem.utilities.static(`decoration-clone`, () => [
decl('-webkit-box-decoration-break', `clone`),
decl('box-decoration-break', `clone`),
])

designSystem.utilities.suggest('flex-shrink', () => [])
designSystem.utilities.functional('flex-shrink', (candidate) => {
if (candidate.modifier) return

Expand All @@ -75,6 +89,7 @@ export function registerLegacyUtilities(designSystem: DesignSystem) {
}
})

designSystem.utilities.suggest('flex-grow', () => [])
designSystem.utilities.functional('flex-grow', (candidate) => {
if (candidate.modifier) return

Expand All @@ -91,6 +106,9 @@ export function registerLegacyUtilities(designSystem: DesignSystem) {
}
})

designSystem.utilities.suggest('order-none', () => [])
designSystem.utilities.static('order-none', () => [decl('order', '0')])

designSystem.utilities.suggest('break-words', () => [])
designSystem.utilities.static('break-words', () => [decl('overflow-wrap', 'break-word')])
}
71 changes: 36 additions & 35 deletions packages/tailwindcss/src/intellisense.test.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
import { expect, test } from 'vitest'
import { __unstable__loadDesignSystem } from '.'
import { buildDesignSystem } from './design-system'
import plugin from './plugin'
import { Theme, ThemeOptions } from './theme'
import { ThemeOptions } from './theme'

const css = String.raw

function loadDesignSystem() {
let theme = new Theme()
theme.add('--spacing', '0.25rem')
theme.add('--colors-red-500', 'red')
theme.add('--colors-blue-500', 'blue')
theme.add('--breakpoint-sm', '640px')
theme.add('--aspect-video', '16 / 9')
theme.add('--font-sans', 'sans-serif')
theme.add('--font-weight-superbold', '900')
theme.add('--text-xs', '0.75rem')
theme.add('--text-xs--line-height', '1rem')
theme.add('--perspective-dramatic', '100px')
theme.add('--perspective-normal', '500px')
theme.add('--opacity-background', '0.3')
theme.add('--drop-shadow-sm', '0 1px 1px rgb(0 0 0 / 0.05)')
theme.add('--inset-shadow-sm', 'inset 0 1px 1px rgb(0 0 0 / 0.05)')
theme.add('--font-weight-bold', '700')
theme.add('--container-md', '768px')
theme.add('--container-lg', '1024px')
return buildDesignSystem(theme)
return __unstable__loadDesignSystem(`
@theme {
--spacing: 0.25rem;
--colors-red-500: red;
--colors-blue-500: blue;
--breakpoint-sm: 640px;
--aspect-video: 16 / 9;
--font-sans: sans-serif;
--font-weight-superbold: 900;
--text-xs: 0.75rem;
--text-xs--line-height: 1rem;
--perspective-dramatic: 100px;
--perspective-normal: 500px;
--opacity-background: 0.3;
--drop-shadow-sm: 0 1px 1px rgb(0 0 0 / 0.05);
--inset-shadow-sm: inset 0 1px 1px rgb(0 0 0 / 0.05);
--font-weight-bold: 700;
--container-md: 768px;
--container-lg: 1024px;
}
`)
}

test('getClassList', () => {
let design = loadDesignSystem()
test('getClassList', async () => {
let design = await loadDesignSystem()
let classList = design.getClassList()
let classNames = classList.flatMap(([name, meta]) => [
name,
Expand All @@ -39,8 +40,8 @@ test('getClassList', () => {
expect(classNames).toMatchSnapshot()
})

test('Spacing utilities do not suggest bare values when not using the multiplier-based spacing scale', () => {
let design = loadDesignSystem()
test('Spacing utilities do not suggest bare values when not using the multiplier-based spacing scale', async () => {
let design = await loadDesignSystem()

// Remove spacing scale
design.theme.clearNamespace('--spacing', ThemeOptions.NONE)
Expand All @@ -58,22 +59,22 @@ test('Spacing utilities do not suggest bare values when not using the multiplier
expect(classNames).not.toContain('p-4')
})

test('Theme values with underscores are converted back to decimal points', () => {
let design = loadDesignSystem()
test('Theme values with underscores are converted back to decimal points', async () => {
let design = await loadDesignSystem()
let classes = design.getClassList()

expect(classes).toContainEqual(['inset-0.5', { modifiers: [] }])
})

test('getVariants', () => {
let design = loadDesignSystem()
test('getVariants', async () => {
let design = await loadDesignSystem()
let variants = design.getVariants()

expect(variants).toMatchSnapshot()
})

test('getVariants compound', () => {
let design = loadDesignSystem()
test('getVariants compound', async () => {
let design = await loadDesignSystem()
let variants = design.getVariants()
let group = variants.find((v) => v.name === 'group')!

Expand Down Expand Up @@ -130,16 +131,16 @@ test('variant selectors are in the correct order', async () => {
`)
})

test('The variant `has-force` does not crash', () => {
let design = loadDesignSystem()
test('The variant `has-force` does not crash', async () => {
let design = await loadDesignSystem()
let variants = design.getVariants()
let has = variants.find((v) => v.name === 'has')!

expect(has.selectors({ value: 'force' })).toMatchInlineSnapshot(`[]`)
})

test('Can produce CSS per candidate using `candidatesToCss`', () => {
let design = loadDesignSystem()
test('Can produce CSS per candidate using `candidatesToCss`', async () => {
let design = await loadDesignSystem()
design.invalidCandidates = new Set(['bg-[#fff]'])

expect(design.candidatesToCss(['underline', 'i-dont-exist', 'bg-[#fff]', 'bg-[#000]', 'text-xs']))
Expand Down
3 changes: 3 additions & 0 deletions packages/tailwindcss/src/intellisense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export function getClassList(design: DesignSystem): ClassEntry[] {

// Static utilities only work as-is
for (let utility of design.utilities.keys('static')) {
let completions = design.utilities.getCompletions(utility)
if (completions.length === 0) continue

let item = items.get(utility)
item.fraction = false
item.modifiers = []
Expand Down
6 changes: 6 additions & 0 deletions packages/tailwindcss/src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ export class Utilities {
}

getCompletions(name: string): SuggestionGroup[] {
if (this.has(name, 'static')) {
return (
this.completions.get(name)?.() ?? [{ supportsNegative: false, values: [], modifiers: [] }]
)
}

return this.completions.get(name)?.() ?? []
}

Expand Down