diff --git a/packages/preset-mini/src/theme/types.ts b/packages/preset-mini/src/theme/types.ts index 736db43f6b..d7672e72c9 100644 --- a/packages/preset-mini/src/theme/types.ts +++ b/packages/preset-mini/src/theme/types.ts @@ -52,6 +52,10 @@ export interface Theme { gridRow?: Record gridTemplateColumn?: Record gridTemplateRow?: Record + // container + container?: { + center?: boolean + } // vars /** Used to generate CSS variables placeholder in preflight */ preflightBase?: Record diff --git a/packages/preset-wind/src/rules/container.ts b/packages/preset-wind/src/rules/container.ts index 9402bc359e..04678a4450 100644 --- a/packages/preset-wind/src/rules/container.ts +++ b/packages/preset-wind/src/rules/container.ts @@ -7,7 +7,7 @@ const queryMatcher = /@media \(min-width: (.+)\)/ export const container: Rule[] = [ [ /^__container$/, - (m, { variantHandlers }) => { + (m, { theme, variantHandlers }) => { let width = '100%' for (const v of variantHandlers) { const query = v.handle?.({} as VariantHandlerContext, x => x)?.parent @@ -17,6 +17,13 @@ export const container: Rule[] = [ width = match } } + if (theme.container?.center) { + return { + 'max-width': width, + 'margin-left': 'auto', + 'margin-right': 'auto', + } + } return { 'max-width': width } }, { internal: true }, diff --git a/test/__snapshots__/preset-wind.test.ts.snap b/test/__snapshots__/preset-wind.test.ts.snap index 54175dab05..6547322f5d 100644 --- a/test/__snapshots__/preset-wind.test.ts.snap +++ b/test/__snapshots__/preset-wind.test.ts.snap @@ -1,5 +1,32 @@ // Vitest Snapshot v1 +exports[`preset-wind > centered containers 1`] = ` +"/* layer: shortcuts */ +.container{max-width:100%;margin-left:auto;margin-right:auto;} +@media (min-width: 640px){ +.container{max-width:640px;margin-left:auto;margin-right:auto;} +} +@media (min-width: 768px){ +.container, +.md\\\\:container{max-width:768px;margin-left:auto;margin-right:auto;} +} +@media (min-width: 1024px){ +.container, +.lg\\\\:container, +.md\\\\:container{max-width:1024px;margin-left:auto;margin-right:auto;} +} +@media (min-width: 1280px){ +.container, +.lg\\\\:container, +.md\\\\:container{max-width:1280px;margin-left:auto;margin-right:auto;} +} +@media (min-width: 1536px){ +.container, +.lg\\\\:container, +.md\\\\:container{max-width:1536px;margin-left:auto;margin-right:auto;} +}" +`; + exports[`preset-wind > containers 1`] = ` "/* layer: preflights */ *,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x:var(--un-empty,/*!*/ /*!*/);--un-pan-y:var(--un-empty,/*!*/ /*!*/);--un-pinch-zoom:var(--un-empty,/*!*/ /*!*/);--un-scroll-snap-strictness:proximity;--un-ordinal:var(--un-empty,/*!*/ /*!*/);--un-slashed-zero:var(--un-empty,/*!*/ /*!*/);--un-numeric-figure:var(--un-empty,/*!*/ /*!*/);--un-numeric-spacing:var(--un-empty,/*!*/ /*!*/);--un-numeric-fraction:var(--un-empty,/*!*/ /*!*/);--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 #0000;--un-ring-shadow:0 0 #0000;--un-shadow-inset:var(--un-empty,/*!*/ /*!*/);--un-shadow:0 0 #0000;--un-ring-inset:var(--un-empty,/*!*/ /*!*/);--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,0.5);--un-blur:var(--un-empty,/*!*/ /*!*/);--un-brightness:var(--un-empty,/*!*/ /*!*/);--un-contrast:var(--un-empty,/*!*/ /*!*/);--un-drop-shadow:var(--un-empty,/*!*/ /*!*/);--un-grayscale:var(--un-empty,/*!*/ /*!*/);--un-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-invert:var(--un-empty,/*!*/ /*!*/);--un-saturate:var(--un-empty,/*!*/ /*!*/);--un-sepia:var(--un-empty,/*!*/ /*!*/);--un-backdrop-blur:var(--un-empty,/*!*/ /*!*/);--un-backdrop-brightness:var(--un-empty,/*!*/ /*!*/);--un-backdrop-contrast:var(--un-empty,/*!*/ /*!*/);--un-backdrop-grayscale:var(--un-empty,/*!*/ /*!*/);--un-backdrop-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-invert:var(--un-empty,/*!*/ /*!*/);--un-backdrop-opacity:var(--un-empty,/*!*/ /*!*/);--un-backdrop-saturate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-sepia:var(--un-empty,/*!*/ /*!*/);}::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x:var(--un-empty,/*!*/ /*!*/);--un-pan-y:var(--un-empty,/*!*/ /*!*/);--un-pinch-zoom:var(--un-empty,/*!*/ /*!*/);--un-scroll-snap-strictness:proximity;--un-ordinal:var(--un-empty,/*!*/ /*!*/);--un-slashed-zero:var(--un-empty,/*!*/ /*!*/);--un-numeric-figure:var(--un-empty,/*!*/ /*!*/);--un-numeric-spacing:var(--un-empty,/*!*/ /*!*/);--un-numeric-fraction:var(--un-empty,/*!*/ /*!*/);--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 #0000;--un-ring-shadow:0 0 #0000;--un-shadow-inset:var(--un-empty,/*!*/ /*!*/);--un-shadow:0 0 #0000;--un-ring-inset:var(--un-empty,/*!*/ /*!*/);--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgba(147,197,253,0.5);--un-blur:var(--un-empty,/*!*/ /*!*/);--un-brightness:var(--un-empty,/*!*/ /*!*/);--un-contrast:var(--un-empty,/*!*/ /*!*/);--un-drop-shadow:var(--un-empty,/*!*/ /*!*/);--un-grayscale:var(--un-empty,/*!*/ /*!*/);--un-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-invert:var(--un-empty,/*!*/ /*!*/);--un-saturate:var(--un-empty,/*!*/ /*!*/);--un-sepia:var(--un-empty,/*!*/ /*!*/);--un-backdrop-blur:var(--un-empty,/*!*/ /*!*/);--un-backdrop-brightness:var(--un-empty,/*!*/ /*!*/);--un-backdrop-contrast:var(--un-empty,/*!*/ /*!*/);--un-backdrop-grayscale:var(--un-empty,/*!*/ /*!*/);--un-backdrop-hue-rotate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-invert:var(--un-empty,/*!*/ /*!*/);--un-backdrop-opacity:var(--un-empty,/*!*/ /*!*/);--un-backdrop-saturate:var(--un-empty,/*!*/ /*!*/);--un-backdrop-sepia:var(--un-empty,/*!*/ /*!*/);} diff --git a/test/preset-wind.test.ts b/test/preset-wind.test.ts index 282333748c..6fddc0670b 100644 --- a/test/preset-wind.test.ts +++ b/test/preset-wind.test.ts @@ -56,4 +56,27 @@ describe('preset-wind', () => { expect(matched).toEqual(new Set(targets)) expect(css).toMatchSnapshot() }) + + test('centered containers', async () => { + const uno = createGenerator({ + presets: [ + presetWind(), + ], + theme: { + container: { + center: true, + }, + }, + }) + + const targets = [ + 'container', + 'md:container', + 'lg:container', + ] + const { css, matched } = await uno.generate(new Set(targets), { preflights: false }) + + expect(matched).toEqual(new Set(targets)) + expect(css).toMatchSnapshot() + }) })