@mackin.com/styleguide 7.9.0 → 8.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +45 -75
  2. package/index.js +546 -301
  3. package/package.json +4 -4
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  var css = require('@emotion/css');
4
+ var lodash = require('lodash');
4
5
  var React = require('react');
5
6
  var nanoid = require('nanoid');
6
7
  var proRegularSvgIcons = require('@fortawesome/pro-regular-svg-icons');
@@ -8,7 +9,6 @@ var proSolidSvgIcons = require('@fortawesome/pro-solid-svg-icons');
8
9
  var proLightSvgIcons = require('@fortawesome/pro-light-svg-icons');
9
10
  var reactFontawesome = require('@fortawesome/react-fontawesome');
10
11
  var dateFns = require('date-fns');
11
- var lodash = require('lodash');
12
12
  var reactDom = require('react-dom');
13
13
  var reactTinyPopover = require('react-tiny-popover');
14
14
  var reactRouterDom = require('react-router-dom');
@@ -47,6 +47,7 @@ const calcDynamicThemeProps = (theme) => {
47
47
  theme.controls.focusOutlineShadow = `0px 0px 4px 2px ${theme.colors.focusOutline}`;
48
48
  theme.controls.focusOutlineRequiredShadow = `0px 0px 4px 2px ${theme.colors.focusOutlineRequired}`;
49
49
  theme.controls.dividerBorder = `2px solid ${theme.colors.divider}`;
50
+ theme.controls.inputErrorMinHeight = `calc(${theme.fonts.sizeSmall} * 1.5 + 4px)`;
50
51
  };
51
52
  const defaultTheme = {
52
53
  colors: {
@@ -110,14 +111,13 @@ const defaultTheme = {
110
111
  focusOutlineShadow: '',
111
112
  focusOutlineRequiredShadow: '',
112
113
  roundRadius: '3rem',
113
- /** @deprecated Use theme.controls.borderRadius (global) or style the components individually. */
114
- roundedRadius: '0.5rem',
115
114
  disabledOpacity: '0.5',
116
115
  formButtonMinWidth: '7rem',
117
116
  gap: '1rem',
118
117
  dividerMargin: '1rem',
119
118
  dividerBorder: '',
120
- headerBoxShadow: '0px 2px 12px 6px rgba(0, 0, 0, 0.2)'
119
+ headerBoxShadow: '0px 2px 12px 6px rgba(0, 0, 0, 0.2)',
120
+ inputErrorMinHeight: ''
121
121
  },
122
122
  zIndexes: {
123
123
  header: 50,
@@ -341,7 +341,7 @@ const Icon = (props) => {
341
341
 
342
342
  const Button = (props) => {
343
343
  var _a, _b;
344
- const nativeProps = __rest(props, ["variant", "textAlign", "block", "round", "rounded", "rightIcon", "leftIcon", "iconBlock", "small", "readonly", "waiting", "enforceMinWidth"]);
344
+ const nativeProps = __rest(props, ["variant", "textAlign", "block", "round", "rightIcon", "leftIcon", "iconBlock", "small", "readOnly", "waiting", "enforceMinWidth"]);
345
345
  const theme = useThemeSafely();
346
346
  const buttonStyles = css.css `
347
347
  padding-left: ${theme.controls.padding};
@@ -477,7 +477,7 @@ const Button = (props) => {
477
477
  ${props.enforceMinWidth && `
478
478
  min-width: ${theme.controls.formButtonMinWidth};
479
479
  `}
480
- ${props.readonly && `
480
+ ${props.readOnly && `
481
481
  cursor: default;
482
482
  box-shadow: none;
483
483
  pointer-events:none;
@@ -497,9 +497,6 @@ const Button = (props) => {
497
497
  ${props.round && `
498
498
  border-radius: ${theme.controls.roundRadius};
499
499
  `}
500
- ${props.rounded && `
501
- border-radius: ${theme.controls.roundedRadius};
502
- `}
503
500
  ${props.block && `
504
501
  width: 100%;
505
502
  `}
@@ -589,8 +586,6 @@ const Input = React__namespace.forwardRef((props, ref) => {
589
586
  borderRadius: theme.controls.roundRadius,
590
587
  paddingLeft: `calc(${theme.controls.padding} * 2)`,
591
588
  paddingRight: `calc(${theme.controls.padding} * 2)`
592
- }, props.rounded && {
593
- borderRadius: theme.controls.roundedRadius
594
589
  }, props.readOnly && {
595
590
  backgroundColor: 'transparent',
596
591
  cursor: 'default',
@@ -875,8 +870,9 @@ const getAutocompleteValueId = (v) => {
875
870
  }
876
871
  return v.id;
877
872
  };
878
- //TB: will need to use the new input
873
+ //TB: FUTURE will need to use the new input
879
874
  const Autocomplete = (p) => {
875
+ var _a;
880
876
  const element = React__namespace.useRef(null);
881
877
  const input = React__namespace.useRef(null);
882
878
  const list = React__namespace.useRef(null);
@@ -886,6 +882,19 @@ const Autocomplete = (p) => {
886
882
  var _a;
887
883
  return values.slice(0, (_a = p.maxShownValues) !== null && _a !== void 0 ? _a : DEFAULT_MAX_SHOWN_VALUES);
888
884
  }, [values]);
885
+ const onChangeForOptions = React__namespace.useRef(lodash.debounce((value) => {
886
+ if (!p.minChars || value.length >= p.minChars) {
887
+ p.getOptions(value)
888
+ .then(vals => {
889
+ setValues(vals);
890
+ }).catch(err => {
891
+ // ignore it
892
+ });
893
+ }
894
+ else {
895
+ setValues([]);
896
+ }
897
+ }, (_a = p.getOptionsDebounceMs) !== null && _a !== void 0 ? _a : 0, { leading: true, trailing: true }));
889
898
  const theme = useThemeSafely();
890
899
  const baseClass = css.css `
891
900
  label: Autocomplete;
@@ -893,7 +902,7 @@ const Autocomplete = (p) => {
893
902
  width: 100%;
894
903
  `;
895
904
  let listBorderRadius = '';
896
- if (p.round || p.rounded || theme.controls.borderRadius) {
905
+ if (p.round || theme.controls.borderRadius) {
897
906
  listBorderRadius = theme.controls.borderRadius || '0.5rem';
898
907
  }
899
908
  const listClass = css.css({
@@ -946,20 +955,10 @@ const Autocomplete = (p) => {
946
955
  return (React__namespace.createElement("div", { ref: element, className: css.cx(baseClass, 'autocomplete') },
947
956
  React__namespace.createElement(Backdrop$1, { onClick: () => setValues([]), show: showValues, allowScroll: true, transparent: true }),
948
957
  React__namespace.createElement(TabLocker, { disabled: !showValues, style: { position: 'relative' } },
949
- React__namespace.createElement(Input, { inputAriaAttributes: p.inputAriaAttributes, ref: input, debounceMs: 0, type: "text", value: getAutocompleteValueText(p.value), round: p.round, rounded: p.rounded, rightControl: p.rightControl, placeholder: p.placeholder, id: p.id, disabled: p.disabled, className: p.className, inputClassName: css.cx(inputClass, p.inputClassName), maxLength: p.maxLength, required: p.required, onChange: v => {
958
+ React__namespace.createElement(Input, { inputAriaAttributes: p.inputAriaAttributes, ref: input, debounceMs: 0, type: "text", value: getAutocompleteValueText(p.value), round: p.round, rightControl: p.rightControl, placeholder: p.placeholder, id: p.id, disabled: p.disabled, className: p.className, inputClassName: css.cx(inputClass, p.inputClassName), maxLength: p.maxLength, required: p.required, onChange: v => {
950
959
  const value = v;
951
960
  p.onChange(value);
952
- if (!p.minChars || value.length >= p.minChars) {
953
- p.getOptions(value)
954
- .then(vals => {
955
- setValues(vals);
956
- }).catch(err => {
957
- // ignore it
958
- });
959
- }
960
- else {
961
- setValues([]);
962
- }
961
+ onChangeForOptions.current(value);
963
962
  }, onKeyDown: e => {
964
963
  var _a, _b;
965
964
  if (showValues) {
@@ -1220,7 +1219,7 @@ const Calendar = (p) => {
1220
1219
  };
1221
1220
 
1222
1221
  const Checkbox = (props) => {
1223
- const inputProps = __rest(props, ["checked", "onChange", "label", "checkedIcon", "uncheckedIcon", "checkedThemeColor", "checkedColor", "readonly"]);
1222
+ const inputProps = __rest(props, ["checked", "onChange", "label", "checkedIcon", "uncheckedIcon", "checkedThemeColor", "checkedColor", "readOnly"]);
1224
1223
  const selected = props.checkedIcon || 'selected';
1225
1224
  const unselected = props.uncheckedIcon || 'unselected';
1226
1225
  const theme = useThemeSafely();
@@ -1235,7 +1234,7 @@ const Checkbox = (props) => {
1235
1234
  }
1236
1235
  const checkboxStyles = css.css `
1237
1236
  display: inline-block;
1238
- ${!props.disabled && !props.readonly && `
1237
+ ${!props.disabled && !props.readOnly && `
1239
1238
  &:hover {
1240
1239
  filter: ${theme.controls.hoverBrightness};
1241
1240
  }
@@ -1249,7 +1248,7 @@ const Checkbox = (props) => {
1249
1248
  ${props.disabled && `
1250
1249
  cursor: not-allowed;
1251
1250
  `}
1252
- ${props.readonly && `
1251
+ ${props.readOnly && `
1253
1252
  cursor: default;
1254
1253
  `}
1255
1254
  `;
@@ -1261,7 +1260,7 @@ const Checkbox = (props) => {
1261
1260
  width: 0;
1262
1261
  opacity: 0;
1263
1262
 
1264
- ${!props.readonly && `
1263
+ ${!props.readOnly && `
1265
1264
  &:focus + .checkboxIcon {
1266
1265
  box-shadow: ${theme.controls.focusOutlineShadow};
1267
1266
  }
@@ -1275,7 +1274,7 @@ const Checkbox = (props) => {
1275
1274
  background-color: ${theme.colors.disabled};
1276
1275
  cursor: not-allowed;
1277
1276
  `}
1278
- ${props.readonly && `
1277
+ ${props.readOnly && `
1279
1278
  cursor: default;
1280
1279
  `}
1281
1280
  ${props.checked && `
@@ -1284,8 +1283,8 @@ const Checkbox = (props) => {
1284
1283
  `;
1285
1284
  return (React__namespace.createElement("span", { className: css.cx('checkbox', checkboxStyles, props.className) },
1286
1285
  React__namespace.createElement("label", { className: labelStyles },
1287
- React__namespace.createElement("input", Object.assign({}, inputProps, { tabIndex: props.readonly ? -1 : undefined, className: nativeCheckboxStyles, type: "checkbox", onChange: e => {
1288
- if (props.readonly) {
1286
+ React__namespace.createElement("input", Object.assign({}, inputProps, { tabIndex: props.readOnly ? -1 : undefined, className: nativeCheckboxStyles, type: "checkbox", onChange: e => {
1287
+ if (props.readOnly) {
1289
1288
  e.preventDefault();
1290
1289
  return;
1291
1290
  }
@@ -1492,93 +1491,6 @@ const CopyButton = (props) => {
1492
1491
  React__namespace.createElement(Icon, { id: copied ? 'paste' : 'copy' })));
1493
1492
  };
1494
1493
 
1495
- const Popover = (p) => {
1496
- var _a, _b;
1497
- const theme = useThemeSafely();
1498
- const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
1499
- return (React__namespace.createElement(reactTinyPopover.Popover, { containerClassName: css.css({
1500
- zIndex: theme.zIndexes.tooltip
1501
- }), reposition: resposition, isOpen: p.isOpen, positions: (_b = p.positions) !== null && _b !== void 0 ? _b : ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
1502
- var _a, _b, _c, _d;
1503
- return (React__namespace.createElement(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
1504
- React__namespace.createElement(TabLocker, null,
1505
- React__namespace.createElement("div", { className: css.css({
1506
- border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
1507
- borderRadius: (_c = p.border) !== null && _c !== void 0 ? _c : theme.controls.borderRadius,
1508
- boxShadow: theme.controls.boxShadow,
1509
- backgroundColor: (_d = p.backgroundColor) !== null && _d !== void 0 ? _d : theme.colors.bg,
1510
- }) }, p.content))));
1511
- } },
1512
- React__namespace.createElement("span", null, p.parent)));
1513
- };
1514
-
1515
- const getCalendarDate = (date, min, max) => {
1516
- let calendarDate = date ? new Date(date) : new Date();
1517
- // if there is a min/max we don't want the calendar to open to the current date if it's out of range
1518
- if (min && dateFns.isBefore(calendarDate, min)) {
1519
- calendarDate = new Date(min);
1520
- }
1521
- else if (max && dateFns.isAfter(calendarDate, max)) {
1522
- calendarDate = new Date(max);
1523
- }
1524
- return calendarDate;
1525
- };
1526
- const DatePicker = (p) => {
1527
- const [showCalendar, setShowCalendar] = React__namespace.useState(false);
1528
- const [calendarDate, setCalendarDate] = React__namespace.useState(getCalendarDate(p.value, p.min, p.max));
1529
- // controls the one-time focus set on show
1530
- const needsFocus = React__namespace.useRef(false);
1531
- const popover = React__namespace.useRef(null);
1532
- React__namespace.useEffect(() => {
1533
- var _a;
1534
- setCalendarDate(getCalendarDate((_a = p.value) !== null && _a !== void 0 ? _a : 0, p.min, p.max));
1535
- }, [p.value]);
1536
- React__namespace.useLayoutEffect(() => {
1537
- var _a, _b;
1538
- if (needsFocus.current) {
1539
- (_b = (_a = popover.current) === null || _a === void 0 ? void 0 : _a.querySelector('button')) === null || _b === void 0 ? void 0 : _b.focus();
1540
- needsFocus.current = false;
1541
- }
1542
- });
1543
- //TB: replace with new inputs
1544
- return (React__namespace.createElement(Popover, { reposition: p.reposition, isOpen: showCalendar, onClickOutside: () => {
1545
- needsFocus.current = false;
1546
- setShowCalendar(false);
1547
- }, parent: (React__namespace.createElement(Input, Object.assign({ onFocus: () => {
1548
- needsFocus.current = false;
1549
- setShowCalendar(false);
1550
- }, placeholder: 'MM/DD/YYYY' }, p, { type: "date", rightControl: !p.readOnly ? (React__namespace.createElement(Button, { variant: "icon", readonly: p.readOnly, disabled: p.disabled, small: true, style: {
1551
- fontSize: '1rem'
1552
- }, onClick: () => {
1553
- needsFocus.current = !showCalendar;
1554
- setShowCalendar(!showCalendar);
1555
- } },
1556
- React__namespace.createElement(Icon, { id: "pickDate" }))) : undefined, onChange: v => {
1557
- p.onChange(v);
1558
- } }))), content: (React__namespace.createElement("div", { ref: popover, className: css.css({
1559
- paddingLeft: '1rem',
1560
- paddingRight: '1rem',
1561
- paddingBottom: '1rem'
1562
- }) },
1563
- React__namespace.createElement(Calendar, { onClick: date => {
1564
- p.onChange(date.valueOf());
1565
- needsFocus.current = false;
1566
- setShowCalendar(false);
1567
- }, customTitle: React__namespace.createElement("div", { className: css.css({
1568
- display: 'flex',
1569
- justifyContent: 'space-between',
1570
- alignItems: 'center'
1571
- }) },
1572
- React__namespace.createElement(Button, { disabled: !!p.min && dateFns.isBefore(dateFns.endOfMonth(dateFns.addMonths(calendarDate, -1)), p.min), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, -1)) },
1573
- React__namespace.createElement(Icon, { id: "pagerLeft" })),
1574
- React__namespace.createElement(Text, { align: "center" },
1575
- dateFns.format(calendarDate, 'LLLL'),
1576
- " ",
1577
- calendarDate.getFullYear()),
1578
- React__namespace.createElement(Button, { disabled: !!p.max && dateFns.isAfter(dateFns.startOfMonth(dateFns.addMonths(calendarDate, 1)), p.max), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, 1)) },
1579
- React__namespace.createElement(Icon, { id: "pagerRight" }))), month: calendarDate.getMonth() + 1, year: calendarDate.getFullYear(), showCurrent: true, smallHeader: true, selectedValue: p.value, cellSize: '2rem', min: p.min, max: p.max }))) }));
1580
- };
1581
-
1582
1494
  const Divider = () => {
1583
1495
  const theme = useThemeSafely();
1584
1496
  return (React__namespace.createElement("hr", { className: css.cx("divider", css.css({
@@ -1894,13 +1806,6 @@ const getSizeString = (size) => {
1894
1806
  }
1895
1807
  };
1896
1808
 
1897
- /** @deprecated This will not work correctly with emotion/css. Use 'cx' for adding multiple class names together. */
1898
- const mergeClassNames = (...classes) => {
1899
- if (!classes) {
1900
- return undefined;
1901
- }
1902
- return classes.filter(c => c).map(c => c).join(' ');
1903
- };
1904
1809
  const getCurrencyDisplay = (value, isCents, denomination = '$') => {
1905
1810
  let actualValue = value || 0;
1906
1811
  if (isCents) {
@@ -2033,6 +1938,26 @@ const Image = (props) => {
2033
1938
  }), props.className), src: props.src }));
2034
1939
  };
2035
1940
 
1941
+ const Popover = (p) => {
1942
+ var _a, _b;
1943
+ const theme = useThemeSafely();
1944
+ const resposition = (_a = p.reposition) !== null && _a !== void 0 ? _a : true;
1945
+ return (React__namespace.createElement(reactTinyPopover.Popover, { containerClassName: css.css({
1946
+ zIndex: theme.zIndexes.tooltip
1947
+ }), reposition: resposition, isOpen: p.isOpen, positions: (_b = p.positions) !== null && _b !== void 0 ? _b : ['right', 'top', 'left', 'bottom'], onClickOutside: p.onClickOutside, content: ({ position, childRect, popoverRect }) => {
1948
+ var _a, _b, _c, _d;
1949
+ return (React__namespace.createElement(reactTinyPopover.ArrowContainer, { position: position, childRect: childRect, popoverRect: popoverRect, arrowColor: (_a = p.arrorColor) !== null && _a !== void 0 ? _a : theme.colors.border, arrowSize: 10 },
1950
+ React__namespace.createElement(TabLocker, null,
1951
+ React__namespace.createElement("div", { className: css.css({
1952
+ border: (_b = p.border) !== null && _b !== void 0 ? _b : theme.controls.border,
1953
+ borderRadius: (_c = p.border) !== null && _c !== void 0 ? _c : theme.controls.borderRadius,
1954
+ boxShadow: theme.controls.boxShadow,
1955
+ backgroundColor: (_d = p.backgroundColor) !== null && _d !== void 0 ? _d : theme.colors.bg,
1956
+ }) }, p.content))));
1957
+ } },
1958
+ React__namespace.createElement("span", null, p.parent)));
1959
+ };
1960
+
2036
1961
  const InfoTip = (props) => {
2037
1962
  var _a, _b;
2038
1963
  const [showTip, setShowTip] = React__namespace.useState(false);
@@ -2110,6 +2035,15 @@ const InfoTip = (props) => {
2110
2035
  }
2111
2036
  };
2112
2037
 
2038
+ const InputErrorDisplay = (props) => {
2039
+ const theme = useThemeSafely();
2040
+ return (React__namespace.createElement(Text, { className: css.css({
2041
+ minHeight: theme.controls.inputErrorMinHeight,
2042
+ lineHeight: theme.controls.inputErrorMinHeight,
2043
+ color: theme.colors.negative
2044
+ }), smaller: true, noPad: true }, props.error));
2045
+ };
2046
+
2113
2047
  const defaultMaxLength$1 = 100;
2114
2048
  const BaseInput = React__namespace.forwardRef((props, ref) => {
2115
2049
  var _a;
@@ -2173,178 +2107,417 @@ const BaseInput = React__namespace.forwardRef((props, ref) => {
2173
2107
  right: calc(${theme.controls.padding} * 2);
2174
2108
  `}
2175
2109
  `;
2176
- return (React__namespace.createElement("div", { className: css.cx('input', inputWrapperStyles, wrapperClassName) },
2177
- inputElement,
2178
- props.rightControl && React__namespace.createElement("div", { className: rightControlStyles }, props.rightControl)));
2110
+ return (React__namespace.createElement("div", null,
2111
+ React__namespace.createElement("div", { className: css.cx('input', inputWrapperStyles, wrapperClassName) },
2112
+ inputElement,
2113
+ props.rightControl && (React__namespace.createElement("div", { className: rightControlStyles }, props.rightControl))),
2114
+ React__namespace.createElement(InputErrorDisplay, { error: props.error })));
2179
2115
  });
2180
2116
 
2181
- const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
2182
- const datePattern = dateRegex.source;
2183
- const outOfRangeValidityMessage = 'Out of range';
2184
- const isOutOfRange = (value, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {
2185
- if (typeof value === 'number') {
2186
- return value < min || value > max;
2117
+ const tryClampRange = (value, min, max) => {
2118
+ if (value === undefined) {
2119
+ return value;
2120
+ }
2121
+ if (isNaN(value)) {
2122
+ return undefined;
2123
+ }
2124
+ if (min !== undefined && value < min) {
2125
+ return min;
2126
+ }
2127
+ if (max !== undefined && value > max) {
2128
+ return max;
2129
+ }
2130
+ return value;
2131
+ };
2132
+ const isOutOfRange = (value, min, max) => {
2133
+ if (min !== undefined && value < min) {
2134
+ return true;
2135
+ }
2136
+ if (max !== undefined && value > max) {
2137
+ return true;
2187
2138
  }
2188
2139
  return false;
2189
2140
  };
2190
- const parseDateMs = (rawValue, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {
2191
- let value;
2192
- let outOfRange = false;
2141
+ const getStepDecimalPlaces = (step) => {
2142
+ var _a, _b;
2143
+ if (!step) {
2144
+ return 0;
2145
+ }
2146
+ const strStep = typeof step === 'number' ? step.toString() : step;
2147
+ return (_b = (_a = strStep.split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
2148
+ };
2149
+ const tryClampDecimals = (value, step = 0) => {
2150
+ if (value === undefined) {
2151
+ return value;
2152
+ }
2153
+ if (isNaN(value)) {
2154
+ return undefined;
2155
+ }
2156
+ const decimals = getStepDecimalPlaces(step);
2157
+ if (decimals === 0) {
2158
+ return Math.floor(value);
2159
+ }
2160
+ return parseFloat(value.toFixed(decimals));
2161
+ };
2162
+
2163
+ /** useEffect but ignores the first call on component mount. */
2164
+ const useIgnoreMount = (effect, deps) => {
2165
+ const mounted = React__default['default'].useRef(false);
2166
+ React__default['default'].useEffect(() => {
2167
+ if (!mounted.current) {
2168
+ mounted.current = true;
2169
+ }
2170
+ else {
2171
+ effect();
2172
+ }
2173
+ }, deps);
2174
+ };
2175
+
2176
+ /** Common state handling for displaying validation messages with inputs. */
2177
+ const useInputValidationMessage = (ref, props) => {
2178
+ const [validationError, setValidationError] = React__default['default'].useState('');
2179
+ const updateErrorMessage = (customErrorOverride) => {
2180
+ var _a;
2181
+ const customError = customErrorOverride || props.customError || '';
2182
+ // set it OR clear it. either way, update it.
2183
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.setCustomValidity(customError);
2184
+ setValidationError(customError || getValidationMessage(ref.current, props.patternErrorMessage));
2185
+ };
2186
+ React__default['default'].useEffect(() => {
2187
+ updateErrorMessage();
2188
+ }, []);
2189
+ return [validationError, updateErrorMessage];
2190
+ };
2191
+ const getValidationMessage = (element, patternErrorMessage) => {
2192
+ var _a;
2193
+ if (!element) {
2194
+ return '';
2195
+ }
2196
+ const validity = element.validity;
2197
+ if (validity.valid) {
2198
+ return '';
2199
+ }
2200
+ if (validity.customError) {
2201
+ return element.validationMessage;
2202
+ }
2203
+ if (validity.typeMismatch) {
2204
+ switch (element.type) {
2205
+ case 'url':
2206
+ return `Invalid URL.`;
2207
+ case 'email':
2208
+ return `Invalid email.`;
2209
+ default:
2210
+ return element.validationMessage;
2211
+ }
2212
+ }
2213
+ if (element instanceof HTMLInputElement) {
2214
+ if (validity.rangeOverflow) {
2215
+ return `Must be less than or equal to ${element.max}.`;
2216
+ }
2217
+ if (validity.rangeUnderflow) {
2218
+ return `Must be greater than or equal to ${element.min}.`;
2219
+ }
2220
+ if (validity.stepMismatch) {
2221
+ const decimalPlaces = getStepDecimalPlaces(element.step);
2222
+ if (decimalPlaces > 0) {
2223
+ const place = decimalPlaces === 1 ? 'place' : 'places';
2224
+ return `Limited to ${getStepDecimalPlaces(element.step)} decimal ${place}.`;
2225
+ }
2226
+ else {
2227
+ /*
2228
+ step is buggy!
2229
+
2230
+ at least in Chrome, setting step=5 will cause the browser to mark the field as invalid if the number is not divisible
2231
+ by 5. 55 is ok. 50 is ok. 59 is not ok.
2232
+
2233
+ to make things worse, if you enter an invalid number like 59 with step=5 and then clear the input, Chrome will tell
2234
+ you the number 5 is now invalid and should be 4 or 9.
2235
+ */
2236
+ return `Must be an integer.`;
2237
+ }
2238
+ }
2239
+ }
2240
+ if (validity.tooShort) {
2241
+ return `Must be at least ${((_a = element.minLength) !== null && _a !== void 0 ? _a : 0).toLocaleString()} characters in length.`;
2242
+ }
2243
+ if (validity.valueMissing) {
2244
+ return 'Required.';
2245
+ }
2246
+ if (validity.patternMismatch && patternErrorMessage) {
2247
+ return patternErrorMessage;
2248
+ }
2249
+ // unhandled. let the browser decide.
2250
+ return element.validationMessage;
2251
+ };
2252
+
2253
+ const dateRegex = /(\d{1,2})(?:\/|-)(\d{1,2})(?:\/|-)(\d{4})/;
2254
+ const datePattern = dateRegex.source;
2255
+ const invalidDateMessage = 'Invalid date.';
2256
+ const DateInput = React__namespace.forwardRef((props, ref) => {
2257
+ var _a;
2258
+ const [dateValue, setDateValue] = React__namespace.useState(props.value);
2259
+ const [textValue, setTextValue] = React__namespace.useState(parseDateString(props.value));
2260
+ const updateValues = React__namespace.useCallback((value) => {
2261
+ let newDateValue;
2262
+ let newTextValue;
2263
+ if (typeof value === 'number') {
2264
+ newDateValue = value;
2265
+ newTextValue = parseDateString(value);
2266
+ }
2267
+ else if (typeof value === 'string') {
2268
+ newDateValue = parseDateNumber(value);
2269
+ newTextValue = value;
2270
+ }
2271
+ setDateValue(newDateValue);
2272
+ setTextValue(newTextValue);
2273
+ }, []);
2274
+ const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
2275
+ const [validationError, updateErrorMessage] = useInputValidationMessage(inputRef, { customError: props.customError, patternErrorMessage: invalidDateMessage });
2276
+ const updateDateErrorMessages = React__namespace.useCallback(() => {
2277
+ let dateError = '';
2278
+ if (dateValue === undefined) {
2279
+ if (!!textValue) {
2280
+ // the text pattern is a valid date format, but the numbers are wrong. example: 05/35/2000.
2281
+ dateError = invalidDateMessage;
2282
+ }
2283
+ }
2284
+ else if (isOutOfRange(dateValue, props.min, props.max)) {
2285
+ // out of range
2286
+ if (props.min !== undefined && props.max !== undefined) {
2287
+ dateError = `Must be be between ${parseDateString(props.min)} and ${parseDateString(props.max)}.`;
2288
+ }
2289
+ else if (props.min !== undefined) {
2290
+ dateError = `Must be greater than or equal to ${parseDateString(props.min)}.`;
2291
+ }
2292
+ else {
2293
+ dateError = `Must be less than or equal to ${parseDateString(props.max)}.`;
2294
+ }
2295
+ }
2296
+ updateErrorMessage(dateError);
2297
+ }, [dateValue, textValue]);
2298
+ const [showCalendar, setShowCalendar] = React__namespace.useState(false);
2299
+ const [calendarDate, setCalendarDate] = React__namespace.useState(getCalendarDate(props.value, props.min, props.max));
2300
+ // controls the one-time focus set on show
2301
+ const needsFocus = React__namespace.useRef(false);
2302
+ const toggleCalendar = React__namespace.useCallback((show) => {
2303
+ var _a;
2304
+ if (show === showCalendar) {
2305
+ return;
2306
+ }
2307
+ needsFocus.current = show;
2308
+ setShowCalendar(show);
2309
+ if (show) {
2310
+ setCalendarDate(getCalendarDate(dateValue, props.min, props.max));
2311
+ }
2312
+ else {
2313
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
2314
+ }
2315
+ }, [dateValue, showCalendar]);
2316
+ const popover = React__namespace.useRef(null);
2317
+ const nativeProps = __rest(props, ["customError", "reposition", "onValueChange"]);
2318
+ useIgnoreMount(() => {
2319
+ var _a;
2320
+ if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
2321
+ props.onValueChange(dateValue);
2322
+ }
2323
+ else {
2324
+ props.onValueChange(undefined);
2325
+ }
2326
+ updateDateErrorMessages();
2327
+ }, [dateValue]);
2328
+ useIgnoreMount(() => {
2329
+ updateDateErrorMessages();
2330
+ }, [textValue]);
2331
+ useIgnoreMount(() => {
2332
+ var _a;
2333
+ if (document.activeElement !== inputRef.current) {
2334
+ updateValues(props.value);
2335
+ setCalendarDate(getCalendarDate((_a = props.value) !== null && _a !== void 0 ? _a : 0, props.min, props.max));
2336
+ }
2337
+ updateDateErrorMessages();
2338
+ }, [props.value]);
2339
+ React__namespace.useLayoutEffect(() => {
2340
+ var _a, _b;
2341
+ if (needsFocus.current) {
2342
+ (_b = (_a = popover.current) === null || _a === void 0 ? void 0 : _a.querySelector('button')) === null || _b === void 0 ? void 0 : _b.focus();
2343
+ needsFocus.current = false;
2344
+ }
2345
+ });
2346
+ const input = (React__namespace.createElement(BaseInput, Object.assign({}, nativeProps, { error: validationError, type: "text", ref: inputRef, value: textValue !== null && textValue !== void 0 ? textValue : '', maxLength: 10, placeholder: (_a = props.placeholder) !== null && _a !== void 0 ? _a : 'MM/DD/YYYY', pattern: datePattern, rightControl: (!props.readOnly && !props.disabled) ? (React__namespace.createElement(Button, { variant: "icon", readOnly: props.readOnly, disabled: props.disabled, small: true, style: {
2347
+ fontSize: '1rem'
2348
+ }, onClick: () => {
2349
+ toggleCalendar(!showCalendar);
2350
+ } },
2351
+ React__namespace.createElement(Icon, { id: "pickDate" }))) : undefined, onChange: e => {
2352
+ var _a;
2353
+ updateValues(e.target.value || undefined);
2354
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
2355
+ }, onFocus: e => {
2356
+ var _a;
2357
+ toggleCalendar(false);
2358
+ (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2359
+ }, onBlur: e => {
2360
+ var _a, _b;
2361
+ if (!((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity())) {
2362
+ if (dateValue !== undefined) {
2363
+ if (isOutOfRange(dateValue, props.min, props.max)) {
2364
+ // try and fix the range
2365
+ updateValues(tryClampRange(dateValue, props.min, props.max));
2366
+ }
2367
+ }
2368
+ else {
2369
+ // just wipe it all
2370
+ updateValues(undefined);
2371
+ }
2372
+ }
2373
+ (_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
2374
+ } })));
2375
+ return (React__namespace.createElement(Popover, { reposition: props.reposition, isOpen: showCalendar, onClickOutside: () => {
2376
+ toggleCalendar(false);
2377
+ }, parent: input, content: (React__namespace.createElement("div", { ref: popover, className: css.css({
2378
+ paddingLeft: '1rem',
2379
+ paddingRight: '1rem',
2380
+ paddingBottom: '1rem'
2381
+ }) },
2382
+ React__namespace.createElement(Calendar, { onClick: date => {
2383
+ updateValues(date.valueOf());
2384
+ toggleCalendar(false);
2385
+ }, customTitle: React__namespace.createElement("div", { className: css.css({
2386
+ display: 'flex',
2387
+ justifyContent: 'space-between',
2388
+ alignItems: 'center'
2389
+ }) },
2390
+ React__namespace.createElement(Button, { disabled: !!props.min && dateFns.isBefore(dateFns.endOfMonth(dateFns.addMonths(calendarDate, -1)), props.min), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, -1)) },
2391
+ React__namespace.createElement(Icon, { id: "pagerLeft" })),
2392
+ React__namespace.createElement(Text, { align: "center" },
2393
+ dateFns.format(calendarDate, 'LLLL'),
2394
+ " ",
2395
+ calendarDate.getFullYear()),
2396
+ React__namespace.createElement(Button, { disabled: !!props.max && dateFns.isAfter(dateFns.startOfMonth(dateFns.addMonths(calendarDate, 1)), props.max), small: true, variant: "icon", onClick: () => setCalendarDate(dateFns.addMonths(calendarDate, 1)) },
2397
+ React__namespace.createElement(Icon, { id: "pagerRight" }))), month: calendarDate.getMonth() + 1, year: calendarDate.getFullYear(), showCurrent: true, smallHeader: true, selectedValue: dateValue, cellSize: '2rem', min: props.min, max: props.max }))) }));
2398
+ });
2399
+ const parseDateNumber = (rawValue) => {
2400
+ if (!rawValue) {
2401
+ return undefined;
2402
+ }
2403
+ let dateMs;
2193
2404
  const dateParts = dateRegex.exec(rawValue);
2194
2405
  if (dateParts) {
2195
- const month = parseInt(dateParts[1], 10);
2406
+ const month = parseInt(dateParts[1], 10) - 1;
2196
2407
  const day = parseInt(dateParts[2], 10);
2197
2408
  const year = parseInt(dateParts[3], 10);
2198
2409
  if (dateFns.isExists(year, month, day)) {
2199
- value = new Date(year, month - 1, day).valueOf();
2200
- outOfRange = isOutOfRange(value, min, max);
2201
- if (outOfRange) {
2202
- value = Math.max(Math.min(value, max), min);
2203
- }
2410
+ dateMs = new Date(year, month, day).valueOf();
2204
2411
  }
2205
2412
  }
2206
- return {
2207
- value,
2208
- outOfRange
2209
- };
2413
+ return dateMs;
2210
2414
  };
2211
- const formatOuterValue = (value) => {
2212
- if (typeof value === 'number') {
2213
- return dateFns.format(value, 'MM/dd/yyyy');
2415
+ const parseDateString = (dateMs) => {
2416
+ if (typeof dateMs === 'number') {
2417
+ return dateFns.format(dateMs, 'MM/dd/yyyy');
2214
2418
  }
2215
- return '';
2419
+ return undefined;
2216
2420
  };
2217
- const DateInput = React__namespace.forwardRef((props, ref) => {
2218
- const [localValue, setLocalValue] = React__namespace.useState('');
2219
- const hasFocus = React__namespace.useRef(false);
2421
+ const getCalendarDate = (date, min, max) => {
2422
+ let calendarDate = date ? new Date(date) : new Date();
2423
+ // if there is a min/max we don't want the calendar to open to the current date if it's out of range
2424
+ if (min && dateFns.isBefore(calendarDate, min)) {
2425
+ calendarDate = new Date(min);
2426
+ }
2427
+ else if (max && dateFns.isAfter(calendarDate, max)) {
2428
+ calendarDate = new Date(max);
2429
+ }
2430
+ return calendarDate;
2431
+ };
2432
+
2433
+ const NumberInput = React__namespace.forwardRef((props, ref) => {
2434
+ const [localValue, setLocalValue] = React__namespace.useState(props.value);
2220
2435
  const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
2221
- const { value, onChange } = props, otherProps = __rest(props, ["value", "onChange"]);
2222
- React__namespace.useEffect(() => {
2436
+ const [validationError, updateErrorMessage] = useInputValidationMessage(inputRef, props);
2437
+ const nativeProps = __rest(props, ["customError", "onValueChange"]);
2438
+ useIgnoreMount(() => {
2223
2439
  var _a;
2224
- // prevent the outer value from influencing the inner value while you're typing.
2225
- if (!hasFocus.current) {
2226
- // sync the outer value to the local value if it changed.
2227
- setLocalValue(formatOuterValue(value));
2228
- (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.setCustomValidity((isOutOfRange(value, props.min, props.max) ? outOfRangeValidityMessage : ''));
2229
- }
2230
- }, [value]);
2231
- return (React__namespace.createElement(BaseInput, Object.assign({}, otherProps, { pattern: datePattern, maxLength: 10, ref: inputRef, type: "text", value: localValue, onChange: e => {
2232
- setLocalValue(e.target.value);
2233
- const { value: v, outOfRange } = parseDateMs(e.target.value, props.min, props.max);
2234
- // need to force invalid due to our using a 'text' input rather than a 'number' or 'date'.
2235
- e.target.setCustomValidity(outOfRange ? outOfRangeValidityMessage : '');
2236
- onChange(v, e);
2237
- }, onFocus: e => {
2440
+ if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
2441
+ props.onValueChange(localValue);
2442
+ }
2443
+ else {
2444
+ props.onValueChange(undefined);
2445
+ }
2446
+ updateErrorMessage();
2447
+ }, [localValue]);
2448
+ useIgnoreMount(() => {
2449
+ if (document.activeElement !== inputRef.current) {
2450
+ setLocalValue(props.value);
2451
+ }
2452
+ updateErrorMessage();
2453
+ }, [props.value]);
2454
+ return (React__namespace.createElement(BaseInput, Object.assign({}, nativeProps, { error: validationError, type: "number", ref: inputRef, value: localValue !== null && localValue !== void 0 ? localValue : '', maxLength: 20, onChange: e => {
2238
2455
  var _a;
2239
- hasFocus.current = true;
2240
- (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2456
+ const newLocalValue = parseNumber(e.target.value);
2457
+ setLocalValue(newLocalValue);
2458
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
2241
2459
  }, onBlur: e => {
2242
- var _a;
2243
- hasFocus.current = false;
2244
- (_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
2245
- // min/max constraints won't be reflected in the local input value. fix that now.
2246
- // handling min/max while typing would be difficult and frustrating to the user.
2247
- setLocalValue(formatOuterValue(value));
2248
- e.target.setCustomValidity(isOutOfRange(value, props.min, props.max) ? outOfRangeValidityMessage : '');
2460
+ var _a, _b;
2461
+ let adjustedValue = localValue;
2462
+ if (e.target.validity.customError) {
2463
+ // if we're invalid due to a custom error, just wipe everything
2464
+ adjustedValue = undefined;
2465
+ }
2466
+ else {
2467
+ // try and fix the value
2468
+ adjustedValue = tryClampRange(adjustedValue, props.min, props.max);
2469
+ adjustedValue = tryClampDecimals(adjustedValue, props.step);
2470
+ }
2471
+ setLocalValue(adjustedValue);
2472
+ // makes our displayed value always matches the adjusted value
2473
+ // examples of failures are 'e', '-', and 5.0 in an integer (step=0) field.
2474
+ e.target.value = (_a = adjustedValue === null || adjustedValue === void 0 ? void 0 : adjustedValue.toString()) !== null && _a !== void 0 ? _a : '';
2475
+ (_b = props.onBlur) === null || _b === void 0 ? void 0 : _b.call(props, e);
2249
2476
  } })));
2250
- });
2251
-
2252
- const parseNumber = (rawValue, step = 0, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER, applyMinMax) => {
2253
- var _a;
2254
- const decimals = step === 0 ? 0 : (_a = step.toString().split('.')[1]) === null || _a === void 0 ? void 0 : _a.length;
2477
+ });
2478
+ const parseNumber = (rawValue) => {
2255
2479
  let value;
2256
2480
  if (rawValue) {
2257
2481
  value = parseFloat(rawValue);
2258
2482
  if (isNaN(value)) {
2259
- value = undefined;
2260
- }
2261
- else {
2262
- if (decimals === 0) {
2263
- value = Math.floor(value);
2264
- }
2265
- else {
2266
- value = parseFloat(value.toFixed(decimals));
2267
- }
2268
- if (applyMinMax) {
2269
- value = Math.max(Math.min(value, max), min);
2270
- }
2483
+ return undefined;
2271
2484
  }
2272
2485
  }
2273
- return [value, value === null || value === void 0 ? void 0 : value.toString()];
2274
- };
2275
- const NumberInput = React__namespace.forwardRef((props, ref) => {
2276
- var _a, _b;
2277
- const { value, onChange, constrainOnInput } = props, otherProps = __rest(props, ["value", "onChange", "constrainOnInput"]);
2278
- const applyInputConstraints = (_a = props.constrainOnInput) !== null && _a !== void 0 ? _a : true;
2279
- return (React__namespace.createElement(BaseInput, Object.assign({}, otherProps, { ref: ref, maxLength: (_b = props.maxLength) !== null && _b !== void 0 ? _b : 50, type: "number", value: value !== null && value !== void 0 ? value : '', onChange: e => {
2280
- const [v, displayValue] = parseNumber(e.target.value, props.step, props.min, props.max, applyInputConstraints);
2281
- // make sure the displayed value always matches our parsed value.
2282
- e.target.value = displayValue !== null && displayValue !== void 0 ? displayValue : '';
2283
- onChange(v, e);
2284
- }, onBlur: e => {
2285
- if (applyInputConstraints) {
2286
- // catch all for things we missed.
2287
- // onChange would have been called with undefined, but something strange might remain.
2288
- if (!e.target.checkValidity()) {
2289
- e.target.value = '';
2290
- }
2291
- }
2292
- } })));
2293
- });
2294
-
2295
- const defaultMaxLength = 200;
2296
- const defaultRows = 10;
2297
- const TextArea = React__namespace.forwardRef((props, ref) => {
2298
- var _a, _b;
2299
- const { className, value, onChange } = props, otherProps = __rest(props, ["className", "value", "onChange"]);
2300
- const theme = useThemeSafely();
2301
- const styles = css.css({
2302
- maxWidth: '100%',
2303
- minHeight: theme.controls.height,
2304
- fontFamily: theme.fonts.family,
2305
- fontSize: theme.fonts.size,
2306
- width: '100%',
2307
- border: theme.controls.border,
2308
- borderRadius: theme.controls.borderRadius,
2309
- color: theme.colors.font,
2310
- paddingTop: '0.75rem',
2311
- paddingLeft: theme.controls.padding,
2312
- paddingRight: theme.controls.padding,
2313
- height: 'auto',
2314
- transition: theme.controls.transition,
2315
- ':focus': {
2316
- outline: 'none',
2317
- boxShadow: theme.controls.focusOutlineShadow
2318
- },
2319
- ':disabled': {
2320
- backgroundColor: theme.colors.disabled,
2321
- cursor: 'not-allowed'
2322
- },
2323
- ':invalid': {
2324
- borderColor: theme.colors.required,
2325
- ':focus': {
2326
- boxShadow: theme.controls.focusOutlineRequiredShadow
2327
- }
2328
- },
2329
- }, props.readOnly && {
2330
- backgroundColor: 'transparent',
2331
- cursor: 'default',
2332
- border: 'none',
2333
- ':focus': {
2334
- outline: 'none',
2335
- boxShadow: 'none'
2336
- }
2337
- });
2338
- return (React__namespace.createElement("textarea", Object.assign({}, otherProps, { className: css.cx(styles, className), autoComplete: (_a = props.autoComplete) !== null && _a !== void 0 ? _a : 'off', tabIndex: props.readOnly ? -1 : props.tabIndex, maxLength: props.maxLength || defaultMaxLength, rows: (_b = props.rows) !== null && _b !== void 0 ? _b : defaultRows, ref: ref, value: value !== null && value !== void 0 ? value : '', onChange: e => {
2339
- onChange(e.target.value || undefined, e);
2340
- } })));
2341
- });
2486
+ return value;
2487
+ };
2342
2488
 
2343
2489
  const TextInput = React__namespace.forwardRef((props, ref) => {
2344
2490
  var _a;
2345
- const { value, onChange } = props, otherProps = __rest(props, ["value", "onChange"]);
2346
- return (React__namespace.createElement(BaseInput, Object.assign({}, otherProps, { type: (_a = props.type) !== null && _a !== void 0 ? _a : 'text', ref: ref, value: value !== null && value !== void 0 ? value : '', onChange: e => {
2347
- onChange(e.target.value || undefined, e);
2491
+ const [localValue, setLocalValue] = React__namespace.useState(props.value);
2492
+ const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
2493
+ const [validationError, updateErrorMessage] = useInputValidationMessage(inputRef, props);
2494
+ const nativeProps = __rest(props, ["onValueChange", "customError", "patternErrorMessage"]);
2495
+ useIgnoreMount(() => {
2496
+ var _a;
2497
+ if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
2498
+ props.onValueChange(localValue);
2499
+ }
2500
+ else {
2501
+ props.onValueChange(undefined);
2502
+ }
2503
+ updateErrorMessage();
2504
+ }, [localValue]);
2505
+ useIgnoreMount(() => {
2506
+ if (document.activeElement !== inputRef.current) {
2507
+ setLocalValue(props.value);
2508
+ }
2509
+ updateErrorMessage();
2510
+ }, [props.value]);
2511
+ return (React__namespace.createElement(BaseInput, Object.assign({}, nativeProps, { error: validationError, type: (_a = props.type) !== null && _a !== void 0 ? _a : 'text', ref: inputRef, value: localValue !== null && localValue !== void 0 ? localValue : '', onChange: e => {
2512
+ var _a;
2513
+ setLocalValue(e.target.value || undefined);
2514
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
2515
+ }, onBlur: e => {
2516
+ var _a;
2517
+ if (!e.target.checkValidity()) {
2518
+ setLocalValue(undefined);
2519
+ }
2520
+ (_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
2348
2521
  } })));
2349
2522
  });
2350
2523
 
@@ -2700,9 +2873,6 @@ const OmniLink = (props) => {
2700
2873
  ${props.round && `
2701
2874
  border-radius: ${theme.controls.roundRadius};
2702
2875
  `}
2703
- ${props.rounded && `
2704
- border-radius: ${theme.controls.roundedRadius};
2705
- `}
2706
2876
  ${props.small && `
2707
2877
  font-size: 0.8rem;
2708
2878
  height: ${theme.controls.heightSmall};
@@ -2732,7 +2902,7 @@ const OmniLink = (props) => {
2732
2902
  const Picker = (props) => {
2733
2903
  const selectProps = __rest(props
2734
2904
  // if we put numbers in, we expect them out
2735
- , ["value", "options", "onChange", "type", "rounded", "round", "readonly"]);
2905
+ , ["value", "options", "onChange", "readOnly", "round", "controlAlign"]);
2736
2906
  // if we put numbers in, we expect them out
2737
2907
  let isNumber = false;
2738
2908
  if (props.options && props.options.length) {
@@ -2765,13 +2935,10 @@ const Picker = (props) => {
2765
2935
  outline: none;
2766
2936
  box-shadow: ${theme.controls.focusOutlineShadow};
2767
2937
  }
2768
- ${props.rounded && `
2769
- border-radius: ${theme.controls.roundedRadius};
2770
- `}
2771
2938
  ${props.round && `
2772
2939
  border-radius: ${theme.controls.roundRadius};
2773
2940
  `}
2774
- ${props.readonly && `
2941
+ ${props.readOnly && `
2775
2942
  background-color: transparent !important;
2776
2943
  border: none;
2777
2944
  -webkit-appearance: none;
@@ -2782,9 +2949,9 @@ const Picker = (props) => {
2782
2949
  }
2783
2950
  `}
2784
2951
  `;
2785
- return (React__namespace.createElement("select", Object.assign({}, selectProps, { tabIndex: props.readonly ? -1 : selectProps.tabIndex, className: css.cx('picker', selectStyles, props.className), value: props.value, onKeyDown: e => {
2952
+ const select = (React__namespace.createElement("select", Object.assign({}, selectProps, { tabIndex: props.readOnly ? -1 : selectProps.tabIndex, className: css.cx('picker', selectStyles, props.className), value: props.value, onKeyDown: e => {
2786
2953
  var _a;
2787
- if (props.readonly) {
2954
+ if (props.readOnly) {
2788
2955
  if (e.keyCode === 9) {
2789
2956
  //TAB
2790
2957
  return;
@@ -2797,7 +2964,7 @@ const Picker = (props) => {
2797
2964
  }
2798
2965
  }, onMouseDown: e => {
2799
2966
  var _a;
2800
- if (props.readonly) {
2967
+ if (props.readOnly) {
2801
2968
  e.preventDefault();
2802
2969
  e.stopPropagation();
2803
2970
  }
@@ -2827,6 +2994,14 @@ const Picker = (props) => {
2827
2994
  }
2828
2995
  return React__namespace.createElement("option", { key: val, value: val }, label);
2829
2996
  })));
2997
+ if (props.controlAlign) {
2998
+ return (React__namespace.createElement("span", { className: css.css({
2999
+ display: 'inline-block',
3000
+ width: '100%',
3001
+ paddingBottom: theme.controls.inputErrorMinHeight
3002
+ }) }, select));
3003
+ }
3004
+ return select;
2830
3005
  };
2831
3006
 
2832
3007
  const Pager = (props) => {
@@ -2857,9 +3032,6 @@ const Pager = (props) => {
2857
3032
  @media(min-width: ${theme.breakpoints.tablet}) {
2858
3033
  grid-template-columns: ${theme.controls.height} 1fr 1fr 1fr ${theme.controls.height};
2859
3034
  }
2860
- ${props.rounded && `
2861
- border-radius: ${theme.controls.roundedRadius};
2862
- `}
2863
3035
  `;
2864
3036
  const controlStyles = css.css `
2865
3037
  display: none;
@@ -2894,8 +3066,8 @@ const BoundMemoryPager = (p) => {
2894
3066
  var _a, _b, _c;
2895
3067
  const { pager, showPageText } = p, rest = __rest(p, ["pager", "showPageText"]);
2896
3068
  return (React__namespace.createElement(Pager, Object.assign({}, rest, { pageIndex: p.showPageText ? pager.page : undefined, totalPages: p.showPageText ? pager.totalPages : undefined, canGoNext: pager.hasNext, canGoPrevious: pager.hasPrevious, minItem: pager.minItemIndex + 1, maxItem: pager.maxItemIndex + 1, totalItems: pager.totalItems, leftControls: pager.limitOptions.length > 1 && p.onLimit ? (React__namespace.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
2897
- React__namespace.createElement(Picker, { type: "select", value: pager.limit, options: pager.limitOptions, onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: pager.sortOptions.length > 1 && p.onSort ? (React__namespace.createElement(Label, { text: (_b = p.sortText) !== null && _b !== void 0 ? _b : 'Sort', orientation: "horizontalReverse" },
2898
- React__namespace.createElement(Picker, { type: "select", value: (_c = pager.sort) !== null && _c !== void 0 ? _c : '', options: pager.sortOptions, onChange: v => { var _a; return (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, page: d => {
3069
+ React__namespace.createElement(Picker, { value: pager.limit, options: pager.limitOptions, onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: pager.sortOptions.length > 1 && p.onSort ? (React__namespace.createElement(Label, { text: (_b = p.sortText) !== null && _b !== void 0 ? _b : 'Sort', orientation: "horizontalReverse" },
3070
+ React__namespace.createElement(Picker, { value: (_c = pager.sort) !== null && _c !== void 0 ? _c : '', options: pager.sortOptions, onChange: v => { var _a; return (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, page: d => {
2899
3071
  p.onPage(d);
2900
3072
  } })));
2901
3073
  };
@@ -2906,8 +3078,8 @@ const BoundStaticPager = (p) => {
2906
3078
  const showLimit = !!(result.limit && p.limitOptions && p.limitOptions.length > 1 && p.onLimit);
2907
3079
  const showSort = !!(p.sort !== undefined && p.sortOptions && p.sortOptions.length > 1 && p.onSort);
2908
3080
  return (React__namespace.createElement(Pager, Object.assign({}, rest, { pageIndex: p.showPageText ? result.page : undefined, totalPages: p.showPageText ? result.totalPages : undefined, canGoNext: result.hasNext, canGoPrevious: result.hasPrevious, minItem: result.minPageItemIndex + 1, maxItem: result.maxPageItemIndex + 1, totalItems: result.total, leftControls: showLimit ? (React__namespace.createElement(Label, { text: (_a = p.limitText) !== null && _a !== void 0 ? _a : 'Limit', orientation: "horizontal" },
2909
- React__namespace.createElement(Picker, { type: "select", value: (_b = result.limit) !== null && _b !== void 0 ? _b : 1, options: (_c = p.limitOptions) !== null && _c !== void 0 ? _c : [1], onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: showSort ? (React__namespace.createElement(Label, { text: (_d = p.sortText) !== null && _d !== void 0 ? _d : 'Sort', orientation: "horizontalReverse" },
2910
- React__namespace.createElement(Picker, { type: "select", value: (_e = p.sort) !== null && _e !== void 0 ? _e : '', options: (_f = p.sortOptions) !== null && _f !== void 0 ? _f : [], onChange: v => {
3081
+ React__namespace.createElement(Picker, { value: (_b = result.limit) !== null && _b !== void 0 ? _b : 1, options: (_c = p.limitOptions) !== null && _c !== void 0 ? _c : [1], onChange: v => { var _a; return (_a = p.onLimit) === null || _a === void 0 ? void 0 : _a.call(p, v); } }))) : undefined, rightControls: showSort ? (React__namespace.createElement(Label, { text: (_d = p.sortText) !== null && _d !== void 0 ? _d : 'Sort', orientation: "horizontalReverse" },
3082
+ React__namespace.createElement(Picker, { value: (_e = p.sort) !== null && _e !== void 0 ? _e : '', options: (_f = p.sortOptions) !== null && _f !== void 0 ? _f : [], onChange: v => {
2911
3083
  var _a;
2912
3084
  (_a = p.onSort) === null || _a === void 0 ? void 0 : _a.call(p, v);
2913
3085
  } }))) : undefined, page: d => {
@@ -3334,14 +3506,14 @@ const SearchBox = (props) => {
3334
3506
  return (_c = props.onSubmit) === null || _c === void 0 ? void 0 : _c.call(props);
3335
3507
  });
3336
3508
  const theme = useThemeSafely();
3337
- const submitButton = (React__namespace.createElement(Button, { disabled: waiting, readonly: !props.onSubmit, type: "submit", className: css.css({
3509
+ const submitButton = (React__namespace.createElement(Button, { disabled: waiting, readOnly: !props.onSubmit, type: "submit", className: css.css({
3338
3510
  color: `${theme.colors.font} !important;`,
3339
3511
  fontSize: '1rem'
3340
3512
  }), variant: "icon", small: true },
3341
3513
  React__namespace.createElement(Icon, { id: waiting ? 'waiting' : 'search', spin: waiting })));
3342
- //TB: replace with new inputs
3514
+ //TB: FUTURE replace with new inputs
3343
3515
  return (React__namespace.createElement(Form, { role: "search", className: css.cx('searchBox', props.className), onSubmit: onSubmit },
3344
- React__namespace.createElement(Input, { id: props.id, debounceMs: props.debounceMs, disabled: waiting, type: "text", value: props.value, placeholder: props.placeholder, round: props.round, rounded: props.rounded, onChange: props.onChange, rightControl: submitButton })));
3516
+ React__namespace.createElement(Input, { id: props.id, debounceMs: props.debounceMs, disabled: waiting, type: "text", value: props.value, placeholder: props.placeholder, round: props.round, onChange: props.onChange, rightControl: submitButton })));
3345
3517
  };
3346
3518
 
3347
3519
  const GlobalStyles = () => {
@@ -3500,10 +3672,6 @@ const TabHeader = (p) => {
3500
3672
  borderBottomRightRadius: 0,
3501
3673
  borderBottom: 'none',
3502
3674
  zIndex: 3,
3503
- }, active && p.rounded && {
3504
- borderRadius: p.rounded && theme.controls.roundedRadius,
3505
- borderBottomLeftRadius: 0,
3506
- borderBottomRightRadius: 0,
3507
3675
  });
3508
3676
  buttonVariant = 'link';
3509
3677
  buttonStyles = css.css({
@@ -3521,7 +3689,7 @@ const TabHeader = (p) => {
3521
3689
  });
3522
3690
  }
3523
3691
  return (React__namespace.createElement("li", { key: index, className: tabStyles },
3524
- React__namespace.createElement(Button, { className: buttonStyles, variant: buttonVariant, title: tab.name, readonly: active, rounded: p.rounded && variant === 'button', onClick: () => {
3692
+ React__namespace.createElement(Button, { className: buttonStyles, variant: buttonVariant, title: tab.name, readOnly: active, onClick: () => {
3525
3693
  setTabIndex(index);
3526
3694
  if (p.onTabChanged) {
3527
3695
  p.onTabChanged(index);
@@ -3653,6 +3821,86 @@ const ThSort = (props) => {
3653
3821
  props.rightContent)));
3654
3822
  };
3655
3823
 
3824
+ const defaultMaxLength = 200;
3825
+ const defaultRows = 10;
3826
+ const TextArea = React__namespace.forwardRef((props, ref) => {
3827
+ var _a, _b;
3828
+ const [localValue, setLocalValue] = React__namespace.useState(props.value);
3829
+ const [validationError, setValidationError] = React__namespace.useState('');
3830
+ const updateErrorMessage = React__namespace.useCallback(() => {
3831
+ setValidationError(getValidationMessage(inputRef.current));
3832
+ }, []);
3833
+ const inputRef = (ref !== null && ref !== void 0 ? ref : React__namespace.useRef(null));
3834
+ const nativeProps = __rest(props, ["onValueChange"]);
3835
+ const theme = useThemeSafely();
3836
+ React__namespace.useEffect(() => {
3837
+ updateErrorMessage();
3838
+ }, []);
3839
+ useIgnoreMount(() => {
3840
+ var _a;
3841
+ if ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.checkValidity()) {
3842
+ props.onValueChange(localValue);
3843
+ }
3844
+ else {
3845
+ props.onValueChange(undefined);
3846
+ }
3847
+ updateErrorMessage();
3848
+ }, [localValue]);
3849
+ useIgnoreMount(() => {
3850
+ if (document.activeElement !== inputRef.current) {
3851
+ setLocalValue(props.value);
3852
+ }
3853
+ updateErrorMessage();
3854
+ }, [props.value]);
3855
+ const styles = css.css({
3856
+ maxWidth: '100%',
3857
+ minHeight: theme.controls.height,
3858
+ fontFamily: theme.fonts.family,
3859
+ fontSize: theme.fonts.size,
3860
+ width: '100%',
3861
+ border: theme.controls.border,
3862
+ borderRadius: theme.controls.borderRadius,
3863
+ color: theme.colors.font,
3864
+ paddingTop: '0.75rem',
3865
+ paddingLeft: theme.controls.padding,
3866
+ paddingRight: theme.controls.padding,
3867
+ height: 'auto',
3868
+ transition: theme.controls.transition,
3869
+ ':focus': {
3870
+ outline: 'none',
3871
+ boxShadow: theme.controls.focusOutlineShadow
3872
+ },
3873
+ ':disabled': {
3874
+ backgroundColor: theme.colors.disabled,
3875
+ cursor: 'not-allowed'
3876
+ },
3877
+ ':invalid': {
3878
+ borderColor: theme.colors.required,
3879
+ ':focus': {
3880
+ boxShadow: theme.controls.focusOutlineRequiredShadow
3881
+ }
3882
+ },
3883
+ }, props.readOnly && {
3884
+ backgroundColor: 'transparent',
3885
+ cursor: 'default',
3886
+ border: 'none',
3887
+ ':focus': {
3888
+ outline: 'none',
3889
+ boxShadow: 'none'
3890
+ }
3891
+ });
3892
+ return (React__namespace.createElement("span", { className: css.css({
3893
+ display: 'inline-block',
3894
+ width: '100%'
3895
+ }) },
3896
+ 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 => {
3897
+ var _a;
3898
+ setLocalValue(e.target.value || undefined);
3899
+ (_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, e);
3900
+ } })),
3901
+ React__namespace.createElement(InputErrorDisplay, { error: validationError })));
3902
+ });
3903
+
3656
3904
  const ToggleButton = (props) => {
3657
3905
  return (React__namespace.createElement(Button, { type: "button", className: css.cx('toggleButton', props.checked && 'toggleButton--checked', props.className, props.checked && props.checkedClassName), rightIcon: props.checked ? props.checkedIcon : props.uncheckedIcon, disabled: props.disabled, enforceMinWidth: props.enforceMinWidth, variant: props.checked ? props.checkedVariant : props.variant, style: props.checked ? props.checkedStyle : props.style, onClick: props.onClick }, props.checked ? props.checkedText : props.uncheckedText));
3658
3906
  };
@@ -3720,10 +3968,9 @@ const ToggleButtonGroup = (props) => {
3720
3968
  })));
3721
3969
  };
3722
3970
 
3723
- const TogglePasswordInput = (p) => {
3971
+ const TogglePasswordInput = React__namespace.forwardRef((props, ref) => {
3724
3972
  const [show, setShow] = React__namespace.useState(false);
3725
- //TB: replace with new inputs
3726
- return (React__namespace.createElement(Input, Object.assign({}, p, { type: show ? 'text' : 'password', rightControl: (React__namespace.createElement(Button, { small: true, style: {
3973
+ return (React__namespace.createElement(TextInput, Object.assign({}, props, { ref: ref, type: show ? 'text' : 'password', rightControl: (React__namespace.createElement(Button, { small: true, style: {
3727
3974
  // small button is required here due to the icon pushing outside the boundries of the
3728
3975
  // parent textbox. increasing the font size here to fill the small button.
3729
3976
  fontSize: '1rem'
@@ -3731,7 +3978,7 @@ const TogglePasswordInput = (p) => {
3731
3978
  setShow(previous => !previous);
3732
3979
  } },
3733
3980
  React__namespace.createElement(Icon, { id: show ? 'show' : 'hide' }))) })));
3734
- };
3981
+ });
3735
3982
 
3736
3983
  const WaitingIndicator = (p) => {
3737
3984
  var _a, _b;
@@ -3808,7 +4055,6 @@ exports.Checkbox = Checkbox;
3808
4055
  exports.ConfirmModal = ConfirmModal;
3809
4056
  exports.CopyButton = CopyButton;
3810
4057
  exports.DateInput = DateInput;
3811
- exports.DatePicker = DatePicker;
3812
4058
  exports.Divider = Divider;
3813
4059
  exports.ErrorModal = ErrorModal;
3814
4060
  exports.FileUploader = FileUploader;
@@ -3859,7 +4105,6 @@ exports.WaitingIndicator = WaitingIndicator;
3859
4105
  exports.calcDynamicThemeProps = calcDynamicThemeProps;
3860
4106
  exports.defaultTheme = defaultTheme;
3861
4107
  exports.getCurrencyDisplay = getCurrencyDisplay;
3862
- exports.mergeClassNames = mergeClassNames;
3863
4108
  exports.useMediaQuery = useMediaQuery;
3864
4109
  exports.useThemeSafely = useThemeSafely;
3865
4110
  //# sourceMappingURL=index.js.map