dce-reactkit 3.0.40 → 3.0.43
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/cjs/index.js +344 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/CopiableBox.d.ts +16 -0
- package/dist/cjs/types/components/PopFailureMark.d.ts +12 -0
- package/dist/cjs/types/components/PopPendingMark.d.ts +12 -0
- package/dist/cjs/types/index.d.ts +4 -1
- package/dist/esm/index.js +344 -14
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/CopiableBox.d.ts +16 -0
- package/dist/esm/types/components/PopFailureMark.d.ts +12 -0
- package/dist/esm/types/components/PopPendingMark.d.ts +12 -0
- package/dist/esm/types/index.d.ts +4 -1
- package/dist/index.d.ts +61 -21
- package/package.json +1 -1
- package/src/components/CopiableBox.tsx +267 -0
- package/src/components/PopFailureMark.tsx +171 -0
- package/src/components/PopPendingMark.tsx +141 -0
- package/src/helpers/getHumanReadableDate.ts +1 -1
- package/src/index.ts +6 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copiable text box
|
|
3
|
+
* @author Gabe Abrams
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Import React
|
|
7
|
+
import React, { useReducer } from 'react';
|
|
8
|
+
|
|
9
|
+
// Import other reactkit functions
|
|
10
|
+
import { alert, waitMs } from '..';
|
|
11
|
+
|
|
12
|
+
// Import FontAwesome
|
|
13
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
14
|
+
import { faClipboard } from '@fortawesome/free-solid-svg-icons';
|
|
15
|
+
|
|
16
|
+
/*------------------------------------------------------------------------*/
|
|
17
|
+
/* Types */
|
|
18
|
+
/*------------------------------------------------------------------------*/
|
|
19
|
+
|
|
20
|
+
// Props definition
|
|
21
|
+
type Props = {
|
|
22
|
+
// Unique name of the item to copy (no spaces, compatible with css classes)
|
|
23
|
+
name: string,
|
|
24
|
+
// The text to copy
|
|
25
|
+
text: string,
|
|
26
|
+
// Human-readable label of the copy field
|
|
27
|
+
label: string,
|
|
28
|
+
// FontAwesome icon to place before the label
|
|
29
|
+
labelIcon?: any,
|
|
30
|
+
// If defined, the label will have a minimum width
|
|
31
|
+
minLabelWidthRem: number,
|
|
32
|
+
// If true, the box will be a textarea to support larger, multiline text
|
|
33
|
+
multiline?: boolean,
|
|
34
|
+
// Number of lines to show in multiline view (only relevant if multiline)
|
|
35
|
+
numVisibleLines?: number,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/*------------------------------------------------------------------------*/
|
|
39
|
+
/* State */
|
|
40
|
+
/*------------------------------------------------------------------------*/
|
|
41
|
+
|
|
42
|
+
/* -------- State Definition -------- */
|
|
43
|
+
|
|
44
|
+
type State = {
|
|
45
|
+
// True if text was recently copied
|
|
46
|
+
recentlyCopied: boolean,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/* ------------- Actions ------------ */
|
|
50
|
+
|
|
51
|
+
// Types of actions
|
|
52
|
+
enum ActionType {
|
|
53
|
+
// Indicate that the text was recently copied
|
|
54
|
+
IndicateRecentlyCopied = 'indicate-recently-copied',
|
|
55
|
+
// Clear the status
|
|
56
|
+
ClearRecentlyCopiedStatus = 'clear-recently-copied-status',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Action definitions
|
|
60
|
+
type Action = {
|
|
61
|
+
// Action type
|
|
62
|
+
type: (
|
|
63
|
+
| ActionType.IndicateRecentlyCopied
|
|
64
|
+
| ActionType.ClearRecentlyCopiedStatus
|
|
65
|
+
),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Reducer that executes actions
|
|
70
|
+
* @author Gabe Abrams
|
|
71
|
+
* @param state current state
|
|
72
|
+
* @param action action to execute
|
|
73
|
+
*/
|
|
74
|
+
const reducer = (state: State, action: Action): State => {
|
|
75
|
+
switch (action.type) {
|
|
76
|
+
case ActionType.IndicateRecentlyCopied: {
|
|
77
|
+
return {
|
|
78
|
+
recentlyCopied: true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
case ActionType.ClearRecentlyCopiedStatus: {
|
|
82
|
+
return {
|
|
83
|
+
recentlyCopied: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
default: {
|
|
87
|
+
return state;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/*------------------------------------------------------------------------*/
|
|
93
|
+
/* Component */
|
|
94
|
+
/*------------------------------------------------------------------------*/
|
|
95
|
+
|
|
96
|
+
const CopiableBox: React.FC<Props> = (props) => {
|
|
97
|
+
/*------------------------------------------------------------------------*/
|
|
98
|
+
/* Setup */
|
|
99
|
+
/*------------------------------------------------------------------------*/
|
|
100
|
+
|
|
101
|
+
/* -------------- Props ------------- */
|
|
102
|
+
|
|
103
|
+
// Destructure all props
|
|
104
|
+
const {
|
|
105
|
+
name,
|
|
106
|
+
text,
|
|
107
|
+
label,
|
|
108
|
+
labelIcon,
|
|
109
|
+
minLabelWidthRem,
|
|
110
|
+
multiline,
|
|
111
|
+
numVisibleLines = 10,
|
|
112
|
+
} = props;
|
|
113
|
+
|
|
114
|
+
/* -------------- State ------------- */
|
|
115
|
+
|
|
116
|
+
// Initial state
|
|
117
|
+
const initialState: State = {
|
|
118
|
+
recentlyCopied: false,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// Initialize state
|
|
122
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
123
|
+
|
|
124
|
+
// Destructure common state
|
|
125
|
+
const {
|
|
126
|
+
recentlyCopied,
|
|
127
|
+
} = state;
|
|
128
|
+
|
|
129
|
+
/*------------------------------------------------------------------------*/
|
|
130
|
+
/* Component Functions */
|
|
131
|
+
/*------------------------------------------------------------------------*/
|
|
132
|
+
|
|
133
|
+
// Determine the id for the copiable text field
|
|
134
|
+
const copiableFieldClassName = `CopiableBox-text-box-${name}`;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Perform a copy
|
|
138
|
+
* @author Gabe Abrams
|
|
139
|
+
*/
|
|
140
|
+
const performCopy = async () => {
|
|
141
|
+
// Write to clipboard
|
|
142
|
+
let copyFailed = false;
|
|
143
|
+
try {
|
|
144
|
+
await navigator.clipboard.writeText(text);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
copyFailed = true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Try copy again if it failed
|
|
150
|
+
if (copyFailed) {
|
|
151
|
+
try {
|
|
152
|
+
const input = (
|
|
153
|
+
document.getElementsByClassName(copiableFieldClassName)[0]
|
|
154
|
+
) as HTMLInputElement;
|
|
155
|
+
input.focus();
|
|
156
|
+
input.select();
|
|
157
|
+
document.execCommand('copy');
|
|
158
|
+
input.blur();
|
|
159
|
+
} catch (err) {
|
|
160
|
+
return alert(
|
|
161
|
+
'Unable to copy',
|
|
162
|
+
'Oops! We couldn\'t copy that to the clipboard. Please copy the text manually.',
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Show copied notice
|
|
168
|
+
dispatch({
|
|
169
|
+
type: ActionType.IndicateRecentlyCopied,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Wait a moment
|
|
173
|
+
await waitMs(4000);
|
|
174
|
+
|
|
175
|
+
// Hide copied notice
|
|
176
|
+
dispatch({
|
|
177
|
+
type: ActionType.ClearRecentlyCopiedStatus,
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/*------------------------------------------------------------------------*/
|
|
182
|
+
/* Render */
|
|
183
|
+
/*------------------------------------------------------------------------*/
|
|
184
|
+
|
|
185
|
+
/*----------------------------------------*/
|
|
186
|
+
/* Main UI */
|
|
187
|
+
/*----------------------------------------*/
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div className="input-group mb-2">
|
|
191
|
+
{/* Label */}
|
|
192
|
+
<span
|
|
193
|
+
className="input-group-text"
|
|
194
|
+
style={{
|
|
195
|
+
minWidth: (
|
|
196
|
+
minLabelWidthRem
|
|
197
|
+
? `${minLabelWidthRem}rem`
|
|
198
|
+
: undefined
|
|
199
|
+
),
|
|
200
|
+
}}
|
|
201
|
+
>
|
|
202
|
+
{labelIcon && (
|
|
203
|
+
<FontAwesomeIcon
|
|
204
|
+
icon={labelIcon}
|
|
205
|
+
className="me-1"
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
208
|
+
{label}
|
|
209
|
+
</span>
|
|
210
|
+
|
|
211
|
+
{/* Text */}
|
|
212
|
+
{
|
|
213
|
+
multiline
|
|
214
|
+
? (
|
|
215
|
+
<textarea
|
|
216
|
+
className={`${copiableFieldClassName} CopiableBox-text-multiline form-control bg-white text-dark`}
|
|
217
|
+
value={text}
|
|
218
|
+
aria-label={`${label} text`}
|
|
219
|
+
rows={numVisibleLines}
|
|
220
|
+
readOnly
|
|
221
|
+
/>
|
|
222
|
+
)
|
|
223
|
+
: (
|
|
224
|
+
<input
|
|
225
|
+
type="text"
|
|
226
|
+
className={`${copiableFieldClassName} CopiableBox-text-single-line form-control bg-white text-dark`}
|
|
227
|
+
value={text}
|
|
228
|
+
aria-label={`${label} text`}
|
|
229
|
+
readOnly
|
|
230
|
+
/>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
<button
|
|
235
|
+
className="btn btn-secondary"
|
|
236
|
+
type="button"
|
|
237
|
+
aria-label={`copy ${label} to the clipboard`}
|
|
238
|
+
disabled={recentlyCopied}
|
|
239
|
+
style={{
|
|
240
|
+
minWidth: '5.2rem',
|
|
241
|
+
}}
|
|
242
|
+
onClick={performCopy}
|
|
243
|
+
>
|
|
244
|
+
{
|
|
245
|
+
recentlyCopied
|
|
246
|
+
? 'Copied!'
|
|
247
|
+
: (
|
|
248
|
+
<span>
|
|
249
|
+
<FontAwesomeIcon
|
|
250
|
+
icon={faClipboard}
|
|
251
|
+
className="me-1"
|
|
252
|
+
/>
|
|
253
|
+
Copy
|
|
254
|
+
</span>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
</button>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
/*------------------------------------------------------------------------*/
|
|
263
|
+
/* Wrap Up */
|
|
264
|
+
/*------------------------------------------------------------------------*/
|
|
265
|
+
|
|
266
|
+
// Export component
|
|
267
|
+
export default CopiableBox;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure x mark 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 x mark in rem
|
|
16
|
+
sizeRem?: number,
|
|
17
|
+
// Bootstrap variant of circle
|
|
18
|
+
circleVariant?: string,
|
|
19
|
+
// Bootstrap variant of x mark
|
|
20
|
+
xVariant?: string,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/*------------------------------------------------------------------------*/
|
|
24
|
+
/* Style */
|
|
25
|
+
/*------------------------------------------------------------------------*/
|
|
26
|
+
|
|
27
|
+
const style = `
|
|
28
|
+
.PopFailureMark-outer-container {
|
|
29
|
+
position: relative;
|
|
30
|
+
display: inline-block;
|
|
31
|
+
border-radius: 50%;
|
|
32
|
+
|
|
33
|
+
animation-name: PopFailureMark-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 PopFailureMark-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
|
+
.PopFailureMark-x-stroke-1 {
|
|
58
|
+
position: absolute;
|
|
59
|
+
left: 25%;
|
|
60
|
+
top: 19%;
|
|
61
|
+
|
|
62
|
+
display: inline-block;
|
|
63
|
+
height: 16%;
|
|
64
|
+
width: 70%;
|
|
65
|
+
|
|
66
|
+
transform-origin: left;
|
|
67
|
+
|
|
68
|
+
animation-name: PopFailureMark-x-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 PopFailureMark-x-stroke-1 {
|
|
76
|
+
0% {
|
|
77
|
+
transform: rotate(45deg) scaleX(0);
|
|
78
|
+
}
|
|
79
|
+
100% {
|
|
80
|
+
transform: rotate(45deg) scaleX(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.PopFailureMark-x-stroke-2 {
|
|
85
|
+
position: absolute;
|
|
86
|
+
left: 75%;
|
|
87
|
+
top: 19%;
|
|
88
|
+
|
|
89
|
+
display: inline-block;
|
|
90
|
+
height: 16%;
|
|
91
|
+
width: 70%;
|
|
92
|
+
|
|
93
|
+
transform-origin: left;
|
|
94
|
+
|
|
95
|
+
animation-name: PopFailureMark-x-stroke-2;
|
|
96
|
+
animation-duration: 0.3s;
|
|
97
|
+
animation-delay: 0.6s;
|
|
98
|
+
animation-fill-mode: both;
|
|
99
|
+
animation-iteration-count: 1;
|
|
100
|
+
animation-timing-function: ease-out;
|
|
101
|
+
}
|
|
102
|
+
@keyframes PopFailureMark-x-stroke-2 {
|
|
103
|
+
0% {
|
|
104
|
+
transform: rotate(135deg) scaleX(0);
|
|
105
|
+
}
|
|
106
|
+
100% {
|
|
107
|
+
transform: rotate(135deg) scaleX(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
/*------------------------------------------------------------------------*/
|
|
113
|
+
/* Component */
|
|
114
|
+
/*------------------------------------------------------------------------*/
|
|
115
|
+
|
|
116
|
+
const PopFailureMark: React.FC<Props> = (props) => {
|
|
117
|
+
/*------------------------------------------------------------------------*/
|
|
118
|
+
/* Setup */
|
|
119
|
+
/*------------------------------------------------------------------------*/
|
|
120
|
+
|
|
121
|
+
/* -------------- Props ------------- */
|
|
122
|
+
|
|
123
|
+
// Destructure all props
|
|
124
|
+
const {
|
|
125
|
+
sizeRem = 3,
|
|
126
|
+
circleVariant = 'danger',
|
|
127
|
+
xVariant = 'white',
|
|
128
|
+
} = props;
|
|
129
|
+
|
|
130
|
+
/*------------------------------------------------------------------------*/
|
|
131
|
+
/* Render */
|
|
132
|
+
/*------------------------------------------------------------------------*/
|
|
133
|
+
|
|
134
|
+
/*----------------------------------------*/
|
|
135
|
+
/* Main UI */
|
|
136
|
+
/*----------------------------------------*/
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div
|
|
140
|
+
className={`PopFailureMark-outer-container bg-${circleVariant}`}
|
|
141
|
+
style={{
|
|
142
|
+
width: `${sizeRem}rem`,
|
|
143
|
+
height: `${sizeRem}rem`,
|
|
144
|
+
}}
|
|
145
|
+
aria-label="mark indicating failure"
|
|
146
|
+
>
|
|
147
|
+
{/* Style */}
|
|
148
|
+
<style>{style}</style>
|
|
149
|
+
{/* Failure mark */}
|
|
150
|
+
<div
|
|
151
|
+
className={`PopFailureMark-x-stroke-1 bg-${xVariant}`}
|
|
152
|
+
style={{
|
|
153
|
+
borderRadius: `${sizeRem / 5}rem`,
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
<div
|
|
157
|
+
className={`PopFailureMark-x-stroke-2 bg-${xVariant}`}
|
|
158
|
+
style={{
|
|
159
|
+
borderRadius: `${sizeRem / 5}rem`,
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/*------------------------------------------------------------------------*/
|
|
167
|
+
/* Wrap Up */
|
|
168
|
+
/*------------------------------------------------------------------------*/
|
|
169
|
+
|
|
170
|
+
// Export component
|
|
171
|
+
export default PopFailureMark;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure pending that pops into view
|
|
3
|
+
* @author Gabe Abrams
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Import React
|
|
7
|
+
import React from 'react';
|
|
8
|
+
|
|
9
|
+
// Import FontAwesome
|
|
10
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
11
|
+
import { faHourglass } from '@fortawesome/free-solid-svg-icons';
|
|
12
|
+
|
|
13
|
+
/*------------------------------------------------------------------------*/
|
|
14
|
+
/* Types */
|
|
15
|
+
/*------------------------------------------------------------------------*/
|
|
16
|
+
|
|
17
|
+
// Props definition
|
|
18
|
+
type Props = {
|
|
19
|
+
// Size of pending in rem
|
|
20
|
+
sizeRem?: number,
|
|
21
|
+
// Bootstrap variant of circle
|
|
22
|
+
circleVariant?: string,
|
|
23
|
+
// Bootstrap variant of pending
|
|
24
|
+
hourglassVariant?: string,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/*------------------------------------------------------------------------*/
|
|
28
|
+
/* Style */
|
|
29
|
+
/*------------------------------------------------------------------------*/
|
|
30
|
+
|
|
31
|
+
const style = `
|
|
32
|
+
.PopPendingMark-outer-container {
|
|
33
|
+
position: relative;
|
|
34
|
+
display: inline-block;
|
|
35
|
+
border-radius: 50%;
|
|
36
|
+
|
|
37
|
+
animation-name: PopPendingMark-outer-container;
|
|
38
|
+
animation-duration: 0.8s;
|
|
39
|
+
animation-fill-mode: both;
|
|
40
|
+
animation-iteration-count: 1;
|
|
41
|
+
animation-timing-function: ease-out;
|
|
42
|
+
}
|
|
43
|
+
@keyframes PopPendingMark-outer-container {
|
|
44
|
+
0% {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transform: scale(1.5);
|
|
47
|
+
filter: saturate(0);
|
|
48
|
+
}
|
|
49
|
+
80.7% {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
transform: scale(1);
|
|
52
|
+
filter: saturate(0);
|
|
53
|
+
}
|
|
54
|
+
100% {
|
|
55
|
+
opacity: 1;
|
|
56
|
+
transform: scale(1);
|
|
57
|
+
filter: saturate(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.PopPendingMark-hourglass {
|
|
62
|
+
position: absolute;
|
|
63
|
+
left: 28%;
|
|
64
|
+
top: 21%;
|
|
65
|
+
|
|
66
|
+
animation-name: PopPendingMark-pending;
|
|
67
|
+
animation-duration: 0.3s;
|
|
68
|
+
animation-delay: 0.3s;
|
|
69
|
+
animation-fill-mode: both;
|
|
70
|
+
animation-iteration-count: 1;
|
|
71
|
+
animation-timing-function: ease-in;
|
|
72
|
+
}
|
|
73
|
+
@keyframes PopPendingMark-pending {
|
|
74
|
+
0% {
|
|
75
|
+
transform: scale(0.7) rotate(30deg);
|
|
76
|
+
opacity: 0;
|
|
77
|
+
}
|
|
78
|
+
100% {
|
|
79
|
+
transform: scale(1) rotate(0);
|
|
80
|
+
opacity: 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
/*------------------------------------------------------------------------*/
|
|
86
|
+
/* Component */
|
|
87
|
+
/*------------------------------------------------------------------------*/
|
|
88
|
+
|
|
89
|
+
const PopPendingMark: React.FC<Props> = (props) => {
|
|
90
|
+
/*------------------------------------------------------------------------*/
|
|
91
|
+
/* Setup */
|
|
92
|
+
/*------------------------------------------------------------------------*/
|
|
93
|
+
|
|
94
|
+
/* -------------- Props ------------- */
|
|
95
|
+
|
|
96
|
+
// Destructure all props
|
|
97
|
+
const {
|
|
98
|
+
sizeRem = 3,
|
|
99
|
+
circleVariant = 'warning',
|
|
100
|
+
hourglassVariant = 'white',
|
|
101
|
+
} = props;
|
|
102
|
+
|
|
103
|
+
/*------------------------------------------------------------------------*/
|
|
104
|
+
/* Render */
|
|
105
|
+
/*------------------------------------------------------------------------*/
|
|
106
|
+
|
|
107
|
+
/*----------------------------------------*/
|
|
108
|
+
/* Main UI */
|
|
109
|
+
/*----------------------------------------*/
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div
|
|
113
|
+
className={`PopPendingMark-outer-container bg-${circleVariant}`}
|
|
114
|
+
style={{
|
|
115
|
+
width: `${sizeRem}rem`,
|
|
116
|
+
height: `${sizeRem}rem`,
|
|
117
|
+
}}
|
|
118
|
+
aria-label="mark indicating that the item is pending"
|
|
119
|
+
>
|
|
120
|
+
{/* Style */}
|
|
121
|
+
<style>{style}</style>
|
|
122
|
+
{/* Pending mark */}
|
|
123
|
+
<div>
|
|
124
|
+
<FontAwesomeIcon
|
|
125
|
+
icon={faHourglass}
|
|
126
|
+
className={`PopPendingMark-hourglass text-${hourglassVariant}`}
|
|
127
|
+
style={{
|
|
128
|
+
fontSize: `${sizeRem * 0.6}rem`,
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/*------------------------------------------------------------------------*/
|
|
137
|
+
/* Wrap Up */
|
|
138
|
+
/*------------------------------------------------------------------------*/
|
|
139
|
+
|
|
140
|
+
// Export component
|
|
141
|
+
export default PopPendingMark;
|
|
@@ -33,7 +33,7 @@ const getHumanReadableDate = (dateOrTimestamp?: Date | number) => {
|
|
|
33
33
|
const currYear = getTimeInfoInET().year;
|
|
34
34
|
|
|
35
35
|
// Create start of description
|
|
36
|
-
let description = `${monthMap[month as keyof typeof monthMap]} ${getOrdinal(day)}`;
|
|
36
|
+
let description = `${monthMap[month as keyof typeof monthMap]} ${day}${getOrdinal(day)}`;
|
|
37
37
|
|
|
38
38
|
// Add on year if it's different
|
|
39
39
|
if (year !== currYear) {
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,9 @@ import ButtonInputGroup from './components/ButtonInputGroup';
|
|
|
10
10
|
import SimpleDateChooser from './components/SimpleDateChooser';
|
|
11
11
|
import Drawer from './components/Drawer';
|
|
12
12
|
import PopSuccessMark from './components/PopSuccessMark';
|
|
13
|
+
import PopFailureMark from './components/PopFailureMark';
|
|
14
|
+
import PopPendingMark from './components/PopPendingMark';
|
|
15
|
+
import CopiableBox from './components/CopiableBox';
|
|
13
16
|
|
|
14
17
|
// Import errors
|
|
15
18
|
import ErrorWithCode from './errors/ErrorWithCode';
|
|
@@ -63,6 +66,9 @@ export {
|
|
|
63
66
|
SimpleDateChooser,
|
|
64
67
|
Drawer,
|
|
65
68
|
PopSuccessMark,
|
|
69
|
+
PopFailureMark,
|
|
70
|
+
PopPendingMark,
|
|
71
|
+
CopiableBox,
|
|
66
72
|
// Global functions
|
|
67
73
|
alert,
|
|
68
74
|
confirm,
|