Skip to content
Permalink
Browse files

feat(dueling-picklist): Update docs to add non-reorderable version an…

…d view mode (#3048)
  • Loading branch information...
Ayesha Mazumdar
Ayesha Mazumdar committed Feb 8, 2018
1 parent 6c79edd commit c336057d070b1db456d23f7a8ddd58d224e36cdb
Showing with 12,017 additions and 117 deletions.
  1. +987 −0 test/__tests__/__snapshots__/Dueling_Picklist.json
  2. +1,079 −0 test/__tests__/__snapshots__/Dueling_Picklist_Disabled.json
  3. +88 −0 test/__tests__/__snapshots__/Dueling_Picklist_in_View_Mode.json
  4. +987 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Item_Selected.json
  5. +987 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Items_Dropped.json
  6. +987 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Multiple_Items_Selected.json
  7. +1,049 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reoder_Active.json
  8. +1,049 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reoder_Active_Item_Dropped.json
  9. +1,049 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reoder_Active_Item_Grabbed.json
  10. +1,049 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reoder_Active_Item_Moved_within_List.json
  11. +1,049 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reoder_Active_Item_Selected.json
  12. +60 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_Reorder.json
  13. +982 −0 test/__tests__/__snapshots__/Dueling_Picklist_with_a_Locked_Item.json
  14. +1 −1 ui/components/dueling-picklist/__tests__/__snapshots__/renders_a_default_dueling_picklist.json
  15. +51 −0 ...eling-picklist/__tests__/__snapshots__/renders_a_default_dueling_picklist_with_no_reordering.json
  16. +1 −1 ui/components/dueling-picklist/__tests__/__snapshots__/renders_a_disabled_dueling_picklist.json
  17. +7 −7 ...ts/dueling-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_a_dropped_option.json
  18. +7 −7 ...ts/dueling-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_a_grabbed_option.json
  19. +1 −1 ...s/dueling-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_a_required_option.json
  20. +7 −7 ...s/dueling-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_a_selected_option.json
  21. +7 −7 ...ng-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_an_option_that_was_moved.json
  22. +7 −7 ...sts__/__snapshots__/renders_a_dueling_picklist_with_an_option_that_was_moved_to_another_list.json
  23. +1 −1 ...g-picklist/__tests__/__snapshots__/renders_a_dueling_picklist_with_multiple_selected_options.json
  24. +12 −0 ui/components/dueling-picklist/__tests__/__snapshots__/renders_a_view_mode_of_dueling_picklist.json
  25. +8 −1 ui/components/dueling-picklist/__tests__/index.spec.js
  26. +1 −36 ui/components/dueling-picklist/_doc.scss
  27. +10 −1 ui/components/dueling-picklist/base/_index.scss
  28. +12 −1 ui/components/dueling-picklist/base/example.jsx
  29. +187 −0 ui/components/dueling-picklist/docs.mdx
  30. +288 −32 ui/components/dueling-picklist/index.js
  31. +5 −6 ui/components/select/_doc.scss
  32. +2 −1 ui/components/select/base/example.jsx

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -11,7 +11,8 @@ import {
GrabbedSnapShot,
MovedInSnapShot,
DroppedSnapShot,
MoveToSnapShot
MoveToSnapShot,
MultiSelectViewMode
} from '../';

import createHelpers from '../../../../jest.setup';
@@ -21,6 +22,9 @@ const { matchesMarkupAndStyle } = createHelpers(__dirname);
it('renders a default dueling picklist', () =>
matchesMarkupAndStyle(<MultiSelect dataSet={DefaultSnapShot} />));

it('renders a default dueling picklist with no reordering', () =>
matchesMarkupAndStyle(<MultiSelect dataSet={DefaultSnapShot} noReorder />));

it('renders a dueling picklist with a required option', () =>
matchesMarkupAndStyle(<MultiSelect dataSet={LockedSnapShot} />));

@@ -44,3 +48,6 @@ it('renders a dueling picklist with a dropped option', () =>

it('renders a dueling picklist with an option that was moved to another list', () =>
matchesMarkupAndStyle(<MultiSelect dataSet={MovedInSnapShot} />));

it('renders a view mode of dueling picklist', () =>
matchesMarkupAndStyle(<MultiSelectViewMode />));
@@ -2,42 +2,7 @@
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license

/**
* #### Accessibility
* This component is essentially 2 ARIA listboxes side by side, so we follow the [ARIA practices guide](https://www.w3.org/TR/wai-aria-practices/#Listbox) to help implement their interaction in an accessible way. Some additional details, supplementary to the ARIA guide include:
*
* **Notable attributes**
* - `aria-multiselectable="true"` should be set on each listbox
* - `aria-selected` should be placed on each `role="option`, and only set to `true` when selected
* - `aria-labelledby` is used to identify the list to the user and should point to the list label
* - `aria-describedby` is used to provide operation instructions for the Drag and Drop interaction
* - `tabindex` should be set to "0" when an item is selected and "-1" otherwise
*
* **Focus management**
* - Initially, nothing should be selected and the first item in each list should have `tabindex="0"`
* - When an item is focused, it becomes selected
* - When focus leaves the list, the last selected item remains selected and focusable. When focus returns to the list focus is placed on the last selected item.
* - When moving items:
* - With the move button: the items are unselected and added to the target list. The focus should remain on the move button.
* - With a keyboard shortcut: focus remains on the item, but in the target list. Since the item is focused, it is also selected.
* - If there are already selected items in the target list, they stay selected and the new items are added below them.
*
* **Keyboard navigation**
* - Each list is a tab stop. This provides identification and operation instruction as provided by `aria-describedby` and `aria-labelledby`. State of the overall list is also provided, including total number and number of selected options in the list when focused.
* - Because we support drag and drop re-ordering, we implement the second multi-select keyboard model.
* - `up` and `down` arrows move focus _and_ selection, with `aria-selected="true"`. Any previously selected items are deselected.
* - `shift + up` and `shift + down` move focus and creates addition selections
* - `ctrl + down` or `ctrl + up` moves focus but selection remains where it is
* - `ctrl + space` toggles selection on the focused option, in addition to previous selections
* - `ctrl + a` selects all options in the list
* - `cmd/ctrl + right` and `cmd/ctrl + left` Moves selected items between lists
* - `space` toggles "Drag and Drop" mode. When in "Drag and Drop" mode:
* - `up` and `down` arrows move the selected items _within_ the current list
*
* **Updating operation and state**
* - The content in the `option-drag-label` assistive text should provide clear instructions on how to drag and drop with a keyboard
* - The `aria-live` region should update as items are moved to provide context about the state and location of the items
*
* @summary Dueling picklist are used to move options between two lists. The list options can be re-ordered.
* @summary A dueling-picklist is used to move options between two lists and is often referred to as a multi-select. Sometimes, the list options can then be re-ordered, depending on the use case.
*
* @base
* @name dueling-picklist
@@ -53,7 +53,7 @@

/**
* @summary Selected/dragging state of a listbox option
* @selector .slds-is-grabbed
* @selector .slds-is-selected
* @restrict .slds-dueling-list__options div
*/
[aria-selected="true"] {
@@ -67,6 +67,15 @@
}
}

/**
* @summary grabbed state of a listbox option
* @selector .slds-is-grabbed
* @restrict .slds-dueling-list__options div
*/
.slds-is-grabbed {
transform: rotate(3deg);
}

/**
* @summary Disabled state of a picklist option
* @selector .slds-is-disabled
@@ -12,7 +12,8 @@ import {
GrabbedSnapShot,
MovedInSnapShot,
DroppedSnapShot,
MoveToSnapShot
MoveToSnapShot,
MultiSelectViewMode
} from '../';
/// ////////////////////////////////////////
// Examples
@@ -60,5 +61,15 @@ export let states = [
id: 'multi-select-moved-to',
label: 'Moved to list',
element: <MultiSelect dataSet={MoveToSnapShot} />
},
{
id: 'no-reordering-dueling-picklist',
label: 'No Reordering',
element: <MultiSelect dataSet={DefaultSnapShot} noReorder />
},
{
id: 'view-mode-dueling-picklist',
label: 'View Mode',
element: <MultiSelectViewMode />
}
];
@@ -0,0 +1,187 @@
import CodeView from '../../../shared/components/CodeView';
import CodeBlock from '../../../shared/components/CodeBlock';
import Example from '../../../shared/components/Example';
import Blockquote from '../../../shared/components/Blockquote';
import { MultiSelect, MultiSelectViewMode, DefaultSnapShot, LockedSnapShot, DisabledSnapShot, SelectedSnapShot, MultiSelectedSnapShot, GrabbedSnapShot, MovedInSnapShot, DroppedSnapShot, MoveToSnapShot, CountriesSnapshot, SelectedCountriesSnapshot, MultipleSelectedCountriesSnapshot, DroppedCountriesSnapshot } from './';
import { DoctypeIcon } from '../icons/doctype/example';

<div className="doc lead">
A dueling-picklist is used to move options between two lists and is often referred to as a multi-select. Sometimes, the list options can then be re-ordered, depending on the use case.
</div>

<Example title="Dueling Picklist with Reorder">
<MultiSelect dataSet={DefaultSnapShot} />
</Example>

This component is essentially 2 ARIA listboxes side by side, so we follow the [ARIA practices guide](https://www.w3.org/TR/wai-aria-practices/#Listbox) to help implement their interaction in an accessible way. Some additional details, supplementary to the ARIA guide include:

## Notable Attributes
- `aria-multiselectable="true"` should be set on each listbox
- `aria-selected` should be placed on each `role="option"`, and set to `false` by default
- `aria-labelledby` is used to identify the list to the user and should point to the list label
- `aria-describedby` is used to provide operation instructions for the Drag and Drop interaction
- `tabindex` should be set to "0" when an item is selected and "-1" otherwise

## Focus Management
- Initially, nothing should be selected and the first item in each list should have `tabindex="0"`
- When an item is focused, it becomes selected
- When focus leaves the list, the last selected item remains selected and focusable. When focus returns to the list focus is placed on the last selected item.
- When moving items:
- With the move button: the items are unselected and added to the target list. The focus should remain on the move button.
- With a keyboard shortcut: focus remains on the item, but in the target list. Since the item is focused, it is also selected.
- If there are already selected items in the target list, they stay selected and the new items are added below them.

## Expected Keyboard Navigation
- Each list has a single focusable option inside. There is only ever one focusable option per list and it is expected that a user will use their arrow keys, and some modifier keys, to perform all actions.
- Because we support drag and drop re-ordering within a list, we implement the second multi-select keyboard model.
- `up` and `down` arrows move focus _and_ selection, with `aria-selected="true"`. Any previously selected items are deselected.
- `shift + up` and `shift + down` move focus and creates addition selections
- `ctrl + down` or `ctrl + up` moves focus but selection remains where it is
- `ctrl + space` toggles selection on the focused option, in addition to previous selections
- `ctrl + a` selects all options in the list
- `cmd/ctrl + right` and `cmd/ctrl + left` Moves selected items between lists
- `space` toggles "Drag and Drop" mode. When in "Drag and Drop" mode:
- `up` and `down` arrows move the selected items _within_ the current list


## Edit Mode

If the user needs to select multiple options for a field, like a list of languages supported, then use a dueling picklist without the re-order arrows on the right.

<Blockquote header="Helpful Assistive Text" type="a11y">
The assistive text content in the `option-drag-label` `<div>` should provide clear instructions on how to drag and drop with a keyboard.
</Blockquote>

<Example title="Dueling Picklist">
<CodeView>
<MultiSelect dataSet={CountriesSnapshot} noReorder />
</CodeView>
</Example>

### Selected Item

<Blockquote header="Aria Selected" type="a11y">
<code class="doc">aria-selected</code> should be placed on each <code class="doc">role="option"</code>, and set to <code class="doc">true</code> when the item is selected.
</Blockquote>

<Example title="Dueling Picklist with Item Selected">
<CodeView>
<MultiSelect dataSet={SelectedCountriesSnapshot} noReorder />
</CodeView>
</Example>

### Multiple Selected Items

<Example title="Dueling Picklist with Multiple Items Selected">
<CodeView>
<MultiSelect dataSet={MultipleSelectedCountriesSnapshot} noReorder />
</CodeView>
</Example>

### Dropped Items

<Blockquote type="a11y" header="Aria Live">
The `drag-live-region` `<div>` with `aria-live="assertive"` should update as items are moved to provide context about the state and location of the items.
</Blockquote>

<CodeBlock toggleCode={false}>
<div class="slds-dueling-list">
<div class="slds-assistive-text" id="drag-live-region" aria-live="assertive">
Arabic and German: Moved to Selected Languages.
</div>
</div>
</CodeBlock>

<Example title="Dueling Picklist with Items Dropped">
<CodeView>
<MultiSelect dataSet={DroppedCountriesSnapshot} noReorder />
</CodeView>
</Example>

### Locked Items

If items are not able to be removed from the selected list, a lock icon appears next to the item name.

<Example title="Dueling Picklist with a Locked Item">
<CodeView>
<MultiSelect dataSet={LockedSnapShot} noReorder />
</CodeView>
</Example>

### With Reordering

If the order of the selected options matters, include the vertical arrows to the right. This allows the user to reorder the second listbox of options.

<Example title="Dueling Picklist with Reoder Active">
<CodeView>
<MultiSelect dataSet={DefaultSnapShot} />
</CodeView>
</Example>

The following examples show the process of selecting an item, moving it within a list, and dropping it in a final position.

<Blockquote type="a11y" header="Aria Live">
Pay attention to the `drag-live-region` `<div>` with `aria-live="assertive"`. This should update as items are moved to provide context about the state and location of the items at all times.
</Blockquote>

#### Item Selected

<Example title="Dueling Picklist with Reoder Active Item Selected">
<CodeView>
<MultiSelect dataSet={SelectedSnapShot} />
</CodeView>
</Example>

#### Item Grabbed

Within a list, users are able to drag and drop an item.

<Example title="Dueling Picklist with Reoder Active Item Grabbed">
<CodeView>
<MultiSelect dataSet={GrabbedSnapShot} />
</CodeView>
</Example>

#### Item Moved Within a List

<Example title="Dueling Picklist with Reoder Active Item Moved within List">
<CodeView>
<MultiSelect dataSet={MovedInSnapShot} />
</CodeView>
</Example>

#### Item Dropped in a List

<Example title="Dueling Picklist with Reoder Active Item Dropped">
<CodeView>
<MultiSelect dataSet={DroppedSnapShot} />
</CodeView>
</Example>

### Disabled

If the user is not able to interact with the dueling picklist, then it should be marked as disabled.

<Blockquote type="a11y" header="Aria Disabled">
In disabled mode, both list boxes <code class="doc">ul[role=listbox]</code> should receive <code class="doc">aria-disabled="true"</code>, and all directional buttons should receive the <code class="doc">disabled</code> attribute.
</Blockquote>

<Blockquote type="note" header="Utility Class">
The class <code class="doc">slds-is-disabled</code> should also be applied to the divs with the class <code class="doc">slds-dueling-list_options</code>.
</Blockquote>

<Example title="Dueling Picklist Disabled">
<CodeView>
<MultiSelect dataSet={DisabledSnapShot} disabled />
</CodeView>
</Example>

## View Mode

When the user is done selecting options, or is in view mode of the field, they are presented with a comma separated list.

<Example title="Dueling Picklist in View Mode">
<CodeView>
<MultiSelectViewMode />
</CodeView>
</Example>
Oops, something went wrong.

0 comments on commit c336057

Please sign in to comment.
You can’t perform that action at this time.