@jobber/components 4.74.1 → 4.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ declare const styles: {
2
+ readonly "requestColor": string;
3
+ readonly "quoteColor": string;
4
+ readonly "jobColor": string;
5
+ readonly "invoiceColor": string;
6
+ readonly "blue": string;
7
+ readonly "blueLight": string;
8
+ readonly "blueLighter": string;
9
+ readonly "blueLightest": string;
10
+ readonly "blueDark": string;
11
+ readonly "green": string;
12
+ readonly "greenLight": string;
13
+ readonly "greenLighter": string;
14
+ readonly "greenLightest": string;
15
+ readonly "greenDark": string;
16
+ readonly "lime": string;
17
+ readonly "limeLight": string;
18
+ readonly "limeLighter": string;
19
+ readonly "limeLightest": string;
20
+ readonly "limeDark": string;
21
+ readonly "yellowGreen": string;
22
+ readonly "yellowGreenLight": string;
23
+ readonly "yellowGreenLighter": string;
24
+ readonly "yellowGreenLightest": string;
25
+ readonly "yellowGreenDark": string;
26
+ readonly "yellow": string;
27
+ readonly "yellowLight": string;
28
+ readonly "yellowLighter": string;
29
+ readonly "yellowLightest": string;
30
+ readonly "yellowDark": string;
31
+ readonly "red": string;
32
+ readonly "redLight": string;
33
+ readonly "redLighter": string;
34
+ readonly "redLightest": string;
35
+ readonly "redDark": string;
36
+ readonly "grey": string;
37
+ readonly "greyLight": string;
38
+ readonly "greyLighter": string;
39
+ readonly "greyLightest": string;
40
+ readonly "greyDark": string;
41
+ readonly "greyBlue": string;
42
+ readonly "greyBlueLight": string;
43
+ readonly "greyBlueLighter": string;
44
+ readonly "greyBlueLightest": string;
45
+ readonly "greyBlueDark": string;
46
+ readonly "lightBlue": string;
47
+ readonly "lightBlueLight": string;
48
+ readonly "lightBlueLighter": string;
49
+ readonly "lightBlueLightest": string;
50
+ readonly "lightBlueDark": string;
51
+ readonly "purple": string;
52
+ readonly "purpleLight": string;
53
+ readonly "purpleLighter": string;
54
+ readonly "purpleLightest": string;
55
+ readonly "purpleDark": string;
56
+ readonly "pink": string;
57
+ readonly "pinkLight": string;
58
+ readonly "pinkLighter": string;
59
+ readonly "pinkLightest": string;
60
+ readonly "pinkDark": string;
61
+ readonly "teal": string;
62
+ readonly "tealLight": string;
63
+ readonly "tealLighter": string;
64
+ readonly "tealLightest": string;
65
+ readonly "tealDark": string;
66
+ readonly "orange": string;
67
+ readonly "orangeLight": string;
68
+ readonly "orangeLighter": string;
69
+ readonly "orangeLightest": string;
70
+ readonly "orangeDark": string;
71
+ readonly "brown": string;
72
+ readonly "brownLight": string;
73
+ readonly "brownLighter": string;
74
+ readonly "brownLightest": string;
75
+ readonly "brownDark": string;
76
+ readonly "navy": string;
77
+ readonly "navyLight": string;
78
+ readonly "navyLighter": string;
79
+ readonly "navyLightest": string;
80
+ readonly "navyDark": string;
81
+ readonly "indigo": string;
82
+ readonly "indigoLight": string;
83
+ readonly "indigoLighter": string;
84
+ readonly "indigoLightest": string;
85
+ readonly "indigoDark": string;
86
+ readonly "white": string;
87
+ };
88
+ export = styles;
89
+
@@ -26,10 +26,22 @@ export interface ComboboxProps {
26
26
  * Callback function invoked upon the Combobox menu closing.
27
27
  */
28
28
  readonly onClose?: () => void;
29
+ /**
30
+ * Debounced callback function invoked on Combobox search input change. Receives the current search value as an argument.
31
+ */
32
+ readonly onSearch?: (searchValue: string) => void;
33
+ /**
34
+ * The amount of time in ms to debounce the onSearch callback. Defaults to 300ms.
35
+ */
36
+ readonly onSearchDebounce?: number;
29
37
  /**
30
38
  * The Chip heading for the trigger
31
39
  */
32
40
  readonly label?: string;
41
+ /**
42
+ * Should the Combobox display the loading state.
43
+ */
44
+ readonly loading?: boolean;
33
45
  }
34
46
  export interface ComboboxActivatorProps {
35
47
  readonly children: React.ReactElement;
@@ -81,6 +93,10 @@ export interface ComboboxContentProps {
81
93
  * Setter for the current search term.
82
94
  */
83
95
  readonly setSearchValue: Dispatch<SetStateAction<string>>;
96
+ /**
97
+ * Function called when search input changes.
98
+ */
99
+ readonly handleSearchChange: (value: string) => void;
84
100
  /**
85
101
  * Reference to the wrapping div element of all the Combobox pieces
86
102
  */
@@ -97,6 +113,10 @@ export interface ComboboxContentProps {
97
113
  * The full set of options for the Combobox in the shape of data, not elements.
98
114
  */
99
115
  readonly options: ComboboxOption[];
116
+ /**
117
+ * Should loading state be shown.
118
+ */
119
+ readonly loading?: boolean;
100
120
  }
101
121
  export interface ComboboxSearchProps {
102
122
  /**
@@ -115,6 +135,10 @@ export interface ComboboxSearchProps {
115
135
  * Setter for the search input value.
116
136
  */
117
137
  setSearchValue: Dispatch<SetStateAction<string>>;
138
+ /**
139
+ * Function called when search input changes.
140
+ */
141
+ readonly handleSearchChange: (value: string) => void;
118
142
  }
119
143
  export interface ComboboxHeaderProps {
120
144
  /**
@@ -143,10 +167,6 @@ export interface ComboboxListProps {
143
167
  * The options to display in the list. May be the full set of the Combobox or could be filtered.
144
168
  */
145
169
  readonly options: ComboboxOption[];
146
- /**
147
- * Used to determine if the empty state should be shown and given priority over the options list.
148
- */
149
- readonly showEmptyState: boolean;
150
170
  /**
151
171
  * The currently selected options.
152
172
  */
@@ -167,6 +187,10 @@ export interface ComboboxListProps {
167
187
  * The noun to be used in the empty state message.
168
188
  */
169
189
  readonly subjectNoun?: string;
190
+ /**
191
+ * Should loading state be shown.
192
+ */
193
+ readonly loading?: boolean;
170
194
  }
171
195
  export interface ComboboxActionProps {
172
196
  /**
@@ -10,6 +10,8 @@ type UseComboboxReturn = {
10
10
  selectedOptions: ComboboxOption[];
11
11
  selectedStateSetter: (selection: ComboboxOption[]) => void;
12
12
  shouldScroll: MutableRefObject<boolean>;
13
+ internalFilteredOptions: ComboboxOption[];
14
+ handleSearchChange: (value: string) => void;
13
15
  } & UseMakeComboboxHandlersReturn;
14
- export declare function useCombobox(selected: ComboboxOption[], onSelect: (selection: ComboboxOption[]) => void, onClose?: () => void, multiSelect?: boolean): UseComboboxReturn;
16
+ export declare function useCombobox(selected: ComboboxOption[], onSelect: (selection: ComboboxOption[]) => void, options: ComboboxOption[], onClose?: () => void, multiSelect?: boolean, onSearch?: (searchValue: string) => void, debounceTime?: number): UseComboboxReturn;
15
17
  export {};
@@ -1,8 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import { ComboboxOption } from "../Combobox.types";
3
3
  interface useComboboxContent {
4
- filteredOptions: ComboboxOption[];
5
4
  optionsListRef: React.RefObject<HTMLUListElement>;
6
5
  }
7
- export declare function useComboboxContent(options: ComboboxOption[], open: boolean, selected: ComboboxOption[], searchValue: string): useComboboxContent;
6
+ export declare function useComboboxContent(open: boolean, selected: ComboboxOption[]): useComboboxContent;
8
7
  export {};
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var Combobox = require('../Combobox-95b3c413.js');
5
+ var Combobox = require('../Combobox-ac089920.js');
6
6
  require('react');
7
7
  require('classnames');
8
8
  require('react-dom');
@@ -11,7 +11,9 @@ require('../Icon-405a216c.js');
11
11
  require('@jobber/design');
12
12
  require('../Text-259af966.js');
13
13
  require('../Typography-c45bf216.js');
14
+ require('../Glimmer-f40d5ea5.js');
14
15
  require('../tslib.es6-5b8768b7.js');
16
+ require('../Content-e3f7b6fc.js');
15
17
  require('../Button-b73a5e01.js');
16
18
  require('react-router-dom');
17
19
  require('@jobber/hooks/useRefocusOnActivator');
@@ -24,6 +26,7 @@ require('../Avatar-76a799fa.js');
24
26
  require('color');
25
27
  require('../Tooltip-27771182.js');
26
28
  require('framer-motion');
29
+ require('lodash/debounce');
27
30
  require('@jobber/hooks/useAssert');
28
31
 
29
32
 
@@ -6,6 +6,7 @@ var ReactDOM = require('react-dom');
6
6
  var styleInject_es = require('./style-inject.es-9d2f5f4e.js');
7
7
  var Icon = require('./Icon-405a216c.js');
8
8
  var Text = require('./Text-259af966.js');
9
+ var Glimmer = require('./Glimmer-f40d5ea5.js');
9
10
  var tslib_es6 = require('./tslib.es6-5b8768b7.js');
10
11
  var Typography = require('./Typography-c45bf216.js');
11
12
  var Button = require('./Button-b73a5e01.js');
@@ -14,6 +15,7 @@ var useFocusTrap = require('@jobber/hooks/useFocusTrap');
14
15
  var reactPopper = require('react-popper');
15
16
  var useOnKeyDown = require('@jobber/hooks/useOnKeyDown');
16
17
  var Chip = require('./Chip-c91fd6c8.js');
18
+ var debounce = require('lodash/debounce');
17
19
  require('@jobber/design');
18
20
  var useAssert = require('@jobber/hooks/useAssert');
19
21
 
@@ -22,6 +24,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
22
24
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
23
25
  var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
24
26
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
27
+ var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
25
28
 
26
29
  var css_248z$6 = ".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(217, 223, 225);\n border: var(--border-base) solid var(--color-border);\n border-radius: calc(16px / 2);\n border-radius: var(--radius-larger);\n overflow: auto;\n background: rgba(255, 255, 255, 1);\n background: var(--color-surface);\n}\n\n.jobber-retheme .m1w5vdUZ6rQ- {\n border-radius: calc(16px / 8);\n border-radius: var(--radius-base);\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.m1w5vdUZ6rQ-:focus,\n.m1w5vdUZ6rQ-:focus-visible {\n outline: none;\n}\n\n.m1w5vdUZ6rQ-:focus-visible {\n box-shadow: 0px 0px 0px calc(16px / 8) rgba(255, 255, 255, 1),\n 0px 0px 0px calc(16px / 4) rgb(147, 161, 169);\n box-shadow: var(--shadow-focus);\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
30
  var styles$6 = {"content":"m1w5vdUZ6rQ-","hidden":"Zlkv2HA096A-","actions":"YQry-Rd6zfQ-","actionPadding":"TcpqL34s4lI-"};
@@ -48,15 +51,17 @@ function ComboboxContentSearch(props) {
48
51
  function clearSearch() {
49
52
  var _a;
50
53
  props.setSearchValue("");
54
+ props.handleSearchChange("");
51
55
  (_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.focus();
52
56
  }
53
57
  function handleSearch(event) {
54
- props.setSearchValue(event.target.value);
58
+ props.setSearchValue(event.currentTarget.value);
59
+ props.handleSearchChange(event.currentTarget.value);
55
60
  }
56
61
  }
57
62
 
58
- var css_248z$4 = ".SgMzjOcdE-E- {\n position: relative;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n}\n\n.TwoTCjgcssc- {\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: auto;\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._8T5M7MGwCRE-,\n._4y5NXkNeIQM- {\n padding: calc(16px / 2) calc(16px * 1);\n padding: var(--space-small) var(--space-base);\n}\n\n.SgMzjOcdE-E-::before,\n.SgMzjOcdE-E-::after {\n content: \"\";\n display: block;\n position: absolute;\n right: 0;\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n pointer-events: none;\n transition: opacity 0.3s ease-in-out;\n}\n\n.SgMzjOcdE-E-::after {\n bottom: calc(16px / 2);\n bottom: var(--space-small);\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgb(255, 255, 255) 100%\n );\n}\n\n.SgMzjOcdE-E-::before {\n top: calc(16px / 2);\n top: var(--space-small);\n background: linear-gradient(\n to bottom,\n rgba(255, 255, 255, 1),\n rgba(255, 255, 255, 0)\n );\n}\n\n.T6E3VwBGoQM-::before,\n._6HQzxMQkXnE-::before {\n opacity: 0;\n}\n\n._5YsJZyMDkbA-::after,\n._6HQzxMQkXnE-::after {\n opacity: 0;\n}\n";
59
- var styles$4 = {"container":"SgMzjOcdE-E-","optionsList":"TwoTCjgcssc-","filterMessage":"_8T5M7MGwCRE-","emptyStateMessage":"_4y5NXkNeIQM-","scrollTop":"T6E3VwBGoQM-","scrollNone":"_6HQzxMQkXnE-","scrollBottom":"_5YsJZyMDkbA-"};
63
+ var css_248z$4 = ".SgMzjOcdE-E- {\n position: relative;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n}\n\n.TwoTCjgcssc- {\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: auto;\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._8T5M7MGwCRE-,\n._4y5NXkNeIQM- {\n padding: calc(16px / 2) calc(16px * 1);\n padding: var(--space-small) var(--space-base);\n}\n\n.SgMzjOcdE-E-::before,\n.SgMzjOcdE-E-::after {\n content: \"\";\n display: block;\n position: absolute;\n right: 0;\n left: 0;\n height: calc(16px * 1);\n height: var(--space-base);\n pointer-events: none;\n transition: opacity 0.3s ease-in-out;\n}\n\n.SgMzjOcdE-E-::after {\n bottom: calc(16px / 2);\n bottom: var(--space-small);\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0) 0%,\n rgb(255, 255, 255) 100%\n );\n}\n\n.SgMzjOcdE-E-::before {\n top: calc(16px / 2);\n top: var(--space-small);\n background: linear-gradient(\n to bottom,\n rgba(255, 255, 255, 1),\n rgba(255, 255, 255, 0)\n );\n}\n\n.T6E3VwBGoQM-::before,\n._6HQzxMQkXnE-::before {\n opacity: 0;\n}\n\n._5YsJZyMDkbA-::after,\n._6HQzxMQkXnE-::after {\n opacity: 0;\n}\n\n.A6z4OI58xoE- {\n padding: calc(16px * 1) calc(16px * 1);\n padding: var(--space-base) var(--space-base);\n}\n";
64
+ var styles$4 = {"container":"SgMzjOcdE-E-","optionsList":"TwoTCjgcssc-","filterMessage":"_8T5M7MGwCRE-","emptyStateMessage":"_4y5NXkNeIQM-","scrollTop":"T6E3VwBGoQM-","scrollNone":"_6HQzxMQkXnE-","scrollBottom":"_5YsJZyMDkbA-","loadingContainer":"A6z4OI58xoE-"};
60
65
  styleInject_es.styleInject(css_248z$4);
61
66
 
62
67
  var css_248z$3 = "._5QdRGmaNHvc- {\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.jobber-retheme ._5QdRGmaNHvc- {\n border-radius: calc(16px / 8);\n border-radius: var(--radius-base);\n}\n\n._5QdRGmaNHvc-:hover,\n._5QdRGmaNHvc-:focus-visible {\n background-color: rgb(244, 246, 250);\n background-color: var(--color-surface--hover);\n}\n\n._5QdRGmaNHvc-:focus,\n._5QdRGmaNHvc-:focus-visible {\n outline: none;\n}\n\n._5QdRGmaNHvc-:focus-visible {\n box-shadow: 0px 0px 0px calc(16px / 8) rgba(255, 255, 255, 1),\n 0px 0px 0px calc(16px / 4) rgb(147, 161, 169);\n box-shadow: var(--shadow-focus);\n}\n";
@@ -79,11 +84,37 @@ function ComboboxOption(props) {
79
84
  }
80
85
 
81
86
  function ComboboxContentList(props) {
87
+ const optionsExist = props.options.length > 0;
88
+ const showOptions = optionsExist && !props.loading;
89
+ const hasSearchTerm = props.searchValue.length > 0;
90
+ const { listScrollState } = useScrollState(props.optionsListRef, props.options);
91
+ return (React__default["default"].createElement("div", { className: classnames__default["default"](styles$4.container, styles$4[listScrollState]) },
92
+ optionsExist && (React__default["default"].createElement("ul", { className: styles$4.optionsList, role: "listbox", "aria-multiselectable": props.multiselect, ref: props.optionsListRef },
93
+ showOptions &&
94
+ props.options.map(option => {
95
+ return (React__default["default"].createElement(ComboboxOption, { key: option.id, id: option.id, label: option.label }));
96
+ }),
97
+ props.loading && (React__default["default"].createElement(React__default["default"].Fragment, null, Array.from({ length: 5 }).map((_, index) => (React__default["default"].createElement("div", { className: styles$4.loadingContainer, key: index },
98
+ React__default["default"].createElement(Glimmer.Glimmer, { shape: "rectangle", size: "small" })))))))),
99
+ hasSearchTerm && !optionsExist && (React__default["default"].createElement("div", { className: styles$4.filterMessage },
100
+ React__default["default"].createElement(Text.Text, { variation: "subdued" },
101
+ "No results for ",
102
+ `“${props.searchValue}”`))),
103
+ !hasSearchTerm && !optionsExist && (React__default["default"].createElement("div", { className: styles$4.emptyStateMessage },
104
+ React__default["default"].createElement(Text.Text, { variation: "subdued" }, getZeroIndexStateText(props.subjectNoun))))));
105
+ }
106
+ function getZeroIndexStateText(subjectNoun) {
107
+ if (subjectNoun) {
108
+ return `You don't have any ${subjectNoun} yet`;
109
+ }
110
+ return "No options yet";
111
+ }
112
+ function useScrollState(optionsListRef, options) {
82
113
  const [listScrollState, setlistScrollState] = React.useState("");
83
114
  React.useEffect(() => {
84
115
  const handleScroll = () => {
85
- if (props.optionsListRef.current) {
86
- const { scrollTop, clientHeight, scrollHeight } = props.optionsListRef.current;
116
+ if (optionsListRef.current) {
117
+ const { scrollTop, clientHeight, scrollHeight } = optionsListRef.current;
87
118
  if (scrollHeight === clientHeight) {
88
119
  setlistScrollState("scrollNone");
89
120
  }
@@ -98,36 +129,20 @@ function ComboboxContentList(props) {
98
129
  }
99
130
  }
100
131
  };
101
- if (!props.showEmptyState && props.options.length === 0) {
132
+ if (options.length === 0) {
102
133
  handleScroll();
103
134
  }
104
- if (props.optionsListRef.current) {
105
- props.optionsListRef.current.addEventListener("scroll", handleScroll);
135
+ if (optionsListRef.current) {
136
+ optionsListRef.current.addEventListener("scroll", handleScroll);
106
137
  handleScroll();
107
138
  }
108
139
  return () => {
109
- if (props.optionsListRef.current) {
110
- props.optionsListRef.current.removeEventListener("scroll", handleScroll);
140
+ if (optionsListRef.current) {
141
+ optionsListRef.current.removeEventListener("scroll", handleScroll);
111
142
  }
112
143
  };
113
- }, [props.options]);
114
- return (React__default["default"].createElement("div", { className: classnames__default["default"](styles$4.container, styles$4[listScrollState]) },
115
- !props.showEmptyState && props.options.length > 0 && (React__default["default"].createElement("ul", { className: styles$4.optionsList, role: "listbox", "aria-multiselectable": props.multiselect, ref: props.optionsListRef }, !props.showEmptyState &&
116
- props.options.map(option => {
117
- return (React__default["default"].createElement(ComboboxOption, { key: option.id, id: option.id, label: option.label }));
118
- }))),
119
- !props.showEmptyState && props.options.length === 0 && (React__default["default"].createElement("div", { className: styles$4.filterMessage },
120
- React__default["default"].createElement(Text.Text, { variation: "subdued" },
121
- "No results for ",
122
- `“${props.searchValue}”`))),
123
- props.showEmptyState && (React__default["default"].createElement("div", { className: styles$4.emptyStateMessage },
124
- React__default["default"].createElement(Text.Text, { variation: "subdued" }, getZeroIndexStateText(props.subjectNoun))))));
125
- }
126
- function getZeroIndexStateText(subjectNoun) {
127
- if (subjectNoun) {
128
- return `You don't have any ${subjectNoun} yet`;
129
- }
130
- return "No options yet";
144
+ }, [options]);
145
+ return { listScrollState };
131
146
  }
132
147
 
133
148
  var css_248z$2 = ".Q-mwo-g5Fi8- {\n display: -ms-flexbox;\n display: flex;\n padding: calc(16px * 1) calc(16px / 2) 0 calc(16px * 1);\n padding: var(--space-base) var(--space-small) 0 var(--space-base);\n -ms-flex-pack: justify;\n justify-content: space-between;\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n}\n";
@@ -154,10 +169,9 @@ function getLabel(hasSelected, count, subjectNoun) {
154
169
  return "Select";
155
170
  }
156
171
 
157
- function useComboboxContent(options, open, selected, searchValue) {
172
+ function useComboboxContent(open, selected) {
158
173
  const { shouldScroll } = React.useContext(ComboboxContext);
159
174
  const optionsListRef = React.useRef(null);
160
- const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchValue.toLowerCase()));
161
175
  React.useEffect(() => {
162
176
  var _a;
163
177
  if (open && shouldScroll.current && optionsListRef.current) {
@@ -170,7 +184,6 @@ function useComboboxContent(options, open, selected, searchValue) {
170
184
  }
171
185
  }, [open, selected]);
172
186
  return {
173
- filteredOptions,
174
187
  optionsListRef,
175
188
  };
176
189
  }
@@ -266,16 +279,16 @@ function useComboboxAccessibility(selectionCallback, filteredOptions, optionsLis
266
279
 
267
280
  function ComboboxContent(props) {
268
281
  const optionsExist = props.options.length > 0;
269
- const { filteredOptions, optionsListRef } = useComboboxContent(props.options, props.open, props.selected, props.searchValue);
270
- const { popperRef, popperStyles, attributes } = useComboboxAccessibility(props.handleSelection, filteredOptions, optionsListRef, props.open, props.wrapperRef);
282
+ const { optionsListRef } = useComboboxContent(props.open, props.selected);
283
+ const { popperRef, popperStyles, attributes } = useComboboxAccessibility(props.handleSelection, props.options, optionsListRef, props.open, props.wrapperRef);
271
284
  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$6.content, { [styles$6.hidden]: !props.open }), style: popperStyles.popper }, attributes.popper),
272
- React__default["default"].createElement(ComboboxContentSearch, { open: props.open, placeholder: props.subjectNoun, searchValue: props.searchValue, setSearchValue: props.setSearchValue }),
273
- props.multiselect && optionsExist && (React__default["default"].createElement(ComboboxContentHeader, { hasOptionsVisible: filteredOptions.length > 0, subjectNoun: props.subjectNoun, selectedCount: props.selected.length, onClearAll: () => {
285
+ React__default["default"].createElement(ComboboxContentSearch, { open: props.open, placeholder: props.subjectNoun, searchValue: props.searchValue, setSearchValue: props.setSearchValue, handleSearchChange: props.handleSearchChange }),
286
+ props.multiselect && optionsExist && (React__default["default"].createElement(ComboboxContentHeader, { hasOptionsVisible: optionsExist, subjectNoun: props.subjectNoun, selectedCount: props.selected.length, onClearAll: () => {
274
287
  props.selectedStateSetter([]);
275
288
  }, onSelectAll: () => {
276
- props.selectedStateSetter(filteredOptions);
289
+ props.selectedStateSetter(props.options);
277
290
  } })),
278
- React__default["default"].createElement(ComboboxContentList, { multiselect: props.multiselect, showEmptyState: !optionsExist, options: filteredOptions, selected: props.selected, optionsListRef: optionsListRef, searchValue: props.searchValue, subjectNoun: props.subjectNoun }),
291
+ React__default["default"].createElement(ComboboxContentList, { multiselect: props.multiselect, options: props.options, selected: props.selected, optionsListRef: optionsListRef, searchValue: props.searchValue, subjectNoun: props.subjectNoun, loading: props.loading }),
279
292
  props.actionElements && (React__default["default"].createElement("div", { className: styles$6.actions, role: "group" }, props.actionElements.map((child, index, childrenArray) => (React__default["default"].createElement("div", { key: index, className: classnames__default["default"]({
280
293
  [styles$6.actionPadding]: index === childrenArray.length - 1,
281
294
  }) }, child)))))));
@@ -355,11 +368,19 @@ function handleMultiSelect(selectCallback, selected, selection) {
355
368
  }
356
369
  }
357
370
 
358
- function useCombobox(selected, onSelect, onClose, multiSelect) {
371
+ function useCombobox(selected, onSelect, options, onClose, multiSelect, onSearch, debounceTime = 300) {
359
372
  const wrapperRef = React.useRef(null);
360
373
  const shouldScroll = React.useRef(false);
361
374
  const [open, setOpen] = React.useState(false);
362
375
  const [searchValue, setSearchValue] = React.useState("");
376
+ const [internalFilteredOptions, setInternalFilteredOptions] = React.useState(options);
377
+ const searchCallback = React.useCallback(debounce__default["default"]((value) => onSearch && onSearch(value), debounceTime), []);
378
+ const debouncedFilterOptions = React.useCallback((value) => {
379
+ const filtered = options.filter(option => {
380
+ return option.label.toLowerCase().includes(value.toLowerCase());
381
+ });
382
+ setInternalFilteredOptions(filtered);
383
+ }, []);
363
384
  const { handleClose, handleSelection } = useMakeComboboxHandlers(setOpen, setSearchValue, selected, shouldScroll, onSelect, multiSelect, onClose);
364
385
  return {
365
386
  wrapperRef,
@@ -372,6 +393,8 @@ function useCombobox(selected, onSelect, onClose, multiSelect) {
372
393
  shouldScroll,
373
394
  handleClose,
374
395
  handleSelection,
396
+ internalFilteredOptions,
397
+ handleSearchChange: onSearch ? searchCallback : debouncedFilterOptions,
375
398
  };
376
399
  }
377
400
 
@@ -424,12 +447,12 @@ function Combobox(props) {
424
447
  id: option.props.id,
425
448
  label: option.props.label,
426
449
  }))) || [], [optionElements]);
427
- const { selectedOptions, selectedStateSetter, shouldScroll, wrapperRef, searchValue, setSearchValue, open, setOpen, handleClose, handleSelection, } = useCombobox(props.selected, props.onSelect, props.onClose, props.multiSelect);
450
+ const { selectedOptions, selectedStateSetter, shouldScroll, wrapperRef, searchValue, setSearchValue, open, setOpen, handleClose, handleSelection, internalFilteredOptions, handleSearchChange, } = useCombobox(props.selected, props.onSelect, options, props.onClose, props.multiSelect, props.onSearch, props.onSearchDebounce);
428
451
  return (React__default["default"].createElement(ComboboxContextProvider, { selected: selectedOptions, selectionHandler: handleSelection, open: open, setOpen: setOpen, handleClose: handleClose, shouldScroll: shouldScroll, searchValue: searchValue },
429
452
  React__default["default"].createElement("div", { ref: wrapperRef, className: styles.wrapper },
430
453
  open && (React__default["default"].createElement("div", { className: styles.overlay, onClick: () => handleClose(), "data-testid": "ATL-Combobox-Overlay" })),
431
454
  triggerElement || (React__default["default"].createElement(ComboboxTrigger, { label: props.label, selected: props.selected })),
432
- React__default["default"].createElement(ComboboxContent, { multiselect: props.multiSelect, subjectNoun: props.subjectNoun, selected: selectedOptions, actionElements: actionElements, selectedStateSetter: selectedStateSetter, handleSelection: handleSelection, searchValue: searchValue, setSearchValue: setSearchValue, wrapperRef: wrapperRef, open: open, setOpen: setOpen, options: options }))));
455
+ React__default["default"].createElement(ComboboxContent, { multiselect: props.multiSelect, subjectNoun: props.subjectNoun, selected: selectedOptions, actionElements: actionElements, selectedStateSetter: selectedStateSetter, handleSelection: handleSelection, searchValue: searchValue, setSearchValue: setSearchValue, wrapperRef: wrapperRef, open: open, setOpen: setOpen, options: props.onSearch ? options : internalFilteredOptions, loading: props.loading, handleSearchChange: handleSearchChange }))));
433
456
  }
434
457
  Combobox.Activator = ComboboxActivator;
435
458
  Combobox.Action = ComboboxAction;
@@ -0,0 +1,13 @@
1
+ declare const styles: {
2
+ readonly "minuscule": string;
3
+ readonly "smallest": string;
4
+ readonly "smaller": string;
5
+ readonly "small": string;
6
+ readonly "base": string;
7
+ readonly "large": string;
8
+ readonly "larger": string;
9
+ readonly "largest": string;
10
+ readonly "extravagant": string;
11
+ };
12
+ export = styles;
13
+
@@ -25,7 +25,7 @@ var ReactDOM = require('react-dom');
25
25
  var Checkbox = require('../Checkbox-1cdd5cf6.js');
26
26
  var reactRouterDom = require('react-router-dom');
27
27
  var AnimatedSwitcher = require('../AnimatedSwitcher-d1e1ddcf.js');
28
- var Combobox = require('../Combobox-95b3c413.js');
28
+ var Combobox = require('../Combobox-ac089920.js');
29
29
  var Chip = require('../Chip-c91fd6c8.js');
30
30
  var Icon = require('../Icon-405a216c.js');
31
31
  var debounce = require('lodash/debounce');
@@ -0,0 +1,9 @@
1
+ declare const styles: {
2
+ readonly "gallery": string;
3
+ readonly "galleryLarge": string;
4
+ readonly "showMoreButton": string;
5
+ readonly "baseShowMoreButton": string;
6
+ readonly "largeShowMoreButton": string;
7
+ };
8
+ export = styles;
9
+
@@ -0,0 +1,9 @@
1
+ declare const styles: {
2
+ readonly "rectangle": string;
3
+ readonly "rectangleShort": string;
4
+ readonly "rectangleShorter": string;
5
+ readonly "square": string;
6
+ readonly "circle": string;
7
+ };
8
+ export = styles;
9
+
@@ -0,0 +1,10 @@
1
+ declare const styles: {
2
+ readonly "small": string;
3
+ readonly "base": string;
4
+ readonly "large": string;
5
+ readonly "larger": string;
6
+ readonly "largest": string;
7
+ readonly "auto": string;
8
+ };
9
+ export = styles;
10
+
@@ -0,0 +1,6 @@
1
+ declare const styles: {
2
+ readonly "base": string;
3
+ readonly "fast": string;
4
+ };
5
+ export = styles;
6
+
@@ -0,0 +1,8 @@
1
+ declare const styles: {
2
+ readonly "center": string;
3
+ readonly "start": string;
4
+ readonly "end": string;
5
+ readonly "stretch": string;
6
+ };
7
+ export = styles;
8
+
@@ -0,0 +1,6 @@
1
+ declare const styles: {
2
+ readonly "small": string;
3
+ readonly "large": string;
4
+ };
5
+ export = styles;
6
+
@@ -0,0 +1,7 @@
1
+ declare const styles: {
2
+ readonly "smaller": string;
3
+ readonly "small": string;
4
+ readonly "base": string;
5
+ };
6
+ export = styles;
7
+
@@ -0,0 +1,6 @@
1
+ declare const styles: {
2
+ readonly "italic": string;
3
+ readonly "highlight": string;
4
+ };
5
+ export = styles;
6
+
@@ -0,0 +1,6 @@
1
+ declare const styles: {
2
+ readonly "base": string;
3
+ readonly "display": string;
4
+ };
5
+ export = styles;
6
+
@@ -0,0 +1,12 @@
1
+ declare const styles: {
2
+ readonly "extravagant": string;
3
+ readonly "jumbo": string;
4
+ readonly "largest": string;
5
+ readonly "larger": string;
6
+ readonly "large": string;
7
+ readonly "base": string;
8
+ readonly "small": string;
9
+ readonly "smaller": string;
10
+ };
11
+ export = styles;
12
+
@@ -0,0 +1,10 @@
1
+ declare const styles: {
2
+ readonly "regular": string;
3
+ readonly "medium": string;
4
+ readonly "semiBold": string;
5
+ readonly "bold": string;
6
+ readonly "extraBold": string;
7
+ readonly "black": string;
8
+ };
9
+ export = styles;
10
+
@@ -0,0 +1,7 @@
1
+ declare const styles: {
2
+ readonly "start": string;
3
+ readonly "center": string;
4
+ readonly "end": string;
5
+ };
6
+ export = styles;
7
+
@@ -0,0 +1,7 @@
1
+ declare const styles: {
2
+ readonly "uppercase": string;
3
+ readonly "lowercase": string;
4
+ readonly "capitalize": string;
5
+ };
6
+ export = styles;
7
+
@@ -0,0 +1,22 @@
1
+ declare const styles: {
2
+ readonly "blue": string;
3
+ readonly "grey": string;
4
+ readonly "greyBlueDark": string;
5
+ readonly "greyBlue": string;
6
+ readonly "green": string;
7
+ readonly "red": string;
8
+ readonly "yellow": string;
9
+ readonly "yellowDark": string;
10
+ readonly "lightBlue": string;
11
+ readonly "white": string;
12
+ readonly "heading": string;
13
+ readonly "text": string;
14
+ readonly "textSecondary": string;
15
+ readonly "critical": string;
16
+ readonly "warning": string;
17
+ readonly "informative": string;
18
+ readonly "success": string;
19
+ readonly "disabled": string;
20
+ };
21
+ export = styles;
22
+
@@ -0,0 +1,5 @@
1
+ declare const styles: {
2
+ readonly "textTruncate": string;
3
+ };
4
+ export = styles;
5
+
@@ -0,0 +1,5 @@
1
+ declare const styles: {
2
+ readonly "base": string;
3
+ };
4
+ export = styles;
5
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "4.74.1",
3
+ "version": "4.75.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -68,6 +68,7 @@
68
68
  "postcss-import": "^12.0.1",
69
69
  "postcss-preset-env": "^8.3.0",
70
70
  "rollup": "^2.79.1",
71
+ "rollup-plugin-copy": "^3.4.0",
71
72
  "rollup-plugin-multi-input": "^1.4.1",
72
73
  "rollup-plugin-postcss": "^4.0.2",
73
74
  "typed-css-modules": "^0.7.0",
@@ -83,5 +84,5 @@
83
84
  "> 1%",
84
85
  "IE 10"
85
86
  ],
86
- "gitHead": "6782515ef63049514a8430407efb2551bf5cb461"
87
+ "gitHead": "27452dd8241062254d7f71c756bbf4076b700471"
87
88
  }
package/rollup.config.js CHANGED
@@ -3,6 +3,7 @@ import multiInput from "rollup-plugin-multi-input";
3
3
  import typescript from "@rollup/plugin-typescript";
4
4
  import postcss from "rollup-plugin-postcss";
5
5
  import commonjs from "@rollup/plugin-commonjs";
6
+ import copy from "rollup-plugin-copy";
6
7
 
7
8
  export default {
8
9
  input: `src/*/index.{ts,tsx}`,
@@ -37,6 +38,62 @@ export default {
37
38
  commonjs({
38
39
  ignore: ["time-input-polyfill", "time-input-polyfill/supportsTime"],
39
40
  }),
41
+ copy({
42
+ targets: [
43
+ { src: "src/Card/colors.css.d.ts", dest: "dist/Card" },
44
+ { src: "src/Content/Spacing.css.d.ts", dest: "dist/Content" },
45
+ { src: "src/Gallery/Gallery.css.d.ts", dest: "dist/Gallery" },
46
+ { src: "src/Grid/GridAlign.css.d.ts", dest: "dist/Grid" },
47
+ { src: "src/Modal/Sizes.css.d.ts", dest: "dist/Modal" },
48
+ { src: "src/ProgressBar/Sizes.css.d.ts", dest: "dist/ProgressBar" },
49
+ {
50
+ src: "src/Typography/css/Emphasis.css.d.ts",
51
+ dest: "dist/Typography/css",
52
+ },
53
+ {
54
+ src: "src/Typography/css/FontFamilies.css.d.ts",
55
+ dest: "dist/Typography/css",
56
+ },
57
+ {
58
+ src: "src/Typography/css/FontSizes.css.d.ts",
59
+ dest: "dist/Typography/css",
60
+ },
61
+ {
62
+ src: "src/Typography/css/FontWeights.css.d.ts",
63
+ dest: "dist/Typography/css",
64
+ },
65
+ {
66
+ src: "src/Typography/css/TextAlignment.css.d.ts",
67
+ dest: "dist/Typography/css",
68
+ },
69
+ {
70
+ src: "src/Typography/css/TextCases.css.d.ts",
71
+ dest: "dist/Typography/css",
72
+ },
73
+ {
74
+ src: "src/Typography/css/TextColors.css.d.ts",
75
+ dest: "dist/Typography/css",
76
+ },
77
+ {
78
+ src: "src/Typography/css/Truncate.css.d.ts",
79
+ dest: "dist/Typography/css",
80
+ },
81
+ {
82
+ src: "src/Typography/css/Typography.css.d.ts",
83
+ dest: "dist/Typography/css",
84
+ },
85
+ { src: "src/Glimmer/style/Shape.css.d.ts", dest: "dist/Glimmer/style" },
86
+ { src: "src/Glimmer/style/Sizes.css.d.ts", dest: "dist/Glimmer/style" },
87
+ {
88
+ src: "src/Glimmer/style/Timing.css.d.ts",
89
+ dest: "dist/Glimmer/style",
90
+ },
91
+ {
92
+ src: "src/Combobox/components/ComboboxContent/ComboboxContentList/ComboboxContent.css.d.ts",
93
+ dest: "dist/Combobox/components/ComboboxContent/ComboboxContentList",
94
+ },
95
+ ],
96
+ }),
40
97
  ],
41
98
  output: [
42
99
  {