mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-14 08:32:48 +08:00
feat(css): add new css utility classes for display and flex utils (#30567)
Issue number: resolves #22469 --------- - Adds new responsive display classes with the following values: `none`, `inline`, `inline-block`, `block`, `flex`, `inline-flex`, `grid`, `inline-grid`, `table`, `table-cell`, `table-row` - Adds new responsive flex util classes for the following properties: `align-content`, `align-items`, `align-self`, `justify-content`, `flex-direction`, `flex-wrap`, `flex`, `flex-grow` , `flex-shrink`, `order` - Adds e2e tests to verify the correct classes are in the CSS files --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:

committed by
Brandy Smith

parent
d5627c7368
commit
75f6c05fb9
@ -125,7 +125,7 @@
|
||||
|
||||
<ion-toolbar color="dark">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button class="ion-hide"></ion-back-button>
|
||||
<ion-back-button class="ion-display-none"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Hidden</ion-title>
|
||||
</ion-toolbar>
|
||||
|
@ -107,6 +107,7 @@ const renderProgress = (value: number, buffer: number) => {
|
||||
* When finalBuffer === 1, we use display: none
|
||||
* instead of removing the element to avoid flickering.
|
||||
*/
|
||||
// TODO(FW-6697): change `ion-hide` class to `ion-display-none` or another class
|
||||
<div
|
||||
class={{ 'buffer-circles-container': true, 'ion-hide': finalBuffer === 1 }}
|
||||
style={{ transform: `translateX(${finalBuffer * 100}%)` }}
|
||||
|
@ -2,9 +2,14 @@
|
||||
@import "../themes/ionic.mixins";
|
||||
|
||||
// Display
|
||||
// --------------------------------------------------
|
||||
// Modifies display of a particular element based on the given classes
|
||||
// ------------------------------------------------------------------
|
||||
// Provides utility classes to control the CSS display property
|
||||
// of elements. Includes responsive variants for toggling between
|
||||
// block, inline, flex, grid, and other display values at different
|
||||
// breakpoints.
|
||||
|
||||
// TODO(FW-6697): remove ion-hide-* classes in favor of the new
|
||||
// ion-display-* classes
|
||||
.ion-hide {
|
||||
display: none !important;
|
||||
}
|
||||
@ -29,3 +34,29 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$display-values: (
|
||||
none,
|
||||
inline,
|
||||
inline-block,
|
||||
block,
|
||||
flex,
|
||||
inline-flex,
|
||||
grid,
|
||||
inline-grid,
|
||||
table,
|
||||
table-cell,
|
||||
table-row
|
||||
);
|
||||
|
||||
@each $display in $display-values {
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-display#{$infix}-#{$display} {
|
||||
display: #{$display} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,99 +1,211 @@
|
||||
@import "../themes/ionic.globals";
|
||||
@import "../themes/ionic.mixins";
|
||||
|
||||
// Flex Utilities
|
||||
// --------------------------------------------------
|
||||
// Creates flex classes to align flex containers
|
||||
// and items
|
||||
// ------------------------------------------------------------------
|
||||
// Provides utility classes to control flexbox layout, alignment,
|
||||
// and sizing of elements. Includes responsive variants for managing
|
||||
// flex direction, alignment, justification, wrapping, growth,
|
||||
// shrinking, and ordering at different breakpoints.
|
||||
|
||||
// Align Self
|
||||
// --------------------------------------------------
|
||||
// Align Content
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.ion-align-self-start {
|
||||
align-self: flex-start !important;
|
||||
$align-content-values: (
|
||||
start: flex-start,
|
||||
end: flex-end,
|
||||
center: center,
|
||||
between: space-between,
|
||||
around: space-around,
|
||||
stretch: stretch
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $key, $value in $align-content-values {
|
||||
.ion-align-content#{$infix}-#{$key} {
|
||||
align-content: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-self-end {
|
||||
align-self: flex-end !important;
|
||||
}
|
||||
|
||||
.ion-align-self-center {
|
||||
align-self: center !important;
|
||||
}
|
||||
|
||||
.ion-align-self-stretch {
|
||||
align-self: stretch !important;
|
||||
}
|
||||
|
||||
.ion-align-self-baseline {
|
||||
align-self: baseline !important;
|
||||
}
|
||||
|
||||
.ion-align-self-auto {
|
||||
align-self: auto !important;
|
||||
}
|
||||
|
||||
|
||||
// Flex Wrap
|
||||
// --------------------------------------------------
|
||||
|
||||
.ion-wrap {
|
||||
flex-wrap: wrap !important;
|
||||
}
|
||||
|
||||
.ion-nowrap {
|
||||
flex-wrap: nowrap !important;
|
||||
}
|
||||
|
||||
.ion-wrap-reverse {
|
||||
flex-wrap: wrap-reverse !important;
|
||||
}
|
||||
|
||||
|
||||
// Justify Content
|
||||
// --------------------------------------------------
|
||||
|
||||
.ion-justify-content-start {
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-center {
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-end {
|
||||
justify-content: flex-end !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-around {
|
||||
justify-content: space-around !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-between {
|
||||
justify-content: space-between !important;
|
||||
}
|
||||
|
||||
.ion-justify-content-evenly {
|
||||
justify-content: space-evenly !important;
|
||||
}
|
||||
|
||||
|
||||
// Align Items
|
||||
// --------------------------------------------------
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
.ion-align-items-start {
|
||||
align-items: flex-start !important;
|
||||
$align-items-values: (
|
||||
start,
|
||||
end,
|
||||
center,
|
||||
stretch,
|
||||
baseline
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $align-items-values {
|
||||
.ion-align-items#{$infix}-#{$value} {
|
||||
align-items: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-center {
|
||||
align-items: center !important;
|
||||
// Align Self
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$align-self-values: (
|
||||
start,
|
||||
end,
|
||||
center,
|
||||
stretch,
|
||||
baseline,
|
||||
auto
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $align-self-values {
|
||||
.ion-align-self#{$infix}-#{$value} {
|
||||
align-self: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-end {
|
||||
align-items: flex-end !important;
|
||||
// Justify Content
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$justify-content-values: (
|
||||
start: flex-start,
|
||||
end: flex-end,
|
||||
center: center,
|
||||
between: space-between,
|
||||
around: space-around,
|
||||
evenly: space-evenly
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $key, $value in $justify-content-values {
|
||||
.ion-justify-content#{$infix}-#{$key} {
|
||||
justify-content: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-stretch {
|
||||
align-items: stretch !important;
|
||||
// Flex Direction
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-direction-values: (
|
||||
row,
|
||||
row-reverse,
|
||||
column,
|
||||
column-reverse
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-direction-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex-direction: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ion-align-items-baseline {
|
||||
align-items: baseline !important;
|
||||
// Flex Wrap
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-wrap-values: (
|
||||
wrap,
|
||||
nowrap,
|
||||
wrap-reverse
|
||||
);
|
||||
|
||||
@each $value in $flex-wrap-values {
|
||||
// TODO(FW-6697): remove ion-wrap, ion-nowrap, ion-wrap-reverse
|
||||
// in favor of the new ion-flex-wrap, ion-flex-nowrap, and
|
||||
// ion-flex-wrap-reverse classes
|
||||
.ion-#{$value} {
|
||||
flex-wrap: #{$value} !important;
|
||||
}
|
||||
}
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-wrap-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex-wrap: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Fill
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
$flex-fill-values: (
|
||||
1,
|
||||
auto,
|
||||
initial,
|
||||
none
|
||||
);
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
@each $value in $flex-fill-values {
|
||||
.ion-flex#{$infix}-#{$value} {
|
||||
flex: #{$value} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Grow and Shrink
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-flex#{$infix}-grow-0 {
|
||||
flex-grow: 0 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-grow-1 {
|
||||
flex-grow: 1 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-shrink-0 {
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.ion-flex#{$infix}-shrink-1 {
|
||||
flex-shrink: 1 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flex Order
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@each $breakpoint in map-keys($screen-breakpoints) {
|
||||
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
|
||||
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
|
||||
.ion-order#{$infix}-first { order: -1 !important; }
|
||||
|
||||
@for $i from 0 through 12 {
|
||||
.ion-order#{$infix}-#{$i} { order: #{$i} !important; }
|
||||
}
|
||||
|
||||
.ion-order#{$infix}-last { order: 13 !important; }
|
||||
}
|
||||
}
|
||||
|
48
core/src/css/test/display.e2e.ts
Normal file
48
core/src/css/test/display.e2e.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
test.describe('display css utility classes', () => {
|
||||
let css: string;
|
||||
|
||||
test.beforeAll(() => {
|
||||
css = fs.readFileSync(path.resolve(__dirname, '../../../css/display.css'), 'utf8');
|
||||
});
|
||||
|
||||
const INFIXES = ['', '-sm', '-md', '-lg', '-xl'];
|
||||
|
||||
// TODO(FW-6697): remove `ion-hide classes` test
|
||||
test('ion-hide classes', () => {
|
||||
expect(css).toContain('.ion-hide');
|
||||
|
||||
const values = ['up', 'down'];
|
||||
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-hide${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('ion-display classes', () => {
|
||||
const values = [
|
||||
'none',
|
||||
'inline',
|
||||
'inline-block',
|
||||
'block',
|
||||
'flex',
|
||||
'inline-flex',
|
||||
'grid',
|
||||
'inline-grid',
|
||||
'table',
|
||||
'table-cell',
|
||||
'table-row',
|
||||
];
|
||||
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-display${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
100
core/src/css/test/flex-utils.e2e.ts
Normal file
100
core/src/css/test/flex-utils.e2e.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
test.describe('flex-utils css utility classes', () => {
|
||||
let css: string;
|
||||
|
||||
test.beforeAll(() => {
|
||||
css = fs.readFileSync(path.resolve(__dirname, '../../../css/flex-utils.css'), 'utf8');
|
||||
});
|
||||
|
||||
const INFIXES = ['', '-sm', '-md', '-lg', '-xl'];
|
||||
|
||||
test('align-content classes', () => {
|
||||
const values = ['start', 'end', 'center', 'between', 'around', 'stretch'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-content${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('align-items classes', () => {
|
||||
const values = ['start', 'center', 'end', 'stretch', 'baseline'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-items${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('align-self classes', () => {
|
||||
const values = ['start', 'end', 'center', 'stretch', 'baseline', 'auto'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-align-self${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('justify-content classes', () => {
|
||||
const values = ['start', 'center', 'end', 'around', 'between', 'evenly'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-justify-content${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-direction classes', () => {
|
||||
const values = ['row', 'row-reverse', 'column', 'column-reverse'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-wrap classes', () => {
|
||||
const values = ['wrap', 'nowrap', 'wrap-reverse'];
|
||||
// TODO(FW-6697): remove all `ion-wrap-*` expects
|
||||
for (const value of values) {
|
||||
expect(css).toContain(`.ion-${value}`);
|
||||
}
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-fill classes', () => {
|
||||
const values = ['1', 'auto', 'initial', 'none'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-grow and flex-shrink classes', () => {
|
||||
const values = ['grow', 'shrink'];
|
||||
for (const value of values) {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}-0`);
|
||||
expect(css).toContain(`.ion-flex${infix}-${value}-1`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('flex-order classes', () => {
|
||||
for (const infix of INFIXES) {
|
||||
expect(css).toContain(`.ion-order${infix}-first`);
|
||||
expect(css).toContain(`.ion-order${infix}-last`);
|
||||
for (let i = 0; i <= 12; i++) {
|
||||
expect(css).toContain(`.ion-order${infix}-${i}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user