@dhis2-ui/transfer 10.13.0 → 10.14.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 (53) hide show
  1. package/build/cjs/__e2e__/reorder-with-buttons.e2e.stories.js +15 -4
  2. package/build/cjs/__tests__/helper/default-filter-callback.test.js +6 -0
  3. package/build/cjs/__tests__/helper/is-reorder-down-disabled.test.js +50 -11
  4. package/build/cjs/__tests__/helper/is-reorder-up-disabled.test.js +50 -11
  5. package/build/cjs/__tests__/helper/move-highlighted-picked-option-down.test.js +65 -11
  6. package/build/cjs/__tests__/helper/move-highlighted-picked-option-to-bottom.test.js +85 -0
  7. package/build/cjs/__tests__/helper/move-highlighted-picked-option-to-top.test.js +85 -0
  8. package/build/cjs/__tests__/helper/move-highlighted-picked-option-up.test.js +65 -11
  9. package/build/cjs/__tests__/reordering-actions.test.js +104 -0
  10. package/build/cjs/features/reorder-with-buttons/index.js +70 -2
  11. package/build/cjs/features/reorder-with-buttons.feature +97 -5
  12. package/build/cjs/icons.js +53 -13
  13. package/build/cjs/locales/en/translations.json +7 -0
  14. package/build/cjs/locales/index.js +21 -0
  15. package/build/cjs/reordering-actions.js +93 -27
  16. package/build/cjs/transfer/default-filter-callback.js +17 -6
  17. package/build/cjs/transfer/get-highlighted-picked-indices.js +34 -0
  18. package/build/cjs/transfer/index.js +33 -0
  19. package/build/cjs/transfer/is-reorder-down-disabled.js +19 -8
  20. package/build/cjs/transfer/is-reorder-up-disabled.js +18 -8
  21. package/build/cjs/transfer/move-highlighted-picked-option-down.js +23 -6
  22. package/build/cjs/transfer/move-highlighted-picked-option-to-bottom.js +45 -0
  23. package/build/cjs/transfer/move-highlighted-picked-option-to-top.js +44 -0
  24. package/build/cjs/transfer/move-highlighted-picked-option-up.js +21 -6
  25. package/build/cjs/transfer.js +58 -6
  26. package/build/cjs/transfer.prod.stories.js +89 -19
  27. package/build/es/__e2e__/reorder-with-buttons.e2e.stories.js +14 -2
  28. package/build/es/__tests__/helper/default-filter-callback.test.js +6 -0
  29. package/build/es/__tests__/helper/is-reorder-down-disabled.test.js +50 -11
  30. package/build/es/__tests__/helper/is-reorder-up-disabled.test.js +50 -11
  31. package/build/es/__tests__/helper/move-highlighted-picked-option-down.test.js +65 -11
  32. package/build/es/__tests__/helper/move-highlighted-picked-option-to-bottom.test.js +83 -0
  33. package/build/es/__tests__/helper/move-highlighted-picked-option-to-top.test.js +83 -0
  34. package/build/es/__tests__/helper/move-highlighted-picked-option-up.test.js +65 -11
  35. package/build/es/__tests__/reordering-actions.test.js +101 -0
  36. package/build/es/features/reorder-with-buttons/index.js +70 -2
  37. package/build/es/features/reorder-with-buttons.feature +97 -5
  38. package/build/es/icons.js +51 -13
  39. package/build/es/locales/en/translations.json +7 -0
  40. package/build/es/locales/index.js +13 -0
  41. package/build/es/reordering-actions.js +94 -28
  42. package/build/es/transfer/default-filter-callback.js +17 -6
  43. package/build/es/transfer/get-highlighted-picked-indices.js +27 -0
  44. package/build/es/transfer/index.js +3 -0
  45. package/build/es/transfer/is-reorder-down-disabled.js +20 -8
  46. package/build/es/transfer/is-reorder-up-disabled.js +19 -8
  47. package/build/es/transfer/move-highlighted-picked-option-down.js +24 -6
  48. package/build/es/transfer/move-highlighted-picked-option-to-bottom.js +39 -0
  49. package/build/es/transfer/move-highlighted-picked-option-to-top.js +38 -0
  50. package/build/es/transfer/move-highlighted-picked-option-up.js +22 -6
  51. package/build/es/transfer.js +60 -8
  52. package/build/es/transfer.prod.stories.js +88 -18
  53. package/package.json +9 -7
@@ -3,7 +3,7 @@ Given('reordering of items is enabled', () => {
3
3
  // no op
4
4
  });
5
5
  Given('the selected list has three items', () => {
6
- cy.visitStory('Transfer Reorder Buttons', 'Has Some Selected');
6
+ cy.visitStory('Transfer Reorder Buttons', 'Has Three Selected');
7
7
  });
8
8
  Given('the selected list has some items', () => {
9
9
  cy.visitStory('Transfer Reorder Buttons', 'Has Some Selected');
@@ -34,11 +34,79 @@ When("the user clicks the 'move down' button", () => {
34
34
  force: true
35
35
  });
36
36
  });
37
+ When("the user clicks the 'move to top' button", () => {
38
+ // force, so we click disabled buttons
39
+ cy.get('{transfer-reorderingactions-buttonmovetotop}').click({
40
+ force: true
41
+ });
42
+ });
43
+ When("the user clicks the 'move to bottom' button", () => {
44
+ // force, so we click disabled buttons
45
+ cy.get('{transfer-reorderingactions-buttonmovetobottom}').click({
46
+ force: true
47
+ });
48
+ });
37
49
  Then('the highlighted item should be moved to the {int}. place', next => {
38
50
  const index = next - 1;
39
51
  cy.get('@previousValue').then(previousValue => cy.get(`[data-value="${previousValue}"]`)).invoke('index').should('equal', index);
40
52
  });
41
- Then("the 'move up' and 'move down' buttons should be disabled", () => {
53
+ Then('all four reorder buttons should be disabled', () => {
54
+ cy.get('{transfer-reorderingactions-buttonmovetotop}').should('have.attr', 'disabled');
42
55
  cy.get('{transfer-reorderingactions-buttonmoveup}').should('have.attr', 'disabled');
43
56
  cy.get('{transfer-reorderingactions-buttonmovedown}').should('have.attr', 'disabled');
57
+ cy.get('{transfer-reorderingactions-buttonmovetobottom}').should('have.attr', 'disabled');
58
+ });
59
+
60
+ // --- Multi-select ---
61
+
62
+ Given('the selected list has eight items', () => {
63
+ cy.visitStory('Transfer Reorder Buttons', 'Has Some Selected');
64
+ cy.get('{transfer-pickedoptions} {transferoption}').should('have.length', 8);
65
+ });
66
+ const highlightPositionWithCtrl = position => cy.get('{transfer-pickedoptions} {transferoption}').eq(position - 1).then($option => cy.get('@highlightedValues').then(values => {
67
+ values.push($option.attr('data-value'));
68
+ return $option;
69
+ })).clickWith('ctrl');
70
+ When('the user highlights the items at positions {int} and {int}', (first, second) => {
71
+ cy.wrap([]).as('highlightedValues');
72
+ highlightPositionWithCtrl(first);
73
+ highlightPositionWithCtrl(second);
74
+ });
75
+ When('the user highlights every item in the selected list', () => {
76
+ cy.wrap([]).as('highlightedValues');
77
+ cy.get('{transfer-pickedoptions} {transferoption}').each($option => {
78
+ cy.get('@highlightedValues').then(values => {
79
+ values.push($option.attr('data-value'));
80
+ });
81
+ cy.wrap($option).clickWith('ctrl');
82
+ });
83
+ });
84
+ Then('those items should be at positions {int} and {int}', (first, second) => {
85
+ cy.get('@highlightedValues').then(values => {
86
+ const targetIndices = [first - 1, second - 1];
87
+ values.forEach((value, i) => {
88
+ cy.get(`[data-value="${value}"]`).invoke('index').should('equal', targetIndices[i]);
89
+ });
90
+ });
91
+ });
92
+ Then('those items should still be highlighted', () => {
93
+ cy.get('@highlightedValues').then(values => {
94
+ values.forEach(value => {
95
+ cy.get(`{transfer-pickedoptions} [data-value="${value}"]`).should('have.class', 'highlighted');
96
+ });
97
+ });
98
+ });
99
+ const reorderButtonSelectors = {
100
+ 'move up': '{transfer-reorderingactions-buttonmoveup}',
101
+ 'move down': '{transfer-reorderingactions-buttonmovedown}',
102
+ 'move to top': '{transfer-reorderingactions-buttonmovetotop}',
103
+ 'move to bottom': '{transfer-reorderingactions-buttonmovetobottom}'
104
+ };
105
+ Then('the {string} and {string} buttons should be disabled', (first, second) => {
106
+ cy.get(reorderButtonSelectors[first]).should('have.attr', 'disabled');
107
+ cy.get(reorderButtonSelectors[second]).should('have.attr', 'disabled');
108
+ });
109
+ Then('the {string} and {string} buttons should not be disabled', (first, second) => {
110
+ cy.get(reorderButtonSelectors[first]).should('not.have.attr', 'disabled');
111
+ cy.get(reorderButtonSelectors[second]).should('not.have.attr', 'disabled');
44
112
  });
@@ -35,12 +35,104 @@ Feature: Reorder items in the selected list using buttons
35
35
  | 2 | 3 |
36
36
  | 3 | 3 |
37
37
 
38
+ Scenario Outline: The user clicks the 'move to top' button with a highlighted item in the selected list
39
+ Given the selected list has three items
40
+ And the <previous>. item is highlighted
41
+ When the user clicks the 'move to top' button
42
+ Then the highlighted item should be moved to the <next>. place
43
+
44
+ Examples:
45
+ | previous | next |
46
+ | 1 | 1 |
47
+ | 2 | 1 |
48
+ | 3 | 1 |
49
+
50
+ Scenario Outline: The user clicks the 'move to bottom' button with a highlighted item in the selected list
51
+ Given the selected list has three items
52
+ And the <previous>. item is highlighted
53
+ When the user clicks the 'move to bottom' button
54
+ Then the highlighted item should be moved to the <next>. place
55
+
56
+ Examples:
57
+ | previous | next |
58
+ | 1 | 3 |
59
+ | 2 | 3 |
60
+ | 3 | 3 |
61
+
38
62
  Scenario: Disable reorder buttons when no items are highlighted
39
63
  Given the selected list has some items
40
64
  And no items are highlighted in the list
41
- Then the 'move up' and 'move down' buttons should be disabled
65
+ Then all four reorder buttons should be disabled
42
66
 
43
- Scenario: Disabled reorder buttons when multiple selected items are highlighted
44
- Given the selected list has some items
45
- And more than one item is highlighted in the list
46
- Then the 'move up' and 'move down' buttons should be disabled
67
+ # --- Multi-select ---
68
+ #
69
+ # All four buttons act on the highlighted picked items as a group,
70
+ # preserving the group's relative order. Non-contiguous selections
71
+ # collapse into a contiguous block before landing at the target edge.
72
+
73
+ Scenario: 'move up' shifts a contiguous block of highlighted items up by one slot
74
+ Given the selected list has eight items
75
+ When the user highlights the items at positions 3 and 4
76
+ And the user clicks the 'move up' button
77
+ Then those items should be at positions 2 and 3
78
+ And those items should still be highlighted
79
+
80
+ Scenario: 'move up' collapses and shifts a non-contiguous selection in one press
81
+ Given the selected list has eight items
82
+ When the user highlights the items at positions 2 and 4
83
+ And the user clicks the 'move up' button
84
+ Then those items should be at positions 1 and 2
85
+
86
+ Scenario: 'move down' shifts a contiguous block of highlighted items down by one slot
87
+ Given the selected list has eight items
88
+ When the user highlights the items at positions 2 and 3
89
+ And the user clicks the 'move down' button
90
+ Then those items should be at positions 3 and 4
91
+
92
+ Scenario: 'move down' collapses and shifts a non-contiguous selection in one press
93
+ Given the selected list has eight items
94
+ When the user highlights the items at positions 2 and 4
95
+ And the user clicks the 'move down' button
96
+ Then those items should be at positions 4 and 5
97
+
98
+ Scenario: 'move to top' collapses a non-contiguous selection flush to the top
99
+ Given the selected list has eight items
100
+ When the user highlights the items at positions 3 and 5
101
+ And the user clicks the 'move to top' button
102
+ Then those items should be at positions 1 and 2
103
+
104
+ Scenario: 'move to bottom' collapses a non-contiguous selection flush to the bottom
105
+ Given the selected list has eight items
106
+ When the user highlights the items at positions 2 and 4
107
+ And the user clicks the 'move to bottom' button
108
+ Then those items should be at positions 7 and 8
109
+
110
+ Scenario: The highlighted group stays highlighted after moving, allowing chained presses
111
+ Given the selected list has eight items
112
+ When the user highlights the items at positions 3 and 4
113
+ And the user clicks the 'move up' button
114
+ And the user clicks the 'move up' button
115
+ Then those items should be at positions 1 and 2
116
+ And those items should still be highlighted
117
+
118
+ Scenario: Both up-side buttons are disabled when the highlighted block is flush to the top
119
+ Given the selected list has eight items
120
+ When the user highlights the items at positions 1 and 2
121
+ Then the 'move up' and 'move to top' buttons should be disabled
122
+ And the 'move down' and 'move to bottom' buttons should not be disabled
123
+
124
+ Scenario: Both down-side buttons are disabled when the highlighted block is flush to the bottom
125
+ Given the selected list has eight items
126
+ When the user highlights the items at positions 7 and 8
127
+ Then the 'move down' and 'move to bottom' buttons should be disabled
128
+ And the 'move up' and 'move to top' buttons should not be disabled
129
+
130
+ Scenario: Up-side buttons remain enabled when a non-contiguous selection contains the top item
131
+ Given the selected list has eight items
132
+ When the user highlights the items at positions 1 and 3
133
+ Then the 'move up' and 'move to top' buttons should not be disabled
134
+
135
+ Scenario: All four reorder buttons are disabled when every picked item is highlighted
136
+ Given the selected list has eight items
137
+ When the user highlights every item in the selected list
138
+ Then all four reorder buttons should be disabled
package/build/es/icons.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import _JSXStyle from "styled-jsx/style";
2
- import { theme } from '@dhis2/ui-constants';
2
+ import { colors, theme } from '@dhis2/ui-constants';
3
3
  import PropTypes from 'prop-types';
4
4
  import React from 'react';
5
5
  const centerButtonStyles = ["svg.jsx-2392683210{min-width:20px;}", "div.centerButton.jsx-2392683210:dir(rtl){-webkit-transform:rotate(180deg) translateX(4px);-ms-transform:rotate(180deg) translateX(4px);transform:rotate(180deg) translateX(4px);}"];
@@ -17,7 +17,7 @@ export const IconAddAll = _ref => {
17
17
  height: "16",
18
18
  viewBox: "0 0 16 16",
19
19
  "data-test": dataTest,
20
- fill: disabled ? theme.disabled : '#404B5A',
20
+ fill: disabled ? theme.disabled : colors.grey800,
21
21
  className: `jsx-${centerButtonStyles.__hash}`
22
22
  }, /*#__PURE__*/React.createElement("g", {
23
23
  fillRule: "evenodd",
@@ -46,7 +46,7 @@ export const IconAddIndividual = _ref2 => {
46
46
  return /*#__PURE__*/React.createElement("div", {
47
47
  className: `jsx-${centerButtonStyles.__hash}` + " " + "centerButton"
48
48
  }, /*#__PURE__*/React.createElement("svg", {
49
- fill: disabled ? theme.disabled : '#404B5A',
49
+ fill: disabled ? theme.disabled : colors.grey800,
50
50
  xmlns: "http://www.w3.org/2000/svg",
51
51
  width: "16",
52
52
  height: "16",
@@ -72,7 +72,7 @@ export const IconRemoveAll = _ref3 => {
72
72
  return /*#__PURE__*/React.createElement("div", {
73
73
  className: `jsx-${centerButtonStyles.__hash}` + " " + "centerButton"
74
74
  }, /*#__PURE__*/React.createElement("svg", {
75
- fill: disabled ? theme.disabled : '#404B5A',
75
+ fill: disabled ? theme.disabled : colors.grey800,
76
76
  width: "16px",
77
77
  height: "16px",
78
78
  viewBox: "0 0 16 16",
@@ -108,7 +108,7 @@ export const IconRemoveIndividual = _ref4 => {
108
108
  return /*#__PURE__*/React.createElement("div", {
109
109
  className: `jsx-${centerButtonStyles.__hash}` + " " + "centerButton"
110
110
  }, /*#__PURE__*/React.createElement("svg", {
111
- fill: disabled ? theme.disabled : '#404B5A',
111
+ fill: disabled ? theme.disabled : colors.grey800,
112
112
  xmlns: "http://www.w3.org/2000/svg",
113
113
  width: "16",
114
114
  height: "16",
@@ -133,15 +133,14 @@ export const IconMoveDown = _ref5 => {
133
133
  disabled
134
134
  } = _ref5;
135
135
  return /*#__PURE__*/React.createElement("svg", {
136
- fill: disabled ? theme.disabled : '#404B5A',
136
+ fill: disabled ? colors.grey500 : colors.grey800,
137
137
  xmlns: "http://www.w3.org/2000/svg",
138
138
  width: "16",
139
139
  height: "16",
140
140
  viewBox: "0 0 16 16",
141
141
  "data-test": dataTest
142
- }, /*#__PURE__*/React.createElement("polygon", {
143
- points: "8 2 6.94 3.06 11.13 7.25 2 7.25 2 8.75 11.13 8.75 6.94 12.94 8 14 14 8",
144
- transform: "matrix(0 1 1 0 0 0)"
142
+ }, /*#__PURE__*/React.createElement("path", {
143
+ d: "M13.5303 8.53027L12.4697 7.46973L8.75 11.1895V2H7.25V11.1895L3.53027 7.46973L2.46973 8.53027L8 14.0605L13.5303 8.53027Z"
145
144
  }));
146
145
  };
147
146
  IconMoveDown.propTypes = {
@@ -154,18 +153,57 @@ export const IconMoveUp = _ref6 => {
154
153
  disabled
155
154
  } = _ref6;
156
155
  return /*#__PURE__*/React.createElement("svg", {
157
- fill: disabled ? theme.disabled : '#404B5A',
156
+ fill: disabled ? colors.grey500 : colors.grey800,
158
157
  xmlns: "http://www.w3.org/2000/svg",
159
158
  width: "16",
160
159
  height: "16",
161
160
  viewBox: "0 0 16 16",
162
161
  "data-test": dataTest
163
- }, /*#__PURE__*/React.createElement("polygon", {
164
- points: "8 2 6.94 3.06 11.13 7.25 2 7.25 2 8.75 11.13 8.75 6.94 12.94 8 14 14 8",
165
- transform: "rotate(-90 8 8)"
162
+ }, /*#__PURE__*/React.createElement("path", {
163
+ d: "M13.5303 7.46973L12.4697 8.53027L8.75 4.81055V14H7.25V4.81055L3.53027 8.53027L2.46973 7.46973L8 1.93945L13.5303 7.46973Z"
166
164
  }));
167
165
  };
168
166
  IconMoveUp.propTypes = {
169
167
  dataTest: PropTypes.string.isRequired,
170
168
  disabled: PropTypes.bool
169
+ };
170
+ export const IconMoveToTop = _ref7 => {
171
+ let {
172
+ dataTest,
173
+ disabled
174
+ } = _ref7;
175
+ return /*#__PURE__*/React.createElement("svg", {
176
+ fill: disabled ? colors.grey500 : colors.grey800,
177
+ xmlns: "http://www.w3.org/2000/svg",
178
+ width: "16",
179
+ height: "16",
180
+ viewBox: "0 0 16 16",
181
+ "data-test": dataTest
182
+ }, /*#__PURE__*/React.createElement("path", {
183
+ d: "M13.5303 10.4697L12.4697 11.5303L8.75 7.81055V14H7.25V7.81055L3.53027 11.5303L2.46973 10.4697L8 4.93945L13.5303 10.4697ZM13.5303 6.46973L12.4697 7.53027L8 3.06055L3.53027 7.53027L2.46973 6.46973L8 0.939453L13.5303 6.46973Z"
184
+ }));
185
+ };
186
+ IconMoveToTop.propTypes = {
187
+ dataTest: PropTypes.string.isRequired,
188
+ disabled: PropTypes.bool
189
+ };
190
+ export const IconMoveToBottom = _ref8 => {
191
+ let {
192
+ dataTest,
193
+ disabled
194
+ } = _ref8;
195
+ return /*#__PURE__*/React.createElement("svg", {
196
+ fill: disabled ? colors.grey500 : colors.grey800,
197
+ xmlns: "http://www.w3.org/2000/svg",
198
+ width: "16",
199
+ height: "16",
200
+ viewBox: "0 0 16 16",
201
+ "data-test": dataTest
202
+ }, /*#__PURE__*/React.createElement("path", {
203
+ d: "M13.5303 5.53027L12.4697 4.46973L8.75 8.18945V2H7.25V8.18945L3.53027 4.46973L2.46973 5.53027L8 11.0605L13.5303 5.53027ZM13.5303 9.53027L12.4697 8.46973L8 12.9395L3.53027 8.46973L2.46973 9.53027L8 15.0605L13.5303 9.53027Z"
204
+ }));
205
+ };
206
+ IconMoveToBottom.propTypes = {
207
+ dataTest: PropTypes.string.isRequired,
208
+ disabled: PropTypes.bool
171
209
  };
@@ -0,0 +1,7 @@
1
+ {
2
+ "Reordering not allowed when filtering list": "Reordering not allowed when filtering list",
3
+ "Move selected items to top": "Move selected items to top",
4
+ "Move selected items up": "Move selected items up",
5
+ "Move selected items down": "Move selected items down",
6
+ "Move selected items to bottom": "Move selected items to bottom"
7
+ }
@@ -0,0 +1,13 @@
1
+ //------------------------------------------------------------------------------
2
+ // <auto-generated>
3
+ // This code was generated by d2-i18n-generate.
4
+ //
5
+ // Changes to this file may cause incorrect behavior and will be lost if
6
+ // the code is regenerated.
7
+ // </auto-generated>
8
+ //------------------------------------------------------------------------------
9
+ import i18n from '@dhis2/d2-i18n';
10
+ import enTranslations from './en/translations.json';
11
+ const namespace = 'default';
12
+ i18n.addResources('en', namespace, enTranslations);
13
+ export default i18n;
@@ -1,47 +1,113 @@
1
1
  import _JSXStyle from "styled-jsx/style";
2
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
3
  import { spacers } from '@dhis2/ui-constants';
3
4
  import { Button } from '@dhis2-ui/button';
5
+ import { Tooltip } from '@dhis2-ui/tooltip';
4
6
  import PropTypes from 'prop-types';
5
7
  import React from 'react';
6
- import { IconMoveDown, IconMoveUp } from './icons.js';
8
+ import { IconMoveDown, IconMoveToBottom, IconMoveToTop, IconMoveUp } from './icons.js';
9
+ import i18n from './locales/index.js';
10
+ const filterActiveTooltip = i18n.t('Reordering not allowed when filtering list');
7
11
  export const ReorderingActions = _ref => {
8
12
  let {
9
13
  dataTest,
10
14
  disabledDown,
11
15
  disabledUp,
16
+ filterActive,
12
17
  onChangeUp,
13
- onChangeDown
18
+ onChangeDown,
19
+ onChangeToTop,
20
+ onChangeToBottom
14
21
  } = _ref;
15
- return /*#__PURE__*/React.createElement("div", {
16
- "data-test": dataTest,
17
- className: _JSXStyle.dynamic([["874845231", [spacers.dp8, spacers.dp8, spacers.dp8]]])
18
- }, /*#__PURE__*/React.createElement(Button, {
19
- small: true,
20
- disabled: disabledDown,
21
- onClick: () => !disabledDown && onChangeDown(event),
22
- dataTest: `${dataTest}-buttonmovedown`,
23
- icon: /*#__PURE__*/React.createElement(IconMoveDown, {
24
- dataTest: `${dataTest}-iconmovedown`,
25
- disabled: disabledDown
26
- })
27
- }), /*#__PURE__*/React.createElement(Button, {
28
- small: true,
29
- disabled: disabledUp,
30
- onClick: () => !disabledUp && onChangeUp(event),
31
- dataTest: `${dataTest}-buttonmoveup`,
32
- icon: /*#__PURE__*/React.createElement(IconMoveUp, {
33
- dataTest: `${dataTest}-iconmoveup`,
34
- disabled: disabledUp
35
- })
36
- }), /*#__PURE__*/React.createElement(_JSXStyle, {
37
- id: "874845231",
38
- dynamic: [spacers.dp8, spacers.dp8, spacers.dp8]
39
- }, [`div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;padding-top:${spacers.dp8};}`, `div.__jsx-style-dynamic-selector:last-child{padding-bottom:${spacers.dp8};}`, `div.__jsx-style-dynamic-selector>button:first-child{margin-inline-start:${spacers.dp8};}`]));
22
+ const moveToTopLabel = i18n.t('Move selected items to top');
23
+ const moveUpLabel = i18n.t('Move selected items up');
24
+ const moveDownLabel = i18n.t('Move selected items down');
25
+ const moveToBottomLabel = i18n.t('Move selected items to bottom');
26
+ const renderButtons = function () {
27
+ let tooltipHandlers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
28
+ return /*#__PURE__*/React.createElement("div", _extends({
29
+ "data-test": dataTest
30
+ }, tooltipHandlers, {
31
+ className: _JSXStyle.dynamic([["3663884558", [spacers.dp4, spacers.dp8, spacers.dp8]]]) + " " + (tooltipHandlers && tooltipHandlers.className != null && tooltipHandlers.className || "")
32
+ }), /*#__PURE__*/React.createElement(Button, {
33
+ small: true,
34
+ secondary: true,
35
+ disabled: disabledUp,
36
+ onClick: () => !disabledUp && onChangeToTop(),
37
+ dataTest: `${dataTest}-buttonmovetotop`,
38
+ "aria-label": moveToTopLabel,
39
+ icon: /*#__PURE__*/React.createElement(IconMoveToTop, {
40
+ dataTest: `${dataTest}-iconmovetotop`,
41
+ disabled: disabledUp
42
+ })
43
+ }), /*#__PURE__*/React.createElement(Button, {
44
+ small: true,
45
+ secondary: true,
46
+ disabled: disabledUp,
47
+ onClick: () => !disabledUp && onChangeUp(),
48
+ dataTest: `${dataTest}-buttonmoveup`,
49
+ "aria-label": moveUpLabel,
50
+ icon: /*#__PURE__*/React.createElement(IconMoveUp, {
51
+ dataTest: `${dataTest}-iconmoveup`,
52
+ disabled: disabledUp
53
+ })
54
+ }), /*#__PURE__*/React.createElement(Button, {
55
+ small: true,
56
+ secondary: true,
57
+ disabled: disabledDown,
58
+ onClick: () => !disabledDown && onChangeDown(),
59
+ dataTest: `${dataTest}-buttonmovedown`,
60
+ "aria-label": moveDownLabel,
61
+ icon: /*#__PURE__*/React.createElement(IconMoveDown, {
62
+ dataTest: `${dataTest}-iconmovedown`,
63
+ disabled: disabledDown
64
+ })
65
+ }), /*#__PURE__*/React.createElement(Button, {
66
+ small: true,
67
+ secondary: true,
68
+ disabled: disabledDown,
69
+ onClick: () => !disabledDown && onChangeToBottom(),
70
+ dataTest: `${dataTest}-buttonmovetobottom`,
71
+ "aria-label": moveToBottomLabel,
72
+ icon: /*#__PURE__*/React.createElement(IconMoveToBottom, {
73
+ dataTest: `${dataTest}-iconmovetobottom`,
74
+ disabled: disabledDown
75
+ })
76
+ }), /*#__PURE__*/React.createElement(_JSXStyle, {
77
+ id: "3663884558",
78
+ dynamic: [spacers.dp4, spacers.dp8, spacers.dp8]
79
+ }, [`div.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end;margin-inline-start:auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;gap:${spacers.dp4};padding-top:${spacers.dp8};}`, `div.__jsx-style-dynamic-selector:last-child{padding-bottom:${spacers.dp8};}`]));
80
+ };
81
+ if (filterActive) {
82
+ return /*#__PURE__*/React.createElement(Tooltip, {
83
+ openDelay: 500,
84
+ content: filterActiveTooltip
85
+ }, _ref2 => {
86
+ let {
87
+ onMouseOver,
88
+ onMouseOut,
89
+ onFocus,
90
+ onBlur,
91
+ ref
92
+ } = _ref2;
93
+ return renderButtons({
94
+ ref,
95
+ onMouseOver,
96
+ onMouseOut,
97
+ onFocus,
98
+ onBlur
99
+ });
100
+ });
101
+ }
102
+ return renderButtons();
40
103
  };
41
104
  ReorderingActions.propTypes = {
42
105
  dataTest: PropTypes.string.isRequired,
43
106
  onChangeDown: PropTypes.func.isRequired,
107
+ onChangeToBottom: PropTypes.func.isRequired,
108
+ onChangeToTop: PropTypes.func.isRequired,
44
109
  onChangeUp: PropTypes.func.isRequired,
45
110
  disabledDown: PropTypes.bool,
46
- disabledUp: PropTypes.bool
111
+ disabledUp: PropTypes.bool,
112
+ filterActive: PropTypes.bool
47
113
  };
@@ -3,9 +3,20 @@
3
3
  * @param {string} filter
4
4
  * @returns {Object[]}
5
5
  */
6
- export const defaultFilterCallback = (options, filter) => filter === '' ? options : options.filter(_ref => {
7
- let {
8
- label
9
- } = _ref;
10
- return label.match(new RegExp(filter, 'i'));
11
- });
6
+ export const defaultFilterCallback = (options, filter) => {
7
+ if (filter === '') {
8
+ return options;
9
+ }
10
+ try {
11
+ const regex = new RegExp(filter, 'i');
12
+ return options.filter(_ref => {
13
+ let {
14
+ label
15
+ } = _ref;
16
+ return label.match(regex);
17
+ });
18
+ } catch {
19
+ console.warn('Invalid regex filter:', filter);
20
+ return options;
21
+ }
22
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Returns the indices, in ascending order, of `highlightedPickedOptions`
3
+ * within `selected`. Values in `highlightedPickedOptions` that don't appear
4
+ * in `selected` are ignored, so callers can pass a potentially stale
5
+ * highlight list without filtering first.
6
+ *
7
+ * Runs in O(n) over `selected` via a Set lookup.
8
+ *
9
+ * @param {Object} args
10
+ * @param {string[]} args.selected
11
+ * @param {string[]} args.highlightedPickedOptions
12
+ * @returns {number[]}
13
+ */
14
+ export const getHighlightedPickedIndices = _ref => {
15
+ let {
16
+ selected,
17
+ highlightedPickedOptions
18
+ } = _ref;
19
+ const highlightedSet = new Set(highlightedPickedOptions);
20
+ const indices = [];
21
+ selected.forEach((value, index) => {
22
+ if (highlightedSet.has(value)) {
23
+ indices.push(index);
24
+ }
25
+ });
26
+ return indices;
27
+ };
@@ -2,10 +2,13 @@ export * from './add-all-selectable-source-options.js';
2
2
  export * from './add-individual-source-options.js';
3
3
  export * from './create-double-click-handlers.js';
4
4
  export * from './default-filter-callback.js';
5
+ export * from './get-highlighted-picked-indices.js';
5
6
  export * from './get-option-click-handlers.js';
6
7
  export * from './is-reorder-down-disabled.js';
7
8
  export * from './is-reorder-up-disabled.js';
8
9
  export * from './move-highlighted-picked-option-down.js';
10
+ export * from './move-highlighted-picked-option-to-bottom.js';
11
+ export * from './move-highlighted-picked-option-to-top.js';
9
12
  export * from './move-highlighted-picked-option-up.js';
10
13
  export * from './remove-all-picked-options.js';
11
14
  export * from './remove-individual-picked-options.js';
@@ -1,18 +1,30 @@
1
+ import { getHighlightedPickedIndices } from './get-highlighted-picked-indices.js';
2
+
1
3
  /**
2
4
  * @param {Object} args
3
- * @param {string} args.highlightedPickedOptions
5
+ * @param {string[]} args.highlightedPickedOptions
4
6
  * @param {string[]} args.selected
7
+ * @param {boolean} [args.filterActivePicked] reorder is disabled while a filter is applied to the picked side
5
8
  * @returns {bool}
6
9
  */
7
10
  export const isReorderDownDisabled = _ref => {
8
11
  let {
9
12
  highlightedPickedOptions,
10
- selected
13
+ selected,
14
+ filterActivePicked = false
11
15
  } = _ref;
12
- return (
13
- // only one item can be moved with the buttons
14
- highlightedPickedOptions.length !== 1 ||
15
- // can't move an item down if it's the last one
16
- selected.indexOf(highlightedPickedOptions[0]) === selected.length - 1
17
- );
16
+ if (filterActivePicked) {
17
+ return true;
18
+ }
19
+ const indices = getHighlightedPickedIndices({
20
+ selected,
21
+ highlightedPickedOptions
22
+ });
23
+ if (indices.length === 0) {
24
+ return true;
25
+ }
26
+ const lastIndex = selected.length - 1;
27
+
28
+ // Flush to the bottom: indices are [len-n, ..., len-1]
29
+ return indices.every((index, i) => index === lastIndex - (indices.length - 1 - i));
18
30
  };
@@ -1,18 +1,29 @@
1
+ import { getHighlightedPickedIndices } from './get-highlighted-picked-indices.js';
2
+
1
3
  /**
2
4
  * @param {Object} args
3
- * @param {string} args.highlightedPickedOptions
5
+ * @param {string[]} args.highlightedPickedOptions
4
6
  * @param {string[]} args.selected
7
+ * @param {boolean} [args.filterActivePicked] reorder is disabled while a filter is applied to the picked side
5
8
  * @returns {bool}
6
9
  */
7
10
  export const isReorderUpDisabled = _ref => {
8
11
  let {
9
12
  highlightedPickedOptions,
10
- selected
13
+ selected,
14
+ filterActivePicked = false
11
15
  } = _ref;
12
- return (
13
- // only one item can be moved with the buttons
14
- highlightedPickedOptions.length !== 1 ||
15
- // can't move an item up if it's the first one
16
- selected.indexOf(highlightedPickedOptions[0]) === 0
17
- );
16
+ if (filterActivePicked) {
17
+ return true;
18
+ }
19
+ const indices = getHighlightedPickedIndices({
20
+ selected,
21
+ highlightedPickedOptions
22
+ });
23
+ if (indices.length === 0) {
24
+ return true;
25
+ }
26
+
27
+ // Flush to the top: indices are [0, 1, ..., n-1]
28
+ return indices.every((index, i) => index === i);
18
29
  };