@jobber/components 4.32.1 → 4.33.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.
@@ -14,4 +14,5 @@ export declare const BREAKPOINT_SIZES: Record<Breakpoints, number>;
14
14
  export declare const SEARCH_DEBOUNCE_DELAY: number;
15
15
  export declare const DATA_LIST_FILTERING_SPINNER_TEST_ID = "ATL-DataList-filteringSpinner";
16
16
  export declare const DATA_LIST_LOADING_MORE_SPINNER_TEST_ID = "ATL-DataList-loadingMoreSpinner";
17
+ export declare const DATA_LOAD_MORE_TEST_ID = "ATL-DataList-LoadMore-trigger";
17
18
  export {};
@@ -72,6 +72,10 @@ export interface DataListProps<T extends DataListObject> {
72
72
  [Breakpoint in Breakpoints]?: boolean;
73
73
  };
74
74
  readonly children: ReactElement | ReactElement[];
75
+ /**
76
+ * The callback function when the user scrolls to the bottom of the list.
77
+ */
78
+ readonly onLoadMore?: () => void;
75
79
  }
76
80
  export interface DataListLayoutProps<T extends DataListObject> {
77
81
  readonly children: (item: DataListItemType<T[]>) => JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function DataListLoadMore(): JSX.Element;
@@ -0,0 +1 @@
1
+ export * from "./DataListLoadMore";
@@ -36,13 +36,13 @@ var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
36
36
  var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
37
37
  var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
38
38
 
39
- var css_248z$7 = ".TkdrExYnvcY- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n position: relative;\n z-index: 0;\n z-index: var(--elevation-default);\n -ms-flex: 1;\n flex: 1;\n}\n\n.IcAlZHoB4LI- {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n z-index: 1;\n z-index: var(--elevation-base);\n margin-bottom: calc(16px / 2);\n margin-bottom: var(--space-small);\n -ms-flex-align: center;\n align-items: center;\n}\n\n.TFO76ysivmg- {\n display: grid;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n gap: calc(16px / 2);\n grid-gap: calc(16px / 2);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n grid-template-columns: auto -webkit-max-content;\n grid-template-columns: auto max-content;\n}\n\n.jGHZZYZm1ZY- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-bottom: calc(16px / 8) solid rgb(225, 225, 225);\n border-bottom: var(--border-thick) solid var(--color-border);\n}\n\n.Gj9kAGnfKco- > * {\n font-weight: 500;\n}\n\n.ise8kHCfhCY- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-bottom: calc(16px / 16) solid rgb(225, 225, 225);\n border-bottom: var(--border-base) solid var(--color-border);\n}\n\n.Kkp-IYmwq-s- {\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: rgba(255, 255, 255, 0.6);\n background-color: var(--color-overlay--dimmed);\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.m-eCShL7TU4- {\n position: sticky;\n top: 50vh;\n}\n\n.xeUxuTlqQtk- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-pack: center;\n justify-content: center;\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n";
40
- var styles$7 = {"wrapper":"TkdrExYnvcY-","titleContainer":"IcAlZHoB4LI-","headerFilters":"TFO76ysivmg-","headerTitles":"jGHZZYZm1ZY-","headerLabel":"Gj9kAGnfKco-","listItem":"ise8kHCfhCY-","filtering":"Kkp-IYmwq-s-","filteringSpinner":"m-eCShL7TU4-","loadingMore":"xeUxuTlqQtk-"};
41
- styleInject_es.styleInject(css_248z$7);
39
+ var css_248z$8 = ".TkdrExYnvcY- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n position: relative;\n z-index: 0;\n z-index: var(--elevation-default);\n -ms-flex: 1;\n flex: 1;\n}\n\n.IcAlZHoB4LI- {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n z-index: 1;\n z-index: var(--elevation-base);\n margin-bottom: calc(16px / 2);\n margin-bottom: var(--space-small);\n -ms-flex-align: center;\n align-items: center;\n}\n\n.TFO76ysivmg- {\n display: grid;\n padding: calc(16px / 2) 0;\n padding: var(--space-small) 0;\n gap: calc(16px / 2);\n grid-gap: calc(16px / 2);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n grid-template-columns: auto -webkit-max-content;\n grid-template-columns: auto max-content;\n}\n\n.jGHZZYZm1ZY- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-bottom: calc(16px / 8) solid rgb(225, 225, 225);\n border-bottom: var(--border-thick) solid var(--color-border);\n}\n\n.Gj9kAGnfKco- > * {\n font-weight: 500;\n}\n\n.ise8kHCfhCY- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n border-bottom: calc(16px / 16) solid rgb(225, 225, 225);\n border-bottom: var(--border-base) solid var(--color-border);\n}\n\n.Kkp-IYmwq-s- {\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: rgba(255, 255, 255, 0.6);\n background-color: var(--color-overlay--dimmed);\n -ms-flex-align: center;\n align-items: center;\n -ms-flex-pack: center;\n justify-content: center;\n}\n\n.m-eCShL7TU4- {\n position: sticky;\n top: 50vh;\n}\n\n.xeUxuTlqQtk- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-pack: center;\n justify-content: center;\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n";
40
+ var styles$8 = {"wrapper":"TkdrExYnvcY-","titleContainer":"IcAlZHoB4LI-","headerFilters":"TFO76ysivmg-","headerTitles":"jGHZZYZm1ZY-","headerLabel":"Gj9kAGnfKco-","listItem":"ise8kHCfhCY-","filtering":"Kkp-IYmwq-s-","filteringSpinner":"m-eCShL7TU4-","loadingMore":"xeUxuTlqQtk-"};
41
+ styleInject_es.styleInject(css_248z$8);
42
42
 
43
- var css_248z$6 = ".F56prQsXm3A- {\n min-width: 80px;\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n";
44
- var styles$6 = {"results":"F56prQsXm3A-"};
45
- styleInject_es.styleInject(css_248z$6);
43
+ var css_248z$7 = ".F56prQsXm3A- {\n min-width: 80px;\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n";
44
+ var styles$7 = {"results":"F56prQsXm3A-"};
45
+ styleInject_es.styleInject(css_248z$7);
46
46
 
47
47
  const DATALIST_TOTALCOUNT_TEST_ID = "ATL-DataList-TotalCount";
48
48
  function DataListTotalCount({ totalCount, loading, }) {
@@ -58,12 +58,12 @@ function DataListTotalCount({ totalCount, loading, }) {
58
58
  totalCount.toLocaleString(),
59
59
  " results)"));
60
60
  }
61
- return (React__default["default"].createElement("div", { className: styles$6.results, "data-testid": DATALIST_TOTALCOUNT_TEST_ID }, output));
61
+ return (React__default["default"].createElement("div", { className: styles$7.results, "data-testid": DATALIST_TOTALCOUNT_TEST_ID }, output));
62
62
  }
63
63
 
64
- var css_248z$5 = ".Rh--6fVpkm4- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n\n.zbS7UvpVoWI- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex-pack: justify;\n justify-content: space-between;\n height: calc(16px * 3);\n height: var(--space-largest);\n padding: calc(16px * 1) 0;\n padding: var(--space-base) 0;\n}\n";
65
- var styles$5 = {"loadingItem":"Rh--6fVpkm4-","mobileLoadingState":"zbS7UvpVoWI-"};
66
- styleInject_es.styleInject(css_248z$5);
64
+ var css_248z$6 = ".Rh--6fVpkm4- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n\n.zbS7UvpVoWI- {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n -ms-flex-pack: justify;\n justify-content: space-between;\n height: calc(16px * 3);\n height: var(--space-largest);\n padding: calc(16px * 1) 0;\n padding: var(--space-base) 0;\n}\n";
65
+ var styles$6 = {"loadingItem":"Rh--6fVpkm4-","mobileLoadingState":"zbS7UvpVoWI-"};
66
+ styleInject_es.styleInject(css_248z$6);
67
67
 
68
68
  const EMPTY_RESULTS_MESSAGE = "List is looking empty";
69
69
  const EMPTY_FILTER_RESULTS_MESSAGE = "No results for selected filters";
@@ -82,10 +82,11 @@ const BREAKPOINT_SIZES = {
82
82
  const SEARCH_DEBOUNCE_DELAY = design.tokens["timing-slowest"];
83
83
  const DATA_LIST_FILTERING_SPINNER_TEST_ID = "ATL-DataList-filteringSpinner";
84
84
  const DATA_LIST_LOADING_MORE_SPINNER_TEST_ID = "ATL-DataList-loadingMoreSpinner";
85
+ const DATA_LOAD_MORE_TEST_ID = "ATL-DataList-LoadMore-trigger";
85
86
 
86
- var css_248z$4 = ".WRV-UmQmPzo- {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n z-index: 0;\n z-index: var(--elevation-default);\n overflow: hidden;\n gap: calc(16px / 2);\n gap: var(--space-small);\n}\n\n.liQeWCMenD0- {\n --overflow-bg: var(--color-white);\n\n display: -ms-flexbox;\n\n display: flex;\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n padding-left: calc(16px * 1);\n padding-left: var(--space-base);\n background-image: linear-gradient(\n 90deg,\n transparent 0,\n rgba(255, 255, 255, 1) calc(16px * 1),\n rgba(255, 255, 255, 1) 100%\n );\n background-image: linear-gradient(\n 90deg,\n transparent 0,\n var(--overflow-bg) var(--space-base),\n var(--overflow-bg) 100%\n );\n -ms-flex-align: center;\n align-items: center;\n}\n";
87
- var styles$4 = {"tags":"WRV-UmQmPzo-","tagCount":"liQeWCMenD0-"};
88
- styleInject_es.styleInject(css_248z$4);
87
+ var css_248z$5 = ".WRV-UmQmPzo- {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n z-index: 0;\n z-index: var(--elevation-default);\n overflow: hidden;\n gap: calc(16px / 2);\n gap: var(--space-small);\n}\n\n.liQeWCMenD0- {\n --overflow-bg: var(--color-white);\n\n display: -ms-flexbox;\n\n display: flex;\n position: absolute;\n top: 0;\n right: 0;\n height: 100%;\n padding-left: calc(16px * 1);\n padding-left: var(--space-base);\n background-image: linear-gradient(\n 90deg,\n transparent 0,\n rgba(255, 255, 255, 1) calc(16px * 1),\n rgba(255, 255, 255, 1) 100%\n );\n background-image: linear-gradient(\n 90deg,\n transparent 0,\n var(--overflow-bg) var(--space-base),\n var(--overflow-bg) 100%\n );\n -ms-flex-align: center;\n align-items: center;\n}\n";
88
+ var styles$5 = {"tags":"WRV-UmQmPzo-","tagCount":"liQeWCMenD0-"};
89
+ styleInject_es.styleInject(css_248z$5);
89
90
 
90
91
  function DataListTags({ items }) {
91
92
  const ref = React.useRef(null);
@@ -95,8 +96,6 @@ function DataListTags({ items }) {
95
96
  var _a;
96
97
  if (!window.IntersectionObserver)
97
98
  return;
98
- // Reset counter every time the items change
99
- setVisibleIndex([]);
100
99
  const observer = new IntersectionObserver(handleIntersection, {
101
100
  root: ref.current,
102
101
  threshold: buildIntersectionThreshold(items),
@@ -107,10 +106,10 @@ function DataListTags({ items }) {
107
106
  elements === null || elements === void 0 ? void 0 : elements.forEach(element => observer.unobserve(element));
108
107
  };
109
108
  }, [items]);
110
- return (React__default["default"].createElement("div", { className: styles$4.tags, ref: ref },
109
+ return (React__default["default"].createElement("div", { className: styles$5.tags, ref: ref },
111
110
  items.filter(Boolean).map((tag, index) => (React__default["default"].createElement("div", { key: tag, "data-tag-element": index },
112
111
  React__default["default"].createElement(InlineLabel.InlineLabel, null, tag)))),
113
- Boolean(visibleItems) && (React__default["default"].createElement("div", { className: styles$4.tagCount },
112
+ Boolean(visibleItems) && (React__default["default"].createElement("div", { className: styles$5.tagCount },
114
113
  React__default["default"].createElement(Text.Text, null,
115
114
  "+",
116
115
  visibleItems)))));
@@ -188,7 +187,7 @@ function generateListItemElements(data) {
188
187
  * Generate the header elements with the default styling
189
188
  */
190
189
  function generateHeaderElements(headers) {
191
- const headerElements = Object.keys(headers).reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: (React__default["default"].createElement("div", { className: styles$7.headerLabel },
190
+ const headerElements = Object.keys(headers).reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: (React__default["default"].createElement("div", { className: styles$8.headerLabel },
192
191
  React__default["default"].createElement(Text.Text, { variation: "subdued", maxLines: "single", size: "small" }, headers[key]))) })), {});
193
192
  return isEmpty__default["default"](headerElements) ? undefined : headerElements;
194
193
  }
@@ -232,7 +231,7 @@ function DataListItems({ layouts, mediaMatches, data, }) {
232
231
  const elementData = generateListItemElements(data);
233
232
  return (React__default["default"].createElement(DataListLayoutInternal, { layouts: layouts, mediaMatches: mediaMatches, renderLayout: layout => {
234
233
  return (React__default["default"].createElement(React__default["default"].Fragment, null, elementData.map((child, i) => {
235
- return (React__default["default"].createElement("div", { className: styles$7.listItem, key: `${data[i].id}` }, layout.props.children(child)));
234
+ return (React__default["default"].createElement("div", { className: styles$8.listItem, key: `${data[i].id}` }, layout.props.children(child)));
236
235
  })));
237
236
  } }));
238
237
  }
@@ -248,7 +247,7 @@ function DataListHeader({ layouts, mediaMatches, headerData, headerVisibility, }
248
247
  if (!showHeader || !headerData)
249
248
  return React__default["default"].createElement(React__default["default"].Fragment, null);
250
249
  return (React__default["default"].createElement(DataListLayoutInternal, { layouts: layouts, renderLayout: layout => {
251
- return (React__default["default"].createElement("div", { className: styles$7.headerTitles }, layout.props.children(headerData)));
250
+ return (React__default["default"].createElement("div", { className: styles$8.headerTitles }, layout.props.children(headerData)));
252
251
  }, mediaMatches: mediaMatches }));
253
252
  }
254
253
 
@@ -264,13 +263,13 @@ function DataListLoadingState({ headers, layouts, mediaMatches, }) {
264
263
  if (layout.props.size === "xs") {
265
264
  return React__default["default"].createElement(LoadingStateXSBreakpoint, null);
266
265
  }
267
- return (React__default["default"].createElement(React__default["default"].Fragment, null, loadingElements.map((child, i) => (React__default["default"].createElement("div", { className: styles$5.loadingItem, key: i, "data-testid": DATALIST_LOADINGSTATE_ROW_TEST_ID }, layout.props.children(child))))));
266
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, loadingElements.map((child, i) => (React__default["default"].createElement("div", { className: styles$6.loadingItem, key: i, "data-testid": DATALIST_LOADINGSTATE_ROW_TEST_ID }, layout.props.children(child))))));
268
267
  } }));
269
268
  }
270
269
  function LoadingStateXSBreakpoint() {
271
270
  const loadingData = new Array(LOADING_STATE_LIMIT_ITEMS).fill(0);
272
271
  return (React__default["default"].createElement(React__default["default"].Fragment, null, loadingData.map((_, i) => {
273
- return (React__default["default"].createElement("div", { className: styles$5.mobileLoadingState, key: i },
272
+ return (React__default["default"].createElement("div", { className: styles$6.mobileLoadingState, key: i },
274
273
  React__default["default"].createElement(Glimmer.Glimmer.Text, null)));
275
274
  })));
276
275
  }
@@ -281,9 +280,9 @@ _) {
281
280
  return React__default["default"].createElement(React__default["default"].Fragment, null);
282
281
  }
283
282
 
284
- var css_248z$3 = ".E-mG3prPSN8- {\n -ms-flex-item-align: center;\n align-self: center;\n position: relative;\n min-width: 0;\n}\n\n._0LGNoZxtqSE- {\n display: grid;\n overflow-x: auto;\n grid-auto-flow: column;\n grid-auto-columns: -webkit-max-content;\n grid-auto-columns: max-content;\n -ms-flex-align: center;\n align-items: center;\n}\n\n._0LGNoZxtqSE- > :nth-child(n + 3):not(:last-child) {\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n\n.LA3-gtgehrE- {\n visibility: hidden;\n}\n\n.fSPvawYWzZ8-::before,\n.ChfEJMPPVTk-::after {\n content: \"\";\n position: absolute;\n top: 0;\n width: calc(16px * 1.5);\n width: var(--space-large);\n height: 100%;\n background-image: linear-gradient(\n to right,\n rgba(255, 255, 255, 1) 0%,\n rgba(255, 255, 255, 0) 100%\n );\n background-image: linear-gradient(\n var(--data-list-filters-overflow-shadow-angle, to right),\n var(--color-surface) 0%,\n rgba(var(--color-white--rgb), 0) 100%\n );\n pointer-events: none;\n}\n\n.fSPvawYWzZ8-::before {\n left: 0;\n}\n\n.ChfEJMPPVTk-::after {\n --data-list-filters-overflow-shadow-angle: to left;\n right: 0;\n}\n";
285
- var styles$3 = {"filters":"E-mG3prPSN8-","filterActions":"_0LGNoZxtqSE-","overflowTrigger":"LA3-gtgehrE-","overflowLeft":"fSPvawYWzZ8-","overflowRight":"ChfEJMPPVTk-"};
286
- styleInject_es.styleInject(css_248z$3);
283
+ var css_248z$4 = ".E-mG3prPSN8- {\n -ms-flex-item-align: center;\n align-self: center;\n position: relative;\n min-width: 0;\n}\n\n._0LGNoZxtqSE- {\n display: grid;\n overflow-x: auto;\n grid-auto-flow: column;\n grid-auto-columns: -webkit-max-content;\n grid-auto-columns: max-content;\n -ms-flex-align: center;\n align-items: center;\n}\n\n._0LGNoZxtqSE- > :nth-child(n + 3):not(:last-child) {\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n\n.LA3-gtgehrE- {\n visibility: hidden;\n}\n\n.fSPvawYWzZ8-::before,\n.ChfEJMPPVTk-::after {\n content: \"\";\n position: absolute;\n top: 0;\n width: calc(16px * 1.5);\n width: var(--space-large);\n height: 100%;\n background-image: linear-gradient(\n to right,\n rgba(255, 255, 255, 1) 0%,\n rgba(255, 255, 255, 0) 100%\n );\n background-image: linear-gradient(\n var(--data-list-filters-overflow-shadow-angle, to right),\n var(--color-surface) 0%,\n rgba(var(--color-white--rgb), 0) 100%\n );\n pointer-events: none;\n}\n\n.fSPvawYWzZ8-::before {\n left: 0;\n}\n\n.ChfEJMPPVTk-::after {\n --data-list-filters-overflow-shadow-angle: to left;\n right: 0;\n}\n";
284
+ var styles$4 = {"filters":"E-mG3prPSN8-","filterActions":"_0LGNoZxtqSE-","overflowTrigger":"LA3-gtgehrE-","overflowLeft":"fSPvawYWzZ8-","overflowRight":"ChfEJMPPVTk-"};
285
+ styleInject_es.styleInject(css_248z$4);
287
286
 
288
287
  const CONTAINER_TEST_ID = "ATL-DataListFilters-Container";
289
288
 
@@ -314,19 +313,19 @@ function InternalDataListFilters() {
314
313
  if (!component)
315
314
  return null;
316
315
  const { children } = component.props;
317
- return (React__default["default"].createElement("div", { "data-testid": CONTAINER_TEST_ID, className: classnames__default["default"](styles$3.filters, {
318
- [styles$3.overflowLeft]: !isLeftVisible,
319
- [styles$3.overflowRight]: !isRightVisible,
316
+ return (React__default["default"].createElement("div", { "data-testid": CONTAINER_TEST_ID, className: classnames__default["default"](styles$4.filters, {
317
+ [styles$4.overflowLeft]: !isLeftVisible,
318
+ [styles$4.overflowRight]: !isRightVisible,
320
319
  }) },
321
- React__default["default"].createElement("div", { className: styles$3.filterActions },
322
- React__default["default"].createElement("span", { ref: leftRef, className: styles$3.overflowTrigger }),
320
+ React__default["default"].createElement("div", { className: styles$4.filterActions },
321
+ React__default["default"].createElement("span", { ref: leftRef, className: styles$4.overflowTrigger }),
323
322
  children,
324
- React__default["default"].createElement("span", { ref: rightRef, className: styles$3.overflowTrigger }))));
323
+ React__default["default"].createElement("span", { ref: rightRef, className: styles$4.overflowTrigger }))));
325
324
  }
326
325
 
327
- var css_248z$2 = ".PGOHzrMh374- {\n --offset: 1px;\n --sticky-header-transition-properties: var(--timing-base) ease-in-out;\n\n position: sticky;\n top: calc(1px * -1);\n top: calc(var(--offset) * -1);\n z-index: 1;\n z-index: var(--elevation-base);\n padding-top: 1px;\n padding-top: var(--offset);\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n/**\n * Draw a border that gets covered by the column headers border when it shows up.\n *\n * Mostly to prevent us from writing some complex JS to remove the border when\n * the column headers show up.\n */\n\n.PGOHzrMh374-::before {\n content: \"\";\n display: block;\n position: absolute;\n bottom: 0;\n left: 50%;\n z-index: -1;\n width: 0;\n height: 0;\n background-color: rgb(225, 225, 225);\n background-color: var(--color-border);\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n transition: height var(--sticky-header-transition-properties)\n 100ms,\n width var(--sticky-header-transition-properties);\n transition: height var(--sticky-header-transition-properties)\n var(--timing-quick),\n width var(--sticky-header-transition-properties);\n}\n\n.PGjWc5ocjpI-::before {\n width: 100%;\n height: calc(16px / 8);\n height: var(--border-thick);\n transition: height var(--sticky-header-transition-properties),\n width var(--sticky-header-transition-properties) 100ms;\n transition: height var(--sticky-header-transition-properties),\n width var(--sticky-header-transition-properties) var(--timing-quick);\n}\n";
328
- var styles$2 = {"header":"PGOHzrMh374-","stuck":"PGjWc5ocjpI-"};
329
- styleInject_es.styleInject(css_248z$2);
326
+ var css_248z$3 = ".PGOHzrMh374- {\n --offset: 1px;\n --sticky-header-transition-properties: var(--timing-base) ease-in-out;\n\n position: sticky;\n top: calc(1px * -1);\n top: calc(var(--offset) * -1);\n z-index: 1;\n z-index: var(--elevation-base);\n padding-top: 1px;\n padding-top: var(--offset);\n background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n}\n\n/**\n * Draw a border that gets covered by the column headers border when it shows up.\n *\n * Mostly to prevent us from writing some complex JS to remove the border when\n * the column headers show up.\n */\n\n.PGOHzrMh374-::before {\n content: \"\";\n display: block;\n position: absolute;\n bottom: 0;\n left: 50%;\n z-index: -1;\n width: 0;\n height: 0;\n background-color: rgb(225, 225, 225);\n background-color: var(--color-border);\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n transition: height var(--sticky-header-transition-properties)\n 100ms,\n width var(--sticky-header-transition-properties);\n transition: height var(--sticky-header-transition-properties)\n var(--timing-quick),\n width var(--sticky-header-transition-properties);\n}\n\n.PGjWc5ocjpI-::before {\n width: 100%;\n height: calc(16px / 8);\n height: var(--border-thick);\n transition: height var(--sticky-header-transition-properties),\n width var(--sticky-header-transition-properties) 100ms;\n transition: height var(--sticky-header-transition-properties),\n width var(--sticky-header-transition-properties) var(--timing-quick);\n}\n";
327
+ var styles$3 = {"header":"PGOHzrMh374-","stuck":"PGjWc5ocjpI-"};
328
+ styleInject_es.styleInject(css_248z$3);
330
329
 
331
330
  function DataListStickyHeader({ children }) {
332
331
  const [isStuck, setIsStuck] = React.useState(false);
@@ -341,12 +340,12 @@ function DataListStickyHeader({ children }) {
341
340
  ref.current && observer.unobserve(ref.current);
342
341
  };
343
342
  }, [handleObserver, ref.current]);
344
- return (React__default["default"].createElement("div", { ref: ref, className: classnames__default["default"](styles$2.header, { [styles$2.stuck]: isStuck }) }, children));
343
+ return (React__default["default"].createElement("div", { ref: ref, className: classnames__default["default"](styles$3.header, { [styles$3.stuck]: isStuck }) }, children));
345
344
  }
346
345
 
347
- var css_248z$1 = ".SaPMOnvw-3c- {\n --transition-properties: var(--timing-base) ease-in-out;\n --button-offset: calc(var(--space-largest) - var(--space-smallest));\n\n position: absolute;\n /* Inputs are off by 1 when put beside a button */\n top: calc((16px / 2) - 1px);\n top: calc(calc(16px / 2) - 1px);\n top: calc(var(--space-small) - 1px);\n right: calc((16px * 3) - (16px / 8));\n right: calc(calc(16px * 3) - calc(16px / 8));\n right: var(--button-offset);\n visibility: hidden;\n width: 0;\n opacity: 0;\n transition: opacity 200ms ease-in-out,\n width 200ms ease-in-out, visibility 200ms ease-in-out;\n transition: opacity var(--transition-properties),\n width var(--transition-properties), visibility var(--transition-properties);\n}\n\n._3S1-91v2SYI- {\n visibility: visible;\n width: calc(100% - var(--button-offset));\n opacity: 1;\n}\n\n@media (min-width: 768px) {\n\n.SaPMOnvw-3c-,\n._3S1-91v2SYI- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n.SaPMOnvw-3c-,\n._3S1-91v2SYI- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n }\n\n._9GlBktsUALw- {\n display: block;\n}\n\n@media (min-width: 768px) {\n\n._9GlBktsUALw- {\n display: none;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n._9GlBktsUALw- {\n display: none;\n}\n }\n\n/*\n * No Filters Styling\n *\n * When there are no filters, the search input is always visible.\n * ------------------------------------------------------------------------- */\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n\n@media (min-width: 768px) {\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n max-width: 30%;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n max-width: 30%;\n}\n }\n\n._3Pjrt42x454- ._9GlBktsUALw- {\n display: none;\n}\n";
348
- var styles$1 = {"searchInput":"SaPMOnvw-3c-","searchInputVisible":"_3S1-91v2SYI-","searchButton":"_9GlBktsUALw-","withNoFilters":"_3Pjrt42x454-"};
349
- styleInject_es.styleInject(css_248z$1);
346
+ var css_248z$2 = ".SaPMOnvw-3c- {\n --transition-properties: var(--timing-base) ease-in-out;\n --button-offset: calc(var(--space-largest) - var(--space-smallest));\n\n position: absolute;\n /* Inputs are off by 1 when put beside a button */\n top: calc((16px / 2) - 1px);\n top: calc(calc(16px / 2) - 1px);\n top: calc(var(--space-small) - 1px);\n right: calc((16px * 3) - (16px / 8));\n right: calc(calc(16px * 3) - calc(16px / 8));\n right: var(--button-offset);\n visibility: hidden;\n width: 0;\n opacity: 0;\n transition: opacity 200ms ease-in-out,\n width 200ms ease-in-out, visibility 200ms ease-in-out;\n transition: opacity var(--transition-properties),\n width var(--transition-properties), visibility var(--transition-properties);\n}\n\n._3S1-91v2SYI- {\n visibility: visible;\n width: calc(100% - var(--button-offset));\n opacity: 1;\n}\n\n@media (min-width: 768px) {\n\n.SaPMOnvw-3c-,\n._3S1-91v2SYI- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n.SaPMOnvw-3c-,\n._3S1-91v2SYI- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n }\n\n._9GlBktsUALw- {\n display: block;\n}\n\n@media (min-width: 768px) {\n\n._9GlBktsUALw- {\n display: none;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n._9GlBktsUALw- {\n display: none;\n}\n }\n\n/*\n * No Filters Styling\n *\n * When there are no filters, the search input is always visible.\n * ------------------------------------------------------------------------- */\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n position: static;\n visibility: visible;\n width: auto;\n opacity: 1;\n transition: none;\n}\n\n@media (min-width: 768px) {\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n max-width: 30%;\n}\n }\n\n@media (--medium-screens-and-up) {\n\n._3Pjrt42x454- .SaPMOnvw-3c- {\n max-width: 30%;\n}\n }\n\n._3Pjrt42x454- ._9GlBktsUALw- {\n display: none;\n}\n";
347
+ var styles$2 = {"searchInput":"SaPMOnvw-3c-","searchInputVisible":"_3S1-91v2SYI-","searchButton":"_9GlBktsUALw-","withNoFilters":"_3Pjrt42x454-"};
348
+ styleInject_es.styleInject(css_248z$2);
350
349
 
351
350
  const DATA_LIST_SEARCH_TEST_ID = "ATL-DataList-Search-input-wrapper";
352
351
  // This component is meant to capture the props of the DataList.Search
@@ -365,12 +364,12 @@ function InternalDataListSearch() {
365
364
  if (!searchComponent)
366
365
  return null;
367
366
  const { placeholder } = searchComponent.props;
368
- return (React__default["default"].createElement("div", { className: classnames__default["default"]({ [styles$1.withNoFilters]: !filterComponent }) },
369
- React__default["default"].createElement("div", { "data-testid": DATA_LIST_SEARCH_TEST_ID, className: classnames__default["default"](styles$1.searchInput, {
370
- [styles$1.searchInputVisible]: visible,
367
+ return (React__default["default"].createElement("div", { className: classnames__default["default"]({ [styles$2.withNoFilters]: !filterComponent }) },
368
+ React__default["default"].createElement("div", { "data-testid": DATA_LIST_SEARCH_TEST_ID, className: classnames__default["default"](styles$2.searchInput, {
369
+ [styles$2.searchInputVisible]: visible,
371
370
  }) },
372
371
  React__default["default"].createElement(InputText.InputText, { ref: inputRef, placeholder: getPlaceholder(), onChange: debouncedSearch, prefix: { icon: "search" }, size: "small" })),
373
- React__default["default"].createElement("div", { className: styles$1.searchButton },
372
+ React__default["default"].createElement("div", { className: styles$2.searchButton },
374
373
  React__default["default"].createElement(AnimatedSwitcher.AnimatedSwitcher, { switched: visible, initialChild: React__default["default"].createElement(Button.Button, { variation: "subtle", icon: "search", ariaLabel: "Search", onClick: toggleSearch }), switchTo: React__default["default"].createElement(Button.Button, { variation: "subtle", icon: "remove", ariaLabel: "Close search bar", onClick: toggleSearch }) }))));
375
374
  function getPlaceholder() {
376
375
  if (placeholder)
@@ -388,9 +387,9 @@ function InternalDataListSearch() {
388
387
  }
389
388
  }
390
389
 
391
- var css_248z = ".zg3w9nQga-M- {\n display: -ms-flexbox;\n display: flex;\n box-sizing: border-box;\n padding: calc(16px * 1);\n padding: var(--space-base);\n -ms-flex-pack: center;\n justify-content: center;\n -ms-flex-direction: column;\n flex-direction: column;\n row-gap: calc(16px * 1);\n row-gap: var(--space-base);\n -ms-flex-align: center;\n align-items: center;\n -ms-flex: 1;\n flex: 1;\n}\n";
392
- var styles = {"emptyStateWrapper":"zg3w9nQga-M-"};
393
- styleInject_es.styleInject(css_248z);
390
+ var css_248z$1 = ".zg3w9nQga-M- {\n display: -ms-flexbox;\n display: flex;\n box-sizing: border-box;\n padding: calc(16px * 1);\n padding: var(--space-base);\n -ms-flex-pack: center;\n justify-content: center;\n -ms-flex-direction: column;\n flex-direction: column;\n row-gap: calc(16px * 1);\n row-gap: var(--space-base);\n -ms-flex-align: center;\n align-items: center;\n -ms-flex: 1;\n flex: 1;\n}\n";
391
+ var styles$1 = {"emptyStateWrapper":"zg3w9nQga-M-"};
392
+ styleInject_es.styleInject(css_248z$1);
394
393
 
395
394
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
396
395
  function DataListEmptyState(_) {
@@ -399,7 +398,7 @@ function DataListEmptyState(_) {
399
398
  function InternalDataListEmptyState() {
400
399
  const { emptyStateComponents: components, filtered } = React.useContext(DataListContext);
401
400
  const { message, action } = getMessages();
402
- return (React__default["default"].createElement("div", { className: styles.emptyStateWrapper },
401
+ return (React__default["default"].createElement("div", { className: styles$1.emptyStateWrapper },
403
402
  React__default["default"].createElement(Text.Text, { align: "center" }, message),
404
403
  renderButton(action)));
405
404
  function getMessages() {
@@ -433,6 +432,19 @@ function getEmptyStates(components) {
433
432
  return { defaultEmptyState, filteredEmptyState };
434
433
  }
435
434
 
435
+ var css_248z = ".IC-Y9bTIVFo- {\n position: relative;\n -webkit-transform: translateY(calc((16px * 3) * -1));\n -webkit-transform: translateY(calc(calc(16px * 3) * -1));\n -webkit-transform: translateY(calc(var(--space-largest) * -1));\n transform: translateY(calc((16px * 3) * -1));\n transform: translateY(calc(calc(16px * 3) * -1));\n transform: translateY(calc(var(--space-largest) * -1));\n}\n";
436
+ var styles = {"trigger":"IC-Y9bTIVFo-"};
437
+ styleInject_es.styleInject(css_248z);
438
+
439
+ function DataListLoadMore() {
440
+ const { onLoadMore } = useDataListContext();
441
+ const [inViewRef, isInView] = useInView.useInView();
442
+ React.useEffect(() => {
443
+ isInView && (onLoadMore === null || onLoadMore === void 0 ? void 0 : onLoadMore());
444
+ }, [isInView]);
445
+ return (React__default["default"].createElement("div", { ref: inViewRef, className: styles.trigger, "data-testid": DATA_LOAD_MORE_TEST_ID }));
446
+ }
447
+
436
448
  function useLayoutMediaQueries() {
437
449
  const mediaQueries = BREAKPOINTS.reduce((previous, breakpoint) => (Object.assign(Object.assign({}, previous), { [breakpoint]: window.matchMedia(breakpointToMediaQuery(breakpoint)) })), {});
438
450
  const initialMatches = BREAKPOINTS.reduce((previous, breakpoint) => (Object.assign(Object.assign({}, previous), { [breakpoint]: mediaQueries[breakpoint].matches })), {});
@@ -475,22 +487,24 @@ function InternalDataList() {
475
487
  const mediaMatches = useLayoutMediaQueries();
476
488
  const initialLoading = loadingState === "initial";
477
489
  const showEmptyState = !initialLoading && data.length === 0;
478
- return (React__default["default"].createElement("div", { className: styles$7.wrapper },
479
- React__default["default"].createElement("div", { className: styles$7.titleContainer },
490
+ const shouldRenderLoadMoreTrigger = !initialLoading && !showEmptyState;
491
+ return (React__default["default"].createElement("div", { className: styles$8.wrapper },
492
+ React__default["default"].createElement("div", { className: styles$8.titleContainer },
480
493
  title && React__default["default"].createElement(Heading.Heading, { level: 3 }, title),
481
494
  React__default["default"].createElement(DataListTotalCount, { totalCount: totalCount, loading: initialLoading })),
482
495
  React__default["default"].createElement(DataListStickyHeader, null,
483
- React__default["default"].createElement("div", { className: styles$7.headerFilters },
496
+ React__default["default"].createElement("div", { className: styles$8.headerFilters },
484
497
  React__default["default"].createElement(InternalDataListFilters, null),
485
498
  React__default["default"].createElement(InternalDataListSearch, null)),
486
499
  headerData && (React__default["default"].createElement(DataListHeader, { layouts: layoutComponents, headerData: headerData, headerVisibility: headerVisibility, mediaMatches: mediaMatches }))),
487
500
  initialLoading && (React__default["default"].createElement(DataListLoadingState, { headers: headers, layouts: layoutComponents, mediaMatches: mediaMatches })),
488
501
  showEmptyState && React__default["default"].createElement(InternalDataListEmptyState, null),
489
502
  !initialLoading && (React__default["default"].createElement(DataListItems, { data: data, layouts: layoutComponents, mediaMatches: mediaMatches })),
490
- loadingState === "filtering" && (React__default["default"].createElement("div", { "data-testid": DATA_LIST_FILTERING_SPINNER_TEST_ID, className: styles$7.filtering },
491
- React__default["default"].createElement("div", { className: styles$7.filteringSpinner },
503
+ loadingState === "filtering" && (React__default["default"].createElement("div", { "data-testid": DATA_LIST_FILTERING_SPINNER_TEST_ID, className: styles$8.filtering },
504
+ React__default["default"].createElement("div", { className: styles$8.filteringSpinner },
492
505
  React__default["default"].createElement(Spinner.Spinner, { size: "small" })))),
493
- loadingState === "loadingMore" && (React__default["default"].createElement("div", { "data-testid": DATA_LIST_LOADING_MORE_SPINNER_TEST_ID, className: styles$7.loadingMore },
506
+ shouldRenderLoadMoreTrigger && React__default["default"].createElement(DataListLoadMore, null),
507
+ loadingState === "loadingMore" && (React__default["default"].createElement("div", { "data-testid": DATA_LIST_LOADING_MORE_SPINNER_TEST_ID, className: styles$8.loadingMore },
494
508
  React__default["default"].createElement(Spinner.Spinner, { size: "small" })))));
495
509
  }
496
510
  DataList.Layout = DataListLayout;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "4.32.1",
3
+ "version": "4.33.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -84,5 +84,5 @@
84
84
  "> 1%",
85
85
  "IE 10"
86
86
  ],
87
- "gitHead": "71e830b2c91ff606f62100920e4ece78daa79b4b"
87
+ "gitHead": "4ad7db01af3c57a0eefed5e714059615d71b56d3"
88
88
  }