playbook_ui 12.6.0.pre.alpha.sectionseparator1 → 12.7.0

Sign up to get free protection for your applications and to get access to all the features.
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: