Skip to content

Commit

Permalink
feat(ListBox): add slug prop to Dropdown, MultiSelect, `ComboBo…
Browse files Browse the repository at this point in the history
…x`, and `Select` (#15206)

* feat(TextInput): support slug prop

* fix(TextInput): add types for slug prop

* refactor(Slug): remove old file, move demo to form story

* docs(Storybook): update form story

* feat(NumberInput): add slug to NumberInput

* refactor(NumberInput): remove pseudo elements and use box-shadow

* style(NumberInput): fix issue with z-index, add invalid styles

* feat(DatePicker): add slug prop to DatePickerInput

* feat(TextArea): add slug prop to TextArea

* test(snapshot): update snapshots

* fix(TextArea): remove console warning

* style(Fluid): adjust styles for fluid inputs

* docs(Storybook): fix ids

* fix(Slug): adjust positioning, add storybook controls

* fix(Storybook): add story styles to form example

* fix(Slug): adjust positioning when invalid, warning state

* style(Slug): adjust padding when slug is present

* docs(Storybook): add examples with revert functionality

* fix(NumberInput): fix type error

* refactor(storybook): adjust stories

* feat(Slug): add revertLabel prop

* fix(Undo): replace undo, redo with coreect asset

* feat(ListBox): add Slug prop to ListBox components

* fix(Slug): adjust revert positioning, remove margin

* docs(Storybook): rearrange storybook order

* fix(NumberInput): don't set defaultValue if not provided, remove console

* feat(Select): add Slug prop to Select

* chore(files): add ai-gradient to react package

* test(snapshot): update snapshots

* refactor(Slug): remove aria-hidden
  • Loading branch information
tw15egan authored Nov 16, 2023
1 parent 30d3172 commit 3117cb9
Show file tree
Hide file tree
Showing 11 changed files with 308 additions and 14 deletions.
18 changes: 18 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"titleText": Object {
"type": "node",
},
Expand Down Expand Up @@ -2905,6 +2908,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"titleText": Object {
"isRequired": true,
"type": "node",
Expand Down Expand Up @@ -3606,6 +3612,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"sortItems": Object {
"type": "func",
},
Expand Down Expand Up @@ -5189,6 +5198,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"sortItems": Object {
"type": "func",
},
Expand Down Expand Up @@ -5307,6 +5319,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"sortItems": Object {
"type": "func",
},
Expand Down Expand Up @@ -6507,6 +6522,9 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"warn": Object {
"type": "bool",
},
Expand Down
23 changes: 22 additions & 1 deletion packages/react/src/components/ComboBox/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Downshift, {
ControllerStateAndHelpers,
StateChangeOptions,
} from 'downshift';
import PropTypes from 'prop-types';
import PropTypes, { ReactNodeLike } from 'prop-types';
import React, {
useContext,
useEffect,
Expand Down Expand Up @@ -281,6 +281,11 @@ export interface ComboBoxProps<ItemType>
*/
size?: ListBoxSize;

/**
* Provide a `Slug` component to be rendered inside the `ComboBox` component
*/
slug?: ReactNodeLike;

/**
* Provide text to be used in a `<label>` element that is tied to the
* combobox via ARIA attributes.
Expand Down Expand Up @@ -338,6 +343,7 @@ const ComboBox = forwardRef(
warn,
warnText,
allowCustomValue = false,
slug,
...rest
} = props;
const prefix = usePrefix();
Expand Down Expand Up @@ -505,6 +511,7 @@ const ComboBox = forwardRef(
{
[`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
[`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
[`${prefix}--list-box__wrapper--slug`]: slug,
},
]);

Expand All @@ -516,6 +523,14 @@ const ComboBox = forwardRef(
// needs to be Capitalized for react to render it correctly
const ItemToElement = itemToElement;

// Slug is always size `mini`
let normalizedSlug;
if (slug) {
normalizedSlug = React.cloneElement(slug as React.ReactElement<any>, {
size: 'mini',
});
}

return (
<Downshift
{...downshiftProps}
Expand Down Expand Up @@ -706,6 +721,7 @@ const ComboBox = forwardRef(
translateWithId={translateWithId}
/>
</div>
{normalizedSlug}
<ListBox.Menu
{...getMenuProps({
'aria-label': deprecatedAriaLabel || ariaLabel,
Expand Down Expand Up @@ -927,6 +943,11 @@ ComboBox.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,

/**
* Provide a `Slug` component to be rendered inside the `ComboBox` component
*/
slug: PropTypes.node,

/**
* Provide text to be used in a `<label>` element that is tied to the
* combobox via ARIA attributes.
Expand Down
23 changes: 22 additions & 1 deletion packages/react/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
UseSelectStateChangeTypes,
} from 'downshift';
import cx from 'classnames';
import PropTypes from 'prop-types';
import PropTypes, { ReactNodeLike } from 'prop-types';
import {
Checkmark,
WarningAltFilled,
Expand Down Expand Up @@ -198,6 +198,11 @@ export interface DropdownProps<ItemType>
*/
size?: ListBoxSize;

/**
* Provide a `Slug` component to be rendered inside the `Dropdown` component
*/
slug?: ReactNodeLike;

/**
* Provide the title text that will be read by a screen reader when
* visiting this control
Expand Down Expand Up @@ -255,6 +260,7 @@ const Dropdown = React.forwardRef(
selectedItem: controlledSelectedItem,
downshiftProps,
readOnly,
slug,
...other
}: DropdownProps<ItemType>,
ref: ForwardedRef<HTMLButtonElement>
Expand Down Expand Up @@ -351,6 +357,7 @@ const Dropdown = React.forwardRef(
[`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
[`${prefix}--list-box__wrapper--fluid--focus`]:
isFluid && isFocused && !isOpen,
[`${prefix}--list-box__wrapper--slug`]: slug,
}
);

Expand Down Expand Up @@ -435,6 +442,14 @@ const Dropdown = React.forwardRef(

const menuProps = getMenuProps();

// Slug is always size `mini`
let normalizedSlug;
if (slug) {
normalizedSlug = React.cloneElement(slug as React.ReactElement<any>, {
size: 'mini',
});
}

return (
<div className={wrapperClasses} {...other}>
{titleText && (
Expand Down Expand Up @@ -492,6 +507,7 @@ const Dropdown = React.forwardRef(
translateWithId={translateWithId}
/>
</button>
{normalizedSlug}
<ListBox.Menu {...menuProps}>
{isOpen &&
items.map((item, index) => {
Expand Down Expand Up @@ -684,6 +700,11 @@ Dropdown.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,

/**
* Provide a `Slug` component to be rendered inside the `Dropdown` component
*/
slug: PropTypes.node,

/**
* Provide the title text that will be read by a screen reader when
* visiting this control
Expand Down
90 changes: 89 additions & 1 deletion packages/react/src/components/Form/Form.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

import React, { useState, useRef } from 'react';
import Checkbox from '../Checkbox';
import ComboBox from '../ComboBox';
import Dropdown from '../Dropdown';
import DatePicker from '../DatePicker';
import DatePickerInput from '../DatePickerInput';
import Form from './Form';
import FormGroup from '../FormGroup';
import FileUploader from '../FileUploader';
import { MultiSelect, FilterableMultiSelect } from '../MultiSelect';
import FluidForm from '../FluidForm';
import FluidNumberInput from '../FluidNumberInput';
import FluidDatePicker from '../FluidDatePicker';
Expand Down Expand Up @@ -117,6 +120,34 @@ const buttonEvents = {
className: 'some-class',
};

const items = [
{
id: 'option-0',
text: 'Lorem, ipsum dolor sit amet consectetur adipisicing elit.',
},
{
id: 'option-1',
text: 'Option 1',
},
{
id: 'option-2',
text: 'Option 2',
},
{
id: 'option-3',
text: 'Option 3 - a disabled item',
disabled: true,
},
{
id: 'option-4',
text: 'Option 4',
},
{
id: 'option-5',
text: 'Option 5',
},
];

export default {
title: 'Components/Form',
component: Form,
Expand Down Expand Up @@ -391,13 +422,70 @@ export const _AIForm = (args) => {
</DatePicker>
<TextInput {...TextInputProps} slug={slug} {...rest} />
<TextArea {...textareaProps} slug={slug} {...rest} />
<Dropdown
id="default"
titleText="Dropdown title"
helperText="This is some helper text"
initialSelectedItem={items[1]}
label="Option 1"
items={items}
itemToString={(item) => (item ? item.text : '')}
slug={slug}
{...rest}
/>
<MultiSelect
label="Multiselect Label"
id="carbon-multiselect-example"
titleText="Multiselect title"
helperText="This is helper text"
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
slug={slug}
{...rest}
/>
<FilterableMultiSelect
id="carbon-multiselect-example-3"
titleText="FilterableMultiselect title"
helperText="This is helper text"
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
slug={slug}
{...rest}
/>
<ComboBox
onChange={() => {}}
id="carbon-combobox"
items={items}
itemToString={(item) => (item ? item.text : '')}
titleText="ComboBox title"
helperText="Combobox helper text"
slug={slug}
{...rest}
/>
<Select
id="select-1"
labelText="Select an option"
helperText="Optional helper text"
slug={slug}
{...rest}>
<SelectItem value="" text="" />
<SelectItem
value="An example option that is really long to show what should be done to handle long text"
text="An example option that is really long to show what should be done to handle long text"
/>
<SelectItem value="Option 2" text="Option 2" />
<SelectItem value="Option 3" text="Option 3" />
<SelectItem value="Option 4" text="Option 4" />
</Select>
<Button type="submit" className="some-class" {...buttonEvents}>
Submit
</Button>
</Stack>
</Form>

<FluidForm aria-label="sample form" className="fluid-slug-form">
<FluidForm aria-label="sample ai form" className="fluid-slug-form">
<div style={{ display: 'flex' }}>
<FluidDatePicker datePickerType="single" style={{ width: '100%' }}>
<FluidDatePickerInput
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/components/MultiSelect/FilterableMultiSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect(
useTitleInItem,
warn,
warnText,
slug,
},
ref
) {
Expand Down Expand Up @@ -100,6 +101,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect(
[`${prefix}--list-box--up`]: direction === 'top',
[`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
[`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
[`${prefix}--list-box__wrapper--slug`]: slug,
}
);
const helperId = !helperText
Expand Down Expand Up @@ -207,6 +209,14 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect(
}
}

// Slug is always size `mini`
let normalizedSlug;
if (slug) {
normalizedSlug = React.cloneElement(slug, {
size: 'mini',
});
}

return (
<Selection
disabled={disabled}
Expand Down Expand Up @@ -448,6 +458,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect(
translateWithId={translateWithId}
/>
</div>
{normalizedSlug}
{isOpen ? (
<ListBox.Menu {...menuProps}>
{sortItems(
Expand Down Expand Up @@ -657,6 +668,11 @@ FilterableMultiSelect.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,

/**
* Provide a `Slug` component to be rendered inside the `FilterableMultiSelect` component
*/
slug: PropTypes.node,

...sortingPropTypes,

/**
Expand Down
Loading

0 comments on commit 3117cb9

Please sign in to comment.