-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PBNTR-529] Children for MultiLevelSelect (#3661)
[Runway Story](https://runway.powerhrg.com/backlog_items/PBNTR-529) This PR: - ✅ Creates MultiLevelSelect.Options subcomponent - ✅ Backwards compatible so none subcomponent structure also works - ✅ Render children next to Checkbox/Radios <img width="855" alt="Screenshot 2024-10-01 at 9 41 45 PM" src="https://github.com/user-attachments/assets/20ff1dac-0173-4e0e-8396-ed43d70c530c"> <img width="825" alt="Screenshot 2024-10-01 at 9 42 02 PM" src="https://github.com/user-attachments/assets/f5fa5c6f-e4fd-4409-a53f-5ef838dc53d3">
- Loading branch information
Showing
10 changed files
with
568 additions
and
229 deletions.
There are no files selected for viewing
423 changes: 195 additions & 228 deletions
423
playbook/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx
Large diffs are not rendered by default.
Oops, something went wrong.
5 changes: 5 additions & 0 deletions
5
playbook/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createContext } from "react"; | ||
|
||
const MultiLevelSelectContext = createContext<any>({}); | ||
|
||
export default MultiLevelSelectContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
...ook/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import React from "react"; | ||
import MultiLevelSelect from "../_multi_level_select"; | ||
import Badge from "../../pb_badge/_badge"; | ||
|
||
const treeData = [ | ||
{ | ||
label: "Power Home Remodeling", | ||
value: "Power Home Remodeling", | ||
id: "powerhome1", | ||
expanded: true, | ||
children: [ | ||
{ | ||
label: "People", | ||
value: "People", | ||
id: "people1", | ||
expanded: true, | ||
status: "active", | ||
children: [ | ||
{ | ||
label: "Talent Acquisition", | ||
value: "Talent Acquisition", | ||
id: "talent1", | ||
}, | ||
{ | ||
label: "Business Affairs", | ||
value: "Business Affairs", | ||
id: "business1", | ||
status: "active", | ||
variant: "primary", | ||
|
||
children: [ | ||
{ | ||
label: "Initiatives", | ||
value: "Initiatives", | ||
id: "initiative1", | ||
}, | ||
{ | ||
label: "Learning & Development", | ||
value: "Learning & Development", | ||
id: "development1", | ||
status: "Inactive", | ||
}, | ||
], | ||
}, | ||
{ | ||
label: "People Experience", | ||
value: "People Experience", | ||
id: "experience1", | ||
}, | ||
], | ||
}, | ||
{ | ||
label: "Contact Center", | ||
value: "Contact Center", | ||
id: "contact1", | ||
status: "Inactive", | ||
variant: "error", | ||
children: [ | ||
{ | ||
label: "Appointment Management", | ||
value: "Appointment Management", | ||
id: "appointment1", | ||
}, | ||
{ | ||
label: "Customer Service", | ||
value: "Customer Service", | ||
id: "customer1", | ||
}, | ||
{ | ||
label: "Energy", | ||
value: "Energy", | ||
id: "energy1", | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
const MultiLevelSelectWithChildren = (props) => { | ||
return ( | ||
<div> | ||
<MultiLevelSelect | ||
id="multiselect-with-children" | ||
onSelect={(selectedNodes) => | ||
console.log("Selected Items", selectedNodes) | ||
} | ||
treeData={treeData} | ||
{...props} | ||
> | ||
<MultiLevelSelect.Options> | ||
{(item) => ( | ||
<Badge | ||
marginLeft="sm" | ||
text={item.status} | ||
variant={item.status === "active" ? "success" : "warning"} | ||
/> | ||
)} | ||
</MultiLevelSelect.Options> | ||
</MultiLevelSelect> | ||
</div> | ||
); | ||
}; | ||
|
||
export default MultiLevelSelectWithChildren; |
1 change: 1 addition & 0 deletions
1
...b_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The MultiLevelSelect also provides a subcomponent structure which can be used to render children to the right of the Checkboxes and their labels. As seen in the code snippet below, these children have access to the current item being iterated over which can be used for conditional rendering. |
106 changes: 106 additions & 0 deletions
106
...its/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import React from "react"; | ||
import MultiLevelSelect from "../_multi_level_select"; | ||
import Badge from "../../pb_badge/_badge"; | ||
|
||
const treeData = [ | ||
{ | ||
label: "Power Home Remodeling", | ||
value: "Power Home Remodeling", | ||
id: "powerhome1", | ||
expanded: true, | ||
children: [ | ||
{ | ||
label: "People", | ||
value: "People", | ||
id: "people1", | ||
expanded: true, | ||
status: "active", | ||
children: [ | ||
{ | ||
label: "Talent Acquisition", | ||
value: "Talent Acquisition", | ||
id: "talent1", | ||
}, | ||
{ | ||
label: "Business Affairs", | ||
value: "Business Affairs", | ||
id: "business1", | ||
status: "active", | ||
variant: "primary", | ||
|
||
children: [ | ||
{ | ||
label: "Initiatives", | ||
value: "Initiatives", | ||
id: "initiative1", | ||
}, | ||
{ | ||
label: "Learning & Development", | ||
value: "Learning & Development", | ||
id: "development1", | ||
status: "Inactive", | ||
}, | ||
], | ||
}, | ||
{ | ||
label: "People Experience", | ||
value: "People Experience", | ||
id: "experience1", | ||
}, | ||
], | ||
}, | ||
{ | ||
label: "Contact Center", | ||
value: "Contact Center", | ||
id: "contact1", | ||
status: "Inactive", | ||
variant: "error", | ||
children: [ | ||
{ | ||
label: "Appointment Management", | ||
value: "Appointment Management", | ||
id: "appointment1", | ||
}, | ||
{ | ||
label: "Customer Service", | ||
value: "Customer Service", | ||
id: "customer1", | ||
}, | ||
{ | ||
label: "Energy", | ||
value: "Energy", | ||
id: "energy1", | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
]; | ||
|
||
const MultiLevelSelectWithChildrenWithRadios = (props) => { | ||
return ( | ||
<div> | ||
<MultiLevelSelect | ||
id="multiselect-with-children" | ||
onSelect={(selectedNodes) => | ||
console.log("Selected Items", selectedNodes) | ||
} | ||
treeData={treeData} | ||
variant="single" | ||
{...props} | ||
> | ||
<MultiLevelSelect.Options> | ||
{(item) => ( | ||
<Badge | ||
marginLeft="sm" | ||
text={item.status} | ||
variant={item.status === "active" ? "success" : "warning"} | ||
/> | ||
)} | ||
</MultiLevelSelect.Options> | ||
</MultiLevelSelect> | ||
</div> | ||
); | ||
}; | ||
|
||
export default MultiLevelSelectWithChildrenWithRadios; |
1 change: 1 addition & 0 deletions
1
...ook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
The MultiLevelSelect subcomponent structure is also available in the 'Single Select' variant. In this variant, the children will be rendered to the right of the Radios and their labels. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
149 changes: 149 additions & 0 deletions
149
playbook/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React, {useContext} from "react"; | ||
import classnames from "classnames"; | ||
import MultiLevelSelectContext from "./context"; | ||
import { globalProps, GlobalProps } from "../utilities/globalProps"; | ||
import { | ||
buildAriaProps, | ||
buildCss, | ||
buildDataProps, | ||
buildHtmlProps, | ||
} from "../utilities/props"; | ||
import Checkbox from "../pb_checkbox/_checkbox"; | ||
import Radio from "../pb_radio/_radio"; | ||
import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button"; | ||
import Body from "../pb_body/_body"; | ||
|
||
type MultiLevelSelectOptionsProps = { | ||
aria?: { [key: string]: string }, | ||
children?: React.ReactNode | ((item: any) => React.ReactNode), | ||
className?: string, | ||
dark?: boolean, | ||
data?: { [key: string]: string }, | ||
htmlOptions?: {[key: string]: string | number | boolean | (() => void)}, | ||
} & GlobalProps; | ||
|
||
const MultiLevelSelectOptions = ({ | ||
children, | ||
items, | ||
...props | ||
}: MultiLevelSelectOptionsProps) => { | ||
const { | ||
variant, | ||
inputName, | ||
renderNestedOptions, | ||
isTreeRowExpanded, | ||
handleToggleClick, | ||
handleRadioButtonClick, | ||
handledropdownItemClick, | ||
filterItem, | ||
} = useContext(MultiLevelSelectContext) | ||
|
||
const { | ||
aria = {}, | ||
className, | ||
data = {}, | ||
htmlOptions = {}, | ||
} = props; | ||
|
||
const ariaProps = buildAriaProps(aria); | ||
const dataProps = buildDataProps(data); | ||
const htmlProps = buildHtmlProps(htmlOptions); | ||
const classes = classnames( | ||
buildCss("pb_multi_level_select_options"), | ||
globalProps(props), | ||
className | ||
); | ||
|
||
return ( | ||
<ul | ||
{...ariaProps} | ||
{...dataProps} | ||
{...htmlProps} | ||
className={classes} | ||
> | ||
{Array.isArray(items) && | ||
items.map((item: { [key: string]: any }) => { | ||
return ( | ||
<div key={item.id}> | ||
<li className={"dropdown_item"} | ||
data-name={item.id} | ||
> | ||
<div className="dropdown_item_checkbox_row"> | ||
{!item.parent_id && !item.children ? null : ( | ||
<div | ||
key={ | ||
isTreeRowExpanded(item) | ||
? "chevron-down" | ||
: "chevron-right" | ||
} | ||
> | ||
<CircleIconButton | ||
className={ | ||
item.children && item.children.length > 0 | ||
? "" | ||
: "toggle_icon" | ||
} | ||
icon={ | ||
isTreeRowExpanded(item) | ||
? "chevron-down" | ||
: "chevron-right" | ||
} | ||
onClick={(event: React.MouseEvent) => | ||
handleToggleClick(item.id, event) | ||
} | ||
variant="link" | ||
/> | ||
</div> | ||
)} | ||
{variant === "single" ? ( | ||
item.hideRadio ? ( | ||
<Body>{item.label}</Body> | ||
) : ( | ||
<Radio | ||
checked={item.checked} | ||
id={`${item.id}-${item.label}`} | ||
label={item.label} | ||
name={inputName} | ||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => | ||
handleRadioButtonClick(e) | ||
} | ||
padding={item.children ? "none" : "xs"} | ||
type="radio" | ||
value={item.label} | ||
/> | ||
) | ||
) : ( | ||
<Checkbox id={item.id} | ||
text={item.label} | ||
> | ||
<input | ||
checked={item.checked} | ||
name={item.label} | ||
onChange={(e) => { | ||
handledropdownItemClick(e, !item.checked); | ||
}} | ||
type="checkbox" | ||
value={item.label} | ||
/> | ||
</Checkbox> | ||
)} | ||
{/* Render children next to the checkbox */} | ||
{children && ( | ||
typeof children === "function" ? children(item) : children | ||
)} | ||
</div> | ||
{isTreeRowExpanded(item) && | ||
item.children && | ||
item.children.length > 0 && | ||
(variant === "single" || !filterItem) && ( | ||
<div>{renderNestedOptions(item.children)}</div> | ||
)} | ||
</li> | ||
</div> | ||
); | ||
})} | ||
</ul> | ||
); | ||
}; | ||
|
||
export default MultiLevelSelectOptions; |