playbook_ui 14.5.0.pre.alpha.javascriptassets3932 → 14.5.0.pre.alpha.play1586datearea4115

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/index.js +60 -0
  3. data/app/pb_kits/playbook/pb_advanced_table/table_header.html.erb +1 -9
  4. data/app/pb_kits/playbook/pb_advanced_table/table_subrow_header.html.erb +1 -9
  5. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +20 -4
  6. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.jsx +45 -0
  7. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_clear_selection.md +1 -0
  8. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +1 -0
  9. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +1 -0
  10. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +1 -1
  11. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +2 -2
  12. data/app/pb_kits/playbook/pb_enhanced_element/{element_observer.js → element_observer.ts} +27 -19
  13. data/app/pb_kits/playbook/pb_enhanced_element/{index.js → index.ts} +22 -15
  14. data/app/pb_kits/playbook/pb_filter/Filter/ResultsCount.tsx +4 -2
  15. data/app/pb_kits/playbook/pb_filter/docs/_filter_default.jsx +1 -1
  16. data/app/pb_kits/playbook/pb_form_pill/_form_pill.tsx +9 -1
  17. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +19 -0
  18. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +27 -0
  19. data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.md +1 -0
  20. data/app/pb_kits/playbook/pb_form_pill/docs/example.yml +2 -0
  21. data/app/pb_kits/playbook/pb_form_pill/docs/index.js +1 -0
  22. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +211 -227
  23. data/app/pb_kits/playbook/pb_multi_level_select/context/index.tsx +5 -0
  24. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +1 -1
  25. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +93 -0
  26. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.md +1 -0
  27. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +105 -0
  28. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.md +1 -0
  29. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +106 -0
  30. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.md +1 -0
  31. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +4 -0
  32. data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +2 -0
  33. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select_options.tsx +149 -0
  34. data/app/pb_kits/playbook/pb_timeline/_date_area.tsx +38 -0
  35. data/app/pb_kits/playbook/pb_timeline/_detail_area.tsx +29 -0
  36. data/app/pb_kits/playbook/pb_timeline/_item.tsx +59 -23
  37. data/app/pb_kits/playbook/pb_timeline/_node_area.tsx +42 -0
  38. data/app/pb_kits/playbook/pb_timeline/date_area.html.erb +12 -0
  39. data/app/pb_kits/playbook/pb_timeline/date_area.rb +13 -0
  40. data/app/pb_kits/playbook/pb_timeline/detail_area.html.erb +3 -0
  41. data/app/pb_kits/playbook/pb_timeline/detail_area.rb +11 -0
  42. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb +43 -0
  43. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx +72 -0
  44. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.md +4 -0
  45. data/app/pb_kits/playbook/pb_timeline/docs/example.yml +2 -1
  46. data/app/pb_kits/playbook/pb_timeline/docs/index.js +1 -0
  47. data/app/pb_kits/playbook/pb_timeline/item.html.erb +17 -21
  48. data/app/pb_kits/playbook/pb_timeline/item.rb +4 -0
  49. data/app/pb_kits/playbook/pb_timeline/node_area.html.erb +14 -0
  50. data/app/pb_kits/playbook/pb_timeline/node_area.rb +16 -0
  51. data/app/pb_kits/playbook/pb_timeline/timeline.test.js +84 -0
  52. data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +4 -1
  53. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +3 -1
  54. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +3 -1
  55. data/dist/chunks/{_typeahead-DqTGx35s.js → _typeahead-C9g4qCcE.js} +2 -2
  56. data/dist/chunks/_weekday_stacked-C2sJArua.js +45 -0
  57. data/dist/chunks/{lib-BhrtJPWD.js → lib-CEpcaI8y.js} +1 -1
  58. data/dist/chunks/{pb_form_validation-XV0GXRlN.js → pb_form_validation-D9zkwt2b.js} +1 -1
  59. data/dist/chunks/vendor.js +1 -1
  60. data/dist/playbook-doc.js +1 -1
  61. data/dist/playbook-rails-react-bindings.js +1 -1
  62. data/dist/playbook-rails.js +1 -1
  63. data/lib/playbook/pb_doc_helper.rb +5 -5
  64. data/lib/playbook/version.rb +1 -1
  65. metadata +33 -10
  66. data/dist/chunks/_weekday_stacked-020WXOXv.js +0 -45
  67. data/dist/chunks/index-CpbZDsWE.js +0 -1
  68. data/dist/playbook-rails-friendly.js +0 -1
@@ -0,0 +1,93 @@
1
+ <% treeData = [{
2
+ label: "Power Home Remodeling",
3
+ value: "Power Home Remodeling",
4
+ id: "100",
5
+ expanded: true,
6
+ children: [
7
+ {
8
+ label: "People",
9
+ value: "People",
10
+ id: "101",
11
+ expanded: true,
12
+ children: [
13
+ {
14
+ label: "Talent Acquisition",
15
+ value: "Talent Acquisition",
16
+ id: "102",
17
+ },
18
+ {
19
+ label: "Business Affairs",
20
+ value: "Business Affairs",
21
+ id: "103",
22
+ children: [
23
+ {
24
+ label: "Initiatives",
25
+ value: "Initiatives",
26
+ id: "104",
27
+ },
28
+ {
29
+ label: "Learning & Development",
30
+ value: "Learning & Development",
31
+ id: "105",
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ label: "People Experience",
37
+ value: "People Experience",
38
+ id: "106",
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ label: "Contact Center",
44
+ value: "Contact Center",
45
+ id: "107",
46
+ children: [
47
+ {
48
+ label: "Appointment Management",
49
+ value: "Appointment Management",
50
+ id: "108",
51
+ },
52
+ {
53
+ label: "Customer Service",
54
+ value: "Customer Service",
55
+ id: "109",
56
+ },
57
+ {
58
+ label: "Energy",
59
+ value: "Energy",
60
+ id: "110",
61
+ },
62
+ ],
63
+ },
64
+ ],
65
+ }] %>
66
+
67
+ <%= pb_rails("multi_level_select", props: {
68
+ id: "multi-level-select-reset-example",
69
+ name: "my_array",
70
+ tree_data: treeData,
71
+ return_all_selected: true
72
+ }) %>
73
+
74
+ <%= pb_rails("button", props: { text: "Reset", margin_top: "lg", id:"multilevelselect-reset-button" }) %>
75
+
76
+
77
+ <script>
78
+ window.addEventListener('DOMContentLoaded', () => {
79
+ const exampleResetButton = document.querySelector("#multilevelselect-reset-button");
80
+
81
+ exampleResetButton.addEventListener("click", () => {
82
+ clearMultiLevelSelectById('multi-level-select-reset-example');
83
+ });
84
+ function clearMultiLevelSelectById(id) {
85
+ const clearFunction = window[`clearMultiLevelSelect_${id}`];
86
+ if (clearFunction) {
87
+ clearFunction();
88
+ } else {
89
+ console.warn(`No clear function found for MultiLevelSelect with id: ${id}`);
90
+ }
91
+ }
92
+ })
93
+ </script>
@@ -0,0 +1 @@
1
+ In order to clear the multilevelselect selection using an external trigger (like a reset button), the `clearMultiLevelSelect` function can be used. See the code snippet below to see this in action. The function is scoped by id so an id MUST be used on the multilevelselect kit and passed to the function as shown for it to work.
@@ -0,0 +1,105 @@
1
+ import React from "react";
2
+ import MultiLevelSelect from "../_multi_level_select";
3
+ import Badge from "../../pb_badge/_badge";
4
+
5
+ const treeData = [
6
+ {
7
+ label: "Power Home Remodeling",
8
+ value: "Power Home Remodeling",
9
+ id: "powerhome1",
10
+ expanded: true,
11
+ children: [
12
+ {
13
+ label: "People",
14
+ value: "People",
15
+ id: "people1",
16
+ expanded: true,
17
+ status: "active",
18
+ children: [
19
+ {
20
+ label: "Talent Acquisition",
21
+ value: "Talent Acquisition",
22
+ id: "talent1",
23
+ },
24
+ {
25
+ label: "Business Affairs",
26
+ value: "Business Affairs",
27
+ id: "business1",
28
+ status: "active",
29
+ variant: "primary",
30
+
31
+ children: [
32
+ {
33
+ label: "Initiatives",
34
+ value: "Initiatives",
35
+ id: "initiative1",
36
+ },
37
+ {
38
+ label: "Learning & Development",
39
+ value: "Learning & Development",
40
+ id: "development1",
41
+ status: "Inactive",
42
+ },
43
+ ],
44
+ },
45
+ {
46
+ label: "People Experience",
47
+ value: "People Experience",
48
+ id: "experience1",
49
+ },
50
+ ],
51
+ },
52
+ {
53
+ label: "Contact Center",
54
+ value: "Contact Center",
55
+ id: "contact1",
56
+ status: "Inactive",
57
+ variant: "error",
58
+ children: [
59
+ {
60
+ label: "Appointment Management",
61
+ value: "Appointment Management",
62
+ id: "appointment1",
63
+ },
64
+ {
65
+ label: "Customer Service",
66
+ value: "Customer Service",
67
+ id: "customer1",
68
+ },
69
+ {
70
+ label: "Energy",
71
+ value: "Energy",
72
+ id: "energy1",
73
+ },
74
+ ],
75
+ },
76
+ ],
77
+ },
78
+ ];
79
+
80
+ const MultiLevelSelectWithChildren = (props) => {
81
+ return (
82
+ <div>
83
+ <MultiLevelSelect
84
+ id="multiselect-with-children"
85
+ onSelect={(selectedNodes) =>
86
+ console.log("Selected Items", selectedNodes)
87
+ }
88
+ treeData={treeData}
89
+ {...props}
90
+ >
91
+ <MultiLevelSelect.Options>
92
+ {(item) => (
93
+ <Badge
94
+ marginLeft="sm"
95
+ text={item.status}
96
+ variant={item.status === "active" ? "success" : "warning"}
97
+ />
98
+ )}
99
+ </MultiLevelSelect.Options>
100
+ </MultiLevelSelect>
101
+ </div>
102
+ );
103
+ };
104
+
105
+ export default MultiLevelSelectWithChildren;
@@ -0,0 +1 @@
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.
@@ -0,0 +1,106 @@
1
+ import React from "react";
2
+ import MultiLevelSelect from "../_multi_level_select";
3
+ import Badge from "../../pb_badge/_badge";
4
+
5
+ const treeData = [
6
+ {
7
+ label: "Power Home Remodeling",
8
+ value: "Power Home Remodeling",
9
+ id: "powerhome1",
10
+ expanded: true,
11
+ children: [
12
+ {
13
+ label: "People",
14
+ value: "People",
15
+ id: "people1",
16
+ expanded: true,
17
+ status: "active",
18
+ children: [
19
+ {
20
+ label: "Talent Acquisition",
21
+ value: "Talent Acquisition",
22
+ id: "talent1",
23
+ },
24
+ {
25
+ label: "Business Affairs",
26
+ value: "Business Affairs",
27
+ id: "business1",
28
+ status: "active",
29
+ variant: "primary",
30
+
31
+ children: [
32
+ {
33
+ label: "Initiatives",
34
+ value: "Initiatives",
35
+ id: "initiative1",
36
+ },
37
+ {
38
+ label: "Learning & Development",
39
+ value: "Learning & Development",
40
+ id: "development1",
41
+ status: "Inactive",
42
+ },
43
+ ],
44
+ },
45
+ {
46
+ label: "People Experience",
47
+ value: "People Experience",
48
+ id: "experience1",
49
+ },
50
+ ],
51
+ },
52
+ {
53
+ label: "Contact Center",
54
+ value: "Contact Center",
55
+ id: "contact1",
56
+ status: "Inactive",
57
+ variant: "error",
58
+ children: [
59
+ {
60
+ label: "Appointment Management",
61
+ value: "Appointment Management",
62
+ id: "appointment1",
63
+ },
64
+ {
65
+ label: "Customer Service",
66
+ value: "Customer Service",
67
+ id: "customer1",
68
+ },
69
+ {
70
+ label: "Energy",
71
+ value: "Energy",
72
+ id: "energy1",
73
+ },
74
+ ],
75
+ },
76
+ ],
77
+ },
78
+ ];
79
+
80
+ const MultiLevelSelectWithChildrenWithRadios = (props) => {
81
+ return (
82
+ <div>
83
+ <MultiLevelSelect
84
+ id="multiselect-with-children"
85
+ onSelect={(selectedNodes) =>
86
+ console.log("Selected Items", selectedNodes)
87
+ }
88
+ treeData={treeData}
89
+ variant="single"
90
+ {...props}
91
+ >
92
+ <MultiLevelSelect.Options>
93
+ {(item) => (
94
+ <Badge
95
+ marginLeft="sm"
96
+ text={item.status}
97
+ variant={item.status === "active" ? "success" : "warning"}
98
+ />
99
+ )}
100
+ </MultiLevelSelect.Options>
101
+ </MultiLevelSelect>
102
+ </div>
103
+ );
104
+ };
105
+
106
+ export default MultiLevelSelectWithChildrenWithRadios;
@@ -0,0 +1 @@
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.
@@ -7,6 +7,7 @@ examples:
7
7
  - multi_level_select_selected_ids: Selected Ids
8
8
  - multi_level_select_with_form: With Form
9
9
  - multi_level_select_color: With Pills (Custom Color)
10
+ - multi_level_select_reset: Reset Selection
10
11
 
11
12
  react:
12
13
  - multi_level_select_default: Default
@@ -15,3 +16,6 @@ examples:
15
16
  - multi_level_select_return_all_selected: Return All Selected
16
17
  - multi_level_select_selected_ids_react: Selected Ids
17
18
  - multi_level_select_color: With Pills (Custom Color)
19
+ - multi_level_select_with_children: Checkboxes With Children
20
+ - multi_level_select_with_children_with_radios: Single Select With Children
21
+
@@ -4,3 +4,5 @@ export { default as MultiLevelSelectSingleChildrenOnly } from './_multi_level_se
4
4
  export { default as MultiLevelSelectReturnAllSelected } from './_multi_level_select_return_all_selected.jsx'
5
5
  export { default as MultiLevelSelectSelectedIdsReact } from "./_multi_level_select_selected_ids_react.jsx"
6
6
  export { default as MultiLevelSelectColor } from './_multi_level_select_color.jsx'
7
+ export { default as MultiLevelSelectWithChildren } from './_multi_level_select_with_children.jsx'
8
+ export { default as MultiLevelSelectWithChildrenWithRadios } from './_multi_level_select_with_children_with_radios.jsx'
@@ -0,0 +1,149 @@
1
+ import React, {useContext} from "react";
2
+ import classnames from "classnames";
3
+ import MultiLevelSelectContext from "./context";
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps";
5
+ import {
6
+ buildAriaProps,
7
+ buildCss,
8
+ buildDataProps,
9
+ buildHtmlProps,
10
+ } from "../utilities/props";
11
+ import Checkbox from "../pb_checkbox/_checkbox";
12
+ import Radio from "../pb_radio/_radio";
13
+ import CircleIconButton from "../pb_circle_icon_button/_circle_icon_button";
14
+ import Body from "../pb_body/_body";
15
+
16
+ type MultiLevelSelectOptionsProps = {
17
+ aria?: { [key: string]: string },
18
+ children?: React.ReactNode | ((item: any) => React.ReactNode),
19
+ className?: string,
20
+ dark?: boolean,
21
+ data?: { [key: string]: string },
22
+ htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
23
+ } & GlobalProps;
24
+
25
+ const MultiLevelSelectOptions = ({
26
+ children,
27
+ items,
28
+ ...props
29
+ }: MultiLevelSelectOptionsProps) => {
30
+ const {
31
+ variant,
32
+ inputName,
33
+ renderNestedOptions,
34
+ isTreeRowExpanded,
35
+ handleToggleClick,
36
+ handleRadioButtonClick,
37
+ handledropdownItemClick,
38
+ filterItem,
39
+ } = useContext(MultiLevelSelectContext)
40
+
41
+ const {
42
+ aria = {},
43
+ className,
44
+ data = {},
45
+ htmlOptions = {},
46
+ } = props;
47
+
48
+ const ariaProps = buildAriaProps(aria);
49
+ const dataProps = buildDataProps(data);
50
+ const htmlProps = buildHtmlProps(htmlOptions);
51
+ const classes = classnames(
52
+ buildCss("pb_multi_level_select_options"),
53
+ globalProps(props),
54
+ className
55
+ );
56
+
57
+ return (
58
+ <ul
59
+ {...ariaProps}
60
+ {...dataProps}
61
+ {...htmlProps}
62
+ className={classes}
63
+ >
64
+ {Array.isArray(items) &&
65
+ items.map((item: { [key: string]: any }) => {
66
+ return (
67
+ <div key={item.id}>
68
+ <li className={"dropdown_item"}
69
+ data-name={item.id}
70
+ >
71
+ <div className="dropdown_item_checkbox_row">
72
+ {!item.parent_id && !item.children ? null : (
73
+ <div
74
+ key={
75
+ isTreeRowExpanded(item)
76
+ ? "chevron-down"
77
+ : "chevron-right"
78
+ }
79
+ >
80
+ <CircleIconButton
81
+ className={
82
+ item.children && item.children.length > 0
83
+ ? ""
84
+ : "toggle_icon"
85
+ }
86
+ icon={
87
+ isTreeRowExpanded(item)
88
+ ? "chevron-down"
89
+ : "chevron-right"
90
+ }
91
+ onClick={(event: React.MouseEvent) =>
92
+ handleToggleClick(item.id, event)
93
+ }
94
+ variant="link"
95
+ />
96
+ </div>
97
+ )}
98
+ {variant === "single" ? (
99
+ item.hideRadio ? (
100
+ <Body>{item.label}</Body>
101
+ ) : (
102
+ <Radio
103
+ checked={item.checked}
104
+ id={`${item.id}-${item.label}`}
105
+ label={item.label}
106
+ name={inputName}
107
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
108
+ handleRadioButtonClick(e)
109
+ }
110
+ padding={item.children ? "none" : "xs"}
111
+ type="radio"
112
+ value={item.label}
113
+ />
114
+ )
115
+ ) : (
116
+ <Checkbox id={item.id}
117
+ text={item.label}
118
+ >
119
+ <input
120
+ checked={item.checked}
121
+ name={item.label}
122
+ onChange={(e) => {
123
+ handledropdownItemClick(e, !item.checked);
124
+ }}
125
+ type="checkbox"
126
+ value={item.label}
127
+ />
128
+ </Checkbox>
129
+ )}
130
+ {/* Render children next to the checkbox */}
131
+ {children && (
132
+ typeof children === "function" ? children(item) : children
133
+ )}
134
+ </div>
135
+ {isTreeRowExpanded(item) &&
136
+ item.children &&
137
+ item.children.length > 0 &&
138
+ (variant === "single" || !filterItem) && (
139
+ <div>{renderNestedOptions(item.children)}</div>
140
+ )}
141
+ </li>
142
+ </div>
143
+ );
144
+ })}
145
+ </ul>
146
+ );
147
+ };
148
+
149
+ export default MultiLevelSelectOptions;
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+ import { buildHtmlProps } from '../utilities/props'
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps"
5
+ import DateStacked from '../pb_date_stacked/_date_stacked'
6
+
7
+ type TimelineDateAreaProps = {
8
+ date?: Date,
9
+ children?: React.ReactNode,
10
+ className?: string,
11
+ htmlOptions?: { [key: string]: any },
12
+ } & GlobalProps
13
+
14
+ const TimelineDateArea: React.FC<TimelineDateAreaProps> = ({
15
+ date,
16
+ children,
17
+ className,
18
+ htmlOptions = {},
19
+ ...props
20
+ }) => {
21
+ const htmlProps = buildHtmlProps(htmlOptions)
22
+ return (
23
+ <div
24
+ {...htmlProps}
25
+ className={classnames('pb_timeline_item_left_block', globalProps(props), className)}
26
+ >
27
+ {children}
28
+ {date && (
29
+ <DateStacked align="center"
30
+ date={date}
31
+ size="sm"
32
+ />
33
+ )}
34
+ </div>
35
+ )
36
+ }
37
+
38
+ export default TimelineDateArea
@@ -0,0 +1,29 @@
1
+ import React from 'react'
2
+ import classnames from 'classnames'
3
+ import { buildHtmlProps } from '../utilities/props'
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps"
5
+
6
+ type TimelineDetailAreaProps = {
7
+ children?: React.ReactNode,
8
+ className?: string,
9
+ htmlOptions?: { [key: string]: any },
10
+ } & GlobalProps
11
+
12
+ const TimelineDetailArea: React.FC<TimelineDetailAreaProps> = ({
13
+ children,
14
+ className,
15
+ htmlOptions = {},
16
+ ...props
17
+ }) => {
18
+ const htmlProps = buildHtmlProps(htmlOptions)
19
+ return (
20
+ <div
21
+ {...htmlProps}
22
+ className={classnames('pb_timeline_item_right_block', globalProps(props), className)}
23
+ >
24
+ {children}
25
+ </div>
26
+ )
27
+ }
28
+
29
+ export default TimelineDetailArea
@@ -1,12 +1,15 @@
1
1
  import React from 'react'
2
2
  import classnames from 'classnames'
3
-
4
3
  import { buildCss, buildHtmlProps } from '../utilities/props'
5
- import { globalProps, GlobalProps } from "../utilities/globalProps";
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps"
6
5
 
7
6
  import DateStacked from '../pb_date_stacked/_date_stacked'
8
7
  import IconCircle from '../pb_icon_circle/_icon_circle'
9
8
 
9
+ import TimelineDateArea from './_date_area'
10
+ import TimelineNodeArea from './_node_area'
11
+ import TimelineDetailArea from './_detail_area'
12
+
10
13
  type ItemProps = {
11
14
  className?: string,
12
15
  children?: React.ReactNode[] | React.ReactNode,
@@ -17,6 +20,13 @@ type ItemProps = {
17
20
  lineStyle?: 'solid' | 'dotted',
18
21
  } & GlobalProps
19
22
 
23
+ function isElementOfType<P>(
24
+ element: React.ReactNode,
25
+ component: React.ComponentType<P>
26
+ ): element is React.ReactElement<P> {
27
+ return React.isValidElement<P>(element) && element.type === component
28
+ }
29
+
20
30
  const TimelineItem = ({
21
31
  className,
22
32
  children,
@@ -31,31 +41,57 @@ const TimelineItem = ({
31
41
 
32
42
  const htmlProps = buildHtmlProps(htmlOptions)
33
43
 
44
+ const childrenArray = React.Children.toArray(children)
45
+
46
+ const dateAreaChild = childrenArray.find(
47
+ (child): child is React.ReactElement => isElementOfType(child, TimelineDateArea)
48
+ )
49
+
50
+ const nodeAreaChild = childrenArray.find(
51
+ (child): child is React.ReactElement => isElementOfType(child, TimelineNodeArea)
52
+ )
53
+
54
+ const detailAreaChild = childrenArray.find(
55
+ (child): child is React.ReactElement => isElementOfType(child, TimelineDetailArea)
56
+ )
57
+
58
+ const otherChildren = childrenArray.filter(
59
+ (child) =>
60
+ !isElementOfType(child, TimelineDateArea) &&
61
+ !isElementOfType(child, TimelineNodeArea) &&
62
+ !isElementOfType(child, TimelineDetailArea)
63
+ )
64
+
34
65
  return (
35
- <div
66
+ <div
36
67
  {...htmlProps}
37
68
  className={classnames(timelineItemCss, globalProps(props), className)}
38
69
  >
39
- <div className="pb_timeline_item_left_block">
40
- {date &&
41
- <DateStacked
42
- align="center"
43
- date={date}
44
- size="sm"
45
- />
46
- }
47
- </div>
48
- <div className="pb_timeline_item_step">
49
- <IconCircle
50
- icon={icon}
51
- size="xs"
52
- variant={iconColor}
53
- />
54
- <div className="pb_timeline_item_connector" />
55
- </div>
56
- <div className="pb_timeline_item_right_block">
57
- {children}
58
- </div>
70
+ {dateAreaChild || (
71
+ <div className="pb_timeline_item_left_block">
72
+ {date && (
73
+ <DateStacked
74
+ align="center"
75
+ date={date}
76
+ size="sm"
77
+ />
78
+ )}
79
+ </div>
80
+ )}
81
+ {nodeAreaChild || (
82
+ <div className="pb_timeline_item_step">
83
+ <IconCircle icon={icon}
84
+ size="xs"
85
+ variant={iconColor}
86
+ />
87
+ <div className="pb_timeline_item_connector" />
88
+ </div>
89
+ )}
90
+ {detailAreaChild || (
91
+ <div className="pb_timeline_item_right_block">
92
+ { otherChildren }
93
+ </div>
94
+ )}
59
95
  </div>
60
96
  )
61
97
  }