@zohodesk/components 1.4.5 → 1.4.7

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.
package/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Dot UI is a customizable React component library built to deliver a clean, accessible, and developer-friendly UI experience. It offers a growing set of reusable components designed to align with modern design systems and streamline application development across projects.
4
4
 
5
+ # 1.4.7
6
+
7
+ - **Card**
8
+ - Added support for reverse infinite scroll with `isRecentOnBottom`.
9
+
10
+ # 1.4.6
11
+
12
+ - **Popup**
13
+ - - Added fixed popup scroll block behavior support to iframe elements (same-origin only).
14
+
5
15
  # 1.4.5
6
16
 
7
17
  - **Portal**
@@ -8,7 +8,7 @@ import '@zohodesk/variables/assets/colorVariables.module.css';
8
8
  import '@zohodesk/variables/assets/dotVariables.module.css';
9
9
  import '@zohodesk/variables/assets/sizeVariables.module.css';
10
10
  import '@zohodesk/variables/assets/fontsizeVariables.module.css';
11
- import '@zohodesk/variables/lib/fontFamilyVariables.module.css';
11
+ import '@zohodesk/variables/es/fontFamilyVariables.module.css';
12
12
  import '@zohodesk/variables/assets/transitionVariables.module.css';
13
13
  import '@zohodesk/variables/assets/no_transitionVariables.module.css';
14
14
  import "../common/a11y.module.css";
package/es/Card/Card.js CHANGED
@@ -96,7 +96,9 @@ export default class Card extends Component {
96
96
  this.to = from + 3 * limit;
97
97
  this.isFetching = false;
98
98
  this.lastScrollTop = 0;
99
- this.onScroll = this.onScroll.bind(this); //this.onSetScroll = debounce(this.setScroll.bind(this, true), 10, true);
99
+ this.onScroll = this.onScroll.bind(this);
100
+ this.setScrollRef = this.setScrollRef.bind(this);
101
+ this.childEleRef = null; //this.onSetScroll = debounce(this.setScroll.bind(this, true), 10, true);
100
102
  //this.onClearScroll = debounce(this.setScroll.bind(this, false), 500);
101
103
  }
102
104
 
@@ -127,25 +129,36 @@ export default class Card extends Component {
127
129
  scrollAt,
128
130
  noNeedUpScroll,
129
131
  // isScrollShadow,
130
- isPercentageScroll
132
+ isPercentageScroll,
133
+ scrollDirection
131
134
  } = this.props;
135
+ const scrollLimitHeight = scrollHeight - scrollAt;
136
+ const currentVisibleBottom = scrollTop + offsetHeight;
132
137
 
133
138
  if (scrollTop > this.lastScrollTop) {
134
- this.scrollDirection = 'down';
139
+ this.scrollingDirection = 'down';
135
140
  } else {
136
- this.scrollDirection = 'up';
141
+ this.scrollingDirection = 'up';
137
142
  }
138
143
 
139
144
  this.lastScrollTop = scrollTop;
140
145
 
141
146
  if (fetchData && !this.isFetching) {
142
- if (this.scrollDirection === 'down' && !noMoreData) {
143
- const scrollingPercentage = (scrollTop + offsetHeight) / (scrollHeight - scrollAt) * 100;
144
- const prefetch = isPercentageScroll ? scrollingPercentage >= getLibraryConfig('scrollFetchLimit') : scrollHeight - scrollAt <= scrollTop + offsetHeight;
147
+ const fetchDirection = scrollDirection === 'bottomToTop' ? 'up' : 'down';
148
+
149
+ if (this.scrollingDirection === fetchDirection && !noMoreData) {
150
+ let prefetch = false;
151
+
152
+ if (isPercentageScroll) {
153
+ const scrollingPercentage = scrollDirection === 'bottomToTop' ? (scrollHeight - scrollTop) / scrollLimitHeight * 100 : currentVisibleBottom / scrollLimitHeight * 100;
154
+ prefetch = scrollingPercentage >= getLibraryConfig('scrollFetchLimit');
155
+ } else {
156
+ prefetch = scrollDirection === 'bottomToTop' ? scrollTop <= scrollAt : scrollLimitHeight <= currentVisibleBottom;
157
+ }
145
158
 
146
159
  if (prefetch) {
147
160
  this.isFetching = true;
148
- fetchData(this.from + this.limit, this.limit + this.to, this.scrollDirection).then(() => {
161
+ fetchData(this.from + this.limit, this.limit + this.to, this.scrollingDirection).then(() => {
149
162
  this.to = this.limit + this.to;
150
163
  this.isFetching = false;
151
164
  }, () => {
@@ -153,9 +166,11 @@ export default class Card extends Component {
153
166
  });
154
167
  }
155
168
  } else {
156
- if (0 >= scrollTop - scrollAt && this.from !== 0 && !noNeedUpScroll) {
169
+ const prefetch = scrollDirection === 'bottomToTop' ? scrollLimitHeight <= currentVisibleBottom : 0 >= scrollTop - scrollAt;
170
+
171
+ if (prefetch && this.from !== 0 && !noNeedUpScroll) {
157
172
  this.isFetching = true;
158
- fetchData(this.from - this.limit, this.to - this.limit, this.scrollDirection).then(() => {
173
+ fetchData(this.from - this.limit, this.to - this.limit, this.scrollingDirection).then(() => {
159
174
  this.to = this.to - this.limit;
160
175
  this.isFetching = false;
161
176
  }, () => {
@@ -166,9 +181,12 @@ export default class Card extends Component {
166
181
  }
167
182
 
168
183
  if (fetchData && !noNeedUpScroll) {
169
- if (this.from !== 0 && scrollTop === 0 && !noNeedUpScroll) {
184
+ const topFetch = scrollDirection === 'bottomToTop' ? !noMoreData : !noNeedUpScroll && this.from !== 0;
185
+ const bottomFetch = scrollDirection === 'bottomToTop' ? !noNeedUpScroll && this.from !== 0 : !noMoreData;
186
+
187
+ if (scrollTop === 0 && topFetch) {
170
188
  scrollContainerObj.scrollTop = scrollTop + offsetHeight / 3;
171
- } else if (scrollHeight === scrollTop + offsetHeight && !noMoreData) {
189
+ } else if (scrollHeight === currentVisibleBottom && bottomFetch) {
172
190
  scrollContainerObj.scrollTop = scrollTop - offsetHeight / 2;
173
191
  }
174
192
  } // if (isScrollShadow) {
@@ -187,6 +205,21 @@ export default class Card extends Component {
187
205
  // }
188
206
 
189
207
 
208
+ setScrollRef(el) {
209
+ const {
210
+ scrollAt,
211
+ scrollDirection
212
+ } = this.props;
213
+
214
+ if (el && scrollDirection === 'bottomToTop') {
215
+ requestAnimationFrame(() => {
216
+ el.scrollTop = el.scrollHeight + Number(scrollAt);
217
+ });
218
+ }
219
+
220
+ this.childEleRef && this.childEleRef(el);
221
+ }
222
+
190
223
  render() {
191
224
  let {
192
225
  onClick,
@@ -220,6 +253,7 @@ export default class Card extends Component {
220
253
  isScroll
221
254
  });
222
255
  } else if (child.type === CardContent || this.props.childTypes && child.type === this.props.childTypes.cardContent) {
256
+ this.childEleRef = child.props.eleRef;
223
257
  return /*#__PURE__*/React.createElement(Box, {
224
258
  id: htmlId,
225
259
  role: role,
@@ -227,7 +261,7 @@ export default class Card extends Component {
227
261
  scroll: child.props.scroll,
228
262
  preventParentScroll: child.props.preventParentScroll,
229
263
  onScroll: this.onScroll,
230
- eleRef: child.props.eleRef,
264
+ eleRef: this.setScrollRef,
231
265
  isScrollAttribute: child.props.isScrollAttribute,
232
266
  dataId: child.props.dataId,
233
267
  shrink: child.props.shrink,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import Card from "../Card";
2
+ import { render, fireEvent, within, waitFor } from '@testing-library/react';
3
+ import Card, { CardContent } from "../Card";
4
4
  describe('Card', () => {
5
5
  test('rendering the defult props', () => {
6
6
  const {
@@ -8,4 +8,83 @@ describe('Card', () => {
8
8
  } = render( /*#__PURE__*/React.createElement(Card, null));
9
9
  expect(asFragment()).toMatchSnapshot();
10
10
  });
11
+ test('should trigger fetch, when scroll to the bottom of the card while isRecentOnBottom = false', async () => {
12
+ const mockGetNextOptions = jest.fn(() => {
13
+ return new Promise(resolve => {
14
+ resolve();
15
+ });
16
+ });
17
+ const {
18
+ getByTestId,
19
+ asFragment
20
+ } = render( /*#__PURE__*/React.createElement(Card, {
21
+ from: 0,
22
+ limit: 10,
23
+ fetchData: mockGetNextOptions
24
+ }, /*#__PURE__*/React.createElement(CardContent, {
25
+ dataId: "scrollToBottomCardContent"
26
+ }, /*#__PURE__*/React.createElement("div", null, "Hello Zam"))));
27
+ const cardContent = getByTestId('scrollToBottomCardContent');
28
+ Object.defineProperty(cardContent, 'scrollHeight', {
29
+ value: 1000,
30
+ writable: true
31
+ });
32
+ Object.defineProperty(cardContent, 'clientHeight', {
33
+ value: 600,
34
+ writable: true
35
+ });
36
+ Object.defineProperty(cardContent, 'offsetHeight', {
37
+ value: 600,
38
+ writable: true
39
+ });
40
+ fireEvent.scroll(cardContent, {
41
+ target: {
42
+ scrollTop: 401
43
+ }
44
+ });
45
+ await waitFor(() => {
46
+ expect(asFragment()).toMatchSnapshot();
47
+ expect(mockGetNextOptions).toHaveBeenCalledWith(10, 40, 'down');
48
+ });
49
+ });
50
+ test('should trigger fetch, when scroll to the top of the card while scrollDirection = bottomToTop', async () => {
51
+ const mockGetNextOptions = jest.fn(() => {
52
+ return new Promise(resolve => {
53
+ resolve();
54
+ });
55
+ });
56
+ const {
57
+ getByTestId,
58
+ asFragment
59
+ } = render( /*#__PURE__*/React.createElement(Card, {
60
+ from: 0,
61
+ limit: 10,
62
+ scrollDirection: "bottomToTop",
63
+ fetchData: mockGetNextOptions
64
+ }, /*#__PURE__*/React.createElement(CardContent, {
65
+ dataId: "scrollToTopCardContent"
66
+ }, /*#__PURE__*/React.createElement("div", null, "Hello Zam"))));
67
+ const cardContent = getByTestId('scrollToTopCardContent');
68
+ Object.defineProperty(cardContent, 'scrollHeight', {
69
+ value: 1000,
70
+ writable: true
71
+ });
72
+ Object.defineProperty(cardContent, 'clientHeight', {
73
+ value: 600,
74
+ writable: true
75
+ });
76
+ Object.defineProperty(cardContent, 'offsetHeight', {
77
+ value: 600,
78
+ writable: true
79
+ });
80
+ fireEvent.scroll(cardContent, {
81
+ target: {
82
+ scrollTop: 0
83
+ }
84
+ });
85
+ await waitFor(() => {
86
+ expect(asFragment()).toMatchSnapshot();
87
+ expect(mockGetNextOptions).toHaveBeenCalledWith(10, 40, 'up');
88
+ });
89
+ });
11
90
  });
@@ -10,3 +10,47 @@ exports[`Card rendering the defult props 1`] = `
10
10
  />
11
11
  </DocumentFragment>
12
12
  `;
13
+
14
+ exports[`Card should trigger fetch, when scroll to the bottom of the card while isRecentOnBottom = false 1`] = `
15
+ <DocumentFragment>
16
+ <div
17
+ class="flex cover coldir"
18
+ data-id="containerComponent"
19
+ data-selector-id="container"
20
+ data-test-id="containerComponent"
21
+ >
22
+ <div
23
+ class="grow basis shrinkOff scrolly"
24
+ data-id="scrollToBottomCardContent"
25
+ data-selector-id="cardContent"
26
+ data-test-id="scrollToBottomCardContent"
27
+ >
28
+ <div>
29
+ Hello Zam
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </DocumentFragment>
34
+ `;
35
+
36
+ exports[`Card should trigger fetch, when scroll to the top of the card while scrollDirection = bottomToTop 1`] = `
37
+ <DocumentFragment>
38
+ <div
39
+ class="flex cover coldir"
40
+ data-id="containerComponent"
41
+ data-selector-id="container"
42
+ data-test-id="containerComponent"
43
+ >
44
+ <div
45
+ class="grow basis shrinkOff scrolly"
46
+ data-id="scrollToTopCardContent"
47
+ data-selector-id="cardContent"
48
+ data-test-id="scrollToTopCardContent"
49
+ >
50
+ <div>
51
+ Hello Zam
52
+ </div>
53
+ </div>
54
+ </div>
55
+ </DocumentFragment>
56
+ `;
@@ -4,7 +4,8 @@ export const Card_defaultProps = {
4
4
  onClick: null,
5
5
  scrollAt: '10',
6
6
  a11y: {},
7
- isPercentageScroll: false
7
+ isPercentageScroll: false,
8
+ scrollDirection: 'topToBottom'
8
9
  };
9
10
  export const CardHeader_defaultProps = {
10
11
  dataId: 'CardHeader',
@@ -38,7 +38,8 @@ export const Card_propTypes = {
38
38
  role: PropTypes.string
39
39
  }),
40
40
  isPercentageScroll: PropTypes.bool,
41
- eleRef: PropTypes.func
41
+ eleRef: PropTypes.func,
42
+ scrollDirection: PropTypes.oneOf(['topToBottom', 'bottomToTop'])
42
43
  };
43
44
  export const CardFooter_propTypes = {
44
45
  children: PropTypes.node,
@@ -18,6 +18,11 @@
18
18
  box-shadow: var(--dropbox_box_shadow);
19
19
  }
20
20
 
21
+ .defaultPalette,
22
+ .darkPalette {
23
+ /*css:theme-validation:ignore*/
24
+ }
25
+
21
26
  .defaultPalette, .darkPalette {
22
27
  background-color: var(--dropbox_bg_color);
23
28
  }
@@ -207,6 +212,7 @@
207
212
  height: var(--zd_size10) ;
208
213
  width: var(--zd_size10) ;
209
214
  box-shadow: 1px -1px 2px 0 var(--dropbox_arrow_box_shadow_color);
215
+ /*css:theme-validation:ignore*/
210
216
  background-color: var(--dropbox_bg_color);
211
217
  -webkit-transform: rotateZ(-45deg);
212
218
  transform: rotateZ(-45deg);
@@ -419,6 +425,7 @@
419
425
  .closeBar {
420
426
  /* Variable:Ignore */
421
427
  height: 6px;
428
+ /*css:theme-validation:ignore*/
422
429
  width: 20% ;
423
430
  border-radius: 5px;
424
431
  background-color: var(--dropbox_mob_close_bg_color);