@mackin.com/styleguide 7.13.1 → 7.14.1-beta1

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/index.esm.js ADDED
@@ -0,0 +1,3817 @@
1
+ import { css, cx, keyframes, injectGlobal } from '@emotion/css';
2
+ import { debounce, sumBy, orderBy, get } from 'lodash';
3
+ import * as React from 'react';
4
+ import React__default, { createContext, useContext, useState, useEffect, useRef, useMemo } from 'react';
5
+ import { nanoid } from 'nanoid';
6
+ import { faCheckCircle, faCircle, faChevronDown, faChevronUp, faSquare, faTimesCircle } from '@fortawesome/pro-regular-svg-icons';
7
+ import { faPlus, faTrashAlt, faSave, faCrow, faTimes, faSync, faCheckSquare } from '@fortawesome/pro-solid-svg-icons';
8
+ import { faWifi, faWifiSlash, faBars, faSearch, faQuestionCircle, faNarwhal, faChevronRight, faChevronLeft, faCloudDownload, faCloudUpload, faCalendarAlt, faCopy, faPaste, faEyeSlash, faEye } from '@fortawesome/pro-light-svg-icons';
9
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
10
+ import { format, isExists, getDaysInMonth, getDay, isSameMonth, isBefore, isAfter, isSameDay, endOfMonth, addMonths, startOfMonth } from 'date-fns';
11
+ import { createPortal } from 'react-dom';
12
+ import { Popover as Popover$1, ArrowContainer } from 'react-tiny-popover';
13
+ import { Link } from 'react-router-dom';
14
+ import ReactSlider from 'react-slider';
15
+
16
+ /** Call this on your theme after messing with the props. It will re-build things that depend on sizes and colors. */
17
+ const calcDynamicThemeProps = (theme) => {
18
+ theme.controls.border = `${theme.controls.borderWidth} solid ${theme.colors.border}`;
19
+ theme.controls.transition = `box-shadow ${theme.controls.transitionDuration} ${theme.controls.transitionEasing}, opacity ${theme.controls.transitionDuration} ${theme.controls.transitionEasing}, background-color ${theme.controls.transitionDuration} ${theme.controls.transitionEasing}, filter ${theme.controls.transitionDuration} ${theme.controls.transitionEasing}`;
20
+ theme.controls.focusOutlineShadow = `0px 0px 4px 2px ${theme.colors.focusOutline}`;
21
+ theme.controls.focusOutlineRequiredShadow = `0px 0px 4px 2px ${theme.colors.focusOutlineRequired}`;
22
+ theme.controls.dividerBorder = `2px solid ${theme.colors.divider}`;
23
+ theme.mediaQueries.desktop = `@media(min-width:${theme.breakpoints.desktop})`;
24
+ theme.mediaQueries.tablet = `@media(min-width:${theme.breakpoints.tablet})`;
25
+ };
26
+ const defaultTheme = {
27
+ colors: {
28
+ primary: '#7851a9',
29
+ primaryFont: 'rgba(255, 255, 255, 0.9)',
30
+ primary2: '#007bff',
31
+ primary2Font: 'rgba(255, 255, 255, 0.9)',
32
+ secondary: '#9e9e9e',
33
+ secondary2Font: 'rgba(255, 255, 255, 0.9)',
34
+ info: '#7851a9',
35
+ infoFont: 'rgba(255, 255, 255, 0.9)',
36
+ warning: '#F5AD94',
37
+ warningFont: 'rgba(0, 0, 0, 0.9)',
38
+ positive: '#28a745',
39
+ positiveFont: 'rgba(255, 255, 255, 0.9)',
40
+ negative: '#dc3545',
41
+ negativeFont: 'rgba(255, 255, 255, 0.9)',
42
+ omg: '#dc3545',
43
+ omgFont: 'rgba(255, 255, 255, 0.9)',
44
+ bg: 'white',
45
+ lightBg: 'rgba(0,0,0,.075)',
46
+ font: 'rgba(0, 0, 0, 0.70)',
47
+ header: '#7851a9',
48
+ headerFont: 'rgba(255, 255, 255, 0.9)',
49
+ link: '#007bff',
50
+ border: 'rgba(0, 0, 0, 0.25)',
51
+ divider: 'rgba(0, 0, 0, 0.50)',
52
+ nav: '#7851a9',
53
+ navFont: 'rgba(255, 255, 255, 0.9)',
54
+ focusOutline: 'hsl(155deg 67% 85%)',
55
+ progressBg: '#007bff63',
56
+ progressFill: '#007bff',
57
+ modalBg: 'white',
58
+ disabled: 'rgba(0,0,0,.075)',
59
+ textHighlight: 'hsl(54deg 100% 62%)',
60
+ required: '#dc3545',
61
+ focusOutlineRequired: 'rgb(212 28 89 / 75%)',
62
+ backdrop: 'rgba(0, 0, 0, 0.25)',
63
+ pagerBg: 'rgba(0,0,0,.075)'
64
+ },
65
+ fonts: {
66
+ family: 'Arial, Helvetica, sans-serif',
67
+ size: '16px',
68
+ sizeSmall: '0.7rem',
69
+ sizeLarge: '1.3rem',
70
+ headerFamily: 'Arial, Helvetica, sans-serif',
71
+ },
72
+ controls: {
73
+ padding: '0.5rem',
74
+ fontSize: '1rem',
75
+ borderWidth: '1px',
76
+ borderRadius: '',
77
+ border: ``,
78
+ height: '44px',
79
+ heightSmall: '34px',
80
+ boxShadow: '2px 2px 4px rgba(0, 0, 0, 0.25)',
81
+ hoverBrightness: 'brightness(0.75)',
82
+ transitionDuration: '0.25s',
83
+ transitionEasing: 'ease-in-out',
84
+ transition: '',
85
+ focusOutlineShadow: '',
86
+ focusOutlineRequiredShadow: '',
87
+ roundRadius: '3rem',
88
+ /** @deprecated Use theme.controls.borderRadius (global) or style the components individually. */
89
+ roundedRadius: '0.5rem',
90
+ disabledOpacity: '0.5',
91
+ formButtonMinWidth: '7rem',
92
+ gap: '1rem',
93
+ dividerMargin: '1rem',
94
+ dividerBorder: '',
95
+ headerBoxShadow: '0px 2px 12px 6px rgba(0, 0, 0, 0.2)'
96
+ },
97
+ zIndexes: {
98
+ header: 50,
99
+ backdrop: 100,
100
+ nav: 110,
101
+ flyout: 120,
102
+ modal: 130,
103
+ tooltip: 1000
104
+ },
105
+ layout: {
106
+ headerHeight: '74px',
107
+ headerBodyOffset: '2rem',
108
+ navWidth: '300px'
109
+ },
110
+ breakpoints: {
111
+ desktop: '800px',
112
+ tablet: '768px'
113
+ },
114
+ mediaQueries: {
115
+ desktop: '',
116
+ tablet: ''
117
+ }
118
+ };
119
+ calcDynamicThemeProps(defaultTheme);
120
+
121
+ const ThemeContext = createContext(defaultTheme);
122
+ const ThemeProvider = (p) => {
123
+ return (React__default.createElement(ThemeContext.Provider, { value: p.theme }, p.children));
124
+ };
125
+
126
+ /** Returns a user-provided theme if ThemeProvider was used correctly, or the default theme. */
127
+ const useThemeSafely = () => {
128
+ const theme = useContext(ThemeContext);
129
+ // Check for expected prop. If not present, the user did not wrap the app in ThemeProvider
130
+ // OR did not pass the default theme as the base.
131
+ if (theme && theme.breakpoints) {
132
+ return theme;
133
+ }
134
+ return defaultTheme;
135
+ };
136
+
137
+ /** @deprecated Use Backdrop2 going forward. */
138
+ const Backdrop$1 = (props) => {
139
+ var _a;
140
+ const showTimeMs = (_a = props.showTimeMs) !== null && _a !== void 0 ? _a : 250;
141
+ const backdropId = React.useRef('Backdrop' + nanoid());
142
+ const theme = useThemeSafely();
143
+ const backdropStyles = css `
144
+ opacity: 0;
145
+ position: fixed;
146
+ top: 0;
147
+ left: 0;
148
+ right: 0;
149
+ bottom: 0;
150
+ background-color: ${theme.colors.backdrop};
151
+ transition: opacity ${showTimeMs}ms ease-in-out;
152
+ visibility: hidden;
153
+ user-select: none;
154
+ -webkit-tap-highlight-color: transparent;
155
+ `;
156
+ const showStyles = css `
157
+ z-index: ${theme.zIndexes.backdrop} !important;
158
+ opacity: 1.0 !important;
159
+ label:${backdropId.current};
160
+ `;
161
+ const bodyStyles = css `
162
+ overflow: hidden !important;
163
+ label:${backdropId.current};
164
+ `;
165
+ const bodyResponsiveStyles = css `
166
+ label:${backdropId.current};
167
+ @media(min-width:${theme.breakpoints.desktop}) {
168
+ overflow: auto !important;
169
+ }
170
+ `;
171
+ const bodyReverseResponsiveStyles = css `
172
+ ${bodyStyles}
173
+ overflow: auto !important;
174
+ @media(min-width:${theme.breakpoints.desktop}) {
175
+ overflow: hidden !important;
176
+ }
177
+ `;
178
+ const styles = css `
179
+ ${backdropStyles}
180
+ ${props.onClick && `
181
+ cursor: pointer;
182
+ `}
183
+ ${props.transparent && `
184
+ background-color: transparent;
185
+ transition: none;
186
+ `}
187
+ ${props.children && `
188
+ display: flex;
189
+ justify-content:center;
190
+ align-items: center;
191
+ `}
192
+ ${props.responsive && `
193
+ @media(min-width:${theme.breakpoints.desktop}) {
194
+ display: none;
195
+ }
196
+ `}
197
+ ${props.reverseResponsive && `
198
+ display: none;
199
+ @media(min-width:${theme.breakpoints.desktop}) {
200
+ display: flex;
201
+ }
202
+ `}
203
+ `;
204
+ const backdrop = React.useRef(null);
205
+ React.useEffect(() => {
206
+ if (backdrop && backdrop.current) {
207
+ if (props.show && backdrop.current.style.visibility !== 'visible') {
208
+ backdrop.current.style.visibility = 'visible';
209
+ backdrop.current.classList.add(showStyles);
210
+ if (!props.allowScroll) {
211
+ document.body.classList.add(bodyStyles);
212
+ if (props.responsive) {
213
+ document.body.classList.add(bodyResponsiveStyles);
214
+ }
215
+ else if (props.reverseResponsive) {
216
+ document.body.classList.add(bodyReverseResponsiveStyles);
217
+ }
218
+ }
219
+ }
220
+ else if (!props.show && backdrop.current.style.visibility === 'visible') {
221
+ backdrop.current.classList.remove(showStyles);
222
+ if (backdrop && backdrop.current) {
223
+ backdrop.current.style.visibility = 'hidden';
224
+ if (!props.allowScroll) {
225
+ document.body.classList.remove(bodyStyles);
226
+ if (props.responsive) {
227
+ document.body.classList.remove(bodyResponsiveStyles);
228
+ }
229
+ else if (props.reverseResponsive) {
230
+ document.body.classList.remove(bodyReverseResponsiveStyles);
231
+ }
232
+ }
233
+ }
234
+ }
235
+ }
236
+ return () => {
237
+ if (backdrop && backdrop.current && !props.allowScroll) {
238
+ document.body.classList.remove(bodyStyles);
239
+ }
240
+ };
241
+ }, [props.show]);
242
+ return (React.createElement("div", { onMouseDown: e => {
243
+ var _a;
244
+ e.stopPropagation();
245
+ e.preventDefault();
246
+ (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
247
+ }, onClick: e => {
248
+ e.stopPropagation();
249
+ e.preventDefault();
250
+ }, ref: backdrop, className: cx('backdrop', styles, props.className) }, props.children));
251
+ };
252
+
253
+ /*! *****************************************************************************
254
+ Copyright (c) Microsoft Corporation.
255
+
256
+ Permission to use, copy, modify, and/or distribute this software for any
257
+ purpose with or without fee is hereby granted.
258
+
259
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
260
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
261
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
262
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
263
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
264
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
265
+ PERFORMANCE OF THIS SOFTWARE.
266
+ ***************************************************************************** */
267
+
268
+ function __rest(s, e) {
269
+ var t = {};
270
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
271
+ t[p] = s[p];
272
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
273
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
274
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
275
+ t[p[i]] = s[p[i]];
276
+ }
277
+ return t;
278
+ }
279
+
280
+ const ICONS = {
281
+ add: faPlus,
282
+ delete: faTrashAlt,
283
+ save: faSave,
284
+ activate: faCheckCircle,
285
+ deactivate: faCircle,
286
+ online: faWifi,
287
+ offline: faWifiSlash,
288
+ noIcon: faCrow,
289
+ close: faTimes,
290
+ waiting: faSync,
291
+ refresh: faSync,
292
+ menu: faBars,
293
+ search: faSearch,
294
+ expand: faChevronDown,
295
+ collapse: faChevronUp,
296
+ help: faQuestionCircle,
297
+ debug: faNarwhal,
298
+ goTo: faChevronRight,
299
+ goBack: faChevronLeft,
300
+ download: faCloudDownload,
301
+ upload: faCloudUpload,
302
+ selected: faCheckSquare,
303
+ unselected: faSquare,
304
+ pagerLeft: faChevronLeft,
305
+ pagerRight: faChevronRight,
306
+ sortAsc: faChevronUp,
307
+ sortDesc: faChevronDown,
308
+ pickDate: faCalendarAlt,
309
+ copy: faCopy,
310
+ paste: faPaste,
311
+ clear: faTimesCircle,
312
+ hide: faEyeSlash,
313
+ show: faEye
314
+ };
315
+ const Icon = (props) => {
316
+ var _a;
317
+ const icon = (_a = ICONS[props.id]) !== null && _a !== void 0 ? _a : ICONS['noIcon'];
318
+ return React.createElement(FontAwesomeIcon, { style: props.style, onClick: props.onClick, spin: props.spin, className: cx('icon', props.className), icon: icon });
319
+ };
320
+
321
+ const Button = (props) => {
322
+ var _a, _b;
323
+ const nativeProps = __rest(props, ["variant", "textAlign", "block", "round", "rounded", "rightIcon", "leftIcon", "iconBlock", "small", "readonly", "waiting", "enforceMinWidth"]);
324
+ const theme = useThemeSafely();
325
+ const buttonStyles = css `
326
+ padding-left: ${theme.controls.padding};
327
+ padding-right: ${theme.controls.padding};
328
+ background-color: white;
329
+ border: ${theme.controls.border};
330
+ border-radius: ${theme.controls.borderRadius};
331
+ cursor: pointer;
332
+ box-shadow: ${theme.controls.boxShadow};
333
+ color: ${theme.colors.font};
334
+ height: ${theme.controls.height};
335
+ transition: ${theme.controls.transition};
336
+ font-size: 1rem;
337
+ font-weight: bold;
338
+ flex-shrink: 0;
339
+ min-width: ${theme.controls.height};
340
+ text-align: ${(_a = props.textAlign) !== null && _a !== void 0 ? _a : 'center'};
341
+
342
+ &:disabled {
343
+ opacity: ${theme.controls.disabledOpacity};
344
+ cursor: not-allowed;
345
+ }
346
+
347
+ &:focus {
348
+ outline: none;
349
+ box-shadow: ${theme.controls.focusOutlineShadow};
350
+ position: relative;
351
+ z-index: 2;
352
+ }
353
+
354
+ &:active {
355
+ box-shadow: none;
356
+ }
357
+
358
+ &:hover:not(:disabled) {
359
+ filter: ${theme.controls.hoverBrightness};
360
+ }
361
+ `;
362
+ const styles = css `
363
+ ${buttonStyles}
364
+ ${props.variant === 'circle' && `
365
+ width: ${theme.controls.height};
366
+ border-radius: 100%;
367
+ display: flex;
368
+ justify-content: center;
369
+ align-items: center;
370
+ ${props.small && `
371
+ width: ${theme.controls.heightSmall};
372
+ min-width: ${theme.controls.heightSmall};
373
+ `}
374
+ `}
375
+ ${props.variant === 'icon' && `
376
+ width: ${theme.controls.height};
377
+ border-radius: 100%;
378
+ padding: 0;
379
+ box-shadow: none;
380
+ border: none;
381
+ font-size: 1.6rem;
382
+ display: flex;
383
+ justify-content: center;
384
+ align-items: center;
385
+ ${props.small && `
386
+ width: ${theme.controls.heightSmall};
387
+ min-width: ${theme.controls.heightSmall};
388
+ font-size: 1.3rem;
389
+ `}
390
+ `}
391
+ ${props.variant === 'label' && `
392
+ display: inline-block;
393
+ width: auto;
394
+ box-shadow: none;
395
+ border: none;
396
+ `}
397
+ ${props.variant === 'link' && `
398
+ padding: 0;
399
+ display: inline-block;
400
+ width: auto;
401
+ box-shadow: none;
402
+ border: none;
403
+ color: ${theme.colors.link};
404
+ font-weight: normal;
405
+ background-color: transparent;
406
+ &:hover {
407
+ text-decoration: underline;
408
+ }
409
+ &:focus {
410
+ box-shadow: none;
411
+ text-decoration: underline;
412
+ }
413
+ `}
414
+ ${props.variant === 'inlineLink' && `
415
+ padding: 0;
416
+ display: inline-block;
417
+ width: auto;
418
+ box-shadow: none;
419
+ border: none;
420
+ color: ${theme.colors.link};
421
+ font-weight: normal;
422
+ height: auto;
423
+ background-color: transparent;
424
+ &:hover {
425
+ text-decoration: underline;
426
+ }
427
+ &:focus {
428
+ box-shadow: none;
429
+ text-decoration: underline;
430
+ }
431
+ `}
432
+ ${props.variant === 'primary' && `
433
+ background-color: ${theme.colors.primary};
434
+ color: ${theme.colors.primaryFont};
435
+ `}
436
+ ${props.variant === 'primary2' && `
437
+ background-color: ${theme.colors.primary2};
438
+ color: ${theme.colors.primary2Font};
439
+ `}
440
+ ${props.variant === 'secondary' && `
441
+ background-color: ${theme.colors.secondary};
442
+ color: ${theme.colors.secondary2Font};
443
+ `}
444
+ ${props.variant === 'omg' && `
445
+ background-color: ${theme.colors.omg};
446
+ color: ${theme.colors.omgFont};
447
+ `}
448
+ ${props.variant === 'positive' && `
449
+ background-color: ${theme.colors.positive};
450
+ color: ${theme.colors.positiveFont};
451
+ `}
452
+ ${props.variant === 'negative' && `
453
+ background-color: ${theme.colors.negative};
454
+ color: ${theme.colors.negativeFont};
455
+ `}
456
+ ${props.enforceMinWidth && `
457
+ min-width: ${theme.controls.formButtonMinWidth};
458
+ `}
459
+ ${props.readonly && `
460
+ cursor: default;
461
+ box-shadow: none;
462
+ pointer-events:none;
463
+
464
+ &:hover {
465
+ filter:none;
466
+ }
467
+
468
+ &:focus {
469
+ box-shadow: none;
470
+ }
471
+ `}
472
+ ${props.small && `
473
+ font-size: 0.8rem;
474
+ height:${theme.controls.heightSmall};
475
+ `}
476
+ ${props.round && `
477
+ border-radius: ${theme.controls.roundRadius};
478
+ `}
479
+ ${props.rounded && `
480
+ border-radius: ${theme.controls.roundedRadius};
481
+ `}
482
+ ${props.block && `
483
+ width: 100%;
484
+ `}
485
+ ${props.iconBlock && `
486
+ display: flex;
487
+ justify-content: space-between;
488
+ align-items: center;
489
+ `}
490
+ `;
491
+ const disabled = props.disabled || props.waiting;
492
+ return (React.createElement("button", Object.assign({}, nativeProps, { disabled: disabled, className: cx('button', styles, props.className), type: (_b = props.type) !== null && _b !== void 0 ? _b : 'button' }),
493
+ props.leftIcon && React.createElement("span", { className: css({ marginRight: '0.5rem' }) }, props.leftIcon),
494
+ props.waiting ? React.createElement(Icon, { id: "waiting", spin: true }) : props.children,
495
+ props.rightIcon && React.createElement("span", { className: css({ marginLeft: '0.5rem' }) }, props.rightIcon)));
496
+ };
497
+
498
+ const DEFAULT_DEBOUNCE_MS = 250;
499
+ const NUMBER_REGEX = /^-?\d+\.?\d*$/;
500
+ const DATE_REGEX = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
501
+ const DEFAULT_MAX_LENGTH = 100;
502
+ const formatLocalValue = (value, type) => {
503
+ let newValue = '';
504
+ if (value !== undefined && value !== null) {
505
+ if (type === 'date' && typeof value === 'number') {
506
+ newValue = format(value, 'MM/dd/yyyy');
507
+ }
508
+ else {
509
+ newValue = value;
510
+ }
511
+ }
512
+ return newValue;
513
+ };
514
+ /** @deprecated Use DateInput, NumberInput, or TextInput instead. */
515
+ const Input = React.forwardRef((props, ref) => {
516
+ var _a, _b, _c;
517
+ const [localValue, setLocalValue] = React.useState(formatLocalValue(props.value, props.type));
518
+ const debounceMs = (_a = props.debounceMs) !== null && _a !== void 0 ? _a : DEFAULT_DEBOUNCE_MS;
519
+ const autoComplete = (_b = props.autoComplete) !== null && _b !== void 0 ? _b : 'off';
520
+ const vars = React.useRef({
521
+ wrappedOnChange: (props.onChange && debounceMs) ? debounce((value, name) => {
522
+ var _a;
523
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value, name);
524
+ }, debounceMs) : undefined,
525
+ focused: false
526
+ });
527
+ const outerOnChange = (_c = vars.current.wrappedOnChange) !== null && _c !== void 0 ? _c : props.onChange;
528
+ const trySyncLocalValue = () => {
529
+ if (vars.current.focused) {
530
+ return;
531
+ }
532
+ if (props.value === localValue) {
533
+ return;
534
+ }
535
+ const newValue = formatLocalValue(props.value, props.type);
536
+ setLocalValue(newValue);
537
+ };
538
+ React.useEffect(() => {
539
+ trySyncLocalValue();
540
+ }, [props.value]);
541
+ const theme = useThemeSafely();
542
+ const inputStyles = css({
543
+ fontFamily: theme.fonts.family,
544
+ fontSize: theme.fonts.size,
545
+ width: '100%',
546
+ border: theme.controls.border,
547
+ borderRadius: theme.controls.borderRadius,
548
+ color: theme.colors.font,
549
+ paddingLeft: theme.controls.padding,
550
+ paddingRight: theme.controls.padding,
551
+ height: theme.controls.height,
552
+ transition: theme.controls.transition,
553
+ ':focus': {
554
+ outline: 'none',
555
+ boxShadow: theme.controls.focusOutlineShadow
556
+ },
557
+ ':disabled': {
558
+ backgroundColor: theme.colors.disabled,
559
+ cursor: 'not-allowed'
560
+ },
561
+ ':invalid': {
562
+ borderColor: theme.colors.required,
563
+ ':focus': {
564
+ boxShadow: theme.controls.focusOutlineRequiredShadow
565
+ }
566
+ },
567
+ }, props.round && props.type !== 'textarea' && {
568
+ borderRadius: theme.controls.roundRadius,
569
+ paddingLeft: `calc(${theme.controls.padding} * 2)`,
570
+ paddingRight: `calc(${theme.controls.padding} * 2)`
571
+ }, props.rounded && {
572
+ borderRadius: theme.controls.roundedRadius
573
+ }, props.readOnly && {
574
+ backgroundColor: 'transparent',
575
+ cursor: 'default',
576
+ border: 'none',
577
+ ':focus': {
578
+ outline: 'none',
579
+ boxShadow: 'none'
580
+ }
581
+ }, props.rightControl && props.type !== 'textarea' && {
582
+ paddingRight: theme.controls.height
583
+ });
584
+ let inputElement;
585
+ const onFocus = (e) => {
586
+ var _a;
587
+ vars.current.focused = true;
588
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
589
+ };
590
+ const onBlur = (e) => {
591
+ var _a;
592
+ vars.current.focused = false;
593
+ trySyncLocalValue();
594
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
595
+ };
596
+ let localOnChange;
597
+ if (props.type === 'number') {
598
+ localOnChange = e => {
599
+ const value = e.target.value;
600
+ if (NUMBER_REGEX.test(value)) {
601
+ let numValue = parseFloat(value);
602
+ if (props.min && numValue < props.min) {
603
+ numValue = props.min;
604
+ }
605
+ if (props.max && numValue > props.max) {
606
+ numValue = props.max;
607
+ }
608
+ setLocalValue(numValue);
609
+ outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(numValue, props.name, e);
610
+ }
611
+ else if (!value) {
612
+ setLocalValue(value);
613
+ outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(undefined, props.name, e);
614
+ }
615
+ };
616
+ }
617
+ else if (props.type === 'date') {
618
+ localOnChange = e => {
619
+ const value = e.target.value;
620
+ setLocalValue(value);
621
+ if (outerOnChange) {
622
+ const dateParts = DATE_REGEX.exec(value);
623
+ if (!dateParts) {
624
+ outerOnChange(undefined, props.name, e);
625
+ }
626
+ else {
627
+ const year = parseInt(dateParts[3], 10);
628
+ const month = parseInt(dateParts[1], 10);
629
+ const day = parseInt(dateParts[2], 10);
630
+ if (isExists(year, month, day)) {
631
+ let ms = new Date(year, month - 1, day).valueOf();
632
+ if (props.min && ms < props.min) {
633
+ ms = props.min;
634
+ }
635
+ if (props.max && ms > props.max) {
636
+ ms = props.max;
637
+ }
638
+ outerOnChange(ms, props.name, e);
639
+ }
640
+ else {
641
+ outerOnChange(undefined, props.name, e);
642
+ }
643
+ }
644
+ }
645
+ };
646
+ }
647
+ else {
648
+ localOnChange = e => {
649
+ const value = e.target.value;
650
+ setLocalValue(value);
651
+ outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(value, props.name, e);
652
+ };
653
+ }
654
+ if (props.type === 'number') {
655
+ inputElement = React.createElement("input", Object.assign({}, props.inputAriaAttributes, { autoFocus: props.autoFocus, ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly,
656
+ // set fixed default to defeat pasting stupid numbers
657
+ maxLength: 50, min: props.min, max: props.max, required: props.required, disabled: props.disabled, id: props.id, className: cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "number", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress }));
658
+ }
659
+ else if (props.type === 'date') {
660
+ inputElement = React.createElement("input", Object.assign({}, props.inputAriaAttributes, { autoFocus: props.autoFocus, ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: 10, required: props.required, disabled: props.disabled, id: props.id, className: cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: "text", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress }));
661
+ }
662
+ else if (props.type === 'textarea') {
663
+ inputElement = React.createElement("textarea", Object.assign({}, props.inputAriaAttributes, { autoFocus: props.autoFocus, ref: ref, name: props.name, style: props.style, rows: props.rows || 10, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, className: cx(css `
664
+ ${inputStyles}
665
+ max-width: 100%;
666
+ min-height: ${theme.controls.height};
667
+ padding-top: 0.75rem;
668
+ height:auto;`, props.inputClassName), placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress }));
669
+ }
670
+ else {
671
+ // text, password, email, and url
672
+ inputElement = React.createElement("input", Object.assign({}, props.inputAriaAttributes, { autoFocus: props.autoFocus, ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, className: cx(inputStyles, props.inputClassName), placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, onKeyPress: props.onKeyPress }));
673
+ }
674
+ const inputWrapperStyles = css `
675
+ width:100%;
676
+ ${props.rightControl && `
677
+ position: relative;
678
+ `}
679
+ `;
680
+ const rightControlStyles = props.rightControl && css `
681
+ position: absolute;
682
+ right: ${theme.controls.padding};
683
+ top: 0;
684
+ bottom: 0;
685
+ display: flex;
686
+ align-items: center;
687
+ ${props.round && `
688
+ right: calc(${theme.controls.padding} * 2);
689
+ `}
690
+ `;
691
+ return (React.createElement("div", { className: cx('input', inputWrapperStyles, props.className) },
692
+ inputElement,
693
+ props.rightControl && props.type !== 'textarea' && React.createElement("div", { className: rightControlStyles }, props.rightControl)));
694
+ });
695
+
696
+ const List = React.forwardRef((props, ref) => {
697
+ const children = props.items ? props.items.map((item, i) => React.createElement(ListItem, { key: i }, item)) : props.children;
698
+ const theme = useThemeSafely();
699
+ const listProps = __rest(props, ["altRowColor", "noLines", "items"]);
700
+ const listStyles = css `
701
+ margin: 0;
702
+ padding: 0;
703
+ list-style-type: none;
704
+ ${props.altRowColor && `
705
+ > .listItem:nth-of-type(even) {
706
+ background-color: ${theme.colors.lightBg};
707
+ }
708
+ `}
709
+ ${props.noLines && `
710
+ > .listItem {
711
+ border-bottom: none;
712
+ }
713
+ `}
714
+ `;
715
+ return (React.createElement("ul", Object.assign({}, listProps, { ref: ref, className: cx('list', listStyles, props.className) }), children));
716
+ });
717
+ const ListItem = (props) => {
718
+ const liProps = __rest(props, ["variant"]);
719
+ const theme = useThemeSafely();
720
+ const itemStyles = css `
721
+ border-bottom: ${theme.controls.border};
722
+ &:last-child {
723
+ border-bottom: none;
724
+ }
725
+ `;
726
+ const contentStyle = css `
727
+ padding: calc(${theme.controls.padding} * 1.5);
728
+ ${props.variant === 'full' && `
729
+ padding:0;
730
+ >.button {
731
+ padding: calc(${theme.controls.padding} * 1.5);
732
+ width: 100%;
733
+ border: none;
734
+ }
735
+ >.omniLink {
736
+ padding-left: calc(${theme.controls.padding} * 1.5);
737
+ padding-right: calc(${theme.controls.padding} * 1.5);
738
+ width: 100%;
739
+ line-height: ${theme.controls.height};
740
+ border: none;
741
+ }
742
+ >.button:not(:focus), >.omniLink:not(:focus) {
743
+ box-shadow: none;
744
+ }
745
+ >.omniLink:not(.omniLink--iconBlock){
746
+ display: block;
747
+ }
748
+ `}
749
+ `;
750
+ return (React.createElement("li", Object.assign({}, liProps, { className: cx('listItem', itemStyles, props.className) }),
751
+ React.createElement("div", { className: css(contentStyle) }, props.children)));
752
+ };
753
+
754
+ const TabLocker = (props) => {
755
+ const tabLocker = React.useRef(null);
756
+ return (React.createElement("div", { className: "tabLocker", style: props.style, ref: tabLocker, onKeyDown: e => {
757
+ var _a, _b;
758
+ if (props.disabled) {
759
+ return;
760
+ }
761
+ if (e.key === 'Tab') {
762
+ e.preventDefault();
763
+ e.stopPropagation();
764
+ const tabElements = Array.from((_b = (_a = tabLocker.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])')) !== null && _b !== void 0 ? _b : []).filter(el => !el.hasAttribute('disabled'));
765
+ if (tabElements.length) {
766
+ const direction = e.shiftKey ? -1 : 1;
767
+ const index = tabElements.findIndex(x => x === document.activeElement);
768
+ if (index === undefined) {
769
+ tabElements[0].focus();
770
+ }
771
+ else if (index === tabElements.length - 1 && direction === 1) {
772
+ tabElements[0].focus();
773
+ }
774
+ else if (index === 0 && direction === -1) {
775
+ tabElements[tabElements.length - 1].focus();
776
+ }
777
+ else {
778
+ tabElements[index + direction].focus();
779
+ }
780
+ }
781
+ }
782
+ } }, props.children));
783
+ };
784
+
785
+ const tagStyles = {
786
+ 'p': {
787
+ marginTop: '1rem',
788
+ marginBottom: '1rem'
789
+ },
790
+ 'h1': {
791
+ fontSize: '2rem',
792
+ },
793
+ 'h2': {
794
+ fontSize: '1.5rem'
795
+ },
796
+ 'h3': {
797
+ fontSize: '1.17rem' // Chrome default
798
+ },
799
+ 'h4': {
800
+ fontSize: '1rem'
801
+ },
802
+ };
803
+ const headerRegex = /h1|h2|h3|h4/;
804
+ const alignStyles = {
805
+ 'center': { textAlign: 'center' },
806
+ 'left': { textAlign: 'left' },
807
+ 'right': { textAlign: 'right' }
808
+ };
809
+ const Text = (props) => {
810
+ var _a, _b;
811
+ const theme = useThemeSafely();
812
+ const tagChoice = props.tag || 'p';
813
+ const style = props.style || {};
814
+ if (props.lineClamp) {
815
+ style.WebkitLineClamp = props.lineClamp;
816
+ }
817
+ if (props.leftPad) {
818
+ style.paddingLeft = props.leftPad;
819
+ }
820
+ const styles = css({
821
+ userSelect: 'text',
822
+ label: 'Text'
823
+ }, tagStyles[tagChoice], alignStyles[(_a = props.align) !== null && _a !== void 0 ? _a : 'left'], props.smaller && { fontSize: theme.fonts.sizeSmall }, props.larger && { fontSize: theme.fonts.sizeLarge }, props.italics && { fontStyle: 'italic' }, props.ellipsis && {
824
+ overflow: 'hidden',
825
+ whiteSpace: 'nowrap',
826
+ textOverflow: 'ellipsis'
827
+ }, props.lineClamp && {
828
+ WebkitBoxOrient: 'vertical',
829
+ overflow: 'hidden',
830
+ textOverflow: 'ellipsis',
831
+ display: '-webkit-box'
832
+ }, props.spacedOut && { lineHeight: '1.5rem' }, props.bold && { fontWeight: 'bold' }, props.noPad && { margin: 0, padding: 0 }, headerRegex.test((_b = props.tag) !== null && _b !== void 0 ? _b : '') && {
833
+ fontFamily: theme.fonts.headerFamily
834
+ });
835
+ return React.createElement(tagChoice, {
836
+ style: style,
837
+ className: cx('text', styles, props.className)
838
+ }, props.children);
839
+ };
840
+
841
+ const DEFAULT_MAX_SHOWN_VALUES = 7;
842
+ const getAutocompleteValueText = (v) => {
843
+ if (!v) {
844
+ return '';
845
+ }
846
+ if (typeof v === 'string') {
847
+ return v;
848
+ }
849
+ return v.name;
850
+ };
851
+ const getAutocompleteValueId = (v) => {
852
+ if (typeof v === 'string') {
853
+ return v;
854
+ }
855
+ return v.id;
856
+ };
857
+ //TB: will need to use the new input
858
+ const Autocomplete = (p) => {
859
+ var _a, _b, _c;
860
+ const element = React.useRef(null);
861
+ const input = React.useRef(null);
862
+ const list = React.useRef(null);
863
+ const [values, setValues] = React.useState([]);
864
+ const showValues = React.useMemo(() => values.length > 0, [values]);
865
+ const maxShowValues = (_a = p.maxShownValues) !== null && _a !== void 0 ? _a : DEFAULT_MAX_SHOWN_VALUES;
866
+ const shownValues = React.useMemo(() => {
867
+ if (!p.allowScroll) {
868
+ //TB:normalize this value and use it below for list building
869
+ return values.slice(0, maxShowValues);
870
+ }
871
+ return values.slice();
872
+ }, [values]);
873
+ const onChangeForOptions = React.useRef(debounce((value) => {
874
+ if (!p.minChars || value.length >= p.minChars) {
875
+ p.getOptions(value)
876
+ .then(vals => {
877
+ setValues(vals);
878
+ }).catch(err => {
879
+ // ignore it
880
+ });
881
+ }
882
+ else {
883
+ setValues([]);
884
+ }
885
+ }, (_b = p.getOptionsDebounceMs) !== null && _b !== void 0 ? _b : 0, (_c = p.debounceOptions) !== null && _c !== void 0 ? _c : { leading: true, trailing: true }));
886
+ const theme = useThemeSafely();
887
+ const baseClass = css `
888
+ label: Autocomplete;
889
+ position: relative;
890
+ width: 100%;
891
+ `;
892
+ let listBorderRadius = '';
893
+ if (p.round || p.rounded || theme.controls.borderRadius) {
894
+ listBorderRadius = theme.controls.borderRadius || '0.5rem';
895
+ }
896
+ const listClass = css({
897
+ position: 'absolute',
898
+ width: '100%',
899
+ border: theme.controls.border,
900
+ borderRadius: listBorderRadius,
901
+ boxShadow: theme.controls.boxShadow,
902
+ backgroundColor: theme.colors.bg,
903
+ color: theme.colors.font,
904
+ marginTop: `-4px !important`,
905
+ zIndex: theme.zIndexes.backdrop,
906
+ 'li:first-child button': {
907
+ borderTopRightRadius: listBorderRadius,
908
+ borderTopLeftRadius: listBorderRadius,
909
+ },
910
+ 'li:last-child button': {
911
+ borderBottomRightRadius: listBorderRadius,
912
+ borderBottomLeftRadius: listBorderRadius,
913
+ },
914
+ });
915
+ const inputClass = css `
916
+ ${showValues && `
917
+ z-index: ${theme.zIndexes.backdrop};
918
+ position: relative;
919
+ `}
920
+ `;
921
+ const buttonStyles = css({
922
+ borderRadius: 0,
923
+ });
924
+ const buttonMarkerClass = 'ListItem__button';
925
+ const getNextTabElement = (fromIndex, direction) => {
926
+ var _a, _b, _c;
927
+ if (fromIndex === -1) {
928
+ let buttonIndex = 0;
929
+ if (direction === -1) {
930
+ buttonIndex = shownValues.length - 1;
931
+ }
932
+ return (_a = list.current) === null || _a === void 0 ? void 0 : _a.querySelector(`.${buttonMarkerClass}${buttonIndex}`);
933
+ }
934
+ else {
935
+ const nextIndex = fromIndex + direction;
936
+ if (nextIndex >= shownValues.length || nextIndex < 0) {
937
+ return (_b = input.current) !== null && _b !== void 0 ? _b : undefined;
938
+ }
939
+ else {
940
+ return (_c = list.current) === null || _c === void 0 ? void 0 : _c.querySelector(`.${buttonMarkerClass}${nextIndex}`);
941
+ }
942
+ }
943
+ };
944
+ return (React.createElement("div", { ref: element, className: cx(baseClass, 'autocomplete') },
945
+ React.createElement(Backdrop$1, { onClick: () => setValues([]), show: showValues, allowScroll: true, transparent: true }),
946
+ React.createElement(TabLocker, { disabled: !showValues, style: { position: 'relative' } },
947
+ React.createElement(Input, { inputAriaAttributes: p.inputAriaAttributes, ref: input, debounceMs: 0, type: "text", value: getAutocompleteValueText(p.value), round: p.round, rounded: p.rounded, rightControl: p.rightControl, placeholder: p.placeholder, id: p.id, disabled: p.disabled, className: p.className, inputClassName: cx(inputClass, p.inputClassName), maxLength: p.maxLength, required: p.required, onChange: v => {
948
+ const value = v;
949
+ p.onChange(value);
950
+ onChangeForOptions.current(value);
951
+ }, onKeyDown: e => {
952
+ var _a, _b;
953
+ if (showValues) {
954
+ if (e.key === 'ArrowDown') {
955
+ e.preventDefault();
956
+ e.stopPropagation();
957
+ (_a = getNextTabElement(-1, 1)) === null || _a === void 0 ? void 0 : _a.focus();
958
+ }
959
+ else if (e.key === 'ArrowUp') {
960
+ e.preventDefault();
961
+ e.stopPropagation();
962
+ (_b = getNextTabElement(-1, -1)) === null || _b === void 0 ? void 0 : _b.focus();
963
+ }
964
+ }
965
+ }, onKeyPress: e => { var _a; return (_a = p.onKeyPress) === null || _a === void 0 ? void 0 : _a.call(p, e); } }),
966
+ showValues && (React.createElement(List, { ref: list, className: cx(listClass, p.allowScroll && shownValues.length > maxShowValues && css({
967
+ overflowY: 'scroll',
968
+ maxHeight: `calc(${theme.controls.height} * ${maxShowValues})`
969
+ })) },
970
+ shownValues.map((value, listItemIndex) => {
971
+ return (React.createElement(ListItem, { key: getAutocompleteValueId(value), variant: "full" },
972
+ React.createElement(Button, { onKeyDown: e => {
973
+ var _a, _b;
974
+ if (e.key === 'ArrowDown') {
975
+ e.stopPropagation();
976
+ e.preventDefault();
977
+ (_a = getNextTabElement(listItemIndex, 1)) === null || _a === void 0 ? void 0 : _a.focus();
978
+ }
979
+ else if (e.key === 'ArrowUp') {
980
+ e.stopPropagation();
981
+ e.preventDefault();
982
+ (_b = getNextTabElement(listItemIndex, -1)) === null || _b === void 0 ? void 0 : _b.focus();
983
+ }
984
+ }, className: cx(buttonMarkerClass + listItemIndex, buttonStyles), onClick: () => {
985
+ p.onPick(value);
986
+ setValues([]);
987
+ setTimeout(() => {
988
+ var _a;
989
+ // we need to wait until the component is re-rendered.
990
+ // outside changes to Inputs will be ignored if the component has focus.
991
+ (_a = input.current) === null || _a === void 0 ? void 0 : _a.focus();
992
+ }, 0);
993
+ } },
994
+ React.createElement(Text, { tag: "div", ellipsis: true, align: "left" }, getAutocompleteValueText(value)))));
995
+ }),
996
+ !p.allowScroll && shownValues.length < values.length && (React.createElement(ListItem, null,
997
+ React.createElement(Text, { tag: "div", italics: true, align: "center" },
998
+ "Showing ",
999
+ shownValues.length.toLocaleString(),
1000
+ " of ",
1001
+ values.length.toLocaleString(),
1002
+ " results."))))))));
1003
+ };
1004
+
1005
+ const useLogger = (componentName, enabled) => {
1006
+ return (...messages) => {
1007
+ if (enabled) {
1008
+ // tslint:disable-next-line
1009
+ console.log(componentName, ...messages);
1010
+ }
1011
+ };
1012
+ };
1013
+
1014
+ const BackdropContext = React__default.createContext({
1015
+ showing: false,
1016
+ showCount: 0,
1017
+ portalId: 'backdrop',
1018
+ setShow: s => {
1019
+ /* empty */
1020
+ }
1021
+ });
1022
+ const BackdropContextProvider = (p) => {
1023
+ var _a;
1024
+ const [showCount, setShowCount] = useState(0);
1025
+ const log = useLogger('BackdropContextProvider', (_a = p.debug) !== null && _a !== void 0 ? _a : false);
1026
+ if (p.debug) {
1027
+ useEffect(() => {
1028
+ log('mounted');
1029
+ return () => {
1030
+ log('un-mounted');
1031
+ };
1032
+ }, []);
1033
+ useEffect(() => {
1034
+ log('showCount changed', showCount);
1035
+ }, [showCount]);
1036
+ }
1037
+ return (React__default.createElement(BackdropContext.Provider, { value: {
1038
+ portalId: 'backdrop',
1039
+ showing: showCount > 0,
1040
+ showCount: showCount,
1041
+ setShow: (show) => {
1042
+ if (show) {
1043
+ setShowCount(s => {
1044
+ const count = s + 1;
1045
+ log('setShowCount', count);
1046
+ log('showCount was', showCount);
1047
+ return count;
1048
+ });
1049
+ }
1050
+ else {
1051
+ setShowCount(s => {
1052
+ const count = Math.max(0, s - 1);
1053
+ log('setShowCount', count);
1054
+ log('showCount was', showCount);
1055
+ return count;
1056
+ });
1057
+ }
1058
+ }
1059
+ } },
1060
+ p.children,
1061
+ p.debug && (React__default.createElement("p", { className: css({
1062
+ position: 'fixed',
1063
+ top: 0, right: 0,
1064
+ backgroundColor: '#ff00004f',
1065
+ color: 'white',
1066
+ padding: '0.5rem',
1067
+ margin: 0,
1068
+ zIndex: 9999
1069
+ }) },
1070
+ "Backdrop showCount: ",
1071
+ showCount))));
1072
+ };
1073
+ const BackdropOverlay = (p) => {
1074
+ var _a, _b;
1075
+ const context = useContext(BackdropContext);
1076
+ const theme = useThemeSafely();
1077
+ const showTimeMs = (_a = p.showTimeMs) !== null && _a !== void 0 ? _a : 250;
1078
+ const log = useLogger('BackdropOverlay', (_b = p.debug) !== null && _b !== void 0 ? _b : false);
1079
+ if (p.debug) {
1080
+ useEffect(() => {
1081
+ log('mounted');
1082
+ return () => {
1083
+ log('unmounted');
1084
+ };
1085
+ }, []);
1086
+ useEffect(() => {
1087
+ log('context.showing changed', context.showing);
1088
+ }, [context.showing]);
1089
+ }
1090
+ return (React__default.createElement("div", { onClick: () => {
1091
+ context === null || context === void 0 ? void 0 : context.setShow(false);
1092
+ log('onClick', 'setShow', false);
1093
+ }, id: context === null || context === void 0 ? void 0 : context.portalId, className: css({
1094
+ cursor: 'pointer',
1095
+ position: 'fixed',
1096
+ top: 0, right: 0, bottom: 0, left: 0,
1097
+ backgroundColor: theme.colors.backdrop,
1098
+ zIndex: (context === null || context === void 0 ? void 0 : context.showing) ? theme.zIndexes.backdrop : -1,
1099
+ visibility: (context === null || context === void 0 ? void 0 : context.showing) ? 'visible' : 'hidden',
1100
+ opacity: (context === null || context === void 0 ? void 0 : context.showing) ? 1 : 0,
1101
+ transition: `opacity ${showTimeMs}ms ease-in-out`,
1102
+ userSelect: 'none',
1103
+ WebkitTapHighlightColor: 'transparent'
1104
+ }) }));
1105
+ };
1106
+ const Backdrop = (p) => {
1107
+ return (React__default.createElement(BackdropContextProvider, { debug: p.debug },
1108
+ React__default.createElement("div", { className: css({
1109
+ height: '100%'
1110
+ }) },
1111
+ p.children,
1112
+ React__default.createElement(BackdropOverlay, { showTimeMs: p.showTimeMs, debug: p.debug }))));
1113
+ };
1114
+
1115
+ const Calendar = (p) => {
1116
+ var _a, _b, _c, _d;
1117
+ const theme = useThemeSafely();
1118
+ const cellSize = (_a = p.cellSize) !== null && _a !== void 0 ? _a : '3rem';
1119
+ const showTitle = (_b = p.title) !== null && _b !== void 0 ? _b : true;
1120
+ const calendarStyles = css({
1121
+ display: 'grid',
1122
+ gridTemplateColumns: `repeat(7, ${cellSize})`,
1123
+ });
1124
+ const cellStyles = css({
1125
+ border: 'none',
1126
+ backgroundColor: 'transparent',
1127
+ fontFamily: theme.fonts.family,
1128
+ fontSize: theme.fonts.size,
1129
+ color: theme.colors.font,
1130
+ display: 'flex',
1131
+ alignItems: 'center',
1132
+ justifyContent: 'center',
1133
+ borderTop: theme.controls.border,
1134
+ borderLeft: theme.controls.border,
1135
+ width: cellSize,
1136
+ height: cellSize
1137
+ });
1138
+ const rightCellStyles = css({
1139
+ borderRight: theme.controls.border
1140
+ });
1141
+ const bottomCellStyles = css({
1142
+ borderBottom: theme.controls.border
1143
+ });
1144
+ const nonDayStyles = css({
1145
+ backgroundColor: theme.colors.disabled
1146
+ });
1147
+ const clickableStyles = css({
1148
+ cursor: 'pointer',
1149
+ ':focus': {
1150
+ outline: 'none',
1151
+ boxShadow: theme.controls.focusOutlineShadow,
1152
+ position: 'relative',
1153
+ zIndex: 2
1154
+ },
1155
+ ":active": {
1156
+ boxShadow: 'none'
1157
+ },
1158
+ ":hover": {
1159
+ backgroundColor: theme.colors.lightBg,
1160
+ color: theme.colors.font,
1161
+ }
1162
+ });
1163
+ const monthStart = new Date(p.year, p.month - 1, 1);
1164
+ const days = getDaysInMonth(monthStart);
1165
+ const startDayOfWeek = getDay(monthStart);
1166
+ const dayEndIndex = startDayOfWeek + days - 1;
1167
+ const cellCount = p.fixedRows ? 42 : Math.ceil((days + startDayOfWeek) / 7) * 7;
1168
+ const bottomRowStartIndex = cellCount - 7;
1169
+ const currentDate = p.showCurrent ? new Date() : undefined;
1170
+ const selectedDate = p.selectedValue && isSameMonth(p.selectedValue, monthStart) ? new Date(p.selectedValue) : undefined;
1171
+ const cells = [];
1172
+ for (let i = 0; i < cellCount; i++) {
1173
+ const dayOfMonth = i >= startDayOfWeek && i <= dayEndIndex ? i - startDayOfWeek + 1 : undefined;
1174
+ const cellDate = dayOfMonth ? new Date(p.year, p.month - 1, dayOfMonth) : undefined;
1175
+ let canInteract = !!cellDate;
1176
+ if (p.min && isBefore(cellDate !== null && cellDate !== void 0 ? cellDate : 0, p.min)) {
1177
+ canInteract = false;
1178
+ }
1179
+ if (p.max && isAfter(cellDate !== null && cellDate !== void 0 ? cellDate : 0, p.max)) {
1180
+ canInteract = false;
1181
+ }
1182
+ if (cellDate && p.onClick && ((_c = p.isCellDisabled) === null || _c === void 0 ? void 0 : _c.call(p, cellDate))) {
1183
+ canInteract = false;
1184
+ }
1185
+ const styles = css(cellStyles, (i + 1) % 7 === 0 && rightCellStyles, i >= bottomRowStartIndex && bottomCellStyles, !canInteract && nonDayStyles, currentDate && cellDate && isSameDay(currentDate, cellDate) && { fontWeight: 'bold' }, selectedDate && cellDate && isSameDay(selectedDate, cellDate) && { backgroundColor: theme.colors.primary, color: theme.colors.primaryFont }, canInteract && p.onClick && clickableStyles);
1186
+ const onClick = canInteract && p.onClick ? () => {
1187
+ var _a;
1188
+ if (cellDate) {
1189
+ (_a = p.onClick) === null || _a === void 0 ? void 0 : _a.call(p, cellDate);
1190
+ }
1191
+ } : undefined;
1192
+ const cellContent = cellDate && (p.renderCell ? p.renderCell(cellDate) : cellDate.getDate());
1193
+ const cell = onClick ? (React.createElement("button", { type: "button", key: i, className: styles, onClick: onClick }, cellContent)) : (React.createElement("div", { key: i, className: styles }, cellContent));
1194
+ cells.push(cell);
1195
+ }
1196
+ return (React.createElement("div", { id: p.id, className: "calendar" },
1197
+ showTitle && ((_d = p.customTitle) !== null && _d !== void 0 ? _d : React.createElement(Text, { larger: true, align: "center" },
1198
+ format(monthStart, 'LLLL'),
1199
+ p.yearInTitle && ` ${p.year}`)),
1200
+ React.createElement("div", { className: calendarStyles },
1201
+ ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => {
1202
+ return (React.createElement(Text, { style: { paddingBottom: '0.25rem' }, key: day, smaller: p.smallHeader, noPad: true, align: "center" }, day));
1203
+ }),
1204
+ cells)));
1205
+ };
1206
+
1207
+ const Checkbox = (props) => {
1208
+ const inputProps = __rest(props, ["checked", "onChange", "label", "checkedIcon", "uncheckedIcon", "checkedThemeColor", "checkedColor", "readonly"]);
1209
+ const selected = props.checkedIcon || 'selected';
1210
+ const unselected = props.uncheckedIcon || 'unselected';
1211
+ const theme = useThemeSafely();
1212
+ let finalCheckedColor;
1213
+ if (props.checked) {
1214
+ if (props.checkedThemeColor) {
1215
+ finalCheckedColor = theme.colors[props.checkedThemeColor];
1216
+ }
1217
+ else {
1218
+ finalCheckedColor = props.checkedColor;
1219
+ }
1220
+ }
1221
+ const checkboxStyles = css `
1222
+ display: inline-block;
1223
+ ${!props.disabled && !props.readonly && `
1224
+ &:hover {
1225
+ filter: ${theme.controls.hoverBrightness};
1226
+ }
1227
+ `}
1228
+ `;
1229
+ const labelStyles = css `
1230
+ cursor: pointer;
1231
+ user-select: none;
1232
+ display: flex;
1233
+ align-items: center;
1234
+ ${props.disabled && `
1235
+ cursor: not-allowed;
1236
+ `}
1237
+ ${props.readonly && `
1238
+ cursor: default;
1239
+ `}
1240
+ `;
1241
+ // had to reference a marker class ('checkboxIcon') here for the sibling selector to work.
1242
+ // opacity: 0 required for firefox. ignores the width of 0.
1243
+ const nativeCheckboxStyles = css `
1244
+ margin: 0;
1245
+ padding: 0;
1246
+ width: 0;
1247
+ opacity: 0;
1248
+
1249
+ ${!props.readonly && `
1250
+ &:focus + .checkboxIcon {
1251
+ box-shadow: ${theme.controls.focusOutlineShadow};
1252
+ }
1253
+ `}
1254
+ `;
1255
+ const iconStyles = css `
1256
+ ${!!props.label && `
1257
+ margin-right: 0.5rem;
1258
+ `}
1259
+ ${props.disabled && `
1260
+ background-color: ${theme.colors.disabled};
1261
+ cursor: not-allowed;
1262
+ `}
1263
+ ${props.readonly && `
1264
+ cursor: default;
1265
+ `}
1266
+ ${props.checked && `
1267
+ color: ${finalCheckedColor}
1268
+ `}
1269
+ `;
1270
+ return (React.createElement("span", { className: cx('checkbox', checkboxStyles, props.className) },
1271
+ React.createElement("label", { className: labelStyles },
1272
+ React.createElement("input", Object.assign({}, inputProps, { tabIndex: props.readonly ? -1 : undefined, className: nativeCheckboxStyles, type: "checkbox", onChange: e => {
1273
+ if (props.readonly) {
1274
+ e.preventDefault();
1275
+ return;
1276
+ }
1277
+ return props.onChange(e.currentTarget.checked, e);
1278
+ } })),
1279
+ React.createElement(Icon, { className: cx('checkboxIcon', iconStyles), id: props.checked ? selected : unselected }),
1280
+ props.label,
1281
+ props.children)));
1282
+ };
1283
+
1284
+ // Taken from: https://github.com/react-bootstrap/dom-helpers/blob/master/src/scrollbarSize.ts
1285
+ const canUseDom = !!(typeof window !== 'undefined' &&
1286
+ window.document &&
1287
+ window.document.createElement);
1288
+ let size;
1289
+ const useScrollbarSize = (recalc) => {
1290
+ if ((!size && size !== 0) || recalc) {
1291
+ if (canUseDom) {
1292
+ const scrollDiv = document.createElement('div');
1293
+ scrollDiv.style.position = 'absolute';
1294
+ scrollDiv.style.top = '-9999px';
1295
+ scrollDiv.style.width = '50px';
1296
+ scrollDiv.style.height = '50px';
1297
+ scrollDiv.style.overflow = 'scroll';
1298
+ document.body.appendChild(scrollDiv);
1299
+ size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
1300
+ document.body.removeChild(scrollDiv);
1301
+ }
1302
+ }
1303
+ return size;
1304
+ };
1305
+
1306
+ let htmlBodyStyles;
1307
+ const Modal = (p) => {
1308
+ var _a, _b, _c, _d;
1309
+ const backdrop = useContext(BackdropContext);
1310
+ const mouseDownElement = useRef(undefined);
1311
+ const theme = useThemeSafely();
1312
+ const hasHeader = p.closeButton || p.heading;
1313
+ const contentRef = React__default.useRef(null);
1314
+ const log = useLogger(`Modal ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.debug) !== null && _b !== void 0 ? _b : false);
1315
+ const showing = useRef(p.show);
1316
+ useEffect(() => {
1317
+ log('mounted');
1318
+ return () => {
1319
+ // handle the use of modals that are rendered only as show=true and then unmounted.
1320
+ backdrop.setShow(false);
1321
+ log('backdrop.setShow', false);
1322
+ if (showing.current && backdrop.showCount <= 1 && htmlBodyStyles) {
1323
+ log('backdrop.showCount', backdrop.showCount, 'removing htmlBodyStyles');
1324
+ document.body.classList.remove(htmlBodyStyles);
1325
+ }
1326
+ log('un-mounted');
1327
+ };
1328
+ }, []);
1329
+ useEffect(() => {
1330
+ log('show changed', p.show);
1331
+ backdrop.setShow(p.show);
1332
+ showing.current = p.show;
1333
+ log('backdrop.setShow', true);
1334
+ if (!htmlBodyStyles) {
1335
+ log('creating singleton htmlBodyStyles');
1336
+ htmlBodyStyles = css({
1337
+ label: 'ModalBodyOverrides',
1338
+ overflow: 'hidden',
1339
+ paddingRight: `${useScrollbarSize()}px`
1340
+ });
1341
+ }
1342
+ if (p.show) {
1343
+ log('adding htmlBodyStyles');
1344
+ document.body.classList.add(htmlBodyStyles);
1345
+ }
1346
+ else {
1347
+ if (backdrop.showCount <= 1) {
1348
+ log('backdrop.showCount', backdrop.showCount, 'removing htmlBodyStyles');
1349
+ document.body.classList.remove(htmlBodyStyles);
1350
+ }
1351
+ }
1352
+ }, [p.show]);
1353
+ React__default.useLayoutEffect(() => {
1354
+ var _a;
1355
+ if (p.show === true) {
1356
+ const focusSelector = (_a = p.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
1357
+ // still need to wait for the next tick so the children are all rendered.
1358
+ setTimeout(() => {
1359
+ var _a;
1360
+ const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
1361
+ element === null || element === void 0 ? void 0 : element.focus();
1362
+ log('set focus', focusSelector);
1363
+ });
1364
+ }
1365
+ }, [p.show]);
1366
+ const modalBodyStyles = css({
1367
+ zIndex: theme.zIndexes.modal,
1368
+ cursor: 'default',
1369
+ margin: '1rem',
1370
+ backgroundColor: p.noBackground ? undefined : theme.colors.modalBg,
1371
+ border: p.noBackground ? undefined : theme.controls.border,
1372
+ boxShadow: p.noBackground ? undefined : theme.controls.boxShadow,
1373
+ maxWidth: (_c = p.maxWidth) !== null && _c !== void 0 ? _c : theme.breakpoints.tablet,
1374
+ minWidth: (_d = p.minWidth) !== null && _d !== void 0 ? _d : (hasHeader ? '250px' : undefined),
1375
+ opacity: p.show ? 1 : 0,
1376
+ fontSize: theme.fonts.size,
1377
+ fontFamily: theme.fonts.family,
1378
+ fontWeight: 'normal',
1379
+ '&:focus': {
1380
+ outline: 'none'
1381
+ }
1382
+ });
1383
+ const modalHeaderStyles = css({
1384
+ display: 'flex',
1385
+ justifyContent: 'space-between',
1386
+ alignItems: 'center',
1387
+ backgroundColor: theme.colors.header,
1388
+ padding: '1rem',
1389
+ color: theme.colors.headerFont
1390
+ });
1391
+ const modalContainerStyles = css([{
1392
+ position: 'fixed',
1393
+ height: '100%',
1394
+ width: '100%',
1395
+ backgroundColor: "transparent",
1396
+ display: 'flex',
1397
+ justifyContent: 'center',
1398
+ alignItems: 'center',
1399
+ cursor: p.onClick ? 'pointer' : 'default'
1400
+ }, p.scrollable && {
1401
+ overflowY: 'auto',
1402
+ overflowX: 'hidden',
1403
+ alignItems: 'flex-start'
1404
+ }]);
1405
+ if (p.show) {
1406
+ const backdropContainer = document.getElementById(backdrop.portalId);
1407
+ if (backdropContainer) {
1408
+ return createPortal((React__default.createElement("div", { onClick: e => {
1409
+ e.stopPropagation();
1410
+ if (!mouseDownElement.current) {
1411
+ if (p.onClick) {
1412
+ log('backdropContainer onClick');
1413
+ p.onClick();
1414
+ }
1415
+ }
1416
+ mouseDownElement.current = undefined;
1417
+ }, className: cx('modalContainer', modalContainerStyles) },
1418
+ React__default.createElement("div", { id: p.id, ref: contentRef, onClick: e => e.stopPropagation(), onMouseDown: e => {
1419
+ mouseDownElement.current = e.target;
1420
+ e.stopPropagation();
1421
+ }, onMouseUp: e => {
1422
+ mouseDownElement.current = undefined;
1423
+ e.stopPropagation();
1424
+ }, className: cx('modalBody', modalBodyStyles, p.className) },
1425
+ React__default.createElement(TabLocker, null,
1426
+ hasHeader && (React__default.createElement("header", { className: cx('modalHeader', modalHeaderStyles) },
1427
+ p.heading ? React__default.createElement(Text, { className: css({
1428
+ margin: 0,
1429
+ flexGrow: 1
1430
+ }), tag: "h1", bold: true }, p.heading) : React__default.createElement("span", null),
1431
+ p.closeButton && p.onClick ? React__default.createElement(Button, { className: cx('modalCloseButton', css({
1432
+ color: theme.colors.headerFont,
1433
+ marginLeft: '1rem',
1434
+ backgroundColor: 'transparent'
1435
+ })), variant: "icon", onClick: p.onClick },
1436
+ React__default.createElement(Icon, { id: "close" })) : React__default.createElement("span", null))),
1437
+ p.children)))), backdropContainer);
1438
+ }
1439
+ }
1440
+ return null;
1441
+ };
1442
+
1443
+ const ConfirmModal = (props) => {
1444
+ const theme = useThemeSafely();
1445
+ const modalStyle = css `
1446
+ ${props.variant === 'omg' && `
1447
+ .modalHeader {
1448
+ background-color:${theme.colors.omg};
1449
+ color:${theme.colors.omgFont};
1450
+ }
1451
+ `}
1452
+ `;
1453
+ return (React.createElement(Modal, { id: props.id, debug: props.debug, className: cx('confirmModal', modalStyle, props.className), heading: props.header, closeButton: true, show: props.show, onClick: props.onCancel },
1454
+ React.createElement("div", { className: css({ padding: '1rem' }) },
1455
+ React.createElement(Text, { align: "center" }, props.text),
1456
+ React.createElement("div", { className: css({ textAlign: 'center' }) },
1457
+ React.createElement(Button, { className: css({ margin: '0 0.5rem' }), enforceMinWidth: true, variant: props.variant === 'omg' ? "omg" : 'primary2', onClick: props.onConfirm }, props.confirmText || 'OK'),
1458
+ React.createElement(Button, { className: css({ margin: '0 0.5rem' }), enforceMinWidth: true, onClick: props.onCancel }, props.cancelText || 'Cancel')))));
1459
+ };
1460
+
1461
+ const CopyButton = (props) => {
1462
+ const [copied, setCopied] = React.useState(false);
1463
+ return (React.createElement(Button, { title: copied ? 'Copied!' : (props.title || 'Copy to clipboard'), variant: "icon", onBlur: () => {
1464
+ setCopied(false);
1465
+ }, onClick: e => {
1466
+ const button = e.currentTarget;
1467
+ let copySuccess = false;
1468
+ try {
1469
+ const text = document.querySelector(props.selector);
1470
+ text.select();
1471
+ copySuccess = document.execCommand('copy');
1472
+ // the input gets focus on select. bring it back.
1473
+ button.focus();
1474
+ }
1475
+ catch (err) {
1476
+ // You done wrong.
1477
+ }
1478
+ setCopied(copySuccess);
1479
+ } },
1480
+ React.createElement(Icon, { id: copied ? 'paste' : 'copy' })));
1481
+ };
1482
+
1483
+ const Popover = (p) => {
1484
+ var _a, _b;
1485
+ const theme = useThemeSafely();
1486
+ const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
1487
+ return (React.createElement(Popover$1, { containerClassName: css({
1488
+ zIndex: theme.zIndexes.tooltip
1489
+ }), reposition: resposition, isOpen: p.isOpen, positions: (_b = p.positions) !== null && _b !== void 0 ? _b : ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
1490
+ var _a, _b, _c, _d;
1491
+ return (React.createElement(ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
1492
+ React.createElement(TabLocker, null,
1493
+ React.createElement("div", { className: css({
1494
+ border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
1495
+ borderRadius: (_c = p.border) !== null && _c !== void 0 ? _c : theme.controls.borderRadius,
1496
+ boxShadow: theme.controls.boxShadow,
1497
+ backgroundColor: (_d = p.backgroundColor) !== null && _d !== void 0 ? _d : theme.colors.bg,
1498
+ }) }, p.content))));
1499
+ } },
1500
+ React.createElement("span", null, p.parent)));
1501
+ };
1502
+
1503
+ const getCalendarDate = (date, min, max) => {
1504
+ let calendarDate = date ? new Date(date) : new Date();
1505
+ // if there is a min/max we don't want the calendar to open to the current date if it's out of range
1506
+ if (min && isBefore(calendarDate, min)) {
1507
+ calendarDate = new Date(min);
1508
+ }
1509
+ else if (max && isAfter(calendarDate, max)) {
1510
+ calendarDate = new Date(max);
1511
+ }
1512
+ return calendarDate;
1513
+ };
1514
+ const DatePicker = (p) => {
1515
+ const [showCalendar, setShowCalendar] = React.useState(false);
1516
+ const [calendarDate, setCalendarDate] = React.useState(getCalendarDate(p.value, p.min, p.max));
1517
+ // controls the one-time focus set on show
1518
+ const needsFocus = React.useRef(false);
1519
+ const popover = React.useRef(null);
1520
+ React.useEffect(() => {
1521
+ var _a;
1522
+ setCalendarDate(getCalendarDate((_a = p.value) !== null && _a !== void 0 ? _a : 0, p.min, p.max));
1523
+ }, [p.value]);
1524
+ React.useLayoutEffect(() => {
1525
+ var _a, _b;
1526
+ if (needsFocus.current) {
1527
+ (_b = (_a = popover.current) === null || _a === void 0 ? void 0 : _a.querySelector('button')) === null || _b === void 0 ? void 0 : _b.focus();
1528
+ needsFocus.current = false;
1529
+ }
1530
+ });
1531
+ //TB: replace with new inputs
1532
+ return (React.createElement(Popover, { reposition: p.reposition, isOpen: showCalendar, onClickOutside: () => {
1533
+ needsFocus.current = false;
1534
+ setShowCalendar(false);
1535
+ }, parent: (React.createElement(Input, Object.assign({ onFocus: () => {
1536
+ needsFocus.current = false;
1537
+ setShowCalendar(false);
1538
+ }, placeholder: 'MM/DD/YYYY' }, p, { type: "date", rightControl: !p.readOnly ? (React.createElement(Button, { variant: "icon", readonly: p.readOnly, disabled: p.disabled, small: true, style: {
1539
+ fontSize: '1rem'
1540
+ }, onClick: () => {
1541
+ needsFocus.current = !showCalendar;
1542
+ setShowCalendar(!showCalendar);
1543
+ } },
1544
+ React.createElement(Icon, { id: "pickDate" }))) : undefined, onChange: v => {
1545
+ p.onChange(v);
1546
+ } }))), content: (React.createElement("div", { ref: popover, className: css({
1547
+ paddingLeft: '1rem',
1548
+ paddingRight: '1rem',
1549
+ paddingBottom: '1rem'
1550
+ }) },
1551
+ React.createElement(Calendar, { onClick: date => {
1552
+ p.onChange(date.valueOf());
1553
+ needsFocus.current = false;
1554
+ setShowCalendar(false);
1555
+ }, customTitle: React.createElement("div", { className: css({
1556
+ display: 'flex',
1557
+ justifyContent: 'space-between',
1558
+ alignItems: 'center'
1559
+ }) },
1560
+ React.createElement(Button, { disabled: !!p.min && isBefore(endOfMonth(addMonths(calendarDate, -1)), p.min), small: true, variant: "icon", onClick: () => setCalendarDate(addMonths(calendarDate, -1)) },
1561
+ React.createElement(Icon, { id: "pagerLeft" })),
1562
+ React.createElement(Text, { align: "center" },
1563
+ format(calendarDate, 'LLLL'),
1564
+ " ",
1565
+ calendarDate.getFullYear()),
1566
+ React.createElement(Button, { disabled: !!p.max && isAfter(startOfMonth(addMonths(calendarDate, 1)), p.max), small: true, variant: "icon", onClick: () => setCalendarDate(addMonths(calendarDate, 1)) },
1567
+ React.createElement(Icon, { id: "pagerRight" }))), month: calendarDate.getMonth() + 1, year: calendarDate.getFullYear(), showCurrent: true, smallHeader: true, selectedValue: p.value, cellSize: '2rem', min: p.min, max: p.max }))) }));
1568
+ };
1569
+
1570
+ const Divider = () => {
1571
+ const theme = useThemeSafely();
1572
+ return (React.createElement("hr", { className: cx("divider", css({
1573
+ margin: theme.controls.dividerMargin,
1574
+ border: theme.controls.dividerBorder
1575
+ })) }));
1576
+ };
1577
+
1578
+ const ErrorModal = (props) => {
1579
+ const { message } = props;
1580
+ const theme = useThemeSafely();
1581
+ const modalStyles = css `
1582
+ .modalHeader {
1583
+ background-color: ${theme.colors.omg};
1584
+ color: ${theme.colors.omgFont};
1585
+ }
1586
+ .modalCloseButton {
1587
+ color: ${theme.colors.omgFont};
1588
+ }
1589
+ `;
1590
+ return (React.createElement(Modal, { id: props.id, debug: props.debug, className: cx('errorModal', modalStyles), heading: "Error", closeButton: true, show: props.show, onClick: props.close },
1591
+ React.createElement("div", { className: css({ padding: '1rem' }) },
1592
+ React.createElement(Text, { align: "center" }, message))));
1593
+ };
1594
+
1595
+ /** Use this instead of <form> directly. If we need to fight Chrome's autofill, we can do so at a global level. */
1596
+ const Form = React.forwardRef((props, ref) => {
1597
+ const { inline, children, onSubmit, className, ajax } = props, rest = __rest(props, ["inline", "children", "onSubmit", "className", "ajax"]);
1598
+ const theme = useThemeSafely();
1599
+ return (React.createElement("form", Object.assign({}, rest, { ref: ref, className: cx('form', css({
1600
+ display: 'flex',
1601
+ flexDirection: props.inline ? 'row' : 'column',
1602
+ alignItems: props.inline ? 'flex-end' : 'normal',
1603
+ gap: theme.controls.gap
1604
+ }), props.className), onSubmit: e => {
1605
+ if (ajax !== false) {
1606
+ e.preventDefault();
1607
+ e.stopPropagation();
1608
+ }
1609
+ if (onSubmit) {
1610
+ onSubmit(e);
1611
+ }
1612
+ } }), children));
1613
+ });
1614
+ const FormFlexRow = (props) => {
1615
+ var _a;
1616
+ const theme = useThemeSafely();
1617
+ return (React.createElement("div", { style: props.style, className: cx('formFlexRow', css({
1618
+ display: 'flex',
1619
+ gap: theme.controls.gap,
1620
+ justifyContent: (_a = props.justifyContent) !== null && _a !== void 0 ? _a : 'normal'
1621
+ }), props.className) }, props.children));
1622
+ };
1623
+ const FormColumnRow = (props) => {
1624
+ const theme = useThemeSafely();
1625
+ return (React.createElement("div", { style: props.style, className: cx('formColumnRow', css({
1626
+ display: 'grid',
1627
+ gap: theme.controls.gap,
1628
+ gridTemplateColumns: `repeat(${props.cols},1fr)`
1629
+ }), props.className) }, props.children));
1630
+ };
1631
+
1632
+ const InfoPanel = (props) => {
1633
+ const theme = useThemeSafely();
1634
+ const styles = css `
1635
+ border:${theme.colors.border};
1636
+ padding:1rem;
1637
+ color: rgba(0, 0, 0, 0.7);
1638
+ margin: 0 !important;
1639
+ ${props.variant === 'info' && `
1640
+ background-color:${theme.colors.info};
1641
+ color:${theme.colors.infoFont};
1642
+ `}
1643
+ ${props.variant === 'warning' && `
1644
+ background-color:${theme.colors.warning};
1645
+ color:${theme.colors.warningFont};
1646
+ `}
1647
+ ${props.variant === 'error' && `
1648
+ background-color:${theme.colors.omg};
1649
+ color:${theme.colors.omgFont};
1650
+ `}
1651
+ ${props.variant === 'negative' && `
1652
+ background-color:${theme.colors.negative};
1653
+ color:${theme.colors.negativeFont};
1654
+ `}
1655
+ ${props.variant === 'positive' && `
1656
+ background-color:${theme.colors.positive};
1657
+ color:${theme.colors.positiveFont};
1658
+ `}
1659
+ `;
1660
+ return (React.createElement(Text, { tag: props.tag || 'p', style: props.style, align: "center", className: cx('infoPanel', styles, props.className) }, props.children));
1661
+ };
1662
+
1663
+ class FileListPlus {
1664
+ constructor(_raw, _args = {}) {
1665
+ this._raw = _raw;
1666
+ this._args = _args;
1667
+ this._files = Array.from(this._raw).map(f => {
1668
+ return { name: f.name, size: f.size, type: f.type };
1669
+ });
1670
+ if (this._args.accept) {
1671
+ const acceptTypes = this._args.accept.split(',');
1672
+ this._invalidFiles = this._files.filter(f => {
1673
+ if (acceptTypes.includes(f.type)) {
1674
+ return false;
1675
+ }
1676
+ if (acceptTypes.some(t => f.name.endsWith(t))) {
1677
+ return false;
1678
+ }
1679
+ return true;
1680
+ });
1681
+ }
1682
+ else {
1683
+ this._invalidFiles = [];
1684
+ }
1685
+ }
1686
+ get raw() {
1687
+ return this._raw;
1688
+ }
1689
+ get length() {
1690
+ return this._files.length;
1691
+ }
1692
+ get files() {
1693
+ return this._files;
1694
+ }
1695
+ get invalidFiles() {
1696
+ return this._invalidFiles;
1697
+ }
1698
+ get totalBytes() {
1699
+ return sumBy(this.files, f => f.size);
1700
+ }
1701
+ get overMaxBytes() {
1702
+ var _a;
1703
+ return this.totalBytes >= ((_a = this._args.maxBytes) !== null && _a !== void 0 ? _a : Infinity);
1704
+ }
1705
+ get overFileLimit() {
1706
+ return this.length > (this._args.multiple ? Infinity : 1);
1707
+ }
1708
+ get hasErrors() {
1709
+ return this.overMaxBytes || this.overFileLimit || !!this.invalidFiles.length;
1710
+ }
1711
+ }
1712
+
1713
+ const DEFAULT_FAILURE_MESSAGE = 'Upload failed.';
1714
+ const hoverClass = css({
1715
+ backgroundColor: 'rgba(0,0,0,0.25) !important'
1716
+ });
1717
+ const FileUploader = (p) => {
1718
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1719
+ const [message, setMessage] = useState(undefined);
1720
+ const [canUpload, setCanUpload] = useState(false);
1721
+ const [uploading, setUploading] = useState(false);
1722
+ const [files, setFiles] = useState(undefined);
1723
+ const [fullFailureMessage, setFullFailureMessage] = useState(undefined);
1724
+ const form = useRef(null);
1725
+ const input = useRef(null);
1726
+ const totalFileSize = (_a = files === null || files === void 0 ? void 0 : files.totalBytes) !== null && _a !== void 0 ? _a : 0;
1727
+ const theme = useThemeSafely();
1728
+ let filesDisplay = '';
1729
+ if (!message) {
1730
+ if (!(files === null || files === void 0 ? void 0 : files.length)) {
1731
+ filesDisplay = (_b = p.instructionMessage) !== null && _b !== void 0 ? _b : `Click or drag and drop files.`;
1732
+ }
1733
+ else {
1734
+ filesDisplay = `${files.length.toLocaleString()} file${files.length > 1 ? 's' : ''} selected (${getFileSizeDisplay(totalFileSize)}): ${files.files.map(f => f.name).join(', ')}`;
1735
+ }
1736
+ }
1737
+ const setAllFiles = (inputFiles) => {
1738
+ if (input.current && inputFiles === undefined) {
1739
+ input.current.value = '';
1740
+ }
1741
+ setFiles(inputFiles);
1742
+ };
1743
+ const onFilesChange = (rawFiles) => {
1744
+ setAllFiles(rawFiles ? createFileList(rawFiles) : undefined);
1745
+ setCanUpload(!!(rawFiles === null || rawFiles === void 0 ? void 0 : rawFiles.length));
1746
+ setMessage(undefined);
1747
+ setFullFailureMessage(undefined);
1748
+ };
1749
+ const createFileList = (rawFiles) => {
1750
+ return new FileListPlus(rawFiles, {
1751
+ accept: p.accept,
1752
+ multiple: p.multiple,
1753
+ maxBytes: p.maxBytes
1754
+ });
1755
+ };
1756
+ const showInfoOnPick = (_c = p.showInfoOnPick) !== null && _c !== void 0 ? _c : true;
1757
+ let infoMessage;
1758
+ if (p.infoMessage && (!files || showInfoOnPick)) {
1759
+ if (typeof p.infoMessage === 'string') {
1760
+ infoMessage = React__default.createElement(Text, { noPad: true }, p.infoMessage);
1761
+ }
1762
+ else {
1763
+ infoMessage = p.infoMessage;
1764
+ }
1765
+ }
1766
+ return (React__default.createElement(Form, { ref: form, className: css({
1767
+ border: theme.controls.border,
1768
+ borderStyle: 'dashed',
1769
+ alignItems: 'center',
1770
+ justifyContent: 'center',
1771
+ position: 'relative',
1772
+ padding: '1rem',
1773
+ overflow: 'hidden',
1774
+ backgroundColor: theme.colors.lightBg,
1775
+ }, p.disabled && {
1776
+ opacity: theme.controls.disabledOpacity
1777
+ }), onDragOver: e => {
1778
+ var _a, _b;
1779
+ e.preventDefault();
1780
+ // we're using onDragOver instead of onDragEnter because *Enter and *Leave apparently can fire multiple times even though you're over the target.
1781
+ // *Over is continuous.
1782
+ if (!((_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.contains(hoverClass))) {
1783
+ (_b = form.current) === null || _b === void 0 ? void 0 : _b.classList.add(hoverClass);
1784
+ }
1785
+ }, onDragLeave: e => {
1786
+ var _a;
1787
+ (_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.remove(hoverClass);
1788
+ }, onDrop: e => {
1789
+ var _a;
1790
+ e.preventDefault();
1791
+ (_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.remove(hoverClass);
1792
+ onFilesChange(e.dataTransfer.files);
1793
+ }, onSubmit: e => {
1794
+ if (!files) {
1795
+ return;
1796
+ }
1797
+ setUploading(true);
1798
+ p.onUpload(files.raw).then(() => {
1799
+ setMessage('success');
1800
+ setAllFiles(undefined);
1801
+ }).catch(err => {
1802
+ var _a;
1803
+ setMessage('failure');
1804
+ setFullFailureMessage(`${(_a = p.failureMessage) !== null && _a !== void 0 ? _a : DEFAULT_FAILURE_MESSAGE} Error: ${err instanceof Error ? err.message : err}`);
1805
+ }).finally(() => {
1806
+ setUploading(false);
1807
+ setCanUpload(false);
1808
+ });
1809
+ } },
1810
+ React__default.createElement("input", { disabled: p.disabled, ref: input, className: css({
1811
+ position: 'absolute',
1812
+ top: -50,
1813
+ left: 0,
1814
+ bottom: 0,
1815
+ right: 0,
1816
+ width: '100%',
1817
+ cursor: 'pointer',
1818
+ opacity: 0
1819
+ }, p.disabled && {
1820
+ cursor: 'not-allowed'
1821
+ }), type: "file", multiple: p.multiple, accept: p.accept, onChange: e => {
1822
+ try {
1823
+ if (!e.target.files) {
1824
+ onFilesChange(undefined);
1825
+ return;
1826
+ }
1827
+ onFilesChange(e.target.files);
1828
+ }
1829
+ catch (err) {
1830
+ // tslint:disable-next-line
1831
+ console.error(err);
1832
+ onFilesChange(undefined);
1833
+ }
1834
+ } }),
1835
+ !message && (React__default.createElement("span", { className: css({
1836
+ display: 'flex',
1837
+ flexDirection: 'column',
1838
+ gap: '1rem',
1839
+ alignItems: 'center',
1840
+ zIndex: !!(files === null || files === void 0 ? void 0 : files.length) ? 1 : undefined
1841
+ }) },
1842
+ !(files === null || files === void 0 ? void 0 : files.length) && React__default.createElement(Icon, { style: { fontSize: '2rem' }, id: "upload" }),
1843
+ React__default.createElement(Text, { align: "center", noPad: true, spacedOut: true, className: css({
1844
+ width: '100%'
1845
+ }) },
1846
+ filesDisplay,
1847
+ !!(files === null || files === void 0 ? void 0 : files.length) && (React__default.createElement(Button, { onClick: e => {
1848
+ e.stopPropagation();
1849
+ onFilesChange(undefined);
1850
+ }, className: css({ marginLeft: '1rem', color: theme.colors.negative }), rightIcon: React__default.createElement(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear"))),
1851
+ infoMessage,
1852
+ !!(files === null || files === void 0 ? void 0 : files.invalidFiles.length) && (React__default.createElement(InfoPanel, { variant: "error", className: css({ width: '100%' }) },
1853
+ "Invalid files: ",
1854
+ files.invalidFiles.map(f => f.name).join(', '),
1855
+ ".")),
1856
+ (files === null || files === void 0 ? void 0 : files.overMaxBytes) && (React__default.createElement(InfoPanel, { variant: "error", className: css({ width: '100%' }) },
1857
+ "Max file size exceeded (",
1858
+ getFileSizeDisplay((_d = p.maxBytes) !== null && _d !== void 0 ? _d : 0),
1859
+ ").")))),
1860
+ canUpload && !(files === null || files === void 0 ? void 0 : files.hasErrors) && (React__default.createElement(Button, { className: css({
1861
+ width: (_e = p.buttonWidth) !== null && _e !== void 0 ? _e : '10rem',
1862
+ zIndex: 1,
1863
+ }), waiting: uploading, type: "submit", variant: (_f = p.buttonVariant) !== null && _f !== void 0 ? _f : 'primary' }, (_g = p.buttonText) !== null && _g !== void 0 ? _g : 'Upload')),
1864
+ message === 'success' && (React__default.createElement(UploadInfoPanel, { variant: "positive", message: (_h = p.successMessage) !== null && _h !== void 0 ? _h : 'Upload successful.', onClear: () => setMessage(undefined) })),
1865
+ message === 'failure' && (React__default.createElement(UploadInfoPanel, { variant: "error", message: fullFailureMessage, onClear: () => setMessage(undefined) }))));
1866
+ };
1867
+ const UploadInfoPanel = (p) => {
1868
+ return (React__default.createElement(InfoPanel, { variant: p.variant, className: css({ zIndex: 1 }) },
1869
+ p.message,
1870
+ React__default.createElement(Button, { block: true, className: css({
1871
+ color: 'inherit',
1872
+ marginTop: '1rem'
1873
+ }), onClick: e => {
1874
+ e.stopPropagation();
1875
+ p.onClear();
1876
+ }, rightIcon: React__default.createElement(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear")));
1877
+ };
1878
+ // OMG this is dumb. We're sticking with decimals for ease of use.
1879
+ // https://stackoverflow.com/questions/40949135/gigabyte-or-gibibyte-1000-or-1024
1880
+ const getFileSizeDisplay = (size) => {
1881
+ let value = 0;
1882
+ let suffix = '';
1883
+ if (size >= 1000000000) {
1884
+ value = size / 1000000000;
1885
+ suffix = 'GB';
1886
+ }
1887
+ else if (size >= 1000000) {
1888
+ value = size / 1000000;
1889
+ suffix = 'MB';
1890
+ }
1891
+ else if (size >= 1000) {
1892
+ value = size / 1000;
1893
+ suffix = 'KB';
1894
+ }
1895
+ else {
1896
+ value = size;
1897
+ suffix = 'B';
1898
+ }
1899
+ return value.toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ` ${suffix}`;
1900
+ };
1901
+
1902
+ /** @deprecated This will not work correctly with emotion/css. Use 'cx' for adding multiple class names together. */
1903
+ const mergeClassNames = (...classes) => {
1904
+ if (!classes) {
1905
+ return undefined;
1906
+ }
1907
+ return classes.filter(c => c).map(c => c).join(' ');
1908
+ };
1909
+ const getCurrencyDisplay = (value, isCents, denomination = '$') => {
1910
+ let actualValue = value || 0;
1911
+ if (isCents) {
1912
+ actualValue /= 100;
1913
+ }
1914
+ return `${denomination}${actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
1915
+ };
1916
+ const noop = () => {
1917
+ // lil' noop would be a great rap name. (thanks linter)
1918
+ };
1919
+ //TB: this will need to be exposed in v8 on the helpers page.
1920
+ /** Converts an enum to an array of entities with id and name. The enum can be an integer or string enum.*/
1921
+ const enumToEntities = (enumObj) => {
1922
+ const entities = [];
1923
+ for (const key in enumObj) {
1924
+ if (isNaN(parseInt(key, 10))) {
1925
+ entities.push({
1926
+ id: enumObj[key],
1927
+ name: key
1928
+ });
1929
+ }
1930
+ }
1931
+ return entities;
1932
+ };
1933
+
1934
+ const Header = (props) => {
1935
+ const theme = useThemeSafely();
1936
+ const bodyStyles = css `
1937
+ padding-top: calc(${theme.layout.headerHeight} + ${theme.layout.headerBodyOffset});
1938
+ label: Header;
1939
+ `;
1940
+ React.useEffect(() => {
1941
+ document.body.classList.add(bodyStyles);
1942
+ return () => {
1943
+ document.body.classList.remove(bodyStyles);
1944
+ };
1945
+ });
1946
+ const toggleMenu = props.toggleMenu || noop;
1947
+ const headerStyles = css `
1948
+ display: flex;
1949
+ gap: ${theme.controls.gap};
1950
+ justify-content: flex-start;
1951
+ align-items: center;
1952
+ position: fixed;
1953
+ top: 0;
1954
+ right: 0;
1955
+ left: 0;
1956
+ height: ${theme.layout.headerHeight};
1957
+ background-color: ${theme.colors.header};
1958
+ box-shadow: ${theme.controls.headerBoxShadow};
1959
+ color: ${theme.colors.headerFont};
1960
+ padding: 1rem;
1961
+ z-index: ${theme.zIndexes.header};
1962
+ flex-wrap: wrap;
1963
+ .button {
1964
+ color: ${theme.colors.headerFont};
1965
+ background-color:transparent;
1966
+ }
1967
+ ${props.inline && `
1968
+ position: static;
1969
+ `}
1970
+ ${!!props.rightElements && `
1971
+ justify-content: space-between;
1972
+ `}
1973
+ ${props.responsive && `
1974
+ @media(min-width:${theme.breakpoints.desktop}) {
1975
+ justify-content: flex-end;
1976
+ }
1977
+ `}
1978
+ `;
1979
+ const headerButtonStyles = !props.noMenu ? css `
1980
+ ${props.responsive && `
1981
+ @media(min-width:${theme.breakpoints.desktop}) {
1982
+ display: none;
1983
+ }
1984
+ `}
1985
+ ` : undefined;
1986
+ const rightElementStyles = props.rightElements && css `
1987
+ margin-left: 1rem;
1988
+ display: grid;
1989
+ grid-gap: 0.5rem;
1990
+ grid-auto-flow: column;
1991
+ align-items: center;
1992
+ `;
1993
+ const leftElementStyles = props.leftElements && css({
1994
+ display: 'grid',
1995
+ gap: '0.5rem',
1996
+ gridAutoFlow: 'column',
1997
+ alignItems: 'center'
1998
+ });
1999
+ const centerElementsStyles = props.centerOffsetElements && css `
2000
+ position: absolute;
2001
+ display: flex;
2002
+ justify-content: center;
2003
+ left: 0;
2004
+ right: 0;
2005
+ margin-top: calc(${theme.layout.headerHeight} * 1.25);
2006
+ `;
2007
+ let title;
2008
+ if (props.title) {
2009
+ if (typeof props.title === 'string') {
2010
+ title = (React.createElement(Text, { className: css({
2011
+ margin: 0,
2012
+ fontSize: '2rem',
2013
+ flexGrow: 1,
2014
+ flexBasis: '33%'
2015
+ }), tag: "h1", ellipsis: !props.fillTitle, align: props.fillTitle ? 'center' : 'left' }, props.title));
2016
+ }
2017
+ else {
2018
+ title = props.title;
2019
+ }
2020
+ }
2021
+ return (React.createElement("div", { className: cx('header', headerStyles, props.className) },
2022
+ !props.noMenu && (React.createElement(Button, { variant: "icon", className: headerButtonStyles, onClick: toggleMenu },
2023
+ React.createElement(Icon, { id: "menu" }))),
2024
+ props.leftElements && React.createElement("div", { className: leftElementStyles }, props.leftElements),
2025
+ title,
2026
+ props.rightElements && React.createElement("div", { className: rightElementStyles }, props.rightElements),
2027
+ props.centerOffsetElements && (React.createElement("div", { className: centerElementsStyles },
2028
+ React.createElement("div", null, props.centerOffsetElements)))));
2029
+ };
2030
+
2031
+ const Highlight = (props) => {
2032
+ const theme = useThemeSafely();
2033
+ const highlightStyles = css `
2034
+ > mark {
2035
+ background-color: ${theme.colors.textHighlight};
2036
+ }
2037
+ `;
2038
+ let text = props.text;
2039
+ if (props.text && props.highlightText) {
2040
+ const replaceText = props.highlightText.trim();
2041
+ if (replaceText) {
2042
+ text = props.text.replace(new RegExp(`(${replaceText})`, 'gi'), `<mark>$1</mark>`);
2043
+ }
2044
+ }
2045
+ return (React.createElement("span", { className: cx('highlight', highlightStyles), dangerouslySetInnerHTML: { __html: text } }));
2046
+ };
2047
+
2048
+ const Image = (props) => {
2049
+ return (React.createElement("img", { alt: props.alt, style: props.style, className: cx('image', css({
2050
+ maxWidth: '100%',
2051
+ maxHeight: '100%',
2052
+ }), props.className), src: props.src }));
2053
+ };
2054
+
2055
+ const InfoTip = (props) => {
2056
+ var _a, _b, _c;
2057
+ const [showTip, setShowTip] = React.useState(false);
2058
+ const theme = useThemeSafely();
2059
+ const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
2060
+ const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
2061
+ const onClick = () => {
2062
+ if (props.onClick) {
2063
+ props.onClick();
2064
+ }
2065
+ else if (props.content) {
2066
+ openTip();
2067
+ }
2068
+ };
2069
+ const onMouseOver = () => {
2070
+ if (props.variant === 'modal') {
2071
+ return;
2072
+ }
2073
+ if (props.loadOnHover) {
2074
+ props.loadOnHover().then(() => {
2075
+ openTip();
2076
+ }).catch(err => {
2077
+ /* Not my responsiblity. */
2078
+ });
2079
+ }
2080
+ else {
2081
+ openTip();
2082
+ }
2083
+ };
2084
+ const onMouseOut = () => {
2085
+ if (props.variant === 'modal') {
2086
+ return;
2087
+ }
2088
+ closeTip();
2089
+ };
2090
+ const openTip = () => {
2091
+ if (!props.content) {
2092
+ return;
2093
+ }
2094
+ setShowTip(props.disabled ? false : true);
2095
+ };
2096
+ const closeTip = () => {
2097
+ if (!props.content) {
2098
+ return;
2099
+ }
2100
+ setShowTip(false);
2101
+ if (props.onClose) {
2102
+ props.onClose();
2103
+ }
2104
+ };
2105
+ const buttonStyles = css `
2106
+ font-weight: bold;
2107
+ width: 1.5rem;
2108
+ min-width:1.5rem;
2109
+ height: 1.5rem;
2110
+ padding: 0 !important;
2111
+ font-family: serif;
2112
+ display:inline-block;
2113
+ `;
2114
+ const button = React.createElement(Button, { className: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
2115
+ if (props.variant === 'modal') {
2116
+ return (React.createElement(React.Fragment, null,
2117
+ button,
2118
+ React.createElement(Modal, { id: props.modalId, debug: props.modalDebug, show: showTip, heading: props.modalHeader, onClick: closeTip, className: css({
2119
+ whiteSpace: 'normal'
2120
+ }), closeButton: true },
2121
+ React.createElement("div", { className: css({ padding: '1rem' }) }, props.content))));
2122
+ }
2123
+ else {
2124
+ return (React.createElement(Popover, { positions: props.positions, reposition: (_c = props.reposition) !== null && _c !== void 0 ? _c : false, isOpen: showTip, onClickOutside: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (React.createElement("div", { className: css({
2125
+ padding: '0.5rem',
2126
+ fontSize: '0.75rem',
2127
+ maxWidth: '22rem'
2128
+ }), style: { backgroundColor: bgColor, color: fontColor }, onMouseOut: closeTip }, props.content)) }));
2129
+ }
2130
+ };
2131
+
2132
+ const defaultMaxLength$1 = 100;
2133
+ const BaseInput = React.forwardRef((props, ref) => {
2134
+ var _a;
2135
+ const theme = useThemeSafely();
2136
+ const { rightControl, round, wrapperClassName } = props, nativeProps = __rest(props, ["rightControl", "round", "wrapperClassName"]);
2137
+ const inputStyles = css({
2138
+ fontFamily: theme.fonts.family,
2139
+ fontSize: theme.fonts.size,
2140
+ width: '100%',
2141
+ border: theme.controls.border,
2142
+ borderRadius: theme.controls.borderRadius,
2143
+ color: theme.colors.font,
2144
+ paddingLeft: theme.controls.padding,
2145
+ paddingRight: theme.controls.padding,
2146
+ height: theme.controls.height,
2147
+ transition: theme.controls.transition,
2148
+ ':focus': {
2149
+ outline: 'none',
2150
+ boxShadow: theme.controls.focusOutlineShadow
2151
+ },
2152
+ ':disabled': {
2153
+ backgroundColor: theme.colors.disabled,
2154
+ cursor: 'not-allowed'
2155
+ },
2156
+ ':invalid': {
2157
+ borderColor: theme.colors.required,
2158
+ ':focus': {
2159
+ boxShadow: theme.controls.focusOutlineRequiredShadow
2160
+ }
2161
+ },
2162
+ }, props.round && {
2163
+ borderRadius: theme.controls.roundRadius,
2164
+ paddingLeft: `calc(${theme.controls.padding} * 2)`,
2165
+ paddingRight: `calc(${theme.controls.padding} * 2)`
2166
+ }, props.readOnly && {
2167
+ backgroundColor: 'transparent',
2168
+ cursor: 'default',
2169
+ border: 'none',
2170
+ ':focus': {
2171
+ outline: 'none',
2172
+ boxShadow: 'none'
2173
+ }
2174
+ }, props.rightControl && {
2175
+ paddingRight: theme.controls.height
2176
+ });
2177
+ const inputElement = React.createElement("input", Object.assign({}, nativeProps, { ref: ref, autoComplete: (_a = nativeProps.autoComplete) !== null && _a !== void 0 ? _a : 'off', tabIndex: nativeProps.readOnly ? -1 : nativeProps.tabIndex, maxLength: nativeProps.maxLength || defaultMaxLength$1, className: cx(inputStyles, props.className) }));
2178
+ const inputWrapperStyles = css `
2179
+ width:100%;
2180
+ ${props.rightControl && `
2181
+ position: relative;
2182
+ `}
2183
+ `;
2184
+ const rightControlStyles = props.rightControl && css `
2185
+ position: absolute;
2186
+ right: ${theme.controls.padding};
2187
+ top: 0;
2188
+ bottom: 0;
2189
+ display: flex;
2190
+ align-items: center;
2191
+ ${props.round && `
2192
+ right: calc(${theme.controls.padding} * 2);
2193
+ `}
2194
+ `;
2195
+ return (React.createElement("div", { className: cx('input', inputWrapperStyles, wrapperClassName) },
2196
+ inputElement,
2197
+ props.rightControl && React.createElement("div", { className: rightControlStyles }, props.rightControl)));
2198
+ });
2199
+
2200
+ const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
2201
+ const datePattern = dateRegex.source;
2202
+ const outOfRangeValidityMessage = 'Out of range';
2203
+ const isOutOfRange = (value, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {
2204
+ if (typeof value === 'number') {
2205
+ return value < min || value > max;
2206
+ }
2207
+ return false;
2208
+ };
2209
+ const parseDateMs = (rawValue, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {
2210
+ let value;
2211
+ let outOfRange = false;
2212
+ const dateParts = dateRegex.exec(rawValue);
2213
+ if (dateParts) {
2214
+ const month = parseInt(dateParts[1], 10);
2215
+ const day = parseInt(dateParts[2], 10);
2216
+ const year = parseInt(dateParts[3], 10);
2217
+ if (isExists(year, month, day)) {
2218
+ value = new Date(year, month - 1, day).valueOf();
2219
+ outOfRange = isOutOfRange(value, min, max);
2220
+ if (outOfRange) {
2221
+ value = Math.max(Math.min(value, max), min);
2222
+ }
2223
+ }
2224
+ }
2225
+ return {
2226
+ value,
2227
+ outOfRange
2228
+ };
2229
+ };
2230
+ const formatOuterValue = (value) => {
2231
+ if (typeof value === 'number') {
2232
+ return format(value, 'MM/dd/yyyy');
2233
+ }
2234
+ return '';
2235
+ };
2236
+ const DateInput = React.forwardRef((props, ref) => {
2237
+ const [localValue, setLocalValue] = React.useState('');
2238
+ const hasFocus = React.useRef(false);
2239
+ const inputRef = (ref !== null && ref !== void 0 ? ref : React.useRef(null));
2240
+ const { value, onChange } = props, otherProps = __rest(props, ["value", "onChange"]);
2241
+ React.useEffect(() => {
2242
+ var _a;
2243
+ // prevent the outer value from influencing the inner value while you're typing.
2244
+ if (!hasFocus.current) {
2245
+ // sync the outer value to the local value if it changed.
2246
+ setLocalValue(formatOuterValue(value));
2247
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.setCustomValidity((isOutOfRange(value, props.min, props.max) ? outOfRangeValidityMessage : ''));
2248
+ }
2249
+ }, [value]);
2250
+ return (React.createElement(BaseInput, Object.assign({}, otherProps, { pattern: datePattern, maxLength: 10, ref: inputRef, type: "text", value: localValue, onChange: e => {
2251
+ setLocalValue(e.target.value);
2252
+ const { value: v, outOfRange } = parseDateMs(e.target.value, props.min, props.max);
2253
+ // need to force invalid due to our using a 'text' input rather than a 'number' or 'date'.
2254
+ e.target.setCustomValidity(outOfRange ? outOfRangeValidityMessage : '');
2255
+ onChange(v, e);
2256
+ }, onFocus: e => {
2257
+ var _a;
2258
+ hasFocus.current = true;
2259
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2260
+ }, onBlur: e => {
2261
+ var _a;
2262
+ hasFocus.current = false;
2263
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2264
+ // min/max constraints won't be reflected in the local input value. fix that now.
2265
+ // handling min/max while typing would be difficult and frustrating to the user.
2266
+ setLocalValue(formatOuterValue(value));
2267
+ e.target.setCustomValidity(isOutOfRange(value, props.min, props.max) ? outOfRangeValidityMessage : '');
2268
+ } })));
2269
+ });
2270
+
2271
+ const parseNumber = (rawValue, step = 0, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER, applyMinMax) => {
2272
+ var _a;
2273
+ const decimals = step === 0 ? 0 : (_a = step.toString().split('.')[1]) === null || _a === void 0 ? void 0 : _a.length;
2274
+ let value;
2275
+ if (rawValue) {
2276
+ value = parseFloat(rawValue);
2277
+ if (isNaN(value)) {
2278
+ value = undefined;
2279
+ }
2280
+ else {
2281
+ if (decimals === 0) {
2282
+ value = Math.floor(value);
2283
+ }
2284
+ else {
2285
+ value = parseFloat(value.toFixed(decimals));
2286
+ }
2287
+ if (applyMinMax) {
2288
+ value = Math.max(Math.min(value, max), min);
2289
+ }
2290
+ }
2291
+ }
2292
+ return [value, value === null || value === void 0 ? void 0 : value.toString()];
2293
+ };
2294
+ const NumberInput = React.forwardRef((props, ref) => {
2295
+ var _a, _b;
2296
+ const { value, onChange, constrainOnInput } = props, otherProps = __rest(props, ["value", "onChange", "constrainOnInput"]);
2297
+ const applyInputConstraints = (_a = props.constrainOnInput) !== null && _a !== void 0 ? _a : true;
2298
+ return (React.createElement(BaseInput, Object.assign({}, otherProps, { ref: ref, maxLength: (_b = props.maxLength) !== null && _b !== void 0 ? _b : 50, type: "number", value: value !== null && value !== void 0 ? value : '', onChange: e => {
2299
+ const [v, displayValue] = parseNumber(e.target.value, props.step, props.min, props.max, applyInputConstraints);
2300
+ // make sure the displayed value always matches our parsed value.
2301
+ e.target.value = displayValue !== null && displayValue !== void 0 ? displayValue : '';
2302
+ onChange(v, e);
2303
+ }, onBlur: e => {
2304
+ if (applyInputConstraints) {
2305
+ // catch all for things we missed.
2306
+ // onChange would have been called with undefined, but something strange might remain.
2307
+ if (!e.target.checkValidity()) {
2308
+ e.target.value = '';
2309
+ }
2310
+ }
2311
+ } })));
2312
+ });
2313
+
2314
+ const defaultMaxLength = 200;
2315
+ const defaultRows = 10;
2316
+ const TextArea = React.forwardRef((props, ref) => {
2317
+ var _a, _b;
2318
+ const { className, value, onChange } = props, otherProps = __rest(props, ["className", "value", "onChange"]);
2319
+ const theme = useThemeSafely();
2320
+ const styles = css({
2321
+ maxWidth: '100%',
2322
+ minHeight: theme.controls.height,
2323
+ fontFamily: theme.fonts.family,
2324
+ fontSize: theme.fonts.size,
2325
+ width: '100%',
2326
+ border: theme.controls.border,
2327
+ borderRadius: theme.controls.borderRadius,
2328
+ color: theme.colors.font,
2329
+ paddingTop: '0.75rem',
2330
+ paddingLeft: theme.controls.padding,
2331
+ paddingRight: theme.controls.padding,
2332
+ height: 'auto',
2333
+ transition: theme.controls.transition,
2334
+ ':focus': {
2335
+ outline: 'none',
2336
+ boxShadow: theme.controls.focusOutlineShadow
2337
+ },
2338
+ ':disabled': {
2339
+ backgroundColor: theme.colors.disabled,
2340
+ cursor: 'not-allowed'
2341
+ },
2342
+ ':invalid': {
2343
+ borderColor: theme.colors.required,
2344
+ ':focus': {
2345
+ boxShadow: theme.controls.focusOutlineRequiredShadow
2346
+ }
2347
+ },
2348
+ }, props.readOnly && {
2349
+ backgroundColor: 'transparent',
2350
+ cursor: 'default',
2351
+ border: 'none',
2352
+ ':focus': {
2353
+ outline: 'none',
2354
+ boxShadow: 'none'
2355
+ }
2356
+ });
2357
+ return (React.createElement("textarea", Object.assign({}, otherProps, { className: cx(styles, className), autoComplete: (_a = props.autoComplete) !== null && _a !== void 0 ? _a : 'off', tabIndex: props.readOnly ? -1 : props.tabIndex, maxLength: props.maxLength || defaultMaxLength, rows: (_b = props.rows) !== null && _b !== void 0 ? _b : defaultRows, ref: ref, value: value !== null && value !== void 0 ? value : '', onChange: e => {
2358
+ onChange(e.target.value || undefined, e);
2359
+ } })));
2360
+ });
2361
+
2362
+ const TextInput = React.forwardRef((props, ref) => {
2363
+ var _a;
2364
+ const { value, onChange } = props, otherProps = __rest(props, ["value", "onChange"]);
2365
+ return (React.createElement(BaseInput, Object.assign({}, otherProps, { type: (_a = props.type) !== null && _a !== void 0 ? _a : 'text', ref: ref, value: value !== null && value !== void 0 ? value : '', onChange: e => {
2366
+ onChange(e.target.value || undefined, e);
2367
+ } })));
2368
+ });
2369
+
2370
+ const Label = (props) => {
2371
+ var _a, _b, _c;
2372
+ const theme = useThemeSafely();
2373
+ const orientation = (_a = props.orientation) !== null && _a !== void 0 ? _a : 'vertical';
2374
+ const align = (_b = props.align) !== null && _b !== void 0 ? _b : 'left';
2375
+ const padding = '0.25rem';
2376
+ const labelStyles = css `
2377
+ ${padding};
2378
+ display: flex;
2379
+ ${orientation === 'vertical' && `
2380
+ flex-direction: column;
2381
+ `}
2382
+ ${orientation === 'horizontal' && `
2383
+ flex-direction: row;
2384
+ align-items: center;
2385
+ `}
2386
+ ${orientation === 'horizontalReverse' && `
2387
+ flex-direction: row-reverse;
2388
+ align-items: center;
2389
+ `}
2390
+ `;
2391
+ const labelTextStyles = css `
2392
+ flex-shrink:0;
2393
+ ${orientation === 'vertical' && `
2394
+ margin-bottom: ${padding};
2395
+ `}
2396
+ ${orientation === 'horizontal' && `
2397
+ flex-direction: row;
2398
+ margin-right:${padding};
2399
+ ${props.static && `
2400
+ margin-right:0.5rem;
2401
+ `}
2402
+ `}
2403
+ ${orientation === 'horizontalReverse' && `
2404
+ margin-left:${padding};
2405
+ `}
2406
+ ${(props.subText || props.optional) && `
2407
+ margin-right: 0.5rem;
2408
+ `}
2409
+ `;
2410
+ const labelContentStyles = css `
2411
+ display:inline-block;
2412
+ width:100%;
2413
+ ${props.controlAlign && `
2414
+ height:${theme.controls.height};
2415
+ line-height:${theme.controls.height};
2416
+ `}
2417
+ `;
2418
+ const outerClass = props.className;
2419
+ let labelText = React.createElement(Text, { align: align, className: labelTextStyles, tag: "div", bold: true }, props.text);
2420
+ let subText;
2421
+ if (props.subText) {
2422
+ if (typeof props.subText === 'string') {
2423
+ subText = React.createElement(Text, { tag: "div" }, props.subText);
2424
+ }
2425
+ else {
2426
+ subText = props.subText;
2427
+ }
2428
+ }
2429
+ else if (props.optional) {
2430
+ subText = React.createElement(Text, { tag: "div" },
2431
+ React.createElement("em", null, "(optional)"));
2432
+ }
2433
+ if (subText) {
2434
+ labelText = React.createElement("span", { className: css({ display: 'flex' }) },
2435
+ labelText,
2436
+ React.createElement("span", { className: css({
2437
+ fontSize: '90%',
2438
+ marginBottom: padding
2439
+ }) }, subText));
2440
+ }
2441
+ if (props.noWrap) {
2442
+ return (React.createElement("span", { className: cx(labelStyles, outerClass) },
2443
+ React.createElement("label", { htmlFor: props.htmlFor, className: outerClass }, labelText),
2444
+ props.children));
2445
+ }
2446
+ const content = React.createElement(React.Fragment, null,
2447
+ labelText,
2448
+ React.createElement("span", { className: css(labelContentStyles) }, props.children));
2449
+ if (props.static) {
2450
+ return (React.createElement("span", { className: cx(labelStyles, outerClass) }, content));
2451
+ }
2452
+ // labels without htmlFor can cause focus, hover, and click issues when wrapping other elements.
2453
+ // this fixes the issues.
2454
+ const htmlFor = (_c = props.htmlFor) !== null && _c !== void 0 ? _c : nanoid();
2455
+ return (React.createElement("label", { htmlFor: htmlFor, className: cx('label', labelStyles, outerClass) }, content));
2456
+ };
2457
+
2458
+ /*
2459
+ From https://fireship.io/snippets/use-media-query-hook/.
2460
+ Tried using https://www.npmjs.com/package/react-media, but it cause Webpack build issues.
2461
+ */
2462
+ const useMediaQuery = (query) => {
2463
+ const [matches, setMatches] = useState(false);
2464
+ useEffect(() => {
2465
+ const media = window.matchMedia(query);
2466
+ if (media.matches !== matches) {
2467
+ setMatches(media.matches);
2468
+ }
2469
+ const listener = () => setMatches(media.matches);
2470
+ window.addEventListener("resize", listener);
2471
+ return () => window.removeEventListener("resize", listener);
2472
+ }, [matches, query]);
2473
+ return matches;
2474
+ };
2475
+
2476
+ const Nav = (props) => {
2477
+ const nav = React.useRef(null);
2478
+ const theme = useThemeSafely();
2479
+ const totalNavOffset = `calc(${theme.layout.navWidth} + 20px)`;
2480
+ const backdrop = React.useContext(BackdropContext);
2481
+ const isLargeScreen = useMediaQuery(`(min-width:${theme.breakpoints.desktop})`);
2482
+ const slideRight = keyframes `
2483
+ 0% {
2484
+ transform: translateX(0);
2485
+ }
2486
+
2487
+ 100% {
2488
+ transform: translateX(${totalNavOffset});
2489
+ }
2490
+ `;
2491
+ const slideLeft = keyframes `
2492
+ 0% {
2493
+ transform: translateX(${totalNavOffset});
2494
+ }
2495
+
2496
+ 100% {
2497
+ transform: translateX(0px);
2498
+ }
2499
+ `;
2500
+ const classNavShowing = css `
2501
+ animation: ${slideRight} 0.250s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
2502
+ `;
2503
+ const classNavNotShowing = css `
2504
+ animation: ${slideLeft} 0.250s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
2505
+ `;
2506
+ // the padding-top here is to offset the navs' content from the header. the shadow creeps over it.
2507
+ const navStyles = css `
2508
+ position: fixed;
2509
+ top: 0;
2510
+ left: calc(${totalNavOffset} * -1);
2511
+ bottom: 0;
2512
+ background-color: ${theme.colors.nav};
2513
+ color: ${theme.colors.navFont};
2514
+ width: ${theme.layout.navWidth};
2515
+ min-width: ${theme.layout.navWidth};
2516
+ box-shadow: 4px 2px 12px 6px rgba(0, 0, 0, 0.2);
2517
+ z-index: ${theme.zIndexes.nav};
2518
+ overflow-y: auto;
2519
+ .omniLink, .omniLink:active, .omniLink:focus, .omniLink:visited {
2520
+ color: ${theme.colors.navFont};
2521
+ }
2522
+ padding-top:0;
2523
+ ${props.responsive && `
2524
+ @media(min-width:${theme.breakpoints.desktop}) {
2525
+ position: relative;
2526
+ left: 0;
2527
+ box-shadow: none;
2528
+ z-index: 1;
2529
+ animation: none !important;
2530
+ margin-right: 1rem;
2531
+ overflow-y: visible;
2532
+ margin-top:-2rem;
2533
+ padding-top: 1rem;
2534
+ }
2535
+ `}
2536
+ `;
2537
+ React.useEffect(() => {
2538
+ if (!backdrop.showing) {
2539
+ props.toggle(false);
2540
+ }
2541
+ }, [backdrop.showing]);
2542
+ React.useEffect(() => {
2543
+ backdrop.setShow(props.show);
2544
+ }, [props.show]);
2545
+ React.useLayoutEffect(() => {
2546
+ if (nav && nav.current) {
2547
+ if (props.show) {
2548
+ if (!nav.current.classList.contains(classNavShowing)) {
2549
+ nav.current.classList.add(classNavShowing);
2550
+ }
2551
+ }
2552
+ else {
2553
+ if (nav.current.classList.contains(classNavShowing)) {
2554
+ nav.current.classList.remove(classNavShowing);
2555
+ nav.current.classList.add(classNavNotShowing);
2556
+ setTimeout(() => {
2557
+ if (nav && nav.current) {
2558
+ nav.current.classList.remove(classNavNotShowing);
2559
+ }
2560
+ }, 250);
2561
+ }
2562
+ }
2563
+ }
2564
+ });
2565
+ if (props.responsive) {
2566
+ React.useEffect(() => {
2567
+ if (backdrop.showing) {
2568
+ props.toggle(false);
2569
+ }
2570
+ }, [isLargeScreen]);
2571
+ }
2572
+ return (React.createElement("nav", { ref: nav, className: cx('nav', navStyles, props.className) }, props.children));
2573
+ };
2574
+
2575
+ const OmniLink = (props) => {
2576
+ var _a, _b, _c;
2577
+ const theme = useThemeSafely();
2578
+ const linkStyles = css `
2579
+ display: inline-block;
2580
+ cursor: pointer;
2581
+ text-decoration: none;
2582
+ color: ${(_a = props.colorOverride) !== null && _a !== void 0 ? _a : theme.colors.link};
2583
+ transition: ${theme.controls.transition};
2584
+ &:hover {
2585
+ filter: ${theme.controls.hoverBrightness};
2586
+ text-decoration: underline;
2587
+ }
2588
+ &:active,
2589
+ &:visited {
2590
+ color: ${(_b = props.colorOverride) !== null && _b !== void 0 ? _b : theme.colors.link};
2591
+ }
2592
+ &:focus {
2593
+ text-decoration: underline;
2594
+ outline: none;
2595
+ color: ${(_c = props.colorOverride) !== null && _c !== void 0 ? _c : theme.colors.link};
2596
+ }
2597
+ ${!!props.variant && `
2598
+ padding-left: ${theme.controls.padding};
2599
+ padding-right: ${theme.controls.padding};
2600
+ border: ${theme.controls.border};
2601
+ border-radius: ${theme.controls.borderRadius};
2602
+ box-shadow: ${theme.controls.boxShadow};
2603
+ height: ${theme.controls.height};
2604
+ line-height: ${theme.controls.height};
2605
+ font-weight: bold;
2606
+ color: ${theme.colors.font};
2607
+ &:active,
2608
+ &:focus,
2609
+ &:visited {
2610
+ color: ${theme.colors.font};
2611
+ }
2612
+ &:focus {
2613
+ outline: none;
2614
+ box-shadow: ${theme.controls.focusOutlineShadow};
2615
+ text-decoration: none;
2616
+ }
2617
+ &:active {
2618
+ box-shadow: none;
2619
+ }
2620
+ &:hover {
2621
+ text-decoration: none;
2622
+ }
2623
+ `}
2624
+ ${props.variant === 'button' && `
2625
+ text-align: center;
2626
+ `}
2627
+ ${props.variant === 'circle' && `
2628
+ text-align: center;
2629
+ width: ${theme.controls.height};
2630
+ border-radius: 100%;
2631
+ display: flex;
2632
+ justify-content: center;
2633
+ align-items: center;
2634
+ ${props.small && `
2635
+ width: ${theme.controls.heightSmall};
2636
+ min-width: ${theme.controls.heightSmall};
2637
+ `}
2638
+ `}
2639
+ ${props.variant === 'primary' && `
2640
+ text-align: center;
2641
+ background-color: ${theme.colors.primary};
2642
+ color: ${theme.colors.primaryFont};
2643
+ &:active,
2644
+ &:focus,
2645
+ &:visited {
2646
+ color: ${theme.colors.primaryFont};
2647
+ }
2648
+ `}
2649
+ ${props.variant === 'primary2' && `
2650
+ text-align: center;
2651
+ background-color: ${theme.colors.primary2};
2652
+ color: ${theme.colors.primary2Font};
2653
+ &:active,
2654
+ &:focus,
2655
+ &:visited {
2656
+ color: ${theme.colors.primary2Font};
2657
+ }
2658
+ `}
2659
+ ${props.variant === 'secondary' && `
2660
+ text-align: center;
2661
+ background-color: ${theme.colors.secondary};
2662
+ color: ${theme.colors.secondary2Font};
2663
+ &:active,
2664
+ &:focus,
2665
+ &:visited {
2666
+ color: ${theme.colors.secondary2Font};
2667
+ }
2668
+ `}
2669
+ ${props.variant === 'positive' && `
2670
+ text-align: center;
2671
+ background-color: ${theme.colors.positive};
2672
+ color: ${theme.colors.positiveFont};
2673
+ &:active,
2674
+ &:focus,
2675
+ &:visited {
2676
+ color: ${theme.colors.positiveFont};
2677
+ }
2678
+ `}
2679
+ ${props.variant === 'negative' && `
2680
+ text-align: center;
2681
+ background-color: ${theme.colors.negative};
2682
+ color: ${theme.colors.negativeFont};
2683
+ &:active,
2684
+ &:focus,
2685
+ &:visited {
2686
+ color: ${theme.colors.negativeFont};
2687
+ }
2688
+ `}
2689
+ ${props.variant === 'omg' && `
2690
+ text-align: center;
2691
+ background-color: ${theme.colors.omg};
2692
+ color: ${theme.colors.omgFont};
2693
+ &:active,
2694
+ &:focus,
2695
+ &:visited {
2696
+ color: ${theme.colors.omgFont};
2697
+ }
2698
+ `}
2699
+ ${props.variant === 'label' && `
2700
+ box-shadow: none;
2701
+ border: none;
2702
+ `}
2703
+ ${props.variant === 'icon' && `
2704
+ box-shadow: none;
2705
+ border: none;
2706
+ border-radius: 100%;
2707
+ width: ${theme.controls.height};
2708
+ text-align: center;
2709
+ `}
2710
+ ${props.block && `
2711
+ display: block;
2712
+ width:100%;
2713
+ `}
2714
+ ${props.iconBlock && `
2715
+ display: flex;
2716
+ justify-content: space-between;
2717
+ align-items: center;
2718
+ `}
2719
+ ${props.round && `
2720
+ border-radius: ${theme.controls.roundRadius};
2721
+ `}
2722
+ ${props.rounded && `
2723
+ border-radius: ${theme.controls.roundedRadius};
2724
+ `}
2725
+ ${props.small && `
2726
+ font-size: 0.8rem;
2727
+ height: ${theme.controls.heightSmall};
2728
+ line-height: ${theme.controls.heightSmall};
2729
+ `}
2730
+ `;
2731
+ const mainClassName = cx('omniLink', linkStyles, props.className);
2732
+ const content = React.createElement(React.Fragment, null,
2733
+ React.createElement("span", null,
2734
+ props.leftIcon && React.createElement("span", { className: css({
2735
+ marginRight: '1rem',
2736
+ display: 'inline-block',
2737
+ minWidth: '1.5rem',
2738
+ verticalAlign: 'middle'
2739
+ }) }, props.leftIcon),
2740
+ props.children),
2741
+ props.rightIcon && React.createElement("span", { className: css({
2742
+ marginLeft: '1rem',
2743
+ verticalAlign: 'middle'
2744
+ }) }, props.rightIcon));
2745
+ if (props.noRouter) {
2746
+ return (React.createElement("a", { title: props.title, style: props.style, target: props.target, className: mainClassName, href: props.href, onClick: props.onClick }, content));
2747
+ }
2748
+ return (React.createElement(Link, { title: props.title, style: props.style, className: mainClassName, onClick: props.onClick, to: props.href }, content));
2749
+ };
2750
+
2751
+ const Picker = (props) => {
2752
+ const selectProps = __rest(props
2753
+ // if we put numbers in, we expect them out
2754
+ , ["value", "options", "onChange", "type", "rounded", "round", "readonly"]);
2755
+ // if we put numbers in, we expect them out
2756
+ let isNumber = false;
2757
+ if (props.options && props.options.length) {
2758
+ const testOption = props.options[0];
2759
+ if (typeof testOption === 'object') {
2760
+ isNumber = typeof testOption.id === 'number';
2761
+ }
2762
+ else {
2763
+ isNumber = typeof testOption === 'number';
2764
+ }
2765
+ }
2766
+ const theme = useThemeSafely();
2767
+ const selectStyles = css `
2768
+ color: ${theme.colors.font};
2769
+ padding-left: ${theme.controls.padding};
2770
+ padding-right: ${theme.controls.padding};
2771
+ height: ${theme.controls.height};
2772
+ font-size: ${theme.controls.fontSize};
2773
+ width: 100%;
2774
+ border: ${theme.controls.border};
2775
+ border-radius: ${theme.controls.borderRadius};
2776
+ transition: ${theme.controls.transition};
2777
+ &:disabled {
2778
+ color: ${theme.colors.font};
2779
+ opacity: 1;
2780
+ background-color: ${theme.colors.disabled};
2781
+ cursor: not-allowed;
2782
+ }
2783
+ &:focus {
2784
+ outline: none;
2785
+ box-shadow: ${theme.controls.focusOutlineShadow};
2786
+ }
2787
+ ${props.rounded && `
2788
+ border-radius: ${theme.controls.roundedRadius};
2789
+ `}
2790
+ ${props.round && `
2791
+ border-radius: ${theme.controls.roundRadius};
2792
+ `}
2793
+ ${props.readonly && `
2794
+ background-color: transparent !important;
2795
+ border: none;
2796
+ -webkit-appearance: none;
2797
+ -moz-appearance: none;
2798
+ &:focus {
2799
+ outline: none;
2800
+ box-shadow: none;
2801
+ }
2802
+ `}
2803
+ `;
2804
+ return (React.createElement("select", Object.assign({}, selectProps, { tabIndex: props.readonly ? -1 : selectProps.tabIndex, className: cx('picker', selectStyles, props.className), value: props.value, onKeyDown: e => {
2805
+ var _a;
2806
+ if (props.readonly) {
2807
+ if (e.keyCode === 9) {
2808
+ //TAB
2809
+ return;
2810
+ }
2811
+ e.preventDefault();
2812
+ e.stopPropagation();
2813
+ }
2814
+ else {
2815
+ (_a = selectProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(selectProps, e);
2816
+ }
2817
+ }, onMouseDown: e => {
2818
+ var _a;
2819
+ if (props.readonly) {
2820
+ e.preventDefault();
2821
+ e.stopPropagation();
2822
+ }
2823
+ else {
2824
+ (_a = selectProps.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(selectProps, e);
2825
+ }
2826
+ }, onChange: e => {
2827
+ let val = e.target.value;
2828
+ if (isNumber) {
2829
+ val = parseInt(val, 10);
2830
+ if (isNaN(val)) {
2831
+ val = '';
2832
+ }
2833
+ }
2834
+ props.onChange(val, e);
2835
+ } }), (props.options || []).map(o => {
2836
+ var _a;
2837
+ let val;
2838
+ let label;
2839
+ if (typeof o === 'object') {
2840
+ val = o.id;
2841
+ label = (_a = o.name) !== null && _a !== void 0 ? _a : o.id;
2842
+ }
2843
+ else {
2844
+ val = o;
2845
+ label = o;
2846
+ }
2847
+ return React.createElement("option", { key: val, value: val }, label);
2848
+ })));
2849
+ };
2850
+
2851
+ const Pager = (props) => {
2852
+ var _a;
2853
+ const canGoNext = props.canGoNext && props.totalItems > 0;
2854
+ const canGoPrevious = props.canGoPrevious && props.totalItems > 0;
2855
+ const dividerText = props.itemDividerText || 'of';
2856
+ let itemText = '';
2857
+ if (props.totalItems > 0) {
2858
+ itemText = `${props.minItem.toLocaleString()}-${props.maxItem.toLocaleString()} ${dividerText} ${props.totalItems.toLocaleString()}`;
2859
+ }
2860
+ else {
2861
+ itemText = props.noResultsText || 'No Results';
2862
+ }
2863
+ let pageText;
2864
+ if (props.pageIndex !== undefined && props.totalPages) {
2865
+ pageText = `${(_a = props.pageText) !== null && _a !== void 0 ? _a : 'Page'} ${(props.pageIndex + 1).toLocaleString()} ${dividerText} ${props.totalPages.toLocaleString()}`;
2866
+ }
2867
+ const theme = useThemeSafely();
2868
+ const pagerStyles = css `
2869
+ display: grid;
2870
+ grid-template-columns: ${theme.controls.height} 1fr ${theme.controls.height};
2871
+ grid-column-gap: ${theme.controls.gap};
2872
+ border: ${theme.controls.border};
2873
+ border-radius: ${theme.controls.borderRadius};
2874
+ padding: 0.5rem;
2875
+ background-color: ${theme.colors.pagerBg};
2876
+ @media(min-width: ${theme.breakpoints.tablet}) {
2877
+ grid-template-columns: ${theme.controls.height} 1fr 1fr 1fr ${theme.controls.height};
2878
+ }
2879
+ ${props.rounded && `
2880
+ border-radius: ${theme.controls.roundedRadius};
2881
+ `}
2882
+ `;
2883
+ const controlStyles = css `
2884
+ display: none;
2885
+ padding:0 1rem;
2886
+ justify-self: center;
2887
+ @media(min-width: ${theme.breakpoints.tablet}) {
2888
+ display: block;
2889
+ }
2890
+ `;
2891
+ const buttonStyles = css({
2892
+ backgroundColor: 'transparent'
2893
+ });
2894
+ return (React.createElement("div", { className: cx(pagerStyles, props.className) },
2895
+ React.createElement(Button, { className: buttonStyles, disabled: !canGoPrevious, onClick: () => props.page(-1), variant: "icon" },
2896
+ React.createElement(Icon, { id: "pagerLeft" })),
2897
+ React.createElement("div", { className: controlStyles }, props.leftControls),
2898
+ React.createElement("div", { className: css({
2899
+ alignSelf: 'center',
2900
+ justifySelf: 'center',
2901
+ display: 'flex',
2902
+ gap: '0.5rem',
2903
+ flexDirection: 'column'
2904
+ }) },
2905
+ React.createElement(Text, { tag: "span", align: "center" }, itemText),
2906
+ pageText && (React.createElement(Text, { tag: "span", smaller: true, align: "center" }, pageText))),
2907
+ React.createElement("div", { className: controlStyles }, props.rightControls),
2908
+ React.createElement(Button, { className: buttonStyles, disabled: !canGoNext, onClick: () => props.page(1), variant: "icon" },
2909
+ React.createElement(Icon, { id: "pagerRight" }))));
2910
+ };
2911
+
2912
+ const BoundMemoryPager = (p) => {
2913
+ var _a, _b, _c;
2914
+ const { pager, showPageText } = p, rest = __rest(p, ["pager", "showPageText"]);
2915
+ return (React.createElement(Pager, Object.assign({}, rest, { pageIndex: p.showPageText ? pager.page : undefined, totalPages: p.showPageText ? pager.totalPages : undefined, canGoNext: pager.hasNext, canGoPrevious: pager.hasPrevious, minItem: pager.minItemIndex + 1, maxItem: pager.maxItemIndex + 1, totalItems: pager.totalItems, leftControls: pager.limitOptions.length > 1 && p.onLimit ? (React.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
2916
+ React.createElement(Picker, { type: "select", value: pager.limit, options: pager.limitOptions, onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: pager.sortOptions.length > 1 && p.onSort ? (React.createElement(Label, { text: (_b = p.sortText) !== null && _b !== void 0 ? _b : 'Sort', orientation: "horizontalReverse" },
2917
+ React.createElement(Picker, { type: "select", value: (_c = pager.sort) !== null && _c !== void 0 ? _c : '', options: pager.sortOptions, onChange: v => { var _a; return (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, page: d => {
2918
+ p.onPage(d);
2919
+ } })));
2920
+ };
2921
+
2922
+ const BoundStaticPager = (p) => {
2923
+ var _a, _b, _c, _d, _e, _f;
2924
+ const { result, showPageText } = p, rest = __rest(p, ["result", "showPageText"]);
2925
+ const showLimit = !!(result.limit && p.limitOptions && p.limitOptions.length > 1 && p.onLimit);
2926
+ const showSort = !!(p.sort !== undefined && p.sortOptions && p.sortOptions.length > 1 && p.onSort);
2927
+ return (React.createElement(Pager, Object.assign({}, rest, { pageIndex: p.showPageText ? result.page : undefined, totalPages: p.showPageText ? result.totalPages : undefined, canGoNext: result.hasNext, canGoPrevious: result.hasPrevious, minItem: result.minPageItemIndex + 1, maxItem: result.maxPageItemIndex + 1, totalItems: result.total, leftControls: showLimit ? (React.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
2928
+ React.createElement(Picker, { type: "select", value: (_b = result.limit) !== null && _b !== void 0 ? _b : 1, options: (_c = p.limitOptions) !== null && _c !== void 0 ? _c : [1], onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: showSort ? (React.createElement(Label, { text: (_d = p.sortText) !== null && _d !== void 0 ? _d : 'Sort', orientation: "horizontalReverse" },
2929
+ React.createElement(Picker, { type: "select", value: (_e = p.sort) !== null && _e !== void 0 ? _e : '', options: (_f = p.sortOptions) !== null && _f !== void 0 ? _f : [], onChange: v => {
2930
+ var _a;
2931
+ (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v);
2932
+ } }))) : undefined, page: d => {
2933
+ p.onPage(d);
2934
+ } })));
2935
+ };
2936
+
2937
+ class PagedResult {
2938
+ constructor(items = [], total = 0, page = 0, limit = 0) {
2939
+ this.items = items;
2940
+ this.page = page;
2941
+ this.limit = limit;
2942
+ this.total = total;
2943
+ }
2944
+ static fromDto(dto) {
2945
+ return new PagedResult(dto.items, dto.total, dto.page, dto.limit);
2946
+ }
2947
+ // allItems: T[]
2948
+ // get pageItems(): T[] {
2949
+ // return this.allItems.slice(this.minPageItemIndex, this.maxPageItemIndex + 1)
2950
+ // }
2951
+ /** Helper for items.length */
2952
+ get length() {
2953
+ return this.items ? this.items.length : 0;
2954
+ }
2955
+ get hasItems() {
2956
+ return !!this.length;
2957
+ }
2958
+ get previousPage() {
2959
+ return Math.max(this.page - 1, 0);
2960
+ }
2961
+ get hasPrevious() {
2962
+ return this.previousPage !== this.page;
2963
+ }
2964
+ get nextPage() {
2965
+ if (!this.total || !this.limit) {
2966
+ return 0;
2967
+ }
2968
+ return Math.min(this.page + 1, this.lastPage);
2969
+ }
2970
+ get hasNext() {
2971
+ return this.page !== this.lastPage;
2972
+ }
2973
+ get lastPage() {
2974
+ return Math.max(this.totalPages - 1, 0);
2975
+ }
2976
+ get totalPages() {
2977
+ if (!this.total || !this.limit) {
2978
+ return 0;
2979
+ }
2980
+ return Math.floor(this.total / this.limit) + (this.total % this.limit ? 1 : 0);
2981
+ }
2982
+ get minPageItemIndex() {
2983
+ if (!this.total || !this.limit) {
2984
+ return 0;
2985
+ }
2986
+ return this.page * this.limit;
2987
+ }
2988
+ get maxPageItemIndex() {
2989
+ if (!this.total || !this.limit) {
2990
+ return 0;
2991
+ }
2992
+ return Math.min(this.minPageItemIndex + this.limit - 1, this.total - 1);
2993
+ }
2994
+ /** Returns the first item on the current page. */
2995
+ get firstPageItem() {
2996
+ return this.items[0];
2997
+ }
2998
+ /** Returns the last item on the current page */
2999
+ get lastPageItem() {
3000
+ return this.items[this.items.length - 1];
3001
+ }
3002
+ getPageRelativeItemIndex(item) {
3003
+ return this.items.indexOf(item);
3004
+ }
3005
+ getResultRelativeItemIndex(item) {
3006
+ const index = this.getPageRelativeItemIndex(item);
3007
+ if (index >= 0) {
3008
+ return this.getPageRelativeItemIndex(item) + this.limit * this.page;
3009
+ }
3010
+ return undefined;
3011
+ }
3012
+ getPreviousItem(fromItem) {
3013
+ const index = this.getPageRelativeItemIndex(fromItem);
3014
+ if (index <= 0) {
3015
+ return undefined;
3016
+ }
3017
+ return this.items[index - 1];
3018
+ }
3019
+ getNextItem(fromItem) {
3020
+ const index = this.getPageRelativeItemIndex(fromItem);
3021
+ if (index < 0) {
3022
+ return undefined;
3023
+ }
3024
+ return this.items[index + 1];
3025
+ }
3026
+ getPagingRange(radius) {
3027
+ const minItems = radius * 2 + 1;
3028
+ const indexes = [];
3029
+ let startIndex = 0;
3030
+ let endIndex = 0;
3031
+ if (this.totalPages > minItems) {
3032
+ startIndex = this.page - radius;
3033
+ endIndex = this.page + radius;
3034
+ if (endIndex > this.lastPage) {
3035
+ startIndex -= endIndex - this.lastPage;
3036
+ endIndex = this.lastPage;
3037
+ }
3038
+ }
3039
+ else {
3040
+ startIndex = 0;
3041
+ endIndex = this.lastPage;
3042
+ }
3043
+ for (let i = startIndex; i <= endIndex; i++) {
3044
+ if (i < 0) {
3045
+ endIndex++;
3046
+ }
3047
+ else {
3048
+ indexes.push(i);
3049
+ }
3050
+ }
3051
+ return indexes;
3052
+ }
3053
+ toJSON() {
3054
+ const json = {
3055
+ items: this.items.map(item => {
3056
+ if (typeof item === 'object') {
3057
+ if ('toJSON' in item) {
3058
+ return item.toJSON();
3059
+ }
3060
+ }
3061
+ return item;
3062
+ }),
3063
+ page: this.page,
3064
+ limit: this.limit,
3065
+ total: this.total
3066
+ };
3067
+ return json;
3068
+ }
3069
+ clone(newItems) {
3070
+ return new PagedResult(newItems || this.items.slice(), this.total, this.page, this.limit);
3071
+ }
3072
+ }
3073
+
3074
+ /** For in-memory paging. */
3075
+ class ItemPager {
3076
+ constructor(allItems, options) {
3077
+ var _a, _b, _c, _d;
3078
+ this._page = 0;
3079
+ this._allItems = allItems || [];
3080
+ this._limitOptions = ((_a = options === null || options === void 0 ? void 0 : options.previous) === null || _a === void 0 ? void 0 : _a.limitOptions) || (options === null || options === void 0 ? void 0 : options.limitOptions) || [10];
3081
+ this._limit = ((_b = options === null || options === void 0 ? void 0 : options.previous) === null || _b === void 0 ? void 0 : _b.limit) || (options === null || options === void 0 ? void 0 : options.limit) || 10;
3082
+ this._filteredItems = [...allItems];
3083
+ this._pageResult = this.createPageResult();
3084
+ this._sortOptions = ((_c = options === null || options === void 0 ? void 0 : options.previous) === null || _c === void 0 ? void 0 : _c.sortOptions) || (options === null || options === void 0 ? void 0 : options.sortOptions) || [];
3085
+ this.sort = ((_d = options === null || options === void 0 ? void 0 : options.previous) === null || _d === void 0 ? void 0 : _d.sort) || (options === null || options === void 0 ? void 0 : options.sort);
3086
+ if (options === null || options === void 0 ? void 0 : options.previous) {
3087
+ if (options.previous._currentFilter) {
3088
+ this.applyFilter(options.previous._currentFilter);
3089
+ }
3090
+ this.page = options.previous.page;
3091
+ }
3092
+ }
3093
+ get allItems() {
3094
+ return this._allItems;
3095
+ }
3096
+ /** The ID of the current sort within the sortOptions. */
3097
+ get sort() {
3098
+ return this._sort;
3099
+ }
3100
+ set sort(sortId) {
3101
+ const option = this._sortOptions.find(o => o.id === sortId);
3102
+ if (!option) {
3103
+ return;
3104
+ }
3105
+ this._sort = sortId;
3106
+ this._allItems = option.sort(this._allItems);
3107
+ this._filteredItems = option.sort(this._filteredItems);
3108
+ this.page = 0;
3109
+ }
3110
+ /** The direction of the current sort when using an option created from addToggleSortOption */
3111
+ get sortDirection() {
3112
+ if (!this.sort) {
3113
+ return undefined;
3114
+ }
3115
+ const [, direction] = this.sort.split('-');
3116
+ return direction;
3117
+ }
3118
+ get sortOptions() {
3119
+ return this._sortOptions;
3120
+ }
3121
+ get limit() {
3122
+ return this._limit;
3123
+ }
3124
+ set limit(value) {
3125
+ if (value >= 0) {
3126
+ this._limit = value;
3127
+ this.page = 0;
3128
+ }
3129
+ }
3130
+ get limitOptions() {
3131
+ return this._limitOptions;
3132
+ }
3133
+ get totalPages() {
3134
+ return this._pageResult.totalPages;
3135
+ }
3136
+ /** The zero-based page index. */
3137
+ get page() {
3138
+ return this._page;
3139
+ }
3140
+ /** The zero-based page index. */
3141
+ set page(value) {
3142
+ if (value >= 0) {
3143
+ this._page = Math.min(value, this._pageResult.lastPage);
3144
+ this._pageResult = this.createPageResult();
3145
+ }
3146
+ }
3147
+ get pageItems() {
3148
+ return this._pageResult.items;
3149
+ }
3150
+ get totalItems() {
3151
+ return this._pageResult.total;
3152
+ }
3153
+ get minItemIndex() {
3154
+ return this._pageResult.minPageItemIndex;
3155
+ }
3156
+ get maxItemIndex() {
3157
+ return this._pageResult.maxPageItemIndex;
3158
+ }
3159
+ get hasNext() {
3160
+ return this._pageResult.hasNext;
3161
+ }
3162
+ get hasPrevious() {
3163
+ return this._pageResult.hasPrevious;
3164
+ }
3165
+ /**
3166
+ * Adds both asc and des sort options
3167
+ *
3168
+ * @param propPath Prop name or path ('resource.title').
3169
+ * @param name Name to display or asc Name and desc Name.
3170
+ */
3171
+ addToggleSortOption(propPath, name) {
3172
+ if (!this._sortOptions) {
3173
+ this._sortOptions = [];
3174
+ }
3175
+ const sort = (item) => {
3176
+ const value = get(item, propPath);
3177
+ if (typeof value === 'string') {
3178
+ return value.toLocaleLowerCase();
3179
+ }
3180
+ return value;
3181
+ };
3182
+ let ascName;
3183
+ let descName;
3184
+ if (name) {
3185
+ if (Array.isArray(name)) {
3186
+ ascName = name[0];
3187
+ descName = name[1];
3188
+ }
3189
+ else {
3190
+ ascName = name;
3191
+ descName = name;
3192
+ }
3193
+ }
3194
+ this._sortOptions.push({ id: `${propPath}-asc`, name: ascName, sort: (items) => orderBy(items, sort, 'asc') });
3195
+ this._sortOptions.push({ id: `${propPath}-desc`, name: descName, sort: (items) => orderBy(items, sort, 'desc') });
3196
+ }
3197
+ /**
3198
+ * Toggles between asc and desc.
3199
+ * @param sortId The ID or partial ID (no '-asc' or '-desc') of a sort option created through addToggleSortOption
3200
+ */
3201
+ toggleSort(sortId) {
3202
+ const [id,] = sortId.split('-');
3203
+ let nextSort;
3204
+ if (!this.sort || !this.sort.startsWith(id)) {
3205
+ nextSort = `${id}-asc`;
3206
+ }
3207
+ else {
3208
+ if (this.sort.endsWith('-asc')) {
3209
+ nextSort = `${id}-desc`;
3210
+ }
3211
+ else {
3212
+ nextSort = `${id}-asc`;
3213
+ }
3214
+ }
3215
+ this.sort = nextSort;
3216
+ }
3217
+ applyFilter(filter, keepPage) {
3218
+ this._currentFilter = filter;
3219
+ if (!this._currentFilter) {
3220
+ this._filteredItems = [...this.allItems];
3221
+ }
3222
+ else {
3223
+ this._filteredItems = this.allItems.filter(this._currentFilter);
3224
+ }
3225
+ if (!keepPage) {
3226
+ this.page = 0;
3227
+ }
3228
+ else {
3229
+ // recreate the page results manually since we're not resetting the page
3230
+ this._pageResult = this.createPageResult();
3231
+ }
3232
+ }
3233
+ next() {
3234
+ if (this._pageResult.hasNext) {
3235
+ this.page = this._pageResult.nextPage;
3236
+ }
3237
+ }
3238
+ previous() {
3239
+ if (this._pageResult.hasPrevious) {
3240
+ this.page = this._pageResult.previousPage;
3241
+ }
3242
+ }
3243
+ pageByOffset(direction) {
3244
+ if (direction === 1) {
3245
+ this.next();
3246
+ }
3247
+ else {
3248
+ this.previous();
3249
+ }
3250
+ }
3251
+ /** Adds the item optionally keeping the current page. */
3252
+ add(item, position = 'end', keepPage = true) {
3253
+ if (position === 'start') {
3254
+ this._allItems.unshift(item);
3255
+ }
3256
+ else {
3257
+ this._allItems.push(item);
3258
+ }
3259
+ this.applyFilter(this._currentFilter, keepPage);
3260
+ }
3261
+ /** Removes the matched item(s). */
3262
+ remove(comparer, keepPage = true) {
3263
+ this._allItems = this.allItems.filter(i => comparer(i) === false);
3264
+ this.applyFilter(this._currentFilter, keepPage);
3265
+ if (!this.pageItems.length) {
3266
+ this.pageByOffset(-1);
3267
+ }
3268
+ }
3269
+ replace(newItem, comparer) {
3270
+ this.allItems.forEach((item, i) => {
3271
+ if (comparer && comparer(item)) {
3272
+ this.allItems[i] = newItem;
3273
+ }
3274
+ });
3275
+ this.applyFilter(this._currentFilter, true);
3276
+ }
3277
+ createPageResult() {
3278
+ const page = new PagedResult([], this._filteredItems.length, this.page, this.limit);
3279
+ page.items = this._filteredItems.slice(page.minPageItemIndex, page.maxPageItemIndex + 1) || [];
3280
+ return page;
3281
+ }
3282
+ }
3283
+
3284
+ const ProgressBar = (props) => {
3285
+ const bar = React.useRef(null);
3286
+ React.useEffect(() => {
3287
+ const pct = cleanPct(props.pct);
3288
+ if (bar.current) {
3289
+ bar.current.style.width = `${pct}%`;
3290
+ }
3291
+ });
3292
+ const theme = useThemeSafely();
3293
+ const barStyles = css `
3294
+ width: 100%;
3295
+ height: 1rem;
3296
+ border: ${theme.controls.border};
3297
+ background-color: ${theme.colors.progressBg};
3298
+ ${props.round && `
3299
+ border-radius: 1rem;
3300
+ `}
3301
+ `;
3302
+ const fillStyles = css `
3303
+ transition: width 0.5s ease-in-out;
3304
+ height: 100%;
3305
+ background-color: ${theme.colors.progressFill};
3306
+ ${props.round && `
3307
+ border-radius: 1rem;
3308
+ `}
3309
+ `;
3310
+ return (React.createElement("div", { className: "progressBar" },
3311
+ React.createElement("div", { className: cx(barStyles, props.className) },
3312
+ React.createElement("div", { ref: bar, className: fillStyles })),
3313
+ props.showPct && React.createElement(Text, { align: "center", tag: "div", spacedOut: true },
3314
+ props.pct,
3315
+ "\u00A0%")));
3316
+ };
3317
+ const cleanPct = (value) => {
3318
+ if (value) {
3319
+ return Math.min(Math.max(value, 0), 100);
3320
+ }
3321
+ return 0;
3322
+ };
3323
+
3324
+ const useWaiting = (func) => {
3325
+ // Guard against the owner of this hook being unmounted at the time of .finally.
3326
+ const isCancelled = useRef(false);
3327
+ const [waiting, setWaiting] = useState(false);
3328
+ const wrappedFunc = (...args) => {
3329
+ setWaiting(true);
3330
+ return func(...args).finally(() => {
3331
+ if (!isCancelled.current) {
3332
+ setWaiting(false);
3333
+ }
3334
+ });
3335
+ };
3336
+ useEffect(() => {
3337
+ isCancelled.current = false;
3338
+ return () => {
3339
+ isCancelled.current = true;
3340
+ };
3341
+ }, []);
3342
+ return [waiting, wrappedFunc];
3343
+ };
3344
+
3345
+ const SearchBox = (props) => {
3346
+ const [waiting, onSubmit] = useWaiting(async () => {
3347
+ var _a, _b, _c;
3348
+ // the active element will be the input. if the submit action changes props.value it will
3349
+ // be ignored due to Inputs focused handling.
3350
+ if (document.activeElement) {
3351
+ (_b = (_a = document.activeElement).blur) === null || _b === void 0 ? void 0 : _b.call(_a);
3352
+ }
3353
+ return (_c = props.onSubmit) === null || _c === void 0 ? void 0 : _c.call(props);
3354
+ });
3355
+ const theme = useThemeSafely();
3356
+ const submitButton = (React.createElement(Button, { disabled: waiting, readonly: !props.onSubmit, type: "submit", className: css({
3357
+ color: `${theme.colors.font} !important;`,
3358
+ fontSize: '1rem'
3359
+ }), variant: "icon", small: true },
3360
+ React.createElement(Icon, { id: waiting ? 'waiting' : 'search', spin: waiting })));
3361
+ //TB: replace with new inputs
3362
+ return (React.createElement(Form, { role: "search", className: cx('searchBox', props.className), onSubmit: onSubmit },
3363
+ React.createElement(Input, { id: props.id, debounceMs: props.debounceMs, disabled: waiting, type: "text", value: props.value, placeholder: props.placeholder, round: props.round, rounded: props.rounded, onChange: props.onChange, rightControl: submitButton })));
3364
+ };
3365
+
3366
+ const GlobalStyles = () => {
3367
+ const theme = useThemeSafely();
3368
+ injectGlobal({
3369
+ '*': {
3370
+ boxSizing: 'border-box'
3371
+ },
3372
+ 'html,body': {
3373
+ backgroundColor: theme.colors.bg,
3374
+ color: theme.colors.font,
3375
+ margin: 0
3376
+ },
3377
+ 'html,body,main': {
3378
+ height: '100%',
3379
+ fontFamily: theme.fonts.family,
3380
+ fontSize: theme.fonts.size
3381
+ },
3382
+ 'main': {
3383
+ height: 'auto',
3384
+ minHeight: '100%',
3385
+ padding: '0 1rem'
3386
+ },
3387
+ 'pre': {
3388
+ backgroundColor: theme.colors.lightBg
3389
+ }
3390
+ });
3391
+ return null;
3392
+ };
3393
+
3394
+ const Slider = (p) => {
3395
+ const theme = useThemeSafely();
3396
+ const currentValue = useRef(p.value);
3397
+ const sliderContainer = useRef(null);
3398
+ const height = p.showValue ? `calc(${theme.controls.height} + 1.5rem)` : theme.controls.height;
3399
+ return (React__default.createElement("div", { ref: sliderContainer, className: css({
3400
+ width: '100%',
3401
+ height,
3402
+ }) },
3403
+ React__default.createElement(ReactSlider, { step: p.step, min: p.min, max: p.max, value: p.value, onAfterChange: (value, index) => {
3404
+ p.onChange(value);
3405
+ }, onChange: p.onUpdate || p.showValue ? (value, index) => {
3406
+ var _a;
3407
+ currentValue.current = value;
3408
+ (_a = p.onUpdate) === null || _a === void 0 ? void 0 : _a.call(p, value);
3409
+ } : undefined, renderTrack: (props, state) => {
3410
+ const { className } = props, rest = __rest(props, ["className"]);
3411
+ return React__default.createElement("div", Object.assign({ className: cx(className, css({
3412
+ display: 'flex',
3413
+ alignItems: 'center',
3414
+ height: theme.controls.height
3415
+ })) }, rest),
3416
+ React__default.createElement("div", { className: css({
3417
+ backgroundColor: theme.colors.secondary,
3418
+ height: `calc(${theme.controls.height} / 4)`,
3419
+ borderRadius: theme.controls.roundRadius,
3420
+ width: '100%'
3421
+ }) }));
3422
+ }, renderThumb: (props, state) => {
3423
+ const { className } = props, rest = __rest(props, ["className"]);
3424
+ return (React__default.createElement("div", Object.assign({ className: cx(className, css({
3425
+ width: theme.controls.height,
3426
+ height: theme.controls.height,
3427
+ borderRadius: theme.controls.roundRadius,
3428
+ backgroundColor: 'white',
3429
+ border: theme.controls.border,
3430
+ cursor: 'grab',
3431
+ boxShadow: theme.controls.boxShadow,
3432
+ transition: theme.controls.transition,
3433
+ '&:focus': {
3434
+ outline: 'none',
3435
+ boxShadow: theme.controls.focusOutlineShadow
3436
+ },
3437
+ '&:active': {
3438
+ boxShadow: 'none',
3439
+ cursor: 'grabbing'
3440
+ },
3441
+ '&:hover': {
3442
+ filter: theme.controls.hoverBrightness
3443
+ }
3444
+ })) }, rest), p.showValue && (React__default.createElement(HandleText, { index: state.index, parentElement: sliderContainer.current, value: Array.isArray(currentValue.current) ? currentValue.current[state.index] : currentValue.current, renderValue: p.renderValue, renderValueWidth: p.renderValueWidth }))));
3445
+ } })));
3446
+ };
3447
+ const rectsCollideX = (r1, r2) => {
3448
+ if (r1.left >= r2.left && r1.left <= r2.right) {
3449
+ return true;
3450
+ }
3451
+ if (r1.right >= r2.left && r1.right <= r2.right) {
3452
+ return true;
3453
+ }
3454
+ return false;
3455
+ };
3456
+ const HandleText = (p) => {
3457
+ var _a, _b, _c;
3458
+ const theme = useThemeSafely();
3459
+ const displayValue = (_b = (_a = p.renderValue) === null || _a === void 0 ? void 0 : _a.call(p, p.value)) !== null && _b !== void 0 ? _b : p.value;
3460
+ const renderValueWidth = (_c = p.renderValueWidth) !== null && _c !== void 0 ? _c : theme.controls.height;
3461
+ const renderValueLeft = useMemo(() => {
3462
+ return `calc(${renderValueWidth} * 0.5 * -1 + (${theme.controls.height} * 0.5))`;
3463
+ }, [p.renderValueWidth]);
3464
+ const [flipText, setFlipText] = useState(false);
3465
+ useEffect(() => {
3466
+ // this needs to fire on every render due to the other handle also moving.
3467
+ var _a, _b;
3468
+ if (p.index === 1) {
3469
+ // only do this for the max/right-most handle
3470
+ const [r1, r2] = Array.from((_b = (_a = p.parentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.slider-handle').values()) !== null && _b !== void 0 ? _b : []).map(e => e.getBoundingClientRect());
3471
+ if (r1 && r2) {
3472
+ setFlipText(rectsCollideX(r1, r2));
3473
+ }
3474
+ }
3475
+ });
3476
+ return (React__default.createElement(Text, { ellipsis: true, className: cx('slider-handle', css({
3477
+ width: renderValueWidth,
3478
+ left: renderValueLeft,
3479
+ top: flipText ? undefined : theme.controls.height,
3480
+ bottom: flipText ? theme.controls.height : undefined,
3481
+ position: 'absolute',
3482
+ overflow: 'hidden',
3483
+ })), tag: "div", align: "center" }, displayValue));
3484
+ };
3485
+
3486
+ const TabHeader = (p) => {
3487
+ var _a;
3488
+ const [tabIndex, setTabIndex] = React.useState(0);
3489
+ const theme = useThemeSafely();
3490
+ const variant = (_a = p.variant) !== null && _a !== void 0 ? _a : 'tab';
3491
+ const menuStyles = css({
3492
+ display: 'flex',
3493
+ gap: theme.controls.gap,
3494
+ listStyleType: 'none',
3495
+ margin: 0,
3496
+ padding: 0,
3497
+ flexWrap: variant === 'button' ? 'wrap' : 'nowrap'
3498
+ }, variant === 'button' && {
3499
+ borderBottom: theme.controls.border,
3500
+ paddingBottom: '1rem'
3501
+ });
3502
+ return (React.createElement("div", { className: "tabHeader" },
3503
+ React.createElement("ul", { className: menuStyles }, p.tabs.map((tab, index) => {
3504
+ var _a, _b;
3505
+ const active = index === tabIndex;
3506
+ let tabStyles;
3507
+ let buttonStyles;
3508
+ let buttonVariant;
3509
+ if (variant === 'tab') {
3510
+ tabStyles = css({
3511
+ paddingLeft: '1rem',
3512
+ paddingRight: '1rem',
3513
+ backgroundColor: theme.colors.bg,
3514
+ zIndex: 1,
3515
+ }, active && {
3516
+ border: theme.controls.border,
3517
+ borderRadius: theme.controls.borderRadius,
3518
+ borderBottomLeftRadius: 0,
3519
+ borderBottomRightRadius: 0,
3520
+ borderBottom: 'none',
3521
+ zIndex: 3,
3522
+ }, active && p.rounded && {
3523
+ borderRadius: p.rounded && theme.controls.roundedRadius,
3524
+ borderBottomLeftRadius: 0,
3525
+ borderBottomRightRadius: 0,
3526
+ });
3527
+ buttonVariant = 'link';
3528
+ buttonStyles = css({
3529
+ maxWidth: (_a = p.maxTabWidth) !== null && _a !== void 0 ? _a : '10rem',
3530
+ overflow: 'hidden'
3531
+ });
3532
+ }
3533
+ else {
3534
+ buttonVariant = active ? 'primary' : undefined;
3535
+ buttonStyles = css({
3536
+ paddingLeft: '1rem',
3537
+ paddingRight: '1rem',
3538
+ maxWidth: (_b = p.maxTabWidth) !== null && _b !== void 0 ? _b : '10rem',
3539
+ overflow: 'hidden',
3540
+ });
3541
+ }
3542
+ return (React.createElement("li", { key: index, className: tabStyles },
3543
+ React.createElement(Button, { className: buttonStyles, variant: buttonVariant, title: tab.name, readonly: active, rounded: p.rounded && variant === 'button', onClick: () => {
3544
+ setTabIndex(index);
3545
+ if (p.onTabChanged) {
3546
+ p.onTabChanged(index);
3547
+ }
3548
+ } }, tab.name)));
3549
+ })),
3550
+ variant === 'tab' && (React.createElement("div", { className: css({
3551
+ borderBottom: theme.controls.border,
3552
+ marginTop: `calc(${theme.controls.borderWidth} * -1)`,
3553
+ zIndex: 2,
3554
+ position: 'relative'
3555
+ }) }))));
3556
+ };
3557
+
3558
+ const Table = (props) => {
3559
+ const theme = useThemeSafely();
3560
+ const tableStyles = css `
3561
+ width: 100%;
3562
+ border-collapse: collapse;
3563
+ ${props.noCellBorder && `
3564
+ .table__td {
3565
+ border-left: none;
3566
+ border-right: none;
3567
+ }
3568
+ `}
3569
+ ${props.altRows && `
3570
+ .table__tr:nth-of-type(even) {
3571
+ background-color: ${theme.colors.lightBg};
3572
+ }
3573
+ `}
3574
+ `;
3575
+ const wrapperStyles = css `
3576
+ width:100%;
3577
+ overflow-y: auto;
3578
+ padding:0 1px; //fixes always showing of the table scroller
3579
+ `;
3580
+ return (React.createElement("div", { className: wrapperStyles },
3581
+ React.createElement("table", { className: cx(tableStyles, props.className) },
3582
+ props.caption && React.createElement("caption", { className: css({
3583
+ fontWeight: 'bold',
3584
+ padding: theme.controls.padding
3585
+ }) }, props.caption),
3586
+ props.children)));
3587
+ };
3588
+ const Tr = (props) => {
3589
+ return (React.createElement("tr", { className: cx('table__tr', props.className) }, props.children));
3590
+ };
3591
+ const Th = (props) => {
3592
+ var _a;
3593
+ let style = props.style;
3594
+ if (props.width) {
3595
+ if (style) {
3596
+ style = Object.assign(Object.assign({}, style), { width: props.width, minWidth: props.width });
3597
+ }
3598
+ else {
3599
+ style = { width: props.width, minWidth: props.width };
3600
+ }
3601
+ }
3602
+ const theme = useThemeSafely();
3603
+ const thStyles = css `
3604
+ border-bottom: ${theme.controls.border};
3605
+ padding: ${theme.controls.padding};
3606
+ font-weight: bold;
3607
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
3608
+ > .button {
3609
+ font-weight: bold;
3610
+ }
3611
+ `;
3612
+ return (React.createElement("th", { className: cx(thStyles, props.className), style: style }, props.children));
3613
+ };
3614
+ const Td = (props) => {
3615
+ var _a;
3616
+ const theme = useThemeSafely();
3617
+ const tdStyles = css `
3618
+ border: ${theme.controls.border};
3619
+ padding: ${theme.controls.padding};
3620
+ vertical-align: middle;
3621
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
3622
+ `;
3623
+ return (React.createElement("td", { colSpan: props.colSpan, style: props.style, className: cx('table__td', tdStyles) }, props.children));
3624
+ };
3625
+
3626
+ const TdCurrency = (props) => {
3627
+ let actualValue = props.value || 0;
3628
+ if (props.cents) {
3629
+ actualValue = actualValue / 100;
3630
+ }
3631
+ const displayValue = actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
3632
+ return (React.createElement(Td, { align: "right" },
3633
+ "$",
3634
+ displayValue));
3635
+ };
3636
+
3637
+ const TdNumber = (props) => {
3638
+ return React.createElement(Td, { align: "right" }, props.value || props.value === 0 ? props.value.toLocaleString() : '');
3639
+ };
3640
+
3641
+ const ThSort = (props) => {
3642
+ let iconId = '';
3643
+ if (props.direction) {
3644
+ if (props.direction === 'asc') {
3645
+ iconId = 'sortAsc';
3646
+ }
3647
+ else {
3648
+ iconId = 'sortDesc';
3649
+ }
3650
+ }
3651
+ let rightContentSpecialJustify = 'center';
3652
+ switch (props.align) {
3653
+ case 'left':
3654
+ rightContentSpecialJustify = 'flex-start';
3655
+ break;
3656
+ case 'right':
3657
+ rightContentSpecialJustify = 'flex-end';
3658
+ break;
3659
+ }
3660
+ return (React.createElement(Th, { align: props.align, style: props.style, width: props.width },
3661
+ React.createElement("div", { className: props.rightContent && css({
3662
+ display: 'flex',
3663
+ alignItems: 'center',
3664
+ justifyContent: rightContentSpecialJustify,
3665
+ gap: '0.5rem'
3666
+ }) },
3667
+ React.createElement(Button, { onClick: props.onClick, variant: "link" },
3668
+ props.text,
3669
+ iconId && React.createElement(Icon, { className: css({
3670
+ marginLeft: '0.5rem'
3671
+ }), id: iconId })),
3672
+ props.rightContent)));
3673
+ };
3674
+
3675
+ const ToggleButton = (props) => {
3676
+ return (React.createElement(Button, { type: "button", className: cx('toggleButton', props.checked && 'toggleButton--checked', props.className, props.checked && props.checkedClassName), rightIcon: props.checked ? props.checkedIcon : props.uncheckedIcon, disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, variant: props.checked ? props.checkedVariant : props.variant, style: props.checked ? props.checkedStyle : props.style, onClick: props.onClick }, props.checked ? props.checkedText : props.uncheckedText));
3677
+ };
3678
+
3679
+ const ToggleButtonGroup = (props) => {
3680
+ const theme = useThemeSafely();
3681
+ const groupStyles = css `
3682
+ display: flex;
3683
+ box-shadow: ${theme.controls.boxShadow};
3684
+ border-radius: ${theme.controls.borderRadius};
3685
+ ${props.round && `
3686
+ border-radius: ${theme.controls.roundRadius};
3687
+ `}
3688
+ `;
3689
+ const buttonStyles = css `
3690
+ flex-grow:1;
3691
+ box-shadow: none;
3692
+ &:nth-of-type(1n+2){
3693
+ margin-left: -1px;
3694
+ }
3695
+ border-radius: 0;
3696
+ &:first-of-type{
3697
+ border-top-left-radius: ${theme.controls.borderRadius};
3698
+ border-bottom-left-radius: ${theme.controls.borderRadius};
3699
+ }
3700
+ &:last-child {
3701
+ border-top-right-radius: ${theme.controls.borderRadius};
3702
+ border-bottom-right-radius: ${theme.controls.borderRadius};
3703
+ }
3704
+ ${props.round && `
3705
+ &:first-of-type{
3706
+ border-top-left-radius: ${theme.controls.roundRadius};
3707
+ border-bottom-left-radius: ${theme.controls.roundRadius};
3708
+ padding-left: 1rem;
3709
+ }
3710
+ &:last-child {
3711
+ border-top-right-radius: ${theme.controls.roundRadius};
3712
+ border-bottom-right-radius: ${theme.controls.roundRadius};
3713
+ padding-right: 1rem;
3714
+ }
3715
+ `}
3716
+ `;
3717
+ return (React.createElement("div", { className: cx('toggleButtonGroup', groupStyles, props.className) }, props.options.map(o => {
3718
+ const active = o.id === props.value;
3719
+ return React.createElement(Button, { style: props.width ? { width: props.width } : undefined, small: props.small, rightIcon: o.rightIcon, key: o.id, tabIndex: active ? -1 : 0, className: cx(css `
3720
+ ${buttonStyles}
3721
+ ${active && `
3722
+ background-color: ${theme.colors.font};
3723
+ color: ${theme.colors.bg};
3724
+ cursor: default;
3725
+ &:hover:not(:disabled) {
3726
+ filter: none;
3727
+ }
3728
+ &:focus {
3729
+ outline: none;
3730
+ box-shadow: none;
3731
+ }
3732
+ `}
3733
+ `, active ? o.activeClass : undefined), disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, onClick: () => {
3734
+ if (active) {
3735
+ return;
3736
+ }
3737
+ props.onChange(o.id);
3738
+ } }, o.name);
3739
+ })));
3740
+ };
3741
+
3742
+ const TogglePasswordInput = (p) => {
3743
+ const [show, setShow] = React.useState(false);
3744
+ //TB: replace with new inputs
3745
+ return (React.createElement(Input, Object.assign({}, p, { type: show ? 'text' : 'password', rightControl: (React.createElement(Button, { small: true, style: {
3746
+ // small button is required here due to the icon pushing outside the boundries of the
3747
+ // parent textbox. increasing the font size here to fill the small button.
3748
+ fontSize: '1rem'
3749
+ }, variant: "icon", onClick: () => {
3750
+ setShow(previous => !previous);
3751
+ } },
3752
+ React.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
3753
+ };
3754
+
3755
+ const WaitingIndicator = (p) => {
3756
+ var _a, _b;
3757
+ const [show, setShow] = useState(p.show);
3758
+ const hideTimer = useRef(0);
3759
+ const lastShowStatus = useRef(false);
3760
+ const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.debug) !== null && _b !== void 0 ? _b : false);
3761
+ if (p.debug) {
3762
+ useEffect(() => {
3763
+ log('mounted');
3764
+ return () => {
3765
+ log('unmounted');
3766
+ };
3767
+ }, []);
3768
+ }
3769
+ useEffect(() => {
3770
+ log('show changed', p.show);
3771
+ // we need to store the 'last props' since props.show will be captured locally and the incorrect
3772
+ // value will display in the timeout below.
3773
+ log('storing lastShowStatus', p.show);
3774
+ lastShowStatus.current = p.show;
3775
+ if (p.show) {
3776
+ log('setShow', true);
3777
+ setShow(true);
3778
+ if (p.minShowTimeMs) {
3779
+ log('staring hideTimer', 'timout in ms:', p.minShowTimeMs);
3780
+ hideTimer.current = window.setTimeout(() => {
3781
+ log('hideTimer complete', 'clearing hideTimer');
3782
+ window.clearTimeout(hideTimer.current);
3783
+ hideTimer.current = 0;
3784
+ // this check is necessary since the show status may have updated again to true.
3785
+ // if so, ignore this timeout since we're already past the min time and we're still
3786
+ // showing the component.
3787
+ if (!lastShowStatus.current) {
3788
+ log('setShow', false);
3789
+ setShow(false);
3790
+ }
3791
+ else {
3792
+ log('ignoring hideTimer handler due to hideTimer ticking');
3793
+ }
3794
+ }, p.minShowTimeMs);
3795
+ }
3796
+ }
3797
+ else {
3798
+ // ignore hiding the component since the min timer is running.
3799
+ if (!hideTimer.current) {
3800
+ log('setShow', false);
3801
+ setShow(false);
3802
+ }
3803
+ else {
3804
+ log('ignoring show change due to hideTimer ticking');
3805
+ }
3806
+ }
3807
+ }, [p.show]);
3808
+ return (React__default.createElement(Modal, { id: p.id, debug: p.debug, className: "waitingIndicator", show: show, noBackground: true },
3809
+ React__default.createElement("div", { className: css({
3810
+ color: 'white',
3811
+ fontSize: '3rem'
3812
+ }) },
3813
+ React__default.createElement(Icon, { id: "waiting", spin: true }))));
3814
+ };
3815
+
3816
+ export { Autocomplete, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, Calendar, Checkbox, ConfirmModal, CopyButton, DateInput, DatePicker, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, Input, ItemPager, Label, List, ListItem, Modal, Nav, NumberInput, OmniLink, PagedResult, Pager, Picker, Popover, ProgressBar, SearchBox, Slider, TabHeader, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextArea, TextInput, Th, ThSort, ThemeProvider, ToggleButton, ToggleButtonGroup, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, enumToEntities, getCurrencyDisplay, getFileSizeDisplay, mergeClassNames, useMediaQuery, useThemeSafely };
3817
+ //# sourceMappingURL=index.esm.js.map