@jobber/components 4.46.0 → 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 (107) 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/components/ComboboxContent/ComboboxContent.d.ts +17 -6
  36. package/dist/Combobox/components/ComboboxContent/ComboboxList.d.ts +9 -8
  37. package/dist/Combobox/components/ComboboxContent/ComboboxSearch.d.ts +4 -4
  38. package/dist/Combobox/hooks/useComboboxContent.d.ts +7 -3
  39. package/dist/Combobox/index.js +61 -28
  40. package/dist/ConfirmationModal/index.js +9 -9
  41. package/dist/{ConfirmationModal-92f07027.js → ConfirmationModal-285c3cbe.js} +2 -2
  42. package/dist/DataDump/index.js +6 -6
  43. package/dist/DataList/DataList.types.d.ts +9 -1
  44. package/dist/DataList/components/DataListSearch/DataListSearch.d.ts +1 -1
  45. package/dist/DataList/index.js +47 -24
  46. package/dist/DataTable/index.js +6 -6
  47. package/dist/DatePicker/index.js +3 -3
  48. package/dist/{DatePicker-39d2dc8b.js → DatePicker-49213434.js} +2 -2
  49. package/dist/DescriptionList/index.js +1 -1
  50. package/dist/Disclosure/index.js +1 -1
  51. package/dist/Drawer/index.js +4 -4
  52. package/dist/Emphasis/index.js +2 -2
  53. package/dist/{Emphasis-cc3456ac.js → Emphasis-e10dde65.js} +1 -1
  54. package/dist/FeatureSwitch/index.js +7 -7
  55. package/dist/FormField/index.js +5 -5
  56. package/dist/{FormField-bef41ec9.js → FormField-fa9254dc.js} +3 -3
  57. package/dist/FormatFile/index.js +10 -10
  58. package/dist/{FormatFile-a470c0f2.js → FormatFile-6423c3b5.js} +4 -4
  59. package/dist/Gallery/index.js +11 -11
  60. package/dist/Heading/index.js +2 -2
  61. package/dist/{Heading-4562900a.js → Heading-4cde9989.js} +1 -1
  62. package/dist/InlineLabel/index.js +2 -2
  63. package/dist/{InlineLabel-3d461632.js → InlineLabel-a24706c4.js} +1 -1
  64. package/dist/InputAvatar/index.js +3 -3
  65. package/dist/InputDate/index.js +6 -6
  66. package/dist/InputEmail/index.js +5 -5
  67. package/dist/InputFile/index.js +3 -3
  68. package/dist/{InputFile-d327dee3.js → InputFile-25c3369b.js} +2 -2
  69. package/dist/InputNumber/index.js +6 -6
  70. package/dist/{InputNumber-5640fb55.js → InputNumber-ea9fcee1.js} +1 -1
  71. package/dist/InputPassword/index.js +5 -5
  72. package/dist/InputPhoneNumber/index.js +5 -5
  73. package/dist/InputText/index.js +6 -6
  74. package/dist/{InputText-5ac5cfe0.js → InputText-ab237501.js} +1 -1
  75. package/dist/InputTime/index.js +5 -5
  76. package/dist/InputValidation/index.js +3 -3
  77. package/dist/{InputValidation-4e809bdd.js → InputValidation-377d6c62.js} +1 -1
  78. package/dist/LightBox/index.js +4 -4
  79. package/dist/{LightBox-02ca409e.js → LightBox-93ef99b9.js} +2 -2
  80. package/dist/List/index.js +5 -5
  81. package/dist/Markdown/index.js +5 -5
  82. package/dist/{Markdown-b37cf9ec.js → Markdown-d53b01bf.js} +3 -3
  83. package/dist/Menu/index.js +3 -3
  84. package/dist/{Menu-cec53b50.js → Menu-2e64307a.js} +2 -2
  85. package/dist/Modal/index.js +5 -5
  86. package/dist/{Modal-dcdc0032.js → Modal-c17cc105.js} +3 -3
  87. package/dist/MultiSelect/index.js +3 -3
  88. package/dist/{Option-9f4a65da.js → Option-07a24acd.js} +1 -1
  89. package/dist/Page/index.js +7 -7
  90. package/dist/Popover/index.js +4 -4
  91. package/dist/{Popover-d401fb54.js → Popover-7c966790.js} +1 -1
  92. package/dist/RadioGroup/index.js +3 -3
  93. package/dist/{RadioGroup-46833fac.js → RadioGroup-9bdd8a59.js} +1 -1
  94. package/dist/RecurringSelect/index.js +8 -8
  95. package/dist/Select/index.js +6 -6
  96. package/dist/StatusLabel/index.js +2 -2
  97. package/dist/Switch/index.js +2 -2
  98. package/dist/{Switch-165f01e3.js → Switch-cc9b645c.js} +1 -1
  99. package/dist/Tabs/index.js +1 -1
  100. package/dist/Text/index.js +2 -2
  101. package/dist/{Text-59bde58c.js → Text-54334431.js} +1 -1
  102. package/dist/Toast/index.js +2 -2
  103. package/dist/Tooltip/index.js +3 -3
  104. package/dist/{Tooltip-59dbab5b.js → Tooltip-d5257798.js} +1 -1
  105. package/dist/Typography/index.js +1 -1
  106. package/dist/{Typography-9bff9c91.js → Typography-83915c54.js} +2 -2
  107. 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;
@@ -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
  }))),
@@ -104,24 +104,38 @@ function ComboboxContextProvider(props) {
104
104
  props.children)));
105
105
  }
106
106
 
107
- function useComboboxContent(options, open) {
107
+ function useComboboxContent(options, open, selected, onClose) {
108
108
  const [searchValue, setSearchValue] = React.useState("");
109
- const [selectedElement, setSelectedElement] = React.useState(null);
109
+ const [firstSelectedElement, setFirstSelectedElement] = React.useState(null);
110
110
  const optionsListRef = React.useRef(null);
111
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]);
112
119
  React.useEffect(() => {
113
- if (open && selectedElement) {
114
- selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.scrollIntoView({
120
+ if (open && firstSelectedElement) {
121
+ firstSelectedElement === null || firstSelectedElement === void 0 ? void 0 : firstSelectedElement.scrollIntoView({
115
122
  block: "nearest",
116
123
  });
117
124
  }
118
- }, [open, selectedElement]);
125
+ }, [open, firstSelectedElement]);
126
+ React.useEffect(() => {
127
+ if (selectedOptions.length === 0) {
128
+ setFirstSelectedElement(null);
129
+ }
130
+ }, [selectedOptions]);
119
131
  return {
120
132
  searchValue,
121
133
  setSearchValue,
122
- setSelectedElement,
134
+ setFirstSelectedElement,
123
135
  filteredOptions,
124
136
  optionsListRef,
137
+ selectedOptions,
138
+ setInternalSelected,
125
139
  };
126
140
  }
127
141
 
@@ -202,23 +216,42 @@ function useComboboxAccessibility(selectionCallback, filteredOptions, optionsLis
202
216
  }
203
217
 
204
218
  function ComboboxContent(props) {
205
- const { open, setOpen, wrapperRef } = React__default["default"].useContext(ComboboxContext);
219
+ const { open, setOpen, wrapperRef, multiselect } = React__default["default"].useContext(ComboboxContext);
206
220
  const optionsExist = props.options.length > 0;
207
- 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);
208
222
  const { popperRef, popperStyles, attributes } = useComboboxAccessibility(handleSelection, filteredOptions, optionsListRef, open, setOpen, wrapperRef);
209
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),
210
224
  React__default["default"].createElement(ComboboxSearch, { open: open, placeholder: props.subjectNoun, searchValue: searchValue, setSearchValue: setSearchValue }),
211
- 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 }),
212
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"]({
213
227
  [styles$5.actionPadding]: index === childrenArray.length - 1,
214
228
  }) }, child)))))));
215
229
  return ReactDOM__default["default"].createPortal(template, document.body);
216
230
  function handleSelection(selection) {
217
- 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]);
218
243
  setSearchValue("");
219
244
  setOpen(false);
220
245
  }
221
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
+ }
222
255
 
223
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";
224
257
  var styles$1 = {"actionContainer":"Ow9wSNnGP-g-","actionButton":"ncp0nKHQ7d8-"};
@@ -226,7 +259,7 @@ styleInject_es.styleInject(css_248z$1);
226
259
 
227
260
  function ComboboxAction(props) {
228
261
  return (React__default["default"].createElement("div", { className: styles$1.actionContainer },
229
- 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 },
230
263
  React__default["default"].createElement(Typography.Typography, { element: "span", size: "base", textColor: "green", fontWeight: "semiBold" }, props.label))));
231
264
  }
232
265
 
@@ -241,7 +274,7 @@ styleInject_es.styleInject(css_248z);
241
274
 
242
275
  function ComboboxTriggerChip(props) {
243
276
  const { open, setOpen } = React__default["default"].useContext(ComboboxContext);
244
- 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: () => {
245
278
  setOpen(!open);
246
279
  } },
247
280
  React__default["default"].createElement(Typography.Typography, { fontWeight: "semiBold", textColor: "heading" }, props.label),
@@ -2,28 +2,28 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var ConfirmationModal = require('../ConfirmationModal-92f07027.js');
5
+ var ConfirmationModal = require('../ConfirmationModal-285c3cbe.js');
6
6
  require('react');
7
7
  require('@jobber/hooks/useOnKeyDown');
8
- require('../Modal-dcdc0032.js');
8
+ require('../Modal-c17cc105.js');
9
9
  require('react-dom');
10
10
  require('classnames');
11
11
  require('framer-motion');
12
12
  require('@jobber/hooks/useRefocusOnActivator');
13
13
  require('@jobber/hooks/useFocusTrap');
14
14
  require('../style-inject.es-9d2f5f4e.js');
15
- require('../Heading-4562900a.js');
16
- require('../Typography-9bff9c91.js');
17
- require('../Button-d89f2271.js');
15
+ require('../Heading-4cde9989.js');
16
+ require('../Typography-83915c54.js');
17
+ require('../Button-db6114a6.js');
18
18
  require('react-router-dom');
19
19
  require('../Icon-405a216c.js');
20
20
  require('@jobber/design');
21
- require('../ButtonDismiss-250840a4.js');
21
+ require('../ButtonDismiss-1ccb84ec.js');
22
22
  require('../Content-2ca1ffe1.js');
23
- require('../Markdown-b37cf9ec.js');
23
+ require('../Markdown-d53b01bf.js');
24
24
  require('react-markdown');
25
- require('../Text-59bde58c.js');
26
- require('../Emphasis-cc3456ac.js');
25
+ require('../Text-54334431.js');
26
+ require('../Emphasis-e10dde65.js');
27
27
 
28
28
 
29
29
 
@@ -2,9 +2,9 @@
2
2
 
3
3
  var React = require('react');
4
4
  var useOnKeyDown = require('@jobber/hooks/useOnKeyDown');
5
- var Modal = require('./Modal-dcdc0032.js');
5
+ var Modal = require('./Modal-c17cc105.js');
6
6
  var Content = require('./Content-2ca1ffe1.js');
7
- var Markdown = require('./Markdown-b37cf9ec.js');
7
+ var Markdown = require('./Markdown-d53b01bf.js');
8
8
 
9
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
10