dce-reactkit 4.2.4-beta.heat-seek.1 → 4.2.6

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.
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Customizable Progress Bar component using Bootstrap styles
3
+ * @author Allison Zhang
4
+ */
5
+
6
+ // Import React
7
+ import React from 'react';
8
+
9
+ // Import types
10
+ import Variant from '../types/Variant';
11
+ import ProgressBarSize from '../types/ProgressBarSize';
12
+
13
+ /*------------------------------------------------------------------------*/
14
+ /* -------------------------------- Types ------------------------------- */
15
+ /*------------------------------------------------------------------------*/
16
+
17
+ // Props definition
18
+ type Props = (
19
+ & (
20
+ // Percent
21
+ | {
22
+ // Percentage progress (0-100)
23
+ percentProgress: number,
24
+ // Num decimal places to show (default 0)
25
+ numDecimalPlaces?: number,
26
+ }
27
+ // Items
28
+ | {
29
+ // Current progress (number of items completed)
30
+ numComplete: number,
31
+ // Maximum progress (total number of items)
32
+ total: number,
33
+ }
34
+ )
35
+ & {
36
+ // Whether to show striped effect (default false)
37
+ striped?: boolean,
38
+ // Variant of the progress bar (default warning)
39
+ variant?: Variant,
40
+ // Background variants (default secondary subtle)
41
+ bgVariant?: Variant,
42
+ // Hide outline (default false)
43
+ showOutline?: boolean,
44
+ // Size of the progress bar (default md)
45
+ size?: ProgressBarSize,
46
+ }
47
+ );
48
+
49
+ // Progress status definition
50
+ type ProgressStatus = (
51
+ | {
52
+ // usePercent true
53
+ usePercent: true,
54
+ // Percentage progress (0-100)
55
+ percentProgress: number,
56
+ // Num decimal places to show (default 0)
57
+ numDecimalPlaces?: number,
58
+ }
59
+ // Items
60
+ | {
61
+ // usePercent false
62
+ usePercent: false,
63
+ // Current progress (number of items completed)
64
+ numComplete: number,
65
+ // Maximum progress (total number of items)
66
+ total: number,
67
+ }
68
+ );
69
+
70
+ /*------------------------------------------------------------------------*/
71
+ /* ------------------------------ Constants ----------------------------- */
72
+ /*------------------------------------------------------------------------*/
73
+
74
+ // Multiplier for calculating width of number of items
75
+ const ITEM_WIDTH_MULTIPLIER = 1.3;
76
+
77
+ // Constant for percent width
78
+ const PERCENT_WIDTH = 3;
79
+
80
+ // Constant for item width
81
+ const ITEM_WIDTH = 2;
82
+
83
+ /*------------------------------------------------------------------------*/
84
+ /* -------------------------------- Style ------------------------------- */
85
+ /*------------------------------------------------------------------------*/
86
+
87
+ // Base styles
88
+ let style = `
89
+ .ProgressBar-number-of,
90
+ .ProgressBar-percent {
91
+ flex: 0 0 auto;
92
+ white-space: nowrap;
93
+ padding-right: 0.5em;
94
+ padding-left: 0.25em;
95
+ text-align: right;
96
+ transition: width .25s ease;
97
+ }
98
+
99
+ .ProgressBar-background {
100
+ overflow: hidden;
101
+ }
102
+
103
+ .ProgressBar-bar {
104
+ transition: width 1s ease;
105
+ overflow: hidden;
106
+ }
107
+ `;
108
+
109
+ /*------------------------------------------------------------------------*/
110
+ /* ------------------------------ Component ----------------------------- */
111
+ /*------------------------------------------------------------------------*/
112
+
113
+ const ProgressBar: React.FC<Props> = (props) => {
114
+ /*------------------------------------------------------------------------*/
115
+ /* -------------------------------- Setup ------------------------------- */
116
+ /*------------------------------------------------------------------------*/
117
+
118
+ /* -------------- Props ------------- */
119
+
120
+ // Destructure props
121
+ const {
122
+ striped,
123
+ variant = Variant.Warning,
124
+ bgVariant = Variant.Secondary,
125
+ showOutline,
126
+ size = ProgressBarSize.Medium,
127
+ } = props;
128
+
129
+ /* -------------- Status ------------- */
130
+
131
+ // Determine progress status
132
+ let status: ProgressStatus;
133
+
134
+ // Check whether to use percent or items
135
+ if ('percentProgress' in props) {
136
+ // Percent
137
+ const {
138
+ percentProgress,
139
+ numDecimalPlaces,
140
+ } = props;
141
+ status = {
142
+ usePercent: true,
143
+ percentProgress,
144
+ numDecimalPlaces,
145
+ };
146
+ } else {
147
+ // Items
148
+ const {
149
+ numComplete,
150
+ total,
151
+ } = props;
152
+ status = {
153
+ usePercent: false,
154
+ numComplete,
155
+ total,
156
+ };
157
+ }
158
+
159
+ /*------------------------------------------------------------------------*/
160
+ /* ------------------------------- Render ------------------------------- */
161
+ /*------------------------------------------------------------------------*/
162
+
163
+ /*----------------------------------------*/
164
+ /* ---------------- Sizes --------------- */
165
+ /*----------------------------------------*/
166
+
167
+ // Size styles
168
+ switch (size) {
169
+ case ProgressBarSize.Small:
170
+ // Small size
171
+ style += `
172
+ .ProgressBar-container .ProgressBar-number-of, .ProgressBar-container .ProgressBar-percent {
173
+ font-size: 1em;
174
+ }
175
+ .ProgressBar-container .ProgressBar-background {
176
+ height: 1.5em;
177
+ border-radius: 0.5em;
178
+ }
179
+ .ProgressBar-container .ProgressBar-bar {
180
+ height: 1.5em;
181
+ border-radius: 0.5em;
182
+ }
183
+ .ProgressBar-percent {
184
+ min-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
185
+ max-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
186
+ }
187
+ .ProgressBar-number-of {
188
+ min-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
189
+ max-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
190
+ }
191
+ `;
192
+ break;
193
+ case ProgressBarSize.Medium:
194
+ // Medium size
195
+ style += `
196
+ .ProgressBar-container .ProgressBar-number-of, .ProgressBar-container .ProgressBar-percent {
197
+ font-size: 1.5em;
198
+ }
199
+ .ProgressBar-container .ProgressBar-background {
200
+ height: 2em;
201
+ border-radius: 0.7em;
202
+ }
203
+ .ProgressBar-container .ProgressBar-bar {
204
+ height: 2em;
205
+ border-radius: 0.7em;
206
+ }
207
+ .ProgressBar-percent {
208
+ min-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
209
+ max-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
210
+ }
211
+ .ProgressBar-number-of {
212
+ min-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
213
+ max-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
214
+ }
215
+ `;
216
+ break;
217
+ case ProgressBarSize.Large:
218
+ // Large size
219
+ style += `
220
+ .ProgressBar-container .ProgressBar-number-of, .ProgressBar-container .ProgressBar-percent {
221
+ font-size: 2em;
222
+ }
223
+ .ProgressBar-container .ProgressBar-background {
224
+ height: 3em;
225
+ border-radius: 1em;
226
+ }
227
+ .ProgressBar-container .ProgressBar-bar {
228
+ height: 3em;
229
+ border-radius: 1em;
230
+ }
231
+ .ProgressBar-percent {
232
+ min-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
233
+ max-width: ${((status.usePercent ? status.numDecimalPlaces ?? 0 : 0) * 1) + PERCENT_WIDTH}em;
234
+ }
235
+ .ProgressBar-number-of {
236
+ min-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
237
+ max-width: ${((!status.usePercent ? status.total?.toString().length || 1 : 0) * ITEM_WIDTH_MULTIPLIER) + ITEM_WIDTH}em;
238
+ }
239
+ `;
240
+ break;
241
+ default:
242
+ break;
243
+ }
244
+
245
+ // Get the width of the outline based on size
246
+ const outlineWidth = (() => {
247
+ switch (size) {
248
+ case ProgressBarSize.Small: return '0.05em';
249
+ case ProgressBarSize.Medium: return '0.08em';
250
+ case ProgressBarSize.Large: return '0.1em';
251
+ default: return '0.05em';
252
+ }
253
+ })();
254
+
255
+ /*----------------------------------------*/
256
+ /* --------------- Stripes -------------- */
257
+ /*----------------------------------------*/
258
+
259
+ // Stripes style
260
+ const stripesStyle = `
261
+ .ProgressBar-stripes {
262
+ background-image: linear-gradient(315deg, #ffffff 25%, #000000 25%, #000000 50%, #ffffff 50%, #ffffff 75%, #000000 75%, #000000 100%);
263
+ background-size: 6em 6em;
264
+ animation: ProgressBar-stripe-animation 2.5s linear infinite;
265
+ opacity: 0.09;
266
+ }
267
+ @keyframes ProgressBar-stripe-animation {
268
+ 0% {
269
+ background-position: -6em 0;
270
+ }
271
+ 100% {
272
+ background-position: 0 0;
273
+ }
274
+ }
275
+ `;
276
+
277
+ // Stripes for striped effect
278
+ const stripes: React.ReactNode = (
279
+ <div>
280
+ <style>{stripesStyle}</style>
281
+ <div
282
+ className="ProgressBar-stripes position-absolute "
283
+ style={{
284
+ width: '200%',
285
+ height: '100%',
286
+ }}
287
+ >
288
+ &nbsp;
289
+ </div>
290
+ </div>
291
+ );
292
+
293
+ /*----------------------------------------*/
294
+ /* --------------- Main UI -------------- */
295
+ /*----------------------------------------*/
296
+
297
+ // Render the progress bar
298
+ return (
299
+ <div className="ProgressBar-container d-flex align-items-center">
300
+ {/* Style */}
301
+ <style>{style}</style>
302
+ {/* Use items */}
303
+ {!status.usePercent && status.numComplete && (
304
+ <span
305
+ className="ProgressBar-number-of pe-2 align-self-center"
306
+ >
307
+ {status.numComplete}
308
+ &nbsp;of&nbsp;
309
+ {status.total}
310
+ </span>
311
+ )}
312
+ {/* Use percentage */}
313
+ {status.usePercent && status.percentProgress && (
314
+ <span
315
+ className="ProgressBar-percent pe-2 align-self-center"
316
+ >
317
+ {status.percentProgress.toFixed(status?.numDecimalPlaces ?? 0)}
318
+ %
319
+ </span>
320
+ )}
321
+ <div
322
+ className={`ProgressBar-background bg-${bgVariant} w-100`}
323
+ style={{
324
+ boxShadow: `0 0 0 ${outlineWidth} ${showOutline ? '#000' : '#DEE2E6'}`,
325
+ }}
326
+ aria-valuenow={status.usePercent ? status.percentProgress : status.numComplete}
327
+ aria-valuemin={0}
328
+ aria-valuemax={status.usePercent ? 100 : status.total}
329
+ >
330
+ <div
331
+ className={
332
+ `ProgressBar-bar bg-${variant} text-start position-relative`
333
+ }
334
+ style={{
335
+ width: `${(status.usePercent ? status.percentProgress : (status.numComplete / status.total) * 100)}%`,
336
+ overflow: 'hidden',
337
+ }}
338
+ >
339
+ {striped && stripes}
340
+ &nbsp;
341
+ </div>
342
+ </div>
343
+ </div>
344
+ );
345
+ };
346
+
347
+ export default ProgressBar;
@@ -6,78 +6,6 @@ import ReactKitErrorCode from '../types/ReactKitErrorCode';
6
6
  import getTimeInfoInET from './getTimeInfoInET';
7
7
  import padZerosLeft from './padZerosLeft';
8
8
 
9
- /*----------------------------------------*/
10
- /* --------------- Helpers -------------- */
11
- /*----------------------------------------*/
12
-
13
- /**
14
- * Check if a timestamp is valid
15
- * @param opts object containing all arguments
16
- * @param opts.timestamp Timestamp in milliseconds since epoch
17
- * @param opts.expectedYear Expected year
18
- * @param opts.expectedMonth Expected month
19
- * @param opts.expectedDay Expected day
20
- * @param opts.expectedHour Expected hour
21
- * @param opts.expectedMinute Expected minute
22
- * @returns 1 if the timestamp needs to be increased, -1 if it needs to be decreased, 0 if it is valid
23
- */
24
- const checkTimestamp = (
25
- opts: {
26
- timestamp: number,
27
- expectedYear: number,
28
- expectedMonth: number,
29
- expectedDay: number,
30
- expectedHour: number,
31
- expectedMinute: number,
32
- },
33
- ): number => {
34
- const {
35
- timestamp,
36
- expectedYear,
37
- expectedMonth,
38
- expectedDay,
39
- expectedHour,
40
- expectedMinute,
41
- } = opts;
42
-
43
- const timeInfoInET = getTimeInfoInET(timestamp);
44
- if (timeInfoInET.year < expectedYear) {
45
- return 1;
46
- }
47
- if (timeInfoInET.year > expectedYear) {
48
- return -1;
49
- }
50
- if (timeInfoInET.month < expectedMonth) {
51
- return 1;
52
- }
53
- if (timeInfoInET.month > expectedMonth) {
54
- return -1;
55
- }
56
- if (timeInfoInET.day < expectedDay) {
57
- return 1;
58
- }
59
- if (timeInfoInET.day > expectedDay) {
60
- return -1;
61
- }
62
- if (timeInfoInET.hour < expectedHour) {
63
- return 1;
64
- }
65
- if (timeInfoInET.hour > expectedHour) {
66
- return -1;
67
- }
68
- if (timeInfoInET.minute < expectedMinute) {
69
- return 1;
70
- }
71
- if (timeInfoInET.minute > expectedMinute) {
72
- return -1;
73
- }
74
- return 0;
75
- };
76
-
77
- /*----------------------------------------*/
78
- /* ---------------- Main ---------------- */
79
- /*----------------------------------------*/
80
-
81
9
  /**
82
10
  * Get a timestamp (ms since epoch) from time info (year, month, day, hour, minute, etc.) in Eastern Time (ET)
83
11
  * @author Gardenia Liu
@@ -87,7 +15,7 @@ const checkTimestamp = (
87
15
  * @param opts.month Month (1-12)
88
16
  * @param opts.day Day of the month (1-31)
89
17
  * @param opts.hour Hour (0-23)
90
- * @param opts.minute Minute (0-59)
18
+ * @param opts.minute Minute (0-59))
91
19
  * @returns Timestamp in milliseconds since epoch
92
20
  */
93
21
  const getTimestampFromTimeInfoInET = (
@@ -122,55 +50,25 @@ const getTimestampFromTimeInfoInET = (
122
50
 
123
51
  // Build ET ISO string and convert to UTC timestamp
124
52
  const etISOString = `${year}-${mm}-${dd}T${hh}:${min}:00${etOffset}`;
125
- let timestamp = (new Date(etISOString)).getTime();
126
-
127
- // Heat seek to get the right timestamp
128
- const maxOffset = 24 * 60; // 24 hours in minutes
129
- let currentOffset = 0; // minutes
130
- const offsetIncrement = 15; // minutes
131
- const offsetDirection = checkTimestamp({
132
- timestamp,
133
- expectedYear: year,
134
- expectedMonth: month,
135
- expectedDay: day,
136
- expectedHour: hour,
137
- expectedMinute: minute,
138
- });
139
- if (offsetDirection === 0) {
140
- // Valid! Return the timestamp
141
- return timestamp;
142
- }
143
-
144
- // Heat seek
145
- while (Math.abs(currentOffset) < maxOffset) {
146
- // Update offset
147
- currentOffset += (offsetDirection * offsetIncrement);
53
+ const timestamp = (new Date(etISOString)).getTime();
148
54
 
149
- // Update timestamp
150
- const offsetMs = currentOffset * 60 * 1000;
151
- timestamp += offsetMs;
152
-
153
- // Check timestamp again
154
- const newDirection = checkTimestamp({
155
- timestamp,
156
- expectedYear: year,
157
- expectedMonth: month,
158
- expectedDay: day,
159
- expectedHour: hour,
160
- expectedMinute: minute,
161
- });
162
- if (newDirection === 0) {
163
- // Valid! Return the timestamp
164
- return timestamp;
165
- }
166
-
167
- // Invalid. Keep looping.
55
+ // Verify that the timestamp is correct
56
+ const timeInfoInET = getTimeInfoInET(timestamp);
57
+ if (
58
+ timeInfoInET.year !== year
59
+ || timeInfoInET.month !== month
60
+ || timeInfoInET.day !== day
61
+ || timeInfoInET.hour !== hour
62
+ || timeInfoInET.minute !== minute
63
+ ) {
64
+ throw new ErrorWithCode(
65
+ `Timestamp mismatch: expected ${year}-${mm}-${dd} ${hh}:${min}, got ${timeInfoInET.year}-${padZerosLeft(timeInfoInET.month, 2)}-${padZerosLeft(timeInfoInET.day, 2)} ${padZerosLeft(timeInfoInET.hour, 2)}:${padZerosLeft(timeInfoInET.minute, 2)}`,
66
+ ReactKitErrorCode.ETTimestampInvalid,
67
+ );
168
68
  }
169
69
 
170
- throw new ErrorWithCode(
171
- `Timestamp mismatch: expected ${year}-${mm}-${dd} ${hh}:${min}, seeked to offset ${currentOffset} minutes but could not find a valid timestamp.`,
172
- ReactKitErrorCode.ETTimestampInvalid,
173
- );
70
+ // Valid! Return the timestamp
71
+ return timestamp;
174
72
  };
175
73
 
176
74
  export default getTimestampFromTimeInfoInET;
package/src/index.ts CHANGED
@@ -31,6 +31,7 @@ import ToggleSwitch from './components/ToggleSwitch';
31
31
  import AutoscrollToBottomContainer from './components/AutoscrollToBottomContainer';
32
32
  import MultiSwitch from './components/MultiSwitch';
33
33
  import Dropdown from './components/Dropdown';
34
+ import ProgressBar from './components/ProgressBar';
34
35
 
35
36
  // Import errors
36
37
  import ErrorWithCode from './errors/ErrorWithCode';
@@ -156,6 +157,7 @@ export {
156
157
  AutoscrollToBottomContainer,
157
158
  MultiSwitch,
158
159
  Dropdown,
160
+ ProgressBar,
159
161
  // Global functions
160
162
  alert,
161
163
  prompt,
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Progress bar sizes
3
+ * @author Allison Zhang
4
+ */
5
+ enum ProgressBarSize {
6
+ Small = 'Small',
7
+ Medium = 'Medium',
8
+ Large = 'Large',
9
+ }
10
+
11
+ export default ProgressBarSize;