-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ 100% at sm, 75% at md, 50% at lg, 25% at xlg
+
+
+
+
+
+ Full Width
+
+
+ Span 4
+
+
+ Span 4
+
+
+ Span 4
+
+
+ Span 4
+
+
+
>
);
}
+
diff --git a/packages/grid/examples/css-grid/src/scss/_reset.scss b/packages/grid/examples/css-grid/src/scss/_reset.scss
index 905dcdb2dd54..67418b5d31b4 100644
--- a/packages/grid/examples/css-grid/src/scss/_reset.scss
+++ b/packages/grid/examples/css-grid/src/scss/_reset.scss
@@ -21,6 +21,6 @@ html, body {
body {
margin: 0;
font-family: 'IBM Plex Mono', monospace;
- padding: 1rem;
+ padding: 0;
}
diff --git a/packages/grid/examples/css-grid/src/scss/components/_header.scss b/packages/grid/examples/css-grid/src/scss/components/_header.scss
deleted file mode 100644
index e92c4872da4d..000000000000
--- a/packages/grid/examples/css-grid/src/scss/components/_header.scss
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright IBM Corp. 2018, 2018
-//
-// This source code is licensed under the Apache-2.0 license found in the
-// LICENSE file in the root directory of this source tree.
-//
-
-@use '@carbon/colors';
-@use '@carbon/grid/scss/modules/css-grid';
-
-.cds-header {
- --cds-header-background-color: #{colors.$gray-100};
- --cds-header-border-color: #{colors.$gray-80};
- --cds-header-text-color: #{colors.$gray-10};
- --cds-header-icon-color: #{colors.$gray-10};
-
- @include css-grid.css-grid();
- background-color: var(--cds-header-background-color);
- border-bottom: 1px solid var(--cds-header-border-color);
- height: 3rem;
-}
-
-.cds-header-label {
- color: var(--cds-header-text-color);
- text-decoration: none;
-}
diff --git a/packages/grid/examples/css-grid/src/styles.scss b/packages/grid/examples/css-grid/src/styles.scss
index d334d3f33687..aaa9e567161d 100644
--- a/packages/grid/examples/css-grid/src/styles.scss
+++ b/packages/grid/examples/css-grid/src/styles.scss
@@ -5,45 +5,87 @@
// LICENSE file in the root directory of this source tree.
//
+@use '@carbon/colors';
+@use '@carbon/grid';
@use 'scss/reset';
-@use '@carbon/grid/scss/modules/css-grid';
-@use 'scss/components';
-@import '@carbon/layout/scss/spacing';
-@import '@carbon/type/scss/styles';
-@import '~carbon-components/scss/globals/scss/vars';
+@include grid.css-grid();
// Grid
-.bx--css-grid {
- background-color: $blue-20;
- outline: 1px dashed $blue-40;
+.cds--css-grid {
+ background-color: colors.$blue-20;
+ outline: 1px dashed colors.$blue-40;
}
-.bx--css-grid.bx--css-grid--condensed {
- background-color: $purple-20;
- outline: 1px dashed $purple-40;
+.cds--css-grid.cds--css-grid--condensed {
+ background-color: colors.$purple-20;
+ outline: 1px dashed colors.$purple-40;
}
-// Only use background for subgrid example, not other subgrids in "mixed modes" example or others
-.bx--subgrid.example {
- background-color: $green-20;
+.cds--css-grid, .cds--subgrid--wide {
+ --grid-mode-color: #97C1FF;
+}
+
+.cds--css-grid--narrow,
+.cds--subgrid--narrow {
+ --grid-mode-color: #20D5D2;
+ background: colors.$green-10;
+}
+
+.cds--css-grid--condensed,
+.cds--subgrid--condensed {
+ --grid-mode-color: #BB8EFF;
+ background: colors.$purple-10;
}
// Columns
-.bx--css-grid > [class*='col'],
-.bx--subgrid > [class*='col'] {
+.cds--css-grid > [class*='col'],
+.cds--subgrid > [class*='col'] {
min-height: 80px;
}
-.bx--css-grid > [class*='col'] {
- background: $blue-10;
+.cds--subgrid {
+ outline: 1px solid black;
+ padding-top: 2rem;
+ padding-bottom: 2rem;
+ position: relative;
+ background: #EEF4FF;
+}
+
+.cds--subgrid--narrow {
+ background: #D6F9F9;
+}
+
+.cds--subgrid--condensed {
+ background: #F7F2FF;
+}
+
+.cds--subgrid::before {
+ position: absolute;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+ height: 1.25rem;
+ display: block;
+ content: 'subgrid';
+ background: var(--grid-mode-color, #97C1FF);
+ color: black;
+ font-size: 12px;
+ padding: 0 0.25rem;
+}
+
+.cds--css-grid-column {
+ --border-color: #97C1FF;
+
+ background: white;
+ box-shadow: 0 0 0 1px var(--border-color);
}
-.bx--subgrid > [class*='col'] {
- background: $green-10;
- outline: 1px dashed $green-30;
+.cds--css-grid--narrow .cds--css-grid-column,
+.cds--subgrid--narrow .cds--css-grid-column {
+ --border-color: #20D5D2;
}
-.bx--css-grid.bx--css-grid--condensed > [class*='col'] {
- background: $purple-10;
+.cds--css-grid--condensed .cds--css-grid-column,
+.cds--subgrid--condensed .cds--css-grid-column {
+ --border-color: #BB8EFF;
}
diff --git a/packages/grid/index.scss b/packages/grid/index.scss
index 8b6f9c3cb551..493712f54a0d 100644
--- a/packages/grid/index.scss
+++ b/packages/grid/index.scss
@@ -5,10 +5,7 @@
// LICENSE file in the root directory of this source tree.
//
-@forward 'scss/modules/config' with (
- $prefix: 'bx' !default,
- $flex-grid-columns: 16 !default,
-);
+@forward 'scss/modules/config';
@forward 'scss/modules/breakpoint';
@forward 'scss/modules/css-grid';
@forward 'scss/modules/flex-grid';
diff --git a/packages/grid/scss/modules/_breakpoint.scss b/packages/grid/scss/modules/_breakpoint.scss
index d21dcf048b66..5723834df205 100644
--- a/packages/grid/scss/modules/_breakpoint.scss
+++ b/packages/grid/scss/modules/_breakpoint.scss
@@ -5,25 +5,11 @@
// LICENSE file in the root directory of this source tree.
//
-// https://github.com/twbs/bootstrap/blob/v4-dev/scss/mixins/_breakpoints.scss
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use '@carbon/layout/scss/modules/convert';
-
-/// Map deep get
-/// @author Hugo Giraudel
-/// @access public
-/// @param {Map} $map - Map
-/// @param {Arglist} $keys - Key chain
-/// @return {*} Desired value
-/// @group @carbon/layout
-@function map-deep-get($map, $keys...) {
- @each $key in $keys {
- $map: map.get($map, $key);
- }
- @return $map;
-}
+@use 'config' as *;
/// Provide a map and index, and get back the relevant key value
/// @access public
@@ -31,65 +17,11 @@
/// @param {Integer} $index - Key chain
/// @return {String} Desired value
/// @group @carbon/layout
-@function key-by-index($map, $index) {
+@function -key-by-index($map, $index) {
$keys: map.keys($map);
@return nth($keys, $index);
}
-/// Pass in a map, and get the last one in the list back
-/// @access public
-/// @param {Map} $map - Map
-/// @return {*} Desired value
-/// @group @carbon/layout
-@function last-map-item($map) {
- $total-length: list.length($map);
- @return map-get($map, key-by-index($map, $total-length));
-}
-
-/// Carbon gutter size in rem
-/// @type Number
-/// @access public
-/// @group @carbon/layout
-$grid-gutter: convert.rem(32px);
-
-/// Carbon condensed gutter size in rem
-/// @type Number
-/// @access public
-/// @group @carbon/layout
-$grid-gutter--condensed: convert.rem(1px);
-
-// Initial map of our breakpoints and their values
-/// @type Map
-/// @access public
-/// @group @carbon/layout
-$grid-breakpoints: (
- sm: (
- columns: 4,
- margin: 0,
- width: convert.rem(320px),
- ),
- md: (
- columns: 8,
- margin: convert.rem(16px),
- width: convert.rem(672px),
- ),
- lg: (
- columns: 16,
- margin: convert.rem(16px),
- width: convert.rem(1056px),
- ),
- xlg: (
- columns: 16,
- margin: convert.rem(16px),
- width: convert.rem(1312px),
- ),
- max: (
- columns: 16,
- margin: convert.rem(24px),
- width: convert.rem(1584px),
- ),
-) !default;
-
/// Get the value of the next breakpoint, or null for the last breakpoint
/// @param {String} $name - The name of the breakpoint
/// @param {Map} $breakpoints [$grid-breakpoints] - A map of breakpoints where the key is the name of the breakpoint and the value is the values for the breakpoint
@@ -145,7 +77,7 @@ $grid-breakpoints: (
/// @group @carbon/layout
@function largest-breakpoint-name($breakpoints: $grid-breakpoints) {
$total-breakpoints: list.length($breakpoints);
- @return key-by-index($breakpoints, $total-breakpoints);
+ @return -key-by-index($breakpoints, $total-breakpoints);
}
/// Get the infix for a given breakpoint in a list of breakpoints. Useful for generating the size part in a selector, for example: `.prefix--col-sm-2`.
diff --git a/packages/grid/scss/modules/_config.scss b/packages/grid/scss/modules/_config.scss
index f7f9f748cb01..00efeb0c459d 100644
--- a/packages/grid/scss/modules/_config.scss
+++ b/packages/grid/scss/modules/_config.scss
@@ -5,14 +5,90 @@
// LICENSE file in the root directory of this source tree.
//
+@use 'sass:map';
+@use '@carbon/layout/scss/modules/convert';
+
/// Namespace prefix
/// @type String
/// @access public
/// @group @carbon/grid
-$prefix: 'bx' !default;
+$prefix: 'cds' !default;
/// Total columns used in the flex grid
/// @type Number
/// @access public
/// @group @carbon/grid
$flex-grid-columns: 16 !default;
+
+/// Carbon gutter size in rem
+/// @type Number
+/// @access public
+/// @group @carbon/layout
+$grid-gutter: convert.rem(32px) !default;
+
+/// Carbon condensed gutter size in rem
+/// @type Number
+/// @access public
+/// @group @carbon/layout
+$grid-gutter-condensed: convert.rem(1px) !default;
+
+// Initial map of our breakpoints and their values
+/// @type Map
+/// @access public
+/// @group @carbon/layout
+$grid-breakpoints: (
+ sm: (
+ columns: 4,
+ margin: 0,
+ width: convert.rem(320px),
+ ),
+ md: (
+ columns: 8,
+ margin: convert.rem(16px),
+ width: convert.rem(672px),
+ ),
+ lg: (
+ columns: 16,
+ margin: convert.rem(16px),
+ width: convert.rem(1056px),
+ ),
+ xlg: (
+ columns: 16,
+ margin: convert.rem(16px),
+ width: convert.rem(1312px),
+ ),
+ max: (
+ columns: 16,
+ margin: convert.rem(24px),
+ width: convert.rem(1584px),
+ ),
+) !default;
+
+@if $flex-grid-columns == 12 {
+ $grid-breakpoints: map.merge(
+ $grid-breakpoints,
+ (
+ lg:
+ map.merge(
+ map.get($grid-breakpoints, lg),
+ (
+ columns: 12,
+ )
+ ),
+ xlg:
+ map.merge(
+ map.get($grid-breakpoints, xlg),
+ (
+ columns: 12,
+ )
+ ),
+ max:
+ map.merge(
+ map.get($grid-breakpoints, max),
+ (
+ columns: 12,
+ )
+ ),
+ )
+ );
+}
diff --git a/packages/grid/scss/modules/_css-grid.scss b/packages/grid/scss/modules/_css-grid.scss
index b2eaf5e5e0a4..086b057c2911 100644
--- a/packages/grid/scss/modules/_css-grid.scss
+++ b/packages/grid/scss/modules/_css-grid.scss
@@ -7,341 +7,464 @@
@use 'sass:list';
@use 'sass:map';
-@use "sass:math";
+@use 'sass:math';
@use 'sass:meta';
@use 'config' as *;
@use 'breakpoint' as *;
-@mixin css-grid() {
- display: grid;
- max-width: 99rem;
- padding-right: calc(var(--cds-grid-margin) + var(--cds-grid-gutter) / 2);
- padding-left: calc(var(--cds-grid-margin) + var(--cds-grid-gutter) / 2);
- margin-right: auto;
- margin-left: auto;
- column-gap: var(--cds-grid-gutter);
- grid-template-columns: repeat(
- var(--cds-grid-columns),
- minmax(0, var(--cds-grid-column-size))
- );
-}
-
-@mixin subgrid() {
- display: grid;
- column-gap: var(--cds-grid-gutter);
- grid-template-columns: repeat(
- var(--cds-grid-columns),
- minmax(0, var(--cds-grid-column-size))
- );
-}
-
-:root {
- --cds-grid-columns: 4;
- --cds-grid-column-size: 1fr;
- --cds-grid-gutter: 2rem;
- // Used to configure appropriate margins for condensed subgrids inside wide grids
- --cds-grid-gutter-wide: 2rem;
- --cds-grid-hang: 1rem;
- --cds-grid-margin: 0;
-
- @include breakpoint(md) {
- --cds-grid-columns: 8;
- --cds-grid-margin: 1rem;
+/// Emit all the styles related to the CSS Grid, these include:
+/// - The base grid class
+/// - The various grid modes
+/// - The ability to specifiy column span
+/// - The ability to specifiy column start,end position
+/// - Support for subgrid
+/// - Support for hanging content on a grid column
+/// - Support for controlling grid gutter on a cell basis
+/// - Support for specifying content alignment
+///
+///
+/// In general, this mixin is structured in a way to emit the fewest CSS styles
+/// as possible. To do this, we will (as much as possible) not emit a value if
+/// one is already defined at a previous breakpoint.
+///
+/// In addition, this mixin will break down emitting styles into several stages:
+/// 1. Emit styles for the smallest breakpoint without any breakpoint. By
+/// default, these styles will be on
+/// 2. For every other breakpoint, wrap it in a breakpoint so that it only is
+/// triggered when that breakpoint is applied
+/// 3. In situations where it is appropriate, we also will emit "unconditional"
+/// selectors that will always apply. For example, if you wanted a column to
+/// always span four columns
+@mixin css-grid($breakpoints: $grid-breakpoints) {
+ /// The :root selector is responsible for setting several top-level CSS Custom
+ /// Properties, including the overall grid gutter, grid column count, and grid
+ /// margin
+ :root {
+ --cds-grid-gutter: #{$grid-gutter};
+
+ // Iterate through the grid breakpoints and only emit the grid-columns and
+ // grid-margin CSS Custom Properties if they've changed from the previous
+ // breakpoint. By default, we emit the smallest breakpoint values on the
+ // :root selector
+ @each $key, $value in $breakpoints {
+ @if is-smallest-breakpoint($key, $breakpoints) {
+ --cds-grid-columns: #{get-column-count($breakpoints, $key)};
+ --cds-grid-margin: #{get-margin($breakpoints, $key)};
+ } @else {
+ $previous-breakpoint: breakpoint-prev($key, $breakpoints);
+ $changes: ();
+
+ @if get-column-count($breakpoints, $key) !=
+ get-column-count($breakpoints, $previous-breakpoint)
+ {
+ $changes: map.set(
+ $changes,
+ grid-columns,
+ get-column-count($breakpoints, $key)
+ );
+ }
+
+ @if get-margin($breakpoints, $key) !=
+ get-margin($breakpoints, $previous-breakpoint)
+ {
+ $changes: map.set(
+ $changes,
+ grid-margin,
+ get-margin($breakpoints, $key)
+ );
+ }
+
+ @include breakpoint($key) {
+ @each $name, $value in $changes {
+ --cds-#{$name}: #{$value};
+ }
+ }
+ }
+ }
}
- @include breakpoint(lg) {
- --cds-grid-columns: 16;
+ // -----------------------------------------------------------------------------
+ // Base CSS Grid
+ // -----------------------------------------------------------------------------
+ .#{$prefix}--css-grid {
+ --cds-grid-gutter-start: calc(var(--cds-grid-gutter) / 2);
+ --cds-grid-gutter-end: calc(var(--cds-grid-gutter) / 2);
+ // We split out a separate "column hang" since "gutter-start" is set
+ // dynamically and could be 0
+ --cds-grid-column-hang: calc(var(--cds-grid-gutter) / 2);
+
+ display: grid;
+ max-width: get-grid-width(
+ $breakpoints,
+ largest-breakpoint-name($breakpoints)
+ );
+ padding-right: var(--cds-grid-margin);
+ padding-left: var(--cds-grid-margin);
+ margin-right: auto;
+ margin-left: auto;
+ grid-template-columns: repeat(var(--cds-grid-columns), minmax(0, 1fr));
}
- @include breakpoint(max) {
- --cds-grid-margin: 1.5rem;
+ // -----------------------------------------------------------------------------
+ // Full width
+ // -----------------------------------------------------------------------------
+ .#{$prefix}--css-grid--full-width {
+ max-width: 100%;
}
-}
-.#{$prefix}--css-grid {
- @include css-grid();
-}
-
-.#{$prefix}--css-grid--12 {
- @include css-grid();
- @include breakpoint(lg) {
- --cds-grid-columns: 12;
+ // -----------------------------------------------------------------------------
+ // Column
+ // -----------------------------------------------------------------------------
+
+ // Add gutter to columns in a CSS Grid. Unfortunately, we cannot use
+ // `grid-gap`, `column-gap`, etc. as we need to conditionally remove leading
+ // and trailing gutter from a column.
+ .#{$prefix}--css-grid-column {
+ // grid-mode-start, grid-mode-end are meant to capture the "grid settings"
+ // so that subgrids can correctly fit in parent grids by reverting the
+ // grid's outer padding
+ --cds-grid-mode-start: var(--cds-grid-gutter-start);
+ --cds-grid-mode-end: var(--cds-grid-gutter-end);
+
+ margin-right: var(--cds-grid-gutter-end);
+ margin-left: var(--cds-grid-gutter-start);
+
+ [dir='rtl'] & {
+ margin-right: var(--cds-grid-gutter-start);
+ margin-left: var(--cds-grid-gutter-end);
+ }
}
-}
-
-.#{$prefix}--subgrid {
- @include subgrid();
-}
-.#{$prefix}--subgrid[class*='col'] {
- display: grid;
-}
-
-// -----------------------------------------------------------------------------
-// Condensed
-// -----------------------------------------------------------------------------
-.#{$prefix}--css-grid--condensed {
- --cds-grid-gutter: 1px;
-
- column-gap: var(--cds-grid-gutter);
- row-gap: var(--cds-grid-gutter);
-}
+ // -----------------------------------------------------------------------------
+ // Grid modes
+ // -----------------------------------------------------------------------------
-// condensed subgrid inside wide
-.#{$prefix}--css-grid .bx--subgrid.#{$prefix}--css-grid--condensed {
- margin-right: calc((var(--cds-grid-gutter-wide) / 2) * -1);
- margin-left: calc((var(--cds-grid-gutter-wide) / 2) * -1);
-}
-
-// -----------------------------------------------------------------------------
-// No Gutter
-// -----------------------------------------------------------------------------
-.#{$prefix}--css-grid--no-gutter {
- // This is set to 0px (versus 0) so that the calc expression for padding for
- // a grid container works as expected. Without the unit, the calc() will
- // result in a value of 0.
- // stylelint-disable-next-line length-zero-no-unit
- --cds-grid-gutter: 0px;
-
- column-gap: var(--cds-grid-gutter);
-}
-
-// -----------------------------------------------------------------------------
-// Full width
-// -----------------------------------------------------------------------------
-.#{$prefix}--css-grid--full-width {
- max-width: 100%;
-}
-
-// -----------------------------------------------------------------------------
-// Column span
-// -----------------------------------------------------------------------------
-@mixin -column-span($i) {
- @if $i == 0 {
- display: none;
- } @else {
- --cds-grid-columns: #{$i};
+ // Narrow
+ .#{$prefix}--css-grid--narrow {
+ --cds-grid-gutter-start: 0;
+ }
- display: block;
- grid-column: span $i / span $i;
+ // Condensed
+ .#{$prefix}--css-grid--condensed {
+ --cds-grid-gutter: #{$grid-gutter-condensed};
+ --cds-grid-column-hang: #{math.div($grid-gutter, 2) -
+ math.div($grid-gutter-condensed, 2)};
}
-}
-@for $i from 0 through 16 {
- .#{$prefix}--col-span-#{$i} {
- @include -column-span($i);
+ // -----------------------------------------------------------------------------
+ // Subgrid
+ // -----------------------------------------------------------------------------
+ .#{$prefix}--subgrid {
+ display: grid;
+ margin-right: calc(var(--cds-grid-mode-end) * -1);
+ margin-left: calc(var(--cds-grid-mode-start) * -1);
+ grid-template-columns: repeat(var(--cds-grid-columns), minmax(0, 1fr));
+
+ [dir='rtl'] & {
+ margin-right: calc(var(--cds-grid-mode-start) * -1);
+ margin-left: calc(var(--cds-grid-mode-end) * -1);
+ }
}
-}
-.#{$prefix}--col-span-auto {
- grid-column: auto;
-}
+ // Support the grid modes in subgrids
+ .#{$prefix}--subgrid--wide {
+ --cds-grid-gutter-start: #{math.div($grid-gutter, 2)};
+ --cds-grid-gutter-end: #{math.div($grid-gutter, 2)};
+ --cds-grid-column-hang: 0;
+ }
-.#{$prefix}--col-span-100 {
- grid-column: 1 / -1;
-}
+ .#{$prefix}--subgrid--narrow {
+ --cds-grid-gutter-start: 0;
+ --cds-grid-gutter-end: #{math.div($grid-gutter, 2)};
+ --cds-grid-column-hang: #{math.div($grid-gutter, 2)};
+ }
-.#{$prefix}--col-span-25 {
- --cds-grid-columns: 1;
+ .#{$prefix}--subgrid--condensed {
+ --cds-grid-gutter-start: #{math.div($grid-gutter-condensed, 2)};
+ --cds-grid-gutter-end: #{math.div($grid-gutter-condensed, 2)};
+ --cds-grid-column-hang: #{math.div($grid-gutter, 2) -
+ math.div($grid-gutter-condensed, 2)};
+ }
- grid-column: span 1;
+ // -----------------------------------------------------------------------------
+ // Column hang
+ // -----------------------------------------------------------------------------
- @include breakpoint(md) {
- --cds-grid-columns: 2;
+ // Helper class to allow for text alignment in columns where the leading
+ // gutter is missing (like narrow) or is reduced (like in condensed).
+ .#{$prefix}--grid-column-hang {
+ margin-left: var(--cds-grid-column-hang);
- grid-column: span 2;
+ [dir='rtl'] & {
+ margin-right: var(--cds-grid-column-hang);
+ margin-left: initial;
+ }
}
- @include breakpoint(lg) {
- --cds-grid-columns: 4;
+ // -----------------------------------------------------------------------------
+ // Column span
+ // -----------------------------------------------------------------------------
- grid-column: span 4;
+ // Generate col-span-{0-16} classes which unconditionally set column span
+ // regardless of breakpoint
+ @for $i from 0 through get-grid-columns($breakpoints) {
+ .#{$prefix}--col-span-#{$i} {
+ @include -column-span($i);
+ }
}
-}
-.#{$prefix}--col-span-50 {
- --cds-grid-columns: 2;
-
- grid-column: span 2;
+ // Responsive column span
+ @each $name, $value in $breakpoints {
+ // Column span per breakpoint
+ @for $i from 0 through get-column-count($breakpoints, $name) {
+ @if is-smallest-breakpoint($name, $breakpoints) {
+ .#{$prefix}--#{$name}\:col-span-#{$i} {
+ @include -column-span($i);
+ }
+ } @else {
+ @include breakpoint($name) {
+ .#{$prefix}--#{$name}\:col-span-#{$i} {
+ @include -column-span($i);
+ }
+ }
+ }
+ }
- @include breakpoint(md) {
- --cds-grid-columns: 4;
+ // Percent column span per breakpoint
+ @if is-smallest-breakpoint($name, $breakpoints) {
+ .#{$prefix}--#{$name}\:col-span-auto {
+ grid-column: auto;
+ }
- grid-column: span 4;
- }
+ .#{$prefix}--#{$name}\:col-span-100 {
+ grid-column: 1 / -1;
+ }
- @include breakpoint(lg) {
- --cds-grid-columns: 8;
+ $columns: get-column-count($breakpoints, $name);
- grid-column: span 8;
- }
-}
+ .#{$prefix}--#{$name}\:col-span-75 {
+ $span: $columns * 0.75;
+ --cds-grid-columns: #{$span};
-.#{$prefix}--col-span-75 {
- --cds-grid-columns: 3;
+ grid-column: span #{$span} / span #{$span};
+ }
- grid-column: span 3;
+ .#{$prefix}--#{$name}\:col-span-50 {
+ $span: $columns * 0.5;
+ --cds-grid-columns: #{$span};
- @include breakpoint(md) {
- --cds-grid-columns: 6;
+ grid-column: span #{$span} / span #{$span};
+ }
- grid-column: span 6;
- }
+ .#{$prefix}--#{$name}\:col-span-25 {
+ $span: $columns * 0.25;
+ --cds-grid-columns: #{$span};
- @include breakpoint(lg) {
- --cds-grid-columns: 12;
+ grid-column: span #{$span} / span #{$span};
+ }
+ } @else {
+ @include breakpoint($name) {
+ .#{$prefix}--#{$name}\:col-span-auto {
+ grid-column: auto;
+ }
- grid-column: span 12;
- }
-}
+ .#{$prefix}--#{$name}\:col-span-100 {
+ grid-column: 1 / -1;
+ }
-@each $name, $value in $grid-breakpoints {
- $columns: map.get($value, columns);
+ $columns: get-column-count($breakpoints, $name);
- @include breakpoint($name) {
- @for $i from 0 through $columns {
- .#{$prefix}--#{$name}\:col-span-#{$i} {
- @include -column-span($i);
- }
- }
+ .#{$prefix}--#{$name}\:col-span-75 {
+ $span: $columns * 0.75;
+ --cds-grid-columns: #{$span};
- .#{$prefix}--#{$name}\:col-span-auto {
- grid-column: auto;
- }
+ grid-column: span #{$span} / span #{$span};
+ }
- .#{$prefix}--#{$name}\:col-span-100 {
- grid-column: 1 / -1;
- }
+ .#{$prefix}--#{$name}\:col-span-50 {
+ $span: $columns * 0.5;
+ --cds-grid-columns: #{$span};
- $quarterGridColumns: math.div($columns, 4);
+ grid-column: span #{$span} / span #{$span};
+ }
- .#{$prefix}--#{$name}\:col-span-75 {
- $calc: $quarterGridColumns * 3;
- --cds-grid-columns: #{$calc};
+ .#{$prefix}--#{$name}\:col-span-25 {
+ $span: $columns * 0.25;
+ --cds-grid-columns: #{$span};
- grid-column: span $calc / span $calc;
+ grid-column: span #{$span} / span #{$span};
+ }
+ }
}
+ }
- .#{$prefix}--#{$name}\:col-span-50 {
- $calc: $quarterGridColumns * 2;
- --cds-grid-columns: #{$calc};
+ // -----------------------------------------------------------------------------
+ // Column percent span
+ // -----------------------------------------------------------------------------
+ .#{$prefix}--col-span-auto {
+ grid-column: auto;
+ }
- grid-column: span $calc / span $calc;
- }
+ .#{$prefix}--col-span-100 {
+ grid-column: 1 / -1;
+ }
- .#{$prefix}--#{$name}\:col-span-25 {
- --cds-grid-columns: #{$quarterGridColumns};
+ .#{$prefix}--col-span-75 {
+ @include -percent-column-span($breakpoints, 0.75);
+ }
- grid-column: span $quarterGridColumns / span $quarterGridColumns;
- }
+ .#{$prefix}--col-span-50 {
+ @include -percent-column-span($breakpoints, 0.5);
}
-}
-// -----------------------------------------------------------------------------
-// Column offset
-// -----------------------------------------------------------------------------
-@for $i from 1 through 17 {
- .#{$prefix}--col-start-#{$i} {
- grid-column-start: $i;
+ .#{$prefix}--col-span-25 {
+ @include -percent-column-span($breakpoints, 0.25);
}
- .#{$prefix}--col-end-#{$i} {
- grid-column-start: $i;
+ // -----------------------------------------------------------------------------
+ // Column offset
+ // -----------------------------------------------------------------------------
+ // Unconditional column start
+ // Note: we start at 1 and end at column-count to match grid lines. We do not
+ // start at column-count + 1 since starting at the end of the grid would mean
+ // a column would have no width available
+ @for $i from 1 through get-grid-columns($breakpoints) {
+ .#{$prefix}--col-start-#{$i} {
+ grid-column-start: $i;
+ }
}
-}
-.#{$prefix}--col-start-auto {
- grid-column-start: auto;
-}
+ // Unconditional column end
+ // Note: we start at 2 since a column ending at line 1 would have no width. We
+ // end at column-count + 1 since grid lines start at 1
+ @for $i from 2 through get-grid-columns($breakpoints) + 1 {
+ .#{$prefix}--col-end-#{$i} {
+ grid-column-end: $i;
+ }
+ }
-.#{$prefix}--col-end-auto {
- grid-column-start: end;
-}
+ .#{$prefix}--col-start-auto {
+ grid-column-start: auto;
+ }
-@each $name, $value in $grid-breakpoints {
- $columns: map.get($value, columns);
+ .#{$prefix}--col-end-auto {
+ grid-column-end: auto;
+ }
- @include breakpoint($name) {
- // The `grid-column-start` property is *not* inclusive.
- // It starts the column *at* the column, not *on* the column. We must
- // ensure that there is one additional class available for each breakpoint.
- @for $i from 1 through $columns + 1 {
- .#{$prefix}--#{$name}\:col-start-#{$i} {
- grid-column-start: $i;
+ // Responsive column start, end
+ @each $name, $value in $breakpoints {
+ @if is-smallest-breakpoint($name, $breakpoints) {
+ // Responsive column start
+ @for $i from 1 through get-grid-columns($breakpoints) {
+ .#{$prefix}--#{$name}\:col-start-#{$i} {
+ grid-column-start: $i;
+ }
}
- .#{$prefix}--#{$name}\:col-end-#{$i} {
- grid-column-end: $i;
+ // Responsive column end
+ @for $i from 2 through get-grid-columns($breakpoints) + 1 {
+ .#{$prefix}--#{$name}\:col-end-#{$i} {
+ grid-column-end: $i;
+ }
}
- }
- .#{$prefix}--#{$name}\:col-start-auto {
- grid-column-start: auto;
- }
+ .#{$prefix}--#{$name}\:col-start-auto {
+ grid-column-start: auto;
+ }
- .#{$prefix}--#{$name}\:col-end-auto {
- grid-column-start: end;
+ .#{$prefix}--#{$name}\:col-end-auto {
+ grid-column-end: auto;
+ }
+ } @else {
+ @include breakpoint($name) {
+ // Responsive column start
+ @for $i from 1 through get-grid-columns($breakpoints) {
+ .#{$prefix}--#{$name}\:col-start-#{$i} {
+ grid-column-start: $i;
+ }
+ }
+
+ // Responsive column end
+ @for $i from 2 through get-grid-columns($breakpoints) + 1 {
+ .#{$prefix}--#{$name}\:col-end-#{$i} {
+ grid-column-end: $i;
+ }
+ }
+
+ .#{$prefix}--#{$name}\:col-start-auto {
+ grid-column-start: auto;
+ }
+
+ .#{$prefix}--#{$name}\:col-end-auto {
+ grid-column-end: auto;
+ }
+ }
}
}
}
-// -----------------------------------------------------------------------------
-// Hang
-// -----------------------------------------------------------------------------
-.#{$prefix}--hang {
- padding-left: var(--cds-grid-hang);
-}
-
-// -----------------------------------------------------------------------------
-// Column gutter
-// -----------------------------------------------------------------------------
-.#{$prefix}--gutter {
- padding-right: var(--cds-grid-hang);
- padding-left: var(--cds-grid-hang);
-}
-
-.#{$prefix}--gutter-start {
- padding-left: var(--cds-grid-hang);
-}
+/// Generate the styles for a grid column
+@mixin -column-span($i) {
+ @if $i == 0 {
+ display: none;
+ } @else {
+ --cds-grid-columns: #{$i};
-[dir='rtl'] .#{$prefix}--gutter-start {
- padding-right: var(--cds-grid-hang);
+ display: block;
+ grid-column: span $i / span $i;
+ }
}
-.#{$prefix}--gutter-end {
- padding-right: var(--cds-grid-hang);
-}
+/// Generate the styles for an unconditional class that represents a percent
+/// span of a grid
+@mixin -percent-column-span($breakpoints, $percent) {
+ @each $key, $value in $breakpoints {
+ $columns: get-column-count($breakpoints, $key);
+ $span: $columns * $percent;
-[dir='rtl'] .#{$prefix}--gutter-end {
- padding-left: var(--cds-grid-hang);
-}
+ @if is-smallest-breakpoint($key, $breakpoints) {
+ --cds-grid-columns: #{$span};
-// -----------------------------------------------------------------------------
-// Utilities
-// -----------------------------------------------------------------------------
+ grid-column: span #{$span} / span #{$span};
+ } @else {
+ $previous-breakpoint: breakpoint-prev($key, $breakpoints);
+ $previous-column-count: get-column-count(
+ $breakpoints,
+ $previous-breakpoint
+ );
+ $previous-span: $previous-column-count * $percent;
-/// Justify items
-.#{$prefix}--justify-items-start {
- justify-items: start;
-}
+ @if $span != $previous-span {
+ @include breakpoint($key) {
+ --cds-grid-columns: #{$span};
-.#{$prefix}--justify-items-end {
- justify-items: end;
+ grid-column: span #{$span} / span #{$span};
+ }
+ }
+ }
+ }
}
-.#{$prefix}--justify-items-center {
- justify-items: center;
+/// Get the grid width for a specific breakpoint name
+@function get-grid-width($breakpoints, $breakpoint) {
+ @return map.get(map.get($breakpoints, $breakpoint), width);
}
-/// Align items
-.#{$prefix}--align-items-start {
- align-items: start;
+/// Get the grid column count for a specific breakpoint name
+@function get-column-count($breakpoints, $breakpoint) {
+ @return map.get(map.get($breakpoints, $breakpoint), columns);
}
-.#{$prefix}--align-items-end {
- align-items: end;
+/// Get the grid margin for a specific breakpoint name
+@function get-margin($breakpoints, $breakpoint) {
+ $value: map.get(map.get($breakpoints, $breakpoint), margin);
+ @if $value == 0 {
+ @return 0;
+ }
+ @return $value;
}
-.#{$prefix}--align-items-center {
- align-items: center;
+/// Return the largest column count from a set of breakpoints
+@function get-grid-columns($breakpoints) {
+ @return get-column-count($breakpoints, largest-breakpoint-name($breakpoints));
}
diff --git a/packages/grid/scss/modules/_flex-grid.scss b/packages/grid/scss/modules/_flex-grid.scss
index c3bb85125c8c..f9a5d825ed30 100644
--- a/packages/grid/scss/modules/_flex-grid.scss
+++ b/packages/grid/scss/modules/_flex-grid.scss
@@ -9,6 +9,7 @@
// and often derived from, bootstrap:
// https://github.com/twbs/bootstrap/blob/v4-dev/scss/mixins/_grid.scss
+@use 'sass:list';
@use 'sass:meta';
@use 'sass:math';
@use 'sass:map';
@@ -24,12 +25,12 @@
/// for setting width and default gutters when a column's breakpoint has not been
/// hit yet.
/// @param {Number} $gutter [$grid-gutter] - The gutter for the grid system
-/// @param {Number} $collapsed-gutter [$grid-gutter--condensed] - The condensed mode gutter
+/// @param {Number} $collapsed-gutter [$grid-gutter-condensed] - The condensed mode gutter
/// @access private
/// @group @carbon/grid
@mixin -make-col-ready(
$gutter: $grid-gutter,
- $condensed-gutter: $grid-gutter--condensed
+ $condensed-gutter: $grid-gutter-condensed
) {
// Prevent columns from becoming too narrow when at smaller grid tiers by
// always setting `width: 100%;`. This works because we use `flex` values
@@ -254,7 +255,7 @@
margin-right: auto;
margin-left: auto;
- @include -set-largest-breakpoint();
+ @include -set-largest-breakpoint($breakpoints);
@each $name, $value in $breakpoints {
$prev-breakpoint: map.get($breakpoints, breakpoint-prev($name));
@@ -282,7 +283,7 @@
/// @access private
/// @group @carbon/grid
@mixin -set-largest-breakpoint($breakpoints: $grid-breakpoints) {
- $largest-breakpoint: last-map-item($breakpoints);
+ $largest-breakpoint: -last-map-item($breakpoints);
max-width: map.get($largest-breakpoint, 'width');
}
@@ -299,16 +300,37 @@
}
}
+/// Pass in a map, and get the last one in the list back
+/// @access public
+/// @param {Map} $map - Map
+/// @return {*} Desired value
+/// @group @carbon/layout
+@function -last-map-item($map) {
+ $total-length: list.length($map);
+ @return map-get($map, -key-by-index($map, $total-length));
+}
+
+/// Provide a map and index, and get back the relevant key value
+/// @access public
+/// @param {Map} $map - Map
+/// @param {Integer} $index - Key chain
+/// @return {String} Desired value
+/// @group @carbon/layout
+@function -key-by-index($map, $index) {
+ $keys: map.keys($map);
+ @return nth($keys, $index);
+}
+
/// Generate the CSS for a grid for the given breakpoints and gutters
/// @param {Map} $breakpoints [$grid-breakpoints] - The default breakpoints
/// @param {Number} $grid-gutter [$grid-gutter] - The default gutters
-/// @param {Number} $condensed-gutter [$grid-gutter--condensed] - The condensed mode gutter
+/// @param {Number} $condensed-gutter [$grid-gutter-condensed] - The condensed mode gutter
/// @access public
/// @group @carbon/grid
@mixin flex-grid(
$breakpoints: $grid-breakpoints,
$grid-gutter: $grid-gutter,
- $condensed-gutter: $grid-gutter--condensed
+ $condensed-gutter: $grid-gutter-condensed
) {
.#{$prefix}--grid {
@include -make-container($breakpoints);
@@ -339,36 +361,3 @@
@include -no-gutter();
@include -hang($grid-gutter);
}
-
-@if $flex-grid-columns == 12 {
- $flex-12-column-grid: map.merge(
- $grid-breakpoints,
- (
- lg:
- map.merge(
- map.get($grid-breakpoints, lg),
- (
- columns: 12,
- )
- ),
- xlg:
- map.merge(
- map.get($grid-breakpoints, xlg),
- (
- columns: 12,
- )
- ),
- max:
- map.merge(
- map.get($grid-breakpoints, max),
- (
- columns: 12,
- )
- ),
- )
- );
-
- @include flex-grid($breakpoints: $flex-12-column-grid);
-} @else {
- @include flex-grid();
-}
diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
index 945a57d6b31b..3150a9863234 100644
--- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
+++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
@@ -7994,6 +7994,29 @@ Map {
},
},
},
+ "unstable_ColumnHang" => Object {
+ "propTypes": Object {
+ "as": Object {
+ "args": Array [
+ Array [
+ Object {
+ "type": "string",
+ },
+ Object {
+ "type": "elementType",
+ },
+ ],
+ ],
+ "type": "oneOfType",
+ },
+ "children": Object {
+ "type": "node",
+ },
+ "className": Object {
+ "type": "string",
+ },
+ },
+ },
"unstable_DefinitionTooltip" => Object {
"propTypes": Object {
"align": Object {
diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js
index 5b1b417106c7..c283775ad7bb 100644
--- a/packages/react/src/__tests__/index-test.js
+++ b/packages/react/src/__tests__/index-test.js
@@ -200,6 +200,7 @@ describe('Carbon Components React', () => {
"TooltipDefinition",
"TooltipIcon",
"UnorderedList",
+ "unstable_ColumnHang",
"unstable_DefinitionTooltip",
"unstable_FeatureFlags",
"unstable_FlexGrid",
diff --git a/packages/react/src/components/Grid/CSSGrid.js b/packages/react/src/components/Grid/CSSGrid.js
index c8d90de0ad8d..4cf48628c010 100644
--- a/packages/react/src/components/Grid/CSSGrid.js
+++ b/packages/react/src/components/Grid/CSSGrid.js
@@ -13,23 +13,41 @@ import { GridSettings, useGridSettings } from './GridContext';
function CSSGrid({
as: BaseComponent = 'div',
+ children,
+ className: customClassName,
condensed = false,
fullWidth = false,
- columns = 16,
- className: containerClassName,
- children,
+ narrow = false,
...rest
}) {
const prefix = usePrefix();
const { subgrid } = useGridSettings();
- const className = cx(containerClassName, {
- [`${prefix}--css-grid`]: !subgrid,
- [`${prefix}--css-grid--${columns}`]: !subgrid && columns !== 16,
- [`${prefix}--css-grid--condensed`]: condensed,
+ let mode = 'wide';
+ if (narrow) {
+ mode = 'narrow';
+ } else if (condensed) {
+ mode = 'condensed';
+ }
+
+ if (subgrid) {
+ return (
+
+
+ {children}
+
+
+ );
+ }
+
+ const className = cx(customClassName, {
+ [`${prefix}--css-grid`]: true,
+ [`${prefix}--css-grid--condensed`]: mode === 'condensed',
+ [`${prefix}--css-grid--narrow`]: mode === 'narrow',
[`${prefix}--css-grid--full-width`]: fullWidth,
- [`${prefix}--subgrid`]: subgrid,
- [`${prefix}--col-span-${columns}`]:
- (subgrid && columns !== 16) || columns !== 16,
});
return (
@@ -57,11 +75,6 @@ CSSGrid.propTypes = {
*/
className: PropTypes.string,
- /**
- * Specify how many columns wide the Grid should span
- */
- columns: PropTypes.number,
-
/**
* Collapse the gutter to 1px. Useful for fluid layouts.
* Rows have 1px of margin between them to match gutter.
@@ -72,6 +85,55 @@ CSSGrid.propTypes = {
* Remove the default max width that the grid has set
*/
fullWidth: PropTypes.bool,
+
+ /**
+ * Container hangs 16px into the gutter. Useful for
+ * typographic alignment with and without containers.
+ */
+ narrow: PropTypes.bool,
+};
+
+function Subgrid({
+ as: BaseComponent = 'div',
+ className: customClassName,
+ children,
+ mode,
+ ...rest
+}) {
+ const prefix = usePrefix();
+ const className = cx(customClassName, {
+ [`${prefix}--subgrid`]: true,
+ [`${prefix}--subgrid--condensed`]: mode === 'condensed',
+ [`${prefix}--subgrid--narrow`]: mode === 'narrow',
+ [`${prefix}--subgrid--wide`]: mode === 'wide',
+ });
+ return (
+
+ {children}
+
+ );
+}
+
+Subgrid.propTypes = {
+ /**
+ * Provide a custom element to render instead of the default
+ */
+ as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
+
+ /**
+ * Pass in content that will be rendered within the `Subgrid`
+ */
+ children: PropTypes.node,
+
+ /**
+ * Specify a custom className to be applied to the `Subgrid`
+ */
+ className: PropTypes.string,
+
+ /**
+ * Specify the grid mode for the subgrid
+ */
+ mode: PropTypes.oneOf(['wide', 'narrow', 'condensed']),
};
export { CSSGrid };
diff --git a/packages/react/src/components/Grid/Column.js b/packages/react/src/components/Grid/Column.js
index d29045d2c23b..1b810d6dddb4 100644
--- a/packages/react/src/components/Grid/Column.js
+++ b/packages/react/src/components/Grid/Column.js
@@ -15,7 +15,7 @@ import { useGridSettings } from './GridContext';
function Column({
as: BaseComponent = 'div',
children,
- className: containerClassName,
+ className: customClassName,
sm,
md,
lg,
@@ -25,12 +25,28 @@ function Column({
}) {
const { mode } = useGridSettings();
const prefix = usePrefix();
- const columnClassName =
- mode === 'css-grid'
- ? getClassNameForBreakpoints([sm, md, lg, xlg, max], prefix)
- : getClassNameForFlexGridBreakpoints([sm, md, lg, xlg, max], prefix);
- const className = cx(containerClassName, columnClassName, {
+ if (mode === 'css-grid') {
+ return (
+
+ {children}
+
+ );
+ }
+
+ const columnClassName = getClassNameForFlexGridBreakpoints(
+ [sm, md, lg, xlg, max],
+ prefix
+ );
+ const className = cx(customClassName, columnClassName, {
[`${prefix}--col`]: columnClassName.length === 0,
});
@@ -121,6 +137,106 @@ Column.propTypes = {
xlg: spanPropType,
};
+function CSSGridColumn({
+ as: BaseComponent = 'div',
+ children,
+ className: containerClassName,
+ sm,
+ md,
+ lg,
+ xlg,
+ max,
+ span,
+ ...rest
+}) {
+ const prefix = usePrefix();
+ const breakpointClassName = getClassNameForBreakpoints(
+ [sm, md, lg, xlg, max],
+ prefix
+ );
+ const spanClassName = getClassNameForSpan(span, prefix);
+ const className = cx(containerClassName, breakpointClassName, spanClassName, {
+ [`${prefix}--css-grid-column`]: true,
+ });
+
+ return (
+
+ {children}
+
+ );
+}
+
+CSSGridColumn.propTypes = {
+ /**
+ * Provide a custom element to render instead of the default
+ */
+ as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
+
+ /**
+ * Pass in content that will be rendered within the `Column`
+ */
+ children: PropTypes.node,
+
+ /**
+ * Specify a custom className to be applied to the `Column`
+ */
+ className: PropTypes.string,
+
+ /**
+ * Specify column span for the `lg` breakpoint (Default breakpoint up to 1312px)
+ * This breakpoint supports 16 columns by default.
+ *
+ * @see https://www.carbondesignsystem.com/guidelines/layout#breakpoints
+ */
+ lg: spanPropType,
+
+ /**
+ * Specify column span for the `max` breakpoint. This breakpoint supports 16
+ * columns by default.
+ *
+ * @see https://www.carbondesignsystem.com/guidelines/layout#breakpoints
+ */
+ max: spanPropType,
+
+ /**
+ * Specify column span for the `md` breakpoint (Default breakpoint up to 1056px)
+ * This breakpoint supports 8 columns by default.
+ *
+ * @see https://www.carbondesignsystem.com/guidelines/layout#breakpoints
+ */
+ md: spanPropType,
+
+ /**
+ * Specify column span for the `sm` breakpoint (Default breakpoint up to 672px)
+ * This breakpoint supports 4 columns by default.
+ *
+ * @see https://www.carbondesignsystem.com/guidelines/layout#breakpoints
+ */
+ sm: spanPropType,
+
+ /**
+ * Specify constant column span, start, or end values that will not change
+ * based on breakpoint
+ */
+ span: PropTypes.oneOfType([
+ PropTypes.number,
+ percentSpanType,
+ PropTypes.shape({
+ span: PropTypes.oneOfType([PropTypes.number, percentSpanType]),
+ start: PropTypes.number,
+ end: PropTypes.number,
+ }),
+ ]),
+
+ /**
+ * Specify column span for the `xlg` breakpoint (Default breakpoint up to
+ * 1584px) This breakpoint supports 16 columns by default.
+ *
+ * @see https://www.carbondesignsystem.com/guidelines/layout#breakpoints
+ */
+ xlg: spanPropType,
+};
+
const breakpointNames = ['sm', 'md', 'lg', 'xlg', 'max'];
/**
@@ -238,4 +354,31 @@ function getClassNameForFlexGridBreakpoints(breakpoints, prefix) {
return classNames.join(' ');
}
+/**
+ * Build the appropriate className for a span value
+ */
+function getClassNameForSpan(value, prefix) {
+ const classNames = [];
+
+ if (typeof value === 'number' || typeof value === 'string') {
+ classNames.push(`${prefix}--col-span-${value}`);
+ } else if (typeof value === 'object') {
+ const { span, start, end } = value;
+
+ if (span !== undefined && span !== null) {
+ classNames.push(`${prefix}--col-span-${span}`);
+ }
+
+ if (start !== undefined && start !== null) {
+ classNames.push(`${prefix}--col-start-${start}`);
+ }
+
+ if (end !== undefined && end !== null) {
+ classNames.push(`${prefix}--col-end-${end}`);
+ }
+ }
+
+ return classNames.join('');
+}
+
export default Column;
diff --git a/packages/react/src/components/Grid/ColumnHang.js b/packages/react/src/components/Grid/ColumnHang.js
new file mode 100644
index 000000000000..e5de6cca3ae3
--- /dev/null
+++ b/packages/react/src/components/Grid/ColumnHang.js
@@ -0,0 +1,49 @@
+/**
+ * Copyright IBM Corp. 2016, 2018
+ *
+ * This source code is licensed under the Apache-2.0 license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import cx from 'classnames';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { usePrefix } from '../../internal/usePrefix';
+
+/**
+ * Helper component for rendering content that hangs on the column. Useful when
+ * trying to align content across different grid modes
+ */
+function ColumnHang({
+ as: BaseComponent = 'div',
+ className: customClassName,
+ children,
+ ...rest
+}) {
+ const prefix = usePrefix();
+ const className = cx(customClassName, `${prefix}--grid-column-hang`);
+ return (
+
+ {children}
+
+ );
+}
+
+ColumnHang.propTypes = {
+ /**
+ * Provide a custom element to render instead of the default
+ */
+ as: PropTypes.oneOfType([PropTypes.string, PropTypes.elementType]),
+
+ /**
+ * Pass in content that will be rendered within the `Grid`
+ */
+ children: PropTypes.node,
+
+ /**
+ * Specify a custom className to be applied to the `Grid`
+ */
+ className: PropTypes.string,
+};
+
+export { ColumnHang };
diff --git a/packages/react/src/components/Grid/__tests__/Grid-test.e2e.js b/packages/react/src/components/Grid/__tests__/Grid-test.e2e.js
index 21f852b70d65..88eca25a6db7 100644
--- a/packages/react/src/components/Grid/__tests__/Grid-test.e2e.js
+++ b/packages/react/src/components/Grid/__tests__/Grid-test.e2e.js
@@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
-import 'carbon-components/scss/globals/scss/vendor/@carbon/grid/scss/modules/_css-grid.scss';
import './Grid-test.e2e.scss';
import React from 'react';
diff --git a/packages/react/src/components/Grid/__tests__/Grid-test.e2e.scss b/packages/react/src/components/Grid/__tests__/Grid-test.e2e.scss
index 5e2ddad08093..36d7a9615af6 100644
--- a/packages/react/src/components/Grid/__tests__/Grid-test.e2e.scss
+++ b/packages/react/src/components/Grid/__tests__/Grid-test.e2e.scss
@@ -1,3 +1,8 @@
+@use '~@carbon/styles/scss/config' with (
+ $prefix: 'bx',
+);
+@use '~@carbon/styles/scss/grid';
+
@import '~carbon-components/scss/globals/scss/vars';
@import '~carbon-components/scss/globals/scss/colors';
@import '~carbon-components/scss/globals/scss/typography';
diff --git a/packages/react/src/components/Grid/index.js b/packages/react/src/components/Grid/index.js
index 6ba488c90806..323e5b2c0840 100644
--- a/packages/react/src/components/Grid/index.js
+++ b/packages/react/src/components/Grid/index.js
@@ -9,3 +9,4 @@ export { FlexGrid } from './FlexGrid';
export { Grid } from './Grid';
export { default as Row } from './Row';
export { default as Column } from './Column';
+export { ColumnHang } from './ColumnHang';
diff --git a/packages/react/src/components/Grid/next/Grid.stories.js b/packages/react/src/components/Grid/next/Grid.stories.js
index bffce7f2b69f..ae2afc29d7a3 100644
--- a/packages/react/src/components/Grid/next/Grid.stories.js
+++ b/packages/react/src/components/Grid/next/Grid.stories.js
@@ -8,7 +8,7 @@
import './Grid.stories.scss';
import React from 'react';
-import { Grid, Column } from '../../Grid';
+import { Grid, Column, ColumnHang } from '../../Grid';
import mdx from './Grid.mdx';
export default {
@@ -19,7 +19,6 @@ export default {
},
parameters: {
controls: {
- include: [], // ensure props are not displayed on the controls pane
hideNoControlsWarning: true,
},
docs: {
@@ -37,7 +36,7 @@ export default {
],
};
-export const Wide = () => {
+export const Default = () => {
return (
@@ -48,6 +47,17 @@ export const Wide = () => {
);
};
+export const Narrow = () => {
+ return (
+
+
+
+
+
+
+ );
+};
+
export const Condensed = () => {
return (
@@ -148,36 +158,69 @@ export const Subgrid = () => {
export const MixedGridModes = () => {
return (
-
-
-
-
- wide
-
-
-
-
-
-
- condensed
-
-
-
-
-
-
- condensed
-
-
-
-
-
-
- wide
-
-
-
-
+ <>
+
+
+
+
+
+
+ Text
+
+
+ Text
+
+
+ Text
+
+
+ Text
+
+
+
+ Text
+ Text
+
+
+
+ Text
+
+
+ Text
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Text
+
+
+ Text
+
+
+ Text
+
+
+ Text
+
+
+
+
+
+
+ >
);
};
@@ -229,18 +272,3 @@ export const Offset = () => (
/>
);
-
-export const AutoColumns = () => {
- return (
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/packages/react/src/components/Grid/next/Grid.stories.scss b/packages/react/src/components/Grid/next/Grid.stories.scss
index 84ab69d043f0..c0b0387c6f68 100644
--- a/packages/react/src/components/Grid/next/Grid.stories.scss
+++ b/packages/react/src/components/Grid/next/Grid.stories.scss
@@ -1,46 +1,101 @@
+//
+// Copyright IBM Corp. 2018, 2018
+//
+// This source code is licensed under the Apache-2.0 license found in the
+// LICENSE file in the root directory of this source tree.
+//
+
@use '@carbon/styles/scss/colors' as *;
@use '@carbon/styles/scss/type' as *;
-// Grid modes
-.sb-css-grid-container .cds--css-grid {
- background-color: $blue-20;
- outline: 1px dashed $blue-40;
-}
+.sb-css-grid-container {
+ // Grid modes
+ .cds--css-grid {
+ background-color: $blue-20;
+ outline: 1px dashed $blue-40;
+ }
-.sb-css-grid-container .cds--css-grid p {
- @include type-style('code-02');
-}
+ .cds--css-grid p {
+ @include type-style('code-02');
+ }
-.sb-css-grid-container .cds--css-grid p:first-of-type {
- //messing up progress indicator stories
- margin-top: 0;
-}
+ .cds--css-grid p:first-of-type {
+ margin-top: 0;
+ }
-.sb-css-grid-container .cds--css-grid.cds--css-grid--condensed {
- background-color: $purple-20;
- outline: 1px dashed $purple-40;
-}
+ // Narrow
+ .cds--css-grid.cds--css-grid--narrow {
+ background-color: #d6f9f9;
+ outline: 1px dashed $green-40;
+ }
-// Only use background for subgrid example, not other subgrids in "mixed modes" story or others
-.sb-css-grid-container .cds--subgrid.example {
- background-color: $green-20;
-}
+ // Condensed
+ .cds--css-grid.cds--css-grid--condensed {
+ background-color: $purple-10;
+ outline: 1px dashed $purple-40;
+ }
-// Columns
-.sb-css-grid-container .cds--css-grid > [class*='col'],
-.sb-css-grid-container .cds--subgrid > [class*='col'] {
- min-height: 80px;
-}
+ .cds--subgrid {
+ outline: 1px solid black;
+ padding-top: 2rem;
+ padding-bottom: 2rem;
+ position: relative;
+ background: #eef4ff;
+ }
-.sb-css-grid-container .cds--css-grid > [class*='col'] {
- background: $blue-10;
-}
+ .cds--css-grid,
+ .cds--subgrid--wide {
+ --grid-mode-color: #97c1ff;
+ }
-.sb-css-grid-container .cds--subgrid > [class*='col'] {
- background: $green-10;
- outline: 1px dashed $green-30;
-}
+ .cds--css-grid--narrow,
+ .cds--subgrid--narrow {
+ --grid-mode-color: #20d5d2;
+ background: $green-10;
+ }
+
+ .cds--css-grid--condensed,
+ .cds--subgrid--condensed {
+ --grid-mode-color: #bb8eff;
+ background: $purple-10;
+ }
+
+ .cds--subgrid--narrow {
+ background: #d6f9f9;
+ }
+
+ .cds--subgrid--condensed {
+ background: #f7f2ff;
+ }
+
+ .cds--subgrid::before {
+ @include type-style('code-01');
+ position: absolute;
+ inset-block-start: 0;
+ inset-inline-start: 0;
+ display: block;
+ content: 'subgrid';
+ background: var(--grid-mode-color, #97c1ff);
+ color: $black;
+ padding: 0.125rem 0.25rem;
+ }
+
+ // Column
+ .cds--css-grid-column {
+ --border-color: #97c1ff;
+
+ background: $white;
+ box-shadow: 0 0 0 1px var(--border-color);
+ min-height: 80px;
+ }
+
+ .cds--css-grid--narrow .cds--css-grid-column,
+ .cds--subgrid--narrow .cds--css-grid-column {
+ --border-color: #20d5d2;
+ }
-.sb-css-grid-container.cds--css-grid.cds--css-grid--condensed > [class*='col'] {
- background: $purple-10;
+ .cds--css-grid--condensed .cds--css-grid-column,
+ .cds--subgrid--condensed .cds--css-grid-column {
+ --border-color: #bb8eff;
+ }
}
diff --git a/packages/react/src/index.js b/packages/react/src/index.js
index ceab213d426c..008f303612e6 100644
--- a/packages/react/src/index.js
+++ b/packages/react/src/index.js
@@ -68,6 +68,7 @@ export {
Grid,
Row,
Column,
+ ColumnHang as unstable_ColumnHang,
FlexGrid as unstable_FlexGrid,
} from './components/Grid';
export Icon from './components/Icon';
diff --git a/packages/styles/docs/sass.md b/packages/styles/docs/sass.md
index dcb6181b0f4d..2a2a83fe6cc8 100644
--- a/packages/styles/docs/sass.md
+++ b/packages/styles/docs/sass.md
@@ -122,28 +122,45 @@ to `false`:
## Grid
-| Import | Filepath |
-| :--------------------------------- | :---------------- |
-| `@use '@carbon/styles/scss/grid';` | `scss/_grid.scss` |
+| Import | Filepath |
+| :----------------------------------------- | :------------------------ |
+| `@use '@carbon/styles/scss/grid';` | `scss/grid/_index.scss` |
+| `@use '@carbon/styles/scss/grid/flexbox';` | `scss/grid/_flexbox.scss` |
### Using the grid
This package `@forward`s the styles defined in the
[`@carbon/grid`](https://github.com/carbon-design-system/carbon/tree/main/packages/grid)
-package. The full source for Carbon grid styles can be found there alongside
-more comprehensive documentation on package contents, configuration, and usage.
+package. For full documentation, visit the
+[Sass Documentation](../../grid/docs/sass.md) for the package.
To use the grid via `@carbon/styles`, it must be brought in directly or the grid
specific style sheet must be imported:
```scss
-/* All the grid styles are included through this central entrypoint */
+// All the grid styles are included through this central entrypoint
@use '@carbon/styles';
-/* Alternatively, the grid styles can be brought in on their own */
+// Alternatively, the grid styles can be brought in on their own
@use '@carbon/styles/scss/grid';
```
+By default, the emitted grid will be a CSS Grid based implementation. If you
+prefer to use flexbox version, you can configure the package by writing the
+following:
+
+```scss
+@use '@carbon/styles' with (
+ $use-flexbox-grid: true,
+);
+```
+
+Or you can import the flexbox grid directly:
+
+```scss
+@use '@carbon/styles/scss/grid/flexbox';
+```
+
### Classes provided
In either case, you will then have access to the grid classes and mixins
@@ -172,22 +189,6 @@ prefix:
```
-### Grid Mixins
-
-In the event that you'd like to configure your own classes for portions of the
-grid, there are a few mixins that can be used.
-
-- `css-grid()` provides the base grid definition
-- `subgrid()` provides the subgrid definition
-- `carbon--aspect-ratio($aspect-ratios: $carbon--aspect-ratios)` generates the
- CSS classname utilities for the aspect ratios
-
-```scss
-.custom-grid-class {
- @include css-grid();
-}
-```
-
## Motion
The motion package provides helper functions, mixins, and duration tokens to add
diff --git a/packages/styles/scss/__tests__/__snapshots__/config-test.js.snap b/packages/styles/scss/__tests__/__snapshots__/config-test.js.snap
index 303394cf3537..aa4d35140b09 100644
--- a/packages/styles/scss/__tests__/__snapshots__/config-test.js.snap
+++ b/packages/styles/scss/__tests__/__snapshots__/config-test.js.snap
@@ -9,6 +9,7 @@ Object {
"font-display": "swap",
"font-path": "~@ibm/plex",
"prefix": "cds",
+ "use-flexbox-grid": false,
"use-google-fonts": false,
}
`;
diff --git a/packages/styles/scss/__tests__/grid-test.js b/packages/styles/scss/__tests__/grid-test.js
index ce40d768483e..e2522e4e49e5 100644
--- a/packages/styles/scss/__tests__/grid-test.js
+++ b/packages/styles/scss/__tests__/grid-test.js
@@ -22,11 +22,11 @@ describe('@carbon/styles/scss/grid', () => {
$_: get('api', (
variables: (
grid-gutter: meta.variable-exists('grid-gutter'),
+ grid-gutter-condensed: meta.variable-exists('grid-gutter-condensed'),
grid-breakpoints: meta.variable-exists('grid-breakpoints'),
),
mixins: (
css-grid: meta.mixin-exists('css-grid'),
- subgrid: meta.mixin-exists('subgrid'),
flex-grid: meta.mixin-exists('flex-grid'),
),
));
@@ -36,11 +36,11 @@ describe('@carbon/styles/scss/grid', () => {
expect(api).toEqual({
variables: {
'grid-gutter': true,
+ 'grid-gutter-condensed': true,
'grid-breakpoints': true,
},
mixins: {
'css-grid': true,
- subgrid: true,
'flex-grid': true,
},
});
diff --git a/packages/styles/scss/_config.scss b/packages/styles/scss/_config.scss
index 6f999508f5ea..b62ca62f3958 100644
--- a/packages/styles/scss/_config.scss
+++ b/packages/styles/scss/_config.scss
@@ -54,3 +54,8 @@ $prefix: 'cds' !default;
/// @access public
/// @group @carbon/grid
$flex-grid-columns: 16 !default;
+
+/// Specify if the default grid type should be the flexbox grid
+/// @type Boolean
+/// @group config
+$use-flexbox-grid: false !default;
diff --git a/packages/styles/scss/_grid.scss b/packages/styles/scss/grid/_config.scss
similarity index 70%
rename from packages/styles/scss/_grid.scss
rename to packages/styles/scss/grid/_config.scss
index 7149ecf3ee12..a54efc0ae21e 100644
--- a/packages/styles/scss/_grid.scss
+++ b/packages/styles/scss/grid/_config.scss
@@ -5,18 +5,14 @@
// LICENSE file in the root directory of this source tree.
//
-@use 'config';
-
+@use '../config';
@forward '@carbon/grid'
show css-grid,
- subgrid,
flex-grid,
$grid-gutter,
$grid-gutter-condensed,
$grid-breakpoints
with (
- $prefix: config.$prefix,
- $flex-grid-columns: config.$flex-grid-columns,
+ $prefix: config.$prefix !default,
+ $flex-grid-columns: config.$flex-grid-columns !default
);
-
-@use '@carbon/grid';
diff --git a/packages/grid/examples/css-grid/src/scss/components/_index.scss b/packages/styles/scss/grid/_flexbox.scss
similarity index 72%
rename from packages/grid/examples/css-grid/src/scss/components/_index.scss
rename to packages/styles/scss/grid/_flexbox.scss
index af0a3e727674..22973473ed67 100644
--- a/packages/grid/examples/css-grid/src/scss/components/_index.scss
+++ b/packages/styles/scss/grid/_flexbox.scss
@@ -5,4 +5,7 @@
// LICENSE file in the root directory of this source tree.
//
-@use 'header';
+@forward 'config';
+@use '@carbon/grid';
+
+@include grid.flex-grid();
diff --git a/packages/styles/scss/grid/_index.scss b/packages/styles/scss/grid/_index.scss
new file mode 100644
index 000000000000..d3bab7bca1bc
--- /dev/null
+++ b/packages/styles/scss/grid/_index.scss
@@ -0,0 +1,16 @@
+//
+// Copyright IBM Corp. 2018, 2018
+//
+// This source code is licensed under the Apache-2.0 license found in the
+// LICENSE file in the root directory of this source tree.
+//
+
+@forward 'config';
+@use '@carbon/grid';
+@use '../config';
+
+@if config.$use-flexbox-grid == true {
+ @include grid.flex-grid();
+} @else {
+ @include grid.css-grid();
+}
diff --git a/packages/type/scss/modules/_styles.scss b/packages/type/scss/modules/_styles.scss
index b3ca5c41b248..00da20725be6 100644
--- a/packages/type/scss/modules/_styles.scss
+++ b/packages/type/scss/modules/_styles.scss
@@ -9,7 +9,7 @@
@use 'sass:map';
@use 'sass:math';
-@use '@carbon/grid/scss/modules/breakpoint' as grid;
+@use '@carbon/grid/scss/modules/config' as grid;
@use 'font-family';
@use 'scale';