@sipesistemas/polaris 1.3.0 → 1.4.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 (51) hide show
  1. package/build/cjs/components/{SearchableSelect/SearchableSelect.css.js → DropDown/DropDown.css.js} +1 -1
  2. package/build/cjs/components/{SearchableSelect/SearchableSelect.js → DropDown/DropDown.js} +122 -72
  3. package/build/cjs/components/DropDown/DropDownField.js +33 -0
  4. package/build/cjs/components/IndexTable/IndexTable.css.js +8 -1
  5. package/build/cjs/components/IndexTable/IndexTable.js +59 -11
  6. package/build/cjs/components/IndexTable/components/Row/Row.js +69 -6
  7. package/build/cjs/index.js +2 -2
  8. package/build/cjs/utilities/index-table/context.js +2 -0
  9. package/build/esm/components/DropDown/DropDown.css.js +5 -0
  10. package/build/esm/components/{SearchableSelect/SearchableSelect.js → DropDown/DropDown.js} +121 -72
  11. package/build/esm/components/DropDown/DropDownField.js +31 -0
  12. package/build/esm/components/IndexTable/IndexTable.css.js +8 -1
  13. package/build/esm/components/IndexTable/IndexTable.js +60 -12
  14. package/build/esm/components/IndexTable/components/Row/Row.js +68 -5
  15. package/build/esm/index.js +1 -1
  16. package/build/esm/styles.css +61 -14
  17. package/build/esm/utilities/index-table/context.js +2 -1
  18. package/build/esnext/components/AppProvider/global.out.css +1 -1
  19. package/build/esnext/components/DropDown/DropDown.css.esnext +7 -0
  20. package/build/esnext/components/{SearchableSelect/SearchableSelect.esnext → DropDown/DropDown.esnext} +124 -75
  21. package/build/esnext/components/DropDown/DropDown.out.css +16 -0
  22. package/build/esnext/components/DropDown/DropDownField.esnext +31 -0
  23. package/build/esnext/components/IndexTable/IndexTable.css.esnext +8 -1
  24. package/build/esnext/components/IndexTable/IndexTable.esnext +60 -12
  25. package/build/esnext/components/IndexTable/IndexTable.out.css +42 -0
  26. package/build/esnext/components/IndexTable/components/Row/Row.esnext +68 -5
  27. package/build/esnext/index.esnext +1 -1
  28. package/build/esnext/utilities/index-table/context.esnext +2 -1
  29. package/build/ts/src/components/DropDown/DropDown.d.ts +101 -0
  30. package/build/ts/src/components/DropDown/DropDown.d.ts.map +1 -0
  31. package/build/ts/src/components/DropDown/DropDownField.d.ts +8 -0
  32. package/build/ts/src/components/DropDown/DropDownField.d.ts.map +1 -0
  33. package/build/ts/src/components/DropDown/index.d.ts +2 -0
  34. package/build/ts/src/components/DropDown/index.d.ts.map +1 -0
  35. package/build/ts/src/components/IndexTable/IndexTable.d.ts +7 -0
  36. package/build/ts/src/components/IndexTable/IndexTable.d.ts.map +1 -1
  37. package/build/ts/src/components/IndexTable/components/Row/Row.d.ts.map +1 -1
  38. package/build/ts/src/index.d.ts +2 -2
  39. package/build/ts/src/index.d.ts.map +1 -1
  40. package/build/ts/src/utilities/index-table/context.d.ts +10 -0
  41. package/build/ts/src/utilities/index-table/context.d.ts.map +1 -1
  42. package/locales/en.json +4 -2
  43. package/locales/pt-BR.json +4 -2
  44. package/package.json +9 -2
  45. package/build/esm/components/SearchableSelect/SearchableSelect.css.js +0 -5
  46. package/build/esnext/components/SearchableSelect/SearchableSelect.css.esnext +0 -7
  47. package/build/esnext/components/SearchableSelect/SearchableSelect.out.css +0 -11
  48. package/build/ts/src/components/SearchableSelect/SearchableSelect.d.ts +0 -60
  49. package/build/ts/src/components/SearchableSelect/SearchableSelect.d.ts.map +0 -1
  50. package/build/ts/src/components/SearchableSelect/index.d.ts +0 -2
  51. package/build/ts/src/components/SearchableSelect/index.d.ts.map +0 -1
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var styles = {
6
- "Activator": "Polaris-SearchableSelect__Activator"
6
+ "Activator": "Polaris-DropDown__Activator"
7
7
  };
8
8
 
9
9
  exports.default = styles;
@@ -2,13 +2,14 @@
2
2
 
3
3
  var polarisIcons = require('@shopify/polaris-icons');
4
4
  var react = require('react');
5
- var SearchableSelect_module = require('./SearchableSelect.css.js');
5
+ var DropDown_module = require('./DropDown.css.js');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var EmptySearchResult = require('../EmptySearchResult/EmptySearchResult.js');
7
8
  var hooks = require('../../utilities/i18n/hooks.js');
8
9
  var TextField = require('../TextField/TextField.js');
9
10
  var Icon = require('../Icon/Icon.js');
11
+ var utils = require('../Button/utils.js');
10
12
  var Listbox = require('../Listbox/Listbox.js');
11
- var EmptySearchResult = require('../EmptySearchResult/EmptySearchResult.js');
12
13
  var Popover = require('../Popover/Popover.js');
13
14
  var Box = require('../Box/Box.js');
14
15
  var Scrollable = require('../Scrollable/Scrollable.js');
@@ -16,26 +17,39 @@ var Scrollable = require('../Scrollable/Scrollable.js');
16
17
  function getValueByPath(obj, path) {
17
18
  return path.split('.').reduce((acc, part) => acc?.[part], obj);
18
19
  }
20
+
21
+ /** Resolves the activator text for an option, falling back to its `label` when there is no `object` */
22
+ function resolveOptionLabel(option, selectedLabelKey) {
23
+ if (!option) return '';
24
+ if (selectedLabelKey && option.object !== undefined) {
25
+ const value = getValueByPath(option.object, selectedLabelKey);
26
+ if (typeof value === 'string') return value;
27
+ }
28
+ return typeof option.label === 'string' ? option.label : '';
29
+ }
19
30
  const SCROLLABLE_HEIGHT = 292;
20
- function SearchableSelect({
31
+ function DropDownBase({
21
32
  loading,
22
33
  loadingMore,
23
34
  options,
24
- selected,
25
- onSelect,
35
+ value,
36
+ onChange,
37
+ onBlur,
26
38
  emptyStateTitle = '',
27
39
  emptyStateDescription,
28
40
  onQueryChange,
29
41
  selectedLabelKey,
30
42
  label,
43
+ labelHidden,
44
+ searchable = true,
31
45
  placeholder,
32
46
  disabled,
33
47
  requiredIndicator,
34
48
  helpText,
35
49
  error,
36
- pinSelected = true,
37
50
  allowClear,
38
- onScrolledToBottom
51
+ onScrolledToBottom,
52
+ suffixAction
39
53
  }) {
40
54
  const i18n = hooks.useI18n();
41
55
  const [query, setQuery] = react.useState('');
@@ -46,10 +60,18 @@ function SearchableSelect({
46
60
  // clicking the clear button bubbles to TextField's container, which focuses the input
47
61
  const skipNextFocusOpen = react.useRef(false);
48
62
  const listboxId = react.useId();
63
+ const selectedValue = value ?? '';
64
+ const selected = selectedValue ? [selectedValue] : [];
65
+ // when the parent does not control filtering, narrow the options by the query ourselves
66
+ const filteredOptions = react.useMemo(() => {
67
+ if (onQueryChange || !query) return options;
68
+ const needle = query.toLowerCase();
69
+ return options.filter(option => resolveOptionLabel(option, selectedLabelKey).toLowerCase().includes(needle));
70
+ }, [options, query, onQueryChange, selectedLabelKey]);
49
71
  const togglePopoverActive = react.useCallback(() => {
50
72
  setPopoverActive(active => !active);
51
73
  setQuery('');
52
- onQueryChange('');
74
+ onQueryChange?.('');
53
75
  }, [onQueryChange]);
54
76
  react.useEffect(() => {
55
77
  function handleEsc(event) {
@@ -62,32 +84,33 @@ function SearchableSelect({
62
84
  // keep the cache in sync while the selected option is loaded, so its label survives (and stays
63
85
  // fresh) if pagination later drops the option from `options`
64
86
  react.useEffect(() => {
65
- if (selected.length < 1) return;
66
- const loadedOption = options.find(option => option.value === selected[0]);
67
- const label = getValueByPath(loadedOption?.object, selectedLabelKey);
68
- if (typeof label === 'string' && (cachedSelection?.value !== selected[0] || cachedSelection.label !== label)) {
87
+ if (!selectedValue) return;
88
+ const loadedOption = options.find(option => option.value === selectedValue);
89
+ if (!loadedOption) return;
90
+ const label = resolveOptionLabel(loadedOption, selectedLabelKey);
91
+ if (label && (cachedSelection?.value !== selectedValue || cachedSelection.label !== label)) {
69
92
  setCachedSelection({
70
- value: selected[0],
93
+ value: selectedValue,
71
94
  label
72
95
  });
73
96
  }
74
- }, [selected, options, selectedLabelKey, cachedSelection]);
97
+ }, [selectedValue, options, selectedLabelKey, cachedSelection]);
75
98
  const textSelectedItem = react.useMemo(() => {
76
- if (selected.length < 1) return '';
77
- const selectedItem = options.find(option => option.value === selected[0]);
78
- const value = getValueByPath(selectedItem?.object, selectedLabelKey);
79
- if (typeof value === 'string') return value;
80
- return cachedSelection?.value === selected[0] ? cachedSelection.label : '';
81
- }, [selected, options, selectedLabelKey, cachedSelection]);
99
+ if (!selectedValue) return '';
100
+ const selectedItem = options.find(option => option.value === selectedValue);
101
+ const resolved = resolveOptionLabel(selectedItem, selectedLabelKey);
102
+ if (resolved) return resolved;
103
+ return cachedSelection?.value === selectedValue ? cachedSelection.label : '';
104
+ }, [selectedValue, options, selectedLabelKey, cachedSelection]);
82
105
  const handleSelectionClear = react.useCallback(() => {
83
106
  setCachedSelection(null);
84
- onSelect([]);
107
+ onChange?.('');
85
108
  if (requiredIndicator) {
86
109
  setPopoverActive(true);
87
110
  } else {
88
111
  skipNextFocusOpen.current = true;
89
112
  }
90
- }, [onSelect, requiredIndicator]);
113
+ }, [onChange, requiredIndicator]);
91
114
  const handleActivatorFocus = react.useCallback(() => {
92
115
  if (disabled) return;
93
116
  if (skipNextFocusOpen.current) {
@@ -96,10 +119,14 @@ function SearchableSelect({
96
119
  }
97
120
  setPopoverActive(true);
98
121
  }, [disabled]);
122
+
123
+ // when the clear button is visible it replaces the caret, so they don't pile up
124
+ const showClearButton = Boolean(allowClear) && textSelectedItem !== '';
99
125
  const activator = /*#__PURE__*/jsxRuntime.jsx("div", {
100
- className: SearchableSelect_module.default.Activator,
126
+ className: DropDown_module.default.Activator,
101
127
  children: /*#__PURE__*/jsxRuntime.jsx(TextField.TextField, {
102
128
  label: label,
129
+ labelHidden: labelHidden,
103
130
  placeholder: placeholder,
104
131
  autoComplete: "off",
105
132
  value: textSelectedItem,
@@ -107,38 +134,23 @@ function SearchableSelect({
107
134
  requiredIndicator: requiredIndicator,
108
135
  helpText: helpText,
109
136
  error: error,
110
- clearButton: allowClear && textSelectedItem !== '',
137
+ clearButton: showClearButton,
111
138
  onClearButtonClick: handleSelectionClear,
112
139
  onFocus: handleActivatorFocus,
113
- suffix: /*#__PURE__*/jsxRuntime.jsx(Icon.Icon, {
140
+ onBlur: onBlur,
141
+ suffix: showClearButton ? undefined : /*#__PURE__*/jsxRuntime.jsx(Icon.Icon, {
114
142
  source: polarisIcons.CaretDownIcon
115
- })
143
+ }),
144
+ connectedRight: suffixAction ? utils.buttonFrom(suffixAction) : undefined
116
145
  })
117
146
  });
118
- const pinnedSelectedOption = react.useMemo(() => {
119
- if (query || selected.length < 1) return null;
120
- const loadedOption = options.find(option => option.value === selected[0]);
121
- if (loadedOption) {
122
- return pinSelected ? {
123
- value: loadedOption.value,
124
- label: loadedOption.label
125
- } : null;
126
- }
127
- return cachedSelection?.value === selected[0] ? cachedSelection : null;
128
- }, [query, selected, options, cachedSelection, pinSelected]);
147
+
148
+ // the selected option keeps its natural position in the list; if it is absent from the loaded
149
+ // `options` (e.g. pagination/search reset) it simply isn't listed, while the activator still
150
+ // shows its label via the cache
129
151
  const optionsMarkup = react.useMemo(() => {
130
- if (loading) return null;
131
- const listOptions = pinnedSelectedOption ? options.filter(option => option.value !== pinnedSelectedOption.value) : options;
132
- if (listOptions.length === 0 && !pinnedSelectedOption) return null;
133
- const pinnedMarkup = pinnedSelectedOption ? /*#__PURE__*/jsxRuntime.jsx(Listbox.Listbox.Option, {
134
- value: pinnedSelectedOption.value,
135
- selected: true,
136
- children: /*#__PURE__*/jsxRuntime.jsx(Listbox.Listbox.TextOption, {
137
- selected: true,
138
- children: pinnedSelectedOption.label
139
- })
140
- }, pinnedSelectedOption.value) : null;
141
- return [pinnedMarkup, ...listOptions.map(option => {
152
+ if (loading || filteredOptions.length === 0) return null;
153
+ return filteredOptions.map(option => {
142
154
  const isSelected = selected.includes(option.value);
143
155
  return /*#__PURE__*/jsxRuntime.jsx(Listbox.Listbox.Option, {
144
156
  value: option.value,
@@ -148,45 +160,45 @@ function SearchableSelect({
148
160
  children: option.label
149
161
  })
150
162
  }, option.value);
151
- })];
152
- }, [loading, options, selected, pinnedSelectedOption]);
163
+ });
164
+ }, [loading, filteredOptions, selected]);
153
165
  const loadingMarkup = loading ? /*#__PURE__*/jsxRuntime.jsx(Listbox.Listbox.Loading, {
154
- accessibilityLabel: i18n.translate('Polaris.SearchableSelect.loadingAccessibilityLabel')
166
+ accessibilityLabel: i18n.translate('Polaris.DropDown.loadingAccessibilityLabel')
155
167
  }) : null;
156
168
  const loadingMoreMarkup = loadingMore ? /*#__PURE__*/jsxRuntime.jsx(Listbox.Listbox.Loading, {
157
- accessibilityLabel: i18n.translate('Polaris.SearchableSelect.loadingMoreAccessibilityLabel')
169
+ accessibilityLabel: i18n.translate('Polaris.DropDown.loadingMoreAccessibilityLabel')
158
170
  }) : null;
159
- const noResultsMarkup = !loading && options.length === 0 && !pinnedSelectedOption ? /*#__PURE__*/jsxRuntime.jsx(EmptySearchResult.EmptySearchResult, {
160
- title: emptyStateTitle,
161
- description: emptyStateDescription ?? (query ? i18n.translate('Polaris.SearchableSelect.noResultsFoundFor', {
171
+ const noResultsMarkup = !loading && filteredOptions.length === 0 ? /*#__PURE__*/jsxRuntime.jsx(EmptySearchResult.EmptySearchResult, {
172
+ title: emptyStateTitle || (query ? i18n.translate('Polaris.DropDown.noResultsFoundFor', {
162
173
  query
163
- }) : i18n.translate('Polaris.SearchableSelect.noResultsFound'))
174
+ }) : i18n.translate('Polaris.DropDown.noResultsFound')),
175
+ description: emptyStateDescription
164
176
  }) : null;
165
177
  const updateSelection = react.useCallback(newSelection => {
166
178
  const option = options.find(({
167
- value
168
- }) => value === newSelection);
169
- const label = getValueByPath(option?.object, selectedLabelKey);
170
- if (typeof label === 'string') {
179
+ value: optionValue
180
+ }) => optionValue === newSelection);
181
+ const label = resolveOptionLabel(option, selectedLabelKey);
182
+ if (label) {
171
183
  setCachedSelection({
172
184
  value: newSelection,
173
185
  label
174
186
  });
175
187
  } else if (cachedSelection?.value !== newSelection) {
176
- // re-selecting the pinned option (absent from `options`) must keep its cached label
188
+ // re-selecting the cached option (absent from `options`) must keep its cached label
177
189
  setCachedSelection(null);
178
190
  }
179
- onSelect([newSelection]);
191
+ onChange?.(newSelection);
180
192
  setQuery('');
181
- onQueryChange('');
193
+ onQueryChange?.('');
182
194
  setPopoverActive(false);
183
- }, [options, selectedLabelKey, cachedSelection, onSelect, onQueryChange]);
195
+ }, [options, selectedLabelKey, cachedSelection, onChange, onQueryChange]);
184
196
  const handleActiveOptionChange = react.useCallback((_value, domId) => {
185
197
  setActiveOptionId(domId);
186
198
  }, []);
187
199
  const handleQueryClear = react.useCallback(() => {
188
200
  setQuery('');
189
- onQueryChange('');
201
+ onQueryChange?.('');
190
202
  }, [onQueryChange]);
191
203
  return /*#__PURE__*/jsxRuntime.jsx(Popover.Popover, {
192
204
  activator: activator,
@@ -197,7 +209,7 @@ function SearchableSelect({
197
209
  preferInputActivator: false,
198
210
  children: /*#__PURE__*/jsxRuntime.jsxs(Popover.Popover.Pane, {
199
211
  fixed: true,
200
- children: [/*#__PURE__*/jsxRuntime.jsx(Box.Box, {
212
+ children: [searchable ? /*#__PURE__*/jsxRuntime.jsx(Box.Box, {
201
213
  padding: "300",
202
214
  children: /*#__PURE__*/jsxRuntime.jsx(TextField.TextField, {
203
215
  prefix: /*#__PURE__*/jsxRuntime.jsx(Icon.Icon, {
@@ -206,22 +218,23 @@ function SearchableSelect({
206
218
  label: "",
207
219
  labelHidden: true,
208
220
  autoComplete: "off",
209
- placeholder: i18n.translate('Polaris.SearchableSelect.searchPlaceholder'),
221
+ placeholder: i18n.translate('Polaris.DropDown.searchPlaceholder'),
210
222
  clearButton: true,
211
223
  ariaActiveDescendant: activeOptionId,
212
224
  ariaControls: listboxId,
213
225
  value: query,
214
226
  onChange: value => {
215
- onQueryChange(value);
227
+ onQueryChange?.(value);
216
228
  setQuery(value);
217
229
  },
218
230
  onClearButtonClick: handleQueryClear
219
231
  })
220
- }), /*#__PURE__*/jsxRuntime.jsx(Scrollable.Scrollable, {
232
+ }) : null, /*#__PURE__*/jsxRuntime.jsx(Scrollable.Scrollable, {
221
233
  style: {
222
234
  position: 'relative',
223
235
  maxHeight: SCROLLABLE_HEIGHT,
224
- padding: '0 0 var(--p-space-200)',
236
+ // without the search field above, the list needs its own top padding
237
+ padding: searchable ? '0 0 var(--p-space-200)' : 'var(--p-space-200) 0',
225
238
  borderBottomLeftRadius: 'var(--p-border-radius-200)',
226
239
  borderBottomRightRadius: 'var(--p-border-radius-200)'
227
240
  },
@@ -239,5 +252,42 @@ function SearchableSelect({
239
252
  })
240
253
  });
241
254
  }
255
+ // react-hook-form is an optional peer dependency: only pull it in when the form-aware mode is used
256
+ const LazyDropDownField = /*#__PURE__*/react.lazy(() => Promise.resolve().then(function () { return require('./DropDownField.js'); }).then(module => ({
257
+ default: module.DropDownField
258
+ })));
259
+
260
+ /**
261
+ * A searchable single-select dropdown. Works standalone via `value`/`onChange`, or as a form-aware
262
+ * field by passing `name` (and optionally `control`) to integrate with react-hook-form.
263
+ */
264
+ function DropDown(props) {
265
+ if (props.name != null) {
266
+ const {
267
+ name,
268
+ control,
269
+ rules,
270
+ defaultValue,
271
+ ...baseProps
272
+ } = props;
273
+ return /*#__PURE__*/jsxRuntime.jsx(react.Suspense, {
274
+ fallback: /*#__PURE__*/jsxRuntime.jsx(DropDownBase, {
275
+ ...baseProps,
276
+ disabled: true
277
+ }),
278
+ children: /*#__PURE__*/jsxRuntime.jsx(LazyDropDownField, {
279
+ name: name,
280
+ control: control,
281
+ rules: rules,
282
+ defaultValue: defaultValue,
283
+ ...baseProps
284
+ })
285
+ });
286
+ }
287
+ return /*#__PURE__*/jsxRuntime.jsx(DropDownBase, {
288
+ ...props
289
+ });
290
+ }
242
291
 
243
- exports.SearchableSelect = SearchableSelect;
292
+ exports.DropDown = DropDown;
293
+ exports.DropDownBase = DropDownBase;
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var reactHookForm = require('react-hook-form');
4
+ var DropDown = require('./DropDown.js');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ function DropDownField({
8
+ name,
9
+ control,
10
+ rules,
11
+ defaultValue = '',
12
+ error,
13
+ ...rest
14
+ }) {
15
+ const {
16
+ field,
17
+ fieldState
18
+ } = reactHookForm.useController({
19
+ name,
20
+ control,
21
+ rules,
22
+ defaultValue
23
+ });
24
+ return /*#__PURE__*/jsxRuntime.jsx(DropDown.DropDownBase, {
25
+ ...rest,
26
+ value: field.value,
27
+ onChange: field.onChange,
28
+ onBlur: field.onBlur,
29
+ error: fieldState.error?.message ?? error
30
+ });
31
+ }
32
+
33
+ exports.DropDownField = DropDownField;
@@ -96,7 +96,14 @@ var styles = {
96
96
  "HeaderWrapper": "Polaris-IndexTable__HeaderWrapper",
97
97
  "StickyTable-condensed": "Polaris-IndexTable__StickyTable--condensed",
98
98
  "StickyTableHeader-condensed": "Polaris-IndexTable__StickyTableHeader--condensed",
99
- "ScrollBarContent": "Polaris-IndexTable__ScrollBarContent"
99
+ "ScrollBarContent": "Polaris-IndexTable__ScrollBarContent",
100
+ "TableHeading-reorder": "Polaris-IndexTable__TableHeading--reorder",
101
+ "TableCellDragHandle": "Polaris-IndexTable__TableCellDragHandle",
102
+ "DragHandle": "Polaris-IndexTable__DragHandle",
103
+ "DragHandleIcon": "Polaris-IndexTable__DragHandleIcon",
104
+ "TableRow-reorderable": "Polaris-IndexTable__TableRow--reorderable",
105
+ "TableRow-dragging": "Polaris-IndexTable__TableRow--dragging",
106
+ "TableRow-dropTarget": "Polaris-IndexTable__TableRow--dropTarget"
100
107
  };
101
108
 
102
109
  exports.default = styles;
@@ -12,7 +12,6 @@ var IndexProvider = require('../IndexProvider/IndexProvider.js');
12
12
  var Row = require('./components/Row/Row.js');
13
13
  var types = require('../../utilities/index-provider/types.js');
14
14
  var utilities = require('./utilities/utilities.js');
15
- var EmptySearchResult = require('../EmptySearchResult/EmptySearchResult.js');
16
15
  var ScrollContainer = require('./components/ScrollContainer/ScrollContainer.js');
17
16
  var BulkActions = require('../BulkActions/BulkActions.js');
18
17
  var Cell = require('./components/Cell/Cell.js');
@@ -20,9 +19,11 @@ var hooks = require('../../utilities/index-provider/hooks.js');
20
19
  var hooks$1 = require('../../utilities/i18n/hooks.js');
21
20
  var Spinner = require('../Spinner/Spinner.js');
22
21
  var AfterInitialMount = require('../AfterInitialMount/AfterInitialMount.js');
22
+ var EmptySearchResult = require('../EmptySearchResult/EmptySearchResult.js');
23
23
  var Pagination = require('../Pagination/Pagination.js');
24
- var Checkbox = require('../Checkbox/Checkbox.js');
24
+ var context = require('../../utilities/index-table/context.js');
25
25
  var Text = require('../Text/Text.js');
26
+ var Checkbox = require('../Checkbox/Checkbox.js');
26
27
  var LegacyStack = require('../LegacyStack/LegacyStack.js');
27
28
  var Badge = require('../Badge/Badge.js');
28
29
  var UnstyledButton = require('../UnstyledButton/UnstyledButton.js');
@@ -49,6 +50,7 @@ function IndexTableBase({
49
50
  sortToggleLabels,
50
51
  hasZebraStriping,
51
52
  pagination,
53
+ onReorder,
52
54
  ...restProps
53
55
  }) {
54
56
  const {
@@ -66,6 +68,34 @@ function IndexTableBase({
66
68
  } = hooks.useIndexValue();
67
69
  const handleSelectionChange = hooks.useIndexSelectionChange();
68
70
  const i18n = hooks$1.useI18n();
71
+ const reorderable = typeof onReorder === 'function';
72
+ const [draggingPosition, setDraggingPosition] = react.useState(null);
73
+ const [dropPosition, setDropPosition] = react.useState(null);
74
+ const handleReorderDragStart = react.useCallback(position => {
75
+ setDraggingPosition(position);
76
+ }, []);
77
+ const handleReorderDragEnter = react.useCallback(position => {
78
+ setDropPosition(position);
79
+ }, []);
80
+ const resetReorderState = react.useCallback(() => {
81
+ setDraggingPosition(null);
82
+ setDropPosition(null);
83
+ }, []);
84
+ const handleReorderDrop = react.useCallback(() => {
85
+ if (draggingPosition !== null && dropPosition !== null && draggingPosition !== dropPosition) {
86
+ onReorder?.(draggingPosition, dropPosition);
87
+ }
88
+ resetReorderState();
89
+ }, [draggingPosition, dropPosition, onReorder, resetReorderState]);
90
+ const reorderContextValue = react.useMemo(() => ({
91
+ reorderable,
92
+ draggingPosition,
93
+ dropPosition,
94
+ onDragStart: handleReorderDragStart,
95
+ onDragEnter: handleReorderDragEnter,
96
+ onDrop: handleReorderDrop,
97
+ onDragEnd: resetReorderState
98
+ }), [reorderable, draggingPosition, dropPosition, handleReorderDragStart, handleReorderDragEnter, handleReorderDrop, resetReorderState]);
69
99
  const {
70
100
  value: hasMoreLeftColumns,
71
101
  toggle: toggleHasMoreLeftColumns
@@ -391,7 +421,8 @@ function IndexTableBase({
391
421
  ...pagination
392
422
  })
393
423
  }) : null;
394
- return /*#__PURE__*/jsxRuntime.jsx(jsxRuntime.Fragment, {
424
+ return /*#__PURE__*/jsxRuntime.jsx(context.RowReorderContext.Provider, {
425
+ value: reorderContextValue,
395
426
  children: /*#__PURE__*/jsxRuntime.jsx("div", {
396
427
  className: IndexTable_module.default.IndexTable,
397
428
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -416,16 +447,33 @@ function IndexTableBase({
416
447
  ...tagProps,
417
448
  children: renderHeadingContent(heading, index)
418
449
  }, getHeadingKey(heading));
419
- if (index !== 0 || !selectable) {
450
+ if (index !== 0 || !selectable && !reorderable) {
420
451
  return headingContent;
421
452
  }
422
- const checkboxClassName = css.classNames(IndexTable_module.default.TableHeading, hasSortable && IndexTable_module.default['TableHeading-sortable'], index === 0 && IndexTable_module.default['TableHeading-first']);
423
- const checkboxContent = /*#__PURE__*/jsxRuntime.jsx(Tag, {
424
- className: checkboxClassName,
425
- ...tagProps,
426
- children: renderCheckboxContent()
427
- }, `${heading}-${index}`);
428
- return [checkboxContent, headingContent];
453
+ const leadingHeadings = [];
454
+
455
+ // Omits `data-index-table-heading` so this column is excluded from the
456
+ // column index math used by sticky columns and sort handling.
457
+ if (reorderable) {
458
+ leadingHeadings.push(/*#__PURE__*/jsxRuntime.jsx(Tag, {
459
+ className: css.classNames(IndexTable_module.default.TableHeading, IndexTable_module.default['TableHeading-reorder']),
460
+ children: /*#__PURE__*/jsxRuntime.jsx(Text.Text, {
461
+ as: "span",
462
+ variant: "bodySm",
463
+ visuallyHidden: true,
464
+ children: i18n.translate('Polaris.IndexTable.reorderColumnHeader')
465
+ })
466
+ }, "reorder-heading"));
467
+ }
468
+ if (selectable) {
469
+ const checkboxClassName = css.classNames(IndexTable_module.default.TableHeading, hasSortable && IndexTable_module.default['TableHeading-sortable'], index === 0 && IndexTable_module.default['TableHeading-first']);
470
+ leadingHeadings.push(/*#__PURE__*/jsxRuntime.jsx(Tag, {
471
+ className: checkboxClassName,
472
+ ...tagProps,
473
+ children: renderCheckboxContent()
474
+ }, `${heading}-${index}`));
475
+ }
476
+ return [...leadingHeadings, headingContent];
429
477
  }
430
478
  function renderCheckboxContent() {
431
479
  return /*#__PURE__*/jsxRuntime.jsx("div", {
@@ -1,15 +1,19 @@
1
1
  'use strict';
2
2
 
3
+ var polarisIcons = require('@shopify/polaris-icons');
3
4
  var react = require('react');
4
5
  var css = require('../../../../utilities/css.js');
5
6
  var useToggle = require('../../../../utilities/use-toggle.js');
6
7
  var IndexTable_module = require('../../IndexTable.css.js');
7
8
  var jsxRuntime = require('react/jsx-runtime');
8
- var hooks = require('../../../../utilities/index-provider/hooks.js');
9
- var types = require('../../../../utilities/index-provider/types.js');
9
+ var hooks$1 = require('../../../../utilities/index-provider/hooks.js');
10
10
  var context = require('../../../../utilities/index-table/context.js');
11
+ var types = require('../../../../utilities/index-provider/types.js');
11
12
  var Cell = require('../Cell/Cell.js');
12
13
  var Checkbox = require('../Checkbox/Checkbox.js');
14
+ var hooks = require('../../../../utilities/i18n/hooks.js');
15
+ var Icon = require('../../../Icon/Icon.js');
16
+ var Text = require('../../../Text/Text.js');
13
17
 
14
18
  const Row = /*#__PURE__*/react.memo(function Row({
15
19
  children,
@@ -25,18 +29,44 @@ const Row = /*#__PURE__*/react.memo(function Row({
25
29
  onNavigation,
26
30
  onClick
27
31
  }) {
32
+ const i18n = hooks.useI18n();
28
33
  const {
29
34
  selectable: tableIsSelectable,
30
35
  selectMode,
31
36
  condensed
32
- } = hooks.useIndexRow();
37
+ } = hooks$1.useIndexRow();
38
+ const {
39
+ resourceName
40
+ } = hooks$1.useIndexValue();
33
41
  const rowIsSelectable = tableIsSelectable && !hideSelectable;
34
- const onSelectionChange = hooks.useIndexSelectionChange();
42
+ const onSelectionChange = hooks$1.useIndexSelectionChange();
35
43
  const {
36
44
  value: hovered,
37
45
  setTrue: setHoverIn,
38
46
  setFalse: setHoverOut
39
47
  } = useToggle.useToggle(false);
48
+ const reorder = react.useContext(context.RowReorderContext);
49
+ const reorderable = Boolean(reorder?.reorderable) && rowType === 'data';
50
+ const isDragging = reorderable && reorder?.draggingPosition === position;
51
+ const isDropTarget = reorderable && reorder?.dropPosition === position && reorder?.draggingPosition !== position;
52
+ const handleDragStart = react.useCallback(event => {
53
+ event.dataTransfer.effectAllowed = 'move';
54
+ reorder?.onDragStart(position);
55
+ }, [reorder, position]);
56
+ const handleDragEnter = react.useCallback(() => {
57
+ reorder?.onDragEnter(position);
58
+ }, [reorder, position]);
59
+ const handleDragOver = react.useCallback(event => {
60
+ event.preventDefault();
61
+ event.dataTransfer.dropEffect = 'move';
62
+ }, []);
63
+ const handleDrop = react.useCallback(event => {
64
+ event.preventDefault();
65
+ reorder?.onDrop();
66
+ }, [reorder]);
67
+ const handleDragEnd = react.useCallback(() => {
68
+ reorder?.onDragEnd();
69
+ }, [reorder]);
40
70
  const handleInteraction = react.useCallback(event => {
41
71
  event.stopPropagation();
42
72
  let selectionType = types.SelectionType.Single;
@@ -66,7 +96,7 @@ const Row = /*#__PURE__*/react.memo(function Row({
66
96
  primaryLinkElement.current = el;
67
97
  }
68
98
  }, []);
69
- const rowClassName = css.classNames(IndexTable_module.default.TableRow, rowType === 'subheader' && IndexTable_module.default['TableRow-subheader'], rowType === 'child' && IndexTable_module.default['TableRow-child'], rowIsSelectable && condensed && IndexTable_module.default.condensedRow, selected && IndexTable_module.default['TableRow-selected'], hovered && !condensed && IndexTable_module.default['TableRow-hovered'], disabled && IndexTable_module.default['TableRow-disabled'], tone && IndexTable_module.default[css.variationName('tone', tone)], !rowIsSelectable && !onClick && !primaryLinkElement.current && IndexTable_module.default['TableRow-unclickable']);
99
+ const rowClassName = css.classNames(IndexTable_module.default.TableRow, rowType === 'subheader' && IndexTable_module.default['TableRow-subheader'], rowType === 'child' && IndexTable_module.default['TableRow-child'], rowIsSelectable && condensed && IndexTable_module.default.condensedRow, selected && IndexTable_module.default['TableRow-selected'], hovered && !condensed && IndexTable_module.default['TableRow-hovered'], disabled && IndexTable_module.default['TableRow-disabled'], tone && IndexTable_module.default[css.variationName('tone', tone)], reorderable && IndexTable_module.default['TableRow-reorderable'], isDragging && IndexTable_module.default['TableRow-dragging'], isDropTarget && IndexTable_module.default['TableRow-dropTarget'], !rowIsSelectable && !onClick && !primaryLinkElement.current && IndexTable_module.default['TableRow-unclickable']);
70
100
  let handleRowClick;
71
101
  if (!disabled && rowIsSelectable || onClick || primaryLinkElement.current) {
72
102
  handleRowClick = event => {
@@ -105,6 +135,35 @@ const Row = /*#__PURE__*/react.memo(function Row({
105
135
  const checkboxMarkup = hideSelectable ? /*#__PURE__*/jsxRuntime.jsx(Cell.Cell, {}) : /*#__PURE__*/jsxRuntime.jsx(Checkbox.Checkbox, {
106
136
  accessibilityLabel: accessibilityLabel
107
137
  });
138
+ const dragHandleMarkup = reorderable ? /*#__PURE__*/jsxRuntime.jsx("td", {
139
+ className: IndexTable_module.default.TableCellDragHandle,
140
+ onClick: stopPropagation,
141
+ children: /*#__PURE__*/jsxRuntime.jsxs("span", {
142
+ className: IndexTable_module.default.DragHandle,
143
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
144
+ className: IndexTable_module.default.DragHandleIcon,
145
+ "aria-hidden": "true",
146
+ children: /*#__PURE__*/jsxRuntime.jsx(Icon.Icon, {
147
+ source: polarisIcons.DragHandleIcon,
148
+ tone: "subdued"
149
+ })
150
+ }), /*#__PURE__*/jsxRuntime.jsx(Text.Text, {
151
+ as: "span",
152
+ visuallyHidden: true,
153
+ children: i18n.translate('Polaris.IndexTable.reorderAccessibilityLabel', {
154
+ resourceName: resourceName.singular
155
+ })
156
+ })]
157
+ })
158
+ }) : null;
159
+ const reorderProps = reorderable ? {
160
+ draggable: true,
161
+ onDragStart: handleDragStart,
162
+ onDragEnter: handleDragEnter,
163
+ onDragOver: handleDragOver,
164
+ onDrop: handleDrop,
165
+ onDragEnd: handleDragEnd
166
+ } : {};
108
167
  return /*#__PURE__*/jsxRuntime.jsx(context.RowContext.Provider, {
109
168
  value: contextValue,
110
169
  children: /*#__PURE__*/jsxRuntime.jsx(context.RowHoveredContext.Provider, {
@@ -116,10 +175,14 @@ const Row = /*#__PURE__*/react.memo(function Row({
116
175
  onMouseLeave: setHoverOut,
117
176
  onClick: handleRowClick,
118
177
  ref: tableRowCallbackRef,
119
- children: [tableIsSelectable ? checkboxMarkup : null, children]
178
+ ...reorderProps,
179
+ children: [dragHandleMarkup, tableIsSelectable ? checkboxMarkup : null, children]
120
180
  }, id)
121
181
  })
122
182
  });
123
183
  });
184
+ function stopPropagation(event) {
185
+ event.stopPropagation();
186
+ }
124
187
 
125
188
  exports.Row = Row;