@jobber/components 4.45.2 → 4.45.4

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.
@@ -8,7 +8,7 @@ import { DataListAction } from "./components/DataListAction";
8
8
  import { DataListLayoutActions } from "./components/DataListLayoutActions";
9
9
  import { DataListBulkActionProps, DataListObject, DataListProps } from "./DataList.types";
10
10
  import { DataListBulkActions } from "./components/DataListBulkActions";
11
- export declare function DataList<T extends DataListObject>({ sorting, ...props }: DataListProps<T>): JSX.Element;
11
+ export declare function DataList<T extends DataListObject>({ selected, sorting, ...props }: DataListProps<T>): JSX.Element;
12
12
  export declare namespace DataList {
13
13
  var Layout: typeof DataListLayout;
14
14
  var LayoutActions: typeof DataListLayoutActions;
@@ -102,8 +102,9 @@ export interface DataListProps<T extends DataListObject> {
102
102
  readonly selected?: T["id"][];
103
103
  readonly onSelectAll?: () => void;
104
104
  }
105
+ export type LayoutRenderer<T extends DataListObject> = (item: DataListItemType<T[]>) => JSX.Element;
105
106
  export interface DataListLayoutProps<T extends DataListObject> {
106
- readonly children: (item: DataListItemType<T[]>) => JSX.Element;
107
+ readonly children: LayoutRenderer<T>;
107
108
  /**
108
109
  * The breakpoint at which the layout should be displayed. It will be rendered until a layout with a larger breakpoint is found.
109
110
  * @default "xs"
@@ -149,6 +150,12 @@ export interface DataListContextProps<T extends DataListObject> extends DataList
149
150
  readonly layoutComponents?: ReactElement<DataListLayoutProps<T>>[];
150
151
  readonly itemActionComponent?: ReactElement<DataListItemActionsProps<T>>;
151
152
  readonly bulkActionsComponent?: ReactElement<DataListItemActionsProps<T>>;
153
+ readonly layoutBreakpoints: Breakpoints[];
154
+ readonly registerLayoutBreakpoints: (breakpoint: Breakpoints) => void;
155
+ readonly layouts: {
156
+ readonly [Breakpoint in Breakpoints]?: LayoutRenderer<T>;
157
+ };
158
+ readonly registerLayout: (size: Breakpoints, layout: LayoutRenderer<T>) => void;
152
159
  }
153
160
  export interface DataListLayoutContextProps {
154
161
  readonly isInLayoutProvider: boolean;
@@ -17,5 +17,5 @@ export declare function generateListItemElement<T extends DataListObject>(item:
17
17
  * Generate the header elements with the default styling
18
18
  */
19
19
  export declare function generateHeaderElements<T extends DataListObject>(headers: DataListHeader<T>): DataListItemTypeFromHeader<T, DataListHeader<T>> | undefined;
20
- export declare function sortSizeProp(sizeProp: Breakpoints[]): ("xs" | "sm" | "md" | "lg" | "xl")[];
20
+ export declare function sortBreakpoints(sizeProp: Breakpoints[]): ("xs" | "sm" | "md" | "lg" | "xl")[];
21
21
  export declare function getExposedActions(childrenArray: ReactElement[], childCount?: number): React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function DataListHeader(): JSX.Element | null;
@@ -0,0 +1 @@
1
+ export * from "./DataListHeader";
@@ -1,9 +1,9 @@
1
- import { ReactElement } from "react";
1
+ /// <reference types="react" />
2
2
  import { DataListLayoutProps, DataListObject } from "@jobber/components/DataList/DataList.types";
3
3
  interface DataListItem<T extends DataListObject> {
4
4
  readonly item: T;
5
5
  readonly index: number;
6
- readonly layout: ReactElement<DataListLayoutProps<T>>;
6
+ readonly layout: DataListLayoutProps<T>["children"];
7
7
  }
8
8
  export declare function DataListItem<T extends DataListObject>({ item, layout, }: DataListItem<T>): JSX.Element;
9
9
  export {};
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import { Breakpoints, DataListObject } from "@jobber/components/DataList/DataList.types";
3
+ interface DataListItemsProps {
4
+ readonly size?: Breakpoints;
5
+ }
6
+ export declare function DataListItems<T extends DataListObject>({ size, }: DataListItemsProps): JSX.Element | null;
7
+ export {};
@@ -0,0 +1 @@
1
+ export * from "./DataListItems";
@@ -1,3 +1,3 @@
1
1
  /// <reference types="react" />
2
- import { DataListLayoutProps, DataListObject } from "../../DataList.types";
3
- export declare function DataListLayout<T extends DataListObject>(_: DataListLayoutProps<T>): JSX.Element;
2
+ import { DataListLayoutProps, DataListObject } from "@jobber/components/DataList/DataList.types";
3
+ export declare function DataListLayout<T extends DataListObject>({ children, size, }: DataListLayoutProps<T>): JSX.Element | null;
@@ -1,11 +1,4 @@
1
- import React from "react";
2
- import { Breakpoints, DataListHeader, DataListLayoutProps, DataListObject } from "../../DataList.types";
3
- interface DataListLoadingStateProps<T extends DataListObject> {
4
- readonly headers: DataListHeader<T>;
5
- readonly layouts: React.ReactElement<DataListLayoutProps<T>>[] | undefined;
6
- readonly mediaMatches?: Record<Breakpoints, boolean>;
7
- }
1
+ /// <reference types="react" />
8
2
  export declare const LOADING_STATE_LIMIT_ITEMS = 10;
9
3
  export declare const DATALIST_LOADINGSTATE_ROW_TEST_ID = "ATL-DataList-LoadingState-Row";
10
- export declare function DataListLoadingState<T extends DataListObject>({ headers, layouts, mediaMatches, }: DataListLoadingStateProps<T>): JSX.Element;
11
- export {};
4
+ export declare function DataListLoadingState(): JSX.Element | null;
@@ -1,5 +1,5 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  import { DataListContextProps, DataListObject } from "../../DataList.types";
3
3
  export declare const defaultValues: DataListContextProps<DataListObject>;
4
- export declare const DataListContext: import("react").Context<DataListContextProps<DataListObject>>;
5
- export declare function useDataListContext(): DataListContextProps<DataListObject>;
4
+ export declare const DataListContext: React.Context<DataListContextProps<DataListObject>>;
5
+ export declare function useDataListContext<T extends DataListObject>(): DataListContextProps<T>;
@@ -0,0 +1,4 @@
1
+ export declare function useActiveLayout(): {
2
+ layout: import("../DataList.types").LayoutRenderer<import("../DataList.types").DataListObject> | undefined;
3
+ activeBreakpoint: "xs" | "sm" | "md" | "lg" | "xl";
4
+ };
@@ -7,28 +7,24 @@ var React = require('react');
7
7
  var styleInject_es = require('../style-inject.es-9d2f5f4e.js');
8
8
  var Text = require('../Text-59bde58c.js');
9
9
  var Glimmer = require('../Glimmer-cfa92a88.js');
10
- var framerMotion = require('framer-motion');
11
- var classnames = require('classnames');
12
10
  var noop = require('lodash/noop');
13
11
  var design = require('@jobber/design');
14
- var ReactDOM = require('react-dom');
12
+ var framerMotion = require('framer-motion');
13
+ var classnames = require('classnames');
15
14
  var Tooltip = require('../Tooltip-59dbab5b.js');
16
- require('react-popper');
17
- var Typography = require('../Typography-9bff9c91.js');
18
- var reactRouterDom = require('react-router-dom');
19
15
  var Button = require('../Button-d89f2271.js');
20
16
  var useInView = require('@jobber/hooks/useInView');
21
17
  var isEmpty = require('lodash/isEmpty');
22
18
  var InlineLabel = require('../InlineLabel-3d461632.js');
19
+ var FormatDate = require('../FormatDate-70ea5b43.js');
20
+ var Heading = require('../Heading-4562900a.js');
23
21
  var useFocusTrap = require('@jobber/hooks/useFocusTrap');
24
22
  var useRefocusOnActivator = require('@jobber/hooks/useRefocusOnActivator');
25
23
  var useOnKeyDown = require('@jobber/hooks/useOnKeyDown');
24
+ var ReactDOM = require('react-dom');
26
25
  var foundation = require('@jobber/design/foundation');
27
- require('uuid');
28
- require('react-hook-form');
29
26
  var Checkbox = require('../Checkbox-eac63b7f.js');
30
- var FormatDate = require('../FormatDate-70ea5b43.js');
31
- var Heading = require('../Heading-4562900a.js');
27
+ var reactRouterDom = require('react-router-dom');
32
28
  var AnimatedSwitcher = require('../AnimatedSwitcher-d1e1ddcf.js');
33
29
  var Popover = require('../Popover-d401fb54.js');
34
30
  var Content = require('../Content-2ca1ffe1.js');
@@ -36,10 +32,14 @@ var Chip = require('../Chip-4d8e6370.js');
36
32
  require('@jobber/hooks/useAssert');
37
33
  require('../Avatar-1aa30ee1.js');
38
34
  require('color');
35
+ var Typography = require('../Typography-9bff9c91.js');
36
+ require('react-popper');
39
37
  var debounce = require('lodash/debounce');
40
38
  var InputText = require('../InputText-5ac5cfe0.js');
41
39
  var Spinner = require('../Spinner-9d8fc7ff.js');
42
40
  var Icon = require('../Icon-405a216c.js');
41
+ require('uuid');
42
+ require('react-hook-form');
43
43
  require('../ButtonDismiss-250840a4.js');
44
44
  require('lodash/sortBy');
45
45
  require('@jobber/hooks/useLiveAnnounce');
@@ -49,8 +49,8 @@ require('../InputValidation-4e809bdd.js');
49
49
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
50
50
 
51
51
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
52
- var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
53
52
  var noop__default = /*#__PURE__*/_interopDefaultLegacy(noop);
53
+ var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
54
54
  var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
55
55
  var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
56
56
 
@@ -79,36 +79,42 @@ function DataListTotalCount({ totalCount, loading, }) {
79
79
  return (React__default["default"].createElement("div", { className: styles$d.results, "data-testid": DATALIST_TOTALCOUNT_TEST_ID }, output));
80
80
  }
81
81
 
82
- var css_248z$c = ".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";
83
- var styles$c = {"loadingItem":"Rh--6fVpkm4-","mobileLoadingState":"zbS7UvpVoWI-"};
84
- styleInject_es.styleInject(css_248z$c);
85
-
86
82
  const defaultValues$1 = {
87
83
  title: "",
88
84
  data: [],
89
85
  headers: {},
90
86
  children: [],
91
87
  selected: [],
88
+ layoutBreakpoints: [],
89
+ registerLayoutBreakpoints: noop__default["default"],
90
+ layouts: {
91
+ xs: children => React__default["default"].createElement(React__default["default"].Fragment, null, children),
92
+ sm: children => React__default["default"].createElement(React__default["default"].Fragment, null, children),
93
+ md: children => React__default["default"].createElement(React__default["default"].Fragment, null, children),
94
+ lg: children => React__default["default"].createElement(React__default["default"].Fragment, null, children),
95
+ xl: children => React__default["default"].createElement(React__default["default"].Fragment, null, children),
96
+ },
97
+ registerLayout: noop__default["default"],
92
98
  };
93
99
  const DataListContext = React.createContext(defaultValues$1);
94
100
  function useDataListContext() {
95
101
  return React.useContext(DataListContext);
96
102
  }
97
103
 
98
- const defaultValues = {
99
- isInLayoutProvider: false,
100
- hasInLayoutActions: false,
101
- setHasInLayoutActions: noop__default["default"],
102
- };
103
- const DataListLayoutContext = React.createContext(defaultValues);
104
- function useDataListLayoutContext() {
105
- return React.useContext(DataListLayoutContext);
104
+ function useMediaQuery(CSSMediaQuery) {
105
+ const [matches, setMatches] = React.useState(window.matchMedia(CSSMediaQuery).matches);
106
+ React.useEffect(() => {
107
+ const media = window.matchMedia(CSSMediaQuery);
108
+ if (media.matches !== matches) {
109
+ setMatches(media.matches);
110
+ }
111
+ const listener = () => setMatches(media.matches);
112
+ media.addEventListener("change", listener);
113
+ return () => media.removeEventListener("change", listener);
114
+ }, [CSSMediaQuery]);
115
+ return matches;
106
116
  }
107
117
 
108
- var css_248z$b = ".jHcHGQ-HDbk- {\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n top: calc((16px / 2) * -1);\n top: calc(calc(16px / 2) * -1);\n top: calc(var(--space-small) * -1);\n right: 0;\n z-index: 6;\n z-index: var(--elevation-menu);\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 / 4);\n padding: var(--space-smaller);\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 background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n}\n";
109
- var styles$b = {"menu":"jHcHGQ-HDbk-"};
110
- styleInject_es.styleInject(css_248z$b);
111
-
112
118
  const EMPTY_RESULTS_MESSAGE = "List is looking empty";
113
119
  const EMPTY_FILTER_RESULTS_MESSAGE = "No results for selected filters";
114
120
  const EMPTY_STATE_ACTION_BUTTON_ONLY_ERROR = "DataListEmptyState action prop must be a Button component";
@@ -130,6 +136,57 @@ const DATA_LOAD_MORE_TEST_ID = "ATL-DataList-LoadMore-trigger";
130
136
  const TRANSITION_DURATION_IN_SECONDS = design.tokens["timing-base"] / 1000;
131
137
  const TRANSITION_DELAY_IN_SECONDS = design.tokens["timing-quick"] / 1000;
132
138
 
139
+ function useResponsiveSizing() {
140
+ const xs = useMediaQuery(`(width > ${BREAKPOINT_SIZES.xs}px)`);
141
+ const sm = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.sm}px)`);
142
+ const md = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.md}px)`);
143
+ const lg = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.lg}px)`);
144
+ const xl = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.xl}px)`);
145
+ return { xs, sm, md, lg, xl };
146
+ }
147
+
148
+ function useActiveLayout() {
149
+ const { layoutBreakpoints, layouts } = useDataListContext();
150
+ const breakpoints = useResponsiveSizing();
151
+ const reversedLayoutBreakpoints = [...layoutBreakpoints].reverse();
152
+ const activeBreakpoint = reversedLayoutBreakpoints.find(key => breakpoints[key]) ||
153
+ layoutBreakpoints[0];
154
+ const layout = layouts[activeBreakpoint];
155
+ return { layout, activeBreakpoint };
156
+ }
157
+
158
+ var css_248z$c = "._8cMzUF8XEwY- {\n position: relative;\n}\n\n._8cMzUF8XEwY-::after {\n content: \"\";\n display: block;\n position: absolute;\n right: 0;\n bottom: 0;\n left: 0;\n height: 100px;\n background-image: linear-gradient(\n to top,\n rgba(255, 255, 255, 1) 0%,\n rgba(255, 255, 255, 0) 100%\n );\n background-image: linear-gradient(\n to top,\n var(--color-surface) 0%,\n rgba(var(--color-white--rgb), 0) 100%\n );\n}\n\n.Rh--6fVpkm4- {\n padding: calc(16px / 2);\n padding: var(--space-small);\n}\n\n.NFaWWvmxtkw- {\n width: 100%;\n min-width: calc(16px * 3);\n min-width: var(--space-largest);\n}\n";
159
+ var styles$c = {"wrapper":"_8cMzUF8XEwY-","loadingItem":"Rh--6fVpkm4-","glimmer":"NFaWWvmxtkw-"};
160
+ styleInject_es.styleInject(css_248z$c);
161
+
162
+ const LOADING_STATE_LIMIT_ITEMS = 10;
163
+ const DATALIST_LOADINGSTATE_ROW_TEST_ID = "ATL-DataList-LoadingState-Row";
164
+ function DataListLoadingState() {
165
+ const { headers } = useDataListContext();
166
+ const { layout, activeBreakpoint } = useActiveLayout();
167
+ if (!layout)
168
+ return null;
169
+ const glimmerSize = activeBreakpoint === "xs" ? "small" : "base";
170
+ const glimmersFromHeader = Object.keys(headers).reduce((data, key) => (Object.assign(Object.assign({}, data), { [key]: (React__default["default"].createElement("div", { className: styles$c.glimmer },
171
+ React__default["default"].createElement(Glimmer.Glimmer, { size: glimmerSize }))) })), {});
172
+ const loadingData = new Array(LOADING_STATE_LIMIT_ITEMS).fill(glimmersFromHeader);
173
+ return (React__default["default"].createElement("div", { className: styles$c.wrapper }, loadingData.map((child, i) => (React__default["default"].createElement("div", { key: i, className: styles$c.loadingItem, "data-testid": DATALIST_LOADINGSTATE_ROW_TEST_ID }, layout(child))))));
174
+ }
175
+
176
+ const defaultValues = {
177
+ isInLayoutProvider: false,
178
+ hasInLayoutActions: false,
179
+ setHasInLayoutActions: noop__default["default"],
180
+ };
181
+ const DataListLayoutContext = React.createContext(defaultValues);
182
+ function useDataListLayoutContext() {
183
+ return React.useContext(DataListLayoutContext);
184
+ }
185
+
186
+ var css_248z$b = ".jHcHGQ-HDbk- {\n display: -ms-flexbox;\n display: flex;\n position: absolute;\n top: calc((16px / 2) * -1);\n top: calc(calc(16px / 2) * -1);\n top: calc(var(--space-small) * -1);\n right: 0;\n z-index: 6;\n z-index: var(--elevation-menu);\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 / 4);\n padding: var(--space-smaller);\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 background-color: rgba(255, 255, 255, 1);\n background-color: var(--color-surface);\n gap: calc(16px / 4);\n gap: var(--space-smaller);\n}\n";
187
+ var styles$b = {"menu":"jHcHGQ-HDbk-"};
188
+ styleInject_es.styleInject(css_248z$b);
189
+
133
190
  const CONTAINER_TEST_ID = "ATL-DataListFilters-Container";
134
191
 
135
192
  var css_248z$a = ".jbBRoxlZlNI- {\n -ms-flex-item-align: center;\n align-self: center;\n position: relative;\n min-width: 0;\n}\n\n.MnN8qbS4hw4- {\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.MnN8qbS4hw4- > :nth-child(n + 3):not(:last-child) {\n margin-left: calc(16px / 2);\n margin-left: var(--space-small);\n}\n\n.b-5P7Z8eGO8- {\n visibility: hidden;\n}\n\n.xzaCS4slLpI-::before,\n.Jf227kC8Nu0-::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-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.xzaCS4slLpI-::before {\n left: 0;\n}\n\n.Jf227kC8Nu0-::after {\n --data-list-overflow-shadow-angle: to left;\n right: 0;\n}\n";
@@ -301,7 +358,7 @@ function generateHeaderElements(headers) {
301
358
  const headerElements = Object.keys(headers).reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: React__default["default"].createElement(DataListHeaderTile, { headers: headers, headerKey: key }) })), {});
302
359
  return isEmpty__default["default"](headerElements) ? undefined : headerElements;
303
360
  }
304
- function sortSizeProp(sizeProp) {
361
+ function sortBreakpoints(sizeProp) {
305
362
  return sizeProp.sort((a, b) => BREAKPOINTS.indexOf(a) - BREAKPOINTS.indexOf(b));
306
363
  }
307
364
  function getExposedActions(childrenArray, childCount = 2) {
@@ -494,7 +551,7 @@ function DataListItem({ item, layout, }) {
494
551
  [styles$e.active]: showMenu && isContextMenuVisible,
495
552
  }), key: item.id },
496
553
  React__default["default"].createElement(DataListItemInternal, { item: item },
497
- React__default["default"].createElement(DataListItemClickable, null, layout.props.children(generatedItem))),
554
+ React__default["default"].createElement(DataListItemClickable, null, layout(generatedItem))),
498
555
  React__default["default"].createElement(framerMotion.AnimatePresence, null,
499
556
  showMenu && !hasInLayoutActions && React__default["default"].createElement(InternalDataListItemActions, null),
500
557
  React__default["default"].createElement(DataListActionsMenu, { key: item.id, visible: shouldShowContextMenu, position: contextPosition || { x: 0, y: 0 }, onRequestClose: () => setContextPosition(undefined) }, contextMenuActions)))));
@@ -515,69 +572,35 @@ function DataListItem({ item, layout, }) {
515
572
  }
516
573
  }
517
574
 
518
- function DataListLayoutInternal({ layouts, renderLayout, mediaMatches, }) {
519
- const sizePropsOfLayouts = layouts === null || layouts === void 0 ? void 0 : layouts.map(layout => layout.props.size || "xs");
520
- const layoutToRender = layouts === null || layouts === void 0 ? void 0 : layouts.find(layout => {
521
- const layoutSize = layout.props.size || "xs";
522
- const isVisible = isLayoutVisible({
523
- layoutSize,
524
- mediaMatches,
525
- sizePropsOfLayouts,
526
- });
527
- return isVisible;
528
- });
529
- return (layoutToRender && renderLayout(layoutToRender)) || React__default["default"].createElement(React__default["default"].Fragment, null);
530
- }
531
- /**
532
- * Determine is layout is visible by checking a media query matches for the
533
- * visible sizes of the layout and there isn't a larger layout that should be rendered
534
- */
535
- function isLayoutVisible({ layoutSize, mediaMatches, sizePropsOfLayouts, }) {
536
- const largerBreakpointsToHide = sizePropsOfLayouts === null || sizePropsOfLayouts === void 0 ? void 0 : sizePropsOfLayouts.filter(size => BREAKPOINTS.indexOf(size) > BREAKPOINTS.indexOf(layoutSize));
537
- const sortedLargerBreakpoints = sortSizeProp(largerBreakpointsToHide || []);
538
- const visibleBreakpoints = BREAKPOINTS.slice(BREAKPOINTS.indexOf(layoutSize), sortedLargerBreakpoints[0]
539
- ? BREAKPOINTS.indexOf(sortedLargerBreakpoints[0])
540
- : undefined);
541
- const isVisibleBreakpoint = visibleBreakpoints.some(breakpoint => {
542
- return Boolean(mediaMatches === null || mediaMatches === void 0 ? void 0 : mediaMatches[breakpoint]);
543
- });
544
- const largerLayoutIsNotVisible = largerBreakpointsToHide === null || largerBreakpointsToHide === void 0 ? void 0 : largerBreakpointsToHide.reduce((acc, breakpoint) => {
545
- return acc && !(mediaMatches === null || mediaMatches === void 0 ? void 0 : mediaMatches[breakpoint]);
546
- }, true);
547
- return isVisibleBreakpoint && largerLayoutIsNotVisible;
548
- }
549
-
550
- function DataListItems({ layouts, mediaMatches, data, }) {
575
+ function DataListItems({ size = "xs", }) {
576
+ const { data, layouts } = useDataListContext();
551
577
  const [hasInLayoutActions, setHasInLayoutActions] = React.useState(false);
578
+ const layout = layouts[size];
579
+ if (!layout)
580
+ return null;
552
581
  return (React__default["default"].createElement(DataListLayoutContext.Provider, { value: {
553
582
  isInLayoutProvider: true,
554
583
  hasInLayoutActions,
555
584
  setHasInLayoutActions,
556
- } },
557
- React__default["default"].createElement(DataListLayoutInternal, { layouts: layouts, mediaMatches: mediaMatches, renderLayout: layout => (React__default["default"].createElement(React__default["default"].Fragment, null, data.map((child, i) => (React__default["default"].createElement(DataListItem, { key: data[i].id, index: i, item: child, layout: layout }))))) })));
585
+ } }, data.map((child, i) => (React__default["default"].createElement(DataListItem, { key: data[i].id, index: i, item: child, layout: layout })))));
558
586
  }
559
587
 
560
- function useMediaQuery(CSSMediaQuery) {
561
- const [matches, setMatches] = React.useState(window.matchMedia(CSSMediaQuery).matches);
588
+ function DataListLayout({ children, size = "xs", }) {
589
+ const { layoutBreakpoints, registerLayout, registerLayoutBreakpoints, loadingState, } = useDataListContext();
590
+ const breakpoints = useResponsiveSizing();
562
591
  React.useEffect(() => {
563
- const media = window.matchMedia(CSSMediaQuery);
564
- if (media.matches !== matches) {
565
- setMatches(media.matches);
566
- }
567
- const listener = () => setMatches(media.matches);
568
- media.addEventListener("change", listener);
569
- return () => media.removeEventListener("change", listener);
570
- }, [CSSMediaQuery]);
571
- return matches;
572
- }
573
-
574
- function useResponsiveSizing() {
575
- const xs = useMediaQuery(`(width > ${BREAKPOINT_SIZES.xs}px)`);
576
- const sm = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.sm}px)`);
577
- const md = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.md}px)`);
578
- const lg = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.lg}px)`);
579
- const xl = useMediaQuery(`(width >= ${BREAKPOINT_SIZES.xl}px)`);
580
- return { xs, sm, md, lg, xl };
592
+ registerLayoutBreakpoints(size);
593
+ }, [size]);
594
+ React.useEffect(() => {
595
+ registerLayout(size, children);
596
+ }, [size, children]);
597
+ const sizeIndex = layoutBreakpoints.indexOf(size);
598
+ const nextAvailableSize = layoutBreakpoints[sizeIndex + 1];
599
+ const shouldRenderList = breakpoints[size] && !breakpoints[nextAvailableSize];
600
+ if (loadingState !== "initial" && shouldRenderList) {
601
+ return React__default["default"].createElement(DataListItems, { size: size });
602
+ }
603
+ return null;
581
604
  }
582
605
 
583
606
  // This component is meant to capture the props of the DataList.BulkActions
@@ -632,57 +655,26 @@ function DataListHeaderCheckbox({ children }) {
632
655
  }
633
656
  }
634
657
 
635
- function useShowHeader() {
636
- const { headerVisibility } = useDataListContext();
637
- if (headerVisibility === undefined)
638
- return true;
639
- const sizes = useResponsiveSizing();
640
- const sizeKeys = Object.keys(sizes);
641
- const showHeader = sizeKeys.reduce((previous, breakpoint) => {
642
- const isHeaderVisible = headerVisibility[breakpoint] || false;
643
- const isBreakpointTriggered = sizes[breakpoint];
644
- return previous || (isBreakpointTriggered && isHeaderVisible);
645
- }, false);
646
- return showHeader;
647
- }
648
-
649
- function DataListHeader({ layouts, mediaMatches, headerData, }) {
650
- const showHeader = useShowHeader();
651
- const { selected } = useDataListContext();
658
+ function DataListHeader() {
659
+ const breakpoints = useResponsiveSizing();
660
+ const { headerVisibility = { xs: true, sm: true, md: true, lg: true, xl: true }, headers, selected, layoutBreakpoints, } = useDataListContext();
661
+ const size = getVisibleSize();
662
+ const { layout } = useActiveLayout();
663
+ const visible = headerVisibility[size];
652
664
  const noItemsSelected = (selected === null || selected === void 0 ? void 0 : selected.length) === 0;
653
- if ((!showHeader && noItemsSelected) || !headerData)
665
+ if ((!visible && noItemsSelected) || !layout)
654
666
  return null;
655
- return (React__default["default"].createElement(DataListLayoutInternal, { layouts: layouts, mediaMatches: mediaMatches, renderLayout: layout => (React__default["default"].createElement("div", { className: classnames__default["default"](styles$e.headerTitles) },
656
- React__default["default"].createElement(DataListHeaderCheckbox, null, layout.props.children(headerData)))) }));
657
- }
658
-
659
- const LOADING_STATE_LIMIT_ITEMS = 10;
660
- const DATALIST_LOADINGSTATE_ROW_TEST_ID = "ATL-DataList-LoadingState-Row";
661
- function DataListLoadingState({ headers, layouts, mediaMatches, }) {
662
- const loadingData = new Array(LOADING_STATE_LIMIT_ITEMS).fill(headers);
663
- const loadingElements = loadingData.map(item => Object.keys(item).reduce((acc, key) => {
664
- acc[key] = React__default["default"].createElement(Glimmer.Glimmer, null);
665
- return acc;
666
- }, {}));
667
- return (React__default["default"].createElement(DataListLayoutInternal, { layouts: layouts, mediaMatches: mediaMatches, renderLayout: layout => {
668
- if (layout.props.size === "xs") {
669
- return React__default["default"].createElement(LoadingStateXSBreakpoint, null);
670
- }
671
- return (React__default["default"].createElement(React__default["default"].Fragment, null, loadingElements.map((child, i) => (React__default["default"].createElement("div", { className: styles$c.loadingItem, key: i, "data-testid": DATALIST_LOADINGSTATE_ROW_TEST_ID }, layout.props.children(child))))));
672
- } }));
673
- }
674
- function LoadingStateXSBreakpoint() {
675
- const loadingData = new Array(LOADING_STATE_LIMIT_ITEMS).fill(0);
676
- return (React__default["default"].createElement(React__default["default"].Fragment, null, loadingData.map((_, i) => {
677
- return (React__default["default"].createElement("div", { className: styles$c.mobileLoadingState, key: i },
678
- React__default["default"].createElement(Glimmer.Glimmer.Text, null)));
679
- })));
680
- }
681
-
682
- function DataListLayout(
683
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
684
- _) {
685
- return React__default["default"].createElement(React__default["default"].Fragment, null);
667
+ const headerData = generateHeaderElements(headers);
668
+ if (!headerData)
669
+ return null;
670
+ return (React__default["default"].createElement("div", { className: styles$e.headerTitles },
671
+ React__default["default"].createElement(DataListHeaderCheckbox, null, layout(headerData))));
672
+ function getVisibleSize() {
673
+ const visibilityKeys = Object.keys(headerVisibility);
674
+ const headerBreakpoints = sortBreakpoints(visibilityKeys).reverse();
675
+ const visibleHeaderSize = headerBreakpoints.find(key => breakpoints[key]);
676
+ return visibleHeaderSize || layoutBreakpoints[0];
677
+ }
686
678
  }
687
679
 
688
680
  function DataListSort() {
@@ -738,6 +730,20 @@ function DataListSort() {
738
730
  }
739
731
  }
740
732
 
733
+ function useShowHeader() {
734
+ const { headerVisibility } = useDataListContext();
735
+ if (headerVisibility === undefined)
736
+ return true;
737
+ const sizes = useResponsiveSizing();
738
+ const sizeKeys = Object.keys(sizes);
739
+ const showHeader = sizeKeys.reduce((previous, breakpoint) => {
740
+ const isHeaderVisible = headerVisibility[breakpoint] || false;
741
+ const isBreakpointTriggered = sizes[breakpoint];
742
+ return previous || (isBreakpointTriggered && isHeaderVisible);
743
+ }, false);
744
+ return showHeader;
745
+ }
746
+
741
747
  // This component is meant to capture the props of the DataList.Filters
742
748
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
743
749
  function DataListFilters(_) {
@@ -921,7 +927,7 @@ var styles = {"hidden":"_0m75bgCVBhk-"};
921
927
  styleInject_es.styleInject(css_248z);
922
928
 
923
929
  function DataListLayoutActions() {
924
- const { itemActionComponent } = useDataListContext();
930
+ const { itemActionComponent, loadingState } = useDataListContext();
925
931
  const { setHasInLayoutActions } = useDataListLayoutContext();
926
932
  const { children: actionsChildren } = (itemActionComponent === null || itemActionComponent === void 0 ? void 0 : itemActionComponent.props) || {};
927
933
  const actions = React.Children.toArray(actionsChildren);
@@ -932,6 +938,9 @@ function DataListLayoutActions() {
932
938
  setHasInLayoutActions(false);
933
939
  };
934
940
  }, []);
941
+ if (loadingState === "initial") {
942
+ return React__default["default"].createElement(Glimmer.Glimmer, { shape: "square", size: "large" });
943
+ }
935
944
  if (!hasActions)
936
945
  return null;
937
946
  return (React__default["default"].createElement(DataListLayoutActionsWrapper, null,
@@ -944,34 +953,10 @@ function DataListLayoutActionsWrapper({ children }) {
944
953
  return React__default["default"].createElement("div", { className: styles.hidden }, children);
945
954
  }
946
955
 
947
- function useLayoutMediaQueries() {
948
- const mediaQueries = BREAKPOINTS.reduce((previous, breakpoint) => (Object.assign(Object.assign({}, previous), { [breakpoint]: window.matchMedia(breakpointToMediaQuery(breakpoint)) })), {});
949
- const initialMatches = BREAKPOINTS.reduce((previous, breakpoint) => (Object.assign(Object.assign({}, previous), { [breakpoint]: mediaQueries[breakpoint].matches })), {});
950
- const [matches, setMatches] = React.useState(initialMatches);
951
- const handlers = BREAKPOINTS.reduce((previous, breakpoint) => {
952
- const handler = (e) => setMatches(previousMatches => (Object.assign(Object.assign({}, previousMatches), { [breakpoint]: e.matches })));
953
- return Object.assign(Object.assign({}, previous), { [breakpoint]: handler });
954
- }, {});
955
- // Set up mediaQuery event handlers
956
- React.useEffect(() => {
957
- BREAKPOINTS.forEach(breakpoint => {
958
- mediaQueries[breakpoint].addEventListener("change", handlers[breakpoint]);
959
- });
960
- return () => {
961
- BREAKPOINTS.forEach(breakpoint => {
962
- mediaQueries[breakpoint].removeEventListener("change", handlers[breakpoint]);
963
- });
964
- };
965
- }, [mediaQueries]);
966
- return matches;
967
- }
968
- function breakpointToMediaQuery(breakpoint) {
969
- return `(min-width: ${BREAKPOINT_SIZES[breakpoint]}px)`;
970
- }
971
-
972
956
  function DataList(_a) {
973
- var _b;
974
- var { sorting } = _a, props = tslib_es6.__rest(_a, ["sorting"]);
957
+ var { selected = [], sorting } = _a, props = tslib_es6.__rest(_a, ["selected", "sorting"]);
958
+ const [layoutBreakpoints, setLayoutBreakpoints] = React.useState([]);
959
+ const [layouts, setLayouts] = React.useState({});
975
960
  const searchComponent = getCompoundComponent(props.children, DataListSearch);
976
961
  const filterComponent = getCompoundComponent(props.children, DataListFilters);
977
962
  const layoutComponents = getCompoundComponents(props.children, DataListLayout);
@@ -983,16 +968,24 @@ function DataList(_a) {
983
968
  layoutComponents,
984
969
  emptyStateComponents,
985
970
  itemActionComponent,
986
- bulkActionsComponent }, props), { selected: (_b = props.selected) !== null && _b !== void 0 ? _b : [],
971
+ bulkActionsComponent,
972
+ layoutBreakpoints,
973
+ registerLayoutBreakpoints,
974
+ layouts,
975
+ registerLayout }, props), { selected,
987
976
  // T !== DataListObject
988
977
  sorting: sorting }) },
989
978
  React__default["default"].createElement(InternalDataList, null)));
979
+ function registerLayoutBreakpoints(size) {
980
+ setLayoutBreakpoints(prev => sortBreakpoints([...prev, size]));
981
+ }
982
+ function registerLayout(size, children) {
983
+ setLayouts(prev => (Object.assign(Object.assign({}, prev), { [size]: children })));
984
+ }
990
985
  }
991
986
  function InternalDataList() {
992
- const { data, headers, title, totalCount, headerVisibility = { xs: true, sm: true, md: true, lg: true, xl: true }, loadingState = "none", layoutComponents, } = useDataListContext();
987
+ const { data, title, totalCount, loadingState = "none", layoutComponents, } = useDataListContext();
993
988
  const backToTopRef = React.useRef(null);
994
- const headerData = generateHeaderElements(headers);
995
- const mediaMatches = useLayoutMediaQueries();
996
989
  const initialLoading = loadingState === "initial";
997
990
  const showEmptyState = !initialLoading && data.length === 0;
998
991
  const shouldRenderLoadMoreTrigger = !initialLoading && !showEmptyState;
@@ -1005,10 +998,10 @@ function InternalDataList() {
1005
998
  React__default["default"].createElement("div", { className: styles$e.headerFilters },
1006
999
  React__default["default"].createElement(InternalDataListFilters, null),
1007
1000
  React__default["default"].createElement(InternalDataListSearch, null)),
1008
- headerData && (React__default["default"].createElement(DataListHeader, { layouts: layoutComponents, headerData: headerData, headerVisibility: headerVisibility, mediaMatches: mediaMatches }))),
1009
- initialLoading && (React__default["default"].createElement(DataListLoadingState, { headers: headers, layouts: layoutComponents, mediaMatches: mediaMatches })),
1001
+ React__default["default"].createElement(DataListHeader, null)),
1002
+ initialLoading && React__default["default"].createElement(DataListLoadingState, null),
1010
1003
  showEmptyState && React__default["default"].createElement(InternalDataListEmptyState, null),
1011
- !initialLoading && (React__default["default"].createElement(DataListItems, { data: data, layouts: layoutComponents, mediaMatches: mediaMatches })),
1004
+ layoutComponents,
1012
1005
  loadingState === "filtering" && (React__default["default"].createElement("div", { "data-testid": DATA_LIST_FILTERING_SPINNER_TEST_ID, className: styles$e.filtering },
1013
1006
  React__default["default"].createElement("div", { className: styles$e.filteringSpinner },
1014
1007
  React__default["default"].createElement(Spinner.Spinner, { size: "small" })))),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "4.45.2",
3
+ "version": "4.45.4",
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": "52699bf3dddbab1cb9f56e9399952ee5f6c389b3"
87
+ "gitHead": "58229de1e3ea0c47e84fe6d4168f81e4f388a362"
88
88
  }
package/rollup.config.js CHANGED
@@ -60,14 +60,11 @@ export default {
60
60
  "framer-motion",
61
61
  "classnames",
62
62
  "uuid",
63
- "lodash/debounce",
64
- "lodash/get",
65
- "lodash/groupBy",
66
- "lodash/omit",
67
- "lodash/sortBy",
63
+ new RegExp("lodash/.*"),
68
64
  "@std-proposal/temporal",
69
65
  "@use-it/event-listener",
70
66
  "@jobber/design",
67
+ "@jobber/design/foundation",
71
68
  "@jobber/formatters",
72
69
  new RegExp("@jobber/hooks/.*"),
73
70
  "zxcvbn",
@@ -1,11 +0,0 @@
1
- import React from "react";
2
- import { Breakpoints } from "../../DataList.const";
3
- import { DataListHeader as DataListHeaderType, DataListItemTypeFromHeader, DataListLayoutProps, DataListObject, DataListProps } from "../../DataList.types";
4
- interface DataListHeaderProps<T extends DataListObject> {
5
- readonly layouts: React.ReactElement<DataListLayoutProps<T>>[] | undefined;
6
- readonly mediaMatches?: Record<Breakpoints, boolean>;
7
- readonly headerData?: DataListItemTypeFromHeader<T, DataListHeaderType<T>>;
8
- readonly headerVisibility: NonNullable<DataListProps<T>["headerVisibility"]>;
9
- }
10
- export declare function DataListHeader<T extends DataListObject>({ layouts, mediaMatches, headerData, }: DataListHeaderProps<T>): JSX.Element | null;
11
- export {};
@@ -1,10 +0,0 @@
1
- import React from "react";
2
- import { Breakpoints } from "@jobber/components/DataList/DataList.const";
3
- import { DataListLayoutProps, DataListObject } from "@jobber/components/DataList/DataList.types";
4
- interface DataListItemsProps<T extends DataListObject> {
5
- readonly layouts: React.ReactElement<DataListLayoutProps<T>>[] | undefined;
6
- readonly mediaMatches?: Record<Breakpoints, boolean>;
7
- readonly data: T[];
8
- }
9
- export declare function DataListItems<T extends DataListObject>({ layouts, mediaMatches, data, }: DataListItemsProps<T>): JSX.Element;
10
- export {};
@@ -1,10 +0,0 @@
1
- import React from "react";
2
- import { Breakpoints } from "../../DataList.const";
3
- import { DataListLayoutProps, DataListObject } from "../../DataList.types";
4
- interface DataListLayoutInternalProps<T extends DataListObject> {
5
- readonly layouts: React.ReactElement<DataListLayoutProps<T>>[] | undefined;
6
- readonly renderLayout: (layout: React.ReactElement<DataListLayoutProps<T>>) => JSX.Element;
7
- readonly mediaMatches?: Record<Breakpoints, boolean>;
8
- }
9
- export declare function DataListLayoutInternal<T extends DataListObject>({ layouts, renderLayout, mediaMatches, }: DataListLayoutInternalProps<T>): JSX.Element;
10
- export {};
@@ -1,3 +0,0 @@
1
- export { DataListItems } from "./DataListItems";
2
- export { DataListHeader } from "./DataListHeader";
3
- export { DataListLayoutInternal } from "./DataListLayoutInternal";
@@ -1 +0,0 @@
1
- export declare function useLayoutMediaQueries(): Record<"xs" | "sm" | "md" | "lg" | "xl", boolean>;