playbook_ui 14.20.0.pre.alpha.PLAY2178advancedtablerowpinning7983 → 14.20.0.pre.alpha.PLAY2214checkboxhiddeninput8052
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_advanced_table/index.js +2 -0
- data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +4 -11
- data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +28 -7
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_custom.html.erb +1 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_custom_rails.md +1 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_form.html.erb +22 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_form.md +5 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +2 -48
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate_rails.md +1 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_options.html.erb +1 -0
- data/app/pb_kits/playbook/pb_checkbox/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_checkbox/index.js +56 -0
- data/app/pb_kits/playbook/pb_draggable/context/index.tsx +17 -58
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +12 -3
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.jsx +42 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +14 -10
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +26 -15
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -1
- data/app/pb_kits/playbook/pb_popover/index.ts +9 -4
- data/app/pb_kits/playbook/pb_table/docs/_table_with_selectable_rows.html.erb +3 -51
- data/app/pb_kits/playbook/pb_table/styles/_mobile_collapse.scss +1 -1
- data/dist/chunks/{_typeahead-CRW6dJbW.js → _typeahead-CoOpeYom.js} +1 -1
- data/dist/chunks/{_weekday_stacked-KnBjAMoL.js → _weekday_stacked-BppvLxTS.js} +2 -2
- data/dist/chunks/{lib-D5R1BjUn.js → lib-D7Va7yqa.js} +1 -1
- data/dist/chunks/{pb_form_validation-BZ2AVAi_.js → pb_form_validation-DSkdRDMf.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/menu.yml +1 -1
- data/dist/playbook-doc.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 +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ccd5f34dd1f2a70f68d8c16e9209ace9bd33d53b7952e0a01a6923c3f89552e
|
4
|
+
data.tar.gz: 43ebf8006b68996baadd8f823d964ef2908c8890bb5d7914d3102910af7c154a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f36f96c61a5b520710754222b4b8bcc111ac2ee5d5b62137f99e1e033f86601c0fed765c36d6b15a44bf40f345b3f299a8e611fd7fc80e40eeebd87ffea9dfa6
|
7
|
+
data.tar.gz: df815bdc4cdac84fc2fcb215e0c304f7656a01eb9e4260677fe3eff97ede106c2ff586ce428cb4fc9b1f5ccf5f044a645da5796ad4131276d54899ed650d2041
|
@@ -569,6 +569,8 @@ class PbAdvancedTableActionBar {
|
|
569
569
|
actionBar.style.height = 'auto';
|
570
570
|
actionBar.style.overflow = 'visible';
|
571
571
|
actionBar.style.opacity = '1';
|
572
|
+
actionBar.style.transitionProperty = 'all';
|
573
|
+
actionBar.style.transitionTimingFunction = 'ease-in-out';
|
572
574
|
actionBar.classList.remove("p_none");
|
573
575
|
actionBar.classList.add("p_xs", "is-visible", "show-action-card");
|
574
576
|
|
@@ -1,16 +1,9 @@
|
|
1
1
|
<%= pb_content_tag(:label) do %>
|
2
2
|
<%= content.presence || object.input %>
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
</span>
|
8
|
-
<% else %>
|
9
|
-
<span data-pb-checkbox-icon-span="true" class="pb_checkbox_checkmark">
|
10
|
-
<%= pb_rails("icon", props: { icon: "check", classname: "check_icon", fixed_width: true}) %>
|
11
|
-
<%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon hidden", fixed_width: true}) %>
|
12
|
-
</span>
|
13
|
-
<% end %>
|
3
|
+
<span data-pb-checkbox-icon-span="true" class="pb_checkbox_checkmark">
|
4
|
+
<%= pb_rails("icon", props: { icon: "check", classname: "check_icon", fixed_width: true}) %>
|
5
|
+
<%= pb_rails("icon", props: { icon: "minus", classname: "indeterminate_icon hidden", fixed_width: true}) %>
|
6
|
+
</span>
|
14
7
|
<span class="pb_checkbox_label">
|
15
8
|
<%= pb_rails("body", props: { status: object.checkbox_label_status, text: object.text, dark: object.dark, margin_right: object.form_spacing ? "xs" : "" }) %>
|
16
9
|
</span>
|
@@ -5,7 +5,8 @@ module Playbook
|
|
5
5
|
class Checkbox < Playbook::KitBase
|
6
6
|
prop :error, type: Playbook::Props::Boolean, default: false
|
7
7
|
prop :checked, type: Playbook::Props::Boolean, default: false
|
8
|
-
prop :
|
8
|
+
prop :indeterminate_main, type: Playbook::Props::Boolean, default: false
|
9
|
+
prop :indeterminate_parent
|
9
10
|
prop :text
|
10
11
|
prop :value
|
11
12
|
prop :name
|
@@ -17,19 +18,43 @@ module Playbook
|
|
17
18
|
default: false
|
18
19
|
prop :form_spacing, type: Playbook::Props::Boolean,
|
19
20
|
default: false
|
21
|
+
prop :hidden_input, type: Playbook::Props::Boolean,
|
22
|
+
default: false
|
23
|
+
prop :hidden_value
|
20
24
|
|
21
25
|
def classname
|
22
|
-
generate_classname("pb_checkbox_kit", checked_class) +
|
26
|
+
generate_classname("pb_checkbox_kit", checked_class) + error_class
|
23
27
|
end
|
24
28
|
|
25
29
|
def input
|
26
|
-
|
30
|
+
inputs = []
|
31
|
+
effective_name = name || input_options[:name]
|
32
|
+
effective_value = value || input_options[:value] || "1"
|
33
|
+
is_checked = checked || input_options[:checked]
|
34
|
+
|
35
|
+
inputs << hidden_field_tag(effective_name, hidden_value || "0") if hidden_input && effective_name.present?
|
36
|
+
|
37
|
+
inputs << check_box_tag(
|
38
|
+
effective_name,
|
39
|
+
effective_value,
|
40
|
+
is_checked,
|
41
|
+
input_options.merge(disabled: disabled)
|
42
|
+
)
|
43
|
+
|
44
|
+
safe_join(inputs)
|
27
45
|
end
|
28
46
|
|
29
47
|
def checkbox_label_status
|
30
48
|
error ? "negative" : nil
|
31
49
|
end
|
32
50
|
|
51
|
+
def data
|
52
|
+
Hash(prop(:data)).merge(
|
53
|
+
pb_checkbox_indeterminate_main: indeterminate_main,
|
54
|
+
pb_checkbox_indeterminate_parent: indeterminate_parent
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
33
58
|
private
|
34
59
|
|
35
60
|
def error_class
|
@@ -39,10 +64,6 @@ module Playbook
|
|
39
64
|
def checked_class
|
40
65
|
checked ? "on" : "off"
|
41
66
|
end
|
42
|
-
|
43
|
-
def indeterminate_class
|
44
|
-
indeterminate ? " indeterminate" : ""
|
45
|
-
end
|
46
67
|
end
|
47
68
|
end
|
48
69
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
When using a custom checkbox wrapped in the Checkbox kit, hidden inputs are not automatically included and cannot be prop enabled. Manually add a hidden input before the checkbox if necessary to submit a value when the checkbox is unchecked (as is standard in Rails forms).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
<%= pb_form_with(scope: :example, url: "", method: :get) do |form| %>
|
3
|
+
<%=pb_rails("flex", props: { gap: "sm", orientation: "column"}) do %>
|
4
|
+
<%= pb_rails("checkbox" , props: {
|
5
|
+
text: "1. pb_rails(\"checkbox\") Checkbox from kit",
|
6
|
+
value: "checkbox-value",
|
7
|
+
name: "checkbox-name",
|
8
|
+
hidden_input: true
|
9
|
+
}) %>
|
10
|
+
<%= form.check_box :example_checkbox,
|
11
|
+
data: { field1: "value1", field2: "value2" },
|
12
|
+
props: { text: "2. form.check_box Checkbox from Form Builder" },
|
13
|
+
unchecked_value: "no",
|
14
|
+
id: "checkbox-id",
|
15
|
+
name: "checkbox-name",
|
16
|
+
class: "checkbox-class"
|
17
|
+
%>
|
18
|
+
<%= form.actions do |action| %>
|
19
|
+
<%= action.button props: { type: "submit", text: "Submit", variant: "primary" } %>
|
20
|
+
<% end %>
|
21
|
+
<% end %>
|
22
|
+
<% end %>
|
@@ -0,0 +1,5 @@
|
|
1
|
+
The way to access hidden inputs for form submission depends on which version of the kit being used within the form context.
|
2
|
+
|
3
|
+
If using the Rails Checkbox version of the kit, set `hidden_input: true`. Inspect Checkbox #1 in the example above to see the hidden input in the DOM.
|
4
|
+
|
5
|
+
If using the Form Builder version of the kit (reference the [Form kit page](https://playbook.powerapp.cloud/kits/form) for more on these), the hidden input will appear if the input has a set `unchecked_value`. Inspect Checkbox #2 in the example above (and the two checkbox examples on the Form kit page) to see the hidden input in the DOM. See the [Rails check_box FormHelper docs](https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box) for more.
|
@@ -9,11 +9,10 @@
|
|
9
9
|
<tr>
|
10
10
|
<th>
|
11
11
|
<%= pb_rails("checkbox", props: {
|
12
|
-
checked: true,
|
13
12
|
text: "Uncheck All",
|
14
13
|
value: "checkbox-value",
|
15
14
|
name: "main-checkbox",
|
16
|
-
|
15
|
+
indeterminate_main: true,
|
17
16
|
id: "indeterminate-checkbox"
|
18
17
|
}) %>
|
19
18
|
</th>
|
@@ -30,55 +29,10 @@
|
|
30
29
|
value: checkbox[:id],
|
31
30
|
name: "#{checkbox[:id]}-indeterminate-checkbox",
|
32
31
|
id: "#{checkbox[:id]}-indeterminate-checkbox",
|
32
|
+
indeterminate_parent: "indeterminate-checkbox",
|
33
33
|
}) %>
|
34
34
|
</td>
|
35
35
|
</tr>
|
36
36
|
<% end %>
|
37
37
|
</tbody>
|
38
38
|
<% end %>
|
39
|
-
|
40
|
-
<script>
|
41
|
-
document.addEventListener('DOMContentLoaded', function() {
|
42
|
-
const mainCheckboxWrapper = document.getElementById('indeterminate-checkbox');
|
43
|
-
const mainCheckbox = document.getElementsByName("main-checkbox")[0];
|
44
|
-
const childCheckboxes = document.querySelectorAll('input[type="checkbox"][id$="indeterminate-checkbox"]');
|
45
|
-
|
46
|
-
const updateMainCheckbox = () => {
|
47
|
-
// Count the number of checked child checkboxes
|
48
|
-
const checkedCount = Array.from(childCheckboxes).filter(cb => cb.checked).length;
|
49
|
-
// Determine if the main checkbox should be in an indeterminate state
|
50
|
-
const indeterminate = checkedCount > 0 && checkedCount < childCheckboxes.length;
|
51
|
-
|
52
|
-
// Set the main checkbox states
|
53
|
-
mainCheckbox.indeterminate = indeterminate;
|
54
|
-
mainCheckbox.checked = checkedCount > 0;
|
55
|
-
|
56
|
-
// Determine the main checkbox label based on the number of checked checkboxes
|
57
|
-
const text = checkedCount === 0 ? 'Check All' : 'Uncheck All';
|
58
|
-
|
59
|
-
// Determine the icon class to add and remove based on the number of checked checkboxes
|
60
|
-
const iconClassToAdd = checkedCount === 0 ? 'pb_checkbox_checkmark' : 'pb_checkbox_indeterminate';
|
61
|
-
const iconClassToRemove = checkedCount === 0 ? 'pb_checkbox_indeterminate' : 'pb_checkbox_checkmark';
|
62
|
-
|
63
|
-
// Update main checkbox label
|
64
|
-
mainCheckboxWrapper.getElementsByClassName('pb_body_kit')[0].textContent = text;
|
65
|
-
|
66
|
-
// Add and remove the icon class to the main checkbox wrapper
|
67
|
-
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.add(iconClassToAdd);
|
68
|
-
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.remove(iconClassToRemove);
|
69
|
-
|
70
|
-
// Toggle the visibility of the checkbox icon based on the indeterminate state
|
71
|
-
mainCheckboxWrapper.getElementsByClassName("indeterminate_icon")[0].classList.toggle('hidden', !indeterminate);
|
72
|
-
mainCheckboxWrapper.getElementsByClassName("check_icon")[0].classList.toggle('hidden', indeterminate);
|
73
|
-
};
|
74
|
-
|
75
|
-
mainCheckbox.addEventListener('change', function() {
|
76
|
-
childCheckboxes.forEach(cb => cb.checked = this.checked);
|
77
|
-
updateMainCheckbox();
|
78
|
-
});
|
79
|
-
|
80
|
-
childCheckboxes.forEach(cb => {
|
81
|
-
cb.addEventListener('change', updateMainCheckbox);
|
82
|
-
});
|
83
|
-
});
|
84
|
-
</script>
|
@@ -0,0 +1 @@
|
|
1
|
+
If you want to use indeterminate, "check/uncheck all" checkboxes, add `indeterminate_main: true` and an `id` to the main checkbox. Then, add an `indeterminate_parent` prop with the main checkbox's `id` to the children checkboxes.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import PbEnhancedElement from "../pb_enhanced_element"
|
2
|
+
|
3
|
+
const INDETERMINATE_MAIN_CHECKBOX_SELECTOR = "[data-pb-checkbox-indeterminate-main='true']"
|
4
|
+
|
5
|
+
export default class PbCheckbox extends PbEnhancedElement {
|
6
|
+
static get selector() {
|
7
|
+
return INDETERMINATE_MAIN_CHECKBOX_SELECTOR
|
8
|
+
}
|
9
|
+
|
10
|
+
connect() {
|
11
|
+
const mainCheckboxWrapper = this.element;
|
12
|
+
const mainCheckbox = mainCheckboxWrapper.querySelector('input')
|
13
|
+
const childCheckboxes = document.querySelectorAll(`[data-pb-checkbox-indeterminate-parent="${this.element.id}"] input[type="checkbox"]`);
|
14
|
+
|
15
|
+
const updateMainCheckbox = () => {
|
16
|
+
// Count the number of checked child checkboxes
|
17
|
+
const checkedCount = Array.from(childCheckboxes).filter(cb => cb.checked).length;
|
18
|
+
// Determine if the main checkbox should be in an indeterminate state
|
19
|
+
const indeterminate = checkedCount > 0 && checkedCount < childCheckboxes.length;
|
20
|
+
|
21
|
+
// Set the main checkbox states
|
22
|
+
mainCheckbox.indeterminate = indeterminate;
|
23
|
+
mainCheckbox.checked = checkedCount > 0;
|
24
|
+
|
25
|
+
// Determine the main checkbox label based on the number of checked checkboxes
|
26
|
+
const text = checkedCount === 0 ? 'Check All' : 'Uncheck All';
|
27
|
+
|
28
|
+
// Determine the icon class to add and remove based on the number of checked checkboxes
|
29
|
+
const iconClassToAdd = checkedCount === 0 ? 'pb_checkbox_checkmark' : 'pb_checkbox_indeterminate';
|
30
|
+
const iconClassToRemove = checkedCount === 0 ? 'pb_checkbox_indeterminate' : 'pb_checkbox_checkmark';
|
31
|
+
|
32
|
+
// Update main checkbox label
|
33
|
+
mainCheckboxWrapper.getElementsByClassName('pb_body_kit')[0].textContent = text;
|
34
|
+
|
35
|
+
// Add and remove the icon class to the main checkbox wrapper
|
36
|
+
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.add(iconClassToAdd);
|
37
|
+
mainCheckboxWrapper.querySelector('[data-pb-checkbox-icon-span]').classList.remove(iconClassToRemove);
|
38
|
+
|
39
|
+
// Toggle the visibility of the checkbox icon based on the indeterminate state
|
40
|
+
mainCheckboxWrapper.getElementsByClassName("indeterminate_icon")[0].classList.toggle('hidden', !indeterminate);
|
41
|
+
mainCheckboxWrapper.getElementsByClassName("check_icon")[0].classList.toggle('hidden', indeterminate);
|
42
|
+
};
|
43
|
+
|
44
|
+
// Set indeterminate icon on main checkbox if initial children checkboxes are checked
|
45
|
+
updateMainCheckbox();
|
46
|
+
|
47
|
+
this.element.querySelector('input').addEventListener('change', function() {
|
48
|
+
childCheckboxes.forEach(cb => cb.checked = this.checked);
|
49
|
+
updateMainCheckbox();
|
50
|
+
});
|
51
|
+
|
52
|
+
childCheckboxes.forEach(cb => {
|
53
|
+
cb.addEventListener('change', updateMainCheckbox);
|
54
|
+
});
|
55
|
+
}
|
56
|
+
}
|
@@ -1,11 +1,11 @@
|
|
1
|
-
import React, { createContext, useReducer, useContext, useEffect, useMemo
|
1
|
+
import React, { createContext, useReducer, useContext, useEffect, useMemo } from "react";
|
2
2
|
import { InitialStateType, ActionType, DraggableProviderType } from "./types";
|
3
3
|
|
4
4
|
const initialState: InitialStateType = {
|
5
5
|
items: [],
|
6
6
|
dragData: { id: "", initialGroup: "" },
|
7
7
|
isDragging: "",
|
8
|
-
activeContainer: ""
|
8
|
+
activeContainer: ""
|
9
9
|
};
|
10
10
|
|
11
11
|
const reducer = (state: InitialStateType, action: ActionType) => {
|
@@ -31,23 +31,9 @@ const reducer = (state: InitialStateType, action: ActionType) => {
|
|
31
31
|
const { dragId, targetId } = action.payload;
|
32
32
|
const newItems = [...state.items];
|
33
33
|
const draggedItem = newItems.find(item => item.id === dragId);
|
34
|
-
const
|
35
|
-
|
36
|
-
if (!draggedItem || !targetItem || draggedItem.container !== targetItem.container) {
|
37
|
-
return state;
|
38
|
-
}
|
39
|
-
|
40
|
-
if (dragId === targetId) {
|
41
|
-
return state;
|
42
|
-
}
|
43
|
-
|
44
|
-
const draggedIndex = newItems.findIndex(item => item.id === dragId);
|
34
|
+
const draggedIndex = newItems.indexOf(draggedItem);
|
45
35
|
const targetIndex = newItems.findIndex(item => item.id === targetId);
|
46
36
|
|
47
|
-
if (draggedIndex === -1 || targetIndex === -1) {
|
48
|
-
return state;
|
49
|
-
}
|
50
|
-
|
51
37
|
newItems.splice(draggedIndex, 1);
|
52
38
|
newItems.splice(targetIndex, 0, draggedItem);
|
53
39
|
|
@@ -62,11 +48,7 @@ const reducer = (state: InitialStateType, action: ActionType) => {
|
|
62
48
|
const DragContext = createContext<any>({});
|
63
49
|
|
64
50
|
export const DraggableContext = () => {
|
65
|
-
|
66
|
-
if (context === undefined) {
|
67
|
-
throw new Error('DraggableContext must be used within a DraggableProvider');
|
68
|
-
}
|
69
|
-
return context;
|
51
|
+
return useContext(DragContext);
|
70
52
|
};
|
71
53
|
|
72
54
|
export const DraggableProvider = ({
|
@@ -81,11 +63,7 @@ export const DraggableProvider = ({
|
|
81
63
|
dropZone = { type: 'ghost', color: 'neutral', direction: 'vertical' }
|
82
64
|
}: DraggableProviderType) => {
|
83
65
|
const [state, dispatch] = useReducer(reducer, initialState);
|
84
|
-
|
85
|
-
// Store initial items in a ref to use if needed (for consistency when needed in future updates)
|
86
|
-
const initialItemsRef = useRef(initialItems);
|
87
|
-
const [isDragging, setIsDragging] = useState(false);
|
88
|
-
|
66
|
+
|
89
67
|
// Parse dropZone prop - handle both string format (backward compatibility) and object format
|
90
68
|
let dropZoneType = 'ghost';
|
91
69
|
let dropZoneColor = 'neutral';
|
@@ -108,64 +86,45 @@ export const DraggableProvider = ({
|
|
108
86
|
|
109
87
|
useEffect(() => {
|
110
88
|
dispatch({ type: 'SET_ITEMS', payload: initialItems });
|
111
|
-
initialItemsRef.current = initialItems;
|
112
89
|
}, [initialItems]);
|
113
90
|
|
114
91
|
useEffect(() => {
|
115
|
-
|
116
|
-
|
117
|
-
}
|
118
|
-
}, [state.items, onReorder]);
|
92
|
+
onReorder(state.items);
|
93
|
+
}, [state.items]);
|
119
94
|
|
120
95
|
const handleDragStart = (id: string, container: string) => {
|
121
|
-
|
122
|
-
dispatch({ type: 'SET_DRAG_DATA', payload: { id, initialGroup: container } });
|
96
|
+
dispatch({ type: 'SET_DRAG_DATA', payload: { id: id, initialGroup: container } });
|
123
97
|
dispatch({ type: 'SET_IS_DRAGGING', payload: id });
|
124
|
-
dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
|
125
98
|
if (onDragStart) onDragStart(id, container);
|
126
99
|
};
|
127
100
|
|
128
101
|
const handleDragEnter = (id: string, container: string) => {
|
129
|
-
if (
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
const draggedItem = state.items.find(item => item.id === state.dragData.id);
|
134
|
-
const targetItem = state.items.find(item => item.id === id);
|
135
|
-
|
136
|
-
if (!draggedItem || !targetItem || draggedItem.container !== targetItem.container) {
|
137
|
-
return;
|
102
|
+
if (state.dragData.id !== id) {
|
103
|
+
dispatch({ type: 'REORDER_ITEMS', payload: { dragId: state.dragData.id, targetId: id } });
|
104
|
+
dispatch({ type: 'SET_DRAG_DATA', payload: { id: state.dragData.id, initialGroup: container } });
|
138
105
|
}
|
139
|
-
|
140
|
-
dispatch({ type: 'REORDER_ITEMS', payload: { dragId: state.dragData.id, targetId: id } });
|
141
|
-
|
142
106
|
if (onDragEnter) onDragEnter(id, container);
|
143
107
|
};
|
144
108
|
|
145
109
|
const handleDragEnd = () => {
|
146
|
-
setIsDragging(false);
|
147
110
|
dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
|
148
111
|
dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
|
149
112
|
if (onDragEnd) onDragEnd();
|
150
113
|
};
|
151
114
|
|
152
|
-
const
|
153
|
-
|
154
|
-
|
155
|
-
if (draggedItem && draggedItem.container !== container) {
|
156
|
-
dispatch({ type: 'CHANGE_CATEGORY', payload: { itemId: state.dragData.id, container } });
|
157
|
-
}
|
115
|
+
const changeCategory = (itemId: string, container: string) => {
|
116
|
+
dispatch({ type: 'CHANGE_CATEGORY', payload: { itemId, container } });
|
117
|
+
};
|
158
118
|
|
119
|
+
const handleDrop = (container: string) => {
|
159
120
|
dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
|
160
121
|
dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
|
161
|
-
|
162
|
-
setIsDragging(false);
|
122
|
+
changeCategory(state.dragData.id, container);
|
163
123
|
if (onDrop) onDrop(container);
|
164
124
|
};
|
165
125
|
|
166
126
|
const handleDragOver = (e: Event, container: string) => {
|
167
127
|
e.preventDefault();
|
168
|
-
e.stopPropagation();
|
169
128
|
dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
|
170
129
|
if (onDragOver) onDragOver(e, container);
|
171
130
|
};
|
@@ -185,7 +144,7 @@ export const DraggableProvider = ({
|
|
185
144
|
handleDragEnd,
|
186
145
|
handleDrop,
|
187
146
|
handleDragOver
|
188
|
-
}), [state, dropZoneType, dropZoneColor, dropZoneDirection
|
147
|
+
}), [state, dropZoneType, dropZoneColor, dropZoneDirection]);
|
189
148
|
|
190
149
|
return (
|
191
150
|
<DragContext.Provider value={contextValue}>{children}</DragContext.Provider>
|
@@ -25,6 +25,7 @@ type DropdownProps = {
|
|
25
25
|
blankSelection?: string;
|
26
26
|
children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
|
27
27
|
className?: string;
|
28
|
+
closeOnSelection?: boolean;
|
28
29
|
formPillProps?: GenericObject;
|
29
30
|
dark?: boolean;
|
30
31
|
data?: { [key: string]: string };
|
@@ -55,6 +56,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
55
56
|
blankSelection = '',
|
56
57
|
children,
|
57
58
|
className,
|
59
|
+
closeOnSelection = true,
|
58
60
|
dark = false,
|
59
61
|
data = {},
|
60
62
|
defaultValue = {},
|
@@ -152,7 +154,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
152
154
|
if (!multiSelect) return optionsWithBlankSelection;
|
153
155
|
return optionsWithBlankSelection.filter((option: GenericObject) => !selectedArray.some((sel) => sel.label === option.label));
|
154
156
|
}, [optionsWithBlankSelection, selectedArray, multiSelect]);
|
155
|
-
|
157
|
+
|
156
158
|
const filteredOptions = useMemo(() => {
|
157
159
|
return availableOptions.filter((opt: GenericObject) =>
|
158
160
|
String(opt.label).toLowerCase().includes(filterItem.toLowerCase())
|
@@ -192,12 +194,18 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
192
194
|
return next;
|
193
195
|
});
|
194
196
|
setFilterItem("");
|
195
|
-
|
197
|
+
// Only close dropdown if closeOnSelection is true
|
198
|
+
if (closeOnSelection) {
|
199
|
+
setIsDropDownClosed(true);
|
200
|
+
}
|
196
201
|
} else {
|
197
202
|
setSelected(clickedItem);
|
198
203
|
setFilterItem("");
|
199
|
-
setIsDropDownClosed(true);
|
200
204
|
onSelect && onSelect(clickedItem);
|
205
|
+
// Only close dropdown if closeOnSelection is true
|
206
|
+
if (closeOnSelection) {
|
207
|
+
setIsDropDownClosed(true);
|
208
|
+
}
|
201
209
|
}
|
202
210
|
};
|
203
211
|
|
@@ -252,6 +260,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
252
260
|
<DropdownContext.Provider
|
253
261
|
value={{
|
254
262
|
autocomplete,
|
263
|
+
closeOnSelection,
|
255
264
|
dropdownContainerRef,
|
256
265
|
filteredOptions,
|
257
266
|
filterItem,
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import Dropdown from '../../pb_dropdown/_dropdown'
|
3
|
+
|
4
|
+
const DropdownCloseOnSelect = (props) => {
|
5
|
+
|
6
|
+
const options = [
|
7
|
+
{
|
8
|
+
label: "United States",
|
9
|
+
value: "United States",
|
10
|
+
},
|
11
|
+
{
|
12
|
+
label: "Canada",
|
13
|
+
value: "Canada",
|
14
|
+
},
|
15
|
+
{
|
16
|
+
label: "Pakistan",
|
17
|
+
value: "Pakistan",
|
18
|
+
}
|
19
|
+
];
|
20
|
+
|
21
|
+
|
22
|
+
return (
|
23
|
+
<div>
|
24
|
+
<Dropdown
|
25
|
+
closeOnSelection={false}
|
26
|
+
label="Default"
|
27
|
+
options={options}
|
28
|
+
{...props}
|
29
|
+
/>
|
30
|
+
<br />
|
31
|
+
<Dropdown
|
32
|
+
closeOnSelection={false}
|
33
|
+
label="Multi Select"
|
34
|
+
multiSelect
|
35
|
+
options={options}
|
36
|
+
{...props}
|
37
|
+
/>
|
38
|
+
</div>
|
39
|
+
)
|
40
|
+
}
|
41
|
+
|
42
|
+
export default DropdownCloseOnSelect
|
@@ -0,0 +1 @@
|
|
1
|
+
By default, the dropdown menu will close when a selection is made. You can prevent this behavior by using the `closeOnSelection` prop, which will leave the menu open after a selection is made when set to 'false'.
|
@@ -19,4 +19,5 @@ export { default as DropdownMultiSelect } from './_dropdown_multi_select.jsx'
|
|
19
19
|
export { default as DropdownMultiSelectDisplay } from './_dropdown_multi_select_display.jsx'
|
20
20
|
export { default as DropdownMultiSelectWithAutocomplete } from './_dropdown_multi_select_with_autocomplete.jsx'
|
21
21
|
export { default as DropdownMultiSelectWithDefault } from './_dropdown_multi_select_with_default.jsx'
|
22
|
-
export { default as DropdownMultiSelectWithCustomOptions } from './_dropdown_multi_select_with_custom_options.jsx'
|
22
|
+
export { default as DropdownMultiSelectWithCustomOptions } from './_dropdown_multi_select_with_custom_options.jsx'
|
23
|
+
export { default as DropdownCloseOnSelect } from './_dropdown_close_on_select.jsx'
|
@@ -25,7 +25,7 @@ type DropdownOptionProps = {
|
|
25
25
|
key?: string | number;
|
26
26
|
option?: GenericObject;
|
27
27
|
padding?: string;
|
28
|
-
}
|
28
|
+
} & GlobalProps;
|
29
29
|
|
30
30
|
const DropdownOption = (props: DropdownOptionProps) => {
|
31
31
|
const {
|
@@ -56,16 +56,17 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
56
56
|
|
57
57
|
// When multiSelect, then if an option is selected, remove from dropdown
|
58
58
|
const isSelected = Array.isArray(selected)
|
59
|
-
|
60
|
-
|
59
|
+
? selected.some((item) => item.label === option?.label)
|
60
|
+
: (selected as GenericObject)?.label === option?.label;
|
61
61
|
|
62
|
-
|
63
62
|
if (!isItemMatchingFilter(option) || (multiSelect && isSelected)) {
|
64
63
|
return null;
|
65
64
|
}
|
65
|
+
|
66
66
|
const isFocused =
|
67
67
|
focusedOptionIndex >= 0 &&
|
68
68
|
filteredOptions[focusedOptionIndex].label === option?.label;
|
69
|
+
|
69
70
|
const focusedClass = isFocused && "focused";
|
70
71
|
|
71
72
|
const selectedClass = isSelected ? "selected" : "list";
|
@@ -91,7 +92,10 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
91
92
|
className={classes}
|
92
93
|
id={id}
|
93
94
|
key={key}
|
94
|
-
onClick=
|
95
|
+
onClick={(e) => {
|
96
|
+
e.stopPropagation();
|
97
|
+
handleOptionClick(option);
|
98
|
+
}}
|
95
99
|
>
|
96
100
|
<ListItem
|
97
101
|
cursor="pointer"
|
@@ -100,12 +104,12 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
100
104
|
key={option?.label}
|
101
105
|
padding="none"
|
102
106
|
>
|
103
|
-
|
107
|
+
{children ?
|
104
108
|
<div className="dropdown_option_wrapper">{children}</div> :
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
+
<Body dark={dark}
|
110
|
+
text={option?.label}
|
111
|
+
/>
|
112
|
+
}
|
109
113
|
</ListItem>
|
110
114
|
</div>
|
111
115
|
);
|