@jobber/components 4.45.6 → 4.46.1-JOB-79340.27

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 (109) hide show
  1. package/Chip.d.ts +1 -0
  2. package/Chip.js +17 -0
  3. package/dist/Autocomplete/index.js +7 -7
  4. package/dist/Avatar/Avatar.d.ts +1 -1
  5. package/dist/Avatar/index.d.ts +1 -1
  6. package/dist/Banner/index.js +3 -3
  7. package/dist/Button/index.js +2 -2
  8. package/dist/{Button-d89f2271.js → Button-db6114a6.js} +1 -1
  9. package/dist/ButtonDismiss/index.js +3 -3
  10. package/dist/{ButtonDismiss-250840a4.js → ButtonDismiss-1ccb84ec.js} +1 -1
  11. package/dist/Card/index.js +5 -5
  12. package/dist/{Card-69304e99.js → Card-116af709.js} +3 -3
  13. package/dist/Checkbox/index.js +3 -3
  14. package/dist/{Checkbox-eac63b7f.js → Checkbox-bc4bc968.js} +1 -1
  15. package/dist/Chip/Chip.d.ts +8 -0
  16. package/dist/Chip/Chip.types.d.d.ts +64 -0
  17. package/dist/Chip/components/ChipDismissible/ChipDismissible.d.ts +3 -0
  18. package/dist/Chip/components/ChipPrefix/Chip.Prefix.d.ts +6 -0
  19. package/dist/Chip/components/ChipSelectable/ChipSelectable.d.ts +3 -0
  20. package/dist/Chip/components/ChipSuffix/Chip.Suffix.d.ts +7 -0
  21. package/dist/Chip/hooks/index.d.ts +1 -0
  22. package/dist/Chip/hooks/useChildComponent.d.ts +8 -0
  23. package/dist/Chip/index.d.ts +4 -0
  24. package/dist/Chip/index.js +28 -0
  25. package/dist/ChipSelectable-8e5509a1.js +74 -0
  26. package/dist/Chips/ChipsTypes.d.ts +12 -8
  27. package/dist/Chips/InternalChipDismissible/InternalChipDismissible.d.ts +2 -2
  28. package/dist/Chips/InternalChipDismissible/InternalChipDismissibleTypes.d.ts +1 -1
  29. package/dist/Chips/InternalChipDismissible/hooks/useInternalChipDismissible.d.ts +1 -1
  30. package/dist/Chips/InternalChipMultiSelect.d.ts +1 -1
  31. package/dist/Chips/InternalChipSingleSelect.d.ts +2 -2
  32. package/dist/Chips/index.d.ts +5 -1
  33. package/dist/Chips/index.js +24 -10
  34. package/dist/{Chip-4d8e6370.js → Chips-2daf43ea.js} +84 -78
  35. package/dist/Combobox/Combobox.d.ts +6 -0
  36. package/dist/Combobox/ComboboxProvider.d.ts +2 -0
  37. package/dist/Combobox/components/ComboboxContent/ComboboxContent.d.ts +17 -6
  38. package/dist/Combobox/components/ComboboxContent/ComboboxList.d.ts +9 -8
  39. package/dist/Combobox/components/ComboboxContent/ComboboxSearch.d.ts +4 -4
  40. package/dist/Combobox/hooks/useComboboxContent.d.ts +7 -3
  41. package/dist/Combobox/index.js +64 -30
  42. package/dist/ConfirmationModal/index.js +9 -9
  43. package/dist/{ConfirmationModal-92f07027.js → ConfirmationModal-285c3cbe.js} +2 -2
  44. package/dist/DataDump/index.js +6 -6
  45. package/dist/DataList/DataList.types.d.ts +9 -1
  46. package/dist/DataList/components/DataListSearch/DataListSearch.d.ts +1 -1
  47. package/dist/DataList/index.js +47 -24
  48. package/dist/DataTable/index.js +6 -6
  49. package/dist/DatePicker/index.js +3 -3
  50. package/dist/{DatePicker-39d2dc8b.js → DatePicker-49213434.js} +2 -2
  51. package/dist/DescriptionList/index.js +1 -1
  52. package/dist/Disclosure/index.js +1 -1
  53. package/dist/Drawer/index.js +4 -4
  54. package/dist/Emphasis/index.js +2 -2
  55. package/dist/{Emphasis-cc3456ac.js → Emphasis-e10dde65.js} +1 -1
  56. package/dist/FeatureSwitch/index.js +7 -7
  57. package/dist/FormField/index.js +5 -5
  58. package/dist/{FormField-bef41ec9.js → FormField-fa9254dc.js} +3 -3
  59. package/dist/FormatFile/index.js +10 -10
  60. package/dist/{FormatFile-a470c0f2.js → FormatFile-6423c3b5.js} +4 -4
  61. package/dist/Gallery/index.js +11 -11
  62. package/dist/Heading/index.js +2 -2
  63. package/dist/{Heading-4562900a.js → Heading-4cde9989.js} +1 -1
  64. package/dist/InlineLabel/index.js +2 -2
  65. package/dist/{InlineLabel-3d461632.js → InlineLabel-a24706c4.js} +1 -1
  66. package/dist/InputAvatar/index.js +3 -3
  67. package/dist/InputDate/index.js +6 -6
  68. package/dist/InputEmail/index.js +5 -5
  69. package/dist/InputFile/index.js +3 -3
  70. package/dist/{InputFile-d327dee3.js → InputFile-25c3369b.js} +2 -2
  71. package/dist/InputNumber/index.js +6 -6
  72. package/dist/{InputNumber-5640fb55.js → InputNumber-ea9fcee1.js} +1 -1
  73. package/dist/InputPassword/index.js +5 -5
  74. package/dist/InputPhoneNumber/index.js +5 -5
  75. package/dist/InputText/index.js +6 -6
  76. package/dist/{InputText-5ac5cfe0.js → InputText-ab237501.js} +1 -1
  77. package/dist/InputTime/index.js +5 -5
  78. package/dist/InputValidation/index.js +3 -3
  79. package/dist/{InputValidation-4e809bdd.js → InputValidation-377d6c62.js} +1 -1
  80. package/dist/LightBox/index.js +4 -4
  81. package/dist/{LightBox-02ca409e.js → LightBox-93ef99b9.js} +2 -2
  82. package/dist/List/index.js +5 -5
  83. package/dist/Markdown/index.js +5 -5
  84. package/dist/{Markdown-b37cf9ec.js → Markdown-d53b01bf.js} +3 -3
  85. package/dist/Menu/index.js +3 -3
  86. package/dist/{Menu-cec53b50.js → Menu-2e64307a.js} +2 -2
  87. package/dist/Modal/index.js +5 -5
  88. package/dist/{Modal-dcdc0032.js → Modal-c17cc105.js} +3 -3
  89. package/dist/MultiSelect/index.js +3 -3
  90. package/dist/{Option-9f4a65da.js → Option-07a24acd.js} +1 -1
  91. package/dist/Page/index.js +7 -7
  92. package/dist/Popover/index.js +4 -4
  93. package/dist/{Popover-d401fb54.js → Popover-7c966790.js} +1 -1
  94. package/dist/RadioGroup/index.js +3 -3
  95. package/dist/{RadioGroup-46833fac.js → RadioGroup-9bdd8a59.js} +1 -1
  96. package/dist/RecurringSelect/index.js +8 -8
  97. package/dist/Select/index.js +6 -6
  98. package/dist/StatusLabel/index.js +2 -2
  99. package/dist/Switch/index.js +2 -2
  100. package/dist/{Switch-165f01e3.js → Switch-cc9b645c.js} +1 -1
  101. package/dist/Tabs/index.js +1 -1
  102. package/dist/Text/index.js +2 -2
  103. package/dist/{Text-59bde58c.js → Text-54334431.js} +1 -1
  104. package/dist/Toast/index.js +2 -2
  105. package/dist/Tooltip/index.js +3 -3
  106. package/dist/{Tooltip-59dbab5b.js → Tooltip-d5257798.js} +1 -1
  107. package/dist/Typography/index.js +1 -1
  108. package/dist/{Typography-9bff9c91.js → Typography-83915c54.js} +2 -2
  109. package/package.json +5 -5
@@ -1,20 +1,22 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var uuid = require('uuid');
5
4
  var styleInject_es = require('./style-inject.es-9d2f5f4e.js');
6
5
  var classnames = require('classnames');
7
6
  var useAssert = require('@jobber/hooks/useAssert');
8
7
  var Icon = require('./Icon-405a216c.js');
9
8
  var Avatar = require('./Avatar-1aa30ee1.js');
10
- var Typography = require('./Typography-9bff9c91.js');
11
- var Tooltip = require('./Tooltip-59dbab5b.js');
9
+ var Typography = require('./Typography-83915c54.js');
10
+ var Tooltip = require('./Tooltip-d5257798.js');
11
+ var ChipSelectable = require('./ChipSelectable-8e5509a1.js');
12
+ require('@jobber/design');
12
13
  var sortBy = require('lodash/sortBy');
13
14
  var useLiveAnnounce = require('@jobber/hooks/useLiveAnnounce');
15
+ var uuid = require('uuid');
14
16
  var debounce = require('lodash/debounce');
15
17
  var reactPopper = require('react-popper');
16
- var Text = require('./Text-59bde58c.js');
17
- var Button = require('./Button-d89f2271.js');
18
+ var Text = require('./Text-54334431.js');
19
+ var Button = require('./Button-db6114a6.js');
18
20
  var Spinner = require('./Spinner-9d8fc7ff.js');
19
21
 
20
22
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -118,14 +120,20 @@ function InternalChip({ label, active = false, disabled = false, invalid = false
118
120
  }
119
121
  }
120
122
 
121
- function InternalChipSingleSelect({ children, selected, name = uuid.v1(), onChange, onClick, }) {
123
+ function InternalChipSingleSelect({ children, selected, onChange, onClick, }) {
122
124
  return (React__default["default"].createElement("div", { className: styles$1.wrapper, "data-testid": "singleselect-chips" }, React__default["default"].Children.map(children, child => {
123
- const isSelected = child.props.value === selected;
124
- return (React__default["default"].createElement("label", null,
125
- React__default["default"].createElement("input", { type: "radio", checked: isSelected, className: styles$1.input, name: name, onClick: handleClick(child.props.value), onKeyUp: handleKeyUp(isSelected, child.props.value), onChange: () => {
126
- /* No op. onClick handles the change to allow deselecting. */
127
- }, disabled: child.props.disabled }),
128
- React__default["default"].createElement(InternalChip, Object.assign({}, child.props, { active: isSelected }))));
125
+ const isSelected = (child === null || child === void 0 ? void 0 : child.props.value) === selected || (child === null || child === void 0 ? void 0 : child.props.label) === selected;
126
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
127
+ React__default["default"].createElement("label", { style: { display: "none" } },
128
+ React__default["default"].createElement("input", { type: "radio", checked: isSelected, className: styles$1.input, onClick: handleClick((child === null || child === void 0 ? void 0 : child.props.value) || ""), onKeyUp: handleKeyUp(isSelected, (child === null || child === void 0 ? void 0 : child.props.value) || ""), onChange: () => {
129
+ /* No op. onClick handles the change to allow deselecting. */
130
+ }, disabled: child === null || child === void 0 ? void 0 : child.props.disabled }),
131
+ React__default["default"].createElement(InternalChip, Object.assign({}, child === null || child === void 0 ? void 0 : child.props, { label: (child === null || child === void 0 ? void 0 : child.props.label) || "", active: isSelected }))),
132
+ React__default["default"].createElement(ChipSelectable.ChipSelectable, Object.assign({}, child === null || child === void 0 ? void 0 : child.props, { label: (child === null || child === void 0 ? void 0 : child.props.label) || "", selected: isSelected, onClick: clickedItem => {
133
+ onChange(clickedItem);
134
+ onClick &&
135
+ onClick({}, child === null || child === void 0 ? void 0 : child.props.value);
136
+ }, onKeyDown: handleKeyUp(isSelected, (child === null || child === void 0 ? void 0 : child.props.value) || "") }))));
129
137
  })));
130
138
  function handleKeyUp(active, value) {
131
139
  if (!active)
@@ -150,47 +158,50 @@ function InternalChipSingleSelect({ children, selected, name = uuid.v1(), onChan
150
158
  }
151
159
 
152
160
  function InternalChipMultiSelect({ children, selected, onChange, onClick, }) {
161
+ const toggleSelectedChip = (val, ev) => {
162
+ const newChips = [...(selected || [])];
163
+ const indexOfItem = newChips.findIndex(d => d === val);
164
+ if (indexOfItem !== -1) {
165
+ newChips.splice(indexOfItem, 1);
166
+ }
167
+ else {
168
+ newChips.push(val);
169
+ }
170
+ onChange(newChips);
171
+ onClick && onClick(ev, val);
172
+ };
153
173
  return (React__default["default"].createElement("div", { className: styles$1.wrapper, "data-testid": "multiselect-chips" }, React__default["default"].Children.map(children, chip => {
154
- const isChipActive = isChipSelected(chip.props.value);
155
- return (React__default["default"].createElement("label", null,
156
- React__default["default"].createElement("input", { type: "checkbox", checked: isChipActive, className: styles$1.input, onClick: handleClick(chip.props.value), onChange: handleChange(chip.props.value), disabled: chip.props.disabled }),
157
- React__default["default"].createElement(InternalChip, Object.assign({}, chip.props, { active: isChipActive, suffix: checkmarkIcon(isChipActive) }))));
174
+ const isChipActive = selected === null || selected === void 0 ? void 0 : selected.includes((chip === null || chip === void 0 ? void 0 : chip.props.value) || (chip === null || chip === void 0 ? void 0 : chip.props.label));
175
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
176
+ React__default["default"].createElement("label", { style: { display: "none" } },
177
+ React__default["default"].createElement("input", { type: "checkbox", checked: isChipActive, className: styles$1.input, onClick: chip && handleClick(chip.props.value), onChange: chip && handleChange(chip.props.value), disabled: chip === null || chip === void 0 ? void 0 : chip.props.disabled })),
178
+ chip && (React__default["default"].createElement(ChipSelectable.ChipSelectable, Object.assign({}, chip.props, { selected: isChipActive, onClick: toggleSelectedChip })))));
179
+ function isChipSelected(value) {
180
+ return selected === null || selected === void 0 ? void 0 : selected.includes(value);
181
+ }
182
+ function handleClick(value) {
183
+ return (event) => onClick === null || onClick === void 0 ? void 0 : onClick(event, value);
184
+ }
185
+ function handleChange(value) {
186
+ return () => {
187
+ if (isChipSelected(value)) {
188
+ handleDeselect(value);
189
+ }
190
+ else {
191
+ handleSelect(value);
192
+ }
193
+ };
194
+ }
195
+ function handleSelect(value) {
196
+ const newVal = [...(selected || []), value];
197
+ onChange(newVal);
198
+ }
199
+ function handleDeselect(value) {
200
+ const values = selected;
201
+ const newVal = values === null || values === void 0 ? void 0 : values.filter(val => val !== value);
202
+ onChange(newVal || []);
203
+ }
158
204
  })));
159
- function isChipSelected(value) {
160
- return selected.includes(value);
161
- }
162
- function handleClick(value) {
163
- return (event) => onClick === null || onClick === void 0 ? void 0 : onClick(event, value);
164
- }
165
- function handleChange(value) {
166
- return () => {
167
- if (isChipSelected(value)) {
168
- handleDeselect(value);
169
- }
170
- else {
171
- handleSelect(value);
172
- }
173
- };
174
- }
175
- function handleSelect(value) {
176
- const newVal = [...selected, value];
177
- onChange(newVal);
178
- }
179
- function handleDeselect(value) {
180
- const values = selected;
181
- const newVal = values.filter(val => val !== value);
182
- onChange(newVal);
183
- }
184
- function checkmarkIcon(show) {
185
- // Ideally, we should be returning a fragment `<></>` when a function
186
- // returns a component / element. However, this one needs to return nothing
187
- // to prevent it from randomly rendering a suffix.
188
- //
189
- // DO NOT COPY!
190
- if (!show)
191
- return;
192
- return React__default["default"].createElement(Icon.Icon, { name: "checkmark" });
193
- }
194
205
  }
195
206
 
196
207
  var css_248z = ".sCNIjluCskc- {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n box-sizing: border-box;\n border: calc(16px / 16) solid transparent;\n border: var(--border-base) solid transparent;\n border-radius: calc(16px / 8);\n border-radius: var(--radius-base);\n transition: all 200ms;\n transition: all var(--timing-base);\n gap: calc(16px / 2);\n gap: var(--space-small);\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: center;\n align-items: center;\n}\n\n.MFUlz1WQLdk- {\n -ms-flex: 1;\n flex: 1;\n min-width: 120px;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n border: none;\n border-radius: 0;\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n font-size: calc(calc(16px * 1) * 0.875);\n font-size: var(--typography--fontSize-base);\n line-height: 1.25;\n line-height: var(--typography--lineHeight-base);\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n}\n\n.MFUlz1WQLdk-:focus {\n outline: none;\n}\n\n.V9eYJdjPAeY- {\n position: relative;\n z-index: 6;\n z-index: var(--elevation-menu);\n width: 100%;\n}\n\n.LdytkOeCU9c- {\n max-height: 320px;\n box-shadow: 0px calc(16px / 16) calc(16px / 4) 0px\n rgba(0, 0, 0, 0.1),\n 0px calc(16px / 4) 12px 0px rgba(0, 0, 0, 0.05);\n box-shadow: var(--shadow-base);\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n border-radius: calc(16px / 8);\n border-radius: var(--radius-base);\n overflow-y: scroll;\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n.y7Cz2u8BuNE-,\n._-7bmao8Q9As- {\n display: -ms-flexbox;\n display: flex;\n width: 100%;\n padding: calc(16px / 2);\n padding: var(--space-small);\n border: none;\n background-color: transparent;\n cursor: pointer;\n -webkit-appearance: none;\n appearance: none;\n -ms-flex-align: center;\n align-items: center;\n gap: calc(16px / 2);\n gap: var(--space-small);\n}\n\n.y7Cz2u8BuNE-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n}\n\n.y7Cz2u8BuNE-:focus,\n.iCwWdcmtInc- {\n outline: none;\n background-color: rgb(250, 246, 219);\n background-color: var(--color-surface--hover);\n}\n\n._-7bmao8Q9As- {\n -ms-flex-pack: center;\n justify-content: center;\n}\n";
@@ -199,19 +210,20 @@ styleInject_es.styleInject(css_248z);
199
210
 
200
211
  function useInternalChipDismissible({ children, selected, onChange, onClick, onCustomAdd, }) {
201
212
  const ref = React.useRef(null);
202
- const chipOptions = children.map(chip => chip.props);
203
- const visibleChipOptions = chipOptions.filter(chip => selected.includes(chip.value));
204
- const sortedVisibleChipOptions = sortBy__default["default"](visibleChipOptions, chip => selected.indexOf(chip.value));
205
- const availableChipOptions = chipOptions.filter(chip => !selected.includes(chip.value));
213
+ const chipOptions = children === null || children === void 0 ? void 0 : children.map(chip => chip.props);
214
+ const visibleChipOptions = chipOptions === null || chipOptions === void 0 ? void 0 : chipOptions.filter(chip => selected === null || selected === void 0 ? void 0 : selected.includes(chip.value));
215
+ const sortedVisibleChipOptions = sortBy__default["default"](visibleChipOptions, chip => selected === null || selected === void 0 ? void 0 : selected.indexOf(chip.value));
216
+ const availableChipOptions = chipOptions === null || chipOptions === void 0 ? void 0 : chipOptions.filter(chip => !(selected === null || selected === void 0 ? void 0 : selected.includes(chip.value)));
206
217
  const { liveAnnounce } = useLiveAnnounce.useLiveAnnounce();
207
218
  const actions = {
208
219
  handleChipRemove: (value) => {
209
220
  return () => {
210
221
  liveAnnounce(`${value} Removed`);
211
- onChange(selected.filter(val => val !== value));
222
+ onChange((selected === null || selected === void 0 ? void 0 : selected.filter(val => val !== value)) || []);
223
+ onClick && onClick({}, value);
212
224
  };
213
225
  },
214
- handleChipAdd: (value) => onChange([...selected, value]),
226
+ handleChipAdd: (value) => onChange([...(selected || []), value]),
215
227
  handleCustomAdd: onCustomAdd,
216
228
  handleChipClick: (value) => {
217
229
  if (onClick === undefined)
@@ -268,7 +280,7 @@ function useInternalChipDismissibleInput({ options, isLoadingMore = false, onCus
268
280
  const [shouldCancelBlur, setShouldCancelBlur] = React.useState(false);
269
281
  const [shouldCancelEnter, setShouldCancelEnter] = React.useState(false);
270
282
  const canAddCustomOption = onCustomOptionSelect !== undefined && !isLoadingMore;
271
- const maxOptionIndex = allOptions.length - 1;
283
+ const maxOptionIndex = (allOptions === null || allOptions === void 0 ? void 0 : allOptions.length) - 1;
272
284
  const { liveAnnounce } = useLiveAnnounce.useLiveAnnounce();
273
285
  React.useEffect(() => {
274
286
  setAllOptions(generateOptions(options, searchValue, canAddCustomOption));
@@ -276,8 +288,8 @@ function useInternalChipDismissibleInput({ options, isLoadingMore = false, onCus
276
288
  const computed = {
277
289
  menuId,
278
290
  inputRef: React.useRef(null),
279
- activeOption: allOptions[activeIndex],
280
- hasAvailableOptions: allOptions.length > 0,
291
+ activeOption: allOptions === null || allOptions === void 0 ? void 0 : allOptions[activeIndex],
292
+ hasAvailableOptions: (allOptions === null || allOptions === void 0 ? void 0 : allOptions.length) > 0,
281
293
  nextOptionIndex: activeIndex < maxOptionIndex ? activeIndex + 1 : 0,
282
294
  previousOptionIndex: activeIndex > 0 ? activeIndex - 1 : maxOptionIndex,
283
295
  };
@@ -365,16 +377,14 @@ function useInternalChipDismissibleInput({ options, isLoadingMore = false, onCus
365
377
  shouldCancelBlur });
366
378
  }
367
379
  function generateOptions(options, searchValue, canAddCustomOption) {
368
- const allOptions = options
369
- .filter(option => option.label.toLowerCase().match(searchValue.trim().toLowerCase()))
370
- .map(opt => (Object.assign(Object.assign({}, opt), { custom: false })));
380
+ const allOptions = options === null || options === void 0 ? void 0 : options.filter(option => option.label.toLowerCase().match(searchValue.trim().toLowerCase())).map(opt => (Object.assign(Object.assign({}, opt), { custom: false })));
371
381
  const { shouldAddCustomOption, customOption } = generateCustomOption(allOptions, searchValue, canAddCustomOption);
372
382
  shouldAddCustomOption && allOptions.push(customOption);
373
383
  return allOptions;
374
384
  }
375
385
  function generateCustomOption(options, searchValue, canAddCustomOption) {
376
386
  function shouldAddCustomOption() {
377
- const isMatchingOption = options.some(option => option.label.toLowerCase() === searchValue.trim().toLowerCase());
387
+ const isMatchingOption = options === null || options === void 0 ? void 0 : options.some(option => option.label.toLowerCase() === searchValue.trim().toLowerCase());
378
388
  return !!searchValue && !isMatchingOption;
379
389
  }
380
390
  return {
@@ -472,7 +482,7 @@ function InternalChipDismissibleInput(props) {
472
482
  React__default["default"].createElement("input", { ref: inputRef, className: styles.input, type: "text", role: "combobox", "aria-label": "Press up and down arrow to cycle through the options or type to narrow down the results", "aria-autocomplete": "list", "aria-owns": menuId, "aria-expanded": hasAvailableOptions, "aria-activedescendant": generateDescendantId(activeIndex), value: searchValue, onChange: handleSearchChange, onKeyDown: handleKeyDown, onBlur: debounce__default["default"](handleBlur, 200), onFocus: handleOpenMenu, autoFocus: true }),
473
483
  (hasAvailableOptions || isLoadingMore) && (React__default["default"].createElement("div", Object.assign({ ref: setPositionedElementRef, className: styles.menu, style: popperStyles.popper }, attributes.popper),
474
484
  React__default["default"].createElement("div", { ref: menuRef, role: "listbox", id: menuId, className: styles.menuList, "data-testid": "chip-menu" },
475
- allOptions.map((option, i) => (React__default["default"].createElement("button", { key: option.value, role: "option", id: generateDescendantId(i), className: classnames__default["default"](styles.menuListOption, {
485
+ allOptions.map((option, i) => (React__default["default"].createElement("button", { key: option.value, role: "option", type: "button", id: generateDescendantId(i), className: classnames__default["default"](styles.menuListOption, {
476
486
  [styles.activeOption]: activeIndex === i,
477
487
  }), onClick: () => handleSelectOption(option), onMouseEnter: handleSetActiveOnMouseOver(i), onMouseDown: handleCancelBlur, onMouseUp: handleEnableBlur },
478
488
  React__default["default"].createElement("span", { "aria-hidden": true }, option.prefix),
@@ -483,10 +493,12 @@ function InternalChipDismissibleInput(props) {
483
493
  }
484
494
 
485
495
  function InternalChipDismissible(props) {
486
- const { availableChipOptions, ref: wrapperRef, sortedVisibleChipOptions, handleChipAdd, handleChipClick, handleChipKeyDown, handleChipRemove, handleCustomAdd, handleWrapperKeyDown, } = useInternalChipDismissible(props);
496
+ const { availableChipOptions, ref: wrapperRef, sortedVisibleChipOptions, handleChipAdd, handleChipKeyDown, handleChipRemove, handleCustomAdd, handleWrapperKeyDown, } = useInternalChipDismissible(props);
487
497
  return (React__default["default"].createElement("div", { ref: wrapperRef, className: styles.wrapper, "data-testid": "dismissible-chips", onKeyDown: handleWrapperKeyDown, role: "listbox" },
488
- sortedVisibleChipOptions.map(chip => (React__default["default"].createElement(InternalChip, Object.assign({ key: chip.value }, chip, { onKeyDown: handleChipKeyDown(chip.value), onClick: handleChipClick(chip.value), ariaLabel: `${chip.label}. Press delete or backspace to remove ${chip.label}`, tabIndex: 0, suffix: React__default["default"].createElement(InternalChipButton, { icon: "remove", invalid: chip.invalid, disabled: chip.disabled, label: chip.label, onClick: handleChipRemove(chip.value) }) })))),
489
- React__default["default"].createElement(InternalChipDismissibleInput, { activator: props.activator, attachTo: wrapperRef, isLoadingMore: props.isLoadingMore, options: availableChipOptions, onOptionSelect: handleChipAdd, onCustomOptionSelect: handleCustomAdd, onSearch: props.onSearch, onLoadMore: props.onLoadMore })));
498
+ sortedVisibleChipOptions.map(chip => (React__default["default"].createElement(ChipSelectable.Chip, Object.assign({ key: chip.value }, chip, { value: chip.label, onKeyDown: handleChipKeyDown(chip.value), onClick: handleChipRemove(chip.value), role: "radio", "data-testid": props.dataTestId || "remove-chip-button", ariaLabel: `${chip.label}. Press delete or backspace to remove ${chip.label}`, tabIndex: 0 }),
499
+ React__default["default"].createElement(ChipSelectable.Chip.Suffix, null,
500
+ React__default["default"].createElement(Icon.Icon, { name: "cross", size: "small" }))))),
501
+ React__default["default"].createElement(InternalChipDismissibleInput, { activator: props.activator, type: props.type, attachTo: wrapperRef, isLoadingMore: props.isLoadingMore, options: availableChipOptions || [], onOptionSelect: handleChipAdd, onCustomOptionSelect: handleCustomAdd, onSearch: props.onSearch, onLoadMore: props.onLoadMore })));
490
502
  }
491
503
 
492
504
  function Chips(props) {
@@ -496,19 +508,13 @@ function Chips(props) {
496
508
  case "multiselect":
497
509
  return React__default["default"].createElement(InternalChipMultiSelect, Object.assign({}, props));
498
510
  default:
499
- return React__default["default"].createElement(InternalChipSingleSelect, Object.assign({}, props));
511
+ return (React__default["default"].createElement(InternalChipSingleSelect, Object.assign({}, props, { type: "singleselect", selected: props.selected })));
500
512
  }
501
513
  }
502
514
 
503
- // Only need the component to pass in the data as a react children
504
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
505
- function Chip(props) {
506
- // Throw error when <Chip /> gets used outside of the <Chips />
507
- useAssert.useAssert(true, "`<Chip>` component can only be used inside `<Chips>`");
508
- return React__default["default"].createElement(React__default["default"].Fragment, null);
509
- }
510
-
511
- exports.Chip = Chip;
512
515
  exports.Chips = Chips;
513
516
  exports.InternalChip = InternalChip;
514
517
  exports.InternalChipButton = InternalChipButton;
518
+ exports.InternalChipDismissible = InternalChipDismissible;
519
+ exports.InternalChipMultiSelect = InternalChipMultiSelect;
520
+ exports.InternalChipSingleSelect = InternalChipSingleSelect;
@@ -4,6 +4,12 @@ import { ComboboxAction } from "./components/ComboboxAction";
4
4
  import { ComboboxTriggerButton, ComboboxTriggerChip } from "./components/ComboboxTrigger";
5
5
  export interface ComboboxProps {
6
6
  readonly children: ReactElement | ReactElement[];
7
+ /**
8
+ * When `true`, `Combobox` will allow for multiple selections
9
+ *
10
+ * @default false
11
+ */
12
+ readonly multiSelect?: boolean;
7
13
  }
8
14
  export declare const COMBOBOX_TRIGGER_COUNT_ERROR_MESSAGE = "Combobox can only have one Trigger element";
9
15
  export declare const COMBOBOX_REQUIRED_CHILDREN_ERROR_MESSAGE = "Combobox must have a Trigger and Combobox.Content element";
@@ -1,10 +1,12 @@
1
1
  import React, { RefObject } from "react";
2
2
  export declare const ComboboxContext: React.Context<{
3
+ multiselect: boolean;
3
4
  open: boolean;
4
5
  setOpen: (open: boolean) => void;
5
6
  wrapperRef: RefObject<HTMLDivElement>;
6
7
  }>;
7
8
  export interface ComboboxProviderProps {
8
9
  readonly children: React.ReactNode;
10
+ readonly multiselect?: boolean;
9
11
  }
10
12
  export declare function ComboboxContextProvider(props: ComboboxProviderProps): JSX.Element;
@@ -1,14 +1,24 @@
1
1
  import { ReactElement } from "react";
2
+ import { XOR } from "ts-xor";
2
3
  import { ComboboxOption } from "../../Combobox.types";
3
- interface ComboboxContentProps {
4
+ interface ComboboxCloseProps {
4
5
  /**
5
- * List of selectable options to display.
6
+ * Callback function invoked upon the selection of an option. Provides the selected option(s) as an argument.
6
7
  */
7
- readonly options: ComboboxOption[];
8
+ readonly onSelect: (selection: ComboboxOption[]) => void;
9
+ }
10
+ interface ComoboboxSelectProps {
11
+ /**
12
+ *
13
+ * Callback function invoked upon the Combobox menu closing. Provides the selected option(s) as an argument.
14
+ */
15
+ readonly onClose: (selection: ComboboxOption[]) => void;
16
+ }
17
+ interface ComboboxContentBaseProps {
8
18
  /**
9
- * Callback function invoked upon the selection of an option. Provides the selected option as an argument.
19
+ * List of selectable options to display.
10
20
  */
11
- readonly onSelect: (selection: ComboboxOption) => void;
21
+ readonly options: ComboboxOption[];
12
22
  /**
13
23
  * Optional action button(s) to display at the bottom of the list.
14
24
  */
@@ -22,12 +32,13 @@ interface ComboboxContentProps {
22
32
  * @default ""
23
33
  * @type string
24
34
  */
25
- readonly selected: ComboboxOption | null;
35
+ readonly selected: ComboboxOption[];
26
36
  /**
27
37
  * The encapsulating noun for the content of the combobox. Used
28
38
  * in the empty state, and search placeholder. Should be pluralized.
29
39
  */
30
40
  readonly subjectNoun?: string;
31
41
  }
42
+ type ComboboxContentProps = ComboboxContentBaseProps & XOR<ComboboxCloseProps, ComoboboxSelectProps>;
32
43
  export declare function ComboboxContent(props: ComboboxContentProps): JSX.Element;
33
44
  export {};
@@ -1,14 +1,15 @@
1
1
  import React, { SetStateAction } from "react";
2
2
  import { ComboboxOption } from "../../Combobox.types";
3
3
  interface ComboboxListProps {
4
- options: ComboboxOption[];
5
- showEmptyState: boolean;
6
- selected: ComboboxOption | null;
7
- optionsListRef: React.RefObject<HTMLUListElement>;
8
- setSelectedElement: React.Dispatch<SetStateAction<HTMLElement | null>>;
9
- selectionHandler: (option: ComboboxOption) => void;
10
- searchValue: string;
11
- subjectNoun?: string;
4
+ readonly options: ComboboxOption[];
5
+ readonly showEmptyState: boolean;
6
+ readonly selected: ComboboxOption[];
7
+ readonly optionsListRef: React.RefObject<HTMLUListElement>;
8
+ readonly setFirstSelectedElement: React.Dispatch<SetStateAction<HTMLElement | null>>;
9
+ readonly selectionHandler: (option: ComboboxOption) => void;
10
+ readonly searchValue: string;
11
+ readonly multiselect: boolean;
12
+ readonly subjectNoun?: string;
12
13
  }
13
14
  export declare function ComboboxList(props: ComboboxListProps): JSX.Element;
14
15
  export {};
@@ -1,7 +1,7 @@
1
1
  import { Dispatch, SetStateAction } from "react";
2
2
  export declare function ComboboxSearch(props: {
3
- placeholder?: string;
4
- searchValue: string;
5
- open: boolean;
6
- setSearchValue: Dispatch<SetStateAction<string>>;
3
+ readonly placeholder?: string;
4
+ readonly searchValue: string;
5
+ readonly open: boolean;
6
+ readonly setSearchValue: Dispatch<SetStateAction<string>>;
7
7
  }): JSX.Element;
@@ -1,9 +1,13 @@
1
1
  /// <reference types="react" />
2
2
  import { ComboboxOption } from "../Combobox.types";
3
- export declare function useComboboxContent(options: ComboboxOption[], open: boolean): {
3
+ interface useComboboxContent {
4
4
  searchValue: string;
5
5
  setSearchValue: React.Dispatch<React.SetStateAction<string>>;
6
- setSelectedElement: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
6
+ setFirstSelectedElement: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
7
7
  filteredOptions: ComboboxOption[];
8
8
  optionsListRef: React.RefObject<HTMLUListElement>;
9
- };
9
+ selectedOptions: ComboboxOption[];
10
+ setInternalSelected: (selected: ComboboxOption[]) => void;
11
+ }
12
+ export declare function useComboboxContent(options: ComboboxOption[], open: boolean, selected: ComboboxOption[], onClose: ((selection: ComboboxOption[]) => void) | undefined): useComboboxContent;
13
+ export {};
@@ -8,13 +8,13 @@ var classnames = require('classnames');
8
8
  var ReactDOM = require('react-dom');
9
9
  var styleInject_es = require('../style-inject.es-9d2f5f4e.js');
10
10
  var Icon = require('../Icon-405a216c.js');
11
- var Text = require('../Text-59bde58c.js');
11
+ var Text = require('../Text-54334431.js');
12
12
  var useRefocusOnActivator = require('@jobber/hooks/useRefocusOnActivator');
13
13
  var useFocusTrap = require('@jobber/hooks/useFocusTrap');
14
14
  var reactPopper = require('react-popper');
15
15
  var useOnKeyDown = require('@jobber/hooks/useOnKeyDown');
16
- var Typography = require('../Typography-9bff9c91.js');
17
- var Button = require('../Button-d89f2271.js');
16
+ var Typography = require('../Typography-83915c54.js');
17
+ var Button = require('../Button-db6114a6.js');
18
18
  require('@jobber/design');
19
19
  require('react-router-dom');
20
20
 
@@ -24,11 +24,11 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
24
24
  var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
25
25
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
26
26
 
27
- var css_248z$5 = ".m1w5vdUZ6rQ- {\n z-index: 1002;\n z-index: var(--elevation-tooltip);\n max-width: var(--popover--width);\n min-width: calc((16px * 4) * 3.75);\n min-width: calc(calc(16px * 4) * 3.75);\n min-width: calc(var(--space-extravagant) * 3.75);\n box-shadow: 0px calc(16px / 16) calc(16px / 4) 0px\n rgba(0, 0, 0, 0.1),\n 0px calc(16px / 4) 12px 0px rgba(0, 0, 0, 0.05);\n box-shadow: var(--shadow-base);\n margin-top: calc(16px / 2);\n margin-top: var(--space-small);\n border: calc(16px / 16) solid rgb(225, 225, 225);\n border: var(--border-base) solid var(--color-border);\n border-radius: calc(16px / 2);\n border-radius: var(--radius-larger);\n overflow: scroll;\n overflow-y: auto;\n background: rgba(255, 255, 255, 1);\n background: var(--color-surface);\n}\n\n/* CAUTION: Tests for content visibility assume this class' presence hides the content\n* so please be careful if you change this class name, or the css rules within.\n*/\n\n.m1w5vdUZ6rQ-.Zlkv2HA096A- {\n display: none;\n visibility: hidden;\n}\n\n.YQry-Rd6zfQ-::before {\n content: \"\";\n display: block;\n position: absolute;\n top: calc((16px * 1.5) * -1);\n top: calc(calc(16px * 1.5) * -1);\n top: calc(var(--space-large) * -1);\n right: 0;\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgb(255, 255, 255) 100%\n );\n}\n\n.YQry-Rd6zfQ- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n position: sticky;\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n bottom: 0;\n width: 100%;\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n.TcpqL34s4lI- {\n padding-bottom: calc(16px / 2);\n padding-bottom: var(--space-small);\n}\n";
27
+ var css_248z$5 = ".m1w5vdUZ6rQ- {\n z-index: 1002;\n z-index: var(--elevation-tooltip);\n max-width: var(--popover--width);\n min-width: calc((16px * 4) * 3.75);\n min-width: calc(calc(16px * 4) * 3.75);\n min-width: calc(var(--space-extravagant) * 3.75);\n box-shadow: 0px calc(16px / 16) calc(16px / 4) 0px\n rgba(0, 0, 0, 0.1),\n 0px calc(16px / 4) 12px 0px rgba(0, 0, 0, 0.05);\n box-shadow: var(--shadow-base);\n margin-top: calc(16px / 2);\n margin-top: var(--space-small);\n border: calc(16px / 16) solid rgb(225, 225, 225);\n border: var(--border-base) solid var(--color-border);\n border-radius: calc(16px / 2);\n border-radius: var(--radius-larger);\n overflow: scroll;\n overflow-y: auto;\n background: rgba(255, 255, 255, 1);\n background: var(--color-surface);\n}\n\n/* CAUTION: Tests for content visibility assume this class' presence hides the content\n* so please be careful if you change this class name, or the css rules within.\n*/\n\n.m1w5vdUZ6rQ-.Zlkv2HA096A- {\n display: none;\n visibility: hidden;\n}\n\n.YQry-Rd6zfQ- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n position: sticky;\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n bottom: 0;\n width: 100%;\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n.TcpqL34s4lI- {\n padding-bottom: calc(16px / 2);\n padding-bottom: var(--space-small);\n}\n";
28
28
  var styles$5 = {"content":"m1w5vdUZ6rQ-","hidden":"Zlkv2HA096A-","actions":"YQry-Rd6zfQ-","actionPadding":"TcpqL34s4lI-"};
29
29
  styleInject_es.styleInject(css_248z$5);
30
30
 
31
- var css_248z$4 = ".ifwwZOYTf8U- {\n position: relative;\n}\n\n.gIbHknFkZLI- {\n width: 100%;\n padding: calc(16px * 1);\n padding: var(--space-base);\n padding-right: calc((16px * 1.5) * 2.25);\n padding-right: calc(calc(16px * 1.5) * 2.25);\n padding-right: calc(var(--space-large) * 2.25);\n border: none;\n border-bottom: calc(16px / 16) solid rgb(225, 225, 225);\n border-bottom: var(--border-base) solid var(--color-border);\n font-family: \"Inter\", Helvetica, Arial, sans-serif;\n font-family: var(--typography--fontFamily-normal);\n font-size: calc((16px * 1) * 0.875);\n font-size: calc(calc(16px * 1) * 0.875);\n font-size: var(--typography--fontSize-base);\n}\n\n.dZmEG-amk2U- {\n position: absolute;\n top: 50%;\n right: calc(16px * 1);\n right: var(--space-base);\n z-index: 1002;\n z-index: var(--elevation-tooltip);\n width: calc(16px * 1.5);\n width: var(--space-large);\n height: calc(16px * 1.5);\n height: var(--space-large);\n padding: 0;\n border: none;\n border-radius: 100%;\n border-radius: var(--radius-circle);\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n cursor: pointer;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n}\n\n.dZmEG-amk2U-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n}\n\n.ifwwZOYTf8U-::after {\n content: \"\";\n display: block;\n position: absolute;\n right: 0;\n bottom: calc((16px * 1.5) * -1);\n bottom: calc(calc(16px * 1.5) * -1);\n bottom: calc(var(--space-large) * -1);\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n background-image: linear-gradient(\n to bottom,\n rgba(255, 255, 255, 1),\n rgba(255, 255, 255, 0)\n );\n}\n";
31
+ var css_248z$4 = ".ifwwZOYTf8U- {\n position: relative;\n}\n\n.gIbHknFkZLI- {\n width: 100%;\n padding: calc(16px * 1);\n padding: var(--space-base);\n padding-right: calc((16px * 1.5) * 2.25);\n padding-right: calc(calc(16px * 1.5) * 2.25);\n padding-right: calc(var(--space-large) * 2.25);\n border: none;\n border-bottom: calc(16px / 16) solid rgb(225, 225, 225);\n border-bottom: var(--border-base) solid var(--color-border);\n font-family: \"Inter\", Helvetica, Arial, sans-serif;\n font-family: var(--typography--fontFamily-normal);\n font-size: calc((16px * 1) * 0.875);\n font-size: calc(calc(16px * 1) * 0.875);\n font-size: var(--typography--fontSize-base);\n}\n\n.dZmEG-amk2U- {\n position: absolute;\n top: 50%;\n right: calc(16px * 1);\n right: var(--space-base);\n z-index: 1002;\n z-index: var(--elevation-tooltip);\n width: calc(16px * 1.5);\n width: var(--space-large);\n height: calc(16px * 1.5);\n height: var(--space-large);\n padding: 0;\n border: none;\n border-radius: 100%;\n border-radius: var(--radius-circle);\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n cursor: pointer;\n -webkit-transform: translateY(-50%);\n transform: translateY(-50%);\n}\n\n.dZmEG-amk2U-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n}\n";
32
32
  var styles$4 = {"search":"ifwwZOYTf8U-","searchInput":"gIbHknFkZLI-","clearSearch":"dZmEG-amk2U-"};
33
33
  styleInject_es.styleInject(css_248z$4);
34
34
 
@@ -44,7 +44,7 @@ function ComboboxSearch(props) {
44
44
  }, [props.open]);
45
45
  return (React__default["default"].createElement("div", { className: styles$4.search },
46
46
  React__default["default"].createElement("input", { type: "search", ref: searchRef, className: styles$4.searchInput, placeholder: props.placeholder ? `Search ${props.placeholder}` : "Search", onChange: (event) => handleSearch(event), value: props.searchValue }),
47
- props.searchValue && (React__default["default"].createElement("button", { className: styles$4.clearSearch, onClick: clearSearch, "data-testid": "ATL-Combobox-Content-Search-Clear", "aria-label": "Clear search" },
47
+ props.searchValue && (React__default["default"].createElement("button", { className: styles$4.clearSearch, onClick: clearSearch, type: "button", "data-testid": "ATL-Combobox-Content-Search-Clear", "aria-label": "Clear search" },
48
48
  React__default["default"].createElement(Icon.Icon, { name: "remove", size: "small" })))));
49
49
  function clearSearch() {
50
50
  var _a;
@@ -56,22 +56,22 @@ function ComboboxSearch(props) {
56
56
  }
57
57
  }
58
58
 
59
- var css_248z$3 = "._5n7VvEn39-Y- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n\n.KhX5VfZjAog- {\n display: -ms-flexbox;\n display: flex;\n max-height: calc((16px / 2) * 33.33);\n max-height: calc(calc(16px / 2) * 33.33);\n max-height: calc(var(--space-small) * 33.33);\n margin: 0;\n padding: 0;\n overflow: scroll;\n list-style: none;\n -ms-flex-direction: column;\n flex-direction: column;\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n}\n\n.NNCJVHYx6lc- {\n display: -ms-flexbox;\n display: flex;\n min-height: calc((calc(16px * 3) - calc(16px / 4)));\n min-height: calc((var(--space-largest) - var(--space-smaller)));\n box-sizing: border-box;\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-radius: calc(16px / 4);\n border-radius: var(--radius-large);\n color: rgb(1, 41, 57);\n color: var(--color-heading);\n font-weight: 500;\n cursor: pointer;\n -ms-flex-pack: justify;\n justify-content: space-between;\n -ms-flex-align: center;\n align-items: center;\n transition: all 200ms;\n transition: all var(--timing-base);\n}\n\n.IvTItlT0MOQ-,\n.NNCJVHYx6lc-:hover,\n.NNCJVHYx6lc-:focus {\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n}\n\n.NNCJVHYx6lc-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n}\n\n._2IRm1sf-TUU-,\n.DTuoA8WPNzc- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n";
60
- var styles$3 = {"container":"_5n7VvEn39-Y-","optionsList":"KhX5VfZjAog-","option":"NNCJVHYx6lc-","selectedOption":"IvTItlT0MOQ-","filterMessage":"_2IRm1sf-TUU-","emptyStateMessage":"DTuoA8WPNzc-"};
59
+ var css_248z$3 = "._5n7VvEn39-Y- {\n position: relative;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n}\n\n.KhX5VfZjAog- {\n display: -ms-flexbox;\n display: flex;\n max-height: calc((16px / 2) * 33.33);\n max-height: calc(calc(16px / 2) * 33.33);\n max-height: calc(var(--space-small) * 33.33);\n margin: 0;\n padding: 0;\n overflow: scroll;\n list-style: none;\n -ms-flex-direction: column;\n flex-direction: column;\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n}\n\n.NNCJVHYx6lc- {\n display: -ms-flexbox;\n display: flex;\n min-height: calc((calc(16px * 3) - calc(16px / 4)));\n min-height: calc((var(--space-largest) - var(--space-smaller)));\n box-sizing: border-box;\n margin: 0 calc(16px / 2);\n margin: 0 var(--space-small);\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-radius: calc(16px / 4);\n border-radius: var(--radius-large);\n color: rgb(1, 41, 57);\n color: var(--color-heading);\n font-weight: 500;\n cursor: pointer;\n transition: all 200ms;\n transition: all var(--timing-base);\n -ms-flex-pack: justify;\n justify-content: space-between;\n -ms-flex-align: center;\n align-items: center;\n}\n\n.NNCJVHYx6lc-:hover,\n.NNCJVHYx6lc-:focus {\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n}\n\n.NNCJVHYx6lc-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n}\n\n._2IRm1sf-TUU-,\n.DTuoA8WPNzc- {\n padding: calc(16px / 2) calc(16px * 1);\n padding: var(--space-small) var(--space-base);\n}\n\n._5n7VvEn39-Y-::after {\n content: \"\";\n display: block;\n position: absolute;\n right: 0;\n bottom: calc(16px / 2);\n bottom: var(--space-small);\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgb(255, 255, 255) 100%\n );\n}\n\n._5n7VvEn39-Y-::before {\n content: \"\";\n display: block;\n position: absolute;\n top: calc(16px / 2);\n top: var(--space-small);\n right: 0;\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n background: linear-gradient(\n to bottom,\n rgba(255, 255, 255, 1),\n rgba(255, 255, 255, 0)\n );\n}\n";
60
+ var styles$3 = {"container":"_5n7VvEn39-Y-","optionsList":"KhX5VfZjAog-","option":"NNCJVHYx6lc-","filterMessage":"_2IRm1sf-TUU-","emptyStateMessage":"DTuoA8WPNzc-"};
61
61
  styleInject_es.styleInject(css_248z$3);
62
62
 
63
63
  function ComboboxList(props) {
64
+ let hasSeenFirstSelected = false;
64
65
  return (React__default["default"].createElement("div", { className: styles$3.container },
65
- !props.showEmptyState && props.options.length > 0 && (React__default["default"].createElement("ul", { className: styles$3.optionsList, role: "listbox", ref: props.optionsListRef }, !props.showEmptyState &&
66
+ !props.showEmptyState && props.options.length > 0 && (React__default["default"].createElement("ul", { className: styles$3.optionsList, role: "listbox", "aria-multiselectable": props.multiselect, ref: props.optionsListRef }, !props.showEmptyState &&
66
67
  props.options.map(option => {
67
- var _a;
68
- const isSelected = option.id.toString() === ((_a = props.selected) === null || _a === void 0 ? void 0 : _a.id.toString());
68
+ const isSelected = props.selected.some(selection => selection.id.toString() === option.id.toString());
69
69
  return (React__default["default"].createElement("li", { ref: listItem => {
70
- if (isSelected)
71
- props.setSelectedElement(listItem);
72
- }, key: option.id, tabIndex: -1, role: "option", "aria-selected": isSelected, onClick: () => props.selectionHandler(option), className: classnames__default["default"](styles$3.option, {
73
- [styles$3.selectedOption]: isSelected,
74
- }) },
70
+ if (isSelected && !hasSeenFirstSelected) {
71
+ props.setFirstSelectedElement(listItem);
72
+ hasSeenFirstSelected = true;
73
+ }
74
+ }, key: option.id, tabIndex: -1, role: "option", "aria-selected": isSelected, onClick: () => props.selectionHandler(option), className: classnames__default["default"](styles$3.option) },
75
75
  option.label,
76
76
  isSelected && React__default["default"].createElement(Icon.Icon, { name: "checkmark", color: "blue" })));
77
77
  }))),
@@ -95,32 +95,47 @@ styleInject_es.styleInject(css_248z$2);
95
95
 
96
96
  const ComboboxContext = React__default["default"].createContext({});
97
97
  function ComboboxContextProvider(props) {
98
+ const multiselect = props.multiselect || false;
98
99
  const [open, setOpen] = React.useState(false);
99
100
  const wrapperRef = React.useRef(null);
100
- return (React__default["default"].createElement(ComboboxContext.Provider, { value: { open, setOpen, wrapperRef } },
101
+ return (React__default["default"].createElement(ComboboxContext.Provider, { value: { multiselect, open, setOpen, wrapperRef } },
101
102
  React__default["default"].createElement("div", { ref: wrapperRef },
102
103
  open && (React__default["default"].createElement("div", { className: styles$2.overlay, onClick: () => setOpen(false), "data-testid": "ATL-Combobox-Overlay" })),
103
104
  props.children)));
104
105
  }
105
106
 
106
- function useComboboxContent(options, open) {
107
+ function useComboboxContent(options, open, selected, onClose) {
107
108
  const [searchValue, setSearchValue] = React.useState("");
108
- const [selectedElement, setSelectedElement] = React.useState(null);
109
+ const [firstSelectedElement, setFirstSelectedElement] = React.useState(null);
109
110
  const optionsListRef = React.useRef(null);
110
111
  const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchValue.toLowerCase()));
112
+ const [internalSelected, setInternalSelected] = React.useState(selected);
113
+ const selectedOptions = onClose ? internalSelected : selected;
114
+ React.useEffect(() => {
115
+ if (!open && onClose) {
116
+ onClose(selectedOptions);
117
+ }
118
+ }, [open, onClose, selectedOptions]);
111
119
  React.useEffect(() => {
112
- if (open && selectedElement) {
113
- selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.scrollIntoView({
120
+ if (open && firstSelectedElement) {
121
+ firstSelectedElement === null || firstSelectedElement === void 0 ? void 0 : firstSelectedElement.scrollIntoView({
114
122
  block: "nearest",
115
123
  });
116
124
  }
117
- }, [open, selectedElement]);
125
+ }, [open, firstSelectedElement]);
126
+ React.useEffect(() => {
127
+ if (selectedOptions.length === 0) {
128
+ setFirstSelectedElement(null);
129
+ }
130
+ }, [selectedOptions]);
118
131
  return {
119
132
  searchValue,
120
133
  setSearchValue,
121
- setSelectedElement,
134
+ setFirstSelectedElement,
122
135
  filteredOptions,
123
136
  optionsListRef,
137
+ selectedOptions,
138
+ setInternalSelected,
124
139
  };
125
140
  }
126
141
 
@@ -201,23 +216,42 @@ function useComboboxAccessibility(selectionCallback, filteredOptions, optionsLis
201
216
  }
202
217
 
203
218
  function ComboboxContent(props) {
204
- const { open, setOpen, wrapperRef } = React__default["default"].useContext(ComboboxContext);
219
+ const { open, setOpen, wrapperRef, multiselect } = React__default["default"].useContext(ComboboxContext);
205
220
  const optionsExist = props.options.length > 0;
206
- const { searchValue, setSearchValue, setSelectedElement, filteredOptions, optionsListRef, } = useComboboxContent(props.options, open);
221
+ const { searchValue, setSearchValue, setFirstSelectedElement, filteredOptions, optionsListRef, selectedOptions, setInternalSelected, } = useComboboxContent(props.options, open, props.selected, props.onClose);
207
222
  const { popperRef, popperStyles, attributes } = useComboboxAccessibility(handleSelection, filteredOptions, optionsListRef, open, setOpen, wrapperRef);
208
223
  const template = (React__default["default"].createElement("div", Object.assign({ ref: popperRef, id: "ATL-Combobox-Content", "data-testid": "ATL-Combobox-Content", tabIndex: 0, className: classnames__default["default"](styles$5.content, { [styles$5.hidden]: !open }), style: popperStyles.popper }, attributes.popper),
209
224
  React__default["default"].createElement(ComboboxSearch, { open: open, placeholder: props.subjectNoun, searchValue: searchValue, setSearchValue: setSearchValue }),
210
- React__default["default"].createElement(ComboboxList, { showEmptyState: !optionsExist, options: filteredOptions, selected: props.selected, optionsListRef: optionsListRef, setSelectedElement: setSelectedElement, selectionHandler: handleSelection, searchValue: searchValue, subjectNoun: props.subjectNoun }),
225
+ React__default["default"].createElement(ComboboxList, { multiselect: multiselect, showEmptyState: !optionsExist, options: filteredOptions, selected: selectedOptions, optionsListRef: optionsListRef, setFirstSelectedElement: setFirstSelectedElement, selectionHandler: handleSelection, searchValue: searchValue, subjectNoun: props.subjectNoun }),
211
226
  props.children && (React__default["default"].createElement("div", { className: styles$5.actions, role: "group" }, React__default["default"].Children.toArray(props.children).map((child, index, childrenArray) => (React__default["default"].createElement("div", { key: index, className: classnames__default["default"]({
212
227
  [styles$5.actionPadding]: index === childrenArray.length - 1,
213
228
  }) }, child)))))));
214
229
  return ReactDOM__default["default"].createPortal(template, document.body);
215
230
  function handleSelection(selection) {
216
- props.onSelect(selection);
231
+ const callbackHandler = props.onSelect
232
+ ? props.onSelect
233
+ : setInternalSelected;
234
+ if (multiselect) {
235
+ handleMultiSelect(callbackHandler, selectedOptions, selection);
236
+ }
237
+ else {
238
+ handleSingleSelect(callbackHandler, selection);
239
+ }
240
+ }
241
+ function handleSingleSelect(selectCallback, selection) {
242
+ selectCallback([selection]);
217
243
  setSearchValue("");
218
244
  setOpen(false);
219
245
  }
220
246
  }
247
+ function handleMultiSelect(selectCallback, selected, selection) {
248
+ if (selected.some(s => s.id === selection.id)) {
249
+ selectCallback(selected.filter(s => s.id !== selection.id));
250
+ }
251
+ else {
252
+ selectCallback([...selected, selection]);
253
+ }
254
+ }
221
255
 
222
256
  var css_248z$1 = ".Ow9wSNnGP-g- {\n width: 100%;\n box-sizing: border-box;\n padding: 0 calc(16px / 2);\n padding: 0 var(--space-small);\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n.ncp0nKHQ7d8- {\n position: relative;\n width: 100%;\n min-height: calc((calc(16px * 3) - calc(16px / 2)));\n min-height: calc((var(--space-largest) - var(--space-small)));\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n border: none;\n border-radius: calc(16px / 4);\n border-radius: var(--radius-large);\n text-align: left;\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n cursor: pointer;\n transition: all 200ms;\n transition: all var(--timing-base);\n}\n\n.ncp0nKHQ7d8-:focus {\n box-shadow: 0px 0px calc(16px / 4) calc(16px / 8)\n rgb(231, 213, 87);\n box-shadow: var(--shadow-focus);\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n}\n\n.ncp0nKHQ7d8-:hover {\n background-color: rgb(244, 244, 244);\n background-color: var(--color-surface--background);\n}\n\n.ncp0nKHQ7d8- span {\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n";
223
257
  var styles$1 = {"actionContainer":"Ow9wSNnGP-g-","actionButton":"ncp0nKHQ7d8-"};
@@ -225,7 +259,7 @@ styleInject_es.styleInject(css_248z$1);
225
259
 
226
260
  function ComboboxAction(props) {
227
261
  return (React__default["default"].createElement("div", { className: styles$1.actionContainer },
228
- React__default["default"].createElement("button", { className: styles$1.actionButton, onClick: props.onClick, "aria-label": props.label },
262
+ React__default["default"].createElement("button", { className: styles$1.actionButton, onClick: props.onClick, type: "button", "aria-label": props.label },
229
263
  React__default["default"].createElement(Typography.Typography, { element: "span", size: "base", textColor: "green", fontWeight: "semiBold" }, props.label))));
230
264
  }
231
265
 
@@ -240,7 +274,7 @@ styleInject_es.styleInject(css_248z);
240
274
 
241
275
  function ComboboxTriggerChip(props) {
242
276
  const { open, setOpen } = React__default["default"].useContext(ComboboxContext);
243
- return (React__default["default"].createElement("button", { className: styles.trigger, role: "combobox", "aria-expanded": open, "aria-haspopup": "listbox", "aria-controls": "ATL-Combobox-Content", "aria-autocomplete": "list", onClick: () => {
277
+ return (React__default["default"].createElement("button", { className: styles.trigger, role: "combobox", type: "button", "aria-expanded": open, "aria-haspopup": "listbox", "aria-controls": "ATL-Combobox-Content", "aria-autocomplete": "list", onClick: () => {
244
278
  setOpen(!open);
245
279
  } },
246
280
  React__default["default"].createElement(Typography.Typography, { fontWeight: "semiBold", textColor: "heading" }, props.label),
@@ -252,7 +286,7 @@ const COMBOBOX_TRIGGER_COUNT_ERROR_MESSAGE = "Combobox can only have one Trigger
252
286
  const COMBOBOX_REQUIRED_CHILDREN_ERROR_MESSAGE = "Combobox must have a Trigger and Combobox.Content element";
253
287
  const Combobox = (props) => {
254
288
  const { contentElement, triggerElement } = useComboboxValidation(props.children);
255
- return (React__default["default"].createElement(ComboboxContextProvider, null,
289
+ return (React__default["default"].createElement(ComboboxContextProvider, { multiselect: props.multiSelect },
256
290
  triggerElement,
257
291
  contentElement));
258
292
  };