dce-reactkit 3.0.37 → 3.0.40

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/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ import React from 'react';
7
7
  * @author Gabe Abrams
8
8
  */
9
9
 
10
- declare type Props$8 = {
10
+ declare type Props$9 = {
11
11
  children: React.ReactNode;
12
12
  sendRequest: SendRequestFunction;
13
13
  dark?: boolean;
@@ -52,7 +52,7 @@ declare const confirm: (title: string, text: string) => Promise<boolean>;
52
52
  * @param [errorTitle] title of the error box
53
53
  */
54
54
  declare const showFatalError: (error: any, errorTitle?: string) => undefined;
55
- declare const AppWrapper: React.FC<Props$8>;
55
+ declare const AppWrapper: React.FC<Props$9>;
56
56
 
57
57
  /**
58
58
  * Loading spinner/indicator
@@ -65,12 +65,12 @@ declare const LoadingSpinner: () => JSX.Element;
65
65
  * @author Gabe Abrams
66
66
  */
67
67
 
68
- declare type Props$7 = {
68
+ declare type Props$8 = {
69
69
  error: any;
70
70
  title?: string;
71
71
  onClose?: () => void;
72
72
  };
73
- declare const ErrorBox: React.FC<Props$7>;
73
+ declare const ErrorBox: React.FC<Props$8>;
74
74
 
75
75
  /**
76
76
  * Bootstrap variants
@@ -136,7 +136,7 @@ declare enum ModalType {
136
136
  * @author Gabe Abrams
137
137
  */
138
138
 
139
- declare type Props$6 = {
139
+ declare type Props$7 = {
140
140
  type?: ModalType;
141
141
  size?: ModalSize;
142
142
  title?: React.ReactNode;
@@ -165,26 +165,27 @@ declare type Props$6 = {
165
165
  confirmVariant?: Variant;
166
166
  onTopOfOtherModals?: boolean;
167
167
  };
168
- declare const Modal: React.FC<Props$6>;
168
+ declare const Modal: React.FC<Props$7>;
169
169
 
170
170
  /**
171
171
  * A box with a tab on the top that holds buttons and other content
172
172
  * @author Gabe Abrams
173
173
  */
174
174
 
175
- declare type Props$5 = {
175
+ declare type Props$6 = {
176
176
  title: React.ReactNode;
177
177
  children: React.ReactNode;
178
+ noBottomMargin?: boolean;
178
179
  noBottomPadding?: boolean;
179
180
  };
180
- declare const TabBox: React.FC<Props$5>;
181
+ declare const TabBox: React.FC<Props$6>;
181
182
 
182
183
  /**
183
184
  * A radio selection button
184
185
  * @author Gabe Abrams
185
186
  */
186
187
 
187
- declare type Props$4 = {
188
+ declare type Props$5 = {
188
189
  text: string;
189
190
  onSelected: () => void;
190
191
  ariaLabel: string;
@@ -196,14 +197,14 @@ declare type Props$4 = {
196
197
  unselectedVariant?: Variant;
197
198
  small?: boolean;
198
199
  };
199
- declare const RadioButton: React.FC<Props$4>;
200
+ declare const RadioButton: React.FC<Props$5>;
200
201
 
201
202
  /**
202
203
  * A checkbox button
203
204
  * @author Gabe Abrams
204
205
  */
205
206
 
206
- declare type Props$3 = {
207
+ declare type Props$4 = {
207
208
  text: string;
208
209
  onChanged: (checked: boolean) => void;
209
210
  ariaLabel: string;
@@ -215,26 +216,26 @@ declare type Props$3 = {
215
216
  uncheckedVariant?: Variant;
216
217
  small?: boolean;
217
218
  };
218
- declare const CheckboxButton: React.FC<Props$3>;
219
+ declare const CheckboxButton: React.FC<Props$4>;
219
220
 
220
221
  /**
221
222
  * Input group with a title and space for buttons
222
223
  * @author Gabe Abrams
223
224
  */
224
225
 
225
- declare type Props$2 = {
226
+ declare type Props$3 = {
226
227
  label: string;
227
228
  minLabelWidth?: string;
228
229
  children: React.ReactNode;
229
230
  };
230
- declare const ButtonInputGroup: React.FC<Props$2>;
231
+ declare const ButtonInputGroup: React.FC<Props$3>;
231
232
 
232
233
  /**
233
234
  * A very simple, lightweight date chooser
234
235
  * @author Gabe Abrams
235
236
  */
236
237
 
237
- declare type Props$1 = {
238
+ declare type Props$2 = {
238
239
  ariaLabel: string;
239
240
  name: string;
240
241
  month: number;
@@ -249,17 +250,29 @@ declare type Props$1 = {
249
250
  onChange: (month: number, day: number, year: number) => void;
250
251
  numMonthsToShow?: number;
251
252
  };
252
- declare const SimpleDateChooser: React.FC<Props$1>;
253
+ declare const SimpleDateChooser: React.FC<Props$2>;
253
254
 
254
255
  /**
255
256
  * Drawer container
256
257
  * @author Gabe Abrams
257
258
  */
258
259
 
259
- declare type Props = {
260
+ declare type Props$1 = {
260
261
  children: React.ReactNode;
261
262
  };
262
- declare const Drawer: React.FC<Props>;
263
+ declare const Drawer: React.FC<Props$1>;
264
+
265
+ /**
266
+ * Success checkmark that pops into view
267
+ * @author Gabe Abrams
268
+ */
269
+
270
+ declare type Props = {
271
+ sizeRem?: number;
272
+ circleVariant?: string;
273
+ checkVariant?: string;
274
+ };
275
+ declare const PopSuccessMark: React.FC<Props>;
263
276
 
264
277
  /**
265
278
  * An error with a code
@@ -532,6 +545,14 @@ declare const stubServerEndpoint: (opts: {
532
545
  */
533
546
  declare const startMinWait: (minWaitMs: number) => () => Promise<void>;
534
547
 
548
+ /**
549
+ * Get a human-readable description of a date (all in ET)
550
+ * @author Gabe Abrams
551
+ * @param [dateOrTimestamp=today] the date or timestamp for the date to describe
552
+ * @returns human-readable description of the date
553
+ */
554
+ declare const getHumanReadableDate: (dateOrTimestamp?: number | Date | undefined) => string;
555
+
535
556
  /**
536
557
  * List of error codes built into the react kit
537
558
  * @author Gabe Abrams
@@ -549,4 +570,4 @@ declare enum ReactKitErrorCode {
549
570
  NotAdmin = "DRK10"
550
571
  }
551
572
 
552
- export { AppWrapper, ButtonInputGroup, CheckboxButton, DAY_IN_MS, Drawer, ErrorBox, ErrorWithCode, HOUR_IN_MS, LoadingSpinner, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, ParamType, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, Variant, abbreviate, alert, avg, ceilToNumDecimals, confirm, floorToNumDecimals, forceNumIntoBounds, genRouteHandler, getOrdinal, getTimeInfoInET, handleError, handleSuccess, initServer, padDecimalZeros, padZerosLeft, roundToNumDecimals, showFatalError, startMinWait, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
573
+ export { AppWrapper, ButtonInputGroup, CheckboxButton, DAY_IN_MS, Drawer, ErrorBox, ErrorWithCode, HOUR_IN_MS, LoadingSpinner, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, ParamType, PopSuccessMark, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, Variant, abbreviate, alert, avg, ceilToNumDecimals, confirm, floorToNumDecimals, forceNumIntoBounds, genRouteHandler, getHumanReadableDate, getOrdinal, getTimeInfoInET, handleError, handleSuccess, initServer, padDecimalZeros, padZerosLeft, roundToNumDecimals, showFatalError, startMinWait, stubServerEndpoint, sum, visitServerEndpoint, waitMs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dce-reactkit",
3
- "version": "3.0.37",
3
+ "version": "3.0.40",
4
4
  "description": "Shared components for Harvard DCE apps",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Success checkmark that pops into view
3
+ * @author Gabe Abrams
4
+ */
5
+
6
+ // Import React
7
+ import React from 'react';
8
+
9
+ /*------------------------------------------------------------------------*/
10
+ /* Types */
11
+ /*------------------------------------------------------------------------*/
12
+
13
+ // Props definition
14
+ type Props = {
15
+ // Size of checkmark in rem
16
+ sizeRem?: number,
17
+ // Bootstrap variant of circle
18
+ circleVariant?: string,
19
+ // Bootstrap variant of checkmark
20
+ checkVariant?: string,
21
+ };
22
+
23
+ /*------------------------------------------------------------------------*/
24
+ /* Style */
25
+ /*------------------------------------------------------------------------*/
26
+
27
+ const style = `
28
+ .PopSuccessMark-outer-container {
29
+ position: relative;
30
+ display: inline-block;
31
+ border-radius: 50%;
32
+
33
+ animation-name: PopSuccessMark-outer-container;
34
+ animation-duration: 0.8s;
35
+ animation-fill-mode: both;
36
+ animation-iteration-count: 1;
37
+ animation-timing-function: ease-out;
38
+ }
39
+ @keyframes PopSuccessMark-outer-container {
40
+ 0% {
41
+ opacity: 0;
42
+ transform: scale(1.5);
43
+ filter: saturate(0);
44
+ }
45
+ 80.7% {
46
+ opacity: 1;
47
+ transform: scale(1);
48
+ filter: saturate(0);
49
+ }
50
+ 100% {
51
+ opacity: 1;
52
+ transform: scale(1);
53
+ filter: saturate(1);
54
+ }
55
+ }
56
+
57
+ .PopSuccessMark-check-stroke-1 {
58
+ position: absolute;
59
+ left: 20%;
60
+ top: 36%;
61
+
62
+ display: inline-block;
63
+ height: 16%;
64
+ width: 35%;
65
+
66
+ transform-origin: left;
67
+
68
+ animation-name: PopSuccessMark-check-stroke-1;
69
+ animation-duration: 0.3s;
70
+ animation-delay: 0.3s;
71
+ animation-fill-mode: both;
72
+ animation-iteration-count: 1;
73
+ animation-timing-function: ease-in;
74
+ }
75
+ @keyframes PopSuccessMark-check-stroke-1 {
76
+ 0% {
77
+ transform: rotate(45deg) scaleX(0);
78
+ }
79
+ 100% {
80
+ transform: rotate(45deg) scaleX(1);
81
+ }
82
+ }
83
+
84
+
85
+ .PopSuccessMark-check-stroke-2 {
86
+ position: absolute;
87
+ left: 35%;
88
+ top: 63%;
89
+
90
+ display: inline-block;
91
+ height: 16%;
92
+ width: 60%;
93
+
94
+ transform-origin: left;
95
+
96
+ animation-name: PopSuccessMark-check-stroke-2;
97
+ animation-duration: 0.3s;
98
+ animation-delay: 0.6s;
99
+ animation-fill-mode: both;
100
+ animation-iteration-count: 1;
101
+ animation-timing-function: ease-out;
102
+ }
103
+ @keyframes PopSuccessMark-check-stroke-2 {
104
+ 0% {
105
+ transform: rotate(-40deg) scaleX(0);
106
+ }
107
+ 100% {
108
+ transform: rotate(-40deg) scaleX(1);
109
+ }
110
+ }
111
+ `;
112
+
113
+ /*------------------------------------------------------------------------*/
114
+ /* Component */
115
+ /*------------------------------------------------------------------------*/
116
+
117
+ const PopSuccessMark: React.FC<Props> = (props) => {
118
+ /*------------------------------------------------------------------------*/
119
+ /* Setup */
120
+ /*------------------------------------------------------------------------*/
121
+
122
+ /* -------------- Props ------------- */
123
+
124
+ // Destructure all props
125
+ const {
126
+ sizeRem = 3,
127
+ circleVariant = 'success',
128
+ checkVariant = 'white',
129
+ } = props;
130
+
131
+ /*------------------------------------------------------------------------*/
132
+ /* Render */
133
+ /*------------------------------------------------------------------------*/
134
+
135
+ /*----------------------------------------*/
136
+ /* Main UI */
137
+ /*----------------------------------------*/
138
+
139
+ return (
140
+ <div
141
+ className={`PopSuccessMark-outer-container bg-${circleVariant}`}
142
+ style={{
143
+ width: `${sizeRem}rem`,
144
+ height: `${sizeRem}rem`,
145
+ }}
146
+ aria-label="checkmark indicating success"
147
+ >
148
+ {/* Style */}
149
+ <style>{style}</style>
150
+ {/* Check mark */}
151
+ <div
152
+ className={`PopSuccessMark-check-stroke-1 bg-${checkVariant}`}
153
+ style={{
154
+ borderRadius: `${sizeRem / 5}rem`,
155
+ }}
156
+ />
157
+ <div
158
+ className={`PopSuccessMark-check-stroke-2 bg-${checkVariant}`}
159
+ style={{
160
+ borderRadius: `${sizeRem / 5}rem`,
161
+ }}
162
+ />
163
+ </div>
164
+ );
165
+ };
166
+
167
+ /*------------------------------------------------------------------------*/
168
+ /* Wrap Up */
169
+ /*------------------------------------------------------------------------*/
170
+
171
+ // Export component
172
+ export default PopSuccessMark;
@@ -15,7 +15,9 @@ type Props = {
15
15
  title: React.ReactNode,
16
16
  // Children/contents inside the box
17
17
  children: React.ReactNode,
18
- // If true, don't add padding below the tab box
18
+ // If true, don't add margin below the tab box
19
+ noBottomMargin?: boolean,
20
+ // If true, don't add padding to bottom of tab box
19
21
  noBottomPadding?: boolean,
20
22
  };
21
23
 
@@ -102,6 +104,7 @@ const TabBox: React.FC<Props> = (props) => {
102
104
  title,
103
105
  children,
104
106
  noBottomPadding,
107
+ noBottomMargin,
105
108
  } = props;
106
109
 
107
110
  /*------------------------------------------------------------------------*/
@@ -114,7 +117,7 @@ const TabBox: React.FC<Props> = (props) => {
114
117
 
115
118
  // Full UI
116
119
  return (
117
- <div className={`TabBox-container ${noBottomPadding ? '' : 'mb-2'}`}>
120
+ <div className={`TabBox-container ${noBottomMargin ? '' : 'mb-2'}`}>
118
121
  {/* Style */}
119
122
  <style>{style}</style>
120
123
 
@@ -126,7 +129,7 @@ const TabBox: React.FC<Props> = (props) => {
126
129
  </div>
127
130
 
128
131
  {/* Contents */}
129
- <div className="TabBox-box p-2">
132
+ <div className={`TabBox-box ps-2 pt-2 pe-2 ${noBottomPadding ? '' : 'pb-2'}`}>
130
133
  <div className="TabBox-children">
131
134
  {children}
132
135
  </div>
@@ -0,0 +1,47 @@
1
+ import getTimeInfoInET from './getTimeInfoInET';
2
+ import getOrdinal from './getOrdinal';
3
+
4
+ // Map of month to three letter description
5
+ const monthMap = {
6
+ 1: 'Jan',
7
+ 2: 'Feb',
8
+ 3: 'Mar',
9
+ 4: 'Apr',
10
+ 5: 'May',
11
+ 6: 'Jun',
12
+ 7: 'Jul',
13
+ 8: 'Aug',
14
+ 9: 'Sep',
15
+ 10: 'Oct',
16
+ 11: 'Nov',
17
+ 12: 'Dec',
18
+ };
19
+
20
+ /**
21
+ * Get a human-readable description of a date (all in ET)
22
+ * @author Gabe Abrams
23
+ * @param [dateOrTimestamp=today] the date or timestamp for the date to describe
24
+ * @returns human-readable description of the date
25
+ */
26
+ const getHumanReadableDate = (dateOrTimestamp?: Date | number) => {
27
+ // Get the date info
28
+ const {
29
+ month,
30
+ day,
31
+ year,
32
+ } = getTimeInfoInET(dateOrTimestamp);
33
+ const currYear = getTimeInfoInET().year;
34
+
35
+ // Create start of description
36
+ let description = `${monthMap[month as keyof typeof monthMap]} ${getOrdinal(day)}`;
37
+
38
+ // Add on year if it's different
39
+ if (year !== currYear) {
40
+ description += ` ${year}`;
41
+ }
42
+
43
+ // Return description
44
+ return description;
45
+ };
46
+
47
+ export default getHumanReadableDate;
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import CheckboxButton from './components/CheckboxButton';
9
9
  import ButtonInputGroup from './components/ButtonInputGroup';
10
10
  import SimpleDateChooser from './components/SimpleDateChooser';
11
11
  import Drawer from './components/Drawer';
12
+ import PopSuccessMark from './components/PopSuccessMark';
12
13
 
13
14
  // Import errors
14
15
  import ErrorWithCode from './errors/ErrorWithCode';
@@ -38,6 +39,7 @@ import getOrdinal from './helpers/getOrdinal';
38
39
  import getTimeInfoInET from './helpers/getTimeInfoInET';
39
40
  import stubServerEndpoint from './helpers/stubServerEndpoint';
40
41
  import startMinWait from './helpers/startMinWait';
42
+ import getHumanReadableDate from './helpers/getHumanReadableDate';
41
43
 
42
44
  // Import types
43
45
  import ModalButtonType from './types/ModalButtonType';
@@ -60,6 +62,7 @@ export {
60
62
  ButtonInputGroup,
61
63
  SimpleDateChooser,
62
64
  Drawer,
65
+ PopSuccessMark,
63
66
  // Global functions
64
67
  alert,
65
68
  confirm,
@@ -85,6 +88,7 @@ export {
85
88
  getTimeInfoInET,
86
89
  stubServerEndpoint,
87
90
  startMinWait,
91
+ getHumanReadableDate,
88
92
  // Client helpers
89
93
  visitServerEndpoint,
90
94
  // Server helpers