@mackin.com/styleguide 11.0.11 → 11.1.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 (4) hide show
  1. package/index.d.ts +188 -162
  2. package/index.esm.js +1248 -1153
  3. package/index.js +1248 -1152
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -1260,6 +1260,128 @@ const styles = {
1260
1260
  }),
1261
1261
  };
1262
1262
 
1263
+ const defaultMinChars = 3;
1264
+ class AutocompleteController {
1265
+ constructor(getOptions, config) {
1266
+ var _a;
1267
+ this._value = undefined;
1268
+ this._options = [];
1269
+ this._minChars = (_a = config === null || config === void 0 ? void 0 : config.minChars) !== null && _a !== void 0 ? _a : defaultMinChars;
1270
+ if (config === null || config === void 0 ? void 0 : config.debounceMs) {
1271
+ this.getOptions = createDebouncedPromise(getOptions, config === null || config === void 0 ? void 0 : config.debounceMs);
1272
+ }
1273
+ else {
1274
+ this.getOptions = getOptions;
1275
+ }
1276
+ }
1277
+ get value() {
1278
+ return this._value;
1279
+ }
1280
+ get options() {
1281
+ return this._options;
1282
+ }
1283
+ async onChange(newValue) {
1284
+ // don't make getOptions calls if the value hasn't changed.
1285
+ if (newValue === this.value) {
1286
+ return;
1287
+ }
1288
+ // nullish should not make the getOptions call and instead clear everything.
1289
+ if (!newValue) {
1290
+ this._value = newValue;
1291
+ this._options = [];
1292
+ return;
1293
+ }
1294
+ // sub min chars should clear everything and not attempt the getOptions call.
1295
+ if (newValue.length < this._minChars) {
1296
+ this._value = newValue;
1297
+ this._options = [];
1298
+ return;
1299
+ }
1300
+ try {
1301
+ this._value = newValue;
1302
+ this._options = (await this.getOptions(newValue));
1303
+ }
1304
+ catch (err) {
1305
+ // this method will throw errors on debounce rejections. that is to be expected.
1306
+ // for actual getOptions exceptions, the owner of that function will need to handle errors.
1307
+ }
1308
+ }
1309
+ onPick(newValue) {
1310
+ this._value = newValue;
1311
+ this._options = [];
1312
+ }
1313
+ }
1314
+ const createDebouncedPromise = (originalFunction, trailingTimeoutMs) => {
1315
+ let timer;
1316
+ let onCancel;
1317
+ return (value) => {
1318
+ if (timer) {
1319
+ clearTimeout(timer);
1320
+ }
1321
+ if (onCancel) {
1322
+ onCancel('Promise cancelled due to in-progress debounce call.');
1323
+ onCancel = undefined;
1324
+ }
1325
+ return new Promise((res, rej) => {
1326
+ onCancel = rej;
1327
+ timer = setTimeout(() => {
1328
+ originalFunction(value)
1329
+ .then(values => {
1330
+ res(values);
1331
+ })
1332
+ .catch(err => {
1333
+ rej(err);
1334
+ })
1335
+ .finally(() => {
1336
+ clearTimeout(timer);
1337
+ });
1338
+ }, trailingTimeoutMs);
1339
+ });
1340
+ };
1341
+ };
1342
+
1343
+ /** Extracted logic around autocomplete functionality for Autocomplete.tsx that supports Entity (id/name) mapping. */
1344
+ class AutocompleteEntityController {
1345
+ constructor(getOptions, config) {
1346
+ this._options = [];
1347
+ const getStringOptions = async (value) => {
1348
+ this._options = await getOptions(value);
1349
+ return this._options.map(o => o.name);
1350
+ };
1351
+ this._ctrl = new AutocompleteController(getStringOptions, config);
1352
+ }
1353
+ get entity() {
1354
+ return this._pickedEntity;
1355
+ }
1356
+ get entities() {
1357
+ return this._options;
1358
+ }
1359
+ get value() {
1360
+ return this._ctrl.value;
1361
+ }
1362
+ get options() {
1363
+ return this._options.map(o => o.name);
1364
+ }
1365
+ async onChange(newValue) {
1366
+ const clearEntity = newValue !== this._ctrl.value;
1367
+ await this._ctrl.onChange(newValue);
1368
+ if (clearEntity) {
1369
+ this._pickedEntity = undefined;
1370
+ }
1371
+ this.trySyncCtrlOptions();
1372
+ }
1373
+ onPick(newValue) {
1374
+ this._ctrl.onPick(newValue);
1375
+ this._pickedEntity = this._options.find(o => o.name === this._ctrl.value);
1376
+ this.trySyncCtrlOptions();
1377
+ }
1378
+ trySyncCtrlOptions() {
1379
+ if (!this._ctrl.options.length) {
1380
+ this._options = [];
1381
+ }
1382
+ }
1383
+ }
1384
+
1263
1385
  /** Returns a UID. Use this instead of a direct call to a library. */
1264
1386
  function createUid() {
1265
1387
  return lodash.uniqueId();
@@ -1632,55 +1754,37 @@ const Checkbox = (props) => {
1632
1754
  finalCheckedColor = checkedColor;
1633
1755
  }
1634
1756
  }
1635
- const checkboxStyles = css.css `
1636
- display: inline-block;
1637
- ${!props.disabled && !readOnly && `
1638
- &:hover {
1639
- filter: ${theme.controls.hoverBrightness};
1640
- }
1641
- `}
1642
- `;
1643
- const labelStyles = css.css `
1644
- cursor: pointer;
1645
- user-select: none;
1646
- display: flex;
1647
- align-items: center;
1648
- ${props.disabled && `
1649
- cursor: not-allowed;
1650
- `}
1651
- ${readOnly && `
1652
- cursor: default;
1653
- `}
1654
- `;
1655
- // had to reference a marker class ('checkboxIcon') here for the sibling selector to work.
1656
- // opacity: 0 required for firefox. ignores the width of 0.
1657
- const nativeCheckboxStyles = css.css `
1658
- margin: 0;
1659
- padding: 0;
1660
- width: 0;
1661
- opacity: 0;
1662
-
1663
- ${!readOnly && `
1664
- &:focus + .checkboxIcon {
1665
- box-shadow: ${theme.controls.focusOutlineShadow};
1666
- }
1667
- `}
1668
- `;
1669
- const iconStyles = css.css `
1670
- ${!!label && !hideLabel && `
1671
- margin-right: 0.5rem;
1672
- `}
1673
- ${props.disabled && `
1674
- background-color: ${theme.colors.disabled};
1675
- cursor: not-allowed;
1676
- `}
1677
- ${readOnly && `
1678
- cursor: default;
1679
- `}
1680
- ${props.checked && `
1681
- color: ${finalCheckedColor}
1682
- `}
1683
- `;
1757
+ const checkboxStyles = css.css({
1758
+ display: 'inline-block',
1759
+ '&:hover': (!props.disabled && !readOnly) ? {
1760
+ filter: theme.controls.hoverBrightness
1761
+ } : undefined
1762
+ });
1763
+ const cursor = props.disabled ? 'not-allowed' : props.readOnly ? 'default' : 'pointer';
1764
+ const labelStyles = css.css({
1765
+ cursor,
1766
+ userSelect: 'none',
1767
+ display: 'flex',
1768
+ alignItems: 'center',
1769
+ position: 'relative'
1770
+ });
1771
+ const nativeCheckboxStyles = css.css({
1772
+ margin: 0,
1773
+ padding: 0,
1774
+ inset: 0,
1775
+ position: 'absolute',
1776
+ opacity: 0,
1777
+ cursor,
1778
+ '&:focus + .checkboxIcon': !readOnly ? {
1779
+ boxShadow: theme.controls.focusOutlineShadow
1780
+ } : undefined
1781
+ });
1782
+ const iconStyles = css.css({
1783
+ marginRight: (!!label && !hideLabel) ? '0.5rem' : undefined,
1784
+ backgroundColor: props.disabled ? theme.colors.disabled : undefined,
1785
+ cursor,
1786
+ color: props.checked ? finalCheckedColor : uncheckedIcon
1787
+ });
1684
1788
  return (React__namespace.createElement("span", { className: css.cx('checkbox', checkboxStyles, props.className) },
1685
1789
  React__namespace.createElement("label", { className: labelStyles },
1686
1790
  React__namespace.createElement("input", Object.assign({}, inputProps, { "aria-label": hideLabel ? label : undefined, tabIndex: readOnly ? -1 : (_a = props.tabIndex) !== null && _a !== void 0 ? _a : undefined, className: nativeCheckboxStyles, type: "checkbox", onChange: e => {
@@ -2996,132 +3100,30 @@ const Label = (props) => {
2996
3100
  return (React__namespace.createElement("label", Object.assign({}, labelProps, { htmlFor: htmlFor, className: css.cx('label', labelStyles, outerClass) }), content));
2997
3101
  };
2998
3102
 
2999
- const Nav = (props) => {
3000
- var _a, _b, _c, _d;
3001
- const nav = React__namespace.useRef(null);
3002
- const theme = useThemeSafely();
3003
- const navWidth = (_a = props.navWidth) !== null && _a !== void 0 ? _a : theme.layout.navWidth;
3004
- const totalNavOffset = `calc(${navWidth} + 20px)`;
3005
- const backdrop = useBackdropContext();
3006
- const log = useLogger(`Nav ${(_b = props.id) !== null && _b !== void 0 ? _b : '?'}`, (_c = props.__debug) !== null && _c !== void 0 ? _c : false);
3007
- const slideMs = (_d = props.slideMs) !== null && _d !== void 0 ? _d : theme.timings.nav.slideMs;
3008
- const slideRight = css.keyframes `
3009
- 0% {
3010
- transform: translateX(0);
3011
- }
3012
-
3013
- 100% {
3014
- transform: translateX(${totalNavOffset});
3015
- }
3016
- `;
3017
- const slideLeft = css.keyframes `
3018
- 0% {
3019
- transform: translateX(${totalNavOffset});
3020
- }
3021
-
3022
- 100% {
3023
- transform: translateX(0px);
3024
- }
3025
- `;
3026
- const classNavShowing = css.css `
3027
- animation: ${slideRight} ${slideMs}ms cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
3028
- `;
3029
- const classNavNotShowing = css.css `
3030
- animation: ${slideLeft} ${slideMs}ms cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
3031
- `;
3032
- const zIndex = theme.zIndexes.nav;
3033
- // the padding-top here is to offset the navs' content from the header. the shadow creeps over it.
3034
- const navStyles = css.css `
3035
- label: Nav;
3036
- position: fixed;
3037
- top: 0;
3038
- left: calc(${totalNavOffset} * -1);
3039
- bottom: 0;
3040
- background-color: ${theme.colors.nav};
3041
- color: ${theme.colors.navFont};
3042
- width: ${navWidth};
3043
- min-width: ${navWidth};
3044
- box-shadow: 4px 2px 12px 6px rgba(0, 0, 0, 0.2);
3045
- z-index: ${zIndex};
3046
- overflow-y: auto;
3047
- .omniLink, .omniLink:active, .omniLink:focus, .omniLink:visited {
3048
- color: ${theme.colors.navFont};
3049
- }
3050
- padding-top:0;
3051
- `;
3052
- React__namespace.useEffect(() => {
3053
- if (!backdrop.showing) {
3054
- props.toggle(false);
3055
- }
3056
- }, [backdrop.showing]);
3057
- useBooleanChanged((current, previous) => {
3058
- var _a;
3059
- log('show changed', `${previous !== null && previous !== void 0 ? previous : 'undefined'} > ${current}`);
3060
- backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
3061
- if (!props.show && props.onCloseFocusId) {
3062
- const focusId = props.onCloseFocusId;
3063
- setTimeout(() => {
3064
- var _a;
3065
- (_a = document.getElementById(focusId)) === null || _a === void 0 ? void 0 : _a.focus();
3066
- }, 0);
3067
- }
3068
- }, props.show);
3069
- React__namespace.useLayoutEffect(() => {
3070
- if (nav && nav.current) {
3071
- if (props.show) {
3072
- if (!nav.current.classList.contains(classNavShowing)) {
3073
- nav.current.classList.add(classNavShowing);
3074
- setTimeout(() => {
3075
- var _a;
3076
- (_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
3077
- }, slideMs + 1);
3078
- }
3079
- }
3080
- else {
3081
- if (nav.current.classList.contains(classNavShowing)) {
3082
- nav.current.classList.remove(classNavShowing);
3083
- nav.current.classList.add(classNavNotShowing);
3084
- setTimeout(() => {
3085
- if (nav && nav.current) {
3086
- nav.current.classList.remove(classNavNotShowing);
3087
- }
3088
- }, slideMs);
3089
- }
3090
- }
3091
- }
3092
- });
3093
- return (React__namespace.createElement("nav", { role: "dialog", "aria-modal": "true", "aria-label": props.ariaLabel, ref: nav, className: css.cx('nav', navStyles, props.className), onKeyDown: e => {
3094
- if (e.code === 'Escape') {
3095
- props.toggle(false);
3096
- }
3097
- } },
3098
- React__namespace.createElement(TabLocker, { className: css.css({ height: '100%' }) }, props.children)));
3099
- };
3100
-
3101
- const LinkContent = (props) => {
3102
- return (React__namespace.createElement(React__namespace.Fragment, null,
3103
- React__namespace.createElement("span", null,
3104
- props.leftIcon && React__namespace.createElement("span", { className: css.css({
3105
- label: 'LinkLeftIcon',
3106
- marginRight: '1rem',
3107
- display: 'inline-block',
3108
- minWidth: '1.5rem',
3109
- verticalAlign: 'middle'
3110
- }) }, props.leftIcon),
3111
- props.waiting ? React__namespace.createElement(Icon, { id: "waiting", spin: true }) : props.children),
3112
- props.rightIcon && React__namespace.createElement("span", { className: css.css({
3113
- label: 'LinkRightIcon',
3114
- marginLeft: '1rem',
3115
- verticalAlign: 'middle'
3116
- }) }, props.rightIcon)));
3117
- };
3118
-
3119
- const generateLinkStyles = (props, theme) => {
3120
- const disabled = props.disabled || props.waiting;
3121
- let color = props.colorOverride;
3122
- if (!color) {
3123
- if (!props.variant) {
3124
- color = theme.colors.link;
3103
+ const LinkContent = (props) => {
3104
+ return (React__namespace.createElement(React__namespace.Fragment, null,
3105
+ React__namespace.createElement("span", null,
3106
+ props.leftIcon && React__namespace.createElement("span", { className: css.css({
3107
+ label: 'LinkLeftIcon',
3108
+ marginRight: '1rem',
3109
+ display: 'inline-block',
3110
+ minWidth: '1.5rem',
3111
+ verticalAlign: 'middle'
3112
+ }) }, props.leftIcon),
3113
+ props.waiting ? React__namespace.createElement(Icon, { id: "waiting", spin: true }) : props.children),
3114
+ props.rightIcon && React__namespace.createElement("span", { className: css.css({
3115
+ label: 'LinkRightIcon',
3116
+ marginLeft: '1rem',
3117
+ verticalAlign: 'middle'
3118
+ }) }, props.rightIcon)));
3119
+ };
3120
+
3121
+ const generateLinkStyles = (props, theme) => {
3122
+ const disabled = props.disabled || props.waiting;
3123
+ let color = props.colorOverride;
3124
+ if (!color) {
3125
+ if (!props.variant) {
3126
+ color = theme.colors.link;
3125
3127
  }
3126
3128
  else {
3127
3129
  switch (props.variant) {
@@ -3355,6 +3357,29 @@ const generateLinkStyles = (props, theme) => {
3355
3357
  return linkStyles;
3356
3358
  };
3357
3359
 
3360
+ const Link = (props) => {
3361
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3362
+ const { rightIcon, leftIcon, block, iconBlock, variant, round, small, colorOverride, children, disabled, ref, waiting } = props, linkProps = __rest(props, ["rightIcon", "leftIcon", "block", "iconBlock", "variant", "round", "small", "colorOverride", "children", "disabled", "ref", "waiting"]);
3363
+ const theme = useThemeSafely();
3364
+ const linkStyles = generateLinkStyles(props, theme);
3365
+ const mainClassName = css.cx('link', linkStyles, props.className);
3366
+ if (variant === 'text') {
3367
+ return React__namespace.createElement(Text, { className: mainClassName, tag: "div" }, props.children);
3368
+ }
3369
+ const isDisabled = props.disabled || props.waiting;
3370
+ return (React__namespace.createElement("a", Object.assign({}, linkProps, { tabIndex: disabled ? -1 : undefined, target: props.target, className: mainClassName, onClick: e => {
3371
+ var _a;
3372
+ if (isDisabled) {
3373
+ e.stopPropagation();
3374
+ e.preventDefault();
3375
+ }
3376
+ else {
3377
+ (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
3378
+ }
3379
+ } }),
3380
+ React__namespace.createElement(LinkContent, Object.assign({}, props))));
3381
+ };
3382
+
3358
3383
  const OmniLink = (props) => {
3359
3384
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
3360
3385
  const { noRouter, rightIcon, leftIcon, block, iconBlock, variant, round, small, colorOverride, children, ref, waiting } = props, linkProps = __rest(props, ["noRouter", "rightIcon", "leftIcon", "block", "iconBlock", "variant", "round", "small", "colorOverride", "children", "ref", "waiting"]);
@@ -3381,11 +3406,113 @@ const OmniLink = (props) => {
3381
3406
  } }), content));
3382
3407
  };
3383
3408
 
3409
+ const Nav = (props) => {
3410
+ var _a, _b, _c, _d;
3411
+ const nav = React__namespace.useRef(null);
3412
+ const theme = useThemeSafely();
3413
+ const navWidth = (_a = props.navWidth) !== null && _a !== void 0 ? _a : theme.layout.navWidth;
3414
+ const totalNavOffset = `calc(${navWidth} + 20px)`;
3415
+ const backdrop = useBackdropContext();
3416
+ const log = useLogger(`Nav ${(_b = props.id) !== null && _b !== void 0 ? _b : '?'}`, (_c = props.__debug) !== null && _c !== void 0 ? _c : false);
3417
+ const slideMs = (_d = props.slideMs) !== null && _d !== void 0 ? _d : theme.timings.nav.slideMs;
3418
+ const slideRight = css.keyframes `
3419
+ 0% {
3420
+ transform: translateX(0);
3421
+ }
3422
+
3423
+ 100% {
3424
+ transform: translateX(${totalNavOffset});
3425
+ }
3426
+ `;
3427
+ const slideLeft = css.keyframes `
3428
+ 0% {
3429
+ transform: translateX(${totalNavOffset});
3430
+ }
3431
+
3432
+ 100% {
3433
+ transform: translateX(0px);
3434
+ }
3435
+ `;
3436
+ const classNavShowing = css.css `
3437
+ animation: ${slideRight} ${slideMs}ms cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
3438
+ `;
3439
+ const classNavNotShowing = css.css `
3440
+ animation: ${slideLeft} ${slideMs}ms cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
3441
+ `;
3442
+ const zIndex = theme.zIndexes.nav;
3443
+ // the padding-top here is to offset the navs' content from the header. the shadow creeps over it.
3444
+ const navStyles = css.css `
3445
+ label: Nav;
3446
+ position: fixed;
3447
+ top: 0;
3448
+ left: calc(${totalNavOffset} * -1);
3449
+ bottom: 0;
3450
+ background-color: ${theme.colors.nav};
3451
+ color: ${theme.colors.navFont};
3452
+ width: ${navWidth};
3453
+ min-width: ${navWidth};
3454
+ box-shadow: 4px 2px 12px 6px rgba(0, 0, 0, 0.2);
3455
+ z-index: ${zIndex};
3456
+ overflow-y: auto;
3457
+ .omniLink, .omniLink:active, .omniLink:focus, .omniLink:visited {
3458
+ color: ${theme.colors.navFont};
3459
+ }
3460
+ padding-top:0;
3461
+ `;
3462
+ React__namespace.useEffect(() => {
3463
+ if (!backdrop.showing) {
3464
+ props.toggle(false);
3465
+ }
3466
+ }, [backdrop.showing]);
3467
+ useBooleanChanged((current, previous) => {
3468
+ var _a;
3469
+ log('show changed', `${previous !== null && previous !== void 0 ? previous : 'undefined'} > ${current}`);
3470
+ backdrop.setShow(current, { key: (_a = props.id) !== null && _a !== void 0 ? _a : 'Nav', zIndex });
3471
+ if (!props.show && props.onCloseFocusId) {
3472
+ const focusId = props.onCloseFocusId;
3473
+ setTimeout(() => {
3474
+ var _a;
3475
+ (_a = document.getElementById(focusId)) === null || _a === void 0 ? void 0 : _a.focus();
3476
+ }, 0);
3477
+ }
3478
+ }, props.show);
3479
+ React__namespace.useLayoutEffect(() => {
3480
+ if (nav && nav.current) {
3481
+ if (props.show) {
3482
+ if (!nav.current.classList.contains(classNavShowing)) {
3483
+ nav.current.classList.add(classNavShowing);
3484
+ setTimeout(() => {
3485
+ var _a;
3486
+ (_a = document.getElementById(props.focusContentId)) === null || _a === void 0 ? void 0 : _a.focus();
3487
+ }, slideMs + 1);
3488
+ }
3489
+ }
3490
+ else {
3491
+ if (nav.current.classList.contains(classNavShowing)) {
3492
+ nav.current.classList.remove(classNavShowing);
3493
+ nav.current.classList.add(classNavNotShowing);
3494
+ setTimeout(() => {
3495
+ if (nav && nav.current) {
3496
+ nav.current.classList.remove(classNavNotShowing);
3497
+ }
3498
+ }, slideMs);
3499
+ }
3500
+ }
3501
+ }
3502
+ });
3503
+ return (React__namespace.createElement("nav", { role: "dialog", "aria-modal": "true", "aria-label": props.ariaLabel, ref: nav, className: css.cx('nav', navStyles, props.className), onKeyDown: e => {
3504
+ if (e.code === 'Escape') {
3505
+ props.toggle(false);
3506
+ }
3507
+ } },
3508
+ React__namespace.createElement(TabLocker, { className: css.css({ height: '100%' }) }, props.children)));
3509
+ };
3510
+
3384
3511
  const roundPxPadding = '4px';
3385
3512
  const Picker = (props) => {
3386
- const { value, options, onValueChange, readOnly, round, controlAlign, wrapperClassName, iconClassName, error } = props, selectProps = __rest(props
3513
+ const { value, options, onValueChange, readOnly, round, controlAlign, wrapperClassName, iconClassName, error, optionClassName } = props, selectProps = __rest(props
3387
3514
  // if we put numbers in, we expect them out
3388
- , ["value", "options", "onValueChange", "readOnly", "round", "controlAlign", "wrapperClassName", "iconClassName", "error"]);
3515
+ , ["value", "options", "onValueChange", "readOnly", "round", "controlAlign", "wrapperClassName", "iconClassName", "error", "optionClassName"]);
3389
3516
  // if we put numbers in, we expect them out
3390
3517
  let isNumber = false;
3391
3518
  if (options && options.length) {
@@ -3399,6 +3526,7 @@ const Picker = (props) => {
3399
3526
  }
3400
3527
  const theme = useThemeSafely();
3401
3528
  const selectStyles = css.css({
3529
+ label: 'Picker',
3402
3530
  // fix the arrow so browser all look the same
3403
3531
  appearance: 'none',
3404
3532
  paddingLeft: theme.controls.padding,
@@ -3442,8 +3570,7 @@ const Picker = (props) => {
3442
3570
  const select = (React__namespace.createElement("select", Object.assign({}, selectProps, { tabIndex: readOnly ? -1 : selectProps.tabIndex, className: css.cx('picker', selectStyles, props.className), value: value, onKeyDown: e => {
3443
3571
  var _a;
3444
3572
  if (readOnly) {
3445
- if (e.keyCode === 9) {
3446
- //TAB
3573
+ if (e.code === 'Tab') {
3447
3574
  return;
3448
3575
  }
3449
3576
  e.preventDefault();
@@ -3484,7 +3611,7 @@ const Picker = (props) => {
3484
3611
  val = o;
3485
3612
  label = o;
3486
3613
  }
3487
- return React__namespace.createElement("option", { key: val, value: val }, label);
3614
+ return React__namespace.createElement("option", { key: val, value: val, className: optionClassName }, label);
3488
3615
  })));
3489
3616
  return (React__namespace.createElement("span", { className: css.cx(css.css({
3490
3617
  label: 'PickerWrapper',
@@ -3960,40 +4087,152 @@ class ItemPager {
3960
4087
  }
3961
4088
  }
3962
4089
 
3963
- const ProgressBar = (props) => {
3964
- var _a;
3965
- const bar = React__namespace.useRef(null);
3966
- React__namespace.useEffect(() => {
3967
- const pct = cleanPct(props.pct);
3968
- if (bar.current) {
3969
- bar.current.style.width = `${pct}%`;
4090
+ const MultiPicker = (props) => {
4091
+ const { value: values, options, onValueChange, readOnly, controlAlign, wrapperClassName, error, optionClassName } = props, selectProps = __rest(props
4092
+ // if we put numbers in, we expect them out
4093
+ , ["value", "options", "onValueChange", "readOnly", "controlAlign", "wrapperClassName", "error", "optionClassName"]);
4094
+ // if we put numbers in, we expect them out
4095
+ let isNumber = false;
4096
+ if (options && options.length) {
4097
+ const testOption = options[0];
4098
+ if (typeof testOption === 'object') {
4099
+ isNumber = typeof testOption.id === 'number';
3970
4100
  }
3971
- });
4101
+ else {
4102
+ isNumber = typeof testOption === 'number';
4103
+ }
4104
+ }
3972
4105
  const theme = useThemeSafely();
3973
- const barStyles = css.css `
3974
- width: 100%;
3975
- height: 1rem;
3976
- border: ${theme.controls.border};
3977
- background-color: ${theme.colors.progressBg};
3978
- ${props.round && `
3979
- border-radius: 1rem;
3980
- `}
3981
- `;
3982
- const fillStyles = css.css `
3983
- transition: width 0.5s ease-in-out;
3984
- height: 100%;
3985
- background-color: ${theme.colors.progressFill};
3986
- ${props.round && `
3987
- border-radius: 1rem;
3988
- `}
3989
- `;
3990
- const showPctPosition = (_a = props.showPctPosition) !== null && _a !== void 0 ? _a : 'bottom';
3991
- const wrapStyles = css.css({
3992
- label: 'ProgressBar',
3993
- display: 'flex',
3994
- flexDirection: showPctPosition === 'bottom' ? 'column' : 'row',
3995
- alignItems: showPctPosition === 'right' ? 'center' : undefined,
3996
- gap: showPctPosition === 'right' ? '0.5rem' : undefined,
4106
+ const selectStyles = css.css({
4107
+ label: 'MultiPicker',
4108
+ padding: theme.controls.padding,
4109
+ minHeight: theme.controls.height,
4110
+ backgroundColor: theme.colors.bg,
4111
+ color: theme.colors.font,
4112
+ fontSize: theme.controls.fontSize,
4113
+ width: '100%',
4114
+ border: theme.controls.border,
4115
+ borderRadius: theme.controls.borderRadius || 0, /* safari fix */
4116
+ transition: theme.controls.transition,
4117
+ '&:disabled': {
4118
+ color: theme.colors.font,
4119
+ opacity: 1,
4120
+ backgroundColor: theme.colors.disabled,
4121
+ cursor: 'not-allowed'
4122
+ },
4123
+ '&:focus': {
4124
+ outline: 'none',
4125
+ boxShadow: theme.controls.focusOutlineShadow
4126
+ }
4127
+ }, error && {
4128
+ borderColor: theme.colors.required,
4129
+ ':focus': {
4130
+ boxShadow: theme.controls.focusOutlineRequiredShadow
4131
+ }
4132
+ }, readOnly && {
4133
+ backgroundColor: 'transparent !important',
4134
+ backgroundImage: 'unset',
4135
+ border: 'none',
4136
+ '&:focus': {
4137
+ outline: 'none',
4138
+ boxShadow: 'none'
4139
+ }
4140
+ });
4141
+ const select = (React__namespace.createElement("select", Object.assign({}, selectProps, { multiple: true, tabIndex: readOnly ? -1 : selectProps.tabIndex, className: css.cx(selectStyles, props.className), value: values.map(v => v.toString()), onKeyDown: e => {
4142
+ var _a;
4143
+ if (readOnly) {
4144
+ if (e.code === 'Tab') {
4145
+ return;
4146
+ }
4147
+ e.preventDefault();
4148
+ e.stopPropagation();
4149
+ }
4150
+ else {
4151
+ (_a = selectProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(selectProps, e);
4152
+ }
4153
+ }, onMouseDown: e => {
4154
+ var _a;
4155
+ if (readOnly) {
4156
+ e.preventDefault();
4157
+ e.stopPropagation();
4158
+ }
4159
+ else {
4160
+ (_a = selectProps.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(selectProps, e);
4161
+ }
4162
+ }, onChange: e => {
4163
+ var _a;
4164
+ const values = Array.from(e.target.selectedOptions).map(o => {
4165
+ let val = o.value;
4166
+ if (isNumber) {
4167
+ val = parseInt(val, 10);
4168
+ if (isNaN(val)) {
4169
+ val = '';
4170
+ }
4171
+ }
4172
+ return val;
4173
+ });
4174
+ onValueChange(values);
4175
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
4176
+ } }), (options || []).map(o => {
4177
+ var _a;
4178
+ let val;
4179
+ let label;
4180
+ if (typeof o === 'object') {
4181
+ val = o.id;
4182
+ label = (_a = o.name) !== null && _a !== void 0 ? _a : o.id;
4183
+ }
4184
+ else {
4185
+ val = o;
4186
+ label = o;
4187
+ }
4188
+ return React__namespace.createElement("option", { key: val, value: val, className: optionClassName }, label);
4189
+ })));
4190
+ return (React__namespace.createElement("span", { className: css.cx(css.css({
4191
+ label: 'MultiPickerWrapper',
4192
+ position: 'relative',
4193
+ display: 'inline-block',
4194
+ width: '100%',
4195
+ }), wrapperClassName) },
4196
+ React__namespace.createElement("div", { className: css.css({
4197
+ position: 'relative'
4198
+ }) }, select),
4199
+ (error || controlAlign) && React__namespace.createElement(InputErrorDisplay, { error: error })));
4200
+ };
4201
+
4202
+ const ProgressBar = (props) => {
4203
+ var _a;
4204
+ const bar = React__namespace.useRef(null);
4205
+ React__namespace.useEffect(() => {
4206
+ const pct = cleanPct(props.pct);
4207
+ if (bar.current) {
4208
+ bar.current.style.width = `${pct}%`;
4209
+ }
4210
+ });
4211
+ const theme = useThemeSafely();
4212
+ const barStyles = css.css `
4213
+ width: 100%;
4214
+ height: 1rem;
4215
+ border: ${theme.controls.border};
4216
+ background-color: ${theme.colors.progressBg};
4217
+ ${props.round && `
4218
+ border-radius: 1rem;
4219
+ `}
4220
+ `;
4221
+ const fillStyles = css.css `
4222
+ transition: width 0.5s ease-in-out;
4223
+ height: 100%;
4224
+ background-color: ${theme.colors.progressFill};
4225
+ ${props.round && `
4226
+ border-radius: 1rem;
4227
+ `}
4228
+ `;
4229
+ const showPctPosition = (_a = props.showPctPosition) !== null && _a !== void 0 ? _a : 'bottom';
4230
+ const wrapStyles = css.css({
4231
+ label: 'ProgressBar',
4232
+ display: 'flex',
4233
+ flexDirection: showPctPosition === 'bottom' ? 'column' : 'row',
4234
+ alignItems: showPctPosition === 'right' ? 'center' : undefined,
4235
+ gap: showPctPosition === 'right' ? '0.5rem' : undefined,
3997
4236
  });
3998
4237
  const pctLabelStyles = (props.showPct && props.showPctPosition === 'right') ? css.css({
3999
4238
  width: '3rem'
@@ -4088,6 +4327,29 @@ const SearchBox = React__namespace.forwardRef((props, ref) => {
4088
4327
  return (React__namespace.createElement("div", { className: searchBoxWrapperStyles }, input));
4089
4328
  });
4090
4329
 
4330
+ /** Converts an enum to an array of entities with id and name. The enum can be an integer or string enum.*/
4331
+ const enumToEntities = (enumObj) => {
4332
+ const entities = [];
4333
+ for (const key in enumObj) {
4334
+ if (isNaN(parseInt(key, 10))) {
4335
+ entities.push({
4336
+ id: enumObj[key],
4337
+ name: key
4338
+ });
4339
+ }
4340
+ }
4341
+ return entities;
4342
+ };
4343
+
4344
+ /** Displays the value in American dollars. */
4345
+ const getCurrencyDisplay = (value, isCents, denomination = '$') => {
4346
+ let actualValue = value || 0;
4347
+ if (isCents) {
4348
+ actualValue /= 100;
4349
+ }
4350
+ return `${denomination}${actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
4351
+ };
4352
+
4091
4353
  const GlobalStyles = () => {
4092
4354
  const theme = useThemeSafely();
4093
4355
  css.injectGlobal({
@@ -4116,698 +4378,37 @@ const GlobalStyles = () => {
4116
4378
  return null;
4117
4379
  };
4118
4380
 
4119
- /*
4120
- From https://fireship.io/snippets/use-media-query-hook/.
4121
- Tried using https://www.npmjs.com/package/react-media, but it cause Webpack build issues.
4122
- */
4123
- /** React wrapper around window resizing and window.matchMedia.
4124
- * https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
4125
- */
4126
- const useMediaQuery = (query) => {
4127
- const [matches, setMatches] = React.useState(window.matchMedia(query).matches);
4128
- React.useEffect(() => {
4129
- const media = window.matchMedia(query);
4130
- if (media.matches !== matches) {
4131
- setMatches(media.matches);
4132
- }
4133
- const listener = () => setMatches(media.matches);
4134
- window.addEventListener("resize", listener);
4135
- return () => window.removeEventListener("resize", listener);
4136
- }, [matches, query]);
4137
- return matches;
4138
- };
4381
+ var decimal=["decimal","décimale"];var place=["lugar","lieu"];var places=["lugares","lieux"];var file=["archivo","fichier"];var selected=["seleccionado","choisi"];var Upload=["Subir","Télécharger"];var Clear=["Cerrar","Fermer"];var Showing=["Mostrando","Affichage de"];var of=["de","sur"];var results=["resultados","résultats"];var Page=["Página","Page"];var Limit=["Límite","Limite"];var Sort=["Ordenar","Trier"];var January=["Enero","Janvier"];var February=["Febrero","Février"];var March=["Marzo","Mars"];var April=["Abril","Avril"];var May=["Mayo","Mai"];var June=["Junio","Juin"];var July=["Julio","Juillet"];var August=["Agosto","Août"];var September=["Septiembre","Septembre"];var October=["Octubre","Octobre"];var November=["Noviembre","Novembre"];var December=["Diciembre","Décembre"];var Sun=["Dom","Dim"];var Mon=["Lun","Lun"];var Tue=["Mar","Mar"];var Wed=["Mié","Mer"];var Thu=["Jue","Jeu"];var Fri=["Vie","Ven"];var Sat=["Sáb","Sam"];var OK=["Aceptar","Accepter"];var Cancel=["Cancelar","Annuler"];var strings = {"Required.":["Requerido.","Requis."],"Must be at least":["Debe ser al menos","Doit être au moins"],"characters in length.":["caracteres de longitud.","caractères de longueur."],"Must be an integer.":["Debe ser un número entero.","Doit être un entier."],"Limited to":["Limitado a","Limité à"],decimal:decimal,place:place,places:places,"Must be greater than or equal to":["Debe ser mayor o igual a","Doit être supérieur ou égal à"],"Must be less than or equal to":["Debe ser menor o igual a","Doit être inférieur ou égal à"],"Invalid email.":["Correo electrónico no válido.","Email invalide."],"Invalid URL.":["URL no válida.","URL non valide."],"Click or drag and drop files.":["Haga clic o arrastre y suelte archivos.","Cliquez ou faites glisser et déposez les fichiers."],file:file,selected:selected,"Upload failed.":["Error en la carga.","Le téléchargement a échoué."],Upload:Upload,"Upload successful.":["Carga exitosa","Téléchargement réussi."],"Invalid files":["Archivos no válidos","Fichiers invalides"],"Max file size exceeded":["Se ha excedido el tamaño máximo de archivo","La taille maximale du fichier a été dépassée"],"Error":["Error","Erreur"],Clear:Clear,Showing:Showing,of:of,results:results,"No Results":["No Hay Resultados","Aucun Résultat"],Page:Page,Limit:Limit,Sort:Sort,January:January,February:February,March:March,April:April,May:May,June:June,July:July,August:August,September:September,October:October,November:November,December:December,Sun:Sun,Mon:Mon,Tue:Tue,Wed:Wed,Thu:Thu,Fri:Fri,Sat:Sat,OK:OK,Cancel:Cancel,"Copied!":["¡Copiado!","Copié!"],"Copy to clipboard":["Copiar al portapapeles","Copier dans le presse-papier"]};
4139
4382
 
4140
- const Slider = (p) => {
4383
+ const LocalizationProvider = (p) => {
4141
4384
  var _a;
4142
- const theme = useThemeSafely();
4143
- const sliderContainer = React.useRef(null);
4144
- const sliderHandleSize = (_a = p.sliderHandleSize) !== null && _a !== void 0 ? _a : theme.controls.height;
4145
- const height = p.showValue ? `calc(${sliderHandleSize} + 1.5rem)` : sliderHandleSize;
4146
- // we're keeping this value in a ref vs. state so the constant updates don't cause re-render.
4147
- // we will have to respond to outside value changes after the fact however...
4148
- const currentValue = React.useRef(p.value);
4149
- const [, forceUpdate] = React.useState(Date.now());
4150
- React.useEffect(() => {
4151
- if (p.value !== currentValue.current) {
4152
- currentValue.current = p.value;
4153
- forceUpdate(Date.now());
4154
- }
4155
- }, [p.value]);
4156
- return (React.createElement("div", { ref: sliderContainer, className: css.cx(css.css({
4157
- label: 'Slider',
4158
- width: '100%',
4159
- height,
4160
- }), p.className) },
4161
- React.createElement(ReactSlider, { ariaLabel: p.ariaLabel, step: p.step, min: p.min, max: p.max, value: p.value, onAfterChange: (value) => {
4162
- p.onChange(value);
4163
- }, onChange: p.onUpdate || p.showValue ? (value) => {
4164
- var _a;
4165
- currentValue.current = value;
4166
- (_a = p.onUpdate) === null || _a === void 0 ? void 0 : _a.call(p, value);
4167
- } : undefined, renderTrack: (props) => {
4168
- const { className } = props, rest = __rest(props, ["className"]);
4169
- return (React.createElement("div", Object.assign({ className: css.cx(className, p.trackClassName, css.css({
4170
- display: 'flex',
4171
- alignItems: 'center',
4172
- height: sliderHandleSize
4173
- })) }, rest),
4174
- React.createElement("div", { className: css.css({
4175
- backgroundColor: theme.colors.secondary,
4176
- height: `calc(${sliderHandleSize} / 4)`,
4177
- borderRadius: theme.controls.roundRadius,
4178
- width: '100%'
4179
- }, p.innerTrackClassName && rest.key === 'track-1' && Array.isArray(p.value) ? p.innerTrackClassName : undefined) })));
4180
- }, renderThumb: (props, state) => {
4181
- const { className } = props, rest = __rest(props, ["className"]);
4182
- let specificThumbStyles;
4183
- if (p.handle1ClassName && props.key === 'thumb-0') {
4184
- specificThumbStyles = p.handle1ClassName;
4385
+ const log = useLogger('LocalizationProvider', (_a = p.__debug) !== null && _a !== void 0 ? _a : false);
4386
+ const stringsDb = strings;
4387
+ return (React.createElement(LocalizationContext.Provider, { value: {
4388
+ language: p.language,
4389
+ getText: (text) => {
4390
+ if (!text) {
4391
+ return '';
4185
4392
  }
4186
- else if (p.handle2ClassName && props.key === 'thumb-1') {
4187
- specificThumbStyles = p.handle2ClassName;
4393
+ if (!isNaN(parseInt(text))) {
4394
+ return text;
4188
4395
  }
4189
- return (React.createElement("div", Object.assign({ className: css.cx(className, css.css({
4190
- borderRadius: theme.controls.roundRadius,
4191
- backgroundColor: 'white',
4192
- border: theme.controls.border,
4193
- cursor: 'grab',
4194
- boxShadow: theme.controls.buttonBoxShadow,
4195
- transition: theme.controls.transition,
4196
- '&:focus': {
4197
- outline: 'none',
4198
- boxShadow: theme.controls.focusOutlineShadow
4199
- },
4200
- '&:active': {
4201
- boxShadow: 'none',
4202
- cursor: 'grabbing'
4203
- },
4204
- '&:hover': {
4205
- filter: theme.controls.hoverBrightness
4206
- }
4207
- }), specificThumbStyles, p.handleClassName, css.css({
4208
- width: sliderHandleSize,
4209
- height: sliderHandleSize,
4210
- })) }, rest, { tabIndex: p.tabIndex }), p.showValue && (React.createElement(HandleText, { sliderHandleSize: sliderHandleSize, className: p.sliderTextClassName, index: state.index, parentElement: sliderContainer.current, value: Array.isArray(currentValue.current) ? currentValue.current[state.index] : currentValue.current, renderValue: p.renderValue, renderValueWidth: p.renderValueWidth }))));
4211
- } })));
4212
- };
4213
- const rectsCollideX = (r1, r2) => {
4214
- if (r1.left >= r2.left && r1.left <= r2.right) {
4215
- return true;
4216
- }
4217
- if (r1.right >= r2.left && r1.right <= r2.right) {
4218
- return true;
4219
- }
4220
- return false;
4221
- };
4222
- const HandleText = (p) => {
4223
- var _a, _b, _c;
4224
- const displayValue = (_b = (_a = p.renderValue) === null || _a === void 0 ? void 0 : _a.call(p, p.value)) !== null && _b !== void 0 ? _b : p.value;
4225
- const renderValueWidth = (_c = p.renderValueWidth) !== null && _c !== void 0 ? _c : p.sliderHandleSize;
4226
- const renderValueLeft = React.useMemo(() => {
4227
- return `calc(${renderValueWidth} * 0.5 * -1 + (${p.sliderHandleSize} * 0.5))`;
4228
- }, [p.renderValueWidth, p.sliderHandleSize]);
4229
- const [flipText, setFlipText] = React.useState(false);
4230
- const offset = '2px';
4231
- React.useEffect(() => {
4232
- // this needs to fire on every render due to the other handle also moving.
4233
- var _a, _b;
4234
- if (p.index === 1) {
4235
- // only do this for the max/right-most handle
4236
- const [r1, r2] = Array.from((_b = (_a = p.parentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.slider-handle').values()) !== null && _b !== void 0 ? _b : []).map(e => e.getBoundingClientRect());
4237
- if (r1 && r2) {
4238
- setFlipText(rectsCollideX(r1, r2));
4396
+ const wordArray = stringsDb[text];
4397
+ if (!wordArray) {
4398
+ log(`No localization data exists for "${text}".`);
4399
+ }
4400
+ if (p.language === exports.StyleGuideLanguage.English) {
4401
+ return text;
4402
+ }
4403
+ const languageIndex = p.language - 1;
4404
+ const translation = wordArray === null || wordArray === void 0 ? void 0 : wordArray[languageIndex];
4405
+ if (translation) {
4406
+ return translation;
4407
+ }
4408
+ log(`No ${exports.StyleGuideLanguage[p.language]} translations exist for "${text}".`);
4409
+ return text;
4239
4410
  }
4240
- }
4241
- });
4242
- return (React.createElement(Text, { ellipsis: true, className: css.cx('slider-handle', css.css({
4243
- width: renderValueWidth,
4244
- left: renderValueLeft,
4245
- top: flipText ? undefined : `calc(${p.sliderHandleSize} + ${offset})`,
4246
- bottom: flipText ? `calc(${p.sliderHandleSize} + ${offset})` : undefined,
4247
- position: 'absolute',
4248
- overflow: 'hidden',
4249
- }), p.className), tag: "div", align: "center" }, displayValue));
4250
- };
4251
-
4252
- const TabHeader = (p) => {
4253
- var _a, _b;
4254
- const [tabIndex, setTabIndex] = React__namespace.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
4255
- const [tabsChanging, setTabsChanging] = React__namespace.useState(false);
4256
- const theme = useThemeSafely();
4257
- const variant = (_b = p.variant) !== null && _b !== void 0 ? _b : 'tab';
4258
- const menuStyles = css.css({
4259
- display: 'flex',
4260
- gap: theme.controls.gap,
4261
- listStyleType: 'none',
4262
- margin: 0,
4263
- padding: 0,
4264
- flexWrap: variant === 'button' ? 'wrap' : 'nowrap'
4265
- }, variant === 'button' && {
4266
- borderBottom: theme.controls.border,
4267
- paddingBottom: '1rem'
4268
- });
4269
- function onTabSelect(index, tabId, focusAfter) {
4270
- const onChange = () => {
4271
- var _a;
4272
- setTabIndex(index);
4273
- (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
4274
- if (focusAfter) {
4275
- setTimeout(() => {
4276
- var _a;
4277
- (_a = document.getElementById(tabId)) === null || _a === void 0 ? void 0 : _a.focus();
4278
- }, 0);
4279
- }
4280
- };
4281
- if (p.onBeforeTabChanged) {
4282
- setTabsChanging(true);
4283
- p.onBeforeTabChanged(index)
4284
- .then(() => {
4285
- onChange();
4286
- })
4287
- .catch(() => {
4288
- /* do nothing */
4289
- })
4290
- .finally(() => {
4291
- setTabsChanging(false);
4292
- });
4293
- }
4294
- else {
4295
- onChange();
4296
- }
4297
- }
4298
- return (React__namespace.createElement("div", { className: "tabHeader" },
4299
- React__namespace.createElement("ul", { role: 'tablist', "aria-label": p.ariaLabel, className: css.cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
4300
- var _a, _b;
4301
- const active = index === tabIndex;
4302
- let tabStyles;
4303
- let buttonStyles;
4304
- let buttonVariant;
4305
- if (variant === 'tab') {
4306
- tabStyles = css.css({
4307
- paddingLeft: '1rem',
4308
- paddingRight: '1rem',
4309
- backgroundColor: theme.colors.bg,
4310
- zIndex: 1,
4311
- }, active && {
4312
- border: theme.controls.border,
4313
- borderRadius: theme.controls.borderRadius,
4314
- borderBottomLeftRadius: 0,
4315
- borderBottomRightRadius: 0,
4316
- borderBottom: 'none',
4317
- zIndex: 3,
4318
- });
4319
- buttonVariant = 'link';
4320
- buttonStyles = css.css({
4321
- maxWidth: (_a = p.maxTabWidth) !== null && _a !== void 0 ? _a : '10rem',
4322
- overflow: 'hidden'
4323
- });
4324
- }
4325
- else {
4326
- buttonVariant = active ? 'primary' : undefined;
4327
- buttonStyles = css.css({
4328
- paddingLeft: '1rem',
4329
- paddingRight: '1rem',
4330
- maxWidth: (_b = p.maxTabWidth) !== null && _b !== void 0 ? _b : '10rem',
4331
- overflow: 'hidden',
4332
- });
4333
- }
4334
- let title = tab.title;
4335
- let buttonContent;
4336
- if (typeof tab.name === 'string') {
4337
- title !== null && title !== void 0 ? title : (title = tab.name);
4338
- buttonContent = React__namespace.createElement(Text, { tag: "div", align: "center", ellipsis: true }, tab.name);
4339
- }
4340
- else {
4341
- buttonContent = tab.name;
4342
- }
4343
- const tabId = getTabHeaderTabId(p.id, index);
4344
- return (React__namespace.createElement("li", { key: index, className: css.cx(tabStyles, p.tabClassName) },
4345
- React__namespace.createElement(Button, { id: tabId, tabIndex: active ? 0 : -1, role: "tab", "aria-controls": p.ariaControlsId, "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
4346
- onTabSelect(index, tabId, false);
4347
- }, onKeyDown: e => {
4348
- e.stopPropagation();
4349
- let newIndex = index;
4350
- if (e.code === 'ArrowLeft') {
4351
- if (index === 0) {
4352
- newIndex = p.tabs.length - 1;
4353
- }
4354
- else {
4355
- newIndex = index - 1;
4356
- }
4357
- }
4358
- else if (e.code === 'ArrowRight') {
4359
- if (index === p.tabs.length - 1) {
4360
- newIndex = 0;
4361
- }
4362
- else {
4363
- newIndex = index + 1;
4364
- }
4365
- }
4366
- if (newIndex !== index) {
4367
- onTabSelect(newIndex, getTabHeaderTabId(p.id, newIndex), true);
4368
- }
4369
- } }, buttonContent)));
4370
- })),
4371
- variant === 'tab' && (React__namespace.createElement("div", { className: css.cx(css.css({
4372
- label: 'TabHeaderDivider',
4373
- borderBottom: theme.controls.border,
4374
- marginTop: `calc(${theme.controls.borderWidth} * -1)`,
4375
- zIndex: 2,
4376
- position: 'relative'
4377
- }), p.tabHeaderDividerClassName) }))));
4378
- };
4379
- function getTabHeaderTabId(tabHeaderId, tabIndex) {
4380
- return `${tabHeaderId}_tab_${tabIndex}`;
4381
- }
4382
-
4383
- const Table = (props) => {
4384
- const theme = useThemeSafely();
4385
- const tableStyles = css.css `
4386
- label: Table;
4387
- width: 100%;
4388
- border-collapse: collapse;
4389
- ${props.noCellBorder && `
4390
- .table__td {
4391
- border-left: none;
4392
- border-right: none;
4393
- }
4394
- `}
4395
- ${props.altRows && `
4396
- .table__tr:nth-of-type(even) {
4397
- background-color: ${theme.colors.lightBg};
4398
- }
4399
- `}
4400
- `;
4401
- const wrapperStyles = css.css `
4402
- label: TableScrollWrapper;
4403
- width:100%;
4404
- overflow-y: auto;
4405
- padding:0 1px; //fixes always showing of the table scroller
4406
- `;
4407
- return (React__namespace.createElement("div", { className: css.cx(wrapperStyles, props.wrapperClassName) },
4408
- React__namespace.createElement("table", { className: css.cx(tableStyles, props.className) },
4409
- props.caption && React__namespace.createElement("caption", { className: css.css({
4410
- fontWeight: 'bold',
4411
- padding: theme.controls.padding
4412
- }) }, props.caption),
4413
- props.children)));
4414
- };
4415
- const Tr = (props) => {
4416
- return (React__namespace.createElement("tr", { className: css.cx('table__tr', props.className) }, props.children));
4417
- };
4418
- const Th = (props) => {
4419
- var _a;
4420
- let style = props.style;
4421
- if (props.width) {
4422
- if (style) {
4423
- style = Object.assign(Object.assign({}, style), { width: props.width, minWidth: props.width });
4424
- }
4425
- else {
4426
- style = { width: props.width, minWidth: props.width };
4427
- }
4428
- }
4429
- const theme = useThemeSafely();
4430
- const thStyles = css.css `
4431
- border-bottom: ${theme.controls.border};
4432
- padding: ${theme.controls.padding};
4433
- font-weight: bold;
4434
- text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
4435
- > .button {
4436
- font-weight: bold;
4437
- }
4438
- `;
4439
- return (React__namespace.createElement("th", { className: css.cx(thStyles, props.className), style: style }, props.children));
4440
- };
4441
- const Td = (props) => {
4442
- var _a;
4443
- const theme = useThemeSafely();
4444
- const tdStyles = css.css `
4445
- border: ${theme.controls.border};
4446
- padding: ${theme.controls.padding};
4447
- vertical-align: middle;
4448
- text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
4449
- `;
4450
- return (React__namespace.createElement("td", { colSpan: props.colSpan, style: props.style, className: css.cx('table__td', tdStyles, props.className) }, props.children));
4451
- };
4452
-
4453
- const TdCurrency = (props) => {
4454
- let actualValue = props.value || 0;
4455
- if (props.cents) {
4456
- actualValue = actualValue / 100;
4457
- }
4458
- const displayValue = actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
4459
- return (React__namespace.createElement(Td, { align: "right" },
4460
- "$",
4461
- displayValue));
4462
- };
4463
-
4464
- const TdNumber = (props) => {
4465
- return React__namespace.createElement(Td, { align: "right" }, props.value || props.value === 0 ? props.value.toLocaleString() : '');
4466
- };
4467
-
4468
- const ThSort = (props) => {
4469
- let iconId = '';
4470
- if (props.direction) {
4471
- if (props.direction === 'asc') {
4472
- iconId = 'sortAsc';
4473
- }
4474
- else {
4475
- iconId = 'sortDesc';
4476
- }
4477
- }
4478
- let rightContentSpecialJustify = 'center';
4479
- switch (props.align) {
4480
- case 'left':
4481
- rightContentSpecialJustify = 'flex-start';
4482
- break;
4483
- case 'right':
4484
- rightContentSpecialJustify = 'flex-end';
4485
- break;
4486
- }
4487
- return (React__namespace.createElement(Th, { align: props.align, style: props.style, width: props.width },
4488
- React__namespace.createElement("div", { className: props.rightContent && css.css({
4489
- display: 'flex',
4490
- alignItems: 'center',
4491
- justifyContent: rightContentSpecialJustify,
4492
- gap: '0.5rem'
4493
- }) },
4494
- React__namespace.createElement(Button, { onClick: props.onClick, variant: "link" },
4495
- props.text,
4496
- iconId && React__namespace.createElement(Icon, { className: css.css({
4497
- marginLeft: '0.5rem'
4498
- }), id: iconId })),
4499
- props.rightContent)));
4500
- };
4501
-
4502
- const defaultMaxLength = 200;
4503
- const defaultRows = 10;
4504
- const TextArea = React__namespace.forwardRef((props, ref) => {
4505
- var _a, _b;
4506
- const [localValue, setLocalValue] = React__namespace.useState(props.value);
4507
- const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
4508
- const [validationError, updateErrorMessage] = useInputValidationMessage(inputRef, props);
4509
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
4510
- const { onValueChange, customError, reportValueOnError, showErrorDisplay, allowUpdateOnFocus } = props, nativeProps = __rest(props, ["onValueChange", "customError", "reportValueOnError", "showErrorDisplay", "allowUpdateOnFocus"]);
4511
- const theme = useThemeSafely();
4512
- React__namespace.useEffect(() => {
4513
- updateErrorMessage();
4514
- }, []);
4515
- useIgnoreMount(() => {
4516
- var _a;
4517
- if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
4518
- onValueChange(localValue);
4519
- }
4520
- else {
4521
- if (reportValueOnError) {
4522
- onValueChange(localValue);
4523
- }
4524
- else {
4525
- onValueChange(undefined);
4526
- }
4527
- }
4528
- updateErrorMessage();
4529
- }, [localValue]);
4530
- useIgnoreMount(() => {
4531
- if (allowUpdateOnFocus || document.activeElement !== inputRef.current) {
4532
- setLocalValue(props.value);
4533
- }
4534
- updateErrorMessage();
4535
- }, [props.value]);
4536
- const styles = css.css({
4537
- backgroundColor: theme.colors.bg,
4538
- maxWidth: '100%',
4539
- minHeight: theme.controls.height,
4540
- fontFamily: theme.fonts.family,
4541
- fontSize: theme.fonts.size,
4542
- width: '100%',
4543
- border: theme.controls.border,
4544
- borderRadius: theme.controls.borderRadius,
4545
- color: theme.colors.font,
4546
- paddingTop: '0.75rem',
4547
- paddingLeft: theme.controls.padding,
4548
- paddingRight: theme.controls.padding,
4549
- height: 'auto',
4550
- transition: theme.controls.transition,
4551
- ':focus': {
4552
- outline: 'none',
4553
- boxShadow: theme.controls.focusOutlineShadow
4554
- },
4555
- ':disabled': {
4556
- backgroundColor: theme.colors.disabled,
4557
- cursor: 'not-allowed'
4558
- },
4559
- ':invalid': {
4560
- borderColor: theme.colors.required,
4561
- ':focus': {
4562
- boxShadow: theme.controls.focusOutlineRequiredShadow
4563
- }
4564
- },
4565
- }, props.readOnly && {
4566
- backgroundColor: 'transparent',
4567
- cursor: 'default',
4568
- border: 'none',
4569
- ':focus': {
4570
- outline: 'none',
4571
- boxShadow: 'none'
4572
- }
4573
- });
4574
- return (React__namespace.createElement("span", { className: css.css({
4575
- display: 'inline-block',
4576
- width: '100%'
4577
- }) },
4578
- React__namespace.createElement("textarea", Object.assign({}, nativeProps, { className: css.cx(styles, props.className), autoComplete: (_a = props.autoComplete) !== null && _a !== void 0 ? _a : 'off', tabIndex: props.readOnly ? -1 : props.tabIndex, maxLength: props.maxLength || defaultMaxLength, rows: (_b = props.rows) !== null && _b !== void 0 ? _b : defaultRows, ref: inputRef, value: localValue !== null && localValue !== void 0 ? localValue : '', onChange: e => {
4579
- var _a;
4580
- setLocalValue(e.target.value || undefined);
4581
- (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
4582
- }, onBlur: e => {
4583
- var _a;
4584
- if (!props.noTrim) {
4585
- setLocalValue(currentValue => {
4586
- return currentValue === null || currentValue === void 0 ? void 0 : currentValue.trim();
4587
- });
4588
- }
4589
- (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
4590
- } })),
4591
- (showErrorDisplay !== null && showErrorDisplay !== void 0 ? showErrorDisplay : true) && React__namespace.createElement(InputErrorDisplay, { error: validationError })));
4592
- });
4593
-
4594
- const ToggleButton = React__namespace.forwardRef((props, ref) => {
4595
- const { checked, checkedChildren, uncheckedChildren, checkedVariant, checkedClassName, checkedStyle, checkedIcon, uncheckedIcon } = props, buttonProps = __rest(props, ["checked", "checkedChildren", "uncheckedChildren", "checkedVariant", "checkedClassName", "checkedStyle", "checkedIcon", "uncheckedIcon"]);
4596
- let children;
4597
- if (checked) {
4598
- children = checkedChildren;
4599
- }
4600
- else {
4601
- children = uncheckedChildren;
4602
- }
4603
- return (React__namespace.createElement(Button, Object.assign({}, buttonProps, { ref: ref, className: css.cx('toggleButton', checked && 'toggleButton--checked', props.className, checked && checkedClassName), rightIcon: checked ? checkedIcon : uncheckedIcon, variant: checked ? checkedVariant : props.variant, style: checked ? checkedStyle : props.style }), children));
4604
- });
4605
-
4606
- const ToggleButtonGroup = (props) => {
4607
- const theme = useThemeSafely();
4608
- const groupStyles = css.css `
4609
- display: flex;
4610
- box-shadow: ${theme.controls.buttonBoxShadow};
4611
- border-radius: ${theme.controls.borderRadius};
4612
- ${props.round && `
4613
- border-radius: ${theme.controls.roundRadius};
4614
- `}
4615
- `;
4616
- const buttonStyles = css.css `
4617
- flex-grow:1;
4618
- box-shadow: none;
4619
- &:nth-of-type(1n+2){
4620
- margin-left: -1px;
4621
- }
4622
- border-radius: 0;
4623
- &:first-of-type{
4624
- border-top-left-radius: ${theme.controls.borderRadius};
4625
- border-bottom-left-radius: ${theme.controls.borderRadius};
4626
- }
4627
- &:last-child {
4628
- border-top-right-radius: ${theme.controls.borderRadius};
4629
- border-bottom-right-radius: ${theme.controls.borderRadius};
4630
- }
4631
- ${props.round && `
4632
- &:first-of-type{
4633
- border-top-left-radius: ${theme.controls.roundRadius};
4634
- border-bottom-left-radius: ${theme.controls.roundRadius};
4635
- padding-left: 1rem;
4636
- }
4637
- &:last-child {
4638
- border-top-right-radius: ${theme.controls.roundRadius};
4639
- border-bottom-right-radius: ${theme.controls.roundRadius};
4640
- padding-right: 1rem;
4641
- }
4642
- `}
4643
- `;
4644
- return (React__namespace.createElement("div", { className: css.cx('toggleButtonGroup', groupStyles, props.className) }, props.options.map(o => {
4645
- const active = o.id === props.value;
4646
- return React__namespace.createElement(Button, { style: props.width ? { width: props.width } : undefined, small: props.small, rightIcon: o.rightIcon, key: o.id, tabIndex: active ? -1 : 0, className: css.cx(css.css `
4647
- ${buttonStyles}
4648
- ${active && `
4649
- background-color: ${theme.colors.font};
4650
- color: ${theme.colors.bg};
4651
- cursor: default;
4652
- &:hover:not(:disabled) {
4653
- filter: none;
4654
- }
4655
- &:focus {
4656
- outline: none;
4657
- box-shadow: none;
4658
- }
4659
- `}
4660
- `, active ? o.activeClass : undefined), disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, onClick: () => {
4661
- if (active) {
4662
- return;
4663
- }
4664
- props.onChange(o.id);
4665
- } }, o.name);
4666
- })));
4667
- };
4668
-
4669
- const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
4670
- const { onVisibilityChanged } = props, inputProps = __rest(props, ["onVisibilityChanged"]);
4671
- const [show, setShow] = React__namespace.useState(false);
4672
- useIgnoreMount(() => {
4673
- onVisibilityChanged === null || onVisibilityChanged === void 0 ? void 0 : onVisibilityChanged(show);
4674
- }, [show]);
4675
- return (React__namespace.createElement(TextInput, Object.assign({}, inputProps, { ref: ref, type: show ? 'text' : 'password', rightControl: (React__namespace.createElement(Button, { small: true, style: {
4676
- // small button is required here due to the icon pushing outside the boundries of the
4677
- // parent textbox. increasing the font size here to fill the small button.
4678
- fontSize: '1rem'
4679
- }, variant: "icon", onClick: () => {
4680
- setShow(previous => !previous);
4681
- } },
4682
- React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
4683
- });
4684
-
4685
- let clearTimerId = undefined;
4686
- /** Allows for status notificaiton methods for screen readers.
4687
- * This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
4688
- function useAriaLiveRegion() {
4689
- const id = 'MknAriaLiveRegion';
4690
- if (!document.getElementById(id)) {
4691
- const div = document.createElement('div');
4692
- div.id = id;
4693
- // different sources cannot decide if this is needed.
4694
- // "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
4695
- div.role = 'status';
4696
- div.ariaLive = 'polite';
4697
- div.ariaAtomic = 'true';
4698
- div.style.position = 'absolute';
4699
- div.style.width = '1px';
4700
- div.style.height = '1px';
4701
- div.style.padding = '0px';
4702
- div.style.margin = '-1px';
4703
- div.style.overflow = 'hidden';
4704
- div.style.whiteSpace = 'nowrap';
4705
- document.body.prepend(div);
4706
- }
4707
- const clearNotification = () => {
4708
- if (clearTimerId) {
4709
- clearTimeout(clearTimerId);
4710
- }
4711
- const element = document.getElementById(id);
4712
- if (!element) {
4713
- return;
4714
- }
4715
- element.textContent = '';
4716
- };
4717
- return {
4718
- /**
4719
- * @param message - The text to be read by the screen reader.
4720
- * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`.
4721
- */
4722
- notify: (message, clearTimoutMs) => {
4723
- if (clearTimerId) {
4724
- clearTimeout(clearTimerId);
4725
- }
4726
- const element = document.getElementById(id);
4727
- if (!element) {
4728
- return;
4729
- }
4730
- element.textContent = message;
4731
- clearTimerId = setTimeout(() => {
4732
- // this is considered a good practice. if you leave text here, some screen readers will read it out randomly as you navigate around the page.
4733
- clearNotification();
4734
- }, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
4735
- },
4736
- clearNotification
4737
- };
4738
- }
4739
-
4740
- const WaitingIndicator = (p) => {
4741
- var _a, _b, _c;
4742
- const [show, setShow] = React.useState(p.show);
4743
- const hideTimer = React.useRef(0);
4744
- const lastShowStatus = React.useRef(false);
4745
- const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
4746
- const { notify, clearNotification } = useAriaLiveRegion();
4747
- if (p.__debug) {
4748
- React.useEffect(() => {
4749
- log('mounted');
4750
- return () => {
4751
- log('unmounted');
4752
- };
4753
- }, []);
4754
- }
4755
- React.useEffect(() => {
4756
- log('show changed', p.show);
4757
- // we need to store the 'last props' since props.show will be captured locally and the incorrect
4758
- // value will display in the timeout below.
4759
- log('storing lastShowStatus', p.show);
4760
- lastShowStatus.current = p.show;
4761
- if (p.show) {
4762
- log('setShow', true);
4763
- setShow(true);
4764
- if (p.minShowTimeMs) {
4765
- log('staring hideTimer', 'timout in ms:', p.minShowTimeMs);
4766
- hideTimer.current = window.setTimeout(() => {
4767
- log('hideTimer complete', 'clearing hideTimer');
4768
- window.clearTimeout(hideTimer.current);
4769
- hideTimer.current = 0;
4770
- // this check is necessary since the show status may have updated again to true.
4771
- // if so, ignore this timeout since we're already past the min time and we're still
4772
- // showing the component.
4773
- if (!lastShowStatus.current) {
4774
- log('setShow', false);
4775
- setShow(false);
4776
- }
4777
- else {
4778
- log('ignoring hideTimer handler due to hideTimer ticking');
4779
- }
4780
- }, p.minShowTimeMs);
4781
- }
4782
- }
4783
- else {
4784
- // ignore hiding the component since the min timer is running.
4785
- if (!hideTimer.current) {
4786
- log('setShow', false);
4787
- setShow(false);
4788
- }
4789
- else {
4790
- log('ignoring show change due to hideTimer ticking');
4791
- }
4792
- }
4793
- if (p.show) {
4794
- // set to a very long time so the hiding of the waiting indicator clears it.
4795
- notify('Loading content.', 60000);
4796
- }
4797
- else {
4798
- clearNotification();
4799
- }
4800
- }, [p.show]);
4801
- const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
4802
- return (React.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
4803
- /* noop */
4804
- }, className: "waitingIndicator", show: show },
4805
- React.createElement("div", { className: css.css({
4806
- color: 'white',
4807
- fontSize: '3rem',
4808
- padding: '0.7rem'
4809
- }) },
4810
- React.createElement(Icon, { id: "waiting", spin: true }))));
4411
+ } }, p.children));
4811
4412
  };
4812
4413
 
4813
4414
  /*
@@ -5106,283 +4707,777 @@ summary {
5106
4707
  `;
5107
4708
  return null;
5108
4709
  };
5109
-
5110
- /** Displays the value in American dollars. */
5111
- const getCurrencyDisplay = (value, isCents, denomination = '$') => {
5112
- let actualValue = value || 0;
5113
- if (isCents) {
5114
- actualValue /= 100;
4710
+
4711
+ const Table = (props) => {
4712
+ const theme = useThemeSafely();
4713
+ const tableStyles = css.css `
4714
+ label: Table;
4715
+ width: 100%;
4716
+ border-collapse: collapse;
4717
+ ${props.noCellBorder && `
4718
+ .table__td {
4719
+ border-left: none;
4720
+ border-right: none;
4721
+ }
4722
+ `}
4723
+ ${props.altRows && `
4724
+ .table__tr:nth-of-type(even) {
4725
+ background-color: ${theme.colors.lightBg};
4726
+ }
4727
+ `}
4728
+ `;
4729
+ const wrapperStyles = css.css `
4730
+ label: TableScrollWrapper;
4731
+ width:100%;
4732
+ overflow-y: auto;
4733
+ padding:0 1px; //fixes always showing of the table scroller
4734
+ `;
4735
+ return (React__namespace.createElement("div", { className: css.cx(wrapperStyles, props.wrapperClassName) },
4736
+ React__namespace.createElement("table", { className: css.cx(tableStyles, props.className) },
4737
+ props.caption && React__namespace.createElement("caption", { className: css.css({
4738
+ fontWeight: 'bold',
4739
+ padding: theme.controls.padding
4740
+ }) }, props.caption),
4741
+ props.children)));
4742
+ };
4743
+ const Tr = (props) => {
4744
+ return (React__namespace.createElement("tr", { className: css.cx('table__tr', props.className) }, props.children));
4745
+ };
4746
+ const Th = (props) => {
4747
+ var _a;
4748
+ let style = props.style;
4749
+ if (props.width) {
4750
+ if (style) {
4751
+ style = Object.assign(Object.assign({}, style), { width: props.width, minWidth: props.width });
4752
+ }
4753
+ else {
4754
+ style = { width: props.width, minWidth: props.width };
4755
+ }
4756
+ }
4757
+ const theme = useThemeSafely();
4758
+ const thStyles = css.css `
4759
+ border-bottom: ${theme.controls.border};
4760
+ padding: ${theme.controls.padding};
4761
+ font-weight: bold;
4762
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
4763
+ > .button {
4764
+ font-weight: bold;
4765
+ }
4766
+ `;
4767
+ return (React__namespace.createElement("th", { className: css.cx(thStyles, props.className), style: style }, props.children));
4768
+ };
4769
+ const Td = (props) => {
4770
+ var _a;
4771
+ const theme = useThemeSafely();
4772
+ const tdStyles = css.css `
4773
+ border: ${theme.controls.border};
4774
+ padding: ${theme.controls.padding};
4775
+ vertical-align: middle;
4776
+ text-align: ${(_a = props.align) !== null && _a !== void 0 ? _a : 'center'};
4777
+ `;
4778
+ return (React__namespace.createElement("td", { colSpan: props.colSpan, style: props.style, className: css.cx('table__td', tdStyles, props.className) }, props.children));
4779
+ };
4780
+
4781
+ /* eslint @typescript-eslint/no-explicit-any: 0 */
4782
+ const ThemeRenderer = (p) => {
4783
+ const { backgroundColor, color } = p, theme = __rest(p, ["backgroundColor", "color"]);
4784
+ const flatTheme = flatten(theme);
4785
+ const entries = lodash.orderBy(Object.entries(flatTheme), x => x[0]);
4786
+ return (React__namespace.createElement(Table, { caption: (React__namespace.createElement("div", null,
4787
+ React__namespace.createElement(Text, { tag: "h1", align: "center" }, "Theme"),
4788
+ React__namespace.createElement(Text, { tag: "p", align: "center", italics: true }, "Background color applied to show colors with alpha ('rgba(X, X, X, 0.X)')"))), className: css.css({
4789
+ backgroundColor: backgroundColor !== null && backgroundColor !== void 0 ? backgroundColor : '#eee7ca',
4790
+ color: color !== null && color !== void 0 ? color : 'black'
4791
+ }) },
4792
+ React__namespace.createElement("thead", null,
4793
+ React__namespace.createElement(Tr, null,
4794
+ React__namespace.createElement(Th, { align: "left" }, "Property"),
4795
+ React__namespace.createElement(Th, { align: "left" }, "Value"))),
4796
+ React__namespace.createElement("tbody", null, entries.map(([key, value]) => {
4797
+ let colorBox;
4798
+ if (/color/i.test(key)) {
4799
+ colorBox = (React__namespace.createElement("span", { className: css.css({
4800
+ display: 'block',
4801
+ border: '1px solid black',
4802
+ width: '100%',
4803
+ height: 24,
4804
+ background: value
4805
+ }) }));
4806
+ }
4807
+ return (React__namespace.createElement(Tr, { key: key },
4808
+ React__namespace.createElement(Td, { align: "left" }, key),
4809
+ React__namespace.createElement(Td, { align: "left" },
4810
+ React__namespace.createElement("div", { className: css.css({
4811
+ display: 'flex',
4812
+ alignItems: 'center',
4813
+ gap: '1rem'
4814
+ }) },
4815
+ React__namespace.createElement("span", { className: css.css({ flexShrink: 1 }) }, value),
4816
+ " ",
4817
+ colorBox))));
4818
+ }))));
4819
+ };
4820
+ const flatten = (obj, parent, path = 'theme') => {
4821
+ const flatObj = parent !== null && parent !== void 0 ? parent : {};
4822
+ for (const prop in obj) {
4823
+ const value = obj[prop];
4824
+ const fullPath = `${path}.${prop}`;
4825
+ if (typeof value !== 'object') {
4826
+ flatObj[fullPath] = value;
4827
+ }
4828
+ else {
4829
+ flatten(value, flatObj, fullPath);
4830
+ }
4831
+ }
4832
+ return flatObj;
4833
+ };
4834
+
4835
+ let clearTimerId = undefined;
4836
+ /** Allows for status notificaiton methods for screen readers.
4837
+ * This hook does not have any dependencies, so it can be used in projects that don't important anything else from the style_guide. */
4838
+ function useAriaLiveRegion() {
4839
+ const id = 'MknAriaLiveRegion';
4840
+ if (!document.getElementById(id)) {
4841
+ const div = document.createElement('div');
4842
+ div.id = id;
4843
+ // different sources cannot decide if this is needed.
4844
+ // "Can work for status messages, but aria-live="polite" + text is usually simpler and more reliable for loading."
4845
+ div.role = 'status';
4846
+ div.ariaLive = 'polite';
4847
+ div.ariaAtomic = 'true';
4848
+ div.style.position = 'absolute';
4849
+ div.style.width = '1px';
4850
+ div.style.height = '1px';
4851
+ div.style.padding = '0px';
4852
+ div.style.margin = '-1px';
4853
+ div.style.overflow = 'hidden';
4854
+ div.style.whiteSpace = 'nowrap';
4855
+ document.body.prepend(div);
4856
+ }
4857
+ const clearNotification = () => {
4858
+ if (clearTimerId) {
4859
+ clearTimeout(clearTimerId);
4860
+ }
4861
+ const element = document.getElementById(id);
4862
+ if (!element) {
4863
+ return;
4864
+ }
4865
+ element.textContent = '';
4866
+ };
4867
+ return {
4868
+ /**
4869
+ * @param message - The text to be read by the screen reader.
4870
+ * @param clearTimeoutMs - Milliseconds to wait before the message is cleared. Defaults to `2000`.
4871
+ */
4872
+ notify: (message, clearTimoutMs) => {
4873
+ if (clearTimerId) {
4874
+ clearTimeout(clearTimerId);
4875
+ }
4876
+ const element = document.getElementById(id);
4877
+ if (!element) {
4878
+ return;
4879
+ }
4880
+ element.textContent = message;
4881
+ clearTimerId = setTimeout(() => {
4882
+ // this is considered a good practice. if you leave text here, some screen readers will read it out randomly as you navigate around the page.
4883
+ clearNotification();
4884
+ }, clearTimoutMs !== null && clearTimoutMs !== void 0 ? clearTimoutMs : 2000);
4885
+ },
4886
+ clearNotification
4887
+ };
4888
+ }
4889
+
4890
+ /*
4891
+ From https://fireship.io/snippets/use-media-query-hook/.
4892
+ Tried using https://www.npmjs.com/package/react-media, but it cause Webpack build issues.
4893
+ */
4894
+ /** React wrapper around window resizing and window.matchMedia.
4895
+ * https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia
4896
+ */
4897
+ const useMediaQuery = (query) => {
4898
+ const [matches, setMatches] = React.useState(window.matchMedia(query).matches);
4899
+ React.useEffect(() => {
4900
+ const media = window.matchMedia(query);
4901
+ if (media.matches !== matches) {
4902
+ setMatches(media.matches);
4903
+ }
4904
+ const listener = () => setMatches(media.matches);
4905
+ window.addEventListener("resize", listener);
4906
+ return () => window.removeEventListener("resize", listener);
4907
+ }, [matches, query]);
4908
+ return matches;
4909
+ };
4910
+
4911
+ const Slider = (p) => {
4912
+ var _a;
4913
+ const theme = useThemeSafely();
4914
+ const sliderContainer = React.useRef(null);
4915
+ const sliderHandleSize = (_a = p.sliderHandleSize) !== null && _a !== void 0 ? _a : theme.controls.height;
4916
+ const height = p.showValue ? `calc(${sliderHandleSize} + 1.5rem)` : sliderHandleSize;
4917
+ // we're keeping this value in a ref vs. state so the constant updates don't cause re-render.
4918
+ // we will have to respond to outside value changes after the fact however...
4919
+ const currentValue = React.useRef(p.value);
4920
+ const [, forceUpdate] = React.useState(Date.now());
4921
+ React.useEffect(() => {
4922
+ if (p.value !== currentValue.current) {
4923
+ currentValue.current = p.value;
4924
+ forceUpdate(Date.now());
4925
+ }
4926
+ }, [p.value]);
4927
+ return (React.createElement("div", { ref: sliderContainer, className: css.cx(css.css({
4928
+ label: 'Slider',
4929
+ width: '100%',
4930
+ height,
4931
+ }), p.className) },
4932
+ React.createElement(ReactSlider, { ariaLabel: p.ariaLabel, step: p.step, min: p.min, max: p.max, value: p.value, onAfterChange: (value) => {
4933
+ p.onChange(value);
4934
+ }, onChange: p.onUpdate || p.showValue ? (value) => {
4935
+ var _a;
4936
+ currentValue.current = value;
4937
+ (_a = p.onUpdate) === null || _a === void 0 ? void 0 : _a.call(p, value);
4938
+ } : undefined, renderTrack: (props) => {
4939
+ const { className } = props, rest = __rest(props, ["className"]);
4940
+ return (React.createElement("div", Object.assign({ className: css.cx(className, p.trackClassName, css.css({
4941
+ display: 'flex',
4942
+ alignItems: 'center',
4943
+ height: sliderHandleSize
4944
+ })) }, rest),
4945
+ React.createElement("div", { className: css.css({
4946
+ backgroundColor: theme.colors.secondary,
4947
+ height: `calc(${sliderHandleSize} / 4)`,
4948
+ borderRadius: theme.controls.roundRadius,
4949
+ width: '100%'
4950
+ }, p.innerTrackClassName && rest.key === 'track-1' && Array.isArray(p.value) ? p.innerTrackClassName : undefined) })));
4951
+ }, renderThumb: (props, state) => {
4952
+ var _a;
4953
+ const { className } = props, rest = __rest(props, ["className"]);
4954
+ let specificThumbStyles;
4955
+ if (p.handle1ClassName && props.key === 'thumb-0') {
4956
+ specificThumbStyles = p.handle1ClassName;
4957
+ }
4958
+ else if (p.handle2ClassName && props.key === 'thumb-1') {
4959
+ specificThumbStyles = p.handle2ClassName;
4960
+ }
4961
+ return (React.createElement("div", Object.assign({ className: css.cx(className, css.css({
4962
+ borderRadius: theme.controls.roundRadius,
4963
+ backgroundColor: 'white',
4964
+ border: theme.controls.border,
4965
+ cursor: 'grab',
4966
+ boxShadow: theme.controls.buttonBoxShadow,
4967
+ transition: theme.controls.transition,
4968
+ '&:focus': {
4969
+ outline: 'none',
4970
+ boxShadow: theme.controls.focusOutlineShadow
4971
+ },
4972
+ '&:active': {
4973
+ boxShadow: 'none',
4974
+ cursor: 'grabbing'
4975
+ },
4976
+ '&:hover': {
4977
+ filter: theme.controls.hoverBrightness
4978
+ }
4979
+ }), specificThumbStyles, p.handleClassName, css.css({
4980
+ width: sliderHandleSize,
4981
+ height: sliderHandleSize,
4982
+ })) }, rest, { tabIndex: (_a = p.tabIndex) !== null && _a !== void 0 ? _a : 0 }), p.showValue && (React.createElement(HandleText, { sliderHandleSize: sliderHandleSize, className: p.sliderTextClassName, index: state.index, parentElement: sliderContainer.current, value: Array.isArray(currentValue.current) ? currentValue.current[state.index] : currentValue.current, renderValue: p.renderValue, renderValueWidth: p.renderValueWidth }))));
4983
+ } })));
4984
+ };
4985
+ const rectsCollideX = (r1, r2) => {
4986
+ if (r1.left >= r2.left && r1.left <= r2.right) {
4987
+ return true;
5115
4988
  }
5116
- return `${denomination}${actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
4989
+ if (r1.right >= r2.left && r1.right <= r2.right) {
4990
+ return true;
4991
+ }
4992
+ return false;
4993
+ };
4994
+ const HandleText = (p) => {
4995
+ var _a, _b, _c;
4996
+ const displayValue = (_b = (_a = p.renderValue) === null || _a === void 0 ? void 0 : _a.call(p, p.value)) !== null && _b !== void 0 ? _b : p.value;
4997
+ const renderValueWidth = (_c = p.renderValueWidth) !== null && _c !== void 0 ? _c : p.sliderHandleSize;
4998
+ const renderValueLeft = React.useMemo(() => {
4999
+ return `calc(${renderValueWidth} * 0.5 * -1 + (${p.sliderHandleSize} * 0.5))`;
5000
+ }, [p.renderValueWidth, p.sliderHandleSize]);
5001
+ const [flipText, setFlipText] = React.useState(false);
5002
+ const offset = '2px';
5003
+ React.useEffect(() => {
5004
+ // this needs to fire on every render due to the other handle also moving.
5005
+ var _a, _b;
5006
+ if (p.index === 1) {
5007
+ // only do this for the max/right-most handle
5008
+ const [r1, r2] = Array.from((_b = (_a = p.parentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.slider-handle').values()) !== null && _b !== void 0 ? _b : []).map(e => e.getBoundingClientRect());
5009
+ if (r1 && r2) {
5010
+ setFlipText(rectsCollideX(r1, r2));
5011
+ }
5012
+ }
5013
+ });
5014
+ return (React.createElement(Text, { ellipsis: true, className: css.cx('slider-handle', css.css({
5015
+ width: renderValueWidth,
5016
+ left: renderValueLeft,
5017
+ top: flipText ? undefined : `calc(${p.sliderHandleSize} + ${offset})`,
5018
+ bottom: flipText ? `calc(${p.sliderHandleSize} + ${offset})` : undefined,
5019
+ position: 'absolute',
5020
+ overflow: 'hidden',
5021
+ }), p.className), tag: "div", align: "center" }, displayValue));
5117
5022
  };
5118
5023
 
5119
- /** Converts an enum to an array of entities with id and name. The enum can be an integer or string enum.*/
5120
- const enumToEntities = (enumObj) => {
5121
- const entities = [];
5122
- for (const key in enumObj) {
5123
- if (isNaN(parseInt(key, 10))) {
5124
- entities.push({
5125
- id: enumObj[key],
5126
- name: key
5024
+ const TabHeader = (p) => {
5025
+ var _a, _b;
5026
+ const [tabIndex, setTabIndex] = React__namespace.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
5027
+ const [tabsChanging, setTabsChanging] = React__namespace.useState(false);
5028
+ const theme = useThemeSafely();
5029
+ const variant = (_b = p.variant) !== null && _b !== void 0 ? _b : 'tab';
5030
+ const menuStyles = css.css({
5031
+ display: 'flex',
5032
+ gap: theme.controls.gap,
5033
+ listStyleType: 'none',
5034
+ margin: 0,
5035
+ padding: 0,
5036
+ flexWrap: variant === 'button' ? 'wrap' : 'nowrap'
5037
+ }, variant === 'button' && {
5038
+ borderBottom: theme.controls.border,
5039
+ paddingBottom: '1rem'
5040
+ });
5041
+ function onTabSelect(index, tabId, focusAfter) {
5042
+ const onChange = () => {
5043
+ var _a;
5044
+ setTabIndex(index);
5045
+ (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, index);
5046
+ if (focusAfter) {
5047
+ setTimeout(() => {
5048
+ var _a;
5049
+ (_a = document.getElementById(tabId)) === null || _a === void 0 ? void 0 : _a.focus();
5050
+ }, 0);
5051
+ }
5052
+ };
5053
+ if (p.onBeforeTabChanged) {
5054
+ setTabsChanging(true);
5055
+ p.onBeforeTabChanged(index)
5056
+ .then(() => {
5057
+ onChange();
5058
+ })
5059
+ .catch(() => {
5060
+ /* do nothing */
5061
+ })
5062
+ .finally(() => {
5063
+ setTabsChanging(false);
5127
5064
  });
5128
5065
  }
5066
+ else {
5067
+ onChange();
5068
+ }
5069
+ }
5070
+ return (React__namespace.createElement("div", { className: "tabHeader" },
5071
+ React__namespace.createElement("ul", { role: 'tablist', "aria-label": p.ariaLabel, className: css.cx(menuStyles, p.containerClassName) }, p.tabs.map((tab, index) => {
5072
+ var _a, _b;
5073
+ const active = index === tabIndex;
5074
+ let tabStyles;
5075
+ let buttonStyles;
5076
+ let buttonVariant;
5077
+ if (variant === 'tab') {
5078
+ tabStyles = css.css({
5079
+ paddingLeft: '1rem',
5080
+ paddingRight: '1rem',
5081
+ backgroundColor: theme.colors.bg,
5082
+ zIndex: 1,
5083
+ }, active && {
5084
+ border: theme.controls.border,
5085
+ borderRadius: theme.controls.borderRadius,
5086
+ borderBottomLeftRadius: 0,
5087
+ borderBottomRightRadius: 0,
5088
+ borderBottom: 'none',
5089
+ zIndex: 3,
5090
+ });
5091
+ buttonVariant = 'link';
5092
+ buttonStyles = css.css({
5093
+ maxWidth: (_a = p.maxTabWidth) !== null && _a !== void 0 ? _a : '10rem',
5094
+ overflow: 'hidden'
5095
+ });
5096
+ }
5097
+ else {
5098
+ buttonVariant = active ? 'primary' : undefined;
5099
+ buttonStyles = css.css({
5100
+ paddingLeft: '1rem',
5101
+ paddingRight: '1rem',
5102
+ maxWidth: (_b = p.maxTabWidth) !== null && _b !== void 0 ? _b : '10rem',
5103
+ overflow: 'hidden',
5104
+ });
5105
+ }
5106
+ let title = tab.title;
5107
+ let buttonContent;
5108
+ if (typeof tab.name === 'string') {
5109
+ title !== null && title !== void 0 ? title : (title = tab.name);
5110
+ buttonContent = React__namespace.createElement(Text, { tag: "div", align: "center", ellipsis: true }, tab.name);
5111
+ }
5112
+ else {
5113
+ buttonContent = tab.name;
5114
+ }
5115
+ const tabId = getTabHeaderTabId(p.id, index);
5116
+ return (React__namespace.createElement("li", { key: index, className: css.cx(tabStyles, p.tabClassName) },
5117
+ React__namespace.createElement(Button, { id: tabId, tabIndex: active ? 0 : -1, role: "tab", "aria-controls": p.ariaControlsId, "aria-selected": active, disabled: tabsChanging, className: buttonStyles, variant: buttonVariant, title: title, readOnly: active, onClick: () => {
5118
+ onTabSelect(index, tabId, false);
5119
+ }, onKeyDown: e => {
5120
+ e.stopPropagation();
5121
+ let newIndex = index;
5122
+ if (e.code === 'ArrowLeft') {
5123
+ if (index === 0) {
5124
+ newIndex = p.tabs.length - 1;
5125
+ }
5126
+ else {
5127
+ newIndex = index - 1;
5128
+ }
5129
+ }
5130
+ else if (e.code === 'ArrowRight') {
5131
+ if (index === p.tabs.length - 1) {
5132
+ newIndex = 0;
5133
+ }
5134
+ else {
5135
+ newIndex = index + 1;
5136
+ }
5137
+ }
5138
+ if (newIndex !== index) {
5139
+ onTabSelect(newIndex, getTabHeaderTabId(p.id, newIndex), true);
5140
+ }
5141
+ } }, buttonContent)));
5142
+ })),
5143
+ variant === 'tab' && (React__namespace.createElement("div", { className: css.cx(css.css({
5144
+ label: 'TabHeaderDivider',
5145
+ borderBottom: theme.controls.border,
5146
+ marginTop: `calc(${theme.controls.borderWidth} * -1)`,
5147
+ zIndex: 2,
5148
+ position: 'relative'
5149
+ }), p.tabHeaderDividerClassName) }))));
5150
+ };
5151
+ function getTabHeaderTabId(tabHeaderId, tabIndex) {
5152
+ return `${tabHeaderId}_tab_${tabIndex}`;
5153
+ }
5154
+
5155
+ const TabContainer = (p) => {
5156
+ var _a;
5157
+ const [tabIndex, setTabIndex] = React__namespace.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
5158
+ const theme = useThemeSafely();
5159
+ const tabPanelId = `${p.id}_tabpanel`;
5160
+ const tabHeaderId = `${p.id}_TabHeader`;
5161
+ return (React__namespace.createElement("div", { className: css.css({
5162
+ label: 'TabContainer'
5163
+ }) },
5164
+ React__namespace.createElement(TabHeader, { id: tabHeaderId, ariaControlsId: tabPanelId, ariaLabel: p.ariaLabel, tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: (newIndex) => {
5165
+ var _a;
5166
+ setTabIndex(newIndex);
5167
+ (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, newIndex);
5168
+ } }),
5169
+ React__namespace.createElement("div", { role: 'tabpanel', id: tabPanelId, "aria-labelledby": getTabHeaderTabId(tabHeaderId, tabIndex), className: css.cx(css.css({
5170
+ label: 'TabContainerContent',
5171
+ padding: '1rem',
5172
+ borderLeft: theme.controls.border,
5173
+ borderRight: theme.controls.border,
5174
+ borderBottom: theme.controls.border,
5175
+ }), p.contentClassName) }, p.tabs[tabIndex].getContent())));
5176
+ };
5177
+
5178
+ const TdCurrency = (props) => {
5179
+ let actualValue = props.value || 0;
5180
+ if (props.cents) {
5181
+ actualValue = actualValue / 100;
5182
+ }
5183
+ const displayValue = actualValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
5184
+ return (React__namespace.createElement(Td, { align: "right" },
5185
+ "$",
5186
+ displayValue));
5187
+ };
5188
+
5189
+ const TdNumber = (props) => {
5190
+ return React__namespace.createElement(Td, { align: "right" }, props.value || props.value === 0 ? props.value.toLocaleString() : '');
5191
+ };
5192
+
5193
+ const ThSort = (props) => {
5194
+ let iconId = '';
5195
+ if (props.direction) {
5196
+ if (props.direction === 'asc') {
5197
+ iconId = 'sortAsc';
5198
+ }
5199
+ else {
5200
+ iconId = 'sortDesc';
5201
+ }
5129
5202
  }
5130
- return entities;
5203
+ let rightContentSpecialJustify = 'center';
5204
+ switch (props.align) {
5205
+ case 'left':
5206
+ rightContentSpecialJustify = 'flex-start';
5207
+ break;
5208
+ case 'right':
5209
+ rightContentSpecialJustify = 'flex-end';
5210
+ break;
5211
+ }
5212
+ return (React__namespace.createElement(Th, { align: props.align, style: props.style, width: props.width },
5213
+ React__namespace.createElement("div", { className: props.rightContent && css.css({
5214
+ display: 'flex',
5215
+ alignItems: 'center',
5216
+ justifyContent: rightContentSpecialJustify,
5217
+ gap: '0.5rem'
5218
+ }) },
5219
+ React__namespace.createElement(Button, { onClick: props.onClick, variant: "link" },
5220
+ props.text,
5221
+ iconId && React__namespace.createElement(Icon, { className: css.css({
5222
+ marginLeft: '0.5rem'
5223
+ }), id: iconId })),
5224
+ props.rightContent)));
5131
5225
  };
5132
5226
 
5133
- const Link = (props) => {
5227
+ const defaultMaxLength = 200;
5228
+ const defaultRows = 10;
5229
+ const TextArea = React__namespace.forwardRef((props, ref) => {
5230
+ var _a, _b;
5231
+ const [localValue, setLocalValue] = React__namespace.useState(props.value);
5232
+ const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
5233
+ const [validationError, updateErrorMessage] = useInputValidationMessage(inputRef, props);
5134
5234
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5135
- const { rightIcon, leftIcon, block, iconBlock, variant, round, small, colorOverride, children, disabled, ref, waiting } = props, linkProps = __rest(props, ["rightIcon", "leftIcon", "block", "iconBlock", "variant", "round", "small", "colorOverride", "children", "disabled", "ref", "waiting"]);
5235
+ const { onValueChange, customError, reportValueOnError, showErrorDisplay, allowUpdateOnFocus } = props, nativeProps = __rest(props, ["onValueChange", "customError", "reportValueOnError", "showErrorDisplay", "allowUpdateOnFocus"]);
5136
5236
  const theme = useThemeSafely();
5137
- const linkStyles = generateLinkStyles(props, theme);
5138
- const mainClassName = css.cx('link', linkStyles, props.className);
5139
- if (variant === 'text') {
5140
- return React__namespace.createElement(Text, { className: mainClassName, tag: "div" }, props.children);
5141
- }
5142
- const isDisabled = props.disabled || props.waiting;
5143
- return (React__namespace.createElement("a", Object.assign({}, linkProps, { tabIndex: disabled ? -1 : undefined, target: props.target, className: mainClassName, onClick: e => {
5144
- var _a;
5145
- if (isDisabled) {
5146
- e.stopPropagation();
5147
- e.preventDefault();
5237
+ React__namespace.useEffect(() => {
5238
+ updateErrorMessage();
5239
+ }, []);
5240
+ useIgnoreMount(() => {
5241
+ var _a;
5242
+ if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
5243
+ onValueChange(localValue);
5244
+ }
5245
+ else {
5246
+ if (reportValueOnError) {
5247
+ onValueChange(localValue);
5148
5248
  }
5149
5249
  else {
5150
- (_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e);
5151
- }
5152
- } }),
5153
- React__namespace.createElement(LinkContent, Object.assign({}, props))));
5154
- };
5155
-
5156
- /* eslint @typescript-eslint/no-explicit-any: 0 */
5157
- const ThemeRenderer = (p) => {
5158
- const { backgroundColor, color } = p, theme = __rest(p, ["backgroundColor", "color"]);
5159
- const flatTheme = flatten(theme);
5160
- const entries = lodash.orderBy(Object.entries(flatTheme), x => x[0]);
5161
- return (React__namespace.createElement(Table, { caption: (React__namespace.createElement("div", null,
5162
- React__namespace.createElement(Text, { tag: "h1", align: "center" }, "Theme"),
5163
- React__namespace.createElement(Text, { tag: "p", align: "center", italics: true }, "Background color applied to show colors with alpha ('rgba(X, X, X, 0.X)')"))), className: css.css({
5164
- backgroundColor: backgroundColor !== null && backgroundColor !== void 0 ? backgroundColor : '#eee7ca',
5165
- color: color !== null && color !== void 0 ? color : 'black'
5166
- }) },
5167
- React__namespace.createElement("thead", null,
5168
- React__namespace.createElement(Tr, null,
5169
- React__namespace.createElement(Th, { align: "left" }, "Property"),
5170
- React__namespace.createElement(Th, { align: "left" }, "Value"))),
5171
- React__namespace.createElement("tbody", null, entries.map(([key, value]) => {
5172
- let colorBox;
5173
- if (/color/i.test(key)) {
5174
- colorBox = (React__namespace.createElement("span", { className: css.css({
5175
- display: 'block',
5176
- border: '1px solid black',
5177
- width: '100%',
5178
- height: 24,
5179
- background: value
5180
- }) }));
5250
+ onValueChange(undefined);
5181
5251
  }
5182
- return (React__namespace.createElement(Tr, { key: key },
5183
- React__namespace.createElement(Td, { align: "left" }, key),
5184
- React__namespace.createElement(Td, { align: "left" },
5185
- React__namespace.createElement("div", { className: css.css({
5186
- display: 'flex',
5187
- alignItems: 'center',
5188
- gap: '1rem'
5189
- }) },
5190
- React__namespace.createElement("span", { className: css.css({ flexShrink: 1 }) }, value),
5191
- " ",
5192
- colorBox))));
5193
- }))));
5194
- };
5195
- const flatten = (obj, parent, path = 'theme') => {
5196
- const flatObj = parent !== null && parent !== void 0 ? parent : {};
5197
- for (const prop in obj) {
5198
- const value = obj[prop];
5199
- const fullPath = `${path}.${prop}`;
5200
- if (typeof value !== 'object') {
5201
- flatObj[fullPath] = value;
5202
5252
  }
5203
- else {
5204
- flatten(value, flatObj, fullPath);
5253
+ updateErrorMessage();
5254
+ }, [localValue]);
5255
+ useIgnoreMount(() => {
5256
+ if (allowUpdateOnFocus || document.activeElement !== inputRef.current) {
5257
+ setLocalValue(props.value);
5205
5258
  }
5259
+ updateErrorMessage();
5260
+ }, [props.value]);
5261
+ const styles = css.css({
5262
+ backgroundColor: theme.colors.bg,
5263
+ maxWidth: '100%',
5264
+ minHeight: theme.controls.height,
5265
+ fontFamily: theme.fonts.family,
5266
+ fontSize: theme.fonts.size,
5267
+ width: '100%',
5268
+ border: theme.controls.border,
5269
+ borderRadius: theme.controls.borderRadius,
5270
+ color: theme.colors.font,
5271
+ paddingTop: '0.75rem',
5272
+ paddingLeft: theme.controls.padding,
5273
+ paddingRight: theme.controls.padding,
5274
+ height: 'auto',
5275
+ transition: theme.controls.transition,
5276
+ ':focus': {
5277
+ outline: 'none',
5278
+ boxShadow: theme.controls.focusOutlineShadow
5279
+ },
5280
+ ':disabled': {
5281
+ backgroundColor: theme.colors.disabled,
5282
+ cursor: 'not-allowed'
5283
+ },
5284
+ ':invalid': {
5285
+ borderColor: theme.colors.required,
5286
+ ':focus': {
5287
+ boxShadow: theme.controls.focusOutlineRequiredShadow
5288
+ }
5289
+ },
5290
+ }, props.readOnly && {
5291
+ backgroundColor: 'transparent',
5292
+ cursor: 'default',
5293
+ border: 'none',
5294
+ ':focus': {
5295
+ outline: 'none',
5296
+ boxShadow: 'none'
5297
+ }
5298
+ });
5299
+ return (React__namespace.createElement("span", { className: css.css({
5300
+ display: 'inline-block',
5301
+ width: '100%'
5302
+ }) },
5303
+ React__namespace.createElement("textarea", Object.assign({}, nativeProps, { className: css.cx(styles, props.className), autoComplete: (_a = props.autoComplete) !== null && _a !== void 0 ? _a : 'off', tabIndex: props.readOnly ? -1 : props.tabIndex, maxLength: props.maxLength || defaultMaxLength, rows: (_b = props.rows) !== null && _b !== void 0 ? _b : defaultRows, ref: inputRef, value: localValue !== null && localValue !== void 0 ? localValue : '', onChange: e => {
5304
+ var _a;
5305
+ setLocalValue(e.target.value || undefined);
5306
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
5307
+ }, onBlur: e => {
5308
+ var _a;
5309
+ if (!props.noTrim) {
5310
+ setLocalValue(currentValue => {
5311
+ return currentValue === null || currentValue === void 0 ? void 0 : currentValue.trim();
5312
+ });
5313
+ }
5314
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
5315
+ } })),
5316
+ (showErrorDisplay !== null && showErrorDisplay !== void 0 ? showErrorDisplay : true) && React__namespace.createElement(InputErrorDisplay, { error: validationError })));
5317
+ });
5318
+
5319
+ const ToggleButton = React__namespace.forwardRef((props, ref) => {
5320
+ const { checked, checkedChildren, uncheckedChildren, checkedVariant, checkedClassName, checkedStyle, checkedIcon, uncheckedIcon } = props, buttonProps = __rest(props, ["checked", "checkedChildren", "uncheckedChildren", "checkedVariant", "checkedClassName", "checkedStyle", "checkedIcon", "uncheckedIcon"]);
5321
+ let children;
5322
+ if (checked) {
5323
+ children = checkedChildren;
5206
5324
  }
5207
- return flatObj;
5325
+ else {
5326
+ children = uncheckedChildren;
5327
+ }
5328
+ return (React__namespace.createElement(Button, Object.assign({}, buttonProps, { ref: ref, className: css.cx('toggleButton', checked && 'toggleButton--checked', props.className, checked && checkedClassName), rightIcon: checked ? checkedIcon : uncheckedIcon, variant: checked ? checkedVariant : props.variant, style: checked ? checkedStyle : props.style }), children));
5329
+ });
5330
+
5331
+ const ToggleButtonGroup = (props) => {
5332
+ const theme = useThemeSafely();
5333
+ const groupStyles = css.css `
5334
+ display: flex;
5335
+ box-shadow: ${theme.controls.buttonBoxShadow};
5336
+ border-radius: ${theme.controls.borderRadius};
5337
+ ${props.round && `
5338
+ border-radius: ${theme.controls.roundRadius};
5339
+ `}
5340
+ `;
5341
+ const buttonStyles = css.css `
5342
+ flex-grow:1;
5343
+ box-shadow: none;
5344
+ &:nth-of-type(1n+2){
5345
+ margin-left: -1px;
5346
+ }
5347
+ border-radius: 0;
5348
+ &:first-of-type{
5349
+ border-top-left-radius: ${theme.controls.borderRadius};
5350
+ border-bottom-left-radius: ${theme.controls.borderRadius};
5351
+ }
5352
+ &:last-child {
5353
+ border-top-right-radius: ${theme.controls.borderRadius};
5354
+ border-bottom-right-radius: ${theme.controls.borderRadius};
5355
+ }
5356
+ ${props.round && `
5357
+ &:first-of-type{
5358
+ border-top-left-radius: ${theme.controls.roundRadius};
5359
+ border-bottom-left-radius: ${theme.controls.roundRadius};
5360
+ padding-left: 1rem;
5361
+ }
5362
+ &:last-child {
5363
+ border-top-right-radius: ${theme.controls.roundRadius};
5364
+ border-bottom-right-radius: ${theme.controls.roundRadius};
5365
+ padding-right: 1rem;
5366
+ }
5367
+ `}
5368
+ `;
5369
+ return (React__namespace.createElement("div", { className: css.cx('toggleButtonGroup', groupStyles, props.className) }, props.options.map(o => {
5370
+ const active = o.id === props.value;
5371
+ return React__namespace.createElement(Button, { style: props.width ? { width: props.width } : undefined, small: props.small, rightIcon: o.rightIcon, key: o.id, tabIndex: active ? -1 : 0, className: css.cx(css.css `
5372
+ ${buttonStyles}
5373
+ ${active && `
5374
+ background-color: ${theme.colors.font};
5375
+ color: ${theme.colors.bg};
5376
+ cursor: default;
5377
+ &:hover:not(:disabled) {
5378
+ filter: none;
5379
+ }
5380
+ &:focus {
5381
+ outline: none;
5382
+ box-shadow: none;
5383
+ }
5384
+ `}
5385
+ `, active ? o.activeClass : undefined), disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, onClick: () => {
5386
+ if (active) {
5387
+ return;
5388
+ }
5389
+ props.onChange(o.id);
5390
+ } }, o.name);
5391
+ })));
5208
5392
  };
5209
5393
 
5210
- const TabContainer = (p) => {
5211
- var _a;
5212
- const [tabIndex, setTabIndex] = React__namespace.useState((_a = p.startingIndex) !== null && _a !== void 0 ? _a : 0);
5213
- const theme = useThemeSafely();
5214
- const tabPanelId = `${p.id}_tabpanel`;
5215
- const tabHeaderId = `${p.id}_TabHeader`;
5216
- return (React__namespace.createElement("div", { className: css.css({
5217
- label: 'TabContainer'
5218
- }) },
5219
- React__namespace.createElement(TabHeader, { id: tabHeaderId, ariaControlsId: tabPanelId, ariaLabel: p.ariaLabel, tabs: p.tabs, maxTabWidth: p.maxTabWidth, variant: p.variant, containerClassName: p.tabHeaderClassName, tabClassName: p.tabClassName, tabHeaderDividerClassName: p.tabHeaderDividerClassName, startingIndex: tabIndex, onBeforeTabChanged: p.onBeforeTabChanged, onTabChanged: (newIndex) => {
5220
- var _a;
5221
- setTabIndex(newIndex);
5222
- (_a = p.onTabChanged) === null || _a === void 0 ? void 0 : _a.call(p, newIndex);
5223
- } }),
5224
- React__namespace.createElement("div", { role: 'tabpanel', id: tabPanelId, "aria-labelledby": getTabHeaderTabId(tabHeaderId, tabIndex), className: css.cx(css.css({
5225
- label: 'TabContainerContent',
5226
- padding: '1rem',
5227
- borderLeft: theme.controls.border,
5228
- borderRight: theme.controls.border,
5229
- borderBottom: theme.controls.border,
5230
- }), p.contentClassName) }, p.tabs[tabIndex].getContent())));
5231
- };
5394
+ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
5395
+ const { onVisibilityChanged } = props, inputProps = __rest(props, ["onVisibilityChanged"]);
5396
+ const [show, setShow] = React__namespace.useState(false);
5397
+ useIgnoreMount(() => {
5398
+ onVisibilityChanged === null || onVisibilityChanged === void 0 ? void 0 : onVisibilityChanged(show);
5399
+ }, [show]);
5400
+ return (React__namespace.createElement(TextInput, Object.assign({}, inputProps, { ref: ref, type: show ? 'text' : 'password', rightControl: (React__namespace.createElement(Button, { small: true, style: {
5401
+ // small button is required here due to the icon pushing outside the boundries of the
5402
+ // parent textbox. increasing the font size here to fill the small button.
5403
+ fontSize: '1rem'
5404
+ }, variant: "icon", onClick: () => {
5405
+ setShow(previous => !previous);
5406
+ } },
5407
+ React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
5408
+ });
5232
5409
 
5233
- const defaultMinChars = 3;
5234
- class AutocompleteController {
5235
- constructor(getOptions, config) {
5236
- var _a;
5237
- this._value = undefined;
5238
- this._options = [];
5239
- this._minChars = (_a = config === null || config === void 0 ? void 0 : config.minChars) !== null && _a !== void 0 ? _a : defaultMinChars;
5240
- if (config === null || config === void 0 ? void 0 : config.debounceMs) {
5241
- this.getOptions = createDebouncedPromise(getOptions, config === null || config === void 0 ? void 0 : config.debounceMs);
5242
- }
5243
- else {
5244
- this.getOptions = getOptions;
5245
- }
5246
- }
5247
- get value() {
5248
- return this._value;
5249
- }
5250
- get options() {
5251
- return this._options;
5252
- }
5253
- async onChange(newValue) {
5254
- // don't make getOptions calls if the value hasn't changed.
5255
- if (newValue === this.value) {
5256
- return;
5257
- }
5258
- // nullish should not make the getOptions call and instead clear everything.
5259
- if (!newValue) {
5260
- this._value = newValue;
5261
- this._options = [];
5262
- return;
5263
- }
5264
- // sub min chars should clear everything and not attempt the getOptions call.
5265
- if (newValue.length < this._minChars) {
5266
- this._value = newValue;
5267
- this._options = [];
5268
- return;
5269
- }
5270
- try {
5271
- this._value = newValue;
5272
- this._options = (await this.getOptions(newValue));
5273
- }
5274
- catch (err) {
5275
- // this method will throw errors on debounce rejections. that is to be expected.
5276
- // for actual getOptions exceptions, the owner of that function will need to handle errors.
5277
- }
5278
- }
5279
- onPick(newValue) {
5280
- this._value = newValue;
5281
- this._options = [];
5410
+ const WaitingIndicator = (p) => {
5411
+ var _a, _b, _c;
5412
+ const [show, setShow] = React.useState(p.show);
5413
+ const hideTimer = React.useRef(0);
5414
+ const lastShowStatus = React.useRef(false);
5415
+ const log = useLogger(`WaitingIndicator ${(_a = p.id) !== null && _a !== void 0 ? _a : '?'}`, (_b = p.__debug) !== null && _b !== void 0 ? _b : false);
5416
+ const { notify, clearNotification } = useAriaLiveRegion();
5417
+ if (p.__debug) {
5418
+ React.useEffect(() => {
5419
+ log('mounted');
5420
+ return () => {
5421
+ log('unmounted');
5422
+ };
5423
+ }, []);
5282
5424
  }
5283
- }
5284
- const createDebouncedPromise = (originalFunction, trailingTimeoutMs) => {
5285
- let timer;
5286
- let onCancel;
5287
- return (value) => {
5288
- if (timer) {
5289
- clearTimeout(timer);
5425
+ React.useEffect(() => {
5426
+ log('show changed', p.show);
5427
+ // we need to store the 'last props' since props.show will be captured locally and the incorrect
5428
+ // value will display in the timeout below.
5429
+ log('storing lastShowStatus', p.show);
5430
+ lastShowStatus.current = p.show;
5431
+ if (p.show) {
5432
+ log('setShow', true);
5433
+ setShow(true);
5434
+ if (p.minShowTimeMs) {
5435
+ log('staring hideTimer', 'timout in ms:', p.minShowTimeMs);
5436
+ hideTimer.current = window.setTimeout(() => {
5437
+ log('hideTimer complete', 'clearing hideTimer');
5438
+ window.clearTimeout(hideTimer.current);
5439
+ hideTimer.current = 0;
5440
+ // this check is necessary since the show status may have updated again to true.
5441
+ // if so, ignore this timeout since we're already past the min time and we're still
5442
+ // showing the component.
5443
+ if (!lastShowStatus.current) {
5444
+ log('setShow', false);
5445
+ setShow(false);
5446
+ }
5447
+ else {
5448
+ log('ignoring hideTimer handler due to hideTimer ticking');
5449
+ }
5450
+ }, p.minShowTimeMs);
5451
+ }
5290
5452
  }
5291
- if (onCancel) {
5292
- onCancel('Promise cancelled due to in-progress debounce call.');
5293
- onCancel = undefined;
5453
+ else {
5454
+ // ignore hiding the component since the min timer is running.
5455
+ if (!hideTimer.current) {
5456
+ log('setShow', false);
5457
+ setShow(false);
5458
+ }
5459
+ else {
5460
+ log('ignoring show change due to hideTimer ticking');
5461
+ }
5294
5462
  }
5295
- return new Promise((res, rej) => {
5296
- onCancel = rej;
5297
- timer = setTimeout(() => {
5298
- originalFunction(value)
5299
- .then(values => {
5300
- res(values);
5301
- })
5302
- .catch(err => {
5303
- rej(err);
5304
- })
5305
- .finally(() => {
5306
- clearTimeout(timer);
5307
- });
5308
- }, trailingTimeoutMs);
5309
- });
5310
- };
5311
- };
5312
-
5313
- /** Extracted logic around autocomplete functionality for Autocomplete.tsx that supports Entity (id/name) mapping. */
5314
- class AutocompleteEntityController {
5315
- constructor(getOptions, config) {
5316
- this._options = [];
5317
- const getStringOptions = async (value) => {
5318
- this._options = await getOptions(value);
5319
- return this._options.map(o => o.name);
5320
- };
5321
- this._ctrl = new AutocompleteController(getStringOptions, config);
5322
- }
5323
- get entity() {
5324
- return this._pickedEntity;
5325
- }
5326
- get entities() {
5327
- return this._options;
5328
- }
5329
- get value() {
5330
- return this._ctrl.value;
5331
- }
5332
- get options() {
5333
- return this._options.map(o => o.name);
5334
- }
5335
- async onChange(newValue) {
5336
- const clearEntity = newValue !== this._ctrl.value;
5337
- await this._ctrl.onChange(newValue);
5338
- if (clearEntity) {
5339
- this._pickedEntity = undefined;
5463
+ if (p.show) {
5464
+ // set to a very long time so the hiding of the waiting indicator clears it.
5465
+ notify('Loading content.', 60000);
5340
5466
  }
5341
- this.trySyncCtrlOptions();
5342
- }
5343
- onPick(newValue) {
5344
- this._ctrl.onPick(newValue);
5345
- this._pickedEntity = this._options.find(o => o.name === this._ctrl.value);
5346
- this.trySyncCtrlOptions();
5347
- }
5348
- trySyncCtrlOptions() {
5349
- if (!this._ctrl.options.length) {
5350
- this._options = [];
5467
+ else {
5468
+ clearNotification();
5351
5469
  }
5352
- }
5353
- }
5354
-
5355
- var decimal=["decimal","décimale"];var place=["lugar","lieu"];var places=["lugares","lieux"];var file=["archivo","fichier"];var selected=["seleccionado","choisi"];var Upload=["Subir","Télécharger"];var Clear=["Cerrar","Fermer"];var Showing=["Mostrando","Affichage de"];var of=["de","sur"];var results=["resultados","résultats"];var Page=["Página","Page"];var Limit=["Límite","Limite"];var Sort=["Ordenar","Trier"];var January=["Enero","Janvier"];var February=["Febrero","Février"];var March=["Marzo","Mars"];var April=["Abril","Avril"];var May=["Mayo","Mai"];var June=["Junio","Juin"];var July=["Julio","Juillet"];var August=["Agosto","Août"];var September=["Septiembre","Septembre"];var October=["Octubre","Octobre"];var November=["Noviembre","Novembre"];var December=["Diciembre","Décembre"];var Sun=["Dom","Dim"];var Mon=["Lun","Lun"];var Tue=["Mar","Mar"];var Wed=["Mié","Mer"];var Thu=["Jue","Jeu"];var Fri=["Vie","Ven"];var Sat=["Sáb","Sam"];var OK=["Aceptar","Accepter"];var Cancel=["Cancelar","Annuler"];var strings = {"Required.":["Requerido.","Requis."],"Must be at least":["Debe ser al menos","Doit être au moins"],"characters in length.":["caracteres de longitud.","caractères de longueur."],"Must be an integer.":["Debe ser un número entero.","Doit être un entier."],"Limited to":["Limitado a","Limité à"],decimal:decimal,place:place,places:places,"Must be greater than or equal to":["Debe ser mayor o igual a","Doit être supérieur ou égal à"],"Must be less than or equal to":["Debe ser menor o igual a","Doit être inférieur ou égal à"],"Invalid email.":["Correo electrónico no válido.","Email invalide."],"Invalid URL.":["URL no válida.","URL non valide."],"Click or drag and drop files.":["Haga clic o arrastre y suelte archivos.","Cliquez ou faites glisser et déposez les fichiers."],file:file,selected:selected,"Upload failed.":["Error en la carga.","Le téléchargement a échoué."],Upload:Upload,"Upload successful.":["Carga exitosa","Téléchargement réussi."],"Invalid files":["Archivos no válidos","Fichiers invalides"],"Max file size exceeded":["Se ha excedido el tamaño máximo de archivo","La taille maximale du fichier a été dépassée"],"Error":["Error","Erreur"],Clear:Clear,Showing:Showing,of:of,results:results,"No Results":["No Hay Resultados","Aucun Résultat"],Page:Page,Limit:Limit,Sort:Sort,January:January,February:February,March:March,April:April,May:May,June:June,July:July,August:August,September:September,October:October,November:November,December:December,Sun:Sun,Mon:Mon,Tue:Tue,Wed:Wed,Thu:Thu,Fri:Fri,Sat:Sat,OK:OK,Cancel:Cancel,"Copied!":["¡Copiado!","Copié!"],"Copy to clipboard":["Copiar al portapapeles","Copier dans le presse-papier"]};
5356
-
5357
- const LocalizationProvider = (p) => {
5358
- var _a;
5359
- const log = useLogger('LocalizationProvider', (_a = p.__debug) !== null && _a !== void 0 ? _a : false);
5360
- const stringsDb = strings;
5361
- return (React.createElement(LocalizationContext.Provider, { value: {
5362
- language: p.language,
5363
- getText: (text) => {
5364
- if (!text) {
5365
- return '';
5366
- }
5367
- if (!isNaN(parseInt(text))) {
5368
- return text;
5369
- }
5370
- const wordArray = stringsDb[text];
5371
- if (!wordArray) {
5372
- log(`No localization data exists for "${text}".`);
5373
- }
5374
- if (p.language === exports.StyleGuideLanguage.English) {
5375
- return text;
5376
- }
5377
- const languageIndex = p.language - 1;
5378
- const translation = wordArray === null || wordArray === void 0 ? void 0 : wordArray[languageIndex];
5379
- if (translation) {
5380
- return translation;
5381
- }
5382
- log(`No ${exports.StyleGuideLanguage[p.language]} translations exist for "${text}".`);
5383
- return text;
5384
- }
5385
- } }, p.children));
5470
+ }, [p.show]);
5471
+ const id = (_c = p.id) !== null && _c !== void 0 ? _c : 'MknWaitingIndicator';
5472
+ return (React.createElement(Modal, { id: id, __debug: p.__debug, __asWaitingIndicator: true, heading: '', onClose: () => {
5473
+ /* noop */
5474
+ }, className: "waitingIndicator", show: show },
5475
+ React.createElement("div", { className: css.css({
5476
+ color: 'white',
5477
+ fontSize: '3rem',
5478
+ padding: '0.7rem'
5479
+ }) },
5480
+ React.createElement(Icon, { id: "waiting", spin: true }))));
5386
5481
  };
5387
5482
 
5388
5483
  exports.Accordion = Accordion;
@@ -5421,6 +5516,7 @@ exports.List = List;
5421
5516
  exports.ListItem = ListItem;
5422
5517
  exports.LocalizationProvider = LocalizationProvider;
5423
5518
  exports.Modal = Modal;
5519
+ exports.MultiPicker = MultiPicker;
5424
5520
  exports.Nav = Nav;
5425
5521
  exports.NormalizeCss = NormalizeCss;
5426
5522
  exports.NumberInput = NumberInput;