@mackin.com/styleguide 4.2.0

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.
Files changed (3) hide show
  1. package/index.d.ts +938 -0
  2. package/index.js +3126 -0
  3. package/package.json +30 -0
package/index.js ADDED
@@ -0,0 +1,3126 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var react = require('@emotion/react');
4
+ var React = require('react');
5
+ var proRegularSvgIcons = require('@fortawesome/pro-regular-svg-icons');
6
+ var proSolidSvgIcons = require('@fortawesome/pro-solid-svg-icons');
7
+ var proLightSvgIcons = require('@fortawesome/pro-light-svg-icons');
8
+ var reactFontawesome = require('@fortawesome/react-fontawesome');
9
+ var nanoid = require('nanoid');
10
+ var css = require('@emotion/css');
11
+ var lodash = require('lodash');
12
+ var reactTinyPopover = require('react-tiny-popover');
13
+ var dateFns = require('date-fns');
14
+ var reactRouterDom = require('react-router-dom');
15
+ var ReactSlider = require('react-slider');
16
+
17
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
+
19
+ function _interopNamespace(e) {
20
+ if (e && e.__esModule) return e;
21
+ var n = Object.create(null);
22
+ if (e) {
23
+ Object.keys(e).forEach(function (k) {
24
+ if (k !== 'default') {
25
+ var d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: function () {
29
+ return e[k];
30
+ }
31
+ });
32
+ }
33
+ });
34
+ }
35
+ n['default'] = e;
36
+ return Object.freeze(n);
37
+ }
38
+
39
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
40
+ var ReactSlider__default = /*#__PURE__*/_interopDefaultLegacy(ReactSlider);
41
+
42
+ const mergeClassNames = (...classes) => {
43
+ if (!classes) {
44
+ return undefined;
45
+ }
46
+ return classes.filter(c => c).map(c => c).join(' ');
47
+ };
48
+ const getCurrencyDisplay = (value, isCents, denomination = '$') => {
49
+ let actualValue = value || 0;
50
+ if (isCents) {
51
+ actualValue /= 100;
52
+ }
53
+ return `${denomination}${actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
54
+ };
55
+ const noop = () => {
56
+ // lil' noop would be a great rap name. (thanks linter)
57
+ };
58
+
59
+ /** Call this on your theme after messing with the props. It will re-build things that depend on sizes and colors. */
60
+ const calcDynamicThemeProps = (theme) => {
61
+ theme.controls.border = `${theme.controls.borderWidth} solid ${theme.colors.border}`;
62
+ 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}`;
63
+ theme.controls.focusOutlineShadow = `0px 0px 4px 2px ${theme.colors.focusOutline}`;
64
+ theme.controls.focusOutlineRequiredShadow = `0px 0px 4px 2px ${theme.colors.focusOutlineRequired}`;
65
+ theme.controls.dividerBorder = `2px solid ${theme.colors.divider}`;
66
+ };
67
+ const defaultTheme = {
68
+ colors: {
69
+ primary: '#7851a9',
70
+ primaryFont: 'rgba(255, 255, 255, 0.9)',
71
+ primary2: '#007bff',
72
+ primary2Font: 'rgba(255, 255, 255, 0.9)',
73
+ secondary: '#9e9e9e',
74
+ secondary2Font: 'rgba(255, 255, 255, 0.9)',
75
+ info: '#7851a9',
76
+ infoFont: 'rgba(255, 255, 255, 0.9)',
77
+ warning: '#F5AD94',
78
+ warningFont: 'rgba(0, 0, 0, 0.9)',
79
+ positive: '#28a745',
80
+ positiveFont: 'rgba(255, 255, 255, 0.9)',
81
+ negative: '#dc3545',
82
+ negativeFont: 'rgba(255, 255, 255, 0.9)',
83
+ omg: '#dc3545',
84
+ omgFont: 'rgba(255, 255, 255, 0.9)',
85
+ bg: 'white',
86
+ lightBg: 'rgba(0,0,0,.075)',
87
+ font: 'rgba(0, 0, 0, 0.70)',
88
+ header: '#7851a9',
89
+ headerFont: 'rgba(255, 255, 255, 0.9)',
90
+ link: '#007bff',
91
+ border: 'rgba(0, 0, 0, 0.25)',
92
+ divider: 'rgba(0, 0, 0, 0.50)',
93
+ nav: '#7851a9',
94
+ navFont: 'rgba(255, 255, 255, 0.9)',
95
+ focusOutline: 'hsl(155deg 67% 85%)',
96
+ progressBg: '#007bff63',
97
+ progressFill: '#007bff',
98
+ modalBg: 'white',
99
+ disabled: 'rgba(0,0,0,.075)',
100
+ textHighlight: 'hsl(54deg 100% 62%)',
101
+ required: '#dc3545',
102
+ focusOutlineRequired: 'rgb(212 28 89 / 75%)',
103
+ backdrop: 'rgba(0, 0, 0, 0.25)',
104
+ pagerBg: 'rgba(0,0,0,.075)'
105
+ },
106
+ fonts: {
107
+ family: 'Arial, Helvetica, sans-serif',
108
+ size: '16px',
109
+ headerFamily: 'Arial, Helvetica, sans-serif',
110
+ },
111
+ controls: {
112
+ padding: '0.5rem',
113
+ fontSize: '1rem',
114
+ borderWidth: '1px',
115
+ border: ``,
116
+ height: '44px',
117
+ heightSmall: '34px',
118
+ boxShadow: '2px 2px 4px rgba(0, 0, 0, 0.25)',
119
+ hoverBrightness: 'brightness(0.75)',
120
+ transitionDuration: '0.25s',
121
+ transitionEasing: 'ease-in-out',
122
+ transition: '',
123
+ focusOutlineShadow: '',
124
+ focusOutlineRequiredShadow: '',
125
+ roundRadius: '3rem',
126
+ roundedRadius: '0.5rem',
127
+ disabledOpacity: '0.5',
128
+ formButtonMinWidth: '7rem',
129
+ gap: '1rem',
130
+ dividerMargin: '1rem',
131
+ dividerBorder: '',
132
+ headerBoxShadow: '0px 2px 12px 6px rgba(0, 0, 0, 0.2)'
133
+ },
134
+ zIndexes: {
135
+ header: 50,
136
+ backdrop: 100,
137
+ nav: 110,
138
+ flyout: 120,
139
+ modal: 130,
140
+ tooltip: 1000
141
+ },
142
+ layout: {
143
+ headerHeight: '74px',
144
+ headerBodyOffset: '2rem',
145
+ navWidth: '300px'
146
+ },
147
+ breakpoints: {
148
+ desktop: '800px',
149
+ tablet: '768px'
150
+ }
151
+ };
152
+ calcDynamicThemeProps(defaultTheme);
153
+
154
+ const useWaiting = (func) => {
155
+ // Guard against the owner of this hook being unmounted at the time of .finally.
156
+ const isCancelled = React.useRef(false);
157
+ const [waiting, setWaiting] = React.useState(false);
158
+ const wrappedFunc = (...args) => {
159
+ setWaiting(true);
160
+ return func(...args).finally(() => {
161
+ if (!isCancelled.current) {
162
+ setWaiting(false);
163
+ }
164
+ });
165
+ };
166
+ React.useEffect(() => {
167
+ isCancelled.current = false;
168
+ return () => {
169
+ isCancelled.current = true;
170
+ };
171
+ }, []);
172
+ return [waiting, wrappedFunc];
173
+ };
174
+ /** Returns a user-provided theme if ThemeProvider was used correctly, or the default theme. */
175
+ const useThemeSafely = () => {
176
+ const theme = react.useTheme();
177
+ // Check for expected prop. If not present, the user did not wrap the app in ThemeProvider
178
+ // OR did not pass the default theme as the base.
179
+ if (theme && theme.breakpoints) {
180
+ return theme;
181
+ }
182
+ return defaultTheme;
183
+ };
184
+
185
+ /** @jsx jsx */
186
+ const Table = (props) => {
187
+ const theme = useThemeSafely();
188
+ const tableStyles = react.css `
189
+ width: 100%;
190
+ border-collapse: collapse;
191
+ ${props.noCellBorder && `
192
+ .table__td {
193
+ border-left: none;
194
+ border-right: none;
195
+ }
196
+ `}
197
+ ${props.altRows && `
198
+ .table__tr:nth-of-type(even) {
199
+ background-color: ${theme.colors.lightBg};
200
+ }
201
+ `}
202
+ `;
203
+ const wrapperStyles = react.css `
204
+ width:100%;
205
+ overflow-y: auto;
206
+ padding:0 1px; //fixes always showing of the table scroller
207
+ `;
208
+ return (react.jsx("div", { css: wrapperStyles },
209
+ react.jsx("table", { css: tableStyles, className: props.className },
210
+ props.caption && react.jsx("caption", { css: {
211
+ fontWeight: 'bold',
212
+ padding: theme.controls.padding
213
+ } }, props.caption),
214
+ props.children)));
215
+ };
216
+ const Tr = (props) => {
217
+ return (react.jsx("tr", { className: mergeClassNames('table__tr', props.className) }, props.children));
218
+ };
219
+ const Th = (props) => {
220
+ var _a;
221
+ let style = props.style;
222
+ if (props.width) {
223
+ if (style) {
224
+ style = Object.assign(Object.assign({}, style), { width: props.width, minWidth: props.width });
225
+ }
226
+ else {
227
+ style = { width: props.width, minWidth: props.width };
228
+ }
229
+ }
230
+ const theme = useThemeSafely();
231
+ const thStyles = react.css `
232
+ border-bottom: ${theme.controls.border};
233
+ padding: ${theme.controls.padding};
234
+ font-weight: bold;
235
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
236
+ > .button {
237
+ font-weight: bold;
238
+ }
239
+ `;
240
+ return (react.jsx("th", { css: thStyles, className: props.className, style: style }, props.children));
241
+ };
242
+ const Td = (props) => {
243
+ var _a;
244
+ const theme = useThemeSafely();
245
+ const tdStyles = react.css `
246
+ border: ${theme.controls.border};
247
+ padding: ${theme.controls.padding};
248
+ vertical-align: middle;
249
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
250
+ `;
251
+ return (react.jsx("td", { colSpan: props.colSpan, css: tdStyles, style: props.style, className: "table__td" }, props.children));
252
+ };
253
+
254
+ const TdCurrency = (props) => {
255
+ let actualValue = props.value || 0;
256
+ if (props.cents) {
257
+ actualValue = actualValue / 100;
258
+ }
259
+ const displayValue = actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
260
+ return (React__namespace.createElement(Td, { align: "right" },
261
+ "$",
262
+ displayValue));
263
+ };
264
+
265
+ const TdNumber = (props) => {
266
+ return React__namespace.createElement(Td, { align: "right" }, props.value || props.value === 0 ? props.value.toLocaleString() : '');
267
+ };
268
+
269
+ const ICONS = {
270
+ add: proSolidSvgIcons.faPlus,
271
+ delete: proSolidSvgIcons.faTrashAlt,
272
+ save: proSolidSvgIcons.faSave,
273
+ activate: proRegularSvgIcons.faCheckCircle,
274
+ deactivate: proRegularSvgIcons.faCircle,
275
+ online: proLightSvgIcons.faWifi,
276
+ offline: proLightSvgIcons.faWifiSlash,
277
+ noIcon: proSolidSvgIcons.faCrow,
278
+ close: proSolidSvgIcons.faTimes,
279
+ waiting: proSolidSvgIcons.faSync,
280
+ refresh: proSolidSvgIcons.faSync,
281
+ menu: proLightSvgIcons.faBars,
282
+ search: proLightSvgIcons.faSearch,
283
+ expand: proRegularSvgIcons.faChevronDown,
284
+ collapse: proRegularSvgIcons.faChevronUp,
285
+ help: proLightSvgIcons.faQuestionCircle,
286
+ debug: proLightSvgIcons.faNarwhal,
287
+ goTo: proLightSvgIcons.faChevronRight,
288
+ goBack: proLightSvgIcons.faChevronLeft,
289
+ download: proLightSvgIcons.faCloudDownload,
290
+ upload: proLightSvgIcons.faCloudUpload,
291
+ selected: proLightSvgIcons.faCheckCircle,
292
+ unselected: proLightSvgIcons.faCircle,
293
+ pagerLeft: proLightSvgIcons.faChevronLeft,
294
+ pagerRight: proLightSvgIcons.faChevronRight,
295
+ sortAsc: proRegularSvgIcons.faChevronUp,
296
+ sortDesc: proRegularSvgIcons.faChevronDown,
297
+ pickDate: proLightSvgIcons.faCalendarAlt,
298
+ copy: proLightSvgIcons.faCopy,
299
+ paste: proLightSvgIcons.faPaste,
300
+ clear: proRegularSvgIcons.faTimesCircle,
301
+ hide: proLightSvgIcons.faEyeSlash,
302
+ show: proLightSvgIcons.faEye
303
+ };
304
+ const Icon = (props) => {
305
+ var _a;
306
+ const icon = (_a = ICONS[props.id]) !== null && _a !== void 0 ? _a : ICONS['noIcon'];
307
+ return React__namespace.createElement(reactFontawesome.FontAwesomeIcon, { style: props.style, onClick: props.onClick, spin: props.spin, className: mergeClassNames('icon', props.className), icon: icon });
308
+ };
309
+
310
+ /** @jsx jsx */
311
+ const Button = (props) => {
312
+ var _a;
313
+ const theme = useThemeSafely();
314
+ const buttonStyles = react.css `
315
+ padding-left: ${theme.controls.padding};
316
+ padding-right: ${theme.controls.padding};
317
+ background-color: white;
318
+ border: ${theme.controls.border};
319
+ cursor: pointer;
320
+ box-shadow: ${theme.controls.boxShadow};
321
+ color: ${theme.colors.font};
322
+ height: ${theme.controls.height};
323
+ transition: ${theme.controls.transition};
324
+ font-size: 1rem;
325
+ font-weight: bold;
326
+ flex-shrink: 0;
327
+ min-width: ${theme.controls.height};
328
+ text-align: ${(_a = props.textAlign) !== null && _a !== void 0 ? _a : 'center'};
329
+
330
+ &:disabled {
331
+ opacity: ${theme.controls.disabledOpacity};
332
+ cursor: not-allowed;
333
+ }
334
+
335
+ &:focus {
336
+ outline: none;
337
+ box-shadow: ${theme.controls.focusOutlineShadow};
338
+ position: relative;
339
+ z-index: 2;
340
+ }
341
+
342
+ &:active {
343
+ box-shadow: none;
344
+ }
345
+
346
+ &:hover:not(:disabled) {
347
+ filter: ${theme.controls.hoverBrightness};
348
+ }
349
+ `;
350
+ const styles = react.css `
351
+ ${buttonStyles}
352
+ ${props.variant === 'circle' && `
353
+ width: ${theme.controls.height};
354
+ border-radius: 100%;
355
+ display: flex;
356
+ justify-content: center;
357
+ align-items: center;
358
+ ${props.small && `
359
+ width: ${theme.controls.heightSmall};
360
+ min-width: ${theme.controls.heightSmall};
361
+ `}
362
+ `}
363
+ ${props.variant === 'icon' && `
364
+ width: ${theme.controls.height};
365
+ border-radius: 100%;
366
+ padding: 0;
367
+ box-shadow: none;
368
+ border: none;
369
+ font-size: 1.6rem;
370
+ display: flex;
371
+ justify-content: center;
372
+ align-items: center;
373
+ ${props.small && `
374
+ width: ${theme.controls.heightSmall};
375
+ min-width: ${theme.controls.heightSmall};
376
+ font-size: 1.3rem;
377
+ `}
378
+ `}
379
+ ${props.variant === 'label' && `
380
+ display: inline-block;
381
+ width: auto;
382
+ box-shadow: none;
383
+ border: none;
384
+ `}
385
+ ${props.variant === 'link' && `
386
+ padding: 0;
387
+ display: inline-block;
388
+ width: auto;
389
+ box-shadow: none;
390
+ border: none;
391
+ color: ${theme.colors.link};
392
+ font-weight: normal;
393
+ background-color: transparent;
394
+ &:hover {
395
+ text-decoration: underline;
396
+ }
397
+ &:focus {
398
+ box-shadow: none;
399
+ text-decoration: underline;
400
+ }
401
+ `}
402
+ ${props.variant === 'inlineLink' && `
403
+ padding: 0;
404
+ display: inline-block;
405
+ width: auto;
406
+ box-shadow: none;
407
+ border: none;
408
+ color: ${theme.colors.link};
409
+ font-weight: normal;
410
+ height: auto;
411
+ background-color: transparent;
412
+ &:hover {
413
+ text-decoration: underline;
414
+ }
415
+ &:focus {
416
+ box-shadow: none;
417
+ text-decoration: underline;
418
+ }
419
+ `}
420
+ ${props.variant === 'primary' && `
421
+ background-color: ${theme.colors.primary};
422
+ color: ${theme.colors.primaryFont};
423
+ `}
424
+ ${props.variant === 'primary2' && `
425
+ background-color: ${theme.colors.primary2};
426
+ color: ${theme.colors.primary2Font};
427
+ `}
428
+ ${props.variant === 'secondary' && `
429
+ background-color: ${theme.colors.secondary};
430
+ color: ${theme.colors.secondary2Font};
431
+ `}
432
+ ${props.variant === 'omg' && `
433
+ background-color: ${theme.colors.omg};
434
+ color: ${theme.colors.omgFont};
435
+ `}
436
+ ${props.variant === 'positive' && `
437
+ background-color: ${theme.colors.positive};
438
+ color: ${theme.colors.positiveFont};
439
+ `}
440
+ ${props.variant === 'negative' && `
441
+ background-color: ${theme.colors.negative};
442
+ color: ${theme.colors.negativeFont};
443
+ `}
444
+ ${props.enforceMinWidth && `
445
+ min-width: ${theme.controls.formButtonMinWidth};
446
+ `}
447
+ ${props.readonly && `
448
+ cursor: default;
449
+ box-shadow: none;
450
+ pointer-events:none;
451
+
452
+ &:hover {
453
+ filter:none;
454
+ }
455
+
456
+ &:focus {
457
+ box-shadow: none;
458
+ }
459
+ `}
460
+ ${props.small && `
461
+ font-size: 0.8rem;
462
+ height:${theme.controls.heightSmall};
463
+ `}
464
+ ${props.round && `
465
+ border-radius: ${theme.controls.roundRadius};
466
+ `}
467
+ ${props.rounded && `
468
+ border-radius: ${theme.controls.roundedRadius};
469
+ `}
470
+ ${props.block && `
471
+ width: 100%;
472
+ `}
473
+ ${props.iconBlock && `
474
+ display: flex;
475
+ justify-content: space-between;
476
+ align-items: center;
477
+ `}
478
+ `;
479
+ const disabled = props.disabled || props.waiting;
480
+ return (react.jsx("button", { id: props.id, css: styles, tabIndex: props.tabIndex, title: props.title, disabled: disabled, style: props.style, onClick: props.onClick, className: mergeClassNames('button', props.className), onMouseEnter: props.onMouseEnter, onMouseLeave: props.onMouseLeave, onFocus: props.onFocus, onBlur: props.onBlur, type: props.type || 'button' },
481
+ props.leftIcon && react.jsx("span", { css: { marginRight: '0.5rem' } }, props.leftIcon),
482
+ props.waiting ? react.jsx(Icon, { id: "waiting", spin: true }) : props.children,
483
+ props.rightIcon && react.jsx("span", { css: { marginLeft: '0.5rem' } }, props.rightIcon)));
484
+ };
485
+
486
+ /** @jsx jsx */
487
+ const ThSort = (props) => {
488
+ let iconId = '';
489
+ if (props.direction) {
490
+ if (props.direction === 'asc') {
491
+ iconId = 'sortAsc';
492
+ }
493
+ else {
494
+ iconId = 'sortDesc';
495
+ }
496
+ }
497
+ let rightContentSpecialJustify = 'center';
498
+ switch (props.align) {
499
+ case 'left':
500
+ rightContentSpecialJustify = 'flex-start';
501
+ break;
502
+ case 'right':
503
+ rightContentSpecialJustify = 'flex-end';
504
+ break;
505
+ }
506
+ return (react.jsx(Th, { align: props.align, style: props.style, width: props.width },
507
+ react.jsx("div", { css: props.rightContent && {
508
+ display: 'flex',
509
+ alignItems: 'center',
510
+ justifyContent: rightContentSpecialJustify,
511
+ gap: '0.5rem'
512
+ } },
513
+ react.jsx(Button, { onClick: props.onClick, variant: "link" },
514
+ props.text,
515
+ iconId && react.jsx(Icon, { css: {
516
+ marginLeft: '0.5rem'
517
+ }, id: iconId })),
518
+ props.rightContent)));
519
+ };
520
+
521
+ /*! *****************************************************************************
522
+ Copyright (c) Microsoft Corporation.
523
+
524
+ Permission to use, copy, modify, and/or distribute this software for any
525
+ purpose with or without fee is hereby granted.
526
+
527
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
528
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
529
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
530
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
531
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
532
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
533
+ PERFORMANCE OF THIS SOFTWARE.
534
+ ***************************************************************************** */
535
+
536
+ function __rest(s, e) {
537
+ var t = {};
538
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
539
+ t[p] = s[p];
540
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
541
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
542
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
543
+ t[p[i]] = s[p[i]];
544
+ }
545
+ return t;
546
+ }
547
+
548
+ const tagStyles = {
549
+ 'p': {
550
+ marginTop: '1rem',
551
+ marginBottom: '1rem'
552
+ },
553
+ 'h1': {
554
+ fontSize: '2rem',
555
+ },
556
+ 'h2': {
557
+ fontSize: '1.5rem'
558
+ },
559
+ 'h3': {
560
+ fontSize: '1.17rem' // Chrome default
561
+ },
562
+ 'h4': {
563
+ fontSize: '1rem'
564
+ },
565
+ };
566
+ const headerRegex = /h1|h2|h3|h4/;
567
+ const alignStyles = {
568
+ 'center': { textAlign: 'center' },
569
+ 'left': { textAlign: 'left' },
570
+ 'right': { textAlign: 'right' }
571
+ };
572
+ const Text = (props) => {
573
+ var _a, _b;
574
+ const theme = useThemeSafely();
575
+ const tagChoice = props.tag || 'p';
576
+ const style = props.style || {};
577
+ if (props.lineClamp) {
578
+ style.WebkitLineClamp = props.lineClamp;
579
+ }
580
+ if (props.leftPad) {
581
+ style.paddingLeft = props.leftPad;
582
+ }
583
+ const styles = css.css({
584
+ userSelect: 'text',
585
+ label: 'Text'
586
+ }, tagStyles[tagChoice], alignStyles[(_a = props.align) !== null && _a !== void 0 ? _a : 'left'], props.smaller && { fontSize: '0.7rem' }, props.larger && { fontSize: '1.3rem' }, props.italics && { fontStyle: 'italic' }, props.ellipsis && {
587
+ overflow: 'hidden',
588
+ whiteSpace: 'nowrap',
589
+ textOverflow: 'ellipsis'
590
+ }, props.lineClamp && {
591
+ WebkitBoxOrient: 'vertical',
592
+ overflow: 'hidden',
593
+ textOverflow: 'ellipsis',
594
+ display: '-webkit-box'
595
+ }, 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 : '') && {
596
+ fontFamily: theme.fonts.headerFamily
597
+ });
598
+ return React__namespace.createElement(tagChoice, {
599
+ style: style,
600
+ className: mergeClassNames('text', styles, props.className)
601
+ }, props.children);
602
+ };
603
+
604
+ /** @jsx jsx */
605
+ const Label = (props) => {
606
+ var _a, _b, _c;
607
+ const theme = useThemeSafely();
608
+ const orientation = (_a = props.orientation) !== null && _a !== void 0 ? _a : 'vertical';
609
+ const align = (_b = props.align) !== null && _b !== void 0 ? _b : 'left';
610
+ const padding = '0.25rem';
611
+ const labelStyles = react.css `
612
+ ${padding};
613
+ display: flex;
614
+ ${orientation === 'vertical' && `
615
+ flex-direction: column;
616
+ `}
617
+ ${orientation === 'horizontal' && `
618
+ flex-direction: row;
619
+ align-items: center;
620
+ `}
621
+ ${orientation === 'horizontalReverse' && `
622
+ flex-direction: row-reverse;
623
+ align-items: center;
624
+ `}
625
+ `;
626
+ const labelTextStyles = react.css `
627
+ flex-shrink:0;
628
+ ${orientation === 'vertical' && `
629
+ margin-bottom: ${padding};
630
+ `}
631
+ ${orientation === 'horizontal' && `
632
+ flex-direction: row;
633
+ margin-right:${padding};
634
+ ${props.static && `
635
+ margin-right:0.5rem;
636
+ `}
637
+ `}
638
+ ${orientation === 'horizontalReverse' && `
639
+ margin-left:${padding};
640
+ `}
641
+ ${(props.subText || props.optional) && `
642
+ margin-right: 0.5rem;
643
+ `}
644
+ `;
645
+ const labelContentStyles = react.css `
646
+ display:inline-block;
647
+ width:100%;
648
+ ${props.controlAlign && `
649
+ height:${theme.controls.height};
650
+ line-height:${theme.controls.height};
651
+ `}
652
+ `;
653
+ const className = props.className;
654
+ let labelText = react.jsx(Text, { align: align, css: labelTextStyles, tag: "div", bold: true }, props.text);
655
+ let subText;
656
+ if (props.subText) {
657
+ if (typeof props.subText === 'string') {
658
+ subText = react.jsx(Text, { tag: "div" }, props.subText);
659
+ }
660
+ else {
661
+ subText = props.subText;
662
+ }
663
+ }
664
+ else if (props.optional) {
665
+ subText = react.jsx(Text, { tag: "div" },
666
+ react.jsx("em", null, "(optional)"));
667
+ }
668
+ if (subText) {
669
+ labelText = react.jsx("span", { css: { display: 'flex' } },
670
+ labelText,
671
+ react.jsx("span", { css: { fontSize: '90%' } }, subText));
672
+ }
673
+ if (props.noWrap) {
674
+ return (react.jsx("span", { css: labelStyles, className: className },
675
+ react.jsx("label", { htmlFor: props.htmlFor, className: className }, labelText),
676
+ props.children));
677
+ }
678
+ const content = react.jsx(React__namespace.Fragment, null,
679
+ labelText,
680
+ react.jsx("span", { css: labelContentStyles }, props.children));
681
+ if (props.static) {
682
+ return (react.jsx("span", { css: labelStyles, className: className }, content));
683
+ }
684
+ // labels without htmlFor can cause focus, hover, and click issues when wrapping other elements.
685
+ // this fixes the issues.
686
+ const htmlFor = (_c = props.htmlFor) !== null && _c !== void 0 ? _c : nanoid.nanoid();
687
+ return (react.jsx("label", { htmlFor: htmlFor, css: labelStyles, className: mergeClassNames('label', className) }, content));
688
+ };
689
+
690
+ /** @jsx jsx */
691
+ const Picker = (props) => {
692
+ // if we put numbers in, we expect them out
693
+ let isNumber = false;
694
+ if (props.options && props.options.length) {
695
+ const testOption = props.options[0];
696
+ if (typeof testOption === 'object') {
697
+ isNumber = typeof testOption.id === 'number';
698
+ }
699
+ else {
700
+ isNumber = typeof testOption === 'number';
701
+ }
702
+ }
703
+ const theme = useThemeSafely();
704
+ if (props.type === 'select') {
705
+ const selectStyles = react.css `
706
+ color: ${theme.colors.font};
707
+ padding-left: ${theme.controls.padding};
708
+ padding-right: ${theme.controls.padding};
709
+ height: ${theme.controls.height};
710
+ font-size: ${theme.controls.fontSize};
711
+ width: 100%;
712
+ border: ${theme.controls.border};
713
+ transition: ${theme.controls.transition};
714
+ &:disabled {
715
+ color: ${theme.colors.font};
716
+ opacity: 1;
717
+ background-color: ${theme.colors.disabled};
718
+ cursor: not-allowed;
719
+ }
720
+ &:focus {
721
+ outline: none;
722
+ box-shadow: ${theme.controls.focusOutlineShadow};
723
+ }
724
+ ${props.rounded && `
725
+ border-radius: ${theme.controls.roundedRadius};
726
+ `}
727
+ ${props.readonly && `
728
+ background-color: transparent !important;
729
+ border: none;
730
+ -webkit-appearance: none;
731
+ -moz-appearance: none;
732
+ &:focus {
733
+ outline: none;
734
+ box-shadow: none;
735
+ }
736
+ `}
737
+ `;
738
+ return (react.jsx("select", { tabIndex: props.readonly ? -1 : undefined, disabled: props.disabled, id: props.id, css: selectStyles, className: mergeClassNames('picker', props.className), value: props.value, onKeyDown: e => {
739
+ if (props.readonly) {
740
+ if (e.keyCode === 9) {
741
+ //TAB
742
+ return;
743
+ }
744
+ e.preventDefault();
745
+ e.stopPropagation();
746
+ }
747
+ }, onMouseDown: e => {
748
+ if (props.readonly) {
749
+ e.preventDefault();
750
+ e.stopPropagation();
751
+ }
752
+ }, onChange: e => {
753
+ let value = e.target.value;
754
+ if (isNumber) {
755
+ value = parseInt(value, 10);
756
+ if (isNaN(value)) {
757
+ value = '';
758
+ }
759
+ }
760
+ props.onChange(value);
761
+ } }, (props.options || []).map(o => {
762
+ var _a;
763
+ let value;
764
+ let label;
765
+ if (typeof o === 'object') {
766
+ value = o.id;
767
+ label = (_a = o.name) !== null && _a !== void 0 ? _a : o.id;
768
+ }
769
+ else {
770
+ value = o;
771
+ label = o;
772
+ }
773
+ return react.jsx("option", { key: value, value: value }, label);
774
+ })));
775
+ }
776
+ return null;
777
+ };
778
+
779
+ /** @jsx jsx */
780
+ const Pager = (props) => {
781
+ var _a;
782
+ const canGoNext = props.canGoNext && props.totalItems > 0;
783
+ const canGoPrevious = props.canGoPrevious && props.totalItems > 0;
784
+ const dividerText = props.itemDividerText || 'of';
785
+ let itemText = '';
786
+ if (props.totalItems > 0) {
787
+ itemText = `${props.minItem.toLocaleString()}-${props.maxItem.toLocaleString()} ${dividerText} ${props.totalItems.toLocaleString()}`;
788
+ }
789
+ else {
790
+ itemText = props.noResultsText || 'No Results';
791
+ }
792
+ let pageText;
793
+ if (props.pageIndex !== undefined && props.totalPages) {
794
+ pageText = `${(_a = props.pageText) !== null && _a !== void 0 ? _a : 'Page'} ${(props.pageIndex + 1).toLocaleString()} ${dividerText} ${props.totalPages.toLocaleString()}`;
795
+ }
796
+ const theme = useThemeSafely();
797
+ const pagerStyles = react.css `
798
+ display: grid;
799
+ grid-template-columns: ${theme.controls.height} 1fr ${theme.controls.height};
800
+ grid-column-gap: ${theme.controls.gap};
801
+ border: ${theme.controls.border};
802
+ padding: 0.5rem;
803
+ background-color: ${theme.colors.pagerBg};
804
+ @media(min-width: ${theme.breakpoints.tablet}) {
805
+ grid-template-columns: ${theme.controls.height} 1fr 1fr 1fr ${theme.controls.height};
806
+ }
807
+ ${props.rounded && `
808
+ border-radius: ${theme.controls.roundedRadius};
809
+ `}
810
+ `;
811
+ const controlStyles = react.css `
812
+ display: none;
813
+ padding:0 1rem;
814
+ justify-self: center;
815
+ @media(min-width: ${theme.breakpoints.tablet}) {
816
+ display: block;
817
+ }
818
+ `;
819
+ const buttonStyles = react.css({
820
+ backgroundColor: 'transparent'
821
+ });
822
+ return (react.jsx("div", { css: pagerStyles, className: props.className },
823
+ react.jsx(Button, { css: buttonStyles, disabled: !canGoPrevious, onClick: () => props.page(-1), variant: "icon" },
824
+ react.jsx(Icon, { id: "pagerLeft" })),
825
+ react.jsx("div", { css: controlStyles }, props.leftControls),
826
+ react.jsx("div", { css: {
827
+ alignSelf: 'center',
828
+ justifySelf: 'center',
829
+ display: 'flex',
830
+ gap: '0.5rem',
831
+ flexDirection: 'column'
832
+ } },
833
+ react.jsx(Text, { tag: "span", align: "center" }, itemText),
834
+ pageText && (react.jsx(Text, { tag: "span", smaller: true, align: "center" }, pageText))),
835
+ react.jsx("div", { css: controlStyles }, props.rightControls),
836
+ react.jsx(Button, { css: buttonStyles, disabled: !canGoNext, onClick: () => props.page(1), variant: "icon" },
837
+ react.jsx(Icon, { id: "pagerRight" }))));
838
+ };
839
+
840
+ const BoundMemoryPager = (p) => {
841
+ var _a, _b, _c;
842
+ const { pager, showPageText } = p, rest = __rest(p, ["pager", "showPageText"]);
843
+ return (React__namespace.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__namespace.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
844
+ React__namespace.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__namespace.createElement(Label, { text: (_b = p.sortText) !== null && _b !== void 0 ? _b : 'Sort', orientation: "horizontalReverse" },
845
+ React__namespace.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 => {
846
+ p.onPage(d);
847
+ } })));
848
+ };
849
+
850
+ class PagedResult {
851
+ constructor(items = [], total = 0, page = 0, limit = 0) {
852
+ this.items = items;
853
+ this.page = page;
854
+ this.limit = limit;
855
+ this.total = total;
856
+ }
857
+ static fromDto(dto) {
858
+ return new PagedResult(dto.items, dto.total, dto.page, dto.limit);
859
+ }
860
+ // allItems: T[]
861
+ // get pageItems(): T[] {
862
+ // return this.allItems.slice(this.minPageItemIndex, this.maxPageItemIndex + 1)
863
+ // }
864
+ /** Helper for items.length */
865
+ get length() {
866
+ return this.items ? this.items.length : 0;
867
+ }
868
+ get hasItems() {
869
+ return !!this.length;
870
+ }
871
+ get previousPage() {
872
+ return Math.max(this.page - 1, 0);
873
+ }
874
+ get hasPrevious() {
875
+ return this.previousPage !== this.page;
876
+ }
877
+ get nextPage() {
878
+ if (!this.total || !this.limit) {
879
+ return 0;
880
+ }
881
+ return Math.min(this.page + 1, this.lastPage);
882
+ }
883
+ get hasNext() {
884
+ return this.page !== this.lastPage;
885
+ }
886
+ get lastPage() {
887
+ return Math.max(this.totalPages - 1, 0);
888
+ }
889
+ get totalPages() {
890
+ if (!this.total || !this.limit) {
891
+ return 0;
892
+ }
893
+ return Math.floor(this.total / this.limit) + (this.total % this.limit ? 1 : 0);
894
+ }
895
+ get minPageItemIndex() {
896
+ if (!this.total || !this.limit) {
897
+ return 0;
898
+ }
899
+ return this.page * this.limit;
900
+ }
901
+ get maxPageItemIndex() {
902
+ if (!this.total || !this.limit) {
903
+ return 0;
904
+ }
905
+ return Math.min(this.minPageItemIndex + this.limit - 1, this.total - 1);
906
+ }
907
+ /** Returns the first item on the current page. */
908
+ get firstPageItem() {
909
+ return this.items[0];
910
+ }
911
+ /** Returns the last item on the current page */
912
+ get lastPageItem() {
913
+ return this.items[this.items.length - 1];
914
+ }
915
+ getPageRelativeItemIndex(item) {
916
+ return this.items.indexOf(item);
917
+ }
918
+ getResultRelativeItemIndex(item) {
919
+ const index = this.getPageRelativeItemIndex(item);
920
+ if (index >= 0) {
921
+ return this.getPageRelativeItemIndex(item) + this.limit * this.page;
922
+ }
923
+ return undefined;
924
+ }
925
+ getPreviousItem(fromItem) {
926
+ const index = this.getPageRelativeItemIndex(fromItem);
927
+ if (index <= 0) {
928
+ return undefined;
929
+ }
930
+ return this.items[index - 1];
931
+ }
932
+ getNextItem(fromItem) {
933
+ const index = this.getPageRelativeItemIndex(fromItem);
934
+ if (index < 0) {
935
+ return undefined;
936
+ }
937
+ return this.items[index + 1];
938
+ }
939
+ getPagingRange(radius) {
940
+ const minItems = radius * 2 + 1;
941
+ const indexes = [];
942
+ let startIndex = 0;
943
+ let endIndex = 0;
944
+ if (this.totalPages > minItems) {
945
+ startIndex = this.page - radius;
946
+ endIndex = this.page + radius;
947
+ if (endIndex > this.lastPage) {
948
+ startIndex -= endIndex - this.lastPage;
949
+ endIndex = this.lastPage;
950
+ }
951
+ }
952
+ else {
953
+ startIndex = 0;
954
+ endIndex = this.lastPage;
955
+ }
956
+ for (let i = startIndex; i <= endIndex; i++) {
957
+ if (i < 0) {
958
+ endIndex++;
959
+ }
960
+ else {
961
+ indexes.push(i);
962
+ }
963
+ }
964
+ return indexes;
965
+ }
966
+ toJSON() {
967
+ const json = {
968
+ items: this.items.map(item => {
969
+ if (typeof item === 'object') {
970
+ if ('toJSON' in item) {
971
+ return item.toJSON();
972
+ }
973
+ }
974
+ return item;
975
+ }),
976
+ page: this.page,
977
+ limit: this.limit,
978
+ total: this.total
979
+ };
980
+ return json;
981
+ }
982
+ clone(newItems) {
983
+ return new PagedResult(newItems || this.items.slice(), this.total, this.page, this.limit);
984
+ }
985
+ }
986
+
987
+ /** For in-memory paging. */
988
+ class ItemPager {
989
+ constructor(allItems, options) {
990
+ var _a, _b, _c, _d;
991
+ this._page = 0;
992
+ this._allItems = allItems || [];
993
+ 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];
994
+ 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;
995
+ this._filteredItems = [...allItems];
996
+ this._pageResult = this.createPageResult();
997
+ 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) || [];
998
+ 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);
999
+ if (options === null || options === void 0 ? void 0 : options.previous) {
1000
+ if (options.previous._currentFilter) {
1001
+ this.applyFilter(options.previous._currentFilter);
1002
+ }
1003
+ this.page = options.previous.page;
1004
+ }
1005
+ }
1006
+ get allItems() {
1007
+ return this._allItems;
1008
+ }
1009
+ /** The ID of the current sort within the sortOptions. */
1010
+ get sort() {
1011
+ return this._sort;
1012
+ }
1013
+ set sort(sortId) {
1014
+ const option = this._sortOptions.find(o => o.id === sortId);
1015
+ if (!option) {
1016
+ return;
1017
+ }
1018
+ this._sort = sortId;
1019
+ this._allItems = option.sort(this._allItems);
1020
+ this._filteredItems = option.sort(this._filteredItems);
1021
+ this.page = 0;
1022
+ }
1023
+ /** The direction of the current sort when using an option created from addToggleSortOption */
1024
+ get sortDirection() {
1025
+ if (!this.sort) {
1026
+ return undefined;
1027
+ }
1028
+ const [, direction] = this.sort.split('-');
1029
+ return direction;
1030
+ }
1031
+ get sortOptions() {
1032
+ return this._sortOptions;
1033
+ }
1034
+ get limit() {
1035
+ return this._limit;
1036
+ }
1037
+ set limit(value) {
1038
+ if (value >= 0) {
1039
+ this._limit = value;
1040
+ this.page = 0;
1041
+ }
1042
+ }
1043
+ get limitOptions() {
1044
+ return this._limitOptions;
1045
+ }
1046
+ get totalPages() {
1047
+ return this._pageResult.totalPages;
1048
+ }
1049
+ /** The zero-based page index. */
1050
+ get page() {
1051
+ return this._page;
1052
+ }
1053
+ /** The zero-based page index. */
1054
+ set page(value) {
1055
+ if (value >= 0) {
1056
+ this._page = Math.min(value, this._pageResult.lastPage);
1057
+ this._pageResult = this.createPageResult();
1058
+ }
1059
+ }
1060
+ get pageItems() {
1061
+ return this._pageResult.items;
1062
+ }
1063
+ get totalItems() {
1064
+ return this._pageResult.total;
1065
+ }
1066
+ get minItemIndex() {
1067
+ return this._pageResult.minPageItemIndex;
1068
+ }
1069
+ get maxItemIndex() {
1070
+ return this._pageResult.maxPageItemIndex;
1071
+ }
1072
+ get hasNext() {
1073
+ return this._pageResult.hasNext;
1074
+ }
1075
+ get hasPrevious() {
1076
+ return this._pageResult.hasPrevious;
1077
+ }
1078
+ /**
1079
+ * Adds both asc and des sort options
1080
+ *
1081
+ * @param propPath Prop name or path ('resource.title').
1082
+ * @param name Name to display or asc Name and desc Name.
1083
+ */
1084
+ addToggleSortOption(propPath, name) {
1085
+ if (!this._sortOptions) {
1086
+ this._sortOptions = [];
1087
+ }
1088
+ const sort = (item) => {
1089
+ const value = lodash.get(item, propPath);
1090
+ if (typeof value === 'string') {
1091
+ return value.toLocaleLowerCase();
1092
+ }
1093
+ return value;
1094
+ };
1095
+ let ascName;
1096
+ let descName;
1097
+ if (name) {
1098
+ if (Array.isArray(name)) {
1099
+ ascName = name[0];
1100
+ descName = name[1];
1101
+ }
1102
+ else {
1103
+ ascName = name;
1104
+ descName = name;
1105
+ }
1106
+ }
1107
+ this._sortOptions.push({ id: `${propPath}-asc`, name: ascName, sort: (items) => lodash.orderBy(items, sort, 'asc') });
1108
+ this._sortOptions.push({ id: `${propPath}-desc`, name: descName, sort: (items) => lodash.orderBy(items, sort, 'desc') });
1109
+ }
1110
+ /**
1111
+ * Toggles between asc and desc.
1112
+ * @param sortId The ID or partial ID (no '-asc' or '-desc') of a sort option created through addToggleSortOption
1113
+ */
1114
+ toggleSort(sortId) {
1115
+ const [id,] = sortId.split('-');
1116
+ let nextSort;
1117
+ if (!this.sort || !this.sort.startsWith(id)) {
1118
+ nextSort = `${id}-asc`;
1119
+ }
1120
+ else {
1121
+ if (this.sort.endsWith('-asc')) {
1122
+ nextSort = `${id}-desc`;
1123
+ }
1124
+ else {
1125
+ nextSort = `${id}-asc`;
1126
+ }
1127
+ }
1128
+ this.sort = nextSort;
1129
+ }
1130
+ applyFilter(filter, keepPage) {
1131
+ this._currentFilter = filter;
1132
+ if (!this._currentFilter) {
1133
+ this._filteredItems = [...this.allItems];
1134
+ }
1135
+ else {
1136
+ this._filteredItems = this.allItems.filter(this._currentFilter);
1137
+ }
1138
+ if (!keepPage) {
1139
+ this.page = 0;
1140
+ }
1141
+ else {
1142
+ // recreate the page results manually since we're not resetting the page
1143
+ this._pageResult = this.createPageResult();
1144
+ }
1145
+ }
1146
+ next() {
1147
+ if (this._pageResult.hasNext) {
1148
+ this.page = this._pageResult.nextPage;
1149
+ }
1150
+ }
1151
+ previous() {
1152
+ if (this._pageResult.hasPrevious) {
1153
+ this.page = this._pageResult.previousPage;
1154
+ }
1155
+ }
1156
+ pageByOffset(direction) {
1157
+ if (direction === 1) {
1158
+ this.next();
1159
+ }
1160
+ else {
1161
+ this.previous();
1162
+ }
1163
+ }
1164
+ /** Adds the item optionally keeping the current page. */
1165
+ add(item, position = 'end', keepPage = true) {
1166
+ if (position === 'start') {
1167
+ this._allItems.unshift(item);
1168
+ }
1169
+ else {
1170
+ this._allItems.push(item);
1171
+ }
1172
+ this.applyFilter(this._currentFilter, keepPage);
1173
+ }
1174
+ /** Removes the matched item(s). */
1175
+ remove(comparer, keepPage = true) {
1176
+ this._allItems = this.allItems.filter(i => comparer(i) === false);
1177
+ this.applyFilter(this._currentFilter, keepPage);
1178
+ if (!this.pageItems.length) {
1179
+ this.pageByOffset(-1);
1180
+ }
1181
+ }
1182
+ replace(newItem, comparer) {
1183
+ this.allItems.forEach((item, i) => {
1184
+ if (comparer && comparer(item)) {
1185
+ this.allItems[i] = newItem;
1186
+ }
1187
+ });
1188
+ this.applyFilter(this._currentFilter, true);
1189
+ }
1190
+ createPageResult() {
1191
+ const page = new PagedResult([], this._filteredItems.length, this.page, this.limit);
1192
+ page.items = this._filteredItems.slice(page.minPageItemIndex, page.maxPageItemIndex + 1) || [];
1193
+ return page;
1194
+ }
1195
+ }
1196
+
1197
+ /** @jsx jsx */
1198
+ const Checkbox = (props) => {
1199
+ const selected = props.checkedIcon || 'selected';
1200
+ const unselected = props.uncheckedIcon || 'unselected';
1201
+ const theme = useThemeSafely();
1202
+ const checkboxStyles = react.css `
1203
+ display: inline-block;
1204
+ ${!props.disabled && !props.readonly && `
1205
+ &:hover {
1206
+ filter: ${theme.controls.hoverBrightness};
1207
+ }
1208
+ `}
1209
+ `;
1210
+ const labelStyles = react.css `
1211
+ cursor: pointer;
1212
+ user-select: none;
1213
+ display: flex;
1214
+ align-items: center;
1215
+ ${props.disabled && `
1216
+ cursor: not-allowed;
1217
+ `}
1218
+ ${props.readonly && `
1219
+ cursor: default;
1220
+ `}
1221
+ `;
1222
+ // had to reference a marker class ('checkboxIcon') here for the sibling selector to work.
1223
+ const nativeCheckboxStyles = react.css `
1224
+ margin: 0;
1225
+ padding: 0;
1226
+ width: 0;
1227
+
1228
+ ${!props.readonly && `
1229
+ &:focus + .checkboxIcon {
1230
+ box-shadow: ${theme.controls.focusOutlineShadow};
1231
+ border-radius: 100%;
1232
+ }
1233
+ `}
1234
+ `;
1235
+ const iconStyles = react.css `
1236
+ ${!!props.label && `
1237
+ margin-right: 0.5rem;
1238
+ `}
1239
+ ${props.disabled && `
1240
+ background-color: ${theme.colors.disabled};
1241
+ border-radius: 100%;
1242
+ cursor: not-allowed;
1243
+ `}
1244
+ ${props.readonly && `
1245
+ cursor: default;
1246
+ `}
1247
+ `;
1248
+ return (react.jsx("span", { css: checkboxStyles, className: mergeClassNames('checkbox', props.className) },
1249
+ react.jsx("label", { css: labelStyles },
1250
+ react.jsx("input", { tabIndex: props.readonly ? -1 : undefined, disabled: props.disabled, css: nativeCheckboxStyles, type: "checkbox", checked: props.checked, onChange: e => {
1251
+ if (props.readonly) {
1252
+ e.preventDefault();
1253
+ return;
1254
+ }
1255
+ return props.onChange(e.currentTarget.checked);
1256
+ } }),
1257
+ react.jsx(Icon, { css: iconStyles, className: "checkboxIcon", id: props.checked ? selected : unselected }),
1258
+ props.label,
1259
+ props.children)));
1260
+ };
1261
+
1262
+ /** @jsx jsx */
1263
+ const SHOW_TIME_MS = 250;
1264
+ const Backdrop = (props) => {
1265
+ const backdropId = React__namespace.useRef('Backdrop' + nanoid.nanoid());
1266
+ const theme = useThemeSafely();
1267
+ const backdropStyles = react.css `
1268
+ opacity: 0;
1269
+ position: fixed;
1270
+ top: 0;
1271
+ left: 0;
1272
+ right: 0;
1273
+ bottom: 0;
1274
+ background-color: ${theme.colors.backdrop};
1275
+ transition: opacity 0.25s ease-in-out;
1276
+ visibility: hidden;
1277
+ user-select: none;
1278
+ -webkit-tap-highlight-color: transparent;
1279
+ `;
1280
+ const showStyles = css.css `
1281
+ z-index: ${theme.zIndexes.backdrop} !important;
1282
+ opacity: 1.0 !important;
1283
+ label:${backdropId.current};
1284
+ `;
1285
+ const bodyStyles = css.css `
1286
+ overflow: hidden !important;
1287
+ label:${backdropId.current};
1288
+ `;
1289
+ const bodyResponsiveStyles = css.css `
1290
+ label:${backdropId.current};
1291
+ @media(min-width:${theme.breakpoints.desktop}) {
1292
+ overflow: auto !important;
1293
+ }
1294
+ `;
1295
+ const bodyReverseResponsiveStyles = css.css `
1296
+ ${bodyStyles}
1297
+ overflow: auto !important;
1298
+ @media(min-width:${theme.breakpoints.desktop}) {
1299
+ overflow: hidden !important;
1300
+ }
1301
+ `;
1302
+ const styles = react.css `
1303
+ ${backdropStyles}
1304
+ ${props.onClick && `
1305
+ cursor: pointer;
1306
+ `}
1307
+ ${props.transparent && `
1308
+ background-color: transparent;
1309
+ transition: none;
1310
+ `}
1311
+ ${props.children && `
1312
+ display: flex;
1313
+ justify-content:center;
1314
+ align-items: center;
1315
+ `}
1316
+ ${props.responsive && `
1317
+ @media(min-width:${theme.breakpoints.desktop}) {
1318
+ display: none;
1319
+ }
1320
+ `}
1321
+ ${props.reverseResponsive && `
1322
+ display: none;
1323
+ @media(min-width:${theme.breakpoints.desktop}) {
1324
+ display: flex;
1325
+ }
1326
+ `}
1327
+ `;
1328
+ const backdrop = React__namespace.useRef(null);
1329
+ const hideTimeoutId = React__namespace.useRef();
1330
+ React__namespace.useEffect(() => {
1331
+ if (backdrop && backdrop.current) {
1332
+ if (props.show && backdrop.current.style.visibility !== 'visible') {
1333
+ //TB: bug here. if you call show when the timer is in the process of ticking to hide,
1334
+ // this clear timeout won't be hit
1335
+ // you can add move the line above, but you would have to re-add the show styles
1336
+ // which already have been cleared below
1337
+ // cancel a current hide timeout if it exists. this happens when we show a waiting indicator after another one is in the process of
1338
+ // transitioning to close.
1339
+ if (hideTimeoutId.current) {
1340
+ clearTimeout(hideTimeoutId.current);
1341
+ hideTimeoutId.current = undefined;
1342
+ }
1343
+ backdrop.current.style.visibility = 'visible';
1344
+ backdrop.current.classList.add(showStyles);
1345
+ if (!props.allowScroll) {
1346
+ document.body.classList.add(bodyStyles);
1347
+ if (props.responsive) {
1348
+ document.body.classList.add(bodyResponsiveStyles);
1349
+ }
1350
+ else if (props.reverseResponsive) {
1351
+ document.body.classList.add(bodyReverseResponsiveStyles);
1352
+ }
1353
+ }
1354
+ }
1355
+ else if (!props.show && backdrop.current.style.visibility === 'visible') {
1356
+ backdrop.current.classList.remove(showStyles);
1357
+ hideTimeoutId.current = setTimeout(() => {
1358
+ //TB: this will hide prior to the animation callback being hit. why? does it matter?
1359
+ if (backdrop && backdrop.current) {
1360
+ backdrop.current.style.visibility = 'hidden';
1361
+ if (!props.allowScroll) {
1362
+ document.body.classList.remove(bodyStyles);
1363
+ if (props.responsive) {
1364
+ document.body.classList.remove(bodyResponsiveStyles);
1365
+ }
1366
+ else if (props.reverseResponsive) {
1367
+ document.body.classList.remove(bodyReverseResponsiveStyles);
1368
+ }
1369
+ }
1370
+ }
1371
+ }, SHOW_TIME_MS);
1372
+ }
1373
+ }
1374
+ return () => {
1375
+ if (backdrop && backdrop.current && !props.allowScroll) {
1376
+ document.body.classList.remove(bodyStyles);
1377
+ }
1378
+ };
1379
+ }, [props.show]);
1380
+ return (react.jsx("div", { onMouseDown: e => {
1381
+ var _a;
1382
+ e.stopPropagation();
1383
+ e.preventDefault();
1384
+ (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props);
1385
+ }, onClick: e => {
1386
+ e.stopPropagation();
1387
+ e.preventDefault();
1388
+ }, ref: backdrop, css: styles, className: mergeClassNames('backdrop', props.className) }, props.children));
1389
+ };
1390
+
1391
+ const TabLocker = (props) => {
1392
+ const tabLocker = React__namespace.useRef(null);
1393
+ return (React__namespace.createElement("div", { className: "tabLocker", style: props.style, ref: tabLocker, onKeyDown: e => {
1394
+ var _a, _b;
1395
+ if (props.disabled) {
1396
+ return;
1397
+ }
1398
+ if (e.key === 'Tab') {
1399
+ e.preventDefault();
1400
+ e.stopPropagation();
1401
+ 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'));
1402
+ if (tabElements.length) {
1403
+ const direction = e.shiftKey ? -1 : 1;
1404
+ const index = tabElements.findIndex(x => x === document.activeElement);
1405
+ if (index === undefined) {
1406
+ tabElements[0].focus();
1407
+ }
1408
+ else if (index === tabElements.length - 1 && direction === 1) {
1409
+ tabElements[0].focus();
1410
+ }
1411
+ else if (index === 0 && direction === -1) {
1412
+ tabElements[tabElements.length - 1].focus();
1413
+ }
1414
+ else {
1415
+ tabElements[index + direction].focus();
1416
+ }
1417
+ }
1418
+ }
1419
+ } }, props.children));
1420
+ };
1421
+
1422
+ /** @jsx jsx */
1423
+ const Modal = (props) => {
1424
+ var _a, _b;
1425
+ const hasHeader = props.closeButton || props.heading;
1426
+ const theme = useThemeSafely();
1427
+ const contentStyles = react.css `
1428
+ z-index: ${theme.zIndexes.modal};
1429
+ cursor: default;
1430
+ margin: 1rem;
1431
+ padding: 1rem;
1432
+ background-color: ${theme.colors.modalBg};
1433
+ border: ${theme.controls.border};
1434
+ box-shadow: ${theme.controls.boxShadow};
1435
+ max-width: ${(_a = props.maxWidth) !== null && _a !== void 0 ? _a : theme.breakpoints.tablet};
1436
+ min-width: ${(_b = props.minWidth) !== null && _b !== void 0 ? _b : undefined};
1437
+ opacity: 0;
1438
+ font-size: ${theme.fonts.size};
1439
+ font-family: ${theme.fonts.family};
1440
+ font-weight: normal;
1441
+ &:focus {
1442
+ outline: none;
1443
+ }
1444
+ ${props.noBackground && `
1445
+ background-color: transparent;
1446
+ border: none;
1447
+ box-shadow: none;
1448
+ `}
1449
+ ${hasHeader && `
1450
+ padding: 0;
1451
+ min-width: 250px;
1452
+ `}
1453
+ ${props.show && `
1454
+ opacity: 1;
1455
+ `}
1456
+ `;
1457
+ const headerStyles = react.css `
1458
+ display: flex;
1459
+ justify-content: space-between;
1460
+ align-items: center;
1461
+ background-color: ${theme.colors.header};
1462
+ padding: 1rem;
1463
+ color: ${theme.colors.headerFont};
1464
+ `;
1465
+ const contentRef = React__namespace.useRef(null);
1466
+ const backdropStyles = props.scrollable && react.css `
1467
+ height: 100%;
1468
+ width:100%;
1469
+ overflow-y: auto;
1470
+ overflow-x: hidden;
1471
+ display: flex;
1472
+ justify-content: center;
1473
+ align-items:flex-start;
1474
+ padding-top:2rem;
1475
+ `;
1476
+ React__namespace.useLayoutEffect(() => {
1477
+ var _a;
1478
+ if (props.show === true) {
1479
+ const focusSelector = (_a = props.focusSelector) !== null && _a !== void 0 ? _a : '.modalCloseButton';
1480
+ // still need to wait for the next tick so the children are all rendered.
1481
+ setTimeout(() => {
1482
+ var _a;
1483
+ const element = (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusSelector);
1484
+ element === null || element === void 0 ? void 0 : element.focus();
1485
+ });
1486
+ }
1487
+ }, [props.show]);
1488
+ return (react.jsx(Backdrop, { show: props.show, css: backdropStyles, onClick: props.close },
1489
+ react.jsx("div", { id: props.id, tabIndex: -1, ref: contentRef, css: contentStyles, className: mergeClassNames('modal', props.className) },
1490
+ react.jsx(TabLocker, null,
1491
+ hasHeader && (
1492
+ // Marker class. Do not remove.
1493
+ react.jsx("header", { onClick: e => e.stopPropagation(), onMouseDown: e => e.stopPropagation(), css: headerStyles, className: "modalHeader" },
1494
+ props.heading ? react.jsx(Text, { css: {
1495
+ margin: 0,
1496
+ flexGrow: 1
1497
+ }, tag: "h1", bold: true }, props.heading) : react.jsx("span", null),
1498
+ props.closeButton && props.close ? react.jsx(Button, { css: {
1499
+ color: theme.colors.headerFont,
1500
+ marginLeft: '1rem',
1501
+ backgroundColor: 'transparent'
1502
+ }, variant: "icon", onClick: props.close,
1503
+ // Marker class. Do not remove.
1504
+ className: "modalCloseButton" },
1505
+ react.jsx(Icon, { id: "close" })) : react.jsx("span", null))),
1506
+ react.jsx("div", { onClick: e => e.stopPropagation(), onMouseDown: e => e.stopPropagation(), css: {
1507
+ padding: hasHeader ? '1rem' : undefined,
1508
+ } }, props.children)))));
1509
+ };
1510
+
1511
+ /** @jsx jsx */
1512
+ const ConfirmModal = (props) => {
1513
+ const theme = useThemeSafely();
1514
+ const modalStyle = react.css `
1515
+ ${props.variant === 'omg' && `
1516
+ .modalHeader {
1517
+ background-color:${theme.colors.omg};
1518
+ color:${theme.colors.omgFont};
1519
+ }
1520
+ `}
1521
+ `;
1522
+ return (react.jsx(Modal, { css: modalStyle, className: mergeClassNames('confirmModal', props.className), heading: props.header, closeButton: true, show: props.show, close: props.onCancel },
1523
+ react.jsx(Text, { align: "center" }, props.text),
1524
+ react.jsx("div", { css: { textAlign: 'center' } },
1525
+ react.jsx(Button, { css: { margin: '0 0.5rem' }, enforceMinWidth: true, variant: props.variant === 'omg' ? "omg" : 'primary2', onClick: props.onConfirm }, props.confirmText || 'OK'),
1526
+ react.jsx(Button, { css: { margin: '0 0.5rem' }, enforceMinWidth: true, onClick: props.onCancel }, props.cancelText || 'Cancel'))));
1527
+ };
1528
+
1529
+ /** @jsx jsx */
1530
+ const Divider = (props) => {
1531
+ const theme = useThemeSafely();
1532
+ return (react.jsx("hr", { className: "divider", css: {
1533
+ margin: theme.controls.dividerMargin,
1534
+ border: theme.controls.dividerBorder
1535
+ } }));
1536
+ };
1537
+
1538
+ /** @jsx jsx */
1539
+ const ErrorModal = (props) => {
1540
+ const { message } = props, rest = __rest(props, ["message"]);
1541
+ const theme = useThemeSafely();
1542
+ const modalStyles = react.css `
1543
+ .modalHeader {
1544
+ background-color: ${theme.colors.omg};
1545
+ color: ${theme.colors.omgFont};
1546
+ }
1547
+ .modalCloseButton {
1548
+ color: ${theme.colors.omgFont};
1549
+ }
1550
+ `;
1551
+ return (react.jsx(Modal, Object.assign({ css: modalStyles, className: "errorModal", heading: "Error", closeButton: true }, rest),
1552
+ react.jsx(Text, { align: "center" }, message)));
1553
+ };
1554
+
1555
+ /** @jsx jsx */
1556
+ const InfoPanel = (props) => {
1557
+ const theme = useThemeSafely();
1558
+ const styles = react.css `
1559
+ border:${theme.colors.border};
1560
+ padding:1rem;
1561
+ color: rgba(0, 0, 0, 0.7);
1562
+ margin: 0 !important;
1563
+ ${props.variant === 'info' && `
1564
+ background-color:${theme.colors.info};
1565
+ color:${theme.colors.infoFont};
1566
+ `}
1567
+ ${props.variant === 'warning' && `
1568
+ background-color:${theme.colors.warning};
1569
+ color:${theme.colors.warningFont};
1570
+ `}
1571
+ ${props.variant === 'error' && `
1572
+ background-color:${theme.colors.omg};
1573
+ color:${theme.colors.omgFont};
1574
+ `}
1575
+ ${props.variant === 'negative' && `
1576
+ background-color:${theme.colors.negative};
1577
+ color:${theme.colors.negativeFont};
1578
+ `}
1579
+ ${props.variant === 'positive' && `
1580
+ background-color:${theme.colors.positive};
1581
+ color:${theme.colors.positiveFont};
1582
+ `}
1583
+ `;
1584
+ return (react.jsx(Text, { style: props.style, align: "center", css: styles, className: mergeClassNames('infoPanel', props.className) }, props.children));
1585
+ };
1586
+
1587
+ class FileListPlus {
1588
+ constructor(_raw, _args = {}) {
1589
+ this._raw = _raw;
1590
+ this._args = _args;
1591
+ this._files = Array.from(this._raw).map(f => {
1592
+ return { name: f.name, size: f.size, type: f.type };
1593
+ });
1594
+ if (this._args.accept) {
1595
+ const acceptTypes = this._args.accept.split(',');
1596
+ this._invalidFiles = this._files.filter(f => {
1597
+ if (acceptTypes.includes(f.type)) {
1598
+ return false;
1599
+ }
1600
+ if (acceptTypes.some(t => f.name.endsWith(t))) {
1601
+ return false;
1602
+ }
1603
+ return true;
1604
+ });
1605
+ }
1606
+ else {
1607
+ this._invalidFiles = [];
1608
+ }
1609
+ }
1610
+ get raw() {
1611
+ return this._raw;
1612
+ }
1613
+ get length() {
1614
+ return this._files.length;
1615
+ }
1616
+ get files() {
1617
+ return this._files;
1618
+ }
1619
+ get invalidFiles() {
1620
+ return this._invalidFiles;
1621
+ }
1622
+ get totalBytes() {
1623
+ return lodash.sumBy(this.files, f => f.size);
1624
+ }
1625
+ get overMaxBytes() {
1626
+ var _a;
1627
+ return this.totalBytes >= ((_a = this._args.maxBytes) !== null && _a !== void 0 ? _a : Infinity);
1628
+ }
1629
+ get overFileLimit() {
1630
+ return this.length > (this._args.multiple ? Infinity : 1);
1631
+ }
1632
+ get hasErrors() {
1633
+ return this.overMaxBytes || this.overFileLimit || !!this.invalidFiles.length;
1634
+ }
1635
+ }
1636
+
1637
+ /** @jsx jsx */
1638
+ /** Basic implementation here for later abstraction. */
1639
+ const FilePicker = (props) => {
1640
+ var _a, _b, _c, _d;
1641
+ const input = React__namespace.useRef(null);
1642
+ const [fileList, setFileList] = React__namespace.useState(undefined);
1643
+ const totalFileSize = (_a = fileList === null || fileList === void 0 ? void 0 : fileList.totalBytes) !== null && _a !== void 0 ? _a : 0;
1644
+ const theme = useThemeSafely();
1645
+ let filesDisplay = '';
1646
+ if (!(fileList === null || fileList === void 0 ? void 0 : fileList.length)) {
1647
+ filesDisplay = `No file${props.multiple ? 's' : ''} chosen.`;
1648
+ }
1649
+ else {
1650
+ filesDisplay = `${fileList.length.toLocaleString()} file${fileList.length > 1 ? 's' : ''} selected (${getSizeString(totalFileSize)}): ${fileList.files.map(f => f.name).join(', ')}`;
1651
+ }
1652
+ const width = '10rem';
1653
+ const nativeInputStyles = react.css `
1654
+ position: absolute;
1655
+ top: 0;
1656
+ left: 0;
1657
+ bottom: 0;
1658
+ right: 0;
1659
+ border: 1px solid black;
1660
+ cursor: pointer;
1661
+ width:${width};
1662
+ opacity: 0;
1663
+ `;
1664
+ const buttonText = (_b = props.buttonText) !== null && _b !== void 0 ? _b : `Choose File${props.multiple ? 's' : ''}`;
1665
+ const clearFiles = () => {
1666
+ if (input.current) {
1667
+ input.current.value = '';
1668
+ }
1669
+ setFileList(undefined);
1670
+ };
1671
+ (_c = props.__passClearFilesHandle) === null || _c === void 0 ? void 0 : _c.call(props, clearFiles);
1672
+ return (react.jsx("span", { css: { display: 'inline-block' }, className: "fileUploader" },
1673
+ react.jsx("div", { css: {
1674
+ position: 'relative',
1675
+ width
1676
+ } },
1677
+ react.jsx(Button, { block: true, variant: "secondary", type: "button" }, buttonText),
1678
+ react.jsx("input", { ref: input, css: nativeInputStyles, type: "file", multiple: props.multiple, accept: props.accept, onChange: e => {
1679
+ var _a;
1680
+ try {
1681
+ if (!e.target.files) {
1682
+ setFileList(undefined);
1683
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, undefined);
1684
+ return;
1685
+ }
1686
+ const fileListPlus = new FileListPlus(e.target.files, {
1687
+ accept: props.accept,
1688
+ multiple: props.multiple,
1689
+ maxBytes: props.maxBytes
1690
+ });
1691
+ if (props.onChange) {
1692
+ if (fileListPlus.hasErrors) {
1693
+ props.onChange(undefined);
1694
+ setFileList(fileListPlus);
1695
+ }
1696
+ else {
1697
+ const removeFiles = props.onChange(fileListPlus.raw);
1698
+ if (removeFiles) {
1699
+ setFileList(undefined);
1700
+ }
1701
+ else {
1702
+ setFileList(fileListPlus);
1703
+ }
1704
+ }
1705
+ }
1706
+ else {
1707
+ setFileList(fileListPlus);
1708
+ }
1709
+ }
1710
+ catch (err) {
1711
+ // tslint:disable-next-line
1712
+ console.error(err);
1713
+ setFileList(undefined);
1714
+ }
1715
+ } })),
1716
+ react.jsx(Text, null,
1717
+ filesDisplay,
1718
+ !!(fileList === null || fileList === void 0 ? void 0 : fileList.length) && (react.jsx(Button, { onClick: () => {
1719
+ var _a;
1720
+ clearFiles();
1721
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, undefined);
1722
+ }, css: { marginLeft: '1rem', color: theme.colors.negative }, rightIcon: react.jsx(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear"))),
1723
+ !!(fileList === null || fileList === void 0 ? void 0 : fileList.invalidFiles.length) && react.jsx(InfoPanel, { variant: "error" },
1724
+ "Invalid files: ",
1725
+ fileList.invalidFiles.map(f => f.name).join(', '),
1726
+ "."),
1727
+ (fileList === null || fileList === void 0 ? void 0 : fileList.overMaxBytes) && react.jsx(InfoPanel, { variant: "error" },
1728
+ "Max file size exceeded (",
1729
+ getSizeString((_d = props.maxBytes) !== null && _d !== void 0 ? _d : 0),
1730
+ ").")));
1731
+ };
1732
+ const bytesInMb = 1048576;
1733
+ const bytesInKb = 1024;
1734
+ const getSizeString = (size) => {
1735
+ if (size < bytesInKb) {
1736
+ return size.toLocaleString() + ' B';
1737
+ }
1738
+ else if (size < bytesInMb) {
1739
+ return (size / bytesInKb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' KB';
1740
+ }
1741
+ else {
1742
+ return (size / bytesInMb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' MB';
1743
+ }
1744
+ };
1745
+
1746
+ /** @jsx jsx */
1747
+ /** Use this instead of <form> directly. If we need to fight Chrome's autofill, we can do so at a global level. */
1748
+ const Form = (props) => {
1749
+ const { inline, children, onSubmit } = props, rest = __rest(props, ["inline", "children", "onSubmit"]);
1750
+ const theme = useThemeSafely();
1751
+ return (react.jsx("form", Object.assign({ className: "form", css: {
1752
+ display: 'flex',
1753
+ flexDirection: props.inline ? 'row' : 'column',
1754
+ alignItems: props.inline ? 'flex-end' : 'normal',
1755
+ gap: theme.controls.gap
1756
+ } }, rest, { onSubmit: e => {
1757
+ e.preventDefault();
1758
+ e.stopPropagation();
1759
+ if (onSubmit) {
1760
+ onSubmit(e);
1761
+ }
1762
+ } }), children));
1763
+ };
1764
+ const FormFlexRow = (props) => {
1765
+ var _a;
1766
+ const theme = useThemeSafely();
1767
+ return (react.jsx("div", { style: props.style, className: mergeClassNames('formFlexRow', props.className), css: {
1768
+ display: 'flex',
1769
+ gap: theme.controls.gap,
1770
+ justifyContent: (_a = props.justifyContent) !== null && _a !== void 0 ? _a : 'normal'
1771
+ } }, props.children));
1772
+ };
1773
+ const FormColumnRow = (props) => {
1774
+ const theme = useThemeSafely();
1775
+ return (react.jsx("div", { style: props.style, className: mergeClassNames('formColumnRow', props.className), css: {
1776
+ display: 'grid',
1777
+ gap: theme.controls.gap,
1778
+ gridTemplateColumns: `repeat(${props.cols},1fr)`
1779
+ } }, props.children));
1780
+ };
1781
+
1782
+ /** @jsx jsx */
1783
+ const Header = (props) => {
1784
+ const theme = useThemeSafely();
1785
+ const bodyStyles = css.css `
1786
+ padding-top: calc(${theme.layout.headerHeight} + ${theme.layout.headerBodyOffset});
1787
+ label: Header;
1788
+ `;
1789
+ React__namespace.useEffect(() => {
1790
+ document.body.classList.add(bodyStyles);
1791
+ return () => {
1792
+ document.body.classList.remove(bodyStyles);
1793
+ };
1794
+ });
1795
+ const toggleMenu = props.toggleMenu || noop;
1796
+ const headerStyles = react.css `
1797
+ display: flex;
1798
+ gap: ${theme.controls.gap};
1799
+ justify-content: flex-start;
1800
+ align-items: center;
1801
+ position: fixed;
1802
+ top: 0;
1803
+ right: 0;
1804
+ left: 0;
1805
+ height: ${theme.layout.headerHeight};
1806
+ background-color: ${theme.colors.header};
1807
+ box-shadow: ${theme.controls.headerBoxShadow};
1808
+ color: ${theme.colors.headerFont};
1809
+ padding: 1rem;
1810
+ z-index: ${theme.zIndexes.header};
1811
+ flex-wrap: wrap;
1812
+ .button {
1813
+ color: ${theme.colors.headerFont};
1814
+ background-color:transparent;
1815
+ }
1816
+ ${props.inline && `
1817
+ position: static;
1818
+ `}
1819
+ ${!!props.rightElements && `
1820
+ justify-content: space-between;
1821
+ `}
1822
+ ${props.responsive && `
1823
+ @media(min-width:${theme.breakpoints.desktop}) {
1824
+ justify-content: flex-end;
1825
+ }
1826
+ `}
1827
+ `;
1828
+ const headerButtonStyles = !props.noMenu && react.css `
1829
+ ${props.responsive && `
1830
+ @media(min-width:${theme.breakpoints.desktop}) {
1831
+ display: none;
1832
+ }
1833
+ `}
1834
+ `;
1835
+ const rightElementStyles = props.rightElements && react.css `
1836
+ margin-left: 1rem;
1837
+ display: grid;
1838
+ grid-gap: 0.5rem;
1839
+ grid-auto-flow: column;
1840
+ align-items: center;
1841
+ `;
1842
+ const centerElementsStyles = props.centerOffsetElements && react.css `
1843
+ position: absolute;
1844
+ display: flex;
1845
+ justify-content: center;
1846
+ left: 0;
1847
+ right: 0;
1848
+ margin-top: calc(${theme.layout.headerHeight} * 1.25);
1849
+ `;
1850
+ let title;
1851
+ if (props.title) {
1852
+ if (typeof props.title === 'string') {
1853
+ title = (react.jsx(Text, { css: {
1854
+ margin: 0,
1855
+ fontSize: '2rem',
1856
+ flexGrow: 1,
1857
+ flexBasis: '33%'
1858
+ }, tag: "h1", ellipsis: !props.fillTitle, align: props.fillTitle ? 'center' : 'left' }, props.title));
1859
+ }
1860
+ else {
1861
+ title = props.title;
1862
+ }
1863
+ }
1864
+ return (react.jsx("div", { css: headerStyles, className: mergeClassNames('header', props.className) },
1865
+ !props.noMenu && (react.jsx(Button, { variant: "icon", css: headerButtonStyles, onClick: toggleMenu },
1866
+ react.jsx(Icon, { id: "menu" }))),
1867
+ title,
1868
+ props.rightElements && react.jsx("div", { css: rightElementStyles }, props.rightElements),
1869
+ props.centerOffsetElements && (react.jsx("div", { css: centerElementsStyles },
1870
+ react.jsx("div", null, props.centerOffsetElements)))));
1871
+ };
1872
+
1873
+ /** @jsx jsx */
1874
+ const Highlight = (props) => {
1875
+ const theme = useThemeSafely();
1876
+ const highlightStyles = react.css `
1877
+ > mark {
1878
+ background-color: ${theme.colors.textHighlight};
1879
+ }
1880
+ `;
1881
+ let text = props.text;
1882
+ if (props.text && props.highlightText) {
1883
+ const replaceText = props.highlightText.trim();
1884
+ if (replaceText) {
1885
+ text = props.text.replace(new RegExp(`(${replaceText})`, 'gi'), `<mark>$1</mark>`);
1886
+ }
1887
+ }
1888
+ return (react.jsx("span", { className: "highlight", css: highlightStyles, dangerouslySetInnerHTML: { __html: text } }));
1889
+ };
1890
+
1891
+ /** @jsx jsx */
1892
+ const Image = (props) => {
1893
+ return (react.jsx("img", { css: {
1894
+ maxWidth: '100%',
1895
+ maxHeight: '100%',
1896
+ }, alt: props.alt, style: props.style, className: mergeClassNames('image', props.className), src: props.src }));
1897
+ };
1898
+
1899
+ /** @jsx jsx */
1900
+ const Popover = (p) => {
1901
+ var _a;
1902
+ const theme = useThemeSafely();
1903
+ const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
1904
+ return (react.jsx(reactTinyPopover.Popover, { containerClassName: css.css({
1905
+ zIndex: theme.zIndexes.tooltip
1906
+ }), reposition: resposition, isOpen: p.isOpen, positions: ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
1907
+ var _a, _b, _c;
1908
+ return (react.jsx(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
1909
+ react.jsx(TabLocker, null,
1910
+ react.jsx("div", { css: {
1911
+ border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
1912
+ boxShadow: theme.controls.boxShadow,
1913
+ backgroundColor: (_c = p.backgroundColor) !== null && _c !== void 0 ? _c : theme.colors.bg,
1914
+ } }, p.content))));
1915
+ } },
1916
+ react.jsx("span", null, p.parent)));
1917
+ };
1918
+
1919
+ /** @jsx jsx */
1920
+ const InfoTip = (props) => {
1921
+ var _a, _b;
1922
+ const [showTip, setShowTip] = React__namespace.useState(false);
1923
+ const theme = useThemeSafely();
1924
+ const bgColor = (_a = props.bgColor) !== null && _a !== void 0 ? _a : theme.colors.nav;
1925
+ const fontColor = (_b = props.fontColor) !== null && _b !== void 0 ? _b : theme.colors.navFont;
1926
+ const onClick = () => {
1927
+ if (props.onClick) {
1928
+ props.onClick();
1929
+ }
1930
+ else if (props.content) {
1931
+ openTip();
1932
+ }
1933
+ };
1934
+ const onMouseOver = () => {
1935
+ if (props.variant === 'modal') {
1936
+ return;
1937
+ }
1938
+ if (props.loadOnHover) {
1939
+ props.loadOnHover().then(() => {
1940
+ openTip();
1941
+ }).catch(err => {
1942
+ /* Not my responsiblity. */
1943
+ });
1944
+ }
1945
+ else {
1946
+ openTip();
1947
+ }
1948
+ };
1949
+ const onMouseOut = () => {
1950
+ if (props.variant === 'modal') {
1951
+ return;
1952
+ }
1953
+ closeTip();
1954
+ };
1955
+ const openTip = () => {
1956
+ if (!props.content) {
1957
+ return;
1958
+ }
1959
+ setShowTip(props.disabled ? false : true);
1960
+ };
1961
+ const closeTip = () => {
1962
+ if (!props.content) {
1963
+ return;
1964
+ }
1965
+ setShowTip(false);
1966
+ if (props.onClose) {
1967
+ props.onClose();
1968
+ }
1969
+ };
1970
+ const buttonStyles = react.css `
1971
+ font-weight: bold;
1972
+ width: 1.5rem;
1973
+ min-width:1.5rem;
1974
+ height: 1.5rem;
1975
+ padding: 0 !important;
1976
+ font-family: serif;
1977
+ display:inline-block;
1978
+ `;
1979
+ const button = react.jsx(Button, { css: buttonStyles, disabled: props.disabled, variant: 'circle', tabIndex: props.tabIndex, onClick: onClick, onMouseEnter: onMouseOver, onMouseLeave: onMouseOut }, "i");
1980
+ if (props.variant === 'modal') {
1981
+ return (react.jsx(React__namespace.Fragment, null,
1982
+ button,
1983
+ react.jsx(Modal, { show: showTip, heading: props.modalHeader, close: closeTip, css: {
1984
+ whiteSpace: 'normal'
1985
+ }, closeButton: true }, props.content)));
1986
+ }
1987
+ else {
1988
+ return (react.jsx(Popover, { reposition: false, isOpen: showTip, onClickOutside: closeTip, arrorColor: bgColor, border: '', backgroundColor: bgColor, parent: button, content: (react.jsx("div", { css: {
1989
+ padding: '0.5rem',
1990
+ fontSize: '0.75rem',
1991
+ maxWidth: '22rem'
1992
+ }, style: { backgroundColor: bgColor, color: fontColor }, onMouseOut: closeTip }, props.content)) }));
1993
+ }
1994
+ };
1995
+
1996
+ /** @jsx jsx */
1997
+ const DEBOUNCE_MS = 250;
1998
+ const NUMBER_REGEX = /^-?\d+\.?\d*$/;
1999
+ const DATE_REGEX = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
2000
+ const DEFAULT_MAX_LENGTH = 100;
2001
+ const formatLocalValue = (value, type) => {
2002
+ let newValue = '';
2003
+ if (value !== undefined && value !== null) {
2004
+ if (type === 'date' && typeof value === 'number') {
2005
+ newValue = dateFns.format(value, 'MM/dd/yyyy');
2006
+ }
2007
+ else {
2008
+ newValue = value;
2009
+ }
2010
+ }
2011
+ return newValue;
2012
+ };
2013
+ const Input = (props) => {
2014
+ var _a;
2015
+ const [localValue, setLocalValue] = React__namespace.useState(formatLocalValue(props.value, props.type));
2016
+ const vars = React__namespace.useRef({
2017
+ debouncedOnChange: props.onChange && lodash.debounce((value) => {
2018
+ var _a;
2019
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value);
2020
+ }, (_a = props.debounceMs) !== null && _a !== void 0 ? _a : DEBOUNCE_MS),
2021
+ focused: false
2022
+ });
2023
+ const trySyncLocalValue = () => {
2024
+ if (vars.current.focused) {
2025
+ return;
2026
+ }
2027
+ if (props.value === localValue) {
2028
+ return;
2029
+ }
2030
+ const newValue = formatLocalValue(props.value, props.type);
2031
+ setLocalValue(newValue);
2032
+ };
2033
+ React__namespace.useEffect(() => {
2034
+ trySyncLocalValue();
2035
+ });
2036
+ const theme = useThemeSafely();
2037
+ const inputStyles = react.css `
2038
+ font-family: ${theme.fonts.family};
2039
+ font-size: ${theme.fonts.size};
2040
+ width: 100%;
2041
+ border: ${theme.controls.border};
2042
+ color: ${theme.colors.font};
2043
+ padding-left: ${theme.controls.padding};
2044
+ padding-right: ${theme.controls.padding};
2045
+ height: ${theme.controls.height};
2046
+ transition: ${theme.controls.transition};
2047
+ &:focus {
2048
+ outline: none;
2049
+ box-shadow: ${theme.controls.focusOutlineShadow};
2050
+ }
2051
+ &:disabled {
2052
+ background-color: ${theme.colors.disabled};
2053
+ cursor: not-allowed;
2054
+ }
2055
+ ${props.required && !localValue && `
2056
+ border-color: ${theme.colors.required};
2057
+ &:focus {
2058
+ box-shadow: ${theme.controls.focusOutlineRequiredShadow};
2059
+ }
2060
+ `}
2061
+ ${props.round && props.type !== 'textarea' && `
2062
+ border-radius: ${theme.controls.roundRadius};
2063
+ padding-left: calc(${theme.controls.padding} * 2);
2064
+ padding-right: calc(${theme.controls.padding} * 2);
2065
+ `}
2066
+ ${props.rounded && `
2067
+ border-radius: ${theme.controls.roundedRadius};
2068
+ `}
2069
+ ${props.readOnly && `
2070
+ background-color: transparent;
2071
+ cursor: default;
2072
+ border: none;
2073
+ &:focus {
2074
+ outline: none;
2075
+ box-shadow: none;
2076
+ }
2077
+ `}
2078
+ ${props.rightControl && props.type !== 'textarea' && `
2079
+ padding-right: ${theme.controls.height};
2080
+ `}
2081
+ `;
2082
+ let inputElement;
2083
+ const onFocus = (e) => {
2084
+ var _a;
2085
+ vars.current.focused = true;
2086
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2087
+ };
2088
+ const onBlur = (e) => {
2089
+ var _a;
2090
+ vars.current.focused = false;
2091
+ trySyncLocalValue();
2092
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
2093
+ };
2094
+ if (props.type === 'number') {
2095
+ inputElement = react.jsx("input", { style: props.style, autoComplete: "off", tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly,
2096
+ // set fixed default to defeat pasting stupid numbers
2097
+ maxLength: 50, min: props.min, max: props.max, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: "number", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: e => {
2098
+ const value = e.target.value;
2099
+ if (NUMBER_REGEX.test(value)) {
2100
+ let numValue = parseFloat(value);
2101
+ if (props.min && numValue < props.min) {
2102
+ numValue = props.min;
2103
+ }
2104
+ if (props.max && numValue > props.max) {
2105
+ numValue = props.max;
2106
+ }
2107
+ setLocalValue(numValue);
2108
+ if (vars.current.debouncedOnChange) {
2109
+ vars.current.debouncedOnChange(numValue);
2110
+ }
2111
+ }
2112
+ else if (!value) {
2113
+ setLocalValue(value);
2114
+ if (vars.current.debouncedOnChange) {
2115
+ vars.current.debouncedOnChange(undefined);
2116
+ }
2117
+ }
2118
+ } });
2119
+ }
2120
+ else if (props.type === 'date') {
2121
+ inputElement = react.jsx("input", { style: props.style, autoComplete: "off", tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: 10, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: "text", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: e => {
2122
+ const value = e.target.value;
2123
+ setLocalValue(value);
2124
+ if (vars.current.debouncedOnChange) {
2125
+ const dateParts = DATE_REGEX.exec(value);
2126
+ if (!dateParts) {
2127
+ vars.current.debouncedOnChange(undefined);
2128
+ }
2129
+ else {
2130
+ const year = parseInt(dateParts[3], 10);
2131
+ const month = parseInt(dateParts[1], 10);
2132
+ const day = parseInt(dateParts[2], 10);
2133
+ if (dateFns.isExists(year, month, day)) {
2134
+ let ms = new Date(year, month - 1, day).valueOf();
2135
+ if (props.min && ms < props.min) {
2136
+ ms = props.min;
2137
+ }
2138
+ if (props.max && ms > props.max) {
2139
+ ms = props.max;
2140
+ }
2141
+ vars.current.debouncedOnChange(ms);
2142
+ }
2143
+ else {
2144
+ vars.current.debouncedOnChange(undefined);
2145
+ }
2146
+ }
2147
+ }
2148
+ } });
2149
+ }
2150
+ else if (props.type === 'textarea') {
2151
+ inputElement = react.jsx("textarea", { style: props.style, rows: props.rows || 10, autoComplete: "off", tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: react.css `
2152
+ ${inputStyles}
2153
+ max-width: 100%;
2154
+ min-height: ${theme.controls.height};
2155
+ padding-top: 0.75rem;
2156
+ height:auto;
2157
+ `, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: e => {
2158
+ const value = e.target.value;
2159
+ setLocalValue(value);
2160
+ if (vars.current.debouncedOnChange) {
2161
+ vars.current.debouncedOnChange(value);
2162
+ }
2163
+ } });
2164
+ }
2165
+ else {
2166
+ // text & password
2167
+ inputElement = react.jsx("input", { style: props.style, autoComplete: "off", tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: e => {
2168
+ const value = e.target.value;
2169
+ setLocalValue(value);
2170
+ if (vars.current.debouncedOnChange) {
2171
+ vars.current.debouncedOnChange(value);
2172
+ }
2173
+ } });
2174
+ }
2175
+ const inputWrapperStyles = react.css `
2176
+ width:100%;
2177
+ ${props.rightControl && `
2178
+ position: relative;
2179
+ `}
2180
+ `;
2181
+ const rightControlStyles = props.rightControl && react.css `
2182
+ position: absolute;
2183
+ right: ${theme.controls.padding};
2184
+ top: 0;
2185
+ bottom: 0;
2186
+ display: flex;
2187
+ align-items: center;
2188
+ ${props.round && `
2189
+ right: calc(${theme.controls.padding} * 2);
2190
+ `}
2191
+ `;
2192
+ return (react.jsx("div", { css: inputWrapperStyles, className: mergeClassNames('input', props.className) },
2193
+ inputElement,
2194
+ props.rightControl && props.type !== 'textarea' && react.jsx("div", { css: rightControlStyles }, props.rightControl)));
2195
+ };
2196
+
2197
+ /** @jsx jsx */
2198
+ const List = (props) => {
2199
+ const children = props.items ? props.items.map((item, i) => react.jsx(ListItem, { key: i }, item)) : props.children;
2200
+ const theme = useThemeSafely();
2201
+ const listStyles = react.css `
2202
+ margin: 0;
2203
+ padding: 0;
2204
+ list-style-type: none;
2205
+ ${props.altRowColor && `
2206
+ > .listItem:nth-of-type(even) {
2207
+ background-color: ${theme.colors.lightBg};
2208
+ }
2209
+ `}
2210
+ ${props.noLines && `
2211
+ > .listItem {
2212
+ border-bottom: none;
2213
+ }
2214
+ `}
2215
+ `;
2216
+ return (react.jsx("ul", { css: listStyles, className: mergeClassNames('list', props.className) }, children));
2217
+ };
2218
+ const ListItem = (props) => {
2219
+ const theme = useThemeSafely();
2220
+ const itemStyles = react.css `
2221
+ border-bottom: ${theme.controls.border};
2222
+ &:last-child {
2223
+ border-bottom: none;
2224
+ }
2225
+ `;
2226
+ const contentStyle = react.css `
2227
+ padding: calc(${theme.controls.padding} * 1.5);
2228
+ ${props.variant === 'full' && `
2229
+ padding:0;
2230
+ >.button {
2231
+ padding: calc(${theme.controls.padding} * 1.5);
2232
+ width: 100%;
2233
+ border: none;
2234
+ }
2235
+ >.omniLink {
2236
+ padding-left: calc(${theme.controls.padding} * 1.5);
2237
+ padding-right: calc(${theme.controls.padding} * 1.5);
2238
+ width: 100%;
2239
+ line-height: ${theme.controls.height};
2240
+ border: none;
2241
+ }
2242
+ >.button:not(:focus), >.omniLink:not(:focus) {
2243
+ box-shadow: none;
2244
+ }
2245
+ >.omniLink:not(.omniLink--iconBlock){
2246
+ display: block;
2247
+ }
2248
+ `}
2249
+ `;
2250
+ return (react.jsx("li", { css: itemStyles, className: mergeClassNames('listItem', props.className) },
2251
+ react.jsx("div", { css: contentStyle }, props.children)));
2252
+ };
2253
+
2254
+ /** @jsx jsx */
2255
+ const Nav = (props) => {
2256
+ const nav = React__namespace.useRef(null);
2257
+ const theme = useThemeSafely();
2258
+ const totalNavOffset = `calc(${theme.layout.navWidth} + 20px)`;
2259
+ const slideRight = react.keyframes `
2260
+ 0% {
2261
+ transform: translateX(0);
2262
+ }
2263
+
2264
+ 100% {
2265
+ transform: translateX(${totalNavOffset});
2266
+ }
2267
+ `;
2268
+ const slideLeft = react.keyframes `
2269
+ 0% {
2270
+ transform: translateX(${totalNavOffset});
2271
+ }
2272
+
2273
+ 100% {
2274
+ transform: translateX(0px);
2275
+ }
2276
+ `;
2277
+ const classNavShowing = css.css `
2278
+ animation: ${slideRight} 0.250s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
2279
+ `;
2280
+ const classNavNotShowing = css.css `
2281
+ animation: ${slideLeft} 0.250s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
2282
+ `;
2283
+ // the padding-top here is to offset the navs' content from the header. the shadow creeps over it.
2284
+ const navStyles = react.css `
2285
+ position: fixed;
2286
+ top: 0;
2287
+ left: calc(${totalNavOffset} * -1);
2288
+ bottom: 0;
2289
+ background-color: ${theme.colors.nav};
2290
+ color: ${theme.colors.navFont};
2291
+ width: ${theme.layout.navWidth};
2292
+ min-width: ${theme.layout.navWidth};
2293
+ box-shadow: 4px 2px 12px 6px rgba(0, 0, 0, 0.2);
2294
+ z-index: ${theme.zIndexes.nav};
2295
+ overflow-y: auto;
2296
+ .omniLink, .omniLink:active, .omniLink:focus, .omniLink:visited {
2297
+ color: ${theme.colors.navFont};
2298
+ }
2299
+ padding-top:0;
2300
+ ${props.responsive && `
2301
+ @media(min-width:${theme.breakpoints.desktop}) {
2302
+ position: relative;
2303
+ left: 0;
2304
+ box-shadow: none;
2305
+ z-index: 1;
2306
+ animation: none !important;
2307
+ margin-right: 1rem;
2308
+ overflow-y: visible;
2309
+ margin-top:-2rem;
2310
+ padding-top: 1rem;
2311
+ }
2312
+ `}
2313
+ `;
2314
+ React__namespace.useLayoutEffect(() => {
2315
+ if (nav && nav.current) {
2316
+ if (props.show) {
2317
+ if (!nav.current.classList.contains(classNavShowing)) {
2318
+ nav.current.classList.add(classNavShowing);
2319
+ }
2320
+ }
2321
+ else {
2322
+ if (nav.current.classList.contains(classNavShowing)) {
2323
+ nav.current.classList.remove(classNavShowing);
2324
+ nav.current.classList.add(classNavNotShowing);
2325
+ setTimeout(() => {
2326
+ if (nav && nav.current) {
2327
+ nav.current.classList.remove(classNavNotShowing);
2328
+ }
2329
+ }, 250);
2330
+ }
2331
+ }
2332
+ }
2333
+ });
2334
+ return (react.jsx(React__namespace.Fragment, null,
2335
+ react.jsx(Backdrop, { show: props.show, onClick: () => {
2336
+ props.toggle();
2337
+ }, responsive: props.responsive }),
2338
+ react.jsx("nav", { ref: nav, css: navStyles, className: mergeClassNames('nav', props.className) }, props.children)));
2339
+ };
2340
+
2341
+ /** @jsx jsx */
2342
+ const OmniLink = (props) => {
2343
+ var _a, _b, _c;
2344
+ const theme = useThemeSafely();
2345
+ const linkStyles = react.css `
2346
+ display: inline-block;
2347
+ cursor: pointer;
2348
+ text-decoration: none;
2349
+ color: ${(_a = props.colorOverride) !== null && _a !== void 0 ? _a : theme.colors.link};
2350
+ transition: ${theme.controls.transition};
2351
+ &:hover {
2352
+ filter: ${theme.controls.hoverBrightness};
2353
+ text-decoration: underline;
2354
+ }
2355
+ &:active,
2356
+ &:visited {
2357
+ color: ${(_b = props.colorOverride) !== null && _b !== void 0 ? _b : theme.colors.link};
2358
+ }
2359
+ &:focus {
2360
+ text-decoration: underline;
2361
+ outline: none;
2362
+ color: ${(_c = props.colorOverride) !== null && _c !== void 0 ? _c : theme.colors.link};
2363
+ }
2364
+ ${!!props.variant && `
2365
+ padding-left: ${theme.controls.padding};
2366
+ padding-right: ${theme.controls.padding};
2367
+ border: ${theme.controls.border};
2368
+ box-shadow: ${theme.controls.boxShadow};
2369
+ height: ${theme.controls.height};
2370
+ line-height: ${theme.controls.height};
2371
+ font-weight: bold;
2372
+ color: ${theme.colors.font};
2373
+ &:active,
2374
+ &:focus,
2375
+ &:visited {
2376
+ color: ${theme.colors.font};
2377
+ }
2378
+ &:focus {
2379
+ outline: none;
2380
+ box-shadow: ${theme.controls.focusOutlineShadow};
2381
+ text-decoration: none;
2382
+ }
2383
+ &:active {
2384
+ box-shadow: none;
2385
+ }
2386
+ &:hover {
2387
+ text-decoration: none;
2388
+ }
2389
+ `}
2390
+ ${props.variant === 'button' && `
2391
+ text-align: center;
2392
+ `}
2393
+ ${props.variant === 'circle' && `
2394
+ text-align: center;
2395
+ width: ${theme.controls.height};
2396
+ border-radius: 100%;
2397
+ display: flex;
2398
+ justify-content: center;
2399
+ align-items: center;
2400
+ ${props.small && `
2401
+ width: ${theme.controls.heightSmall};
2402
+ min-width: ${theme.controls.heightSmall};
2403
+ `}
2404
+ `}
2405
+ ${props.variant === 'primary' && `
2406
+ text-align: center;
2407
+ background-color: ${theme.colors.primary};
2408
+ color: ${theme.colors.primaryFont};
2409
+ &:active,
2410
+ &:focus,
2411
+ &:visited {
2412
+ color: ${theme.colors.primaryFont};
2413
+ }
2414
+ `}
2415
+ ${props.variant === 'primary2' && `
2416
+ text-align: center;
2417
+ background-color: ${theme.colors.primary2};
2418
+ color: ${theme.colors.primary2Font};
2419
+ &:active,
2420
+ &:focus,
2421
+ &:visited {
2422
+ color: ${theme.colors.primary2Font};
2423
+ }
2424
+ `}
2425
+ ${props.variant === 'secondary' && `
2426
+ text-align: center;
2427
+ background-color: ${theme.colors.secondary};
2428
+ color: ${theme.colors.secondary2Font};
2429
+ &:active,
2430
+ &:focus,
2431
+ &:visited {
2432
+ color: ${theme.colors.secondary2Font};
2433
+ }
2434
+ `}
2435
+ ${props.variant === 'positive' && `
2436
+ text-align: center;
2437
+ background-color: ${theme.colors.positive};
2438
+ color: ${theme.colors.positiveFont};
2439
+ &:active,
2440
+ &:focus,
2441
+ &:visited {
2442
+ color: ${theme.colors.positiveFont};
2443
+ }
2444
+ `}
2445
+ ${props.variant === 'negative' && `
2446
+ text-align: center;
2447
+ background-color: ${theme.colors.negative};
2448
+ color: ${theme.colors.negativeFont};
2449
+ &:active,
2450
+ &:focus,
2451
+ &:visited {
2452
+ color: ${theme.colors.negativeFont};
2453
+ }
2454
+ `}
2455
+ ${props.variant === 'omg' && `
2456
+ text-align: center;
2457
+ background-color: ${theme.colors.omg};
2458
+ color: ${theme.colors.omgFont};
2459
+ &:active,
2460
+ &:focus,
2461
+ &:visited {
2462
+ color: ${theme.colors.omgFont};
2463
+ }
2464
+ `}
2465
+ ${props.variant === 'label' && `
2466
+ box-shadow: none;
2467
+ border: none;
2468
+ `}
2469
+ ${props.variant === 'icon' && `
2470
+ box-shadow: none;
2471
+ border: none;
2472
+ border-radius: 100%;
2473
+ width: ${theme.controls.height};
2474
+ text-align: center;
2475
+ `}
2476
+ ${props.block && `
2477
+ display: block;
2478
+ width:100%;
2479
+ `}
2480
+ ${props.iconBlock && `
2481
+ display: flex;
2482
+ justify-content: space-between;
2483
+ align-items: center;
2484
+ `}
2485
+ ${props.round && `
2486
+ border-radius: ${theme.controls.roundRadius};
2487
+ `}
2488
+ ${props.rounded && `
2489
+ border-radius: ${theme.controls.roundedRadius};
2490
+ `}
2491
+ ${props.small && `
2492
+ font-size: 0.8rem;
2493
+ height: ${theme.controls.heightSmall};
2494
+ line-height: ${theme.controls.heightSmall};
2495
+ `}
2496
+ `;
2497
+ const className = mergeClassNames('omniLink', props.className);
2498
+ const content = react.jsx(React__namespace.Fragment, null,
2499
+ react.jsx("span", null,
2500
+ props.leftIcon && react.jsx("span", { css: {
2501
+ marginRight: '1rem',
2502
+ display: 'inline-block',
2503
+ minWidth: '1.5rem',
2504
+ verticalAlign: 'middle'
2505
+ } }, props.leftIcon),
2506
+ props.children),
2507
+ props.rightIcon && react.jsx("span", { css: {
2508
+ marginLeft: '1rem',
2509
+ verticalAlign: 'middle'
2510
+ } }, props.rightIcon));
2511
+ if (props.noRouter) {
2512
+ return (react.jsx("a", { title: props.title, css: linkStyles, target: props.target, className: className, href: props.href, onClick: props.onClick }, content));
2513
+ }
2514
+ return (react.jsx(reactRouterDom.Link, { title: props.title, css: linkStyles, className: className, onClick: props.onClick, to: props.href }, content));
2515
+ };
2516
+
2517
+ /** @jsx jsx */
2518
+ const ProgressBar = (props) => {
2519
+ const bar = React__namespace.useRef(null);
2520
+ React__namespace.useEffect(() => {
2521
+ const pct = cleanPct(props.pct);
2522
+ if (bar.current) {
2523
+ bar.current.style.width = `${pct}%`;
2524
+ }
2525
+ });
2526
+ const theme = useThemeSafely();
2527
+ const barStyles = react.css `
2528
+ width: 100%;
2529
+ height: 1rem;
2530
+ border: ${theme.controls.border};
2531
+ background-color: ${theme.colors.progressBg};
2532
+ ${props.round && `
2533
+ border-radius: 1rem;
2534
+ `}
2535
+ `;
2536
+ const fillStyles = react.css `
2537
+ transition: width 0.5s ease-in-out;
2538
+ height: 100%;
2539
+ background-color: ${theme.colors.progressFill};
2540
+ ${props.round && `
2541
+ border-radius: 1rem;
2542
+ `}
2543
+ `;
2544
+ return (react.jsx("div", { className: "progressBar" },
2545
+ react.jsx("div", { css: barStyles, className: props.className },
2546
+ react.jsx("div", { ref: bar, css: fillStyles })),
2547
+ props.showPct && react.jsx(Text, { align: "center", tag: "div", spacedOut: true },
2548
+ props.pct,
2549
+ "\u00A0%")));
2550
+ };
2551
+ const cleanPct = (value) => {
2552
+ if (value) {
2553
+ return Math.min(Math.max(value, 0), 100);
2554
+ }
2555
+ return 0;
2556
+ };
2557
+
2558
+ /** @jsx jsx */
2559
+ const SearchBox = (props) => {
2560
+ const [waiting, onSubmit] = useWaiting(props.onSubmit || (() => Promise.resolve()));
2561
+ const theme = useThemeSafely();
2562
+ const submitButton = (react.jsx(Button, { disabled: waiting, readonly: !props.onSubmit, type: "submit", css: {
2563
+ color: `${theme.colors.font} !important;`,
2564
+ fontSize: '1rem'
2565
+ }, variant: "icon", small: true },
2566
+ react.jsx(Icon, { id: waiting ? 'waiting' : 'search', spin: waiting })));
2567
+ return (react.jsx(Form, { role: "search", className: mergeClassNames('searchBox', props.className), onSubmit: onSubmit },
2568
+ react.jsx(Input, { disabled: waiting, type: "text", value: props.value, placeholder: props.placeholder, round: props.round, rounded: props.rounded, onChange: props.onChange, rightControl: submitButton })));
2569
+ };
2570
+
2571
+ const ToggleButton = (props) => {
2572
+ return (React__namespace.createElement(Button, { type: "button", className: mergeClassNames('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));
2573
+ };
2574
+
2575
+ /** @jsx jsx */
2576
+ const ToggleButtonGroup = (props) => {
2577
+ const theme = useThemeSafely();
2578
+ const groupStyles = react.css `
2579
+ display: flex;
2580
+ box-shadow: ${theme.controls.boxShadow};
2581
+ ${props.round && `
2582
+ border-radius: ${theme.controls.roundRadius};
2583
+ `}
2584
+ `;
2585
+ const buttonStyles = react.css `
2586
+ flex-grow:1;
2587
+ box-shadow: none;
2588
+ &:nth-of-type(1n+2){
2589
+ margin-left: -1px;
2590
+ }
2591
+ ${props.round && `
2592
+ &:first-of-type{
2593
+ border-top-left-radius: ${theme.controls.roundRadius};
2594
+ border-bottom-left-radius: ${theme.controls.roundRadius};
2595
+ padding-left: 1rem;
2596
+ }
2597
+ &:last-child {
2598
+ border-top-right-radius: ${theme.controls.roundRadius};
2599
+ border-bottom-right-radius: ${theme.controls.roundRadius};
2600
+ padding-right: 1rem;
2601
+ }
2602
+ `}
2603
+ `;
2604
+ return (react.jsx("div", { css: groupStyles, className: mergeClassNames('toggleButtonGroup', props.className) }, props.options.map(o => {
2605
+ const active = o.id === props.value;
2606
+ return react.jsx(Button, { style: props.width ? { width: props.width } : undefined, small: props.small, rightIcon: o.rightIcon, key: o.id, tabIndex: active ? -1 : 0, css: react.css `
2607
+ ${buttonStyles}
2608
+ ${active && `
2609
+ background-color: ${theme.colors.font};
2610
+ color: ${theme.colors.bg};
2611
+ cursor: default;
2612
+ &:hover:not(:disabled) {
2613
+ filter: none;
2614
+ }
2615
+ &:focus {
2616
+ outline: none;
2617
+ box-shadow: none;
2618
+ }
2619
+ `}
2620
+ `, className: active ? o.activeClass : undefined, disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, onClick: () => {
2621
+ if (active) {
2622
+ return;
2623
+ }
2624
+ props.onChange(o.id);
2625
+ } }, o.name);
2626
+ })));
2627
+ };
2628
+
2629
+ /** @jsx jsx */
2630
+ const WaitingIndicator = (props) => {
2631
+ return (react.jsx(Modal, { className: "waitingIndicator", show: props.show, noBackground: true },
2632
+ react.jsx("div", { css: {
2633
+ color: 'white',
2634
+ fontSize: '3rem'
2635
+ } },
2636
+ react.jsx(Icon, { id: "waiting", spin: true }))));
2637
+ };
2638
+
2639
+ /** @jsx jsx */
2640
+ const Calendar = (p) => {
2641
+ var _a, _b, _c, _d;
2642
+ const theme = useThemeSafely();
2643
+ const cellSize = (_a = p.cellSize) !== null && _a !== void 0 ? _a : '3rem';
2644
+ const showTitle = (_b = p.title) !== null && _b !== void 0 ? _b : true;
2645
+ const calendarStyles = react.css({
2646
+ display: 'grid',
2647
+ gridTemplateColumns: `repeat(7, ${cellSize})`,
2648
+ });
2649
+ const cellStyles = react.css({
2650
+ border: 'none',
2651
+ backgroundColor: 'transparent',
2652
+ fontFamily: theme.fonts.family,
2653
+ fontSize: theme.fonts.size,
2654
+ color: theme.colors.font,
2655
+ display: 'flex',
2656
+ alignItems: 'center',
2657
+ justifyContent: 'center',
2658
+ borderTop: theme.controls.border,
2659
+ borderLeft: theme.controls.border,
2660
+ width: cellSize,
2661
+ height: cellSize
2662
+ });
2663
+ const rightCellStyles = react.css({
2664
+ borderRight: theme.controls.border
2665
+ });
2666
+ const bottomCellStyles = react.css({
2667
+ borderBottom: theme.controls.border
2668
+ });
2669
+ const nonDayStyles = react.css({
2670
+ backgroundColor: theme.colors.disabled
2671
+ });
2672
+ const clickableStyles = react.css({
2673
+ cursor: 'pointer',
2674
+ ':focus': {
2675
+ outline: 'none',
2676
+ boxShadow: theme.controls.focusOutlineShadow,
2677
+ position: 'relative',
2678
+ zIndex: 2
2679
+ },
2680
+ ":active": {
2681
+ boxShadow: 'none'
2682
+ },
2683
+ ":hover": {
2684
+ backgroundColor: theme.colors.lightBg,
2685
+ color: theme.colors.font,
2686
+ }
2687
+ });
2688
+ const monthStart = new Date(p.year, p.month - 1, 1);
2689
+ const days = dateFns.getDaysInMonth(monthStart);
2690
+ const startDayOfWeek = dateFns.getDay(monthStart);
2691
+ const dayEndIndex = startDayOfWeek + days - 1;
2692
+ const cellCount = p.fixedRows ? 42 : Math.ceil((days + startDayOfWeek) / 7) * 7;
2693
+ const bottomRowStartIndex = cellCount - 7;
2694
+ const currentDate = p.showCurrent ? new Date() : undefined;
2695
+ const selectedDate = p.selectedValue && dateFns.isSameMonth(p.selectedValue, monthStart) ? new Date(p.selectedValue) : undefined;
2696
+ const cells = [];
2697
+ for (let i = 0; i < cellCount; i++) {
2698
+ const dayOfMonth = i >= startDayOfWeek && i <= dayEndIndex ? i - startDayOfWeek + 1 : undefined;
2699
+ const cellDate = dayOfMonth ? new Date(p.year, p.month - 1, dayOfMonth) : undefined;
2700
+ let canInteract = !!cellDate;
2701
+ if (p.min && dateFns.isBefore(cellDate !== null && cellDate !== void 0 ? cellDate : 0, p.min)) {
2702
+ canInteract = false;
2703
+ }
2704
+ if (p.max && dateFns.isAfter(cellDate !== null && cellDate !== void 0 ? cellDate : 0, p.max)) {
2705
+ canInteract = false;
2706
+ }
2707
+ if (cellDate && p.onClick && ((_c = p.isCellDisabled) === null || _c === void 0 ? void 0 : _c.call(p, cellDate))) {
2708
+ canInteract = false;
2709
+ }
2710
+ const styles = react.css(cellStyles, (i + 1) % 7 === 0 && rightCellStyles, i >= bottomRowStartIndex && bottomCellStyles, !canInteract && nonDayStyles, currentDate && cellDate && dateFns.isSameDay(currentDate, cellDate) && { fontWeight: 'bold' }, selectedDate && cellDate && dateFns.isSameDay(selectedDate, cellDate) && { backgroundColor: theme.colors.primary, color: theme.colors.primaryFont }, canInteract && p.onClick && clickableStyles);
2711
+ const onClick = canInteract && p.onClick ? () => {
2712
+ var _a;
2713
+ if (cellDate) {
2714
+ (_a = p.onClick) === null || _a === void 0 ? void 0 : _a.call(p, cellDate);
2715
+ }
2716
+ } : undefined;
2717
+ const cellContent = cellDate && (p.renderCell ? p.renderCell(cellDate) : cellDate.getDate());
2718
+ const cell = onClick ? (react.jsx("button", { type: "button", key: i, css: styles, onClick: onClick }, cellContent)) : (react.jsx("div", { key: i, css: styles }, cellContent));
2719
+ cells.push(cell);
2720
+ }
2721
+ return (react.jsx("div", { id: p.id, className: "calendar" },
2722
+ showTitle && ((_d = p.customTitle) !== null && _d !== void 0 ? _d : react.jsx(Text, { larger: true, align: "center" },
2723
+ dateFns.format(monthStart, 'LLLL'),
2724
+ p.yearInTitle && ` ${p.year}`)),
2725
+ react.jsx("div", { css: calendarStyles },
2726
+ ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => {
2727
+ return (react.jsx(Text, { style: { paddingBottom: '0.25rem' }, key: day, smaller: p.smallHeader, noPad: true, align: "center" }, day));
2728
+ }),
2729
+ cells)));
2730
+ };
2731
+
2732
+ /** @jsx jsx */
2733
+ const getCalendarDate = (date, min, max) => {
2734
+ let calendarDate = date ? new Date(date) : new Date();
2735
+ // if there is a min/max we don't want the calendar to open to the current date if it's out of range
2736
+ if (min && dateFns.isBefore(calendarDate, min)) {
2737
+ calendarDate = new Date(min);
2738
+ }
2739
+ else if (max && dateFns.isAfter(calendarDate, max)) {
2740
+ calendarDate = new Date(max);
2741
+ }
2742
+ return calendarDate;
2743
+ };
2744
+ const DatePicker = (p) => {
2745
+ const [showCalendar, setShowCalendar] = React__namespace.useState(false);
2746
+ const [calendarDate, setCalendarDate] = React__namespace.useState(getCalendarDate(p.value, p.min, p.max));
2747
+ // controls the one-time focus set on show
2748
+ const needsFocus = React__namespace.useRef(false);
2749
+ const popover = React__namespace.useRef(null);
2750
+ React__namespace.useEffect(() => {
2751
+ var _a;
2752
+ setCalendarDate(getCalendarDate((_a = p.value) !== null && _a !== void 0 ? _a : 0, p.min, p.max));
2753
+ }, [p.value]);
2754
+ React__namespace.useLayoutEffect(() => {
2755
+ var _a, _b;
2756
+ if (needsFocus.current) {
2757
+ (_b = (_a = popover.current) === null || _a === void 0 ? void 0 : _a.querySelector('button')) === null || _b === void 0 ? void 0 : _b.focus();
2758
+ needsFocus.current = false;
2759
+ }
2760
+ });
2761
+ return (react.jsx(Popover, { reposition: p.reposition, isOpen: showCalendar, onClickOutside: () => {
2762
+ needsFocus.current = false;
2763
+ setShowCalendar(false);
2764
+ }, parent: (react.jsx(Input, Object.assign({ onFocus: () => {
2765
+ needsFocus.current = false;
2766
+ setShowCalendar(false);
2767
+ }, placeholder: 'MM/DD/YYYY' }, p, { type: "date", rightControl: !p.readOnly ? (react.jsx(Button, { variant: "icon", readonly: p.readOnly, disabled: p.disabled, small: true, style: {
2768
+ fontSize: '1rem'
2769
+ }, onClick: () => {
2770
+ needsFocus.current = !showCalendar;
2771
+ setShowCalendar(!showCalendar);
2772
+ } },
2773
+ react.jsx(Icon, { id: "pickDate" }))) : undefined, onChange: v => {
2774
+ p.onChange(v);
2775
+ } }))), content: (react.jsx("div", { ref: popover, css: {
2776
+ paddingLeft: '1rem',
2777
+ paddingRight: '1rem',
2778
+ paddingBottom: '1rem',
2779
+ } },
2780
+ react.jsx(Calendar, { onClick: date => {
2781
+ p.onChange(date.valueOf());
2782
+ needsFocus.current = false;
2783
+ setShowCalendar(false);
2784
+ }, customTitle: react.jsx("div", { css: {
2785
+ display: 'flex',
2786
+ justifyContent: 'space-between',
2787
+ alignItems: 'center'
2788
+ } },
2789
+ react.jsx(Button, { disabled: !!p.min && dateFns.isBefore(dateFns.endOfMonth(dateFns.addMonths(calendarDate, -1)), p.min), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, -1)) },
2790
+ react.jsx(Icon, { id: "pagerLeft" })),
2791
+ react.jsx(Text, { align: "center" },
2792
+ dateFns.format(calendarDate, 'LLLL'),
2793
+ " ",
2794
+ calendarDate.getFullYear()),
2795
+ react.jsx(Button, { disabled: !!p.max && dateFns.isAfter(dateFns.startOfMonth(dateFns.addMonths(calendarDate, 1)), p.max), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, 1)) },
2796
+ react.jsx(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 }))) }));
2797
+ };
2798
+
2799
+ /** @jsx jsx */
2800
+ const TabHeader = (p) => {
2801
+ var _a;
2802
+ const [tabIndex, setTabIndex] = React__namespace.useState(0);
2803
+ const theme = useThemeSafely();
2804
+ const variant = (_a = p.variant) !== null && _a !== void 0 ? _a : 'tab';
2805
+ const menuStyles = react.css({
2806
+ display: 'flex',
2807
+ gap: theme.controls.gap,
2808
+ listStyleType: 'none',
2809
+ margin: 0,
2810
+ padding: 0,
2811
+ flexWrap: variant === 'button' ? 'wrap' : 'nowrap'
2812
+ }, variant === 'button' && {
2813
+ borderBottom: theme.controls.border,
2814
+ paddingBottom: '1rem'
2815
+ });
2816
+ return (react.jsx("div", { className: "tabHeader" },
2817
+ react.jsx("ul", { css: menuStyles }, p.tabs.map((tab, index) => {
2818
+ var _a, _b;
2819
+ const active = index === tabIndex;
2820
+ let tabStyles;
2821
+ let buttonStyles;
2822
+ let buttonVariant;
2823
+ if (variant === 'tab') {
2824
+ tabStyles = react.css({
2825
+ paddingLeft: '1rem',
2826
+ paddingRight: '1rem',
2827
+ backgroundColor: theme.colors.bg,
2828
+ zIndex: 1,
2829
+ }, active && {
2830
+ border: theme.controls.border,
2831
+ borderBottom: 'none',
2832
+ zIndex: 3,
2833
+ }, active && p.rounded && {
2834
+ borderRadius: p.rounded && theme.controls.roundedRadius,
2835
+ borderBottomLeftRadius: 0,
2836
+ borderBottomRightRadius: 0
2837
+ });
2838
+ buttonVariant = 'link';
2839
+ buttonStyles = react.css({
2840
+ maxWidth: (_a = p.maxTabWidth) !== null && _a !== void 0 ? _a : '10rem',
2841
+ overflow: 'hidden'
2842
+ });
2843
+ }
2844
+ else {
2845
+ buttonVariant = active ? 'primary' : undefined;
2846
+ buttonStyles = react.css({
2847
+ paddingLeft: '1rem',
2848
+ paddingRight: '1rem',
2849
+ maxWidth: (_b = p.maxTabWidth) !== null && _b !== void 0 ? _b : '10rem',
2850
+ overflow: 'hidden',
2851
+ });
2852
+ }
2853
+ return (react.jsx("li", { key: index, css: tabStyles },
2854
+ react.jsx(Button, { css: buttonStyles, variant: buttonVariant, title: tab.name, readonly: active, rounded: p.rounded && variant === 'button', onClick: () => {
2855
+ setTabIndex(index);
2856
+ if (p.onTabChanged) {
2857
+ p.onTabChanged(index);
2858
+ }
2859
+ } }, tab.name)));
2860
+ })),
2861
+ variant === 'tab' && (react.jsx("div", { css: {
2862
+ borderBottom: theme.controls.border,
2863
+ marginTop: `calc(${theme.controls.borderWidth} * -1)`,
2864
+ zIndex: 2,
2865
+ position: 'relative'
2866
+ } }))));
2867
+ };
2868
+
2869
+ const GlobalStyles = (p) => {
2870
+ const theme = useThemeSafely();
2871
+ return (React__namespace.createElement(react.Global, { styles: react.css({
2872
+ '*': {
2873
+ boxSizing: 'border-box'
2874
+ },
2875
+ 'html,body': {
2876
+ backgroundColor: theme.colors.bg,
2877
+ color: theme.colors.font,
2878
+ margin: 0
2879
+ },
2880
+ 'html,body,main': {
2881
+ height: '100%',
2882
+ fontFamily: theme.fonts.family,
2883
+ fontSize: theme.fonts.size
2884
+ },
2885
+ 'main': {
2886
+ height: 'auto',
2887
+ minHeight: '100%',
2888
+ padding: '0 1rem'
2889
+ },
2890
+ 'pre': {
2891
+ backgroundColor: theme.colors.lightBg
2892
+ }
2893
+ }) }));
2894
+ };
2895
+
2896
+ /** @jsx jsx */
2897
+ const DEFAULT_FAILURE_MESSAGE = 'Upload failed.';
2898
+ const FileUploader = (p) => {
2899
+ var _a;
2900
+ const [message, setMessage] = React.useState(undefined);
2901
+ const [canUpload, setCanUpload] = React.useState(false);
2902
+ const [uploading, setUploading] = React.useState(false);
2903
+ const [files, setFiles] = React.useState(undefined);
2904
+ const [fullFailureMessage, setFullFailureMessage] = React.useState(undefined);
2905
+ const clearFilePickerHandler = React.useRef(() => {
2906
+ // noop
2907
+ });
2908
+ const { buttonText, successMessage, failureMessage, buttonWidth, buttonVariant, onChange } = p, filePickerProps = __rest(p, ["buttonText", "successMessage", "failureMessage", "buttonWidth", "buttonVariant", "onChange"]);
2909
+ const onClear = () => {
2910
+ var _a;
2911
+ (_a = clearFilePickerHandler.current) === null || _a === void 0 ? void 0 : _a.call(clearFilePickerHandler);
2912
+ setMessage(undefined);
2913
+ };
2914
+ return (react.jsx(Form, { onSubmit: () => {
2915
+ if (!files) {
2916
+ return;
2917
+ }
2918
+ setUploading(true);
2919
+ p.onUpload(files).then(() => {
2920
+ setMessage('success');
2921
+ if (p.clearOnUpload) {
2922
+ clearFilePickerHandler.current();
2923
+ }
2924
+ }).catch(err => {
2925
+ setMessage('failure');
2926
+ setFullFailureMessage(`${failureMessage !== null && failureMessage !== void 0 ? failureMessage : DEFAULT_FAILURE_MESSAGE} Error: ${err instanceof Error ? err.message : err}`);
2927
+ }).finally(() => {
2928
+ setUploading(false);
2929
+ setCanUpload(false);
2930
+ });
2931
+ } },
2932
+ react.jsx(FilePicker, Object.assign({}, filePickerProps, { onChange: filesFromPicker => {
2933
+ setFiles(filesFromPicker);
2934
+ setCanUpload(!!(filesFromPicker === null || filesFromPicker === void 0 ? void 0 : filesFromPicker.length));
2935
+ setMessage(undefined);
2936
+ setFullFailureMessage(undefined);
2937
+ if (onChange) {
2938
+ return onChange(filesFromPicker);
2939
+ }
2940
+ return false;
2941
+ }, __passClearFilesHandle: func => clearFilePickerHandler.current = func })),
2942
+ react.jsx("span", null,
2943
+ react.jsx(Button, { css: { width: (_a = p.buttonWidth) !== null && _a !== void 0 ? _a : '10rem' }, disabled: !canUpload, waiting: uploading, type: "submit", variant: buttonVariant !== null && buttonVariant !== void 0 ? buttonVariant : 'primary', rightIcon: react.jsx(Icon, { id: "save" }) }, buttonText !== null && buttonText !== void 0 ? buttonText : 'Upload')),
2944
+ message === 'success' && (react.jsx(UploadInfoPanel, { variant: "positive", message: successMessage !== null && successMessage !== void 0 ? successMessage : 'Upload successful.', onClear: onClear })),
2945
+ message === 'failure' && (react.jsx(UploadInfoPanel, { variant: "error", message: fullFailureMessage, onClear: onClear }))));
2946
+ };
2947
+ const UploadInfoPanel = (p) => {
2948
+ useThemeSafely();
2949
+ return (react.jsx(InfoPanel, { variant: p.variant },
2950
+ p.message,
2951
+ react.jsx(Button, { block: true, className: css.css({
2952
+ color: 'inherit',
2953
+ marginTop: '1rem'
2954
+ }), onClick: p.onClear, rightIcon: react.jsx(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear")));
2955
+ };
2956
+
2957
+ const CopyButton = (props) => {
2958
+ const [copied, setCopied] = React__namespace.useState(false);
2959
+ return (React__namespace.createElement(Button, { title: copied ? 'Copied!' : (props.title || 'Copy to clipboard'), variant: "icon", onBlur: () => {
2960
+ setCopied(false);
2961
+ }, onClick: e => {
2962
+ const button = e.currentTarget;
2963
+ let copySuccess = false;
2964
+ try {
2965
+ const text = document.querySelector(props.selector);
2966
+ text.select();
2967
+ copySuccess = document.execCommand('copy');
2968
+ // the input gets focus on select. bring it back.
2969
+ button.focus();
2970
+ }
2971
+ catch (err) {
2972
+ // You done wrong.
2973
+ }
2974
+ setCopied(copySuccess);
2975
+ } },
2976
+ React__namespace.createElement(Icon, { id: copied ? 'paste' : 'copy' })));
2977
+ };
2978
+
2979
+ const TogglePasswordInput = (p) => {
2980
+ const [show, setShow] = React__namespace.useState(false);
2981
+ return (React__namespace.createElement(Input, Object.assign({}, p, { type: show ? 'text' : 'password', rightControl: (React__namespace.createElement(Button, { variant: "icon", onClick: () => {
2982
+ setShow(previous => !previous);
2983
+ } },
2984
+ React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
2985
+ };
2986
+
2987
+ const BoundStaticPager = (p) => {
2988
+ var _a, _b, _c, _d, _e, _f;
2989
+ const { result, showPageText } = p, rest = __rest(p, ["result", "showPageText"]);
2990
+ const showLimit = !!(result.limit && p.limitOptions && p.limitOptions.length > 1 && p.onLimit);
2991
+ const showSort = !!(p.sort && p.sortOptions && p.sortOptions.length > 1 && p.onSort);
2992
+ return (React__namespace.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__namespace.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
2993
+ React__namespace.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__namespace.createElement(Label, { text: (_d = p.sortText) !== null && _d !== void 0 ? _d : 'Sort', orientation: "horizontalReverse" },
2994
+ React__namespace.createElement(Picker, { type: "select", value: (_e = p.sort) !== null && _e !== void 0 ? _e : '', options: (_f = p.sortOptions) !== null && _f !== void 0 ? _f : [], onChange: v => {
2995
+ var _a;
2996
+ (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v);
2997
+ } }))) : undefined, page: d => {
2998
+ p.onPage(d);
2999
+ } })));
3000
+ };
3001
+
3002
+ /** @jsx jsx */
3003
+ const Slider = (p) => {
3004
+ const theme = useThemeSafely();
3005
+ const currentValue = React.useRef(p.value);
3006
+ const height = p.showValue ? `calc(${theme.controls.height} + 1.5rem)` : theme.controls.height;
3007
+ return (react.jsx("div", { css: {
3008
+ width: '100%',
3009
+ height,
3010
+ } },
3011
+ react.jsx(ReactSlider__default['default'], { step: p.step, min: p.min, max: p.max, value: p.value, onAfterChange: (value, index) => {
3012
+ p.onChange(value);
3013
+ }, onChange: p.onUpdate || p.showValue ? (value, index) => {
3014
+ var _a;
3015
+ currentValue.current = value;
3016
+ (_a = p.onUpdate) === null || _a === void 0 ? void 0 : _a.call(p, value);
3017
+ } : undefined, renderTrack: (props, state) => {
3018
+ return react.jsx("div", Object.assign({ css: {
3019
+ display: 'flex',
3020
+ alignItems: 'center',
3021
+ height: theme.controls.height
3022
+ } }, props),
3023
+ react.jsx("div", { css: {
3024
+ backgroundColor: theme.colors.secondary,
3025
+ height: `calc(${theme.controls.height} / 4)`,
3026
+ borderRadius: theme.controls.roundRadius,
3027
+ width: '100%'
3028
+ } }));
3029
+ }, renderThumb: (props, state) => {
3030
+ return (react.jsx("div", Object.assign({ css: {
3031
+ width: theme.controls.height,
3032
+ height: theme.controls.height,
3033
+ borderRadius: theme.controls.roundRadius,
3034
+ backgroundColor: 'white',
3035
+ border: theme.controls.border,
3036
+ cursor: 'grab',
3037
+ boxShadow: theme.controls.boxShadow,
3038
+ transition: theme.controls.transition,
3039
+ '&:focus': {
3040
+ outline: 'none',
3041
+ boxShadow: theme.controls.focusOutlineShadow
3042
+ },
3043
+ '&:active': {
3044
+ boxShadow: 'none',
3045
+ cursor: 'grabbing'
3046
+ },
3047
+ '&:hover': {
3048
+ filter: theme.controls.hoverBrightness
3049
+ }
3050
+ } }, props), p.showValue && react.jsx(HandleText, { value: currentValue.current, index: state.index, renderValue: p.renderValue })));
3051
+ } })));
3052
+ };
3053
+ const HandleText = (p) => {
3054
+ var _a, _b, _c;
3055
+ const theme = useThemeSafely();
3056
+ const value = Array.isArray(p.value) ? p.value[(_a = p.index) !== null && _a !== void 0 ? _a : 0] : p.value;
3057
+ const displayValue = (_c = (_b = p.renderValue) === null || _b === void 0 ? void 0 : _b.call(p, value)) !== null && _c !== void 0 ? _c : value;
3058
+ return (react.jsx(Text, { css: {
3059
+ //width: theme.controls.height,
3060
+ width: `calc(${theme.controls.height} * 2)`,
3061
+ left: `calc(${theme.controls.height} / 2 * -1)`,
3062
+ bottom: '-1.5rem',
3063
+ position: 'absolute',
3064
+ overflow: 'hidden'
3065
+ }, tag: "div", align: "center" }, displayValue));
3066
+ };
3067
+
3068
+ exports.Backdrop = Backdrop;
3069
+ exports.BoundMemoryPager = BoundMemoryPager;
3070
+ exports.BoundStaticPager = BoundStaticPager;
3071
+ exports.Button = Button;
3072
+ exports.Calendar = Calendar;
3073
+ exports.Checkbox = Checkbox;
3074
+ exports.ConfirmModal = ConfirmModal;
3075
+ exports.CopyButton = CopyButton;
3076
+ exports.DatePicker = DatePicker;
3077
+ exports.Divider = Divider;
3078
+ exports.ErrorModal = ErrorModal;
3079
+ exports.FilePicker = FilePicker;
3080
+ exports.FileUploader = FileUploader;
3081
+ exports.Form = Form;
3082
+ exports.FormColumnRow = FormColumnRow;
3083
+ exports.FormFlexRow = FormFlexRow;
3084
+ exports.GlobalStyles = GlobalStyles;
3085
+ exports.Header = Header;
3086
+ exports.Highlight = Highlight;
3087
+ exports.ICONS = ICONS;
3088
+ exports.Icon = Icon;
3089
+ exports.Image = Image;
3090
+ exports.InfoPanel = InfoPanel;
3091
+ exports.InfoTip = InfoTip;
3092
+ exports.Input = Input;
3093
+ exports.ItemPager = ItemPager;
3094
+ exports.Label = Label;
3095
+ exports.List = List;
3096
+ exports.ListItem = ListItem;
3097
+ exports.Modal = Modal;
3098
+ exports.Nav = Nav;
3099
+ exports.OmniLink = OmniLink;
3100
+ exports.PagedResult = PagedResult;
3101
+ exports.Pager = Pager;
3102
+ exports.Picker = Picker;
3103
+ exports.Popover = Popover;
3104
+ exports.ProgressBar = ProgressBar;
3105
+ exports.SearchBox = SearchBox;
3106
+ exports.Slider = Slider;
3107
+ exports.TabHeader = TabHeader;
3108
+ exports.TabLocker = TabLocker;
3109
+ exports.Table = Table;
3110
+ exports.Td = Td;
3111
+ exports.TdCurrency = TdCurrency;
3112
+ exports.TdNumber = TdNumber;
3113
+ exports.Text = Text;
3114
+ exports.Th = Th;
3115
+ exports.ThSort = ThSort;
3116
+ exports.ToggleButton = ToggleButton;
3117
+ exports.ToggleButtonGroup = ToggleButtonGroup;
3118
+ exports.TogglePasswordInput = TogglePasswordInput;
3119
+ exports.Tr = Tr;
3120
+ exports.WaitingIndicator = WaitingIndicator;
3121
+ exports.calcDynamicThemeProps = calcDynamicThemeProps;
3122
+ exports.defaultTheme = defaultTheme;
3123
+ exports.getCurrencyDisplay = getCurrencyDisplay;
3124
+ exports.mergeClassNames = mergeClassNames;
3125
+ exports.useThemeSafely = useThemeSafely;
3126
+ //# sourceMappingURL=index.js.map