Skip to content

Commit

Permalink
Merge pull request #2809 from salesforce-ux/feat/carousel
Browse files Browse the repository at this point in the history
feat(carousel): Add carousel component
  • Loading branch information
brandonferrua authored Oct 12, 2017
2 parents 6fb1b9f + 7f718f9 commit 909277f
Show file tree
Hide file tree
Showing 20 changed files with 775 additions and 0 deletions.
Binary file added assets/images/carousel/carousel-01.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/carousel/carousel-02.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/carousel/carousel-03.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions scripts/compile/mdx-post-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const elements = [
'li',
'code',
'blockquote',
'pre',
'tr',
'td',
'th',
Expand Down
1 change: 1 addition & 0 deletions shared/styles/doc.scss
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ h6.doc {

p.doc {
font-size: 1rem;
margin-top: 1.5rem;
margin-bottom: 1.5rem;
}

Expand Down
2 changes: 2 additions & 0 deletions ui/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
'dynamic-icons/waffle/index',
'dynamic-icons/global-action-help/index',

// Carousel
'carousel/base/index',

// Card
'cards/base/index',
Expand Down
8 changes: 8 additions & 0 deletions ui/components/button-icons/base/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,13 @@
.slds-button__icon--inverse-hint {
fill: $color-text-icon-inverse-hint-hover;
}

.slds-button:disabled {

.slds-button__icon_hint,
.slds-button__icon--hint {
fill: currentColor;
}
}
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions ui/components/carousel/__tests__/snapshot.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-env jest */
import React from 'react';
import Carousel from '../';
import createHelpers from '../../../../jest.setup';

const { matchesMarkupAndStyle } = createHelpers(__dirname);

it('renders a carousel, first tab active', () =>
matchesMarkupAndStyle(<Carousel panelActive="1" />));

it('renders a carousel, second tab active', () =>
matchesMarkupAndStyle(<Carousel panelActive="2" />));

it('renders a carousel, third tab active', () =>
matchesMarkupAndStyle(<Carousel panelActive="3" />));

it('renders a carousel, auto-play enabled', () =>
matchesMarkupAndStyle(<Carousel panelActive="1" autoPlay />));

it('renders a carousel, auto-play disabled', () =>
matchesMarkupAndStyle(<Carousel panelActive="1" autoPlay="stop" />));
45 changes: 45 additions & 0 deletions ui/components/carousel/_doc.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

/**
* A Carousel can accept a maximum number of 5 panels where only 1 panel is visible at a time.
*
* You are able to navigate between panels but interacting with the `slds-carousel__indicator` elements that sit below the panel.
*
* A panel becomes visible by toggling the `slds-hide` class with the `slds-show` class on the `slds-carousel__panel` element.
*
* When making the `slds-carousel__panel` active, the indicator should be updated with the `slds-is-active` class. This provides visual feedback showing which carousel panel is active.
*
* ### Accessibility
*
* A Carousel is built using a tabbed UI specification and requires the following to meet accessibility requirements:
*
* - The tab list, which should have `role="tablist"`
* - The tabs in that list, which should each be an `<a role="tab">` anchor wrapped in a `<li role="presentation">` list item
* - The tab panels, which display each tab’s content and should each have `role="tabpanel"`
*
* **Expected markup:**
*
* - Selected tab’s anchor has `aria-selected="true"`, all other tabs’ anchors have `aria-selected="false"`
* - Selected tab’s anchor has `tabindex="0"`, all other tabs have `tabindex="-1"`
* - Each tab’s anchor has an `aria-controls` attribute whose value is the id of the associated `<div role="tabpanel">`
* - Each tab panel has an `aria-labelledby` attribute whose value is the id of its associated `<a role="tab">`
* - When the Carousel is set to auto-play, the HTML for the pause button is required to precede the HTML of the tab set
*
* **Expected keyboard interactions:**
*
* - Arrow keys, when focus is on selected tab, cycle selection to the next or previous tab
* - Tab key, when focus is before the tab list, moves focus to the selected tab panel
* - Tab key, when focus is on selected tabpanel, moves focus into the selected tabpanel's associated tab or to the next focusable element on the page if that panel has no focusable elements
* - Shift+Tab keys, when focus is on first element in a tab panel, move focus focus entirely from tabset
*
* @summary A carousel allows multiple pieces of featured content to occupy an allocated amount of space.
*
* @base
* @name carousel
* @selector .slds-carousel
* @support dev-ready
* @category base
* @type navigation
* @layout responsive
*/
96 changes: 96 additions & 0 deletions ui/components/carousel/_docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import CodeView from '../../../shared/components/CodeView';
import Example from '../../../shared/components/Example';
import Carousel from './';

<div className="lead">
A carousel allows multiple pieces of featured content to occupy an allocated amount of space.
</div>

<Example>
<CodeView>
<Carousel panelActive="1" autoPlay />
</CodeView>
</Example>

A Carousel can accept a maximum number of 5 panels where only 1 panel is visible at a time.

## Navigating between panels

You are able to navigate between panels but interacting with the `slds-carousel__indicator` elements that sit below the panel.

<Example>
<div className="slds-grid slds-grid_pull-padded">
<div className="slds-size_1-of-3 slds-p-horizontal_medium">
<Carousel panelActive="1" />
</div>
<div className="slds-size_1-of-3 slds-p-horizontal_medium">
<Carousel panelActive="2" />
</div>
</div>
</Example>

A panel becomes visible by toggling the `slds-hide` class with the `slds-show` class on the `slds-carousel__panel` element.

```html
<div id="content-id-01" class="slds-carousel__panel slds-show" role="tabpanel" aria-labelledby="indicator-id-01">
...
</div>
<div id="content-id-02" class="slds-carousel__panel slds-hide" role="tabpanel" aria-labelledby="indicator-id-02">
...
</div>
```

When making the `slds-carousel__panel` active, the indicator should be updated with the `slds-is-active` class. This provides visual feedback showing which carousel panel is active.

## Auto-play

<Example>
<Carousel panelActive="1" autoPlay />
</Example>

If the Carousel is set to auto-play, a pause button is required to be first in the HTML before the tab set.

```html
<div class="slds-carousel__stage">

<!-- Pause Button -->
<span class="slds-carousel__autoplay">
<button class="slds-button slds-button_icon slds-button_icon-border-filled slds-button_icon-xx-small" aria-pressed="false" title="Stop auto-play">
<svg class="slds-button__icon" aria-hidden="true">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#pause"></use>
</svg>
<span class="slds-assistive-text">Stop auto-play</span>
</button>
</span>

<!-- Tabs -->
<div class="slds-carousel__panels">
...
</div>
...
</div>
```

When that pause button is interacted with, the `aria-pressed` role needs to be toggled to `true`.

### Accessibility

A Carousel is built using a tabbed UI specification and requires the following to meet accessibility requirements:

- The tab list, which should have `role="tablist"`
- The tabs in that list, which should each be an `<a role="tab">` anchor wrapped in a `<li role="presentation">` list item
- The tab panels, which display each tab’s content and should each have `role="tabpanel"`

**Expected markup:**

- Selected tab’s anchor has `aria-selected="true"`, all other tabs’ anchors have `aria-selected="false"`
- Selected tab’s anchor has `tabindex="0"`, all other tabs have `tabindex="-1"`
- Each tab’s anchor has an `aria-controls` attribute whose value is the id of the associated `<div role="tabpanel">`
- Each tab panel has an `aria-labelledby` attribute whose value is the id of its associated `<a role="tab">`

**Expected keyboard interactions:**

- Arrow keys, when focus is on selected tab, cycle selection to the next or previous tab
- Tab key, when focus is before the tab list, moves focus to the selected tab panel
- Tab key, when focus is on selected tab, moves focus into the selected tab’s associated tab panel or to the next focusable element on the page if that panel has no focusable elements
- Shift+Tab keys, when focus is on first element in a tab panel, move focus to the selected tab
147 changes: 147 additions & 0 deletions ui/components/carousel/base/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

/**
* @summary Initiates a carousel component
* @name base
* @selector .slds-carousel
* @restrict div
* @variant
*/
.slds-carousel {
display: flex;
position: relative;
}

/**
* @summary Main stage for carousel's tab-panels and tab-list inidicators
* @selector .slds-carousel__stage
* @restrict .slds-carousel div
*/
.slds-carousel__stage {
position: relative;
display: flex;
flex-direction: column;
}

/**
* @summary Actionable element that contains the carousel's tab-panel content
* @selector .slds-carousel__panel-action
* @restrict .slds-carousel__stage a
*/
.slds-carousel__panel-action {
display: block;
border: $border-width-thin solid $color-border;
border-radius: $border-radius-medium;

&:focus {
@include focus-button;
border-color: $color-border-brand;
outline: 0;
}
}

/**
* @summary Element that contains the image inside the carousel's tab-panel
* @selector .slds-carousel__image
* @restrict .slds-carousel__panel-action div
*/
.slds-carousel__image {
border-top-left-radius: $border-radius-medium;
border-top-right-radius: $border-radius-medium;
overflow: hidden;
}

/**
* @summary Element that contains the content inside the carousel's tab-panel
* @selector .slds-carousel__content
* @restrict .slds-carousel__panel-action div
*/
.slds-carousel__content {
background: $carousel-color-background;
padding: $spacing-small;
border-bottom-left-radius: $border-radius-medium;
border-bottom-right-radius: $border-radius-medium;
text-align: center;
}

/**
* @summary Heading element that contains the title of the carousel's tab-panel
* @selector .slds-carousel__content-title
* @restrict .slds-carousel__content h2
*/
.slds-carousel__content-title {
font-size: $font-size-heading-small;
font-weight: 600;
}

/**
* @summary List element that contains the carousel's tab-list inidicators
* @selector .slds-carousel__indicators
* @restrict .slds-carousel ul
*/
.slds-carousel__indicators {
align-self: center;
margin: $spacing-x-small 0;
}

/**
* @summary Carousel's tab-list inidicator items
* @selector .slds-carousel__indicator
* @restrict .slds-carousel__indicators li
*/
.slds-carousel__indicator {
display: inline-flex;
margin: 0 $spacing-xxx-small;
}

/**
* @summary Actionable element inside of each tab-list indicator
* @selector .slds-carousel__indicator-action
* @restrict .slds-carousel__indicator a
*/
.slds-carousel__indicator-action {
width: $carousel-indicator-width;
height: $carousel-indicator-width;
background: $carousel-indicator-color-background;
border: $border-width-thin solid $color-border;
border-radius: 50%;

@include mq-medium-min {
width: ($carousel-indicator-width / 2);
height: ($carousel-indicator-width / 2);
}

/**
* @summary Active state notifying the tab that its current panel is active
* @selector .slds-is-active
* @restrict .slds-carousel__indicator-action
*/
&.slds-is-active,
&.slds-is-active:hover {
background: $carousel-indicator-color-background-active;
border-color: $carousel-indicator-color-background-active;
}

&:hover {
background-color: $carousel-indicator-color-background-hover;
}

&:focus {
@include focus-button;
background-color: $carousel-indicator-color-background-focus;
border-color: $carousel-indicator-color-background-focus;
outline: 0;
}
}

/**
* @summary Element that contains the auto-play button icon to toggle on/off
* @selector .slds-carousel__autoplay
* @restrict .slds-carousel__stage div
*/
.slds-carousel__autoplay {
position: absolute;
left: 0;
bottom: $spacing-x-small;
}
39 changes: 39 additions & 0 deletions ui/components/carousel/base/example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

import React from 'react';
import Carousel from '../';

export const Context = props => (
<div style={{ height: '420px' }}>{props.children}</div>
);

export default <Carousel panelActive="1" />;

export let states = [
{
id: 'tab-1-active',
label: 'Tab 1 Active',
element: <Carousel panelActive="1" />
},
{
id: 'tab-2-active',
label: 'Tab 2 Active',
element: <Carousel panelActive="2" />
},
{
id: 'tab-3-active',
label: 'Tab 3 active',
element: <Carousel panelActive="3" />
},
{
id: 'auto-play-enabled',
label: 'Auto-play enabled',
element: <Carousel panelActive="1" autoPlay />
},
{
id: 'auto-play-stopped',
label: 'Auto-play stopped',
element: <Carousel panelActive="1" autoPlay="stop" />
}
];
Loading

0 comments on commit 909277f

Please sign in to comment.