playbook_ui 12.6.0.pre.alpha.sectionseparator1 → 12.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +9 -6
  3. data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +61 -44
  4. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +1 -0
  5. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.html.erb +1 -0
  6. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.jsx +14 -0
  7. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.md +1 -0
  8. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +2 -1
  9. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +1 -0
  10. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_input_styles.scss +68 -0
  11. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +21 -4
  12. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +72 -0
  13. data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.md +3 -1
  14. data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +2 -1
  15. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.html.erb +3 -0
  16. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb +21 -0
  17. data/app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx +1 -2
  18. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +52 -16
  19. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +22 -20
  20. data/app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss +19 -0
  21. data/app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.html.erb +0 -2
  22. data/app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.scss +3 -0
  23. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +41 -35
  24. data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay.jsx +56 -0
  25. data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay.md +5 -0
  26. data/app/pb_kits/playbook/pb_tooltip/docs/example.yml +1 -0
  27. data/app/pb_kits/playbook/pb_tooltip/docs/index.js +1 -0
  28. data/app/pb_kits/playbook/playbook-rails-react-bindings.js +2 -0
  29. data/lib/playbook/version.rb +1 -1
  30. metadata +13 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54b4b391e78f2f58e670391168634c536434667a6e53d4ae31e803f738ee5a1d
4
- data.tar.gz: 871163ff18b7cc73cd8591158fbff9aedb2cbfa647c95a68e5921ccd319fede0
3
+ metadata.gz: 127ac17d49b80d6d30ec216a6f2e0a7e81908664c6a85b1341bdce717f12699a
4
+ data.tar.gz: e15e17d77315240d2c81ea9df13c84d5b6633c55ac9f19a4e0b5ed24e5b2df1e
5
5
  SHA512:
6
- metadata.gz: 4ab7c44f1c8cdd068026bedde9b01b656e4b209bf0997ff539857867c5d5a1cd591a153084716f983b8749d643ecf8a747fde4b05600260e0312b3d02e004d7a
7
- data.tar.gz: 918ca1022a5c4c4ea45436892b8fc5608b10bf06a3d0fbcb495b5f2e8f63bb2ff144b15e039eec1bd6d1ea433680c398a5324829b1f31a5afd619273c7a75271
6
+ metadata.gz: b7089e126a6c6340ccde8c062ad95411bf8c3470cefce3c9309bb591e0efc0a5fac5f56b3984c37ca0f12bd8710c3e7a646f1d77405ec3b2f3d412b3d69de452
7
+ data.tar.gz: b7abd953f3e8c3215b7b142790c5ac6fd15e99b0b44cf3a425dfa7b7c41db5e1f19f9696a363305f055a76d4c7cd2ab8d8387004465eeb90016350c839cad40a
@@ -5,8 +5,7 @@
5
5
  @import "./sass_partials/inline_styles";
6
6
  @import "./sass_partials/month_and_year_styles";
7
7
  @import "./sass_partials/time_selection_styles";
8
-
9
-
8
+ @import "./sass_partials/input_styles";
10
9
 
11
10
  [class^=pb_date_picker_kit] {
12
11
  .input_wrapper {
@@ -20,8 +19,10 @@
20
19
  @import "./sass_partials/calendar_input_icon";
21
20
  }
22
21
 
23
- &:focus, :focus-within {
24
- div.cal_icon_wrapper, input.text_input{
22
+ &:focus,
23
+ :focus-within {
24
+ div.cal_icon_wrapper,
25
+ input.date_picker_input {
25
26
  @include transition_default;
26
27
  border-color: $primary;
27
28
  }
@@ -33,18 +34,20 @@
33
34
  @import "./sass_partials/header_styles";
34
35
  @import "./sass_partials/overrides";
35
36
 
36
- .text_input.flatpickr-input {
37
+ .date_picker_input.flatpickr-input {
37
38
  text-overflow: ellipsis;
38
39
  padding-right: $space_xl + 10 !important;
39
40
  }
41
+
40
42
  // Calendar Shadow and Border
41
43
  .flatpickr-calendar {
42
44
  box-shadow: $shadow_deeper;
43
45
  border: 1px solid $border_light;
44
46
  }
47
+
45
48
  // Hide Caret
46
49
  &:before,
47
50
  &:after {
48
51
  content: none;
49
52
  }
50
- }
53
+ }
@@ -5,13 +5,13 @@ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
5
  import { deprecatedProps, globalProps, GlobalProps } from '../utilities/globalProps'
6
6
 
7
7
  import datePickerHelper from './date_picker_helper'
8
-
9
8
  import Icon from '../pb_icon/_icon'
10
- import TextInput from '../pb_text_input/_text_input'
9
+ import Caption from '../pb_caption/_caption'
10
+ import Body from '../pb_body/_body'
11
11
 
12
12
  type DatePickerProps = {
13
13
  allowInput?: boolean,
14
- aria?: {[key: string]: string},
14
+ aria?: { [key: string]: string },
15
15
  className?: string,
16
16
  dark?: boolean,
17
17
  data?: { [key: string]: string },
@@ -27,15 +27,15 @@ type DatePickerProps = {
27
27
  hideLabel?: boolean,
28
28
  id?: string,
29
29
  inLine?: boolean,
30
- inputAria?: {[key: string]: string},
31
- inputData?: {[key: string]: string},
32
- inputOnChange?: (arg: string) => void,
30
+ inputAria?: { [key: string]: string },
31
+ inputData?: { [key: string]: string },
32
+ inputOnChange?: (e: React.FormEvent<HTMLInputElement>) => void,
33
33
  inputValue?: any,
34
34
  label?: string,
35
35
  maxDate: string,
36
36
  minDate: string,
37
37
  name: string,
38
- pickerId?: ArrayLike<Node> | Node | string,
38
+ pickerId?: string,
39
39
  placeholder?: string,
40
40
  positionElement?: HTMLElement | null,
41
41
  scrollContainer?: string,
@@ -68,8 +68,8 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
68
68
  hideLabel = false,
69
69
  id,
70
70
  inLine = false,
71
- inputAria,
72
- inputData,
71
+ inputAria = {},
72
+ inputData = {},
73
73
  inputOnChange,
74
74
  inputValue,
75
75
  label = 'Date Picker',
@@ -87,11 +87,14 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
87
87
  selectionType = '',
88
88
  showTimezone = false,
89
89
  staticPosition = true,
90
- yearRange = [ 1900, 2100 ],
90
+ yearRange = [1900, 2100],
91
91
  } = props
92
92
 
93
93
  const ariaProps = buildAriaProps(aria)
94
94
  const dataProps = buildDataProps(data)
95
+ const inputAriaProps = buildAriaProps(inputAria)
96
+ const inputDataProps = buildDataProps(inputData)
97
+
95
98
  const classes = classnames(
96
99
  buildCss('pb_date_picker_kit'),
97
100
  globalProps(props),
@@ -128,13 +131,13 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
128
131
 
129
132
  const iconWrapperClass = () => {
130
133
  let base = 'cal_icon_wrapper'
131
- if (dark){
134
+ if (dark) {
132
135
  base += ' dark'
133
136
  }
134
- if (hideLabel){
137
+ if (hideLabel) {
135
138
  base += ' no_label_shift'
136
139
  }
137
- if (error){
140
+ if (error) {
138
141
  base += ' error'
139
142
  }
140
143
  return base
@@ -142,61 +145,75 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
142
145
 
143
146
  return (
144
147
  <div
145
- {...ariaProps}
146
- {...dataProps}
147
- className={classes}
148
- id={id}
148
+ {...ariaProps}
149
+ {...dataProps}
150
+ className={classes}
151
+ id={id}
149
152
  >
150
- <div className="input_wrapper">
151
- <TextInput
152
- aria={inputAria}
153
+ <div
154
+ {...inputAriaProps}
155
+ {...inputDataProps}
156
+ className="input_wrapper">
157
+
158
+ <Caption
159
+ className="pb_date_picker_kit_label"
160
+ text={hideLabel ? null : label}
161
+ />
162
+
163
+ <div className="date_picker_input_wrapper">
164
+ <input
153
165
  autoComplete="off"
154
- dark={dark}
155
- data={inputData}
166
+ className="date_picker_input"
156
167
  disabled={disableInput}
157
- error={error}
158
168
  id={pickerId}
159
- label={hideLabel ? null : label}
160
169
  name={name}
161
170
  onChange={inputOnChange}
162
171
  placeholder={placeholder}
163
172
  value={inputValue}
164
- />
173
+ />
165
174
 
166
- { !hideIcon &&
175
+ {error && <Body
176
+ status="negative"
177
+ text={error}
178
+ variant={null}
179
+ />
180
+ }
181
+ </div>
182
+
183
+ {!hideIcon &&
167
184
  <div
168
- className={iconWrapperClass()}
169
- id={`cal-icon-${pickerId}`}
185
+ className={iconWrapperClass()}
186
+ id={`cal-icon-${pickerId}`}
170
187
  >
171
- <Icon
188
+ <Icon
172
189
  className="cal_icon"
173
190
  icon="calendar-alt"
174
- />
175
- </div>
191
+ />
192
+ </div>
176
193
  }
177
194
 
178
- { hideIcon && inLine ?
195
+ {hideIcon && inLine ?
179
196
  <div>
180
197
  <div
181
- className={iconWrapperClass()}
182
- id={`${pickerId}-icon-plus`}
198
+ className={iconWrapperClass()}
199
+ id={`${pickerId}-icon-plus`}
183
200
  >
184
201
  <Icon
185
- className="date-picker-plus-icon"
186
- icon="plus"
202
+ className="date-picker-plus-icon"
203
+ icon="plus"
187
204
  />
188
205
  </div>
189
206
  <div
190
- className={iconWrapperClass()}
191
- id={`${pickerId}-angle-down`}
207
+ className={iconWrapperClass()}
208
+ id={`${pickerId}-angle-down`}
192
209
  >
193
- <Icon
194
- className="angle_down_icon"
195
- icon="angle-down"
196
- />
210
+ <Icon
211
+ className="angle_down_icon"
212
+ icon="angle-down"
213
+ />
197
214
  </div>
198
- </div>
199
- : null }
215
+ </div>
216
+ : null}
200
217
  </div>
201
218
  </div>
202
219
  )
@@ -112,6 +112,7 @@ const datePickerHelper = (config: DatePickerConfig, scrollContainer: string | HT
112
112
  // ===========================================================
113
113
 
114
114
  flatpickr(`#${pickerId}`, {
115
+ allowInput,
115
116
  closeOnSelect,
116
117
  disableMobile: true,
117
118
  dateFormat: getDateFormat(),
@@ -0,0 +1 @@
1
+ <%= pb_rails("date_picker", props: { allow_input: true, picker_id: "date-picker-allow-input"}) %>
@@ -0,0 +1,14 @@
1
+ import React from 'react'
2
+ import DatePicker from '../_date_picker'
3
+
4
+ const DatePickerAllowInput = (props) => (
5
+ <>
6
+ <DatePicker
7
+ allowInput
8
+ pickerId="date-picker-allow-input"
9
+ {...props}
10
+ />
11
+ </>
12
+ )
13
+
14
+ export default DatePickerAllowInput
@@ -0,0 +1 @@
1
+ Setting the `allowInput` prop to true permits users to key values directly into the input. This prop is set to false by default.
@@ -4,6 +4,7 @@ examples:
4
4
  - date_picker_default: Default
5
5
  - date_picker_hide_icon: Hide Input Icon
6
6
  - date_picker_default_date: Default Date
7
+ - date_picker_allow_input: Allow Input
7
8
  - date_picker_input: Input Field
8
9
  - date_picker_label: Label
9
10
  - date_picker_range: Range
@@ -22,11 +23,11 @@ examples:
22
23
  - date_picker_positions: Custom Positions
23
24
  - date_picker_positions_element: Custom Position (based on element)
24
25
 
25
-
26
26
  react:
27
27
  - date_picker_default: Default
28
28
  - date_picker_hide_icon: Hide Input Icon
29
29
  - date_picker_default_date: Default Date
30
+ - date_picker_allow_input: Allow Input
30
31
  - date_picker_input: Input Field
31
32
  - date_picker_label: Label
32
33
  - date_picker_on_change: onChange
@@ -18,3 +18,4 @@ export { default as DatePickerTime } from './_date_picker_time.jsx'
18
18
  export { default as DatePickerWeek } from './_date_picker_week.jsx'
19
19
  export { default as DatePickerPositions } from './_date_picker_positions.jsx'
20
20
  export { default as DatePickerPositionsElement } from './_date_picker_positions_element.jsx'
21
+ export { default as DatePickerAllowInput } from './_date_picker_allow_input'
@@ -0,0 +1,68 @@
1
+ @import "../../pb_textarea/textarea_mixin";
2
+
3
+ [class^=pb_date_picker_kit] {
4
+ margin-bottom: $space_sm;
5
+
6
+ .pb_date_picker_kit_label {
7
+ margin-bottom: $space_xs;
8
+ display: block;
9
+ }
10
+
11
+ .date_picker_input_wrapper {
12
+ display: block;
13
+
14
+ input::placeholder,
15
+ .date_picker_input .placeholder {
16
+ @include pb_body_light;
17
+ }
18
+
19
+ input,
20
+ .date_picker_input {
21
+ max-height: 45px;
22
+ @include pb_textarea_light;
23
+ overflow: hidden;
24
+ }
25
+
26
+ input:hover,
27
+ .date_picker_input:hover {
28
+ background-color: rgba($focus_input_light, $opacity_5);
29
+ }
30
+
31
+ input:focus,
32
+ .date_picker_input:focus,
33
+ input:-webkit-autofill:focus,
34
+ .date_picker_input:-webkit-autofill:focus {
35
+ @include pb_textarea_focus;
36
+ @include transition_default;
37
+ border-color: $primary;
38
+ background-color: rgba($focus_input_light, $opacity_5);
39
+ }
40
+ }
41
+
42
+ &.error {
43
+ .date_picker_input_wrapper {
44
+ [class*=pb_body_kit] {
45
+ margin-top: $space_xs / 2;
46
+ }
47
+
48
+ input,
49
+ .date_picker_input {
50
+ border-color: $error;
51
+ }
52
+ }
53
+ }
54
+
55
+ &.inline {
56
+ .date_picker_input_wrapper input::placeholder,
57
+ .date_picker_input_wrapper .date_picker_input .placeholder {
58
+ opacity: 1;
59
+ }
60
+
61
+ &:not(:hover) {
62
+ .date_picker_input_wrapper input:not(:focus) {
63
+ background-color: transparent;
64
+ border-color: transparent;
65
+ }
66
+ }
67
+ }
68
+ }
@@ -12,11 +12,18 @@ type MultiLevelSelectProps = {
12
12
  id?: string;
13
13
  treeData?: { [key: string]: string }[];
14
14
  onChange?: any;
15
- onSelect?: (SelectedNodes: { [key: string]: any }) => void;
15
+ onSelect?: (prop: { [key: string]: any }) => void;
16
16
  };
17
17
 
18
18
  const MultiLevelSelect = (props: MultiLevelSelectProps) => {
19
- const { aria = {}, className, data = {}, id, treeData, onSelect } = props;
19
+ const {
20
+ aria = {},
21
+ className,
22
+ data = {},
23
+ id,
24
+ treeData,
25
+ onSelect = () => {},
26
+ } = props;
20
27
 
21
28
  const ariaProps = buildAriaProps(aria);
22
29
  const dataProps = buildDataProps(data);
@@ -28,6 +35,7 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
28
35
 
29
36
  const [formattedData, setFormattedData] = useState(treeData);
30
37
  const [selectedItems, setSelectedItems] = useState([]);
38
+ const [checkedData, setCheckedData] = useState([]);
31
39
 
32
40
  const onChange = (currentNode: { [key: string]: any }) => {
33
41
  const updatedData = formattedData.map((item: any) => {
@@ -62,16 +70,25 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
62
70
  const uniqueSelected = selected.filter(
63
71
  (obj, index, self) => index === self.findIndex((t) => t.id === obj.id)
64
72
  );
65
- onSelect(uniqueSelected);
73
+ setCheckedData(uniqueSelected);
66
74
  }, [selectedItems]);
67
75
 
76
+ useEffect(() => {
77
+ let el = document.getElementById("pb_data_wrapper");
78
+
79
+ if (el) {
80
+ el.setAttribute("data-tree", JSON.stringify(checkedData));
81
+ }
82
+
83
+ onSelect(checkedData);
84
+ }, [checkedData]);
85
+
68
86
  return (
69
87
  <div {...ariaProps} {...dataProps} className={classes} id={id}>
70
88
  <MultiSelectHelper
71
89
  treeData={formattedData}
72
90
  id={id}
73
91
  onChange={onChange}
74
- onSelect={onSelect}
75
92
  {...props}
76
93
  />
77
94
  </div>
@@ -0,0 +1,72 @@
1
+ <% treeData = [{
2
+ label: "Power Home Remodeling",
3
+ value: "Power Home Remodeling",
4
+ id: "powerhome1",
5
+ expanded: true,
6
+ children: [
7
+ {
8
+ label: "People",
9
+ value: "People",
10
+ id: "people1",
11
+ children: [
12
+ {
13
+ label: "Talent Acquisition",
14
+ value: "Talent Acquisition",
15
+ id: "talent1",
16
+ },
17
+ {
18
+ label: "Business Affairs",
19
+ value: "Business Affairs",
20
+ id: "business1",
21
+ children: [
22
+ {
23
+ label: "Initiatives",
24
+ value: "Initiatives",
25
+ id: "initiative1",
26
+ },
27
+ {
28
+ label: "Learning & Development",
29
+ value: "Learning & Development",
30
+ id: "development1",
31
+ },
32
+ ],
33
+ },
34
+ {
35
+ label: "People Experience",
36
+ value: "People Experience",
37
+ id: "experience1",
38
+ },
39
+ ],
40
+ },
41
+ {
42
+ label: "Contact Center",
43
+ value: "Contact Center",
44
+ id: "contact1",
45
+ children: [
46
+ {
47
+ label: "Appointment Management",
48
+ value: "Appointment Management",
49
+ id: "appointment1",
50
+ },
51
+ {
52
+ label: "Customer Service",
53
+ value: "Customer Service",
54
+ id: "customer1",
55
+ },
56
+ {
57
+ label: "Energy",
58
+ value: "Energy",
59
+ id: "energy1",
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ }] %>
65
+
66
+
67
+ <%= pb_rails("multi_level_select", props: {
68
+ id: "default-multi-level-select",
69
+ tree_data:treeData
70
+ }) %>
71
+
72
+
@@ -1,3 +1,5 @@
1
1
  The MultiLevelSelect kit renders a multi leveled select dropdown based on data from the user. `treeData` is a required prop that is expected to contain the data in the form of an array of objects. See code snippet for an example data array.
2
2
 
3
- The `onSelect` prop returns an array of all checked items, irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
3
+ For the React version of the kit, the `onSelect` prop returns an array of all checked items, irrespective of whether it is a parent, child or grandchild. Open the console on this example and check and uncheck checkboxes to see this is action!
4
+
5
+ For the Rails version, the array of checked items is attached to the DOM in a data attribute titled `data-tree` on the wrapping div around the MultiLevelSelect.
@@ -1,5 +1,6 @@
1
1
  examples:
2
-
2
+ rails:
3
+ - multi_level_select_default: Default
3
4
 
4
5
  react:
5
6
  - multi_level_select_default: Default
@@ -0,0 +1,3 @@
1
+ <div id="pb_data_wrapper" data-tree="">
2
+ <%= react_component("MultiLevelSelect", object.multi_level_select_options ) %>
3
+ </div>
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Playbook
4
+ module PbMultiLevelSelect
5
+ class MultiLevelSelect < Playbook::KitBase
6
+ prop :tree_data, type: Playbook::Props::Array,
7
+ default: []
8
+
9
+ def classname
10
+ generate_classname("pb_multi_level_select")
11
+ end
12
+
13
+ def multi_level_select_options
14
+ {
15
+ id: id,
16
+ treeData: tree_data,
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -29,10 +29,9 @@ test('should render custom class', () => {
29
29
  <MultiLevelSelect
30
30
  className='custom-class'
31
31
  data={{ testid: testId}}
32
- onSelect={()=> console.log("hello")}
33
32
  treeData={treeData}
34
33
  />
35
- )
34
+ )
36
35
 
37
36
  const kit = screen.getByTestId(testId)
38
37
  expect(kit).toHaveClass('custom-class')
@@ -1,16 +1,46 @@
1
1
  @import "../tokens/colors";
2
2
 
3
+ $transform-rotate-deg: 135deg;
4
+ $input-max-width: 284px;
5
+ $dropdown-min-width: 340px;
6
+ $flag-min-resolution: 192dpi;
7
+
3
8
  .pb_phone_number_input {
4
9
  input::placeholder {
5
10
  color: $focus_input_light;
6
11
  }
7
12
 
13
+ .text_input {
14
+ max-width: $input-max-width;
15
+ }
16
+
17
+ .dropdown_open {
18
+ .text_input {
19
+ border-color: $primary !important;
20
+ }
21
+
22
+ .iti__selected-flag:focus-visible {
23
+ outline-style: none;
24
+ }
25
+ }
26
+
8
27
  .iti__country {
9
28
  padding: 5px 10px 5px 16px;
29
+ transition: $transition_default;
10
30
  }
11
31
 
12
32
  .iti__selected-flag {
13
- padding: 0 6px 0 16px;
33
+ padding: 0 $space_xxs 0 $space_sm;
34
+
35
+ &[aria-expanded="true"] {
36
+ color: $primary_action;
37
+ }
38
+
39
+ &:focus-visible {
40
+ outline-style: solid;
41
+ border-radius: $space_xxs 0px 0px $space_xxs;
42
+ outline-color: $primary;
43
+ }
14
44
  }
15
45
 
16
46
  .iti__country.iti__highlight {
@@ -31,6 +61,11 @@
31
61
 
32
62
  .iti__flag {
33
63
  background-image: url("https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/img/flags.png");
64
+ border-radius: 1px;
65
+ }
66
+
67
+ .iti--separate-dial-code {
68
+ width: 100%;
34
69
  }
35
70
 
36
71
  .iti--separate-dial-code .iti__selected-flag {
@@ -52,49 +87,50 @@
52
87
 
53
88
  .iti__arrow::before {
54
89
  border-style: solid;
55
- border-width: 0.1em 0.1em 0 0;
90
+ border-width: 1px 1px 0 0;
56
91
  content: '';
57
92
  display: inline-block;
58
- height: 0.6em;
59
- left: 0.1em;
93
+ height: $space_xxs + 1px;
94
+ left: 1px;
60
95
  position: relative;
61
96
  vertical-align: top;
62
- width: 0.6em;
63
- top: 10px;
64
- transform: rotate(135deg);
65
- font-size: 0.5em;
97
+ width: $space_xxs + 1px;
98
+ top: $space_xs + 2px;
99
+ transform: rotate($transform-rotate-deg);
66
100
  color: $slate;
67
101
  }
68
102
 
69
103
  .iti__arrow.iti__arrow--up::before {
70
- transform: rotate(-45deg);
71
- top: 12px;
104
+ transform: rotate(-($transform-rotate-deg/3));
105
+ top: $space_xs + 4px;
106
+ color: $primary_action;
72
107
  }
73
108
 
74
109
  .iti__active::after {
75
110
  float: right;
76
111
  content: "";
77
- margin-top: 5px;
78
- transform: rotate(45deg);
79
- height: 12px;
80
- width: 6px;
112
+ margin-top: $space_xxs + 1px;
113
+ transform: rotate($transform-rotate-deg/3);
114
+ height: $space_xs + 4px;
115
+ width: $space_xxs + 2px;
81
116
  border-bottom: 2px solid;
82
117
  border-right: 2px solid;
83
118
  border-radius: 1px;
84
119
  }
85
120
 
86
121
  .iti__country-list {
87
- min-width: 340px;
122
+ min-width: $dropdown-min-width;
88
123
  border-radius: $border_radius_md;
89
124
  border: 1px solid $border_light;
90
125
  box-shadow: $shadow_deep;
126
+ margin-top: 1px;
91
127
  }
92
128
 
93
129
  .iti__divider {
94
130
  border-bottom: 1px solid $border_light;
95
131
  }
96
132
 
97
- @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
133
+ @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: $flag-min-resolution) {
98
134
  .iti__flag {
99
135
  background-image: url("https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/img/flags@2x.png");
100
136
  }
@@ -1,11 +1,12 @@
1
1
  /* @flow */
2
- import React, { useEffect, useRef, useState } from "react"
3
- import classnames from "classnames"
4
- import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props"
5
- import { globalProps } from "../utilities/globalProps"
6
- import intlTelInput from "intl-tel-input"
7
- import "intl-tel-input/build/css/intlTelInput.css"
8
- import TextInput from "../pb_text_input/_text_input"
2
+ import React, { useEffect, useRef, useState } from 'react'
3
+ import classnames from 'classnames'
4
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
5
+ import { globalProps } from '../utilities/globalProps'
6
+ import intlTelInput from 'intl-tel-input'
7
+ import 'intl-tel-input/build/css/intlTelInput.css'
8
+ import TextInput from '../pb_text_input/_text_input'
9
+ import 'intl-tel-input/build/js/utils.js'
9
10
 
10
11
  declare global {
11
12
  interface Window {
@@ -50,7 +51,7 @@ const formatAllCountries = () => {
50
51
  formatAllCountries()
51
52
 
52
53
  const containOnlyNumbers = (value: string) => {
53
- return /^(\++)*(\d+)$/.test(value)
54
+ return /^[()+\-\ .\d]*$/g.test(value)
54
55
  }
55
56
 
56
57
  const PhoneNumberInput = (props: PhoneNumberInputProps) => {
@@ -85,7 +86,8 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
85
86
  const inputRef = useRef<HTMLInputElement>()
86
87
  const [inputValue, setInputValue] = useState(value)
87
88
  const [itiInit, setItiInit] = useState<any>()
88
- const [error, setError] = useState("")
89
+ const [error, setError] = useState('')
90
+ const [dropDownIsOpen, setDropDownIsOpen] = useState(false)
89
91
 
90
92
  const validateTooLongNumber = (itiInit: any) => {
91
93
  const error = itiInit.getValidationError()
@@ -133,18 +135,17 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
133
135
 
134
136
  useEffect(() => {
135
137
  const telInputInit = new intlTelInput(inputRef.current, {
136
- utilsScript:
137
- "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.19/js/utils.js",
138
- separateDialCode: true,
139
- preferredCountries,
140
- allowDropdown: !disabled,
141
- initialCountry,
142
- onlyCountries,
143
- })
144
-
145
- inputRef.current.addEventListener("countrychange", () =>
146
- validateTooLongNumber(telInputInit)
138
+ separateDialCode: true,
139
+ preferredCountries,
140
+ allowDropdown: !disabled,
141
+ initialCountry,
142
+ onlyCountries,
143
+ }
147
144
  )
145
+
146
+ inputRef.current.addEventListener("countrychange", () => validateTooLongNumber(telInputInit))
147
+ inputRef.current.addEventListener("open:countrydropdown", () => setDropDownIsOpen(true))
148
+ inputRef.current.addEventListener("close:countrydropdown", () => setDropDownIsOpen(false))
148
149
 
149
150
  setItiInit(telInputInit)
150
151
  }, [])
@@ -152,6 +153,7 @@ const PhoneNumberInput = (props: PhoneNumberInputProps) => {
152
153
  return (
153
154
  <div {...ariaProps} {...dataProps} className={classes}>
154
155
  <TextInput
156
+ className={dropDownIsOpen ? 'dropdown_open' : ''}
155
157
  disabled={disabled}
156
158
  error={error}
157
159
  id={id}
@@ -3,6 +3,25 @@
3
3
  text-align: center;
4
4
  user-select: none;
5
5
 
6
+ .buffer > [class*=pb_selectable_icon_kit]::before {
7
+ content: '';
8
+ position: absolute;
9
+ width: 100%;
10
+ height: 100%;
11
+ top: 0;
12
+ left: 0;
13
+ }
14
+
15
+ .buffer > [class*=pb_selectable_icon_kit] {
16
+ @media (hover:hover) {
17
+ &:hover * {
18
+ transition: transform $transition_short ease;
19
+ transform: translateY(-2px);
20
+ }
21
+ }
22
+ }
23
+
24
+
6
25
  input[type="checkbox"],
7
26
  input[type="radio"] {
8
27
 
@@ -13,7 +13,6 @@
13
13
  dark: object.dark,
14
14
  input_options: object.input_options
15
15
  }) do %>
16
-
17
16
  <%= pb_rails("selectable_icon", props: {
18
17
  icon: object.icon,
19
18
  inputs: "disabled",
@@ -26,6 +25,5 @@
26
25
  color: "light",
27
26
  dark: object.dark
28
27
  }) %>
29
-
30
28
  <% end %>
31
29
  <% end %>
@@ -5,6 +5,7 @@
5
5
  text-align: center;
6
6
  cursor: pointer;
7
7
  transition: all $transition_short ease;
8
+
8
9
  @media (hover:hover) {
9
10
  &:hover * {
10
11
  transition: transform $transition_short ease;
@@ -81,3 +82,5 @@
81
82
  }
82
83
  }
83
84
  }
85
+
86
+
@@ -1,16 +1,18 @@
1
1
  import React, { useRef, useState } from "react"
2
- import classnames from "classnames"
2
+
3
3
  import {
4
- Placement,
5
- offset,
6
- arrow,
7
- shift,
8
- useFloating,
4
+ arrow,
5
+ flip,
6
+ offset,
7
+ Placement,
8
+ safePolygon,
9
+ shift,
10
+ useFloating,
11
+ useHover,
9
12
  useInteractions,
10
- useHover,
11
- flip,
12
- safePolygon,
13
13
  } from "@floating-ui/react-dom-interactions"
14
+
15
+ import classnames from "classnames"
14
16
  import { GlobalProps, globalProps } from "../utilities/globalProps"
15
17
  import { buildAriaProps, buildDataProps } from "../utilities/props"
16
18
  import Flex from "../pb_flex/_flex"
@@ -18,12 +20,13 @@ import Flex from "../pb_flex/_flex"
18
20
  type TooltipProps = {
19
21
  aria?: { [key: string]: string },
20
22
  className?: string | string[],
23
+ children: JSX.Element,
21
24
  data?: { [key: string]: string },
22
- text: string,
25
+ delay?: number | Partial<{open: number; close: number}>,
23
26
  icon?: string,
24
27
  interaction?: boolean,
25
28
  placement?: Placement,
26
- children: JSX.Element,
29
+ text: string,
27
30
  zIndex?: Pick<GlobalProps, "ZIndex">,
28
31
  } & GlobalProps
29
32
 
@@ -33,10 +36,11 @@ const Tooltip = (props: TooltipProps): React.ReactElement => {
33
36
  className,
34
37
  children,
35
38
  data = {},
39
+ delay = 0,
36
40
  icon = null,
37
41
  interaction = false,
38
- text,
39
42
  placement: preferredPlacement = "top",
43
+ text,
40
44
  zIndex,
41
45
  ...rest
42
46
  } = props
@@ -45,53 +49,55 @@ const Tooltip = (props: TooltipProps): React.ReactElement => {
45
49
  const ariaProps: { [key: string]: any } = buildAriaProps(aria)
46
50
 
47
51
  const css = classnames(
48
- globalProps({...rest}),
49
- className
52
+ className,
53
+ globalProps({...rest})
50
54
  )
51
55
  const [open, setOpen] = useState(false)
52
56
  const arrowRef = useRef(null)
53
57
  const {
54
- x,
55
- y,
56
- reference,
57
- floating,
58
- strategy,
58
+
59
59
  context,
60
- placement,
60
+ floating,
61
61
  middlewareData: { arrow: { x: arrowX, y: arrowY } = {} },
62
+ placement,
63
+ reference,
64
+ strategy,
65
+ x,
66
+ y,
62
67
  } = useFloating({
63
- placement: preferredPlacement,
64
- open,
65
- onOpenChange(open) {
66
- setOpen(open)
67
- },
68
68
  middleware: [
69
- offset(10),
70
- shift(),
69
+ arrow({
70
+ element: arrowRef,
71
+ }),
71
72
  flip({
72
73
  fallbackPlacements: ["top", "right", "bottom", "left"],
73
74
  fallbackStrategy: "initialPlacement",
74
75
  flipAlignment: false,
75
76
  }),
76
- arrow({
77
- element: arrowRef,
78
- }),
77
+ offset(10),
78
+ shift()
79
79
  ],
80
+ open,
81
+ onOpenChange(open) {
82
+ setOpen(open)
83
+ },
84
+ placement: preferredPlacement
80
85
  })
81
86
 
82
87
  const { getFloatingProps } = useInteractions([
83
88
  useHover(context, {
89
+ delay,
84
90
  handleClose: interaction ? safePolygon({
85
91
  blockPointerEvents: false
86
- }) : null,
92
+ }) : null
87
93
  })
88
94
  ])
89
95
 
90
96
  const staticSide = {
91
- top: "bottom",
92
- right: "left",
93
97
  bottom: "top",
94
98
  left: "right",
99
+ right: "left",
100
+ top: "bottom",
95
101
  }[placement.split("-")[0]]
96
102
 
97
103
  return (
@@ -109,9 +115,9 @@ const Tooltip = (props: TooltipProps): React.ReactElement => {
109
115
  {open && (
110
116
  <div
111
117
  {...getFloatingProps({
112
- role: "tooltip",
113
- ref: floating,
114
118
  className: `tooltip_tooltip ${placement} visible`,
119
+ ref: floating,
120
+ role: "tooltip",
115
121
  style: {
116
122
  position: strategy,
117
123
  top: y ?? 0,
@@ -0,0 +1,56 @@
1
+ // @flow
2
+
3
+ import React from 'react'
4
+ import { Button, Tooltip, Flex, FlexItem } from '../..';
5
+
6
+ const TooltipDelay = (props) => {
7
+
8
+ return (
9
+ <Flex
10
+ flexDirection='row'
11
+ gap='md'
12
+ justifyContent='center'
13
+ wrap
14
+ >
15
+ <FlexItem>
16
+ <Tooltip
17
+ delay={1000}
18
+ placement='top'
19
+ text="1s open/close delay"
20
+ zIndex={10}
21
+ {...props}
22
+ >
23
+ <Button text="1s delay"/>
24
+ </Tooltip>
25
+ </FlexItem>
26
+ <FlexItem>
27
+ <Tooltip
28
+ delay={{
29
+ open: 1000
30
+ }}
31
+ placement='top'
32
+ text="1s open delay"
33
+ zIndex={10}
34
+ {...props}
35
+ >
36
+ <Button text="Open only"/>
37
+ </Tooltip>
38
+ </FlexItem>
39
+ <FlexItem>
40
+ <Tooltip
41
+ delay={{
42
+ close: 1000
43
+ }}
44
+ placement='top'
45
+ text="1s close delay"
46
+ zIndex={10}
47
+ {...props}
48
+ >
49
+ <Button text="Close only"/>
50
+ </Tooltip>
51
+ </FlexItem>
52
+ </Flex>
53
+ )
54
+ }
55
+
56
+ export default TooltipDelay
@@ -0,0 +1,5 @@
1
+ Waits for the specified time when the event listener runs before triggering the tooltip.
2
+
3
+ The `delay` accepts `number` in `ms` or an `object` with `open` and `close` properties.
4
+
5
+ The `default` is `0`.
@@ -11,3 +11,4 @@ examples:
11
11
  - tooltip_interaction: Content Interaction
12
12
  - tooltip_margin: Margin
13
13
  - tooltip_icon: Tooltip with Icon
14
+ - tooltip_delay: Delay
@@ -2,3 +2,4 @@ export { default as TooltipDefaultReact } from './_tooltip_default_react'
2
2
  export { default as TooltipInteraction } from './_tooltip_interaction'
3
3
  export { default as TooltipMargin } from './_tooltip_margin'
4
4
  export { default as TooltipIcon } from './_tooltip_icon'
5
+ export { default as TooltipDelay } from './_tooltip_delay'
@@ -13,6 +13,7 @@ import DistributionBar from './pb_distribution_bar/_distribution_bar'
13
13
  import Gauge from './pb_gauge/_gauge'
14
14
  import Legend from './pb_legend/_legend'
15
15
  import LineGraph from './pb_line_graph/_line_graph'
16
+ import MultiLevelSelect from './pb_multi_level_select/_multi_level_select'
16
17
  import Passphrase from './pb_passphrase/_passphrase'
17
18
  import RichTextEditor from './pb_rich_text_editor/_rich_text_editor'
18
19
  import TreemapChart from './pb_treemap_chart/_treemap_chart'
@@ -27,6 +28,7 @@ WebpackerReact.registerComponents({
27
28
  DialogFooter,
28
29
  DialogHeader,
29
30
  DistributionBar,
31
+ MultiLevelSelect,
30
32
  Legend,
31
33
  LineGraph,
32
34
  Passphrase,
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Playbook
4
4
  PREVIOUS_VERSION = "12.6.0"
5
- VERSION = "12.6.0.pre.alpha.sectionseparator1"
5
+ VERSION = "12.7.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.6.0.pre.alpha.sectionseparator1
4
+ version: 12.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-07 00:00:00.000000000 Z
12
+ date: 2023-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -694,6 +694,9 @@ files:
694
694
  - app/pb_kits/playbook/pb_date_picker/date_picker.rb
695
695
  - app/pb_kits/playbook/pb_date_picker/date_picker.test.js
696
696
  - app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts
697
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.html.erb
698
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.jsx
699
+ - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_allow_input.md
697
700
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_anti_patterns.html.erb
698
701
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default.html.erb
699
702
  - app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default.jsx
@@ -754,6 +757,7 @@ files:
754
757
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss
755
758
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_header_styles.scss
756
759
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_inline_styles.scss
760
+ - app/pb_kits/playbook/pb_date_picker/sass_partials/_input_styles.scss
757
761
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_month_and_year_styles.scss
758
762
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_overrides.scss
759
763
  - app/pb_kits/playbook/pb_date_picker/sass_partials/_time_selection_styles.scss
@@ -1418,11 +1422,14 @@ files:
1418
1422
  - app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss
1419
1423
  - app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx
1420
1424
  - app/pb_kits/playbook/pb_multi_level_select/_multi_select_helper.tsx
1425
+ - app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb
1421
1426
  - app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx
1422
1427
  - app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.md
1423
1428
  - app/pb_kits/playbook/pb_multi_level_select/docs/example.yml
1424
1429
  - app/pb_kits/playbook/pb_multi_level_select/docs/index.js
1425
1430
  - app/pb_kits/playbook/pb_multi_level_select/helper_functions.ts
1431
+ - app/pb_kits/playbook/pb_multi_level_select/multi_level_select.html.erb
1432
+ - app/pb_kits/playbook/pb_multi_level_select/multi_level_select.rb
1426
1433
  - app/pb_kits/playbook/pb_multi_level_select/multi_level_select.test.jsx
1427
1434
  - app/pb_kits/playbook/pb_multiple_users/_multiple_users.jsx
1428
1435
  - app/pb_kits/playbook/pb_multiple_users/_multiple_users.scss
@@ -2154,6 +2161,8 @@ files:
2154
2161
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default.html.erb
2155
2162
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default_react.jsx
2156
2163
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default_react.md
2164
+ - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay.jsx
2165
+ - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_delay.md
2157
2166
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_icon.erb
2158
2167
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_icon.jsx
2159
2168
  - app/pb_kits/playbook/pb_tooltip/docs/_tooltip_icon.md
@@ -2439,9 +2448,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
2439
2448
  version: '0'
2440
2449
  required_rubygems_version: !ruby/object:Gem::Requirement
2441
2450
  requirements:
2442
- - - ">"
2451
+ - - ">="
2443
2452
  - !ruby/object:Gem::Version
2444
- version: 1.3.1
2453
+ version: '0'
2445
2454
  requirements: []
2446
2455
  rubygems_version: 3.3.7
2447
2456
  signing_key: