playbook_ui 12.19.0 → 12.20.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 (26) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +1 -2
  3. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +22 -7
  4. data/app/pb_kits/playbook/pb_multi_level_select/helper_functions.ts +32 -5
  5. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss +9 -4
  6. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.tsx +5 -3
  7. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb +2 -1
  8. data/app/pb_kits/playbook/pb_typeahead/{_typeahead.jsx → _typeahead.tsx} +24 -12
  9. data/app/pb_kits/playbook/pb_typeahead/components/{ClearIndicator.jsx → ClearIndicator.tsx} +2 -4
  10. data/app/pb_kits/playbook/pb_typeahead/components/{Control.jsx → Control.tsx} +5 -7
  11. data/app/pb_kits/playbook/pb_typeahead/components/{IndicatorsContainer.jsx → IndicatorsContainer.tsx} +2 -4
  12. data/app/pb_kits/playbook/pb_typeahead/components/{MenuList.jsx → MenuList.tsx} +0 -2
  13. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +66 -0
  14. data/app/pb_kits/playbook/pb_typeahead/components/Option.tsx +37 -0
  15. data/app/pb_kits/playbook/pb_typeahead/components/{Placeholder.jsx → Placeholder.tsx} +7 -9
  16. data/app/pb_kits/playbook/pb_typeahead/components/{ValueContainer.jsx → ValueContainer.tsx} +3 -5
  17. data/app/pb_kits/playbook/pb_typeahead/{index.js → index.ts} +37 -29
  18. data/app/pb_kits/playbook/pb_typeahead/types.d.ts +2 -0
  19. data/app/pb_kits/playbook/pb_user/_user.tsx +1 -1
  20. data/app/pb_kits/playbook/utilities/_positioning.scss +14 -0
  21. data/app/pb_kits/playbook/utilities/globalProps.ts +16 -4
  22. data/lib/playbook/version.rb +2 -2
  23. data/lib/playbook/z_index.rb +20 -7
  24. metadata +13 -12
  25. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.jsx +0 -62
  26. data/app/pb_kits/playbook/pb_typeahead/components/Option.jsx +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f60bb863c6a7be595fe8ffcaa866a7796a0bb896732cf7ba5990d40444e6405
4
- data.tar.gz: a3e06332bf074ce75e69c35184fd624b26ee9bfd02efcfad057dbafbcac3c608
3
+ metadata.gz: 86c4aefb2ca62f0357facbacd990e8ef9283fe061b307b2b3a48d9a44aae93bd
4
+ data.tar.gz: d46b8bcadd416bed1be375a1a60789b9e82ed3998a7e94d511f183a887e13654
5
5
  SHA512:
6
- metadata.gz: c30ebfe71f1649440d65fda7871d6c6b4d11a0ced08299f38b5de90bd9f0c3108e3179e54fcbe3a064ef0b0411a11eb76382fcb9e464b2cc5c88e7c57224b33d
7
- data.tar.gz: dda14920f8aa81dc398a665fee7b51d4bbedf537669f297fe76b3f04df0b813b47229cff6e809571bf62bbaa00909e9956b6e77d1895e338a956b4d3bf6d947d
6
+ metadata.gz: 9f016eb2b9946595c6bc70b9b48bd7faffe5249084040bc5a0046fa4b9c08fb006a245c5b570a296bc130795b1e510701a0e765c0018ca66dd322bf56619ea96
7
+ data.tar.gz: e08f975d11599e129cf94ce4f4c91f965708fe984565e46538f8dd254577bee99e59cc26d2d8c51948bbcc3488ccf61d7be997ae9ffd3a60ac23e9ea0a616727
@@ -36,10 +36,9 @@
36
36
  vertical-align: top;
37
37
  width: 0.6em;
38
38
  top: 10px;
39
- transform: rotate(135deg);
40
39
  font-size: 0.5em;
41
40
 
42
- transform: rotate(-45deg);
41
+ transform: rotate(45deg);
43
42
  top: 12px;
44
43
  }
45
44
 
@@ -2,7 +2,7 @@ import React, { useState, useEffect, useMemo } from "react";
2
2
  import classnames from "classnames";
3
3
  import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
4
4
  import { globalProps } from "../utilities/globalProps";
5
- import { findItemById, checkIt, unCheckIt } from "./helper_functions";
5
+ import { findItemById, checkIt, unCheckIt, getParentAndAncestorsIds } from "./helper_functions";
6
6
  import MultiSelectHelper from "./_multi_select_helper";
7
7
 
8
8
  type MultiLevelSelectProps = {
@@ -42,17 +42,31 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
42
42
  const updatedData = formattedData.map((item: any) => {
43
43
  if (item.id === currentNode._id) {
44
44
  if (currentNode.checked) {
45
- checkIt(item, selectedItems, setSelectedItems);
45
+ checkIt(item, selectedItems, setSelectedItems, false);
46
46
  } else {
47
- unCheckIt(item, selectedItems, setSelectedItems);
47
+ unCheckIt(item, selectedItems, setSelectedItems, false);
48
48
  }
49
49
  } else if (item.children) {
50
50
  const foundItem = findItemById(item.children, currentNode._id);
51
51
  if (foundItem) {
52
52
  if (currentNode.checked) {
53
- checkIt(foundItem, selectedItems, setSelectedItems);
53
+ checkIt(foundItem, selectedItems, setSelectedItems, false);
54
+ if (currentNode._parent) {
55
+ const parents = getParentAndAncestorsIds(currentNode._parent, formattedData)
56
+ parents.forEach((item:string) => {
57
+ const ancestor = findItemById(formattedData,item)
58
+ ancestor.expanded = true
59
+ });
60
+ }
54
61
  } else {
55
- unCheckIt(foundItem, selectedItems, setSelectedItems);
62
+ unCheckIt(foundItem, selectedItems, setSelectedItems, false);
63
+ if (currentNode._parent) {
64
+ const parents = getParentAndAncestorsIds(currentNode._parent, formattedData)
65
+ parents.forEach((item:string) => {
66
+ const ancestor = findItemById(formattedData,item)
67
+ ancestor.expanded = true
68
+ });
69
+ }
56
70
  }
57
71
  }
58
72
  }
@@ -92,17 +106,18 @@ const MultiLevelSelect = (props: MultiLevelSelectProps) => {
92
106
  treeData={formattedData}
93
107
  onChange={(
94
108
  // @ts-ignore
95
- selectedNodes: { [key: string]: any }[],
109
+ selectedNodes: { [key: string]: any }[],
96
110
  currentNode: { [key: string]: any }[]
97
111
  ) => {
98
112
  setCheckedData(currentNode);
99
113
  onSelect(currentNode);
114
+
100
115
  }}
101
116
  id={id}
102
117
  {...props}
103
118
  />
104
119
  );
105
- }, [formattedData]);
120
+ }, [formattedData])
106
121
 
107
122
  return (
108
123
  <div {...ariaProps} {...dataProps} className={classes} id={id}>
@@ -19,19 +19,20 @@ export const findItemById = (
19
19
  export const checkIt = (
20
20
  foundItem: { [key: string]: any },
21
21
  selectedItems: any[],
22
- setSelectedItems: Function
22
+ setSelectedItems: Function,
23
+ expand: boolean
23
24
  ) => {
24
25
  if (!foundItem) {
25
26
  return;
26
27
  }
27
28
 
28
29
  foundItem.checked = true;
29
- foundItem.expanded = true;
30
+ foundItem.expanded = expand;
30
31
  selectedItems.push(foundItem);
31
32
 
32
33
  if (foundItem.children) {
33
34
  foundItem.children.map((x: any) => {
34
- checkIt(x, selectedItems, setSelectedItems);
35
+ checkIt(x, selectedItems, setSelectedItems, expand);
35
36
  });
36
37
  }
37
38
 
@@ -41,20 +42,46 @@ export const checkIt = (
41
42
  export const unCheckIt = (
42
43
  foundItem: { [key: string]: any },
43
44
  selectedItems: any,
44
- setSelectedItems: any
45
+ setSelectedItems: any,
46
+ expand: boolean
45
47
  ) => {
46
48
  if (!foundItem) {
47
49
  return;
48
50
  }
49
51
 
50
52
  foundItem.checked = false;
53
+ foundItem.expanded = false;
51
54
  const newSelectedItems = selectedItems.filter(
52
55
  (item: any) => item.id !== foundItem.id
53
56
  );
54
57
  if (foundItem.children) {
55
58
  foundItem.children.map((x: any) => {
56
- unCheckIt(x, selectedItems, setSelectedItems);
59
+ unCheckIt(x, selectedItems, setSelectedItems, expand);
57
60
  });
58
61
  }
59
62
  setSelectedItems([...newSelectedItems]);
60
63
  };
64
+
65
+
66
+ export const getParentAndAncestorsIds = (itemId:string, items:{ [key: string]: string; }[], ancestors:string[] = []):any => {
67
+ for (let i = 0; i < items.length; i++) {
68
+ const item:any = items[i];
69
+ if (item.id === itemId) {
70
+ // item found in current level of items array
71
+ return [...ancestors, item.id];
72
+ }
73
+ if (item.children && item.children.length > 0) {
74
+ // recursively search through children
75
+ const foundAncestors = getParentAndAncestorsIds(
76
+ itemId,
77
+ item.children,
78
+ [...ancestors, item.id]
79
+ );
80
+ if (foundAncestors) {
81
+ return foundAncestors;
82
+ }
83
+ }
84
+ }
85
+ // item not found in this level of items array or its children
86
+ return null;
87
+ }
@@ -81,10 +81,11 @@ $pb_selectable_card_border: 2px;
81
81
  }
82
82
 
83
83
  .separator {
84
- width: 2px;
85
- margin-right: 0px;
86
84
  background: $royal;
87
85
  }
86
+ .psuedo_separator {
87
+ background-color: $royal;
88
+ }
88
89
  }
89
90
  }
90
91
  }
@@ -125,13 +126,17 @@ $pb_selectable_card_border: 2px;
125
126
 
126
127
  .separator {
127
128
  align-self: stretch;
128
- width: 1px;
129
- margin-right: 1px;
129
+ padding-right: 1px;
130
130
  margin-top: -1px;
131
131
  margin-bottom: -1px;
132
132
  background: $border_light;
133
133
  }
134
134
 
135
+ .psuedo_separator {
136
+ align-self: stretch;
137
+ padding-right: 1px;
138
+ }
139
+
135
140
  &.error {
136
141
  > label {
137
142
  border-color: $error;
@@ -13,9 +13,9 @@ import {
13
13
 
14
14
  import Icon from '../pb_icon/_icon'
15
15
  import Checkbox from '../pb_checkbox/_checkbox'
16
- import Card from '../pb_card/_card'
17
16
  import Flex from '../pb_flex/_flex'
18
17
  import Radio from '../pb_radio/_radio'
18
+ import Card from '../pb_card/_card'
19
19
 
20
20
  type SelectableCardProps = {
21
21
  aria?: { [key: string]: string },
@@ -149,13 +149,15 @@ const SelectableCard = (props: SelectableCardProps) => {
149
149
  </Input>
150
150
  </Flex>
151
151
  <div className="separator" />
152
- <Card.Body
152
+ <div className="psuedo_separator"/>
153
+ <Card
154
+ borderNone
153
155
  dark={dark}
154
156
  padding="sm"
155
157
  status={error ? 'negative' : null}
156
158
  >
157
159
  {text ||props.children}
158
- </Card.Body>
160
+ </Card>
159
161
  </Flex>
160
162
  :
161
163
  text || props.children
@@ -24,7 +24,8 @@
24
24
  <% end %>
25
25
  <% end %>
26
26
  <div class="separator"></div>
27
- <%= pb_rails("card/card_body", props: { padding: "sm", status: object.status }) do %>
27
+ <div class="psuedo_separator"></div>
28
+ <%= pb_rails("card", props: { padding: "sm", status: object.status, border_none: true }) do %>
28
29
  <% if content.nil? %>
29
30
  <%= pb_rails("body", props: { text: object.text }) %>
30
31
  <% else %>
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import Select from 'react-select'
5
3
  import AsyncSelect from 'react-select/async'
@@ -19,6 +17,7 @@ import Placeholder from './components/Placeholder'
19
17
  import ValueContainer from './components/ValueContainer'
20
18
 
21
19
  import { noop, buildDataProps } from '../utilities/props'
20
+ import { Noop } from '../types'
22
21
 
23
22
  /**
24
23
  * @typedef {object} Props
@@ -33,16 +32,28 @@ type TypeaheadProps = {
33
32
  components?: object,
34
33
  createable?: boolean,
35
34
  dark?: boolean,
36
- data?: object,
35
+ data?: { [key: string]: string },
37
36
  error?: string,
38
37
  id?: string,
39
38
  label?: string,
40
- loadOptions?: string,
39
+ loadOptions?: string | Noop,
41
40
  getOptionLabel?: string | (() => any),
42
41
  getOptionValue?: string | (() => any),
43
42
  name?: string,
44
43
  }
45
44
 
45
+ export type SelectValueType = {
46
+ label: string,
47
+ value: string,
48
+ imageUrl?: string,
49
+ }
50
+
51
+ type TagOnChangeValues = {
52
+ action?: string,
53
+ option?: SelectValueType,
54
+ removedValue?: string,
55
+ }
56
+
46
57
  /**
47
58
  * @constant {React.ReactComponent} Typeahead
48
59
  * @param {TypeaheadProps} props - props as described at https://react-select.com/props
@@ -67,7 +78,7 @@ const Typeahead = ({
67
78
  Control,
68
79
  ClearIndicator,
69
80
  IndicatorsContainer,
70
- IndicatorSeparator: null,
81
+ IndicatorSeparator: null as null,
71
82
  MenuList,
72
83
  MultiValue,
73
84
  Option,
@@ -85,8 +96,9 @@ const Typeahead = ({
85
96
  isSearchable: true,
86
97
  name,
87
98
  multiKit: '',
88
- onCreateOption: null,
99
+ onCreateOption: null as null,
89
100
  plusIcon: false,
101
+ onMultiValueClick: (_option: SelectValueType) => { },
90
102
  ...props,
91
103
  }
92
104
 
@@ -96,7 +108,7 @@ const Typeahead = ({
96
108
  : (async ? AsyncSelect : Select)
97
109
  )
98
110
 
99
- const handleOnChange = (_data, { action, option, removedValue }) => {
111
+ const handleOnChange = (_data: SelectValueType, { action, option, removedValue }: TagOnChangeValues) => {
100
112
  if (action === 'select-option') {
101
113
  if (selectProps.onMultiValueClick) selectProps.onMultiValueClick(option)
102
114
  const multiValueClearEvent = new CustomEvent(`pb-typeahead-kit-${selectProps.id}-result-option-select`, { detail: option ? option : _data })
@@ -123,13 +135,13 @@ const Typeahead = ({
123
135
 
124
136
  return (
125
137
  <div {...dataProps}
126
- className={classnames(classes, inlineClass)}
138
+ className={classnames(classes, inlineClass)}
127
139
  >
128
140
  <Tag
129
- classNamePrefix="typeahead-kit-select"
130
- error={error}
131
- onChange={handleOnChange}
132
- {...selectProps}
141
+ classNamePrefix="typeahead-kit-select"
142
+ error={error}
143
+ onChange={handleOnChange}
144
+ {...selectProps}
133
145
  />
134
146
  </div>
135
147
  )
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React, { useEffect } from 'react'
4
2
  import { components } from 'react-select'
5
3
 
@@ -11,8 +9,8 @@ const ClearContainer = (props: any) => {
11
9
 
12
10
  return (
13
11
  <components.ClearIndicator
14
- className="clear_indicator"
15
- {...props}
12
+ className="clear_indicator"
13
+ {...props}
16
14
  />
17
15
  )
18
16
  }
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import { components } from 'react-select'
5
3
 
@@ -13,14 +11,14 @@ type Props = {
13
11
  const TypeaheadControl = (props: Props) => (
14
12
  <div className="pb_typeahead_wrapper">
15
13
  <TextInput
16
- dark={props.selectProps.dark}
17
- error={props.selectProps.error}
18
- label={props.selectProps.label}
14
+ dark={props.selectProps.dark}
15
+ error={props.selectProps.error}
16
+ label={props.selectProps.label}
19
17
  >
20
18
  <Flex>
21
19
  <components.Control
22
- className="text_input"
23
- {...props}
20
+ className="text_input"
21
+ {...props}
24
22
  />
25
23
  </Flex>
26
24
  </TextInput>
@@ -1,12 +1,10 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import { components } from 'react-select'
5
3
 
6
4
  const IndicatorsContainer = (props: any) => (
7
5
  <components.IndicatorsContainer
8
- className="text_input_indicators"
9
- {...props}
6
+ className="text_input_indicators"
7
+ {...props}
10
8
  />
11
9
  )
12
10
 
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import { components } from 'react-select'
5
3
 
@@ -0,0 +1,66 @@
1
+ import React from 'react'
2
+ import { components } from 'react-select'
3
+
4
+ import Badge from '../../pb_badge/_badge'
5
+ import FormPill from '../../pb_form_pill/_form_pill'
6
+ import { SelectValueType } from '../_typeahead'
7
+
8
+ type Props = {
9
+ data: SelectValueType,
10
+ multiValueTemplate: any,
11
+ removeProps: any,
12
+ selectProps: any,
13
+ }
14
+
15
+ const MultiValue = (props: Props) => {
16
+ const { removeProps } = props
17
+ const { imageUrl, label } = props.data
18
+ const { multiKit } = props.selectProps
19
+
20
+ const formPillProps = {
21
+ marginRight: 'xs',
22
+ name: label,
23
+ avatarUrl: '',
24
+ }
25
+
26
+ if (typeof imageUrl === 'string') formPillProps.avatarUrl = imageUrl
27
+
28
+ return (
29
+ <components.MultiValueContainer
30
+ className="text_input_multivalue_container"
31
+ {...props}
32
+ >
33
+ {multiKit === 'badge' &&
34
+ <Badge
35
+ closeProps={removeProps}
36
+ removeIcon
37
+ text={label}
38
+ variant="primary"
39
+ />
40
+ }
41
+
42
+ {multiKit !== 'badge' && imageUrl &&
43
+ <FormPill
44
+ avatarUrl={imageUrl}
45
+ closeProps={removeProps}
46
+ marginRight="xs"
47
+ name={label}
48
+ size={multiKit === 'smallPill' ? 'small' : ''}
49
+ text=''
50
+ />
51
+ }
52
+
53
+ {multiKit !== 'badge' && !imageUrl &&
54
+ <FormPill
55
+ closeProps={removeProps}
56
+ marginRight="xs"
57
+ name=''
58
+ size={multiKit === 'smallPill' ? 'small' : ''}
59
+ text={label}
60
+ />
61
+ }
62
+ </components.MultiValueContainer>
63
+ )
64
+ }
65
+
66
+ export default MultiValue
@@ -0,0 +1,37 @@
1
+ import React from 'react'
2
+ import { components } from 'react-select'
3
+
4
+ import User from '../../pb_user/_user'
5
+
6
+ const Option = (props: any) => {
7
+ const {
8
+ imageUrl,
9
+ } = props.data
10
+ const { valueComponent } = props.selectProps
11
+
12
+ return (
13
+ <components.Option {...props}>
14
+ <>
15
+ {!valueComponent && imageUrl &&
16
+ <User
17
+ align="left"
18
+ avatarUrl={imageUrl}
19
+ dark={props.selectProps.dark}
20
+ name={props.label}
21
+ orientation="horizontal"
22
+ />
23
+ }
24
+
25
+ {valueComponent &&
26
+ valueComponent(props.data)
27
+ }
28
+
29
+ {!valueComponent && !imageUrl &&
30
+ props.label
31
+ }
32
+ </>
33
+ </components.Option>
34
+ )
35
+ }
36
+
37
+ export default Option
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import { components } from 'react-select'
5
3
 
@@ -9,18 +7,18 @@ import Icon from '../../pb_icon/_icon'
9
7
  const Placeholder = (props: any) => (
10
8
  <>
11
9
  <Flex
12
- align="center"
13
- className="placeholder"
10
+ align="center"
11
+ className="placeholder"
14
12
  >
15
13
  <components.IndicatorsContainer
16
- {...props}
14
+ {...props}
17
15
  />
18
- <If condition={props.selectProps.plusIcon}>
16
+ {props.selectProps.plusIcon &&
19
17
  <Icon
20
- className="typeahead-plus-icon"
21
- icon="plus"
18
+ className="typeahead-plus-icon"
19
+ icon="plus"
22
20
  />
23
- </If>
21
+ }
24
22
  </Flex>
25
23
  </>
26
24
  )
@@ -1,12 +1,10 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import { components } from 'react-select'
5
3
 
6
- const ValueContainer = (props: Props) => (
4
+ const ValueContainer = (props: any) => (
7
5
  <components.ValueContainer
8
- className="text_input_value_container"
9
- {...props}
6
+ className="text_input_value_container"
7
+ {...props}
10
8
  />
11
9
  )
12
10
 
@@ -2,18 +2,26 @@ import PbEnhancedElement from '../pb_enhanced_element'
2
2
  import { debounce } from 'lodash'
3
3
 
4
4
  export default class PbTypeahead extends PbEnhancedElement {
5
+ _searchInput: HTMLInputElement
6
+ _resultsElement: HTMLElement
7
+ _debouncedSearch: Function
8
+ _resultsLoadingIndicator: HTMLElement
9
+ _resultOptionTemplate: HTMLElement
10
+ _resultsOptionCache: Map<string, Array<DocumentFragment>>
11
+ _searchContext: string
12
+
5
13
  static get selector() {
6
14
  return '[data-pb-typeahead-kit]'
7
15
  }
8
16
 
9
17
  connect() {
10
- this.element.addEventListener('keydown', (event) => this.handleKeydown(event))
18
+ this.element.addEventListener('keydown', (event: KeyboardEvent) => this.handleKeydown(event))
11
19
  this.searchInput.addEventListener('focus', () => this.debouncedSearch())
12
20
  this.searchInput.addEventListener('input', () => this.debouncedSearch())
13
- this.resultsElement.addEventListener('click', (event) => this.optionSelected(event))
21
+ this.resultsElement.addEventListener('click', (event: MouseEvent) => this.optionSelected(event))
14
22
  }
15
23
 
16
- handleKeydown(event) {
24
+ handleKeydown(event: KeyboardEvent) {
17
25
  if (event.key === 'ArrowUp') {
18
26
  event.preventDefault()
19
27
  this.focusPreviousOption()
@@ -24,7 +32,7 @@ export default class PbTypeahead extends PbEnhancedElement {
24
32
  }
25
33
 
26
34
  search() {
27
- if (this.searchTerm.length < this.searchTermMinimumLength) return this.clearResults()
35
+ if (this.searchTerm.length < parseInt(this.searchTermMinimumLength)) return this.clearResults()
28
36
 
29
37
  this.toggleResultsLoadingIndicator(true)
30
38
  this.showResults()
@@ -34,17 +42,17 @@ export default class PbTypeahead extends PbEnhancedElement {
34
42
  const search = {
35
43
  searchingFor: searchTerm,
36
44
  searchingContext: searchContext,
37
- setResults: (results) => {
45
+ setResults: (results: Array<DocumentFragment>) => {
38
46
  this.resultsCacheUpdate(searchTerm, searchContext, results)
39
47
  },
40
48
  }
41
49
  this.element.dispatchEvent(new CustomEvent('pb-typeahead-kit-search', { bubbles: true, detail: search }))
42
50
  }
43
51
 
44
- resultsCacheUpdate(searchTerm, searchContext, results) {
52
+ resultsCacheUpdate(searchTerm: string, searchContext: string, results: Array<DocumentFragment>) {
45
53
  const searchTermAndContext = this.cacheKeyFor(searchTerm, searchContext)
46
54
  if (this.resultsOptionCache.has(searchTermAndContext)) this.resultsOptionCache.delete(searchTermAndContext)
47
- if (this.resultsOptionCache.size > 32) this.resultsOptionCache.delete(this.resultsOptionCache.keys[0])
55
+ if (this.resultsOptionCache.size > 32) this.resultsOptionCache.delete(this.resultsOptionCache.keys().next().value)
48
56
 
49
57
  this.resultsOptionCache.set(searchTermAndContext, results)
50
58
  this.showResults()
@@ -57,7 +65,7 @@ export default class PbTypeahead extends PbEnhancedElement {
57
65
  get debouncedSearch() {
58
66
  return this._debouncedSearch = (
59
67
  this._debouncedSearch ||
60
- debounce(this.search, this.searchDebounceTimeout).bind(this)
68
+ debounce(this.search, parseInt(this.searchDebounceTimeout)).bind(this)
61
69
  )
62
70
  }
63
71
 
@@ -70,12 +78,12 @@ export default class PbTypeahead extends PbEnhancedElement {
70
78
  this.resultsElement.appendChild(this.newResultOption(result.cloneNode(true)))
71
79
  }
72
80
  for (const result of this.resultsElement.querySelectorAll('[data-result-option-item]')) {
73
- result.addEventListener('mousedown', (event) => this.optionSelected(event))
81
+ result.addEventListener('mousedown', (event: MouseEvent) => this.optionSelected(event))
74
82
  }
75
83
  }
76
84
 
77
- optionSelected(event) {
78
- const resultOption = event.target.closest('[data-result-option-item]')
85
+ optionSelected(event: MouseEvent) {
86
+ const resultOption = (event.target as Element).closest('[data-result-option-item]')
79
87
  if (!resultOption) return
80
88
 
81
89
  this.resultsCacheClear()
@@ -89,8 +97,8 @@ export default class PbTypeahead extends PbEnhancedElement {
89
97
  this.resultsElement.innerHTML = ''
90
98
  }
91
99
 
92
- newResultOption(content) {
93
- const resultOption = this.resultOptionTemplate.content.cloneNode(true)
100
+ newResultOption(content: DocumentFragment) {
101
+ const resultOption = (this.resultOptionTemplate as HTMLTemplateElement).content.cloneNode(true) as Element
94
102
  resultOption.querySelector('slot[name="content"]').replaceWith(content)
95
103
  return resultOption
96
104
  }
@@ -100,9 +108,9 @@ export default class PbTypeahead extends PbEnhancedElement {
100
108
  const previousIndex = currentIndex - 1
101
109
  const previousOptionItem = (
102
110
  this.resultOptionItems[previousIndex] ||
103
- this.resultOptionItems[this.resultOptionItems.length - 1]
104
- )
105
- previousOptionItem.focus()
111
+ this.resultOptionItems[this.resultOptionItems.length - 1]
112
+ );
113
+ (previousOptionItem as HTMLElement).focus()
106
114
  }
107
115
 
108
116
  focusNextOption() {
@@ -110,9 +118,9 @@ export default class PbTypeahead extends PbEnhancedElement {
110
118
  const nextIndex = currentIndex + 1
111
119
  const nextOptionItem = (
112
120
  this.resultOptionItems[nextIndex] ||
113
- this.resultOptionItems[0]
114
- )
115
- nextOptionItem.focus()
121
+ this.resultOptionItems[0]
122
+ );
123
+ (nextOptionItem as HTMLElement).focus()
116
124
  }
117
125
 
118
126
  get resultOptionItems() {
@@ -134,11 +142,11 @@ export default class PbTypeahead extends PbEnhancedElement {
134
142
  get searchContext() {
135
143
  if (this._searchContext) return this._searchContext
136
144
 
137
- const selector = this.element.dataset.searchContextValueSelector
138
- if (selector) return (
145
+ const selector = (this.element as HTMLElement).dataset.searchContextValueSelector
146
+ if (selector) return ((
139
147
  this.element.parentNode.querySelector(selector) ||
140
- this.element.closest(selector)
141
- ).value
148
+ this.element.closest(selector)
149
+ ) as HTMLInputElement).value
142
150
 
143
151
  return null
144
152
  }
@@ -151,7 +159,7 @@ export default class PbTypeahead extends PbEnhancedElement {
151
159
  return this.cacheKeyFor(this.searchTerm, this.searchContext)
152
160
  }
153
161
 
154
- cacheKeyFor(searchTerm, searchContext) {
162
+ cacheKeyFor(searchTerm: string, searchContext: string) {
155
163
  return [searchTerm, JSON.stringify(searchContext)].join()
156
164
  }
157
165
 
@@ -160,11 +168,11 @@ export default class PbTypeahead extends PbEnhancedElement {
160
168
  }
161
169
 
162
170
  get searchTermMinimumLength() {
163
- return this.element.dataset.pbTypeaheadKitSearchTermMinimumLength
171
+ return (this.element as HTMLElement).dataset.pbTypeaheadKitSearchTermMinimumLength
164
172
  }
165
173
 
166
174
  get searchDebounceTimeout() {
167
- return this.element.dataset.pbTypeaheadKitSearchDebounceTimeout
175
+ return (this.element as HTMLElement).dataset.pbTypeaheadKitSearchDebounceTimeout
168
176
  }
169
177
 
170
178
  get resultsElement() {
@@ -192,9 +200,9 @@ export default class PbTypeahead extends PbEnhancedElement {
192
200
  )
193
201
  }
194
202
 
195
- toggleResultsLoadingIndicator(visible) {
196
- var visibilityProperty = 0
197
- if (visible) visibilityProperty = 1
203
+ toggleResultsLoadingIndicator(visible: boolean) {
204
+ var visibilityProperty = '0'
205
+ if (visible) visibilityProperty = '1'
198
206
  this.resultsLoadingIndicator.style.opacity = visibilityProperty
199
207
  }
200
208
  }
@@ -0,0 +1,2 @@
1
+ declare module 'react-select'
2
+ declare module 'react-select/*'
@@ -18,7 +18,7 @@ type UserProps = {
18
18
  data?: {[key: string]: string},
19
19
  id?: string,
20
20
  name?: string,
21
- orientation?: "horiztonal" | "vertical",
21
+ orientation?: "horizontal" | "vertical",
22
22
  size?: "sm" | "md" | "lg",
23
23
  subtitle?: string | Array<Node> | Node,
24
24
  territory?: string,
@@ -48,3 +48,17 @@
48
48
  .z_index_10 {
49
49
  z-index: 1000;
50
50
  }
51
+
52
+ $zIndex_values: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
53
+
54
+ @each $size, $size_value in $breakpoints_grid {
55
+ @each $zIndex_value in $zIndex_values {
56
+ $min_size: map-get($size_value, "min");
57
+ $max_size: map-get($size_value, "max");
58
+ .z_index_#{$size}_#{$zIndex_value} {
59
+ @include break_on($min_size, $max_size) {
60
+ z-index: #{$zIndex_value * 100} !important;
61
+ }
62
+ }
63
+ }
64
+ }
@@ -113,9 +113,11 @@ type Shadow = {
113
113
 
114
114
  type Space = "spaceBetween" | "spaceAround" | "spaceEvenly"
115
115
 
116
+ type ZIndexType = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
117
+ type ZIndexResponsiveType = {[key: string]: ZIndexType}
116
118
  type ZIndex = {
117
- zIndex?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10,
118
- }
119
+ zIndex?: ZIndexType,
120
+ } | ZIndexResponsiveType
119
121
 
120
122
  // keep this as the last type definition
121
123
  export type GlobalProps = AlignContent & AlignItems & AlignSelf &
@@ -178,9 +180,19 @@ const PROP_CATEGORIES: {[key:string]: (props: {[key: string]: any}) => string} =
178
180
  css += maxWidth ? `max_width_${maxWidth } ` : ''
179
181
  return css
180
182
  },
181
- zIndexProps: ({ zIndex }: ZIndex) => {
183
+ zIndexProps: (zIndex: ZIndex) => {
182
184
  let css = ''
183
- css += zIndex ? `z_index_${zIndex } ` : ''
185
+ Object.entries(zIndex).forEach((zIndexEntry) => {
186
+ if (zIndexEntry[0] == "zIndex") {
187
+ if (typeof zIndexEntry[1] == "number") {
188
+ css += `z_index_${zIndexEntry[1]} `
189
+ } else if (typeof zIndexEntry[1] == "object") {
190
+ Object.entries(zIndexEntry[1]).forEach((zIndexObj) => {
191
+ css += `z_index_${zIndexObj[0]}_${zIndexObj[1]} `
192
+ })
193
+ }
194
+ }
195
+ })
184
196
  return css
185
197
  },
186
198
  shadowProps: ({ shadow }: Shadow) => {
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- PREVIOUS_VERSION = "12.18.0"
5
- VERSION = "12.19.0"
4
+ PREVIOUS_VERSION = "12.19.0"
5
+ VERSION = "12.20.0"
6
6
  end
@@ -16,16 +16,29 @@ module Playbook
16
16
  }
17
17
  end
18
18
 
19
- private
19
+ def screen_size_values
20
+ %w[xs sm md lg xl]
21
+ end
20
22
 
21
23
  def z_index_props
22
- selected_index_props = z_index_options.keys.select { |sk| try(sk) }
23
- return nil unless selected_index_props.present?
24
+ selected_props = z_index_options.keys.select { |sk| try(sk) }
25
+ return nil unless selected_props.present?
26
+
27
+ responsive = selected_props.present? && try(:z_index).is_a?(::Hash)
28
+ css = ""
29
+ if responsive
30
+ z_index_value = send(:z_index)
31
+ z_index_value.each do |key, value|
32
+ css += "z_index_#{key}_#{value} " if screen_size_values.include?(key.to_s) && z_index_values.include?(value.to_s)
33
+ end
34
+ else
35
+ selected_props.each do |k|
36
+ z_index_value = send(k)
37
+ css += "z_index_#{z_index_value} " if z_index_values.include? z_index_value
38
+ end
39
+ end
24
40
 
25
- selected_index_props.map do |k|
26
- index_value = send(k)
27
- "z_index_#{index_value}" if z_index_values.include? index_value
28
- end.compact.join(" ")
41
+ css unless css.blank?
29
42
  end
30
43
  end
31
44
  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.19.0
4
+ version: 12.20.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-05-09 00:00:00.000000000 Z
12
+ date: 2023-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -2248,17 +2248,17 @@ files:
2248
2248
  - app/pb_kits/playbook/pb_treemap_chart/docs/index.js
2249
2249
  - app/pb_kits/playbook/pb_treemap_chart/treemap_chart.html.erb
2250
2250
  - app/pb_kits/playbook/pb_treemap_chart/treemap_chart.rb
2251
- - app/pb_kits/playbook/pb_typeahead/_typeahead.jsx
2252
2251
  - app/pb_kits/playbook/pb_typeahead/_typeahead.scss
2253
2252
  - app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx
2254
- - app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.jsx
2255
- - app/pb_kits/playbook/pb_typeahead/components/Control.jsx
2256
- - app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.jsx
2257
- - app/pb_kits/playbook/pb_typeahead/components/MenuList.jsx
2258
- - app/pb_kits/playbook/pb_typeahead/components/MultiValue.jsx
2259
- - app/pb_kits/playbook/pb_typeahead/components/Option.jsx
2260
- - app/pb_kits/playbook/pb_typeahead/components/Placeholder.jsx
2261
- - app/pb_kits/playbook/pb_typeahead/components/ValueContainer.jsx
2253
+ - app/pb_kits/playbook/pb_typeahead/_typeahead.tsx
2254
+ - app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx
2255
+ - app/pb_kits/playbook/pb_typeahead/components/Control.tsx
2256
+ - app/pb_kits/playbook/pb_typeahead/components/IndicatorsContainer.tsx
2257
+ - app/pb_kits/playbook/pb_typeahead/components/MenuList.tsx
2258
+ - app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx
2259
+ - app/pb_kits/playbook/pb_typeahead/components/Option.tsx
2260
+ - app/pb_kits/playbook/pb_typeahead/components/Placeholder.tsx
2261
+ - app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx
2262
2262
  - app/pb_kits/playbook/pb_typeahead/docs/_description.md
2263
2263
  - app/pb_kits/playbook/pb_typeahead/docs/_footer.md
2264
2264
  - app/pb_kits/playbook/pb_typeahead/docs/_typeahead_async_createable.jsx
@@ -2289,9 +2289,10 @@ files:
2289
2289
  - app/pb_kits/playbook/pb_typeahead/docs/_typeahead_without_pills.md
2290
2290
  - app/pb_kits/playbook/pb_typeahead/docs/example.yml
2291
2291
  - app/pb_kits/playbook/pb_typeahead/docs/index.js
2292
- - app/pb_kits/playbook/pb_typeahead/index.js
2292
+ - app/pb_kits/playbook/pb_typeahead/index.ts
2293
2293
  - app/pb_kits/playbook/pb_typeahead/typeahead.html.erb
2294
2294
  - app/pb_kits/playbook/pb_typeahead/typeahead.rb
2295
+ - app/pb_kits/playbook/pb_typeahead/types.d.ts
2295
2296
  - app/pb_kits/playbook/pb_user/_user.scss
2296
2297
  - app/pb_kits/playbook/pb_user/_user.tsx
2297
2298
  - app/pb_kits/playbook/pb_user/docs/_description.md
@@ -1,62 +0,0 @@
1
- /* @flow */
2
-
3
- import React from 'react'
4
- import { components } from 'react-select'
5
-
6
- import Badge from '../../pb_badge/_badge'
7
- import FormPill from '../../pb_form_pill/_form_pill'
8
-
9
- type Props = {
10
- data: object,
11
- multiValueTemplate: any,
12
- removeProps: any,
13
- selectProps: any,
14
- }
15
-
16
- const MultiValue = (props: Props) => {
17
- const { removeProps } = props
18
- const { imageUrl, label } = props.data
19
- const { multiKit } = props.selectProps
20
-
21
- const formPillProps = {
22
- marginRight: 'xs',
23
- name: label,
24
- }
25
-
26
- if (typeof imageUrl === 'string') formPillProps.avatarUrl = imageUrl
27
-
28
- return (
29
- <components.MultiValueContainer
30
- className="text_input_multivalue_container"
31
- {...props}
32
- >
33
- <If condition={multiKit === 'badge'}>
34
- <Badge
35
- closeProps={removeProps}
36
- removeIcon
37
- text={label}
38
- variant="primary"
39
- />
40
- <Else />
41
- <If condition={imageUrl}>
42
- <FormPill
43
- avatarUrl={imageUrl}
44
- closeProps={removeProps}
45
- marginRight="xs"
46
- name={label}
47
- size={multiKit === 'smallPill' ? 'small' : ''}
48
- />
49
- <Else />
50
- <FormPill
51
- closeProps={removeProps}
52
- marginRight="xs"
53
- size={multiKit === 'smallPill' ? 'small' : ''}
54
- text={label}
55
- />
56
- </If>
57
- </If>
58
- </components.MultiValueContainer>
59
- )
60
- }
61
-
62
- export default MultiValue
@@ -1,39 +0,0 @@
1
- /* @flow */
2
-
3
- import React from 'react'
4
- import { components } from 'react-select'
5
-
6
- import User from '../../pb_user/_user'
7
-
8
- const Option = (props: any) => {
9
- const {
10
- imageUrl,
11
- } = props.data
12
- const { valueComponent } = props.selectProps
13
-
14
- return (
15
- <components.Option {...props}>
16
- <div>
17
- <Choose>
18
- <When condition={!valueComponent && imageUrl}>
19
- <User
20
- align="left"
21
- avatarUrl={imageUrl}
22
- dark={props.selectProps.dark}
23
- name={props.label}
24
- orientation="horizontal"
25
- />
26
- </When>
27
- <When condition={valueComponent}>
28
- { valueComponent(props.data) }
29
- </When>
30
- <Otherwise>
31
- {props.label}
32
- </Otherwise>
33
- </Choose>
34
- </div>
35
- </components.Option>
36
- )
37
- }
38
-
39
- export default Option