Skip to content

Website v4.20.0 Release #2871

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions website/app/styles/pages/components/advanced-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@
// COMPONENTS > TABLE > ADVANCEDTABLE

#show-content-components-table-advanced-table {
.doc-advanced-table-scrollable-wrapper {
overflow-x: auto;
}

.doc-advanced-table-vertical-scrollable-wrapper {
height: 500px;
}

.doc-advanced-table-multiselect-with-pagination-demo {
.hds-advanced-table + .hds-pagination {
margin-top: 16px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
A named block where the utility actions will be rendered. Typically, `Dropdown` or `Button` components should be added here, such as a help menu, user menu, or search button.
</C.Property>
<C.Property @name="breakpoint" @type="string" @default="1088px">
Set a custom breakpoint to control the page width at which the UI switches from displaying the mobile/small view vs. the desktop/view.
Set a custom breakpoint to control the page width at which the UI switches from displaying the mobile/small view vs. the desktop/large view.
</C.Property>
<C.Property @name="hasA11yRefocus" @type="boolean" @default="true">
Controls whether a "navigator narrator" and a "skip link" are added to the navigation (provided by the [`ember-a11y-refocus` Ember addon](https://github.com/ember-a11y/ember-a11y-refocus)). It can be programmatically turned off by passing `false`. Warning: if it is set to false, then it will fail Bypass Blocks, [Success Criteria 2.4.1](https://www.w3.org/WAI/WCAG22/Understanding/bypass-blocks.html). Since this component appears on every page, the application will not be considered conformant.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ This is the full-fledged component (responsive and animated).
<C.Property @name="isMinimized" @type="boolean" @default="false">
Controls if the App Side Nav is rendered collapsed or expanded when initialized. This allows an application to preserve the collapsed/expanded state across sessions. After the initial render, this argument is altered based on user interactions (collapse/expand the App Side Nav or resize the window) and it is not a suitable way of controlling the App Side Nav state from outside after render (it’s an internal state).
</C.Property>
<C.Property @name="breakpoint" @type="string" @default="1088px">
Set a custom breakpoint to control the page width at which the UI switches from displaying the mobile/small view vs. the desktop/large view.
</C.Property>
<C.Property @name="onToggleMinimizedStatus" @type="function">
Callback function invoked when the `AppSideNav` is collapsed or expanded. The function receives a boolean argument stating if the `AppSideNav` is minimized or not.
</C.Property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Below is an example (inspired by the Cloud UI navigation) of how the two kinds o

```handlebars
{{!--
for demo purposes we set `@isResponsive` to `false` but in your app it will probably need to be set to `true`
for demo purposes we set `@isResponsive` to `false` but in your app it will probably need to be set to `true`
(or omitted to rely on defaults)
--}}
<div class="doc-app-sidenav-demo--cloud-ui">
Expand Down Expand Up @@ -175,7 +175,7 @@ When the App Side Nav is used in conjunction with portals, the nesting of naviga
As mentioned above, the full-fledged `Hds::AppSideNav` component is “responsive” by default:

- when the **viewport is `desktop`**, the sidebar navigation is static and has a fixed width
- the width at which the viewport is considered “desktop” is controlled by a dedicated CSS variable `--hds-app-desktop-breakpoint`; if needed it can be overwritten (at `:root` level) to define a custom “desktop” breakpoint
- the width at which the viewport is considered “desktop” can be overwritten using the `@breakpoint` argument
- when the **viewport is `mobile`**, the sidebar navigation is responsive and the user can minimize or maximize its width via a toggle button (the component will take care automatically of the transitions between these two states)
- in this case the App Side Nav occupies only a minimum width in terms of page layout, even when expanded (it partially covers the main content)
- a toggle button is added to the App Side Nav, used to expand/minimize its width
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ loadInitializers(App, config.modulePrefix);"

### Limit height

Code content uses `auto` height by default but you can opt to set a `maxHeight` value to save space. Vertical scrolling is enabled as part of this feature allowing users to scroll vertically to view the overflowing content.
Code content uses `auto` height by default but you can opt to set a `maxHeight` value to save space. If the content height exceeds the set max height, vertical scrolling is enabled to view the overflowing content and a toggle button is displayed to expand the height and show the Code Block content in its entirety.

```handlebars
<Hds::CodeBlock
@language="javascript"
@maxHeight="105px"
@maxHeight="130px"
@value="import Application from `@ember/application`;
import Resolver from `ember-resolver`;
import loadInitializers from `ember-load-initializers`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ Line numbers are displayed by default and can make longer blocks of code and sni
In the Figma component, the code examples have the appropriate number of lines by default but must be manually hidden or shown to match the length of custom snippets.
!!!

## Height toggle button

For longer code content, it can be helpful to set a `maxHeight` for the Code Block to limit how much code is shown by default within the UI layout. If the content exceeds this height, a “Show more code” button will be displayed at the bottom of the Code Block, allowing users to expand it. Activating this button again will collapse the content back to its original height.

In Figma, this is enabled by setting `hasToggleHeightButton` to true. The button is placed inside a footer element that only appears when the content overflows, keeping the layout clean when the toggle isn’t needed.

![Collapsed Code Block showing limited lines and a 'Show more code' button at the bottom.](/assets/components/code-block/code-block-collapsed.png)

Interacting with this button removes the height limit, expanding the Code Block to display the full code snippet.

![Expanded Code Block with all lines visible and a 'Show less code' button displayed at the bottom](/assets/components/code-block/code-block-expanded.png)

Interacting with it again collapses the Code Block back to its set `maxHeight`.


## Line highlighting

Use line highlighting to target and call attention to specific lines or multiple lines within a block of code.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,11 @@ The Advanced Table component itself is where most of the options will be applied
Determines if even-numbered rows will have a different background color from odd-numbered rows.<br><br>
**Important**: Advanced Table does **not** support setting `isStriped` to true when there are nested rows.
</C.Property>
<C.Property @name="hasStickyHeader" @type="boolean" @default="false">
Determines if the Advanced Table has a sticky header.
<C.Property @name="maxHeight" @type="string">
Sets the maximum height of the Advanced Table. If the `@maxHeight` is set, there will automatically be a sticky header. To turn off the sticky header and still have a max height, set `@hasStickyHeader` to false.
</C.Property>
<C.Property @name="hasStickyHeader" @type="boolean">
Determines if the Advanced Table has a sticky header. If set to `true`, must be used with the `@maxHeight` argument. If `@maxHeight` is set and `@hasStickyHeader` is `false`, there will not be a sticky header.
</C.Property>
<C.Property @name="hasStickyFirstColumn" @type="boolean" @default="false">
Determines if the Advanced Table has a sticky first column.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,31 +382,30 @@ We recommend using functionalities like [pagination](/components/pagination), [s

#### Vertical scrolling

For situations where the default number of rows visible may be high, it can be difficult for users to track which column is which once they scroll. In this case, the `hasStickyHeader` argument can be used to make the column headers persist as the user scrolls.
For situations where the default number of rows visible may be high, it can be difficult for users to track which column is which once they scroll. In this case, the `maxHeight` argument can be used to set the maximum height of the Advanced Table which will also add a sticky header. This will make the column headers persist as the user scrolls.

If you want to set the `maxHeight` but not have a sticky header, set `hasStickyHeader` to false.

```handlebars
<!-- this is an element with "height: 500px" -->
<div class="doc-advanced-table-vertical-scrollable-wrapper">
<Hds::AdvancedTable
@model={{this.demoDataWithLargeNumberOfRows}}
@columns={{array
(hash key="id" label="ID")
(hash key="name" label="Name" isSortable=true)
(hash key="email" label="Email")
(hash key="role" label="Role" isSortable=true)
}}
@hasStickyHeader={{true}}
>
<:body as |B|>
<B.Tr>
<B.Td>{{B.data.id}}</B.Td>
<B.Td>{{B.data.name}}</B.Td>
<B.Td>{{B.data.email}}</B.Td>
<B.Td>{{B.data.role}}</B.Td>
</B.Tr>
</:body>
</Hds::AdvancedTable>
</div>
<Hds::AdvancedTable
@model={{this.demoDataWithLargeNumberOfRows}}
@columns={{array
(hash key="id" label="ID")
(hash key="name" label="Name" isSortable=true)
(hash key="email" label="Email")
(hash key="role" label="Role" isSortable=true)
}}
@maxHeight="500px"
>
<:body as |B|>
<B.Tr>
<B.Td>{{B.data.id}}</B.Td>
<B.Td>{{B.data.name}}</B.Td>
<B.Td>{{B.data.email}}</B.Td>
<B.Td>{{B.data.role}}</B.Td>
</B.Tr>
</:body>
</Hds::AdvancedTable>
```

#### Horizontal scrolling
Expand All @@ -418,36 +417,33 @@ The component adds the sticky styles to the `[B].Th` component in each row. If t
Note: Using `@hasStickyFirstColumn` with nested rows is not supported.

```handlebars
<!-- this is an element with "overflow: auto" -->
<div class="doc-advanced-table-scrollable-wrapper">
<Hds::AdvancedTable
@hasStickyFirstColumn={{true}}
@model={{this.demoDataWithLargeNumberOfColumns}}
@columns={{array
(hash key="first_name" label="First Name" isSortable=true)
(hash key="last_name" label="Last Name" isSortable=true)
(hash key="age" label="Age" isSortable=true)
(hash key="email" label="Email")
(hash key="phone" label="Phone")
(hash key="bio" label="Biography" width="350px")
(hash key="education" label="Education Degree")
(hash key="occupation" label="Occupation")
}}
>
<:body as |B|>
<B.Tr>
<B.Th>{{B.data.first_name}}</B.Th>
<B.Td>{{B.data.last_name}}</B.Td>
<B.Td>{{B.data.age}}</B.Td>
<B.Td>{{B.data.email}}</B.Td>
<B.Td>{{B.data.phone}}</B.Td>
<B.Td>{{B.data.bio}}</B.Td>
<B.Td>{{B.data.education}}</B.Td>
<B.Td>{{B.data.occupation}}</B.Td>
</B.Tr>
</:body>
</Hds::AdvancedTable>
</div>
<Hds::AdvancedTable
@hasStickyFirstColumn={{true}}
@model={{this.demoDataWithLargeNumberOfColumns}}
@columns={{array
(hash key="first_name" label="First Name" isSortable=true)
(hash key="last_name" label="Last Name" isSortable=true)
(hash key="age" label="Age" isSortable=true)
(hash key="email" label="Email")
(hash key="phone" label="Phone")
(hash key="bio" label="Biography" width="350px")
(hash key="education" label="Education Degree")
(hash key="occupation" label="Occupation")
}}
>
<:body as |B|>
<B.Tr>
<B.Th>{{B.data.first_name}}</B.Th>
<B.Td>{{B.data.last_name}}</B.Td>
<B.Td>{{B.data.age}}</B.Td>
<B.Td>{{B.data.email}}</B.Td>
<B.Td>{{B.data.phone}}</B.Td>
<B.Td>{{B.data.bio}}</B.Td>
<B.Td>{{B.data.education}}</B.Td>
<B.Td>{{B.data.occupation}}</B.Td>
</B.Tr>
</:body>
</Hds::AdvancedTable>
```

### Multi-select Advanced Table
Expand Down
16 changes: 16 additions & 0 deletions website/docs/foundations/breakpoints/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Breakpoints
caption: Standardized breakpoints for different device widths.
description: Breakpoints are width values that standardize responsive experiences across the HashiCorp product suite.
links:
figma: https://www.figma.com/design/uX4OEaJQdWfzULADchjAeN/HDS-Foundations-v2.0?node-id=13020-244&t=0N1UWbTuY6sSq3Od-1
previewImage: assets/illustrations/foundations/breakpoints.jpg
---

<section data-tab="Guidelines">
@include "partials/guidelines/guidelines.md"
</section>

<section data-tab="Code">
@include "partials/code/how-to-use.md"
</section>
119 changes: 119 additions & 0 deletions website/docs/foundations/breakpoints/partials/code/how-to-use.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
## How to use the breakpoints

In [responsive design](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Responsive_Design) it's common practice to define specific media queries in CSS that can be used to control not only the layout of the entire page and its parts, but also other aspects of a UI like typography, spacing, the rendering of decorative elements, the resolution of media assets, and much more. These media queries are built using CSS `@media` declarations in combination with a set of standard breakpoints.

Our design system defines [breakpoint values](/foundations/breakpoints#the-ranges) based on browser viewport widths. The intervals between these breakpoints create distinct ranges, which can be used with the [Sass](/foundations/breakpoints?tab=code#sass) and [JavaScript](/foundations/breakpoints?tab=code#javascript) helpers to implement responsive designs for our applications.

### Sass

To use the Sass helpers provided by the design system, you must import the corresponding Sass file (via `@use`, [as recommended](https://sass-lang.com/documentation/at-rules/use/#differences-from-import)) from the `@hashicorp/design-system-components` package:


```scss
// from @hashicorp/design-system-components package
@use "mixins/breakpoints" as *;
```

!!! info

If you are not able to import the file using the declaration above, [contact the Design Systems Team](/about/support) for support.

!!!

Once the file is imported, you will have access to the Sass helpers described below.

#### Mixins

Sass mixins offer the simplest, most efficient way to implement responsive layouts using the standard breakpoints defined in our system. We provide three different mixins:

- `hds-breakpoint-above($name)` - for media queries that apply to a viewport range **above** a certain breakpoint (useful for a mobile-first approach)
- `hds-breakpoint-below($name)` - for media queries that apply to a viewport range **below** a certain breakpoint (useful for a desktop-first approach)
- `hds-breakpoint-between($lower, $upper)` - for media queries that apply to a viewport range **between** two breakpoints

Here is an example of how the mixins could be used in a mobile-first responsive layout:

```scss
// from @hashicorp/design-system-components package
@use "mixins/breakpoints" as *;

.my-responsive-layout {
// this is the default behavior, that covers the range 0px–767px
display: flex;
direction: column;
gap: 1rem;

// at 768px the layout changes, from a vertical stack to an horizontal one
@include hds-breakpoint-above('md') {
direction: row;
}

// at larger viewports we increase the spacing between the items
@include hds-breakpoint-above('xl') {
gap: 2rem;
}
}
```

The same layout could be achieved using a desktop-first approach in a similar way:

```scss
// from @hashicorp/design-system-components package
@use "mixins/breakpoints" as *;

.my-responsive-layout {
// this is the default behavior
display: flex;
direction: row;
gap: 2rem;

// at smaller viewports we decrease the spacing between the items
@include hds-breakpoint-below('xl') {
gap: 1rem;
}

// at 768px the layout changes, from an horizontal stack to a vertical one
@include hds-breakpoint-below('md') {
direction: column;
}
}
```

Of course, these are oversimplified examples. In your implementation, you will have to choose which mixin is best suited to achieve the desired responsive layout. This will depend on the design specifications, the context of the layout within the page, and how it relates with other UI elements.

#### Key/Value Map

For special use cases, we also provide a Sass map–`$hds-breakpoints`–which is a lower level helper than the mixins. Here's an example of how this map could be used:

```scss
// explicit import of `map` module (required by Sass)
@use "sass:map";
// from @hashicorp/design-system-components package
@use "mixins/breakpoints" as *;

@each $name, $size in $hds-breakpoints {
.my-custom-breakpoint-class--#{$name} {
// here you have access to the breakpoint name and its value (width in px)
}
}
```

### JavaScript

We also provide helpers in case you need to access the breakpoints names/values in JavaScript code.

You have access to the list of breakpoint names and values using the `hdsBreakpoints` map:

```javascript{data-execute=false}
import { hdsBreakpoints } from '@hashicorp/design-system-components/utils/hds-breakpoints';

// do something with a specific breakpoint value
const myBreakpoint1 = hdsBreakpoints['xl'].value; // numeric (eg. 1440)
const myBreakpoint2 = hdsBreakpoints['lg'].px; // size in px (eg. 1088px)
const myBreakpoint3 = hdsBreakpoints['sm'].rem; // size in rem (eg. 30rem)

// loop over all the breakpoints
Object.entries(hdsBreakpoints).forEach(([name, sizes]) => {
// do something with a specific breakpoint value in px
const myBreakpointSizePx = sizes.px;
});
```
Loading