Skip to content

Commit

Permalink
feat(@clayui/form): LPD-36696 Add new API to set maximum items for Le…
Browse files Browse the repository at this point in the history
…ft and Right side with error message
  • Loading branch information
matuzalemsteles committed Oct 18, 2024
1 parent dfd8f4c commit 8e0ab50
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 34 deletions.
58 changes: 54 additions & 4 deletions packages/clay-form/src/DualListBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
*/

import {ClayButtonWithIcon} from '@clayui/button';
import {sub} from '@clayui/shared';
import classNames from 'classnames';
import React from 'react';

import Form from './Form';
import ClaySelectBox, {TItem, getSelectedIndexes} from './SelectBox';

type TItems = Array<Array<TItem>>;
Expand Down Expand Up @@ -56,6 +58,7 @@ interface IProps extends React.HTMLAttributes<HTMLDivElement> {
* Labels for the aria attributes
*/
ariaLabels?: {
error?: string;
transferLTR: string;
transferRTL: string;
};
Expand Down Expand Up @@ -104,22 +107,36 @@ interface IProps extends React.HTMLAttributes<HTMLDivElement> {
* Path to the spritemap that Icon should use when referencing symbols.
*/
spritemap?: string;

/**
* Sets the maximum value of items on the left side.
*/
leftMaxItems?: number;

/**
* Sets the maximum value of items on the right side.
*/
rightMaxItems?: number;
}

const defaultError = 'The maximum number of items for {0} is {1}';

const ClayDualListBox = ({
ariaLabels = {
error: defaultError,
transferLTR: 'Transfer Item Left to Right',
transferRTL: 'Transfer Item Right to Left',
},
children,
className,
disabled,
disableLTR,
disableRTL,
items = [[], []],
left = {},
leftMaxItems,
onItemsChange,
right = {},
rightMaxItems,
size,
spritemap,
...otherProps
Expand All @@ -144,6 +161,19 @@ const ClayDualListBox = ({
const selectedIndexesLeft = getSelectedIndexes(leftItems!, leftSelected);
const selectedIndexesRight = getSelectedIndexes(rightItems!, rightSelected);

const isLeftError = leftMaxItems
? rightSelected.length + leftItems!.length > leftMaxItems
: false;
const isRightError = rightMaxItems
? leftSelected.length + rightItems!.length > rightMaxItems
: false;
const hasMaxItemsLeft = leftMaxItems
? leftItems!.length > leftMaxItems
: false;
const hasMaxItemsRight = rightMaxItems
? rightItems!.length > rightMaxItems
: false;

return (
<div {...otherProps} className={classNames(className, 'form-group')}>
<div className="clay-dual-listbox">
Expand All @@ -167,7 +197,12 @@ const ClayDualListBox = ({
aria-label={ariaLabels.transferLTR}
className="transfer-button-ltr"
data-testid="ltr"
disabled={disableLTR || disabled}
disabled={
disableLTR ||
isLeftError ||
hasMaxItemsLeft ||
disabled
}
displayType="secondary"
onClick={() => {
const [arrayLeft, arrayRight] = swapArrayItems(
Expand All @@ -186,7 +221,12 @@ const ClayDualListBox = ({
aria-label={ariaLabels.transferRTL}
className="transfer-button-rtl"
data-testid="rtl"
disabled={disableRTL || disabled}
disabled={
disableRTL ||
isRightError ||
hasMaxItemsRight ||
disabled
}
displayType="secondary"
onClick={() => {
const [arrayRight, arrayLeft] = swapArrayItems(
Expand Down Expand Up @@ -220,7 +260,17 @@ const ClayDualListBox = ({
/>
</div>

{children}
{isLeftError ||
(isRightError && (
<Form.FeedbackGroup className="has-error">
<Form.FeedbackItem>
{sub(ariaLabels.error || defaultError, [
isLeftError ? left.label! : right.label!,
isLeftError ? leftMaxItems! : rightMaxItems!,
])}
</Form.FeedbackItem>
</Form.FeedbackGroup>
))}
</div>
);
};
Expand Down
35 changes: 5 additions & 30 deletions packages/clay-form/stories/DualListBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,10 @@ export const Default = (args: any) => {
const [leftSelected, setLeftSelected] = useState<Array<string>>([]);
const [rightSelected, setRightSelected] = useState<Array<string>>([]);

const [firstSelectBoxItems, secondSelectBoxItems] = items;

const isLeftError =
rightSelected.length + firstSelectBoxItems.length > args.leftMaxItems;
const isRightError =
leftSelected.length + secondSelectBoxItems.length > args.rightMaxItems;

return (
<ClayDualListBox
disableLTR={
args.disableLTR ||
isRightError ||
secondSelectBoxItems.length >= args.rightMaxItems
}
disableRTL={
args.disableRTL ||
isLeftError ||
firstSelectBoxItems.length >= args.leftMaxItems
}
disableLTR={args.disableLTR}
disableRTL={args.disableRTL}
disabled={args.disabled}
items={items}
left={{
Expand All @@ -91,6 +76,7 @@ export const Default = (args: any) => {
onSelectChange: setLeftSelected,
selected: leftSelected,
}}
leftMaxItems={args.leftMaxItems}
onItemsChange={(event) => {
setItems(event);
setLeftSelected([]);
Expand All @@ -102,20 +88,9 @@ export const Default = (args: any) => {
onSelectChange: setRightSelected,
selected: rightSelected,
}}
rightMaxItems={args.rightMaxItems}
size={8}
>
<ClayForm.FeedbackGroup
className={classnames('d-none', 'has-error', {
'd-block': isLeftError || isRightError,
})}
>
<ClayForm.FeedbackItem>
The maximum number of items for{' '}
{isLeftError ? 'Available' : 'In Use'} is{' '}
{args.leftMaxItems}
</ClayForm.FeedbackItem>
</ClayForm.FeedbackGroup>
</ClayDualListBox>
/>
);
};

Expand Down

0 comments on commit 8e0ab50

Please sign in to comment.