@mackin.com/styleguide 6.0.2 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +15 -27
- package/index.js +363 -343
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -262,29 +262,12 @@ declare const ErrorModal: (props: {
|
|
|
262
262
|
|
|
263
263
|
/** @jsx jsx */
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
multiple?: boolean;
|
|
268
|
-
accept?: string;
|
|
269
|
-
/** Defaults to 'Choose File(s)'. */
|
|
270
|
-
buttonText?: string;
|
|
271
|
-
/** If the handler returns true, the native file input will be cleared. */
|
|
272
|
-
onChange?: (files: FileList | undefined) => boolean | undefined;
|
|
273
|
-
/**
|
|
274
|
-
* Used the facilitate communication between the FilePicker and FileUploader.
|
|
275
|
-
* Temp solution until we merge both together. Don't use! */
|
|
276
|
-
__passClearFilesHandle?: (func: () => void) => void;
|
|
277
|
-
}
|
|
278
|
-
/** Basic implementation here for later abstraction. */
|
|
279
|
-
declare const FilePicker: (props: FilePickerProps) => jsx.JSX.Element;
|
|
280
|
-
|
|
281
|
-
/** @jsx jsx */
|
|
282
|
-
|
|
283
|
-
interface IProps extends React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> {
|
|
265
|
+
declare type FormProps = React.ClassAttributes<HTMLFormElement> & React.FormHTMLAttributes<HTMLFormElement>;
|
|
266
|
+
interface IProps extends FormProps {
|
|
284
267
|
inline?: boolean;
|
|
285
268
|
}
|
|
286
269
|
/** Use this instead of <form> directly. If we need to fight Chrome's autofill, we can do so at a global level. */
|
|
287
|
-
declare const Form:
|
|
270
|
+
declare const Form: React.ForwardRefExoticComponent<Pick<IProps, "inline" | "key" | "css" | "acceptCharset" | "action" | "autoComplete" | "encType" | "method" | "name" | "noValidate" | "target" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "className" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "hidden" | "id" | "lang" | "placeholder" | "slot" | "spellCheck" | "style" | "tabIndex" | "title" | "translate" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "resource" | "typeof" | "vocab" | "autoCapitalize" | "autoCorrect" | "autoSave" | "color" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "children" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture"> & React.RefAttributes<any>>;
|
|
288
271
|
declare const FormFlexRow: (props: {
|
|
289
272
|
children: React.ReactNode;
|
|
290
273
|
className?: string;
|
|
@@ -374,9 +357,10 @@ declare const InfoTip: (props: InfoTipProps) => jsx.JSX.Element;
|
|
|
374
357
|
/** @jsx jsx */
|
|
375
358
|
|
|
376
359
|
declare type InputValue = string | number | undefined;
|
|
377
|
-
declare type InputType = 'text' | 'number' | 'textarea' | 'date' | 'password';
|
|
360
|
+
declare type InputType = 'text' | 'number' | 'textarea' | 'date' | 'password' | 'url' | 'email';
|
|
378
361
|
interface InputProps {
|
|
379
362
|
type: InputType;
|
|
363
|
+
name?: string;
|
|
380
364
|
style?: React.CSSProperties;
|
|
381
365
|
value?: InputValue;
|
|
382
366
|
rounded?: boolean;
|
|
@@ -392,7 +376,7 @@ interface InputProps {
|
|
|
392
376
|
/** Defaults to 'off'. */
|
|
393
377
|
autoComplete?: string;
|
|
394
378
|
/** Called with debounce when the input changes. */
|
|
395
|
-
onChange?: (value: InputValue) => void;
|
|
379
|
+
onChange?: (value: InputValue, name?: string) => void;
|
|
396
380
|
onFocus?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
397
381
|
onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
398
382
|
/** Defaults to 100. Ignored for type=number and type=date. */
|
|
@@ -407,8 +391,9 @@ interface InputProps {
|
|
|
407
391
|
max?: number;
|
|
408
392
|
/** Only used for type=textarea. Defaults to 10. */
|
|
409
393
|
rows?: number;
|
|
394
|
+
pattern?: string;
|
|
410
395
|
}
|
|
411
|
-
declare const Input:
|
|
396
|
+
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<any>>;
|
|
412
397
|
|
|
413
398
|
/** @jsx jsx */
|
|
414
399
|
|
|
@@ -816,7 +801,7 @@ declare const TabLocker: (props: {
|
|
|
816
801
|
|
|
817
802
|
/** @jsx jsx */
|
|
818
803
|
|
|
819
|
-
interface FileUploaderProps
|
|
804
|
+
interface FileUploaderProps {
|
|
820
805
|
onUpload: (files: FileList) => Promise<void>;
|
|
821
806
|
/** Defaults to 'Upload'. */
|
|
822
807
|
buttonText?: string;
|
|
@@ -828,8 +813,9 @@ interface FileUploaderProps extends FilePickerProps {
|
|
|
828
813
|
buttonWidth?: string;
|
|
829
814
|
/** Defaults to 'primary'. */
|
|
830
815
|
buttonVariant?: ButtonVariant;
|
|
831
|
-
|
|
832
|
-
|
|
816
|
+
maxBytes?: number;
|
|
817
|
+
multiple?: boolean;
|
|
818
|
+
accept?: string;
|
|
833
819
|
}
|
|
834
820
|
declare const FileUploader: (p: FileUploaderProps) => jsx.JSX.Element;
|
|
835
821
|
|
|
@@ -939,6 +925,8 @@ interface SliderProps<T extends SliderValue> {
|
|
|
939
925
|
onUpdate?: (value: T) => void;
|
|
940
926
|
/** Used with showValue. Will be called to render the display string. */
|
|
941
927
|
renderValue?: (value: number) => string;
|
|
928
|
+
/** Used with renderValue for the custom element width. Defaults to theme.controls.height * 2. */
|
|
929
|
+
renderValueWidth?: string;
|
|
942
930
|
}
|
|
943
931
|
declare const Slider: <T extends SliderValue>(p: SliderProps<T>) => jsx.JSX.Element;
|
|
944
932
|
|
|
@@ -972,4 +960,4 @@ declare const Backdrop: (p: {
|
|
|
972
960
|
|
|
973
961
|
declare const useMediaQuery: (query: string) => boolean;
|
|
974
962
|
|
|
975
|
-
export { Alignment, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, ButtonProps, Calendar, CalendarProps, Checkbox, CheckboxProps, ConfirmModal, ConfirmModalProps, CopyButton, DatePicker, DatePickerProps, Divider, ErrorModal,
|
|
963
|
+
export { Alignment, Backdrop$1 as Backdrop, Backdrop as Backdrop2, BoundMemoryPager, BoundStaticPager, Button, ButtonProps, Calendar, CalendarProps, Checkbox, CheckboxProps, ConfirmModal, ConfirmModalProps, CopyButton, DatePicker, DatePickerProps, Divider, ErrorModal, FileUploader, Form, FormColumnRow, FormFlexRow, GlobalStyles, Header, Highlight, ICONS, Icon, Image, InfoPanel, InfoTip, InfoTipProps, Input, InputProps, ItemPager, Label, LabelProps, List, ListItem, MackinTheme, Modal, Nav, OmniLink, OmniLinkProps, PagedResult, Pager, PagerProps, Picker, PickerProps, Popover, ProgressBar, ProgressBarProps, SearchBox, SearchBoxProps, Slider, TabHeader, TabHeaderProps, TabLocker, Table, Td, TdCurrency, TdNumber, Text, TextProps, Th, ThSort, ToggleButton, ToggleButtonGroup, ToggleButtonGroupProps, ToggleButtonProps, TogglePasswordInput, Tr, WaitingIndicator, calcDynamicThemeProps, defaultTheme, getCurrencyDisplay, mergeClassNames, useMediaQuery, useThemeSafely };
|
package/index.js
CHANGED
|
@@ -1591,7 +1591,7 @@ const Divider = (props) => {
|
|
|
1591
1591
|
|
|
1592
1592
|
/** @jsx jsx */
|
|
1593
1593
|
const ErrorModal = (props) => {
|
|
1594
|
-
const { message } = props;
|
|
1594
|
+
const { message } = props;
|
|
1595
1595
|
const theme = useThemeSafely();
|
|
1596
1596
|
const modalStyles = react.css `
|
|
1597
1597
|
.modalHeader {
|
|
@@ -1607,203 +1607,12 @@ const ErrorModal = (props) => {
|
|
|
1607
1607
|
react.jsx(Text, { align: "center" }, message))));
|
|
1608
1608
|
};
|
|
1609
1609
|
|
|
1610
|
-
/** @jsx jsx */
|
|
1611
|
-
const InfoPanel = (props) => {
|
|
1612
|
-
const theme = useThemeSafely();
|
|
1613
|
-
const styles = react.css `
|
|
1614
|
-
border:${theme.colors.border};
|
|
1615
|
-
padding:1rem;
|
|
1616
|
-
color: rgba(0, 0, 0, 0.7);
|
|
1617
|
-
margin: 0 !important;
|
|
1618
|
-
${props.variant === 'info' && `
|
|
1619
|
-
background-color:${theme.colors.info};
|
|
1620
|
-
color:${theme.colors.infoFont};
|
|
1621
|
-
`}
|
|
1622
|
-
${props.variant === 'warning' && `
|
|
1623
|
-
background-color:${theme.colors.warning};
|
|
1624
|
-
color:${theme.colors.warningFont};
|
|
1625
|
-
`}
|
|
1626
|
-
${props.variant === 'error' && `
|
|
1627
|
-
background-color:${theme.colors.omg};
|
|
1628
|
-
color:${theme.colors.omgFont};
|
|
1629
|
-
`}
|
|
1630
|
-
${props.variant === 'negative' && `
|
|
1631
|
-
background-color:${theme.colors.negative};
|
|
1632
|
-
color:${theme.colors.negativeFont};
|
|
1633
|
-
`}
|
|
1634
|
-
${props.variant === 'positive' && `
|
|
1635
|
-
background-color:${theme.colors.positive};
|
|
1636
|
-
color:${theme.colors.positiveFont};
|
|
1637
|
-
`}
|
|
1638
|
-
`;
|
|
1639
|
-
return (react.jsx(Text, { style: props.style, align: "center", css: styles, className: mergeClassNames('infoPanel', props.className) }, props.children));
|
|
1640
|
-
};
|
|
1641
|
-
|
|
1642
|
-
class FileListPlus {
|
|
1643
|
-
constructor(_raw, _args = {}) {
|
|
1644
|
-
this._raw = _raw;
|
|
1645
|
-
this._args = _args;
|
|
1646
|
-
this._files = Array.from(this._raw).map(f => {
|
|
1647
|
-
return { name: f.name, size: f.size, type: f.type };
|
|
1648
|
-
});
|
|
1649
|
-
if (this._args.accept) {
|
|
1650
|
-
const acceptTypes = this._args.accept.split(',');
|
|
1651
|
-
this._invalidFiles = this._files.filter(f => {
|
|
1652
|
-
if (acceptTypes.includes(f.type)) {
|
|
1653
|
-
return false;
|
|
1654
|
-
}
|
|
1655
|
-
if (acceptTypes.some(t => f.name.endsWith(t))) {
|
|
1656
|
-
return false;
|
|
1657
|
-
}
|
|
1658
|
-
return true;
|
|
1659
|
-
});
|
|
1660
|
-
}
|
|
1661
|
-
else {
|
|
1662
|
-
this._invalidFiles = [];
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
get raw() {
|
|
1666
|
-
return this._raw;
|
|
1667
|
-
}
|
|
1668
|
-
get length() {
|
|
1669
|
-
return this._files.length;
|
|
1670
|
-
}
|
|
1671
|
-
get files() {
|
|
1672
|
-
return this._files;
|
|
1673
|
-
}
|
|
1674
|
-
get invalidFiles() {
|
|
1675
|
-
return this._invalidFiles;
|
|
1676
|
-
}
|
|
1677
|
-
get totalBytes() {
|
|
1678
|
-
return lodash.sumBy(this.files, f => f.size);
|
|
1679
|
-
}
|
|
1680
|
-
get overMaxBytes() {
|
|
1681
|
-
var _a;
|
|
1682
|
-
return this.totalBytes >= ((_a = this._args.maxBytes) !== null && _a !== void 0 ? _a : Infinity);
|
|
1683
|
-
}
|
|
1684
|
-
get overFileLimit() {
|
|
1685
|
-
return this.length > (this._args.multiple ? Infinity : 1);
|
|
1686
|
-
}
|
|
1687
|
-
get hasErrors() {
|
|
1688
|
-
return this.overMaxBytes || this.overFileLimit || !!this.invalidFiles.length;
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
/** @jsx jsx */
|
|
1693
|
-
/** Basic implementation here for later abstraction. */
|
|
1694
|
-
const FilePicker = (props) => {
|
|
1695
|
-
var _a, _b, _c, _d;
|
|
1696
|
-
const input = React__namespace.useRef(null);
|
|
1697
|
-
const [fileList, setFileList] = React__namespace.useState(undefined);
|
|
1698
|
-
const totalFileSize = (_a = fileList === null || fileList === void 0 ? void 0 : fileList.totalBytes) !== null && _a !== void 0 ? _a : 0;
|
|
1699
|
-
const theme = useThemeSafely();
|
|
1700
|
-
let filesDisplay = '';
|
|
1701
|
-
if (!(fileList === null || fileList === void 0 ? void 0 : fileList.length)) {
|
|
1702
|
-
filesDisplay = `No file${props.multiple ? 's' : ''} chosen.`;
|
|
1703
|
-
}
|
|
1704
|
-
else {
|
|
1705
|
-
filesDisplay = `${fileList.length.toLocaleString()} file${fileList.length > 1 ? 's' : ''} selected (${getSizeString(totalFileSize)}): ${fileList.files.map(f => f.name).join(', ')}`;
|
|
1706
|
-
}
|
|
1707
|
-
const width = '10rem';
|
|
1708
|
-
const nativeInputStyles = react.css `
|
|
1709
|
-
position: absolute;
|
|
1710
|
-
top: 0;
|
|
1711
|
-
left: 0;
|
|
1712
|
-
bottom: 0;
|
|
1713
|
-
right: 0;
|
|
1714
|
-
border: 1px solid black;
|
|
1715
|
-
cursor: pointer;
|
|
1716
|
-
width:${width};
|
|
1717
|
-
opacity: 0;
|
|
1718
|
-
`;
|
|
1719
|
-
const buttonText = (_b = props.buttonText) !== null && _b !== void 0 ? _b : `Choose File${props.multiple ? 's' : ''}`;
|
|
1720
|
-
const clearFiles = () => {
|
|
1721
|
-
if (input.current) {
|
|
1722
|
-
input.current.value = '';
|
|
1723
|
-
}
|
|
1724
|
-
setFileList(undefined);
|
|
1725
|
-
};
|
|
1726
|
-
(_c = props.__passClearFilesHandle) === null || _c === void 0 ? void 0 : _c.call(props, clearFiles);
|
|
1727
|
-
return (react.jsx("span", { css: { display: 'inline-block' }, className: "fileUploader" },
|
|
1728
|
-
react.jsx("div", { css: {
|
|
1729
|
-
position: 'relative',
|
|
1730
|
-
width
|
|
1731
|
-
} },
|
|
1732
|
-
react.jsx(Button, { block: true, variant: "secondary", type: "button" }, buttonText),
|
|
1733
|
-
react.jsx("input", { ref: input, css: nativeInputStyles, type: "file", multiple: props.multiple, accept: props.accept, onChange: e => {
|
|
1734
|
-
var _a;
|
|
1735
|
-
try {
|
|
1736
|
-
if (!e.target.files) {
|
|
1737
|
-
setFileList(undefined);
|
|
1738
|
-
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, undefined);
|
|
1739
|
-
return;
|
|
1740
|
-
}
|
|
1741
|
-
const fileListPlus = new FileListPlus(e.target.files, {
|
|
1742
|
-
accept: props.accept,
|
|
1743
|
-
multiple: props.multiple,
|
|
1744
|
-
maxBytes: props.maxBytes
|
|
1745
|
-
});
|
|
1746
|
-
if (props.onChange) {
|
|
1747
|
-
if (fileListPlus.hasErrors) {
|
|
1748
|
-
props.onChange(undefined);
|
|
1749
|
-
setFileList(fileListPlus);
|
|
1750
|
-
}
|
|
1751
|
-
else {
|
|
1752
|
-
const removeFiles = props.onChange(fileListPlus.raw);
|
|
1753
|
-
if (removeFiles) {
|
|
1754
|
-
setFileList(undefined);
|
|
1755
|
-
}
|
|
1756
|
-
else {
|
|
1757
|
-
setFileList(fileListPlus);
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
else {
|
|
1762
|
-
setFileList(fileListPlus);
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
catch (err) {
|
|
1766
|
-
// tslint:disable-next-line
|
|
1767
|
-
console.error(err);
|
|
1768
|
-
setFileList(undefined);
|
|
1769
|
-
}
|
|
1770
|
-
} })),
|
|
1771
|
-
react.jsx(Text, null,
|
|
1772
|
-
filesDisplay,
|
|
1773
|
-
!!(fileList === null || fileList === void 0 ? void 0 : fileList.length) && (react.jsx(Button, { onClick: () => {
|
|
1774
|
-
var _a;
|
|
1775
|
-
clearFiles();
|
|
1776
|
-
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, undefined);
|
|
1777
|
-
}, css: { marginLeft: '1rem', color: theme.colors.negative }, rightIcon: react.jsx(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear"))),
|
|
1778
|
-
!!(fileList === null || fileList === void 0 ? void 0 : fileList.invalidFiles.length) && react.jsx(InfoPanel, { variant: "error" },
|
|
1779
|
-
"Invalid files: ",
|
|
1780
|
-
fileList.invalidFiles.map(f => f.name).join(', '),
|
|
1781
|
-
"."),
|
|
1782
|
-
(fileList === null || fileList === void 0 ? void 0 : fileList.overMaxBytes) && react.jsx(InfoPanel, { variant: "error" },
|
|
1783
|
-
"Max file size exceeded (",
|
|
1784
|
-
getSizeString((_d = props.maxBytes) !== null && _d !== void 0 ? _d : 0),
|
|
1785
|
-
").")));
|
|
1786
|
-
};
|
|
1787
|
-
const bytesInMb = 1048576;
|
|
1788
|
-
const bytesInKb = 1024;
|
|
1789
|
-
const getSizeString = (size) => {
|
|
1790
|
-
if (size < bytesInKb) {
|
|
1791
|
-
return size.toLocaleString() + ' B';
|
|
1792
|
-
}
|
|
1793
|
-
else if (size < bytesInMb) {
|
|
1794
|
-
return (size / bytesInKb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' KB';
|
|
1795
|
-
}
|
|
1796
|
-
else {
|
|
1797
|
-
return (size / bytesInMb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' MB';
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1800
|
-
|
|
1801
1610
|
/** @jsx jsx */
|
|
1802
1611
|
/** Use this instead of <form> directly. If we need to fight Chrome's autofill, we can do so at a global level. */
|
|
1803
|
-
const Form = (props) => {
|
|
1612
|
+
const Form = React__namespace.forwardRef((props, ref) => {
|
|
1804
1613
|
const { inline, children, onSubmit } = props, rest = __rest(props, ["inline", "children", "onSubmit"]);
|
|
1805
1614
|
const theme = useThemeSafely();
|
|
1806
|
-
return (react.jsx("form", Object.assign({ className: "form", css: {
|
|
1615
|
+
return (react.jsx("form", Object.assign({ ref: ref, className: "form", css: {
|
|
1807
1616
|
display: 'flex',
|
|
1808
1617
|
flexDirection: props.inline ? 'row' : 'column',
|
|
1809
1618
|
alignItems: props.inline ? 'flex-end' : 'normal',
|
|
@@ -1815,7 +1624,7 @@ const Form = (props) => {
|
|
|
1815
1624
|
onSubmit(e);
|
|
1816
1625
|
}
|
|
1817
1626
|
} }), children));
|
|
1818
|
-
};
|
|
1627
|
+
});
|
|
1819
1628
|
const FormFlexRow = (props) => {
|
|
1820
1629
|
var _a;
|
|
1821
1630
|
const theme = useThemeSafely();
|
|
@@ -1835,6 +1644,7 @@ const FormColumnRow = (props) => {
|
|
|
1835
1644
|
};
|
|
1836
1645
|
|
|
1837
1646
|
/** @jsx jsx */
|
|
1647
|
+
//TB: have a sticky variant
|
|
1838
1648
|
const Header = (props) => {
|
|
1839
1649
|
const theme = useThemeSafely();
|
|
1840
1650
|
const bodyStyles = css.css `
|
|
@@ -1951,6 +1761,38 @@ const Image = (props) => {
|
|
|
1951
1761
|
}, alt: props.alt, style: props.style, className: mergeClassNames('image', props.className), src: props.src }));
|
|
1952
1762
|
};
|
|
1953
1763
|
|
|
1764
|
+
/** @jsx jsx */
|
|
1765
|
+
const InfoPanel = (props) => {
|
|
1766
|
+
const theme = useThemeSafely();
|
|
1767
|
+
const styles = react.css `
|
|
1768
|
+
border:${theme.colors.border};
|
|
1769
|
+
padding:1rem;
|
|
1770
|
+
color: rgba(0, 0, 0, 0.7);
|
|
1771
|
+
margin: 0 !important;
|
|
1772
|
+
${props.variant === 'info' && `
|
|
1773
|
+
background-color:${theme.colors.info};
|
|
1774
|
+
color:${theme.colors.infoFont};
|
|
1775
|
+
`}
|
|
1776
|
+
${props.variant === 'warning' && `
|
|
1777
|
+
background-color:${theme.colors.warning};
|
|
1778
|
+
color:${theme.colors.warningFont};
|
|
1779
|
+
`}
|
|
1780
|
+
${props.variant === 'error' && `
|
|
1781
|
+
background-color:${theme.colors.omg};
|
|
1782
|
+
color:${theme.colors.omgFont};
|
|
1783
|
+
`}
|
|
1784
|
+
${props.variant === 'negative' && `
|
|
1785
|
+
background-color:${theme.colors.negative};
|
|
1786
|
+
color:${theme.colors.negativeFont};
|
|
1787
|
+
`}
|
|
1788
|
+
${props.variant === 'positive' && `
|
|
1789
|
+
background-color:${theme.colors.positive};
|
|
1790
|
+
color:${theme.colors.positiveFont};
|
|
1791
|
+
`}
|
|
1792
|
+
`;
|
|
1793
|
+
return (react.jsx(Text, { style: props.style, align: "center", css: styles, className: mergeClassNames('infoPanel', props.className) }, props.children));
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1954
1796
|
/** @jsx jsx */
|
|
1955
1797
|
const Popover = (p) => {
|
|
1956
1798
|
var _a, _b;
|
|
@@ -2066,19 +1908,19 @@ const formatLocalValue = (value, type) => {
|
|
|
2066
1908
|
}
|
|
2067
1909
|
return newValue;
|
|
2068
1910
|
};
|
|
2069
|
-
const Input = (props) => {
|
|
1911
|
+
const Input = React__namespace.forwardRef((props, ref) => {
|
|
2070
1912
|
var _a, _b, _c;
|
|
2071
1913
|
const [localValue, setLocalValue] = React__namespace.useState(formatLocalValue(props.value, props.type));
|
|
2072
1914
|
const debounceMs = (_a = props.debounceMs) !== null && _a !== void 0 ? _a : DEFAULT_DEBOUNCE_MS;
|
|
2073
1915
|
const autoComplete = (_b = props.autoComplete) !== null && _b !== void 0 ? _b : 'off';
|
|
2074
1916
|
const vars = React__namespace.useRef({
|
|
2075
|
-
wrappedOnChange: (props.onChange && debounceMs) ? lodash.debounce((value) => {
|
|
1917
|
+
wrappedOnChange: (props.onChange && debounceMs) ? lodash.debounce((value, name) => {
|
|
2076
1918
|
var _a;
|
|
2077
|
-
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value);
|
|
1919
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value, name);
|
|
2078
1920
|
}, debounceMs) : undefined,
|
|
2079
1921
|
focused: false
|
|
2080
1922
|
});
|
|
2081
|
-
const
|
|
1923
|
+
const outerOnChange = (_c = vars.current.wrappedOnChange) !== null && _c !== void 0 ? _c : props.onChange;
|
|
2082
1924
|
const trySyncLocalValue = () => {
|
|
2083
1925
|
if (vars.current.focused) {
|
|
2084
1926
|
return;
|
|
@@ -2091,53 +1933,49 @@ const Input = (props) => {
|
|
|
2091
1933
|
};
|
|
2092
1934
|
React__namespace.useEffect(() => {
|
|
2093
1935
|
trySyncLocalValue();
|
|
2094
|
-
});
|
|
1936
|
+
}, [props.value]);
|
|
2095
1937
|
const theme = useThemeSafely();
|
|
2096
|
-
const inputStyles = react.css
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
${props.rightControl && props.type !== 'textarea' && `
|
|
2138
|
-
padding-right: ${theme.controls.height};
|
|
2139
|
-
`}
|
|
2140
|
-
`;
|
|
1938
|
+
const inputStyles = react.css({
|
|
1939
|
+
fontFamily: theme.fonts.family,
|
|
1940
|
+
fontSize: theme.fonts.size,
|
|
1941
|
+
width: '100%',
|
|
1942
|
+
border: theme.controls.border,
|
|
1943
|
+
color: theme.colors.font,
|
|
1944
|
+
paddingLeft: theme.controls.padding,
|
|
1945
|
+
paddingRight: theme.controls.padding,
|
|
1946
|
+
height: theme.controls.height,
|
|
1947
|
+
transition: theme.controls.transition,
|
|
1948
|
+
':focus': {
|
|
1949
|
+
outline: 'none',
|
|
1950
|
+
boxShadow: theme.controls.focusOutlineShadow
|
|
1951
|
+
},
|
|
1952
|
+
':disabled': {
|
|
1953
|
+
backgroundColor: theme.colors.disabled,
|
|
1954
|
+
cursor: 'not-allowed'
|
|
1955
|
+
},
|
|
1956
|
+
':invalid': {
|
|
1957
|
+
borderColor: theme.colors.required,
|
|
1958
|
+
':focus': {
|
|
1959
|
+
boxShadow: theme.controls.focusOutlineRequiredShadow
|
|
1960
|
+
}
|
|
1961
|
+
},
|
|
1962
|
+
}, props.round && props.type !== 'textarea' && {
|
|
1963
|
+
borderRadius: theme.controls.roundRadius,
|
|
1964
|
+
paddingLeft: `calc(${theme.controls.padding} * 2)`,
|
|
1965
|
+
paddingRight: `calc(${theme.controls.padding} * 2)`
|
|
1966
|
+
}, props.rounded && {
|
|
1967
|
+
borderRadius: theme.controls.roundedRadius
|
|
1968
|
+
}, props.readOnly && {
|
|
1969
|
+
backgroundColor: 'transparent',
|
|
1970
|
+
cursor: 'default',
|
|
1971
|
+
border: 'none',
|
|
1972
|
+
':focus': {
|
|
1973
|
+
outline: 'none',
|
|
1974
|
+
boxShadow: 'none'
|
|
1975
|
+
}
|
|
1976
|
+
}, props.rightControl && props.type !== 'textarea' && {
|
|
1977
|
+
paddingRight: theme.controls.height
|
|
1978
|
+
});
|
|
2141
1979
|
let inputElement;
|
|
2142
1980
|
const onFocus = (e) => {
|
|
2143
1981
|
var _a;
|
|
@@ -2150,78 +1988,84 @@ const Input = (props) => {
|
|
|
2150
1988
|
trySyncLocalValue();
|
|
2151
1989
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
2152
1990
|
};
|
|
1991
|
+
let localOnChange;
|
|
2153
1992
|
if (props.type === 'number') {
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
if (
|
|
2159
|
-
|
|
2160
|
-
if (props.min && numValue < props.min) {
|
|
2161
|
-
numValue = props.min;
|
|
2162
|
-
}
|
|
2163
|
-
if (props.max && numValue > props.max) {
|
|
2164
|
-
numValue = props.max;
|
|
2165
|
-
}
|
|
2166
|
-
setLocalValue(numValue);
|
|
2167
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(numValue);
|
|
1993
|
+
localOnChange = e => {
|
|
1994
|
+
const value = e.target.value;
|
|
1995
|
+
if (NUMBER_REGEX.test(value)) {
|
|
1996
|
+
let numValue = parseFloat(value);
|
|
1997
|
+
if (props.min && numValue < props.min) {
|
|
1998
|
+
numValue = props.min;
|
|
2168
1999
|
}
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
|
|
2000
|
+
if (props.max && numValue > props.max) {
|
|
2001
|
+
numValue = props.max;
|
|
2172
2002
|
}
|
|
2173
|
-
|
|
2003
|
+
setLocalValue(numValue);
|
|
2004
|
+
outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(numValue, props.name);
|
|
2005
|
+
}
|
|
2006
|
+
else if (!value) {
|
|
2007
|
+
setLocalValue(value);
|
|
2008
|
+
outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(undefined, props.name);
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2174
2011
|
}
|
|
2175
2012
|
else if (props.type === 'date') {
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
}
|
|
2193
|
-
if (props.max && ms > props.max) {
|
|
2194
|
-
ms = props.max;
|
|
2195
|
-
}
|
|
2196
|
-
onChange(ms);
|
|
2013
|
+
localOnChange = e => {
|
|
2014
|
+
const value = e.target.value;
|
|
2015
|
+
setLocalValue(value);
|
|
2016
|
+
if (outerOnChange) {
|
|
2017
|
+
const dateParts = DATE_REGEX.exec(value);
|
|
2018
|
+
if (!dateParts) {
|
|
2019
|
+
outerOnChange(undefined, props.name);
|
|
2020
|
+
}
|
|
2021
|
+
else {
|
|
2022
|
+
const year = parseInt(dateParts[3], 10);
|
|
2023
|
+
const month = parseInt(dateParts[1], 10);
|
|
2024
|
+
const day = parseInt(dateParts[2], 10);
|
|
2025
|
+
if (dateFns.isExists(year, month, day)) {
|
|
2026
|
+
let ms = new Date(year, month - 1, day).valueOf();
|
|
2027
|
+
if (props.min && ms < props.min) {
|
|
2028
|
+
ms = props.min;
|
|
2197
2029
|
}
|
|
2198
|
-
|
|
2199
|
-
|
|
2030
|
+
if (props.max && ms > props.max) {
|
|
2031
|
+
ms = props.max;
|
|
2200
2032
|
}
|
|
2033
|
+
outerOnChange(ms, props.name);
|
|
2034
|
+
}
|
|
2035
|
+
else {
|
|
2036
|
+
outerOnChange(undefined, props.name);
|
|
2201
2037
|
}
|
|
2202
2038
|
}
|
|
2203
|
-
}
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
else {
|
|
2043
|
+
localOnChange = e => {
|
|
2044
|
+
const value = e.target.value;
|
|
2045
|
+
setLocalValue(value);
|
|
2046
|
+
outerOnChange === null || outerOnChange === void 0 ? void 0 : outerOnChange(value, props.name);
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
if (props.type === 'number') {
|
|
2050
|
+
inputElement = react.jsx("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly,
|
|
2051
|
+
// set fixed default to defeat pasting stupid numbers
|
|
2052
|
+
maxLength: 50, min: props.min, max: props.max, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: "number", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2053
|
+
}
|
|
2054
|
+
else if (props.type === 'date') {
|
|
2055
|
+
inputElement = react.jsx("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: 10, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: "text", value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2204
2056
|
}
|
|
2205
2057
|
else if (props.type === 'textarea') {
|
|
2206
|
-
inputElement = react.jsx("textarea", { style: props.style, rows: props.rows || 10, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: react.css `
|
|
2058
|
+
inputElement = react.jsx("textarea", { ref: ref, name: props.name, style: props.style, rows: props.rows || 10, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: react.css `
|
|
2207
2059
|
${inputStyles}
|
|
2208
2060
|
max-width: 100%;
|
|
2209
2061
|
min-height: ${theme.controls.height};
|
|
2210
2062
|
padding-top: 0.75rem;
|
|
2211
2063
|
height:auto;
|
|
2212
|
-
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange:
|
|
2213
|
-
const value = e.target.value;
|
|
2214
|
-
setLocalValue(value);
|
|
2215
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
2216
|
-
} });
|
|
2064
|
+
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2217
2065
|
}
|
|
2218
2066
|
else {
|
|
2219
|
-
// text
|
|
2220
|
-
inputElement = react.jsx("input", { style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange:
|
|
2221
|
-
const value = e.target.value;
|
|
2222
|
-
setLocalValue(value);
|
|
2223
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
2224
|
-
} });
|
|
2067
|
+
// text, password, email, and url
|
|
2068
|
+
inputElement = react.jsx("input", { ref: ref, name: props.name, pattern: props.pattern, style: props.style, autoComplete: autoComplete, tabIndex: props.readOnly ? -1 : undefined, readOnly: props.readOnly, maxLength: props.maxLength || DEFAULT_MAX_LENGTH, required: props.required, disabled: props.disabled, id: props.id, css: inputStyles, className: props.inputClassName, placeholder: props.placeholder, type: props.type, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2225
2069
|
}
|
|
2226
2070
|
const inputWrapperStyles = react.css `
|
|
2227
2071
|
width:100%;
|
|
@@ -2243,7 +2087,7 @@ const Input = (props) => {
|
|
|
2243
2087
|
return (react.jsx("div", { css: inputWrapperStyles, className: mergeClassNames('input', props.className) },
|
|
2244
2088
|
inputElement,
|
|
2245
2089
|
props.rightControl && props.type !== 'textarea' && react.jsx("div", { css: rightControlStyles }, props.rightControl)));
|
|
2246
|
-
};
|
|
2090
|
+
});
|
|
2247
2091
|
|
|
2248
2092
|
/** @jsx jsx */
|
|
2249
2093
|
const List = (props) => {
|
|
@@ -3059,65 +2903,217 @@ const GlobalStyles = (p) => {
|
|
|
3059
2903
|
}) }));
|
|
3060
2904
|
};
|
|
3061
2905
|
|
|
2906
|
+
class FileListPlus {
|
|
2907
|
+
constructor(_raw, _args = {}) {
|
|
2908
|
+
this._raw = _raw;
|
|
2909
|
+
this._args = _args;
|
|
2910
|
+
this._files = Array.from(this._raw).map(f => {
|
|
2911
|
+
return { name: f.name, size: f.size, type: f.type };
|
|
2912
|
+
});
|
|
2913
|
+
if (this._args.accept) {
|
|
2914
|
+
const acceptTypes = this._args.accept.split(',');
|
|
2915
|
+
this._invalidFiles = this._files.filter(f => {
|
|
2916
|
+
if (acceptTypes.includes(f.type)) {
|
|
2917
|
+
return false;
|
|
2918
|
+
}
|
|
2919
|
+
if (acceptTypes.some(t => f.name.endsWith(t))) {
|
|
2920
|
+
return false;
|
|
2921
|
+
}
|
|
2922
|
+
return true;
|
|
2923
|
+
});
|
|
2924
|
+
}
|
|
2925
|
+
else {
|
|
2926
|
+
this._invalidFiles = [];
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
get raw() {
|
|
2930
|
+
return this._raw;
|
|
2931
|
+
}
|
|
2932
|
+
get length() {
|
|
2933
|
+
return this._files.length;
|
|
2934
|
+
}
|
|
2935
|
+
get files() {
|
|
2936
|
+
return this._files;
|
|
2937
|
+
}
|
|
2938
|
+
get invalidFiles() {
|
|
2939
|
+
return this._invalidFiles;
|
|
2940
|
+
}
|
|
2941
|
+
get totalBytes() {
|
|
2942
|
+
return lodash.sumBy(this.files, f => f.size);
|
|
2943
|
+
}
|
|
2944
|
+
get overMaxBytes() {
|
|
2945
|
+
var _a;
|
|
2946
|
+
return this.totalBytes >= ((_a = this._args.maxBytes) !== null && _a !== void 0 ? _a : Infinity);
|
|
2947
|
+
}
|
|
2948
|
+
get overFileLimit() {
|
|
2949
|
+
return this.length > (this._args.multiple ? Infinity : 1);
|
|
2950
|
+
}
|
|
2951
|
+
get hasErrors() {
|
|
2952
|
+
return this.overMaxBytes || this.overFileLimit || !!this.invalidFiles.length;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
|
|
3062
2956
|
/** @jsx jsx */
|
|
3063
2957
|
const DEFAULT_FAILURE_MESSAGE = 'Upload failed.';
|
|
2958
|
+
const hoverClass = css.css({
|
|
2959
|
+
backgroundColor: 'rgba(0,0,0,0.25) !important'
|
|
2960
|
+
});
|
|
3064
2961
|
const FileUploader = (p) => {
|
|
3065
|
-
var _a;
|
|
2962
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3066
2963
|
const [message, setMessage] = React.useState(undefined);
|
|
3067
2964
|
const [canUpload, setCanUpload] = React.useState(false);
|
|
3068
2965
|
const [uploading, setUploading] = React.useState(false);
|
|
3069
2966
|
const [files, setFiles] = React.useState(undefined);
|
|
3070
2967
|
const [fullFailureMessage, setFullFailureMessage] = React.useState(undefined);
|
|
3071
|
-
const
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
const
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
(
|
|
2968
|
+
const form = React.useRef(null);
|
|
2969
|
+
const input = React.useRef(null);
|
|
2970
|
+
const totalFileSize = (_a = files === null || files === void 0 ? void 0 : files.totalBytes) !== null && _a !== void 0 ? _a : 0;
|
|
2971
|
+
const theme = useThemeSafely();
|
|
2972
|
+
let filesDisplay = '';
|
|
2973
|
+
if (!message) {
|
|
2974
|
+
if (!(files === null || files === void 0 ? void 0 : files.length)) {
|
|
2975
|
+
filesDisplay = `Click or drag and drop files.`;
|
|
2976
|
+
}
|
|
2977
|
+
else {
|
|
2978
|
+
filesDisplay = `${files.length.toLocaleString()} file${files.length > 1 ? 's' : ''} selected (${getSizeString(totalFileSize)}): ${files.files.map(f => f.name).join(', ')}`;
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
const setAllFiles = (inputFiles) => {
|
|
2982
|
+
if (input.current && inputFiles === undefined) {
|
|
2983
|
+
input.current.value = '';
|
|
2984
|
+
}
|
|
2985
|
+
setFiles(inputFiles);
|
|
2986
|
+
};
|
|
2987
|
+
const onFilesChange = (rawFiles) => {
|
|
2988
|
+
setAllFiles(rawFiles ? createFileList(rawFiles) : undefined);
|
|
2989
|
+
setCanUpload(!!(rawFiles === null || rawFiles === void 0 ? void 0 : rawFiles.length));
|
|
3078
2990
|
setMessage(undefined);
|
|
2991
|
+
setFullFailureMessage(undefined);
|
|
2992
|
+
};
|
|
2993
|
+
const createFileList = (rawFiles) => {
|
|
2994
|
+
return new FileListPlus(rawFiles, {
|
|
2995
|
+
accept: p.accept,
|
|
2996
|
+
multiple: p.multiple,
|
|
2997
|
+
maxBytes: p.maxBytes
|
|
2998
|
+
});
|
|
3079
2999
|
};
|
|
3080
|
-
return (react.jsx(Form, {
|
|
3000
|
+
return (react.jsx(Form, { ref: form, css: {
|
|
3001
|
+
border: theme.controls.border,
|
|
3002
|
+
borderStyle: 'dashed',
|
|
3003
|
+
alignItems: 'center',
|
|
3004
|
+
justifyContent: 'center',
|
|
3005
|
+
position: 'relative',
|
|
3006
|
+
padding: '1rem',
|
|
3007
|
+
overflow: 'hidden',
|
|
3008
|
+
backgroundColor: theme.colors.lightBg,
|
|
3009
|
+
}, onDragOver: e => {
|
|
3010
|
+
var _a, _b;
|
|
3011
|
+
e.preventDefault();
|
|
3012
|
+
// we're using onDragOver instead of onDragEnter because *Enter and *Leave apparently can fire multiple times even though you're over the target.
|
|
3013
|
+
// *Over is continuous.
|
|
3014
|
+
if (!((_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.contains(hoverClass))) {
|
|
3015
|
+
(_b = form.current) === null || _b === void 0 ? void 0 : _b.classList.add(hoverClass);
|
|
3016
|
+
}
|
|
3017
|
+
}, onDragLeave: e => {
|
|
3018
|
+
var _a;
|
|
3019
|
+
(_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.remove(hoverClass);
|
|
3020
|
+
}, onDrop: e => {
|
|
3021
|
+
var _a;
|
|
3022
|
+
e.preventDefault();
|
|
3023
|
+
(_a = form.current) === null || _a === void 0 ? void 0 : _a.classList.remove(hoverClass);
|
|
3024
|
+
onFilesChange(e.dataTransfer.files);
|
|
3025
|
+
}, onSubmit: e => {
|
|
3081
3026
|
if (!files) {
|
|
3082
3027
|
return;
|
|
3083
3028
|
}
|
|
3084
3029
|
setUploading(true);
|
|
3085
|
-
p.onUpload(files).then(() => {
|
|
3030
|
+
p.onUpload(files.raw).then(() => {
|
|
3086
3031
|
setMessage('success');
|
|
3087
|
-
|
|
3088
|
-
clearFilePickerHandler.current();
|
|
3089
|
-
}
|
|
3032
|
+
setAllFiles(undefined);
|
|
3090
3033
|
}).catch(err => {
|
|
3034
|
+
var _a;
|
|
3091
3035
|
setMessage('failure');
|
|
3092
|
-
setFullFailureMessage(`${failureMessage !== null &&
|
|
3036
|
+
setFullFailureMessage(`${(_a = p.failureMessage) !== null && _a !== void 0 ? _a : DEFAULT_FAILURE_MESSAGE} Error: ${err instanceof Error ? err.message : err}`);
|
|
3093
3037
|
}).finally(() => {
|
|
3094
3038
|
setUploading(false);
|
|
3095
3039
|
setCanUpload(false);
|
|
3096
3040
|
});
|
|
3097
3041
|
} },
|
|
3098
|
-
react.jsx(
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3042
|
+
react.jsx("input", { ref: input, css: {
|
|
3043
|
+
position: 'absolute',
|
|
3044
|
+
top: -50,
|
|
3045
|
+
left: 0,
|
|
3046
|
+
bottom: 0,
|
|
3047
|
+
right: 0,
|
|
3048
|
+
width: '100%',
|
|
3049
|
+
cursor: 'pointer',
|
|
3050
|
+
opacity: 0
|
|
3051
|
+
}, type: "file", multiple: p.multiple, accept: p.accept, onChange: e => {
|
|
3052
|
+
try {
|
|
3053
|
+
if (!e.target.files) {
|
|
3054
|
+
onFilesChange(undefined);
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
onFilesChange(e.target.files);
|
|
3105
3058
|
}
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3059
|
+
catch (err) {
|
|
3060
|
+
// tslint:disable-next-line
|
|
3061
|
+
console.error(err);
|
|
3062
|
+
onFilesChange(undefined);
|
|
3063
|
+
}
|
|
3064
|
+
} }),
|
|
3065
|
+
!message && (react.jsx("span", { css: {
|
|
3066
|
+
display: 'flex',
|
|
3067
|
+
flexDirection: 'column',
|
|
3068
|
+
gap: '1rem',
|
|
3069
|
+
alignItems: 'center',
|
|
3070
|
+
zIndex: !!(files === null || files === void 0 ? void 0 : files.length) ? 1 : undefined
|
|
3071
|
+
} },
|
|
3072
|
+
!(files === null || files === void 0 ? void 0 : files.length) && react.jsx(Icon, { style: { fontSize: '2rem' }, id: "upload" }),
|
|
3073
|
+
react.jsx(Text, { align: "center", noPad: true, spacedOut: true },
|
|
3074
|
+
filesDisplay,
|
|
3075
|
+
!!(files === null || files === void 0 ? void 0 : files.length) && (react.jsx(Button, { onClick: e => {
|
|
3076
|
+
e.stopPropagation();
|
|
3077
|
+
onFilesChange(undefined);
|
|
3078
|
+
}, css: { marginLeft: '1rem', color: theme.colors.negative }, rightIcon: react.jsx(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear"))),
|
|
3079
|
+
!!(files === null || files === void 0 ? void 0 : files.invalidFiles.length) && (react.jsx(InfoPanel, { variant: "error" },
|
|
3080
|
+
"Invalid files: ",
|
|
3081
|
+
files.invalidFiles.map(f => f.name).join(', '),
|
|
3082
|
+
".")),
|
|
3083
|
+
(files === null || files === void 0 ? void 0 : files.overMaxBytes) && (react.jsx(InfoPanel, { variant: "error" },
|
|
3084
|
+
"Max file size exceeded (",
|
|
3085
|
+
getSizeString((_b = p.maxBytes) !== null && _b !== void 0 ? _b : 0),
|
|
3086
|
+
").")))),
|
|
3087
|
+
canUpload && !(files === null || files === void 0 ? void 0 : files.hasErrors) && (react.jsx(Button, { css: {
|
|
3088
|
+
width: (_c = p.buttonWidth) !== null && _c !== void 0 ? _c : '10rem',
|
|
3089
|
+
zIndex: 1,
|
|
3090
|
+
}, waiting: uploading, type: "submit", variant: (_d = p.buttonVariant) !== null && _d !== void 0 ? _d : 'primary' }, (_e = p.buttonText) !== null && _e !== void 0 ? _e : 'Upload')),
|
|
3091
|
+
message === 'success' && (react.jsx(UploadInfoPanel, { variant: "positive", message: (_f = p.successMessage) !== null && _f !== void 0 ? _f : 'Upload successful.', onClear: () => setMessage(undefined) })),
|
|
3092
|
+
message === 'failure' && (react.jsx(UploadInfoPanel, { variant: "error", message: fullFailureMessage, onClear: () => setMessage(undefined) }))));
|
|
3112
3093
|
};
|
|
3113
3094
|
const UploadInfoPanel = (p) => {
|
|
3114
|
-
|
|
3115
|
-
return (react.jsx(InfoPanel, { variant: p.variant },
|
|
3095
|
+
return (react.jsx(InfoPanel, { variant: p.variant, css: { zIndex: 1 } },
|
|
3116
3096
|
p.message,
|
|
3117
|
-
react.jsx(Button, { block: true,
|
|
3097
|
+
react.jsx(Button, { block: true, css: {
|
|
3118
3098
|
color: 'inherit',
|
|
3119
3099
|
marginTop: '1rem'
|
|
3120
|
-
}
|
|
3100
|
+
}, onClick: e => {
|
|
3101
|
+
e.stopPropagation();
|
|
3102
|
+
p.onClear();
|
|
3103
|
+
}, rightIcon: react.jsx(Icon, { id: "clear" }), variant: "inlineLink" }, "Clear")));
|
|
3104
|
+
};
|
|
3105
|
+
const bytesInMb = 1048576;
|
|
3106
|
+
const bytesInKb = 1024;
|
|
3107
|
+
const getSizeString = (size) => {
|
|
3108
|
+
if (size < bytesInKb) {
|
|
3109
|
+
return size.toLocaleString() + ' B';
|
|
3110
|
+
}
|
|
3111
|
+
else if (size < bytesInMb) {
|
|
3112
|
+
return (size / bytesInKb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' KB';
|
|
3113
|
+
}
|
|
3114
|
+
else {
|
|
3115
|
+
return (size / bytesInMb).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + ' MB';
|
|
3116
|
+
}
|
|
3121
3117
|
};
|
|
3122
3118
|
|
|
3123
3119
|
const CopyButton = (props) => {
|
|
@@ -3173,8 +3169,9 @@ const BoundStaticPager = (p) => {
|
|
|
3173
3169
|
const Slider = (p) => {
|
|
3174
3170
|
const theme = useThemeSafely();
|
|
3175
3171
|
const currentValue = React.useRef(p.value);
|
|
3172
|
+
const sliderContainer = React.useRef(null);
|
|
3176
3173
|
const height = p.showValue ? `calc(${theme.controls.height} + 1.5rem)` : theme.controls.height;
|
|
3177
|
-
return (react.jsx("div", { css: {
|
|
3174
|
+
return (react.jsx("div", { ref: sliderContainer, css: {
|
|
3178
3175
|
width: '100%',
|
|
3179
3176
|
height,
|
|
3180
3177
|
} },
|
|
@@ -3217,22 +3214,46 @@ const Slider = (p) => {
|
|
|
3217
3214
|
'&:hover': {
|
|
3218
3215
|
filter: theme.controls.hoverBrightness
|
|
3219
3216
|
}
|
|
3220
|
-
} }, props), p.showValue && react.jsx(HandleText, { value: currentValue.current
|
|
3217
|
+
} }, props), p.showValue && (react.jsx(HandleText, { index: state.index, parentElement: sliderContainer.current, value: Array.isArray(currentValue.current) ? currentValue.current[state.index] : currentValue.current, renderValue: p.renderValue, renderValueWidth: p.renderValueWidth }))));
|
|
3221
3218
|
} })));
|
|
3222
3219
|
};
|
|
3220
|
+
const rectsCollideX = (r1, r2) => {
|
|
3221
|
+
if (r1.left >= r2.left && r1.left <= r2.right) {
|
|
3222
|
+
return true;
|
|
3223
|
+
}
|
|
3224
|
+
if (r1.right >= r2.left && r1.right <= r2.right) {
|
|
3225
|
+
return true;
|
|
3226
|
+
}
|
|
3227
|
+
return false;
|
|
3228
|
+
};
|
|
3223
3229
|
const HandleText = (p) => {
|
|
3224
3230
|
var _a, _b, _c;
|
|
3225
3231
|
const theme = useThemeSafely();
|
|
3226
|
-
const
|
|
3227
|
-
const
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3232
|
+
const displayValue = (_b = (_a = p.renderValue) === null || _a === void 0 ? void 0 : _a.call(p, p.value)) !== null && _b !== void 0 ? _b : p.value;
|
|
3233
|
+
const renderValueWidth = (_c = p.renderValueWidth) !== null && _c !== void 0 ? _c : theme.controls.height;
|
|
3234
|
+
const renderValueLeft = React.useMemo(() => {
|
|
3235
|
+
return `calc(${renderValueWidth} * 0.5 * -1 + (${theme.controls.height} * 0.5))`;
|
|
3236
|
+
}, [p.renderValueWidth]);
|
|
3237
|
+
const [flipText, setFlipText] = React.useState(false);
|
|
3238
|
+
React.useEffect(() => {
|
|
3239
|
+
// this needs to fire on every render due to the other handle also moving.
|
|
3240
|
+
var _a, _b;
|
|
3241
|
+
if (p.index === 1) {
|
|
3242
|
+
// only do this for the max/right-most handle
|
|
3243
|
+
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());
|
|
3244
|
+
if (r1 && r2) {
|
|
3245
|
+
setFlipText(rectsCollideX(r1, r2));
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
});
|
|
3249
|
+
return (react.jsx(Text, { ellipsis: true, css: {
|
|
3250
|
+
width: renderValueWidth,
|
|
3251
|
+
left: renderValueLeft,
|
|
3252
|
+
top: flipText ? undefined : theme.controls.height,
|
|
3253
|
+
bottom: flipText ? theme.controls.height : undefined,
|
|
3233
3254
|
position: 'absolute',
|
|
3234
|
-
overflow: 'hidden'
|
|
3235
|
-
}, tag: "div", align: "center" }, displayValue));
|
|
3255
|
+
overflow: 'hidden',
|
|
3256
|
+
}, className: "slider-handle", tag: "div", align: "center" }, displayValue));
|
|
3236
3257
|
};
|
|
3237
3258
|
|
|
3238
3259
|
/** @jsx jsx */
|
|
@@ -3364,7 +3385,6 @@ exports.CopyButton = CopyButton;
|
|
|
3364
3385
|
exports.DatePicker = DatePicker;
|
|
3365
3386
|
exports.Divider = Divider;
|
|
3366
3387
|
exports.ErrorModal = ErrorModal;
|
|
3367
|
-
exports.FilePicker = FilePicker;
|
|
3368
3388
|
exports.FileUploader = FileUploader;
|
|
3369
3389
|
exports.Form = Form;
|
|
3370
3390
|
exports.FormColumnRow = FormColumnRow;
|