dce-reactkit 3.5.7 → 3.5.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dce-reactkit",
3
- "version": "3.5.7",
3
+ "version": "3.5.9",
4
4
  "description": "Shared components for Harvard DCE apps",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -58,17 +58,11 @@ const style = `
58
58
 
59
59
  .AutoscrollToBottomContainer-scrollable-container {
60
60
  /* Take up max 100% height, don't take it up if not needed */
61
- /* (so column-reverse layout doesn't start at the bottom) */
62
61
  max-height: 100%;
63
62
  overflow-y: auto;
64
63
 
65
64
  /* Allow children to position */
66
65
  position: relative;
67
-
68
- /* Reverse order of children so scroll starts at bottom */
69
- /* (but children will have to be rendered in reverse order) */
70
- display: flex;
71
- flex-direction: column-reverse;
72
66
  }
73
67
 
74
68
  .AutoscrollToBottomContainer-jump-to-bottom-container {
@@ -101,7 +95,7 @@ const style = `
101
95
 
102
96
  // Scrolled to bottom threshold
103
97
  // (how close you have to be to the bottom for it to count as the bottom)
104
- const SCROLLED_TO_BOTTOM_THRESHOLD_REMS = 2;
98
+ const SCROLLED_TO_BOTTOM_THRESHOLD_REMS = 1.5;
105
99
 
106
100
  /*------------------------------------------------------------------------*/
107
101
  /* -------------------------- Static Functions -------------------------- */
@@ -126,8 +120,6 @@ const getItemIds = (items: AutoScrollItem[]): (string | number)[] => {
126
120
  /* -------- State Definition -------- */
127
121
 
128
122
  type State = {
129
- // If true, the user was scrolled to the bottom after last update
130
- wasScrolledToBottom: boolean,
131
123
  // If true, the "jump to bottom" button is visible
132
124
  jumpToBottomButtonVisible: boolean,
133
125
  };
@@ -136,12 +128,10 @@ type State = {
136
128
 
137
129
  // Types of actions
138
130
  enum ActionType {
139
- // Identify that the user is now scrolled to the bottom
140
- NowScrolledToBottom = 'NowScrolledToBottom',
141
- // Identify that the user scrolled away from the bottom
142
- NowScrolledAwayFromBottom = 'NowScrolledAwayFromBottom',
143
- // Identify that new content appeared at the bottom but is not visible
144
- NewContentAtBottom = 'NewContentAtBottom',
131
+ // Hide the "jump to bottom" button
132
+ HideJumpToBottomButton = 'HideJumpToBottomButton',
133
+ // Show the "jump to bottom" button
134
+ ShowJumpToBottomButton = 'ShowJumpToBottomButton',
145
135
  }
146
136
 
147
137
  // Action definitions
@@ -149,9 +139,8 @@ type Action = (
149
139
  | {
150
140
  // Action type
151
141
  type: (
152
- | ActionType.NowScrolledToBottom
153
- | ActionType.NowScrolledAwayFromBottom
154
- | ActionType.NewContentAtBottom
142
+ | ActionType.HideJumpToBottomButton
143
+ | ActionType.ShowJumpToBottomButton
155
144
  ),
156
145
  }
157
146
  );
@@ -164,28 +153,15 @@ type Action = (
164
153
  */
165
154
  const reducer = (state: State, action: Action): State => {
166
155
  switch (action.type) {
167
- case ActionType.NowScrolledToBottom: {
156
+ case ActionType.HideJumpToBottomButton: {
168
157
  return {
169
158
  ...state,
170
- // Store the event
171
- wasScrolledToBottom: true,
172
- // Hide the "jump to bottom" button
173
159
  jumpToBottomButtonVisible: false,
174
160
  };
175
161
  }
176
- case ActionType.NowScrolledAwayFromBottom: {
177
- return {
178
- ...state,
179
- // Store the event
180
- wasScrolledToBottom: false,
181
- };
182
- }
183
- case ActionType.NewContentAtBottom: {
162
+ case ActionType.ShowJumpToBottomButton: {
184
163
  return {
185
164
  ...state,
186
- // Store the event
187
- wasScrolledToBottom: false,
188
- // Show the "jump to bottom" button
189
165
  jumpToBottomButtonVisible: true,
190
166
  };
191
167
  }
@@ -217,7 +193,6 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
217
193
 
218
194
  // Initial state
219
195
  const initialState: State = {
220
- wasScrolledToBottom: true,
221
196
  jumpToBottomButtonVisible: false,
222
197
  };
223
198
 
@@ -226,7 +201,6 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
226
201
 
227
202
  // Destructure common state
228
203
  const {
229
- wasScrolledToBottom,
230
204
  jumpToBottomButtonVisible,
231
205
  } = state;
232
206
 
@@ -235,6 +209,7 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
235
209
  // Initialize refs
236
210
  const lastItemIds = useRef<(string | number)[]>([]);
237
211
  const container = useRef<HTMLDivElement | null>(null);
212
+ const wasScrolledToBottomBeforeItemsUpdate = useRef<boolean>(true);
238
213
 
239
214
  /*------------------------------------------------------------------------*/
240
215
  /* ------------------------- Component Functions ------------------------ */
@@ -258,6 +233,8 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
258
233
  // Get info about container
259
234
  const {
260
235
  scrollTop,
236
+ scrollHeight,
237
+ clientHeight,
261
238
  } = container.current;
262
239
 
263
240
  // Distance to bottom
@@ -265,7 +242,9 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
265
242
  getComputedStyle(document.documentElement).fontSize,
266
243
  10,
267
244
  );
268
- const distanceToBottomRems = Math.abs(scrollTop / rootFontSizePx);
245
+ const distanceToBottomRems = Math.abs(
246
+ (scrollTop + clientHeight - scrollHeight) / rootFontSizePx,
247
+ );
269
248
 
270
249
  // Figure out if we're scrolled to the bottom
271
250
  return (distanceToBottomRems < SCROLLED_TO_BOTTOM_THRESHOLD_REMS);
@@ -283,11 +262,11 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
283
262
 
284
263
  // Update state
285
264
  dispatch({
286
- type: ActionType.NowScrolledToBottom,
265
+ type: ActionType.HideJumpToBottomButton,
287
266
  });
288
267
 
289
268
  // Scroll to bottom
290
- container.current.scrollTop = 0;
269
+ container.current.scrollTop = container.current.scrollHeight;
291
270
  };
292
271
 
293
272
  /*----------------------------------------*/
@@ -304,17 +283,10 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
304
283
  return;
305
284
  }
306
285
 
307
- // Check if now scrolled to bottom
308
- const nowScrolledToBottom = isScrolledToBottom();
309
-
310
- // Remember if now no longer scrolled to bottom
311
- if (nowScrolledToBottom) {
312
- dispatch({
313
- type: ActionType.NowScrolledToBottom,
314
- });
315
- } else {
286
+ // If scrolled to bottom, hide the button
287
+ if (isScrolledToBottom()) {
316
288
  dispatch({
317
- type: ActionType.NowScrolledAwayFromBottom,
289
+ type: ActionType.HideJumpToBottomButton,
318
290
  });
319
291
  }
320
292
  };
@@ -336,7 +308,7 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
336
308
  );
337
309
 
338
310
  /**
339
- * Update (also called on mount)
311
+ * Update (also called on mount): autoscroll
340
312
  * @author Gabe Abrams
341
313
  */
342
314
  useEffect(
@@ -345,7 +317,7 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
345
317
  const currentItemIds = getItemIds(items);
346
318
 
347
319
  // Check if new content appeared at bottom
348
- const newContentAtBottom = (
320
+ const newContentAppeared = (
349
321
  currentItemIds.length > 0
350
322
  && (
351
323
  currentItemIds[currentItemIds.length - 1]
@@ -354,23 +326,28 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
354
326
  );
355
327
 
356
328
  // Do nothing if no new content
357
- if (!newContentAtBottom) {
329
+ if (!newContentAppeared) {
358
330
  return;
359
331
  }
360
332
 
361
333
  // Check if used to be scrolled to the bottom
362
- if (wasScrolledToBottom) {
334
+ if (wasScrolledToBottomBeforeItemsUpdate.current) {
363
335
  // Was scrolled to the bottom! Autoscroll.
364
336
  scrollToBottom();
365
337
  } else {
366
338
  // Not scrolled to bottom. Show "jump to bottom" button.
367
339
  dispatch({
368
- type: ActionType.NewContentAtBottom,
340
+ type: ActionType.ShowJumpToBottomButton,
369
341
  });
370
342
  }
371
343
 
372
344
  // Update last item ids
373
345
  lastItemIds.current = currentItemIds;
346
+
347
+ // Remember if we were scrolled to the bottom before the update
348
+ return () => {
349
+ wasScrolledToBottomBeforeItemsUpdate.current = isScrolledToBottom();
350
+ };
374
351
  },
375
352
  [items],
376
353
  );
@@ -420,9 +397,7 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
420
397
  {/* Scrollable Item Container */}
421
398
  <div
422
399
  className="AutoscrollToBottomContainer-scrollable-container"
423
- onScroll={() => {
424
- handleScroll();
425
- }}
400
+ onScroll={handleScroll}
426
401
  ref={container}
427
402
  >
428
403
  {/* Items */}
@@ -439,8 +414,6 @@ const AutoscrollToBottomContainer: React.FC<Props> = (props) => {
439
414
  </div>
440
415
  );
441
416
  })
442
- // Reverse order because flex column is reverse
443
- .reverse()
444
417
  }
445
418
  </div>
446
419
  </div>