From cf240571830234f2358ac7b999cadea7dfa7c753 Mon Sep 17 00:00:00 2001 From: Brandy Carney Date: Fri, 14 Apr 2017 12:47:59 -0500 Subject: [PATCH] feat(app): add responsive utility attributes by screen size (#11228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - moves breakpoint mixins to the ionic.mixins file - adds responsive attributes for text alignment, transform, and floating elements - adds ability to turn these off so they don’t get added to the css file using sass variables references #10904 closes #10567 --- src/components/app/app.scss | 182 +++++++++++++----- .../app/test/utilities/app/app.component.ts | 10 + .../app/test/utilities/app/app.module.ts | 22 +++ src/components/app/test/utilities/app/main.ts | 5 + .../utilities/pages/root-page/root-page.html | 137 +++++++++++++ .../utilities/pages/root-page/root-page.ts | 8 + src/components/grid/grid.mixins.scss | 50 +---- src/themes/ionic.mixins.scss | 89 +++++++++ 8 files changed, 404 insertions(+), 99 deletions(-) create mode 100644 src/components/app/test/utilities/app/app.component.ts create mode 100644 src/components/app/test/utilities/app/app.module.ts create mode 100644 src/components/app/test/utilities/app/main.ts create mode 100644 src/components/app/test/utilities/pages/root-page/root-page.html create mode 100644 src/components/app/test/utilities/pages/root-page/root-page.ts diff --git a/src/components/app/app.scss b/src/components/app/app.scss index 3dffd60f81..5025d9116a 100644 --- a/src/components/app/app.scss +++ b/src/components/app/app.scss @@ -2,6 +2,7 @@ // Globals // -------------------------------------------------- @import "../../themes/ionic.globals"; +@import "../../themes/ionic.mixins"; // Normalize @@ -49,6 +50,36 @@ $h5-font-size: 1.8rem !default; $h6-font-size: 1.6rem !default; +// Responsive Utilities +// -------------------------------------------------- + +/// @prop - Whether to include all of the responsive utility attributes +$include-responsive-utilities: true !default; + +/// @prop - Whether to include all of the responsive text alignment attributes +$include-text-alignment-utilities: $include-responsive-utilities !default; + +/// @prop - Whether to include all of the responsive text transform attributes +$include-text-transform-utilities: $include-responsive-utilities !default; + +/// @prop - Whether to include all of the responsive float attributes +$include-float-element-utilities: $include-responsive-utilities !default; + + +// Screen Breakpoints +// -------------------------------------------------- + +/// @prop - 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; + + // App Structure // -------------------------------------------------- @@ -293,77 +324,128 @@ ion-footer { // Text Alignment // -------------------------------------------------- -[text-left] { - text-align: left; -} +@if ($include-text-alignment-utilities == true) { + // Creates text alignment attributes based on screen size + @each $breakpoint in map-keys($screen-breakpoints) { + $infix: breakpoint-infix($breakpoint, $screen-breakpoints); -[text-center] { - text-align: center; -} + @include media-breakpoint-up($breakpoint, $screen-breakpoints) { + // Provide `[text-{bp}]` attributes for aligning the text based + // on the breakpoint + [text#{$infix}-center] { + // scss-lint:disable ImportantRule + text-align: center !important; + } -[text-right] { - text-align: right; -} + [text#{$infix}-justify] { + // scss-lint:disable ImportantRule + text-align: justify !important; + } -[text-start] { - text-align: start; -} + [text#{$infix}-start] { + // scss-lint:disable ImportantRule + text-align: start !important; + } -[text-end] { - text-align: end; -} + [text#{$infix}-end] { + // scss-lint:disable ImportantRule + text-align: end !important; + } -[text-justify] { - text-align: justify; -} + [text#{$infix}-left] { + // scss-lint:disable ImportantRule + text-align: left !important; + } -[text-nowrap] { - white-space: nowrap; -} + [text#{$infix}-right] { + // scss-lint:disable ImportantRule + text-align: right !important; + } -[text-wrap] { - white-space: normal; + [text#{$infix}-nowrap] { + // scss-lint:disable ImportantRule + white-space: nowrap !important; + } + + [text#{$infix}-wrap] { + // scss-lint:disable ImportantRule + white-space: normal !important; + } + } + } } // Text Transformation // -------------------------------------------------- -[text-uppercase] { - text-transform: uppercase; +@if ($include-text-transform-utilities == true) { + // Creates text transform attributes based on screen size + @each $breakpoint in map-keys($screen-breakpoints) { + $infix: breakpoint-infix($breakpoint, $screen-breakpoints); + + @include media-breakpoint-up($breakpoint, $screen-breakpoints) { + // Provide `[text-{bp}]` attributes for transforming the text based + // on the breakpoint + [text#{$infix}-uppercase] { + // scss-lint:disable ImportantRule + text-transform: uppercase !important; + } + + [text#{$infix}-lowercase] { + // scss-lint:disable ImportantRule + text-transform: lowercase !important; + } + + [text#{$infix}-capitalize] { + // scss-lint:disable ImportantRule + text-transform: capitalize !important; + } + } + } } -[text-lowercase] { - text-transform: lowercase; -} -[text-capitalize] { - text-transform: capitalize; -} - -// Float +// Float Elements // -------------------------------------------------- -[pull-left] { - float: left; -} +@if ($include-float-element-utilities == true) { + // Creates text transform attributes based on screen size + @each $breakpoint in map-keys($screen-breakpoints) { + $infix: breakpoint-infix($breakpoint, $screen-breakpoints); -[pull-right] { - float: right; -} + @include media-breakpoint-up($breakpoint, $screen-breakpoints) { + // Provide `[pull-{bp}]` attributes for floating the element based + // on the breakpoint + [pull#{$infix}-left] { + // scss-lint:disable ImportantRule + float: left !important; + } -[pull-start] { - float: left; -} + [pull#{$infix}-right] { + // scss-lint:disable ImportantRule + float: right !important; + } -[pull-end] { - float: right; -} + [pull#{$infix}-start] { + // scss-lint:disable ImportantRule + float: left !important; + } -[dir="rtl"] [pull-start] { - float: right; -} + [pull#{$infix}-end] { + // scss-lint:disable ImportantRule + float: right !important; + } -[dir="rtl"] [pull-end] { - float: left; + [dir="rtl"] [pull#{$infix}-start] { + // scss-lint:disable ImportantRule + float: right !important; + } + + [dir="rtl"] [pull#{$infix}-end] { + // scss-lint:disable ImportantRule + float: left !important; + } + } + } } diff --git a/src/components/app/test/utilities/app/app.component.ts b/src/components/app/test/utilities/app/app.component.ts new file mode 100644 index 0000000000..9cd8e4cc10 --- /dev/null +++ b/src/components/app/test/utilities/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +import { RootPage } from '../pages/root-page/root-page'; + +@Component({ + template: `` +}) +export class AppComponent { + root = RootPage; +} diff --git a/src/components/app/test/utilities/app/app.module.ts b/src/components/app/test/utilities/app/app.module.ts new file mode 100644 index 0000000000..2863e8af61 --- /dev/null +++ b/src/components/app/test/utilities/app/app.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { IonicApp, IonicModule } from '../../../../..'; + +import { AppComponent } from './app.component'; +import { RootPage } from '../pages/root-page/root-page'; + +@NgModule({ + declarations: [ + AppComponent, + RootPage + ], + entryComponents: [ + RootPage + ], + imports: [ + BrowserModule, + IonicModule.forRoot(AppComponent, { statusbarPadding: true }) + ], + bootstrap: [IonicApp], +}) +export class AppModule {} diff --git a/src/components/app/test/utilities/app/main.ts b/src/components/app/test/utilities/app/main.ts new file mode 100644 index 0000000000..6af7a5b2ae --- /dev/null +++ b/src/components/app/test/utilities/app/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/src/components/app/test/utilities/pages/root-page/root-page.html b/src/components/app/test/utilities/pages/root-page/root-page.html new file mode 100644 index 0000000000..04fb9247db --- /dev/null +++ b/src/components/app/test/utilities/pages/root-page/root-page.html @@ -0,0 +1,137 @@ + + + Utilities + + + + + + +
text-center
+
+ +
text-sm-center
+
+ +
text-md-center
+
+ +
text-lg-center
+
+ +
text-xl-center
+
+
+ + + +
text-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap
+
+ +
text-sm-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap
+
+ +
text-md-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap
+
+ +
text-lg-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap
+
+ +
text-xl-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap
+
+
+ + + +
text-uppercase
+
+ +
text-sm-uppercase
+
+ +
text-md-uppercase
+
+ +
text-lg-uppercase
+
+ +
text-xl-uppercase
+
+
+ +
+
pull-left
+
pull-sm-left
+
pull-md-left
+
pull-lg-left
+
pull-xl-left
+
+ +
+
pull-right
+
pull-sm-right
+
pull-md-right
+
pull-lg-right
+
pull-xl-right
+
+ +
+
pull-start
+
pull-sm-start
+
pull-md-start
+
pull-lg-start
+
pull-xl-start
+
+ +
+
pull-end
+
pull-sm-end
+
pull-md-end
+
pull-lg-end
+
pull-xl-end
+
+ +
+
pull-start
+
pull-sm-start
+
pull-md-start
+
pull-lg-start
+
pull-xl-start
+
+ +
+
pull-end
+
pull-sm-end
+
pull-md-end
+
pull-lg-end
+
pull-xl-end
+
+
+ + \ No newline at end of file diff --git a/src/components/app/test/utilities/pages/root-page/root-page.ts b/src/components/app/test/utilities/pages/root-page/root-page.ts new file mode 100644 index 0000000000..f7d39edbee --- /dev/null +++ b/src/components/app/test/utilities/pages/root-page/root-page.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + templateUrl: 'root-page.html' +}) +export class RootPage { + constructor() { } +} diff --git a/src/components/grid/grid.mixins.scss b/src/components/grid/grid.mixins.scss index a19eb5b805..25c2a4f6d2 100644 --- a/src/components/grid/grid.mixins.scss +++ b/src/components/grid/grid.mixins.scss @@ -1,4 +1,5 @@ @import "../../themes/ionic.globals"; +@import "../../themes/ionic.mixins"; // Responsive Mixins // -------------------------------------------------- @@ -255,52 +256,3 @@ } } } - - -// 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/themes/ionic.mixins.scss b/src/themes/ionic.mixins.scss index 49c981a9dc..c3a5fc1e91 100644 --- a/src/themes/ionic.mixins.scss +++ b/src/themes/ionic.mixins.scss @@ -67,3 +67,92 @@ @warn "First value in `#{$map-name}` must start at 0, but starts at #{$first-value}."; } } + + +// 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. + +// --------------------------------------------------------------------------------- + + +// 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}"); +} + + +// 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); +} + + +// 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; + } +} + + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// The maximum value is calculated as the minimum of the next one less 0.1. +// +// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 767px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - 1px, null); +} + + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), 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) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} \ No newline at end of file