diff --git a/src/components/grid/col.ts b/src/components/grid/col.ts new file mode 100644 index 00000000000..d7e10919198 --- /dev/null +++ b/src/components/grid/col.ts @@ -0,0 +1,33 @@ +import { Directive } from '@angular/core'; + +/** + * @name Col + * @module ionic + * @description + * + * Column description + * + * ## Column attributes + * + * By default, columns will stretch to fill the entire height of the row. + * There are several attributes that can be added to a column to customize this behavior. + * + * | Property | Description | + * |-----------------------|-------------------------------------------------------------------------------------------------------------| + * | align-self-start | Adds `align-self: flex-start`. The column will be vertically aligned at the top. | + * | align-self-center | Adds `align-self: center`. The column will be vertically aligned in the center. | + * | align-self-end | Adds `align-self: flex-end`. The column will be vertically aligned at the bottom. | + * | align-self-stretch | Adds `align-self: stretch`. The column will be stretched to take up the entire height of the row. | + * | align-self-baseline | Adds `align-self: baseline`. The column will be vertically aligned at its baselines. | + * + * + */ +@Directive({ + selector: 'ion-col, [ion-col]', + host: { + 'class': 'col' + } +}) +export class Col { + +} diff --git a/src/components/grid/grid.mixins.scss b/src/components/grid/grid.mixins.scss new file mode 100644 index 00000000000..2ceab3c0d3d --- /dev/null +++ b/src/components/grid/grid.mixins.scss @@ -0,0 +1,302 @@ +@import "../../themes/ionic.globals"; + +// Responsive Mixins +// -------------------------------------------------- + +// Creates a grid with padding +// --------------------------------------------------------------------------------- + +@mixin make-grid($padding-width: $grid-padding-width) { + padding: $padding-width / 2; + margin-left: auto; + margin-right: auto; + width: 100%; + + // Remove the padding from the grid and all immediate children columns + &[no-padding] { + padding: 0; + + > .row > .col { + padding: 0; + } + } +} + +// Creates maximum widths for the grid based on screen size +// --------------------------------------------------------------------------------- + +@mixin make-grid-max-widths($max-widths: $grid-max-widths, $breakpoints: $grid-breakpoints) { + @each $breakpoint, $container-max-width in $max-widths { + @include media-breakpoint-up($breakpoint, $breakpoints) { + width: $container-max-width; + max-width: 100%; + } + } +} + +// Creates a row used to align columns +// --------------------------------------------------------------------------------- + +@mixin make-row() { + display: flex; + flex-wrap: wrap; + + &[nowrap] { + flex-wrap: nowrap; + } + + &[wrap-reverse] { + flex-wrap: wrap-reverse; + } + + &[align-items-start] { + align-items: flex-start; + } + + &[align-items-center] { + align-items: center; + } + + &[align-items-end] { + align-items: flex-end; + } + + &[align-items-stretch] { + align-items: stretch; + } + + &[align-items-baseline] { + align-items: baseline; + } + + &[justify-content-start] { + justify-content: flex-start; + } + + &[justify-content-center] { + justify-content: center; + } + + &[justify-content-end] { + justify-content: flex-end; + } + + &[justify-content-around] { + justify-content: space-around; + } + + &[justify-content-between] { + justify-content: space-between; + } +} + + +// Creates the base column which has shared styles among all columns +// --------------------------------------------------------------------------------- + +@mixin make-column-base($padding-width: $grid-padding-width) { + position: relative; + + padding: $padding-width / 2; + + width: 100%; + margin: 0; + min-height: 1px; // Prevent columns from collapsing when empty + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + + &[align-self-start] { + align-self: flex-start; + } + + &[align-self-end] { + align-self: flex-end; + } + + &[align-self-center] { + align-self: center; + } + + &[align-self-stretch] { + align-self: stretch; + } + + &[align-self-baseline] { + align-self: baseline; + } +} + + +// Create an individual column +// --------------------------------------------------------------------------------- + +@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) { + @include media-breakpoint-up($breakpoint) { + $padding-width: map-get($padding-widths, $breakpoint); + padding: ($padding-width / 2); + } + } +} + + +// Offset the column using margin-left +// --------------------------------------------------------------------------------- + +@mixin make-column-offset($size, $columns: $grid-columns) { + margin-left: percentage($size / $columns); +} + + +// Push the column using left +// --------------------------------------------------------------------------------- + +@mixin make-column-push($size, $columns: $grid-columns) { + left: if($size > 0, percentage($size / $columns), auto); +} + + +// Pull the column using right +// --------------------------------------------------------------------------------- + +@mixin make-column-pull($size, $columns: $grid-columns) { + right: if($size > 0, percentage($size / $columns), auto); +} + + +// 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) + } + } + } + } + } +} + + +// Breakpoint Mixins +// --------------------------------------------------------------------------------- + +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (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. + +// --------------------------------------------------------------------------------- + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// "" (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) { + @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) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} diff --git a/src/components/grid/grid.old.scss b/src/components/grid/grid.old.scss new file mode 100644 index 00000000000..d924af03c05 --- /dev/null +++ b/src/components/grid/grid.old.scss @@ -0,0 +1,212 @@ +@import "../../themes/ionic.globals"; + +// Grid +// -------------------------------------------------- +// Using flexbox for the grid, inspired by Philip Walton: +// http://philipwalton.github.io/solved-by-flexbox/demos/grids/ +// By default each .col within a .row will evenly take up +// available width, and the height of each .col with take +// up the height of the tallest .col in the same .row. + +// TODO: Deprecated 2017/02/14: convert to new grid system + +$grid-padding-width: 10px !default; +$grid-responsive-sm-break: 567px !default; // smaller than landscape phone +$grid-responsive-md-break: 767px !default; // smaller than portrait tablet +$grid-responsive-lg-break: 1023px !default; // smaller than landscape tablet + +@mixin responsive-grid-break($selector, $max-width) { + @media (max-width: $max-width) { + #{$selector} { + flex-direction: column; + + ion-col { + flex: 1; + + &[width-10], + &[width-20], + &[width-25], + &[width-33], + &[width-34], + &[width-50], + &[width-66], + &[width-67], + &[width-75], + &[width-80], + &[width-90] { + margin-bottom: ($grid-padding-width * 3) / 2; + margin-left: 0; + + width: 100%; + max-width: 100%; + } + } + + } + } +} + +ion-grid { + display: flex; + + flex-direction: column; + + width: 100%; +} + +ion-row { + &[top] { + align-items: flex-start; + } + + &[bottom] { + align-items: flex-end; + } + + &[center] { + align-items: center; + } + + &[stretch] { + align-items: stretch; + } + + &[baseline] { + align-items: baseline; + } +} + +ion-col { + // Column Alignment + + &[top] { + align-self: flex-start; + } + + &[bottom] { + align-self: flex-end; + } + + &[center] { + align-self: center; + } + + &[stretch] { + align-self: stretch; + } + + &[baseline] { + align-self: baseline; + } + + // Column Offsets + + &[offset-10] { + margin-left: 10%; + } + + &[offset-20] { + margin-left: 20%; + } + + &[offset-25] { + margin-left: 25%; + } + + &[offset-33], + &[offset-34] { + margin-left: 33.3333%; + } + + &[offset-50] { + margin-left: 50%; + } + + &[offset-66], + &[offset-67] { + margin-left: 66.6666%; + } + + &[offset-75] { + margin-left: 75%; + } + + &[offset-80] { + margin-left: 80%; + } + + &[offset-90] { + margin-left: 90%; + } + + // Explicit Column Percent Sizes + // By default each grid column will evenly distribute + // across the grid. However, you can specify individual + // columns to take up a certain size of the available area + + &[width-10] { + flex: 0 0 10%; + + max-width: 10%; + } + + &[width-20] { + flex: 0 0 20%; + + max-width: 20%; + } + + &[width-25] { + flex: 0 0 25%; + + max-width: 25%; + } + + &[width-33], + &[width-34] { + flex: 0 0 33.3333%; + + max-width: 33.3333%; + } + + &[width-50] { + flex: 0 0 50%; + + max-width: 50%; + } + + &[width-66], + &[width-67] { + flex: 0 0 66.6666%; + + max-width: 66.6666%; + } + + &[width-75] { + flex: 0 0 75%; + + max-width: 75%; + } + + &[width-80] { + flex: 0 0 80%; + + max-width: 80%; + } + + &[width-90] { + flex: 0 0 90%; + + max-width: 90%; + } +} + +// Responsive Grid Classes +// Adding a class of responsive-X to a row +// will trigger the width-direction to +// change to column and add some margin +// to any columns in the row for clearity + +@include responsive-grid-break('[responsive-sm]', $grid-responsive-sm-break); +@include responsive-grid-break('[responsive-md]', $grid-responsive-md-break); +@include responsive-grid-break('[responsive-lg]', $grid-responsive-lg-break); diff --git a/src/components/grid/grid.scss b/src/components/grid/grid.scss index 426ab0f1eb7..6e3bec50324 100644 --- a/src/components/grid/grid.scss +++ b/src/components/grid/grid.scss @@ -1,230 +1,92 @@ @import "../../themes/ionic.globals"; +@import "./grid.mixins"; + // Grid // -------------------------------------------------- -// Using flexbox for the grid, inspired by Philip Walton: +// Using flexbox for the grid, originally inspired by Philip Walton: // http://philipwalton.github.io/solved-by-flexbox/demos/grids/ -// By default each .col within a .row will evenly take up -// available width, and the height of each .col with take -// up the height of the tallest .col in the same .row. - - -$grid-padding-width: 10px !default; -$grid-responsive-sm-break: 567px !default; // smaller than landscape phone -$grid-responsive-md-break: 767px !default; // smaller than portrait tablet -$grid-responsive-lg-break: 1023px !default; // smaller than landscape tablet - -@mixin responsive-grid-break($selector, $max-width) { - @media (max-width: $max-width) { - #{$selector} { - flex-direction: column; - - ion-col { - &[width-10], - &[width-20], - &[width-25], - &[width-33], - &[width-34], - &[width-50], - &[width-66], - &[width-67], - &[width-75], - &[width-80], - &[width-90] { - flex: 1; - - margin-bottom: ($grid-padding-width * 3) / 2; - margin-left: 0; - - width: 100%; - max-width: 100%; - } - } - - } - } -} - -ion-grid { - display: flex; - - flex-direction: column; - - padding: ($grid-padding-width / 2); - - width: 100%; -} - -ion-row { - display: flex; - - width: 100%; +// Column layout based on the Bootstrap grid system: +// http://v4-alpha.getbootstrap.com/layout/grid/ - &[wrap] { - flex-wrap: wrap; - } - - &[top] { - align-items: flex-start; - } - - &[bottom] { - align-items: flex-end; - } - - &[center] { - align-items: center; - } - - &[stretch] { - align-items: stretch; - } - - &[baseline] { - align-items: baseline; - } -} - -ion-col { - display: block; - - flex: 1; - - padding: ($grid-padding-width / 2); - - width: 100%; - - // Column Alignment - - &[top] { - align-self: flex-start; - } - - &[bottom] { - align-self: flex-end; - } - - &[center] { - align-self: center; - } - - &[stretch] { - align-self: stretch; - } - - &[baseline] { - align-self: baseline; - } - // Column Offsets - - &[offset-10] { - margin-left: 10%; - } - - &[offset-20] { - margin-left: 20%; - } - - &[offset-25] { - margin-left: 25%; - } - - &[offset-33], - &[offset-34] { - margin-left: 33.3333%; - } - - &[offset-50] { - margin-left: 50%; - } - - &[offset-66], - &[offset-67] { - margin-left: 66.6666%; - } - - &[offset-75] { - margin-left: 75%; - } - - &[offset-80] { - margin-left: 80%; - } - - &[offset-90] { - margin-left: 90%; - } +// Grid Breakpoints +// -------------------------------------------------- - // Explicit Column Percent Sizes - // By default each grid column will evenly distribute - // across the grid. However, you can specify individual - // columns to take up a certain size of the available area +/// @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 +) !default; - &[width-10] { - flex: 0 0 10%; - max-width: 10%; - } +// Grid Containers +// -------------------------------------------------- - &[width-20] { - flex: 0 0 20%; +/// @prop - Maximum width of the grid for different screen sizes +$grid-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px +) !default; - max-width: 20%; - } - &[width-25] { - flex: 0 0 25%; +// Grid Columns +// -------------------------------------------------- - max-width: 25%; - } +/// @prop - Number of columns for the grid +$grid-columns: 12 !default; - &[width-33], - &[width-34] { - flex: 0 0 33.3333%; +/// @prop - Total width of the padding for the grid +$grid-padding-width: 10px !default; - max-width: 33.3333%; - } +/// @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 +) !default; - &[width-50] { - flex: 0 0 50%; - max-width: 50%; - } +// Check that the Sass maps are declared correctly +// -------------------------------------------------- - &[width-66], - &[width-67] { - flex: 0 0 66.6666%; +@include assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); - max-width: 66.6666%; - } +@include assert-ascending($grid-max-widths, "$grid-max-widths"); - &[width-75] { - flex: 0 0 75%; - max-width: 75%; - } +// Grid +// -------------------------------------------------- - &[width-80] { - flex: 0 0 80%; +.grid { + @include make-grid(); - max-width: 80%; + &[fixed] { + @include make-grid-max-widths(); } +} - &[width-90] { - flex: 0 0 90%; +// Row +// -------------------------------------------------- - max-width: 90%; - } +.row { + @include make-row(); } +// Columns +// -------------------------------------------------- -// Responsive Grid Classes -// Adding a class of responsive-X to a row -// will trigger the width-direction to -// change to column and add some margin -// to any columns in the row for clearity +.col { + @include make-column-base(); +} -@include responsive-grid-break('[responsive-sm]', $grid-responsive-sm-break); -@include responsive-grid-break('[responsive-md]', $grid-responsive-md-break); -@include responsive-grid-break('[responsive-lg]', $grid-responsive-lg-break); +@include make-grid-columns(); diff --git a/src/components/grid/grid.ts b/src/components/grid/grid.ts index 51cb758dfce..8add2cd8836 100644 --- a/src/components/grid/grid.ts +++ b/src/components/grid/grid.ts @@ -1,40 +1,520 @@ import { Directive } from '@angular/core'; /** - * @private * @name Grid * @module ionic * @description + * + * The grid is a powerful mobile-first flexbox system for building custom layouts. + * It is heavily influenced by [Bootstrap's grid system](http://v4-alpha.getbootstrap.com/layout/grid/). + * + * The grid is composed of three units — a grid, row(s) and column(s). Columns will expand to fill their + * row, and will resize to fit additional columns. It is based on a 12 column layout with different + * breakpoints based on the screen size. The number of columns and breakpoints can be fully customized + * using Sass. + * + * - [How it works](#how-it-works) + * - [Grid size](#grid-size) + * - [Grid attributes](#grid-attributes) + * - [Default breakpoints](#default-breakpoints) + * - [Auto-layout columns](#auto-layout-columns) + * - [Equal-width](#equal-width) + * - [Setting one column width](#setting-one-column-width) + * - [Variable-width](#variable-width) + * - [Responsive attributes](#responsive-attributes) + * - [All breakpoints](#all-breakpoints) + * - [Stacked to horizontal](#stacked-to-horizontal) + * - [Reordering](#reordering) + * - [Offsetting columns](#offsetting-columns) + * - [Push and pull](#push-and-pull) + * - [Alignment](#alignment) + * - [Vertical Alignment](#vertical-alignment) + * - [Horizontal Alignment](#horizontal-alignment) + * - [Customizing the grid](#customizing-the-grid) + * - [Number of columns and padding](#number-of-columns-and-padding) + * - [Grid tiers](#grid-tiers) + * + * ## How it works + * + * TODO + * + * + * ## Grid size + * + * By default, the grid will take up 100% width. To set a maximum width based on the screen + * size add the `fixed` attribute. The maximum width of the grid for each breakpoint is defined + * in the `$grid-max-widths` Sass variable. For more information, see + * [customizing the grid](#customizing-the-grid). + * + * | Name | Value | Description | + * |----------|----------|-----------------------------------------------------| + * | xs | auto | Don't set the grid width for xs screens | + * | sm | 540px | Set grid width to 540px when (min-width: 576px) | + * | md | 720px | Set grid width to 720px when (min-width: 768px) | + * | lg | 960px | Set grid width to 960px when (min-width: 992px) | + * | xl | 1140px | Set grid width to 1140px when (min-width: 1200px) | + * + * + * ## Grid attributes + * + * The grid takes up full width and has padding added to it based on the screen size. There are two + * attributes that can be used to adjust this behavior. + * + * | Property | Description | + * |-----------------|-------------------------------------------------------------------------------------------------------------------| + * | no-padding | Removes padding from the grid and immediate children columns. | + * | fixed | Set a max width based on the screen size. | + * + * + * ## Default breakpoints + * + * The default breakpoints are defined by the `$grid-breakpoints` Sass variable. It can be + * customized to use different values for the breakpoint, rename and add/remove breakpoints. + * For more information, see [customizing the grid](#customizing-the-grid). + * + * | Name | Value | Width Prefix | Offset Prefix | Push Prefix | Pull Prefix | Description | + * |----------|----------|--------------|---------------|--------------|-------------|---------------------------------------------------| + * | xs | 0 | `col-` | `offset-` | `push-` | `pull-` | Set columns when (min-width: 0) | + * | sm | 576px | `col-sm-` | `offset-sm-` | `push-sm-` | `pull-sm-` | Set columns when (min-width: 576px) | + * | md | 768px | `col-md-` | `offset-md-` | `push-md-` | `pull-md-` | Set columns when (min-width: 768px) | + * | lg | 992px | `col-lg-` | `offset-lg-` | `push-lg-` | `pull-lg-` | Set columns when (min-width: 992px) | + * | xl | 1200px | `col-xl-` | `offset-xl-` | `push-xl-` | `pull-xl-` | Set columns when (min-width: 1200px) | + * + * _Note: the first breakpoint must have the value set to 0 and all breakpoint values must be in + * ascending order._ + * + * ## Auto-layout columns + * + * ### Equal-width + * + * By default, columns will take up equal width inside of a row for all devices and screen sizes. + * + * ``` + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * + * 1 of 3 + * + * + * 2 of 3 + * + * + * 3 of 3 + * + * + * + * ``` + * + * ### Setting one column width + * + * Set the width of one column and the others will automatically resize around it. + * This can be done using our predefined grid attributes. In the example below, + * the other columns will resize no matter the width of the center column. + * + * ``` + * + * + * + * 1 of 3 + * + * + * 2 of 3 (wider) + * + * + * 3 of 3 + * + * + * + * + * 1 of 3 + * + * + * 2 of 3 (wider) + * + * + * 3 of 3 + * + * + * + * ``` + * + * ### Variable-width + * + * Using the `col-{breakpoint}-auto` attributes, the column can size itself based on the + * natural width of its content. This is extremely useful for setting a column width + * using pixels. The columns next to the variable-width column will resize to fill the row. + * + * ``` + * + * + * + * 1 of 3 + * + * + * Variable width content + * + * + * 3 of 3 + * + * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * + * + * + * 4 of 4 + * + * + * + * ``` + * + * + * ## Responsive attributes + * + * ### All breakpoints + * + * To customize a column's width for all devices and screens, add the `col-*` + * attribute. These attributes tell the column to take up `*` columns out + * of the available columns. + * + * ``` + * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * 3 of 4 + * + * + * 4 of 4 + * + * + * + * ``` + * + * ### Stacked to horizontal + * + * Use a combination of width and breakpoint attributes to create a grid that starts out stacked + * on extra small screens before becoming horizontal on small screens. + * + * ``` + * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * 3 of 4 + * + * + * 4 of 4 + * + * + * + * ``` + * + * + * ## Reordering + * + * ### Offseting columns + * + * Move columns to the right by adding the `offset-*` attributes. These attributes + * increase the margin left of the column by `*` columns. For example, in the following + * grid the last column will be offset by 3 columns and take up 3 columns: + * + * ``` + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * ``` + * + * Offsets can also be added based on screen breakpoints. Here's an example of a + * grid where the last column will be offset by 3 columns for `md` screens and up: + * + * ``` + * + * + * + * 1 of 3 + * + * + * 2 of 3 + * + * + * 3 of 3 + * + * + * + * ``` + * + * ### Push and pull + * + * Reorder the columns by adding the `push-*` and `pull-*` attributes. These attributes + * adjust the `left` and `right` of the columns by `*` columns making it easy to reorder + * columns. For example, in the following grid the column with the `1st col` description + * will actually be the last column and the `2nd col` will be the first column. + * + * ``` + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * ``` + * + * Push and pull can also be added based on screen breakpoints. In the following example, + * the column with the `3rd` column description will actually be the first column for + * `md` screens and up: + * + * ``` + * + * + * + * 1 of 3 + * + * + * 2 of 3 + * + * + * 3 of 3 + * + * + * + * ``` + * + * + * ## Alignment + * + * ### Vertical alignment + * + * All columns can be vertically aligned inside of a row by adding different + * attributes to the row. For a list of available attributes, see + * [row attributes](../Row#row-attributes). + * + * ``` + * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * 3 of 4 + * + * + * 4 of 4
#
#
# + *
+ *
+ * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * 3 of 4 + * + * + * 4 of 4
#
#
# + *
+ *
+ * + * + * + * 1 of 4 + * + * + * 2 of 4 + * + * + * 3 of 4 + * + * + * 4 of 4
#
#
# + *
+ *
+ *
+ * ``` + * + * Columns can be also align themselves differently than other columns by + * adding the alignment attribute directly to the column. For a list of available + * attributes, see [column attributes](../Col#column-attributes). + * + * ``` + * + * + * + *
+ * 1 of 4 + *
+ *
+ * + *
+ * 2 of 4 + *
+ *
+ * + *
+ * 3 of 4 + *
+ *
+ * + *
+ * 4 of 4
#
#
# + *
+ *
+ *
+ *
+ * ``` + * + * ### Horizontal alignment + * + * All columns can be horizontally aligned inside of a row by adding different + * attributes to the row. For a list of available attributes, see + * [row attributes](../Row#row-attributes). + * + * ``` + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * + * + * 1 of 2 + * + * + * 2 of 2 + * + * + * + * ``` + * + * + * ## Customizing the grid + * + * Using our built-in grid Sass variables and maps, it’s possible to completely customize + * the predefined grid attributes. Change the number of breakpoints, the media query values, + * the number of columns, and more. + * + * ### Number of columns and padding + * + * The number of grid columns and their padding can be modified via Sass variables. + * `$grid-columns` is used to generate the widths (in percent) of each individual column. + * `$grid-padding-width` is used for the padding on the grid, while `$grid-padding-widths` + * allows breakpoint-specific widths that are divided evenly across `padding-left` and + * `padding-right` as well as `pdading-top` and `padding-bottom` of the grid and columns. + * + * ``` + * $grid-columns: 12 !default; + * + * $grid-padding-width: 10px !default; + * + * $grid-padding-widths: ( + * xs: $grid-padding-width, + * sm: $grid-padding-width, + * md: $grid-padding-width, + * lg: $grid-padding-width, + * xl: $grid-padding-width + * ) !default; + * ``` + * + * ### Grid tiers + * + * To customize the breakpoints and their values, override the values of + * `$grid-breakpoints` and `$grid-max-widths`. For example, to only use + * 3 breakpoints, the following could be written: + * + * ``` + * $grid-breakpoints: ( + * sm: 480px, + * md: 768px, + * lg: 1024px + * ); + * + * $grid-max-widths: ( + * sm: 420px, + * md: 720px, + * lg: 960px + * ); + * ``` + * */ @Directive({ - selector: 'ion-grid' + selector: 'ion-grid, [ion-grid]', + host: { + 'class': 'grid' + } }) export class Grid { } - -/** - * @private - * @name Row - * @module ionic - * @description - */ -@Directive({ - selector: 'ion-row' -}) -export class Row { - -} - -/** - * @private - * @name Column - * @module ionic - * @description - */ -@Directive({ - selector: 'ion-col' -}) -export class Col { - -} diff --git a/src/components/grid/row.ts b/src/components/grid/row.ts new file mode 100644 index 00000000000..7f7a94bd80a --- /dev/null +++ b/src/components/grid/row.ts @@ -0,0 +1,40 @@ +import { Directive } from '@angular/core'; + +/** + * @name Row + * @module ionic + * @description + * + * Row description + * + * ## Row attributes + * + * By default, columns will stretch to fill the entire height of the row and wrap when necessary. + * There are several attributes that can be added to a row to customize this behavior. + * + * | Property | Description | + * |-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| + * | nowrap | Adds `flex-wrap: nowrap`. Forces the columns to a single row. | + * | wrap-reverse | Adds `flex-wrap: wrap-reverse`. The columns will wrap in reverse. | + * | align-items-start | Adds `align-items: flex-start`. All columns will be vertically aligned at the top, unless they specify their own alignment. | + * | align-items-center | Adds `align-items: center`. All columns will be vertically aligned in the center, unless they specify their own alignment. | + * | align-items-end | Adds `align-items: flex-end`. All columns will be vertically aligned at the bottom, unless they specify their own alignment. | + * | align-items-stretch | Adds `align-items: stretch`. All columns will be stretched to take up the entire height of the row, unless they specify their own alignment. | + * | align-items-baseline | Adds `align-items: baseline`. All columns will be vertically aligned at their baselines, unless they specify their own alignment. | + * | justify-content-start | Adds `justify-content: start`. All columns will be horrizontally aligned at the start. | + * | justify-content-center | Adds `justify-content: center`. All columns will be horrizontally aligned at the center. | + * | justify-content-end | Adds `justify-content: end`. All columns will be horrizontally aligned at the end. | + * | justify-content-around | Adds `justify-content: space-around`. All columns will be horrizontally aligned with equal space around them. | + * | justify-content-between | Adds `justify-content: space-between`. All columns will be horrizontally aligned with a half-size space on either end. | + * + * + */ +@Directive({ + selector: 'ion-row, [ion-row]', + host: { + 'class': 'row' + } +}) +export class Row { + +} diff --git a/src/components/grid/test/card/app.module.ts b/src/components/grid/test/card/app.module.ts new file mode 100644 index 00000000000..5f02e526639 --- /dev/null +++ b/src/components/grid/test/card/app.module.ts @@ -0,0 +1,40 @@ +import { Component, NgModule } from '@angular/core'; +import { IonicApp, IonicModule } from '../../../../../ionic-angular'; + + +@Component({ + templateUrl: 'main.html' +}) +export class Page1 { + items: any = []; + + constructor() { + for (let i = 0; i < 100; i++) { + this.items.push(i); + } + } +} + + +@Component({ + template: '' +}) +export class E2EApp { + rootPage = Page1; +} + +@NgModule({ + declarations: [ + E2EApp, + Page1 + ], + imports: [ + IonicModule.forRoot(E2EApp) + ], + bootstrap: [IonicApp], + entryComponents: [ + E2EApp, + Page1 + ] +}) +export class AppModule {} diff --git a/src/components/grid/test/card/main.html b/src/components/grid/test/card/main.html new file mode 100644 index 00000000000..a730ce0d744 --- /dev/null +++ b/src/components/grid/test/card/main.html @@ -0,0 +1,31 @@ + + + + Responsive Cards + + + + + + +
+
+
+ + + Card {{ item }} + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec scelerisque orci odio, vitae faucibus orci mollis eu. Donec tincidunt auctor iaculis. Maecenas in ante turpis. Mauris eget lacinia erat. Sed nulla urna, cursus sed ante eget, tincidunt facilisis nisl. In vulputate quam et augue egestas, vitae auctor elit commodo. + + +
+
+
+
+ + diff --git a/src/components/grid/test/responsive/app.module.ts b/src/components/grid/test/responsive/app.module.ts new file mode 100644 index 00000000000..c2d79c73aa1 --- /dev/null +++ b/src/components/grid/test/responsive/app.module.ts @@ -0,0 +1,34 @@ +import { Component, NgModule } from '@angular/core'; +import { IonicApp, IonicModule } from '../../../../../ionic-angular'; + + +@Component({ + templateUrl: 'main.html' +}) +export class Page1 { + +} + + +@Component({ + template: '' +}) +export class E2EApp { + rootPage = Page1; +} + +@NgModule({ + declarations: [ + E2EApp, + Page1 + ], + imports: [ + IonicModule.forRoot(E2EApp) + ], + bootstrap: [IonicApp], + entryComponents: [ + E2EApp, + Page1 + ] +}) +export class AppModule {} diff --git a/src/components/grid/test/responsive/main.html b/src/components/grid/test/responsive/main.html new file mode 100644 index 00000000000..edd1ae5cad8 --- /dev/null +++ b/src/components/grid/test/responsive/main.html @@ -0,0 +1,474 @@ + + + + Responsive + + + + + + + + + + Equal-width + + + Setting one column width + + + Variable-width + + + Offsetting columns + + + Push and pull + + + Responsive attributes + + + Vertical Alignment + + + Horizontal Alignment + + + + +
+

Equal-width

+

+ The following grid has equal width columns. +

+ + + + 1 of 2 + + + 2 of 2 + + + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + + +

Setting one column width

+

+ The following grid has a wider center column on each row. +

+ + + + 1 of 3 + + + 2 of 3 (wider) + + + 3 of 3 + + + + + 1 of 3 + + + 2 of 3 (wider) + + + 3 of 3 + + + + +

Variable-width

+

+ The following grid has columns that take up the width of their content.
+

+ + + + 1 of 3 + + + Variable width content + + + 3 of 3 + + + + + 1 of 4 + + + 2 of 4 + + + + + + 4 of 4 + + + + +

Offseting Columns

+

+ The following grid has columns that are offset on each row.
+

+ + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + + +

Push and pull

+

+ The following grid has columns that are reordered using push and pull.
+

+ + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + + +

Responsive attributes

+

+ The following grid adds custom widths for all screen sizes.
+

+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4 + + + + +

+ The following grid will take up 12 columns until the sm breakpoint (576px) at which point it will take equal width.
+

+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4 + + + + +

+ The following grid will take up 12 columns until the md breakpoint (768px) at which point it will take equal width.
+

+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4 + + + + +

+ The following grid will take up 12 columns until the lg breakpoint (992px) at which point it will change to take up 6 and 3 columns.
+

+ + + + 1 of 2 + + + 2 of 2 + + + + +

Vertical Alignment

+

+ The following grid has columns that align themselves vertically inside of the row based on the attribute.
+

+ + + + 1 of 4 + + + 2 of 4
# +
+ + 3 of 4
#
# +
+ + 4 of 4
#
#
# +
+
+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4
#
#
# +
+
+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4
#
#
# +
+
+ + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4
#
#
# +
+
+
+ + + + + 1 of 4 + + + 2 of 4 + + + 3 of 4 + + + 4 of 4
#
#
# +
+
+
+ +

Horizontal Alignment

+

+ The following grid has columns that align themselves horizontally inside of the row based on the attribute.
+

+ + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 2 + + + 2 of 2 + + + + + + 1 of 2 + + + 2 of 2 + + + + +

Miscellaneous Features

+

+ The following grid has no padding. +

+ + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + + +

+ The following grid reverses the order of the columns when wrapping on small screens. +

+ + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + + +

Columns Based on Screen Size

+

+ The following grid has columns that will change width based on the screen size.
+ If window size > 0 it will take up 12 columns / 100% width.
+ If window size > 768px it will take up 4 columns / 33% width.
+ If window size > 992px it the middle column will take up 6 columns / 50% width, other two will take up 3 columns / 25% width.
+

+ + + + 1 of 3 + + + 2 of 3 + + + 3 of 3 + + + +
+
+ + diff --git a/src/index.ts b/src/index.ts index 7bc83de2553..b3464dacbb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -67,7 +67,9 @@ import { ClickBlock } from './util/click-block'; import { Content } from './components/content/content'; import { DateTime } from './components/datetime/datetime'; import { FabContainer, FabButton, FabList } from './components/fab/fab'; -import { Grid, Row, Col } from './components/grid/grid'; +import { Col } from './components/grid/col'; +import { Grid } from './components/grid/grid'; +import { Row } from './components/grid/row'; import { Icon } from './components/icon/icon'; import { Img } from './components/img/img'; import { InfiniteScroll } from './components/infinite-scroll/infinite-scroll'; @@ -138,7 +140,9 @@ export { ClickBlock } from './util/click-block'; export { Content, ScrollEvent } from './components/content/content'; export { DateTime } from './components/datetime/datetime'; export { FabContainer, FabButton, FabList } from './components/fab/fab'; -export { Grid, Row, Col } from './components/grid/grid'; +export { Col } from './components/grid/col'; +export { Grid } from './components/grid/grid'; +export { Row } from './components/grid/row'; export { Ion } from './components/ion'; export { Icon } from './components/icon/icon'; export { Img } from './components/img/img'; diff --git a/src/themes/ionic.components.scss b/src/themes/ionic.components.scss index 47837c27cc7..9c6bdbaf04c 100644 --- a/src/themes/ionic.components.scss +++ b/src/themes/ionic.components.scss @@ -72,6 +72,7 @@ "../components/fab/fab.wp"; @import +"../components/grid/grid.old", "../components/grid/grid"; @import diff --git a/src/themes/ionic.mixins.scss b/src/themes/ionic.mixins.scss index 6079faf9922..49c981a9dc2 100644 --- a/src/themes/ionic.mixins.scss +++ b/src/themes/ionic.mixins.scss @@ -37,3 +37,33 @@ $url: url-encode($svg); background-image: url("data:image/svg+xml;charset=utf-8,#{$url}"); } + +// Check that the given map values are in ascending order +// --------------------------------------------------------------------------------- + +@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}."; + } +}