playbook_ui 15.5.0.pre.alpha.draggablefix12589 → 15.5.0.pre.alpha.play250212696
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +31 -0
- data/app/pb_kits/playbook/pb_dialog/index.js +15 -10
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_dropzone.md +3 -1
- data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +4 -4
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +15 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +3 -0
- data/app/pb_kits/playbook/pb_typeahead/components/ClearIndicator.tsx +13 -2
- data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +6 -1
- data/app/pb_kits/playbook/pb_typeahead/components/ValueContainer.tsx +34 -7
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.html.erb +30 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.jsx +37 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_input_display.md +3 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +6 -1
- data/dist/chunks/{_typeahead-DUmTKJUc.js → _typeahead-978gNTWh.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f25d8e230fb6f3cf92eac4b1e458b83579eba7a8f201a70f84c54fb97698b6b
|
|
4
|
+
data.tar.gz: f63d76ad13dada00d5d24667c202d4b8de8b29559fe5b6c0fbcf28eb8e3205f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f81a0dbf26bbbe3705c641959e175d4d4807690c16c672200e0a75a9fda6929eefe20ed29305f863c2229c6b5427a61327372364c4adb4f043ede86ac58cfb0
|
|
7
|
+
data.tar.gz: 9e0869caebd6545288ebe34e1df3d8c3f51faf21c915237aae222029abe6274c934ba2453b46c59f476ea3b38f58e0be319817b5f3d017fef7b915232a5fc5aa
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
<%
|
|
2
|
+
options = [
|
|
3
|
+
{
|
|
4
|
+
label: "United States",
|
|
5
|
+
value: "unitedStates",
|
|
6
|
+
id: "us"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
label: "United Kingdom",
|
|
10
|
+
value: "unitedKingdom",
|
|
11
|
+
id: "gb"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "Pakistan",
|
|
15
|
+
value: "pakistan",
|
|
16
|
+
id: "pk"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
%>
|
|
20
|
+
|
|
21
|
+
|
|
1
22
|
<%= pb_rails("button", props: { text: "Open Complex Dialog", data:{"open-dialog": "dialog-complex"} }) %>
|
|
2
23
|
|
|
3
24
|
<%= pb_rails("dialog", props: { id:"dialog-complex", size: "lg", full_height: true }) do %>
|
|
@@ -10,6 +31,16 @@
|
|
|
10
31
|
<%= pb_rails("rich_text_editor", props: {id: "default", value: "Add your text here"}) %>
|
|
11
32
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
12
33
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
34
|
+
<%= pb_rails("dropdown", props: {options: options, autocomplete: true}) %>
|
|
35
|
+
<%= pb_rails("typeahead", props: {
|
|
36
|
+
id: "typeahead-default",
|
|
37
|
+
placeholder: "Select one...",
|
|
38
|
+
options: options,
|
|
39
|
+
name: :foo,
|
|
40
|
+
margin_top: "sm",
|
|
41
|
+
is_multi: false
|
|
42
|
+
})
|
|
43
|
+
%>
|
|
13
44
|
|
|
14
45
|
<% end %>
|
|
15
46
|
<%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-complex"}) %>
|
|
@@ -143,25 +143,30 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
143
143
|
|
|
144
144
|
// Close dialog box on outside click
|
|
145
145
|
dialogs.forEach((dialogElement) => {
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
146
|
+
const originalClickHandler = dialogElement._outsideClickHandler
|
|
147
|
+
if (originalClickHandler) dialogElement.removeEventListener("click", originalClickHandler)
|
|
148
|
+
|
|
148
149
|
dialogElement._outsideClickHandler = (event) => {
|
|
149
150
|
const dialogParentDataset = dialogElement.parentElement.dataset
|
|
150
151
|
if (dialogParentDataset.overlayClick === "overlay_close") return
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
event.
|
|
156
|
-
event.
|
|
157
|
-
|
|
158
|
-
|
|
153
|
+
// Get the dialog's bounding box (the actual content area)
|
|
154
|
+
const rect = dialogElement.getBoundingClientRect()
|
|
155
|
+
const clickedInDialog = (
|
|
156
|
+
event.clientX >= rect.left &&
|
|
157
|
+
event.clientX <= rect.right &&
|
|
158
|
+
event.clientY >= rect.top &&
|
|
159
|
+
event.clientY <= rect.bottom
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
// Only close if clicked outside the dialog content (on the backdrop)
|
|
163
|
+
if (!clickedInDialog) {
|
|
159
164
|
dialogElement.close()
|
|
160
165
|
event.stopPropagation()
|
|
161
166
|
}
|
|
162
167
|
}
|
|
163
168
|
|
|
164
|
-
dialogElement.addEventListener("
|
|
169
|
+
dialogElement.addEventListener("click", dialogElement._outsideClickHandler);
|
|
165
170
|
})
|
|
166
171
|
}
|
|
167
172
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
The multiple container functionality also supports customized dropzone styling as shown here.
|
|
2
2
|
|
|
3
|
-
In addition to this, the `
|
|
3
|
+
In addition to this, the `enableCrossContainerPreview` prop can be used on the `DraggableProvider` as shown here to enable dropzone preview for cross-container dragging.
|
|
4
|
+
|
|
5
|
+
With `enableCrossContainerPreview`, the `onDrop` and `onDragEnd` event listeners will also provide several arguments to allow developers more context from the drag event.
|
|
4
6
|
|
|
5
7
|
The `onDrop` callback is triggered when an item is successfully dropped into a container. It provides the following arguments:
|
|
6
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.pb_file_upload_kit {
|
|
2
|
-
.
|
|
2
|
+
.pb_card_kit {
|
|
3
3
|
border: 1px #ccc dashed;
|
|
4
4
|
text-align: center;
|
|
5
5
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
}
|
|
12
12
|
&.error,
|
|
13
13
|
&.pb_file_upload_kit_error {
|
|
14
|
-
.
|
|
14
|
+
.pb_card_kit {
|
|
15
15
|
border-color: $error;
|
|
16
16
|
}
|
|
17
17
|
.pb_body_kit_negative {
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
.dark .pb_file_upload_kit {
|
|
33
|
-
.
|
|
33
|
+
.pb_card_kit {
|
|
34
34
|
border: 1px $text_dk_lighter dashed;
|
|
35
35
|
}
|
|
36
36
|
&.error,
|
|
37
37
|
&.pb_file_upload_kit_error {
|
|
38
|
-
.
|
|
38
|
+
.pb_card_kit {
|
|
39
39
|
border-color: $error_dark;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -276,3 +276,18 @@ test('multi-value badges have tabIndex and focus class when focused', () => {
|
|
|
276
276
|
})
|
|
277
277
|
})
|
|
278
278
|
|
|
279
|
+
test('input display none shows number of selected items', () => {
|
|
280
|
+
render(
|
|
281
|
+
<Typeahead
|
|
282
|
+
data={{ testid: 'input-display-none-test' }}
|
|
283
|
+
defaultValue={[options[0], options[1]]}
|
|
284
|
+
inputDisplay="none"
|
|
285
|
+
isMulti
|
|
286
|
+
options={options}
|
|
287
|
+
/>
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
const kit = screen.getByTestId('input-display-none-test')
|
|
291
|
+
const inputDisplayDiv = kit.querySelector(".pb_typeahead_selection_count")
|
|
292
|
+
expect(inputDisplayDiv).toHaveTextContent("2 items selected")
|
|
293
|
+
})
|
|
@@ -43,6 +43,7 @@ type TypeaheadProps = {
|
|
|
43
43
|
error?: string,
|
|
44
44
|
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
|
45
45
|
id?: string,
|
|
46
|
+
inputDisplay?: "pills" | "none",
|
|
46
47
|
label?: string,
|
|
47
48
|
loadOptions?: string | Noop,
|
|
48
49
|
getOptionLabel?: string | (() => string),
|
|
@@ -89,6 +90,7 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
89
90
|
getOptionValue,
|
|
90
91
|
htmlOptions = {},
|
|
91
92
|
id,
|
|
93
|
+
inputDisplay = "pills",
|
|
92
94
|
name,
|
|
93
95
|
loadOptions = noop,
|
|
94
96
|
marginBottom = "sm",
|
|
@@ -238,6 +240,7 @@ const Typeahead = forwardRef<HTMLInputElement, TypeaheadProps>(({
|
|
|
238
240
|
getOptionValue: isString(getOptionValue) ? get(window, getOptionValue) : getOptionValue,
|
|
239
241
|
defaultOptions: true,
|
|
240
242
|
id: id || uniqueId(),
|
|
243
|
+
inputDisplay: inputDisplay,
|
|
241
244
|
inline: false,
|
|
242
245
|
isClearable: true,
|
|
243
246
|
isSearchable: true,
|
|
@@ -7,18 +7,29 @@ type ClearContainerProps = {
|
|
|
7
7
|
id: string,
|
|
8
8
|
},
|
|
9
9
|
clearValue: () => void,
|
|
10
|
+
innerProps?: any,
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const ClearContainer = (props: ClearContainerProps): React.ReactElement => {
|
|
13
|
-
const { selectProps, clearValue } = props
|
|
13
|
+
const ClearContainer = (props: ClearContainerProps | any): React.ReactElement => {
|
|
14
|
+
const { selectProps, clearValue, innerProps } = props
|
|
14
15
|
useEffect(() => {
|
|
15
16
|
document.addEventListener(`pb-typeahead-kit-${selectProps.id}:clear`, clearValue)
|
|
16
17
|
}, [clearValue, selectProps.id])
|
|
17
18
|
|
|
19
|
+
// To stop this from bubbling up when inside a dialog or other modal
|
|
20
|
+
const handleMouseDown = (event: React.MouseEvent) => {
|
|
21
|
+
event.stopPropagation()
|
|
22
|
+
innerProps?.onMouseDown?.(event)
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
return (
|
|
19
26
|
<components.ClearIndicator
|
|
20
27
|
className="clear_indicator"
|
|
21
28
|
{...props}
|
|
29
|
+
innerProps={{
|
|
30
|
+
...innerProps,
|
|
31
|
+
onMouseDown: handleMouseDown,
|
|
32
|
+
}}
|
|
22
33
|
/>
|
|
23
34
|
)
|
|
24
35
|
}
|
|
@@ -19,7 +19,12 @@ type Props = {
|
|
|
19
19
|
const MultiValue = (props: Props) => {
|
|
20
20
|
const { removeProps, isFocused } = props
|
|
21
21
|
const { imageUrl, label } = props.data
|
|
22
|
-
const { dark, multiKit, pillColor, truncate, wrapped } = props.selectProps
|
|
22
|
+
const { dark, multiKit, pillColor, truncate, wrapped, inputDisplay } = props.selectProps
|
|
23
|
+
|
|
24
|
+
// If inputDisplay is "none", don't render the pill/badge, just return null (the count handled in ValueContainer file)
|
|
25
|
+
if (inputDisplay === 'none') {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
23
28
|
|
|
24
29
|
const formPillProps = {
|
|
25
30
|
marginRight: 'xs',
|
|
@@ -1,15 +1,42 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { components } from 'react-select'
|
|
3
|
+
import Body from '../../pb_body/_body'
|
|
3
4
|
|
|
4
5
|
type ValueContainerProps = {
|
|
5
|
-
children: React.ReactNode,
|
|
6
|
+
children: React.ReactNode | React.ReactNode[],
|
|
7
|
+
selectProps?: Record<string, unknown>,
|
|
8
|
+
hasValue?: boolean,
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
const ValueContainer = (props: ValueContainerProps): React.ReactElement =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
11
|
+
const ValueContainer = (props: ValueContainerProps | any): React.ReactElement => {
|
|
12
|
+
const { children, selectProps, hasValue } = props
|
|
13
|
+
const inputDisplay = (selectProps as any)?.inputDisplay
|
|
14
|
+
const value = (selectProps as any)?.value
|
|
15
|
+
|
|
16
|
+
// When inputDisplay is "none" and there are selected values, show count text (this is for multi-select only)
|
|
17
|
+
if (inputDisplay === 'none' && hasValue && value) {
|
|
18
|
+
const selectedCount = Array.isArray(value) ? value.length : 0
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<components.ValueContainer
|
|
22
|
+
className="text_input_value_container"
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<Body
|
|
26
|
+
className="pb_typeahead_selection_count"
|
|
27
|
+
text={`${selectedCount} item${selectedCount !== 1 ? 's' : ''} selected`}
|
|
28
|
+
/>
|
|
29
|
+
{children}
|
|
30
|
+
</components.ValueContainer>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<components.ValueContainer
|
|
36
|
+
className="text_input_value_container"
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
14
41
|
|
|
15
42
|
export default ValueContainer
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%
|
|
2
|
+
options = [
|
|
3
|
+
{ label: 'Orange', value: '#FFA500' },
|
|
4
|
+
{ label: 'Red', value: '#FF0000' },
|
|
5
|
+
{ label: 'Green', value: '#00FF00' },
|
|
6
|
+
{ label: 'Blue', value: '#0000FF' },
|
|
7
|
+
{ label: 'Yellow', value: '#FFFF00' },
|
|
8
|
+
{ label: 'Purple', value: '#800080' },
|
|
9
|
+
{ label: 'Cyan', value: '#00FFFF' },
|
|
10
|
+
{ label: 'Magenta', value: '#FF00FF' }
|
|
11
|
+
]
|
|
12
|
+
%>
|
|
13
|
+
|
|
14
|
+
<%= pb_rails("typeahead", props: {
|
|
15
|
+
id: "typeahead-input-display-none",
|
|
16
|
+
label: "With Input Display None",
|
|
17
|
+
options: options,
|
|
18
|
+
name: :foo,
|
|
19
|
+
input_display: "none",
|
|
20
|
+
})
|
|
21
|
+
%>
|
|
22
|
+
<br/>
|
|
23
|
+
<%= pb_rails("typeahead", props: {
|
|
24
|
+
id: "typeahead-input-display-pills",
|
|
25
|
+
label: "With Input Display Pills (Default)",
|
|
26
|
+
options: options,
|
|
27
|
+
name: :foo,
|
|
28
|
+
pills: true,
|
|
29
|
+
})
|
|
30
|
+
%>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import Typeahead from '../_typeahead'
|
|
4
|
+
|
|
5
|
+
const options = [
|
|
6
|
+
{ label: 'Orange', value: '#FFA500' },
|
|
7
|
+
{ label: 'Red', value: '#FF0000' },
|
|
8
|
+
{ label: 'Green', value: '#00FF00' },
|
|
9
|
+
{ label: 'Blue', value: '#0000FF' },
|
|
10
|
+
{ label: 'Yellow', value: '#FFFF00' },
|
|
11
|
+
{ label: 'Purple', value: '#800080' },
|
|
12
|
+
{ label: 'Cyan', value: '#00FFFF' },
|
|
13
|
+
{ label: 'Magenta', value: '#FF00FF' }
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
const TypeaheadInputDisplay = (props) => {
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
<Typeahead
|
|
20
|
+
inputDisplay="none"
|
|
21
|
+
isMulti
|
|
22
|
+
label="With Input Display None"
|
|
23
|
+
options={options}
|
|
24
|
+
{...props}
|
|
25
|
+
/>
|
|
26
|
+
<br/>
|
|
27
|
+
<Typeahead
|
|
28
|
+
isMulti
|
|
29
|
+
label="With Input Display Pills (Default)"
|
|
30
|
+
options={options}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
</>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default TypeaheadInputDisplay
|
|
@@ -5,6 +5,7 @@ examples:
|
|
|
5
5
|
- typeahead_default_options: With Default Options
|
|
6
6
|
- typeahead_with_context: With Context
|
|
7
7
|
- typeahead_with_pills: With Pills
|
|
8
|
+
- typeahead_input_display: Input Display
|
|
8
9
|
- typeahead_without_pills: Without Pills (Single Select)
|
|
9
10
|
- typeahead_with_pills_async: With Pills (Async Data)
|
|
10
11
|
- typeahead_with_pills_async_users: With Pills (Async Data w/ Users)
|
|
@@ -26,6 +27,7 @@ examples:
|
|
|
26
27
|
- typeahead_react_hook: React Hook
|
|
27
28
|
- typeahead_with_highlight: With Highlight
|
|
28
29
|
- typeahead_with_pills: With Pills
|
|
30
|
+
- typeahead_input_display: Input Display
|
|
29
31
|
- typeahead_with_pills_async: With Pills (Async Data)
|
|
30
32
|
- typeahead_with_pills_async_users: With Pills (Async Data w/ Users)
|
|
31
33
|
- typeahead_with_pills_async_custom_options: With Pills (Async Data w/ Custom Options)
|
|
@@ -17,4 +17,5 @@ export { default as TypeaheadReactHook } from './_typeahead_react_hook.jsx'
|
|
|
17
17
|
export { default as TypeaheadDisabled } from './_typeahead_disabled.jsx'
|
|
18
18
|
export { default as TypeaheadPreserveInput } from './_typeahead_preserve_input.jsx'
|
|
19
19
|
export { default as TypeaheadDefaultValue } from './_typeahead_default_value.jsx'
|
|
20
|
-
export { default as TypeaheadCustomOptions } from './_typeahead_custom_options.jsx'
|
|
20
|
+
export { default as TypeaheadCustomOptions } from './_typeahead_custom_options.jsx'
|
|
21
|
+
export { default as TypeaheadInputDisplay } from './_typeahead_input_display.jsx'
|
|
@@ -25,6 +25,10 @@ module Playbook
|
|
|
25
25
|
prop :is_multi, type: Playbook::Props::Boolean,
|
|
26
26
|
default: true
|
|
27
27
|
|
|
28
|
+
prop :input_display, type: Playbook::Props::Enum,
|
|
29
|
+
values: %w[none pills],
|
|
30
|
+
default: "pills"
|
|
31
|
+
|
|
28
32
|
prop :pills, type: Playbook::Props::Boolean,
|
|
29
33
|
default: false
|
|
30
34
|
|
|
@@ -78,7 +82,7 @@ module Playbook
|
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
def is_react?
|
|
81
|
-
pills || !is_multi || wrapped
|
|
85
|
+
pills || !is_multi || wrapped || input_display == "none"
|
|
82
86
|
end
|
|
83
87
|
|
|
84
88
|
def typeahead_react_options
|
|
@@ -91,6 +95,7 @@ module Playbook
|
|
|
91
95
|
id: id,
|
|
92
96
|
inline: inline,
|
|
93
97
|
isMulti: is_multi,
|
|
98
|
+
inputDisplay: input_display,
|
|
94
99
|
label: label,
|
|
95
100
|
marginBottom: margin_bottom,
|
|
96
101
|
multiKit: multi_kit,
|