From 71faf3681af205809786144689f3248d0ba0f875 Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Mon, 18 Jun 2018 11:33:26 -0400 Subject: [PATCH] refactor(grid): update to support dynamic number of columns - adds size, offset, push, and pull (including specific breakpoints) as properties of ion-col - removes old css mixins to instead style the element itself - updates sass variables to use css variables for grid padding and width --- core/src/components.d.ts | 208 +++++++++++- core/src/components/col/col.tsx | 249 +++++++++++++- core/src/components/col/readme.md | 388 ++++++++++++++++++++++ core/src/components/grid/grid.mixins.scss | 164 ++------- core/src/components/grid/grid.scss | 16 +- core/src/components/grid/grid.tsx | 17 +- core/src/components/grid/grid.vars.scss | 73 ++-- core/src/themes/ionic.globals.scss | 11 + core/src/themes/ionic.mixins.scss | 63 +--- core/src/utils/media.ts | 22 ++ core/src/utils/show-hide-when-utils.ts | 10 +- 11 files changed, 954 insertions(+), 267 deletions(-) create mode 100644 core/src/utils/media.ts diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 459cc78bdd..60622f0b23 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -1472,7 +1472,102 @@ declare global { namespace StencilComponents { interface IonCol { - + /** + * The amount to offset the column, in terms of how many columns it should shift to the right of the total available. + */ + 'offset': string; + /** + * The amount to offset the column for lg screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetLg': string; + /** + * The amount to offset the column for md screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetMd': string; + /** + * The amount to offset the column for sm screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetSm': string; + /** + * The amount to offset the column for xl screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetXl': string; + /** + * The amount to offset the column for xs screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetXs': string; + /** + * The amount to pull the column, in terms of how many columns it should shift to the left of the total available. + */ + 'pull': string; + /** + * The amount to pull the column for lg screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullLg': string; + /** + * The amount to pull the column for md screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullMd': string; + /** + * The amount to pull the column for sm screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullSm': string; + /** + * The amount to pull the column for xl screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullXl': string; + /** + * The amount to pull the column for xs screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullXs': string; + /** + * The amount to push the column, in terms of how many columns it should shift to the right of the total available. + */ + 'push': string; + /** + * The amount to push the column for lg screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushLg': string; + /** + * The amount to push the column for md screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushMd': string; + /** + * The amount to push the column for sm screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushSm': string; + /** + * The amount to push the column for xl screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushXl': string; + /** + * The amount to push the column for xs screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushXs': string; + /** + * The size of the column, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'size': string; + /** + * The size of the column for lg screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeLg': string; + /** + * The size of the column for md screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeMd': string; + /** + * The size of the column for sm screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeSm': string; + /** + * The size of the column for xl screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeXl': string; + /** + * The size of the column for xs screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeXs': string; } } @@ -1495,7 +1590,102 @@ declare global { } namespace JSXElements { export interface IonColAttributes extends HTMLAttributes { - + /** + * The amount to offset the column, in terms of how many columns it should shift to the right of the total available. + */ + 'offset'?: string; + /** + * The amount to offset the column for lg screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetLg'?: string; + /** + * The amount to offset the column for md screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetMd'?: string; + /** + * The amount to offset the column for sm screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetSm'?: string; + /** + * The amount to offset the column for xl screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetXl'?: string; + /** + * The amount to offset the column for xs screens, in terms of how many columns it should shift to the right of the total available. + */ + 'offsetXs'?: string; + /** + * The amount to pull the column, in terms of how many columns it should shift to the left of the total available. + */ + 'pull'?: string; + /** + * The amount to pull the column for lg screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullLg'?: string; + /** + * The amount to pull the column for md screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullMd'?: string; + /** + * The amount to pull the column for sm screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullSm'?: string; + /** + * The amount to pull the column for xl screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullXl'?: string; + /** + * The amount to pull the column for xs screens, in terms of how many columns it should shift to the left of the total available. + */ + 'pullXs'?: string; + /** + * The amount to push the column, in terms of how many columns it should shift to the right of the total available. + */ + 'push'?: string; + /** + * The amount to push the column for lg screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushLg'?: string; + /** + * The amount to push the column for md screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushMd'?: string; + /** + * The amount to push the column for sm screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushSm'?: string; + /** + * The amount to push the column for xl screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushXl'?: string; + /** + * The amount to push the column for xs screens, in terms of how many columns it should shift to the right of the total available. + */ + 'pushXs'?: string; + /** + * The size of the column, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'size'?: string; + /** + * The size of the column for lg screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeLg'?: string; + /** + * The size of the column for md screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeMd'?: string; + /** + * The size of the column for sm screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeSm'?: string; + /** + * The size of the column for xl screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeXl'?: string; + /** + * The size of the column for xs screens, in terms of how many columns it should take up out of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + 'sizeXs'?: string; } } } @@ -2187,7 +2377,10 @@ declare global { namespace StencilComponents { interface IonGrid { - + /** + * If true, the grid will have a fixed width based on the screen size. Defaults to `false`. + */ + 'fixed': boolean; } } @@ -2210,7 +2403,10 @@ declare global { } namespace JSXElements { export interface IonGridAttributes extends HTMLAttributes { - + /** + * If true, the grid will have a fixed width based on the screen size. Defaults to `false`. + */ + 'fixed'?: boolean; } } } @@ -3308,11 +3504,11 @@ declare global { */ 'leaveAnimation': AnimationBuilder; /** - * Returns a promise that resolves when the loading did dismiss. It also accepts a callback that is called in the same circustances. + * Returns a promise that resolves when the loading did dismiss. It also accepts a callback that is called in the same circumstances. */ 'onDidDismiss': (callback?: ((detail: OverlayEventDetail) => void) | undefined) => Promise; /** - * Returns a promise that resolves when the loading will dismiss. It also accepts a callback that is called in the same circustances. ``` const {data, role} = await loading.onWillDismiss(); ``` + * Returns a promise that resolves when the loading will dismiss. It also accepts a callback that is called in the same circumstances. */ 'onWillDismiss': (callback?: ((detail: OverlayEventDetail) => void) | undefined) => Promise; 'overlayId': number; diff --git a/core/src/components/col/col.tsx b/core/src/components/col/col.tsx index 4d2cdb02d7..0d87080bbe 100644 --- a/core/src/components/col/col.tsx +++ b/core/src/components/col/col.tsx @@ -1,7 +1,252 @@ -import { Component } from '@stencil/core'; +import { Component, Element, Listen, Prop } from '@stencil/core'; +import { isMatch } from '../../utils/media'; + +const SUPPORTS_VARS: boolean = CSS.supports('--a', '0'); +const BREAKPOINTS = ['', 'xs', 'sm', 'md', 'lg', 'xl']; @Component({ tag: 'ion-col' }) -export class Col {} +export class Col { + [key: string]: any; + + @Element() el!: HTMLStencilElement; + + /** + * The amount to offset the column, in terms of how many columns it should shift to the right + * of the total available. + */ + @Prop() offset?: string; + + /** + * The amount to offset the column for xs screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() offsetXs?: string; + + /** + * The amount to offset the column for sm screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() offsetSm?: string; + + /** + * The amount to offset the column for md screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() offsetMd?: string; + + /** + * The amount to offset the column for lg screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() offsetLg?: string; + + /** + * The amount to offset the column for xl screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() offsetXl?: string; + + /** + * The amount to pull the column, in terms of how many columns it should shift to the left of + * the total available. + */ + @Prop() pull?: string; + + /** + * The amount to pull the column for xs screens, in terms of how many columns it should shift + * to the left of the total available. + */ + @Prop() pullXs?: string; + /** + * The amount to pull the column for sm screens, in terms of how many columns it should shift + * to the left of the total available. + */ + @Prop() pullSm?: string; + /** + * The amount to pull the column for md screens, in terms of how many columns it should shift + * to the left of the total available. + */ + @Prop() pullMd?: string; + /** + * The amount to pull the column for lg screens, in terms of how many columns it should shift + * to the left of the total available. + */ + @Prop() pullLg?: string; + /** + * The amount to pull the column for xl screens, in terms of how many columns it should shift + * to the left of the total available. + */ + @Prop() pullXl?: string; + + /** + * The amount to push the column, in terms of how many columns it should shift to the right + * of the total available. + */ + @Prop() push?: string; + + /** + * The amount to push the column for xs screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() pushXs?: string; + + /** + * The amount to push the column for sm screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() pushSm?: string; + + /** + * The amount to push the column for md screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() pushMd?: string; + + /** + * The amount to push the column for lg screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() pushLg?: string; + + /** + * The amount to push the column for xl screens, in terms of how many columns it should shift + * to the right of the total available. + */ + @Prop() pushXl?: string; + + /** + * The size of the column, in terms of how many columns it should take up out of the total + * available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() size?: string; + + /** + * The size of the column for xs screens, in terms of how many columns it should take up out + * of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() sizeXs?: string; + + /** + * The size of the column for sm screens, in terms of how many columns it should take up out + * of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() sizeSm?: string; + + /** + * The size of the column for md screens, in terms of how many columns it should take up out + * of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() sizeMd?: string; + + /** + * The size of the column for lg screens, in terms of how many columns it should take up out + * of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() sizeLg?: string; + + /** + * The size of the column for xl screens, in terms of how many columns it should take up out + * of the total available. If `"auto"` is passed, the column will be the size of its content. + */ + @Prop() sizeXl?: string; + + hostData() { + return { + style: { + ...this.calculateOffset(), + ...this.calculatePull(), + ...this.calculatePush(), + ...this.calculateSize() + } + }; + } + + @Listen('window:resize') + onResize() { + this.el.forceUpdate(); + } + + // Loop through all of the breakpoints to see if the media query + // matches and grab the column value from the relevant prop if so + getColumns(property: string) { + let matched; + + for (const breakpoint of BREAKPOINTS) { + const matches = this.isMatch(breakpoint); + + // Grab the value of the property, if it exists and our + // media query matches we return the value + const columns = this[property + breakpoint.charAt(0).toUpperCase() + breakpoint.slice(1)]; + + if (matches && columns !== undefined) { + matched = columns; + } + } + + // Return the last matched columns since the breakpoints + // increase in size and we want to return the largest match + return matched; + } + + calculateSize() { + let columns = this.getColumns('size'); + + // If size wasn't set for any breakpoint + // or if the user set the size without a value + // it means we need to stick with the default and return + // e.g. + if (!columns || columns === '') return; + + columns = SUPPORTS_VARS + // If CSS supports variables we should use the grid columns var + ? `calc(calc(${columns} / var(--ion-grid-columns, 12)) * 100%)` + // Convert the columns to a percentage by dividing by the total number + // of columns (12) and then multiplying by 100 + : ((columns / 12) * 100) + '%'; + + return { + 'flex': `0 0 ${columns}`, + 'width': `${columns}`, + 'max-width': `${columns}` + }; + } + + // Called by push, pull, and offset since they use the same calculations + calculatePosition(property: string, modifier: string) { + const columns = this.getColumns(property); + + if (!columns) return; + + // If the number of columns passed are greater than 0 and less than + // 12 we can position the column, else default to auto + const amount = SUPPORTS_VARS + // If CSS supports variables we should use the grid columns var + ? `calc(calc(${columns} / var(--ion-grid-columns, 12)) * 100%)` + // Convert the columns to a percentage by dividing by the total number + // of columns (12) and then multiplying by 100 + : (columns > 0 && columns < 12) ? (columns / 12 * 100) + '%' : 'auto'; + + return { + [`${modifier}`]: amount + }; + } + + calculateOffset() { + return this.calculatePosition('offset', 'margin-left'); + } + + calculatePull() { + return this.calculatePosition('pull', 'right'); + } + + calculatePush() { + return this.calculatePosition('push', 'left'); + } + + isMatch(bp: string) { + return bp ? isMatch(bp) : true; + } +} diff --git a/core/src/components/col/readme.md b/core/src/components/col/readme.md index d0ae8cbfa9..e40db8ad50 100644 --- a/core/src/components/col/readme.md +++ b/core/src/components/col/readme.md @@ -21,6 +21,394 @@ There are several attributes that can be added to a column to customize this beh +## Properties + +#### offset + +string + +The amount to offset the column, in terms of how many columns it should shift to the right +of the total available. + + +#### offsetLg + +string + +The amount to offset the column for lg screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offsetMd + +string + +The amount to offset the column for md screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offsetSm + +string + +The amount to offset the column for sm screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offsetXl + +string + +The amount to offset the column for xl screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offsetXs + +string + +The amount to offset the column for xs screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pull + +string + +The amount to pull the column, in terms of how many columns it should shift to the left of +the total available. + + +#### pullLg + +string + +The amount to pull the column for lg screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pullMd + +string + +The amount to pull the column for md screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pullSm + +string + +The amount to pull the column for sm screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pullXl + +string + +The amount to pull the column for xl screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pullXs + +string + +The amount to pull the column for xs screens, in terms of how many columns it should shift +to the left of the total available. + + +#### push + +string + +The amount to push the column, in terms of how many columns it should shift to the right +of the total available. + + +#### pushLg + +string + +The amount to push the column for lg screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pushMd + +string + +The amount to push the column for md screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pushSm + +string + +The amount to push the column for sm screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pushXl + +string + +The amount to push the column for xl screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pushXs + +string + +The amount to push the column for xs screens, in terms of how many columns it should shift +to the right of the total available. + + +#### size + +string + +The size of the column, in terms of how many columns it should take up out of the total +available. If `"auto"` is passed, the column will be the size of its content. + + +#### sizeLg + +string + +The size of the column for lg screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### sizeMd + +string + +The size of the column for md screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### sizeSm + +string + +The size of the column for sm screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### sizeXl + +string + +The size of the column for xl screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### sizeXs + +string + +The size of the column for xs screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +## Attributes + +#### offset + +string + +The amount to offset the column, in terms of how many columns it should shift to the right +of the total available. + + +#### offset-lg + +string + +The amount to offset the column for lg screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offset-md + +string + +The amount to offset the column for md screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offset-sm + +string + +The amount to offset the column for sm screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offset-xl + +string + +The amount to offset the column for xl screens, in terms of how many columns it should shift +to the right of the total available. + + +#### offset-xs + +string + +The amount to offset the column for xs screens, in terms of how many columns it should shift +to the right of the total available. + + +#### pull + +string + +The amount to pull the column, in terms of how many columns it should shift to the left of +the total available. + + +#### pull-lg + +string + +The amount to pull the column for lg screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pull-md + +string + +The amount to pull the column for md screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pull-sm + +string + +The amount to pull the column for sm screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pull-xl + +string + +The amount to pull the column for xl screens, in terms of how many columns it should shift +to the left of the total available. + + +#### pull-xs + +string + +The amount to pull the column for xs screens, in terms of how many columns it should shift +to the left of the total available. + + +#### push + +string + +The amount to push the column, in terms of how many columns it should shift to the right +of the total available. + + +#### push-lg + +string + +The amount to push the column for lg screens, in terms of how many columns it should shift +to the right of the total available. + + +#### push-md + +string + +The amount to push the column for md screens, in terms of how many columns it should shift +to the right of the total available. + + +#### push-sm + +string + +The amount to push the column for sm screens, in terms of how many columns it should shift +to the right of the total available. + + +#### push-xl + +string + +The amount to push the column for xl screens, in terms of how many columns it should shift +to the right of the total available. + + +#### push-xs + +string + +The amount to push the column for xs screens, in terms of how many columns it should shift +to the right of the total available. + + +#### size + +string + +The size of the column, in terms of how many columns it should take up out of the total +available. If `"auto"` is passed, the column will be the size of its content. + + +#### size-lg + +string + +The size of the column for lg screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### size-md + +string + +The size of the column for md screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### size-sm + +string + +The size of the column for sm screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### size-xl + +string + +The size of the column for xl screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + +#### size-xs + +string + +The size of the column for xs screens, in terms of how many columns it should take up out +of the total available. If `"auto"` is passed, the column will be the size of its content. + + ---------------------------------------------- diff --git a/core/src/components/grid/grid.mixins.scss b/core/src/components/grid/grid.mixins.scss index b49d6dcdd0..0fab508129 100644 --- a/core/src/components/grid/grid.mixins.scss +++ b/core/src/components/grid/grid.mixins.scss @@ -4,42 +4,38 @@ // Responsive Mixins // -------------------------------------------------- -// Creates a grid with padding +// Creates the shared grid properties // --------------------------------------------------------------------------------- -@mixin make-grid($padding-width: $grid-padding-width) { - @include padding($padding-width / 2); +@mixin make-grid($paddings: $grid-paddings) { + @include make-breakpoint-padding($paddings); @include margin-horizontal(auto); - display: flex; - flex-direction: column; + display: block; - width: 100%; - - - // Remove the padding from the grid and all immediate children columns - &[no-padding] { + // Remove the padding from grid and all immediate children columns + &[no-padding], + &[no-padding] > ion-col { @include padding(0); - - > ion-row > ion-col { - @include padding(0); - } } } -// Creates maximum widths for the grid based on screen size + +// Creates a fixed width for the grid based on the screen size // --------------------------------------------------------------------------------- -@mixin make-grid-max-widths($max-widths: $grid-max-widths, $breakpoints: $grid-breakpoints) { - @each $breakpoint, $container-max-width in $max-widths { +@mixin make-grid-widths($widths: $grid-widths, $breakpoints: $screen-breakpoints) { + max-width: 100%; + + @each $breakpoint, $width in $widths { @include media-breakpoint-up($breakpoint, $breakpoints) { - width: $container-max-width; - max-width: 100%; + width: $width; } } } -// Creates a row used to align columns + +// Creates a flex row used to align columns // --------------------------------------------------------------------------------- @mixin make-row() { @@ -96,12 +92,12 @@ } -// Creates the base column which has shared styles among all columns +// Creates a column // --------------------------------------------------------------------------------- -@mixin make-column-base($padding-width: $grid-padding-width) { +@mixin make-column($column-paddings: $grid-column-paddings) { + @include make-breakpoint-padding($column-paddings); @include margin(0); - @include padding($padding-width / 2); position: relative; @@ -133,126 +129,14 @@ } -// Create an individual column +// Adds padding to the element based on breakpoints // --------------------------------------------------------------------------------- -@mixin make-column($size, $columns: $grid-columns) { - flex: 0 0 percentage($size / $columns); - width: percentage($size / $columns); - // Add a `max-width` to ensure content within each column does not blow out - // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari - // do not appear to require this. - max-width: percentage($size / $columns); -} - - -// Adds padding to the column -// --------------------------------------------------------------------------------- - -@mixin make-column-padding($padding-widths: $grid-padding-widths) { - @each $breakpoint in map-keys($padding-widths) { +@mixin make-breakpoint-padding($paddings) { + @each $breakpoint in map-keys($paddings) { @include media-breakpoint-up($breakpoint) { - $padding-width: map-get($padding-widths, $breakpoint); - @include padding($padding-width / 2); - } - } -} - - -// Offset the column using margin-start -// --------------------------------------------------------------------------------- - -@mixin make-column-offset($size, $columns: $grid-columns) { - @include margin-horizontal(percentage($size / $columns), null); -} - - -// Push the column using left -// --------------------------------------------------------------------------------- - -@mixin make-column-push($size, $columns: $grid-columns) { - @include position(null, null, null, if($size > 0, percentage($size / $columns), auto)); -} - - -// Pull the column using right -// --------------------------------------------------------------------------------- - -@mixin make-column-pull($size, $columns: $grid-columns) { - @include position(null, if($size > 0, percentage($size / $columns), auto), null, null); -} - - -// Determine which modifier to add -// --------------------------------------------------------------------------------- - -@mixin make-column-modifier($type, $size, $columns) { - // Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) - @if $type == push { - @include make-column-push($size, $columns); - } @else if $type == pull { - @include make-column-pull($size, $columns); - } @else if $type == offset { - @include make-column-offset($size, $columns); - } -} - - -// Create the responsive grid columns -// -------------------------------------------------- - -@mixin make-grid-columns($columns: $grid-columns, $padding-widths: $grid-padding-widths, $breakpoints: $grid-breakpoints) { - @each $breakpoint in map-keys($breakpoints) { - $infix: breakpoint-infix($breakpoint, $breakpoints); - - // Allow columns to stretch full width below their breakpoints - @for $i from 1 through $columns { - [col#{$infix}-#{$i}] { - @include make-column-padding($padding-widths); - } - } - - [col#{$infix}] { - @include make-column-padding($padding-widths); - } - - @include media-breakpoint-up($breakpoint, $breakpoints) { - // Provide basic `[col-{bp}]` attributes for equal-width flexbox columns - [col#{$infix}] { - flex-basis: 0; - flex-grow: 1; - - max-width: 100%; - } - - [col#{$infix}-auto] { - flex: 0 0 auto; - - width: auto; - } - - @for $i from 1 through $columns { - [col#{$infix}-#{$i}] { - @include make-column($i, $columns); - } - } - - @each $modifier in (pull, push) { - @for $i from 0 through $columns { - [#{$modifier}#{$infix}-#{$i}] { - @include make-column-modifier($modifier, $i, $columns) - } - } - } - - // `$columns - 1` because offsetting by the width of an entire row isn't possible - @for $i from 0 through ($columns - 1) { - @if not ($infix == "" and $i == 0) { // Avoid emitting useless [offset-xs-0] - [offset#{$infix}-#{$i}] { - @include make-column-modifier(offset, $i, $columns) - } - } - } + $padding: map-get($paddings, $breakpoint); + @include padding($padding); } } } diff --git a/core/src/components/grid/grid.scss b/core/src/components/grid/grid.scss index 3b422e1098..d6fab0f1e2 100644 --- a/core/src/components/grid/grid.scss +++ b/core/src/components/grid/grid.scss @@ -5,24 +5,16 @@ ion-grid { @include make-grid(); - - &[fixed] { - @include make-grid-max-widths(); - } } -// Row -// -------------------------------------------------- +.grid-fixed { + @include make-grid-widths(); +} ion-row { @include make-row(); } -// Columns -// -------------------------------------------------- - ion-col { - @include make-column-base(); + @include make-column(); } - -@include make-grid-columns(); diff --git a/core/src/components/grid/grid.tsx b/core/src/components/grid/grid.tsx index cb23e1daaf..32c2f5ed46 100644 --- a/core/src/components/grid/grid.tsx +++ b/core/src/components/grid/grid.tsx @@ -1,4 +1,4 @@ -import { Component } from '@stencil/core'; +import { Component, Prop } from '@stencil/core'; @Component({ @@ -11,4 +11,17 @@ import { Component } from '@stencil/core'; theme: 'grid' } }) -export class Grid {} +export class Grid { + /** + * If true, the grid will have a fixed width based on the screen size. Defaults to `false`. + */ + @Prop() fixed?: boolean; + + hostData() { + return { + class: { + 'grid-fixed': this.fixed + } + }; + } +} diff --git a/core/src/components/grid/grid.vars.scss b/core/src/components/grid/grid.vars.scss index 6ce2376ef7..ce87da54f1 100644 --- a/core/src/components/grid/grid.vars.scss +++ b/core/src/components/grid/grid.vars.scss @@ -1,64 +1,43 @@ @import "../../themes/ionic.globals"; - @import "./grid.mixins"; // Grid // -------------------------------------------------- -// Using flexbox for the grid, originally inspired by Philip Walton: -// http://philipwalton.github.io/solved-by-flexbox/demos/grids/ -// Column layout based on the Bootstrap grid system: -// http://v4-alpha.getbootstrap.com/layout/grid/ - -// Grid Breakpoints -// -------------------------------------------------- - -/// @prop - The minimum dimensions at which your layout will change, -/// adapting to different screen sizes, for use in media queries -$grid-breakpoints: ( - xs: 0, - sm: 576px, - md: 768px, - lg: 992px, - xl: 1200px +/// @prop - Width of the grid for different screen sizes +/// when fixed is enabled +$grid-widths: ( + xs: var(--ion-grid-width-xs, var(--ion-grid-width, 100%)), + sm: var(--ion-grid-width-sm, var(--ion-grid-width, 540px)), + md: var(--ion-grid-width-md, var(--ion-grid-width, 720px)), + lg: var(--ion-grid-width-lg, var(--ion-grid-width, 960px)), + xl: var(--ion-grid-width-xl, var(--ion-grid-width, 1140px)) ) !default; +/// @prop - The padding for the grid +$grid-padding: var(--ion-grid-padding, 5px) !default; -// Grid Containers -// -------------------------------------------------- - -/// @prop - Maximum width of the grid for different screen sizes -$grid-max-widths: ( - sm: 540px, - md: 720px, - lg: 960px, - xl: 1140px +/// @prop - The padding for the grid at different breakpoints +$grid-paddings: ( + xs: var(--ion-grid-padding-xs, $grid-padding), + sm: var(--ion-grid-padding-sm, $grid-padding), + md: var(--ion-grid-padding-md, $grid-padding), + lg: var(--ion-grid-padding-lg, $grid-padding), + xl: var(--ion-grid-padding-xl, $grid-padding) ) !default; // Grid Columns // -------------------------------------------------- -/// @prop - Number of columns for the grid -$grid-columns: 12 !default; +/// @prop - The padding for the grid column +$grid-column-padding: var(--ion-grid-column-padding, 5px) !default; -/// @prop - Total width of the padding for the grid -$grid-padding-width: 10px !default; - -/// @prop - Padding for the columns for different screen sizes -$grid-padding-widths: ( - xs: $grid-padding-width, - sm: $grid-padding-width, - md: $grid-padding-width, - lg: $grid-padding-width, - xl: $grid-padding-width +/// @prop - The padding for the column at different breakpoints +$grid-column-paddings: ( + xs: var(--ion-grid-column-padding-xs, $grid-column-padding), + sm: var(--ion-grid-column-padding-sm, $grid-column-padding), + md: var(--ion-grid-column-padding-md, $grid-column-padding), + lg: var(--ion-grid-column-padding-lg, $grid-column-padding), + xl: var(--ion-grid-column-padding-xl, $grid-column-padding) ) !default; - - -// Check that the Sass maps are declared correctly -// -------------------------------------------------- - -@include assert-ascending($grid-breakpoints, "$grid-breakpoints"); -@include assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); - -@include assert-ascending($grid-max-widths, "$grid-max-widths"); diff --git a/core/src/themes/ionic.globals.scss b/core/src/themes/ionic.globals.scss index 3a7a96776b..8a14c60f30 100644 --- a/core/src/themes/ionic.globals.scss +++ b/core/src/themes/ionic.globals.scss @@ -32,6 +32,17 @@ $font-path: "/dist/fonts" !default; $hairlines-width: .55px !default; +// The minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries +$screen-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px +) !default; + + // Z-Index // -------------------------------------------------- // Grouped by elements which would be siblings diff --git a/core/src/themes/ionic.mixins.scss b/core/src/themes/ionic.mixins.scss index 4bdc64f31f..27c32f4bc8 100644 --- a/core/src/themes/ionic.mixins.scss +++ b/core/src/themes/ionic.mixins.scss @@ -45,34 +45,11 @@ } -// Check that the given map values are in ascending order -// --------------------------------------------------------------------------------- +// Get the key from a map based on the index +@function index-to-key($map, $index) { + $keys: map-keys($map); -@mixin assert-ascending($map, $map-name) { - $prev-key: null; - $prev-num: null; - @each $key, $num in $map { - @if $prev-num == null { - // Do nothing - } @else if not comparable($prev-num, $num) { - @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; - } @else if $prev-num >= $num { - @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; - } - $prev-key: $key; - $prev-num: $num; - } -} - -// Check that the first value in the given map starts at 0 -// --------------------------------------------------------------------------------- - -@mixin assert-starts-at-zero($map, $map-name) { - $values: map-values($map); - $first-value: nth($values, 1); - @if $first-value != 0 { - @warn "First value in `#{$map-name}` must start at 0, but starts at #{$first-value}."; - } + @return nth($keys, $index); } @@ -85,7 +62,7 @@ // // (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) // -// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. +// The map defined in the `$screen-breakpoints` global variable is used as the `$breakpoints` argument by default. // --------------------------------------------------------------------------------- @@ -93,9 +70,10 @@ // // >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) // 576px -@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { +@function breakpoint-min($name, $breakpoints: $screen-breakpoints) { $min: map-get($breakpoints, $name); - @return if($min != 0, $min, null); + + @return if($name != index-to-key($breakpoints, 1), $min, null); } // Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront. @@ -105,13 +83,13 @@ // "" (Returns a blank string) // >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) // "-sm" -@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { +@function breakpoint-infix($name, $breakpoints: $screen-breakpoints) { @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); } // Media of at least the minimum breakpoint width. No query for the smallest breakpoint. // Makes the @content apply to the given breakpoint and wider. -@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { +@mixin media-breakpoint-up($name, $breakpoints: $screen-breakpoints) { $min: breakpoint-min($name, $breakpoints); @if $min { @media (min-width: $min) { @@ -130,7 +108,7 @@ // md // >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) // md -@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { +@function breakpoint-next($name, $breakpoints: $screen-breakpoints, $breakpoint-names: map-keys($breakpoints)) { $n: index($breakpoint-names, $name); @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); } @@ -140,14 +118,14 @@ // // >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) // 767px -@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { +@function breakpoint-max($name, $breakpoints: $screen-breakpoints) { $next: breakpoint-next($name, $breakpoints); @return if($next, breakpoint-min($next, $breakpoints) - 1px, null); } // Media of at most the maximum breakpoint width. No query for the largest breakpoint. // Makes the @content apply to the given breakpoint and narrower. -@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { +@mixin media-breakpoint-down($name, $breakpoints: $screen-breakpoints) { $max: breakpoint-max($name, $breakpoints); @if $max { @media (max-width: $max) { @@ -206,19 +184,6 @@ } } -// If deprecated variable exists, use it, otherwise, use alternative -// @param {string} $property - property to default -// @param {string} $variable-name - the deprecated variable's name -// @param {string} $variable - the deprecated variable -// ---------------------------------------------------------- -@mixin deprecated-variable($property, $variable-name, $variable) { - @if $variable == null { - @content; - } @else { - @warn "you are using a deprecated variable: #{$variable-name}"; - #{$property}: $variable; - } -} // SVG Background Image Mixin // @param {string} $svg @@ -751,4 +716,4 @@ min-height: calc(#{$toolbar-height} + #{$statusbar-padding}); @include safe-area-sizing(min-height, safe-area-inset-top, $toolbar-height) } -} +} \ No newline at end of file diff --git a/core/src/utils/media.ts b/core/src/utils/media.ts new file mode 100644 index 0000000000..8c683c2eda --- /dev/null +++ b/core/src/utils/media.ts @@ -0,0 +1,22 @@ +// Media Query Functions +// ----------------------------------------------------- + +export const SIZE_TO_MEDIA: any = { + 'xs': '(min-width: 0px)', + 'sm': '(min-width: 576px)', + 'md': '(min-width: 768px)', + 'lg': '(min-width: 992px)', + 'xl': '(min-width: 1200px)', +}; + +// Check if the window matches the media query +// at the breakpoint passed +// e.g. isMatch('sm') => true if screen width exceeds 576px +export function isMatch(breakpoint: string) { + const mediaQuery = SIZE_TO_MEDIA[breakpoint]; + if (mediaQuery && matchMedia(mediaQuery)) { + const media = matchMedia(mediaQuery); + return media.matches; + } + return false; +} diff --git a/core/src/utils/show-hide-when-utils.ts b/core/src/utils/show-hide-when-utils.ts index fa64791bd2..cde39905e3 100644 --- a/core/src/utils/show-hide-when-utils.ts +++ b/core/src/utils/show-hide-when-utils.ts @@ -1,4 +1,5 @@ import { Config, Mode } from '../interface'; +import { SIZE_TO_MEDIA } from './media'; import { isAndroid, isCordova, isElectron, isIOS, isIpad, isIphone, isPhablet, isTablet, matchMedia } from './platform'; export function updateTestResults(displayWhen: DisplayWhen) { @@ -84,14 +85,6 @@ export function isPortrait(win: Window): boolean { } -const SIZE_TO_MEDIA: any = { - 'xs': '(min-width: 0px)', - 'sm': '(min-width: 576px)', - 'md': '(min-width: 768px)', - 'lg': '(min-width: 992px)', - 'xl': '(min-width: 1200px)', -}; - // order from most specifc to least specific export const PLATFORM_CONFIGS: PlatformConfig[] = [ @@ -152,4 +145,3 @@ export interface DisplayWhen { platform?: string; size?: string; } -