@mackin.com/styleguide 6.1.0 → 7.0.2
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 +13 -27
- package/index.js +359 -341
- 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 = Omit<React.ClassAttributes<HTMLFormElement> & React.FormHTMLAttributes<HTMLFormElement>, 'css'>;
|
|
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, "key" | "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" | "inline"> & 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
|
|
|
@@ -974,4 +960,4 @@ declare const Backdrop: (p: {
|
|
|
974
960
|
|
|
975
961
|
declare const useMediaQuery: (query: string) => boolean;
|
|
976
962
|
|
|
977
|
-
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();
|
|
@@ -1952,6 +1761,38 @@ const Image = (props) => {
|
|
|
1952
1761
|
}, alt: props.alt, style: props.style, className: mergeClassNames('image', props.className), src: props.src }));
|
|
1953
1762
|
};
|
|
1954
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
|
+
|
|
1955
1796
|
/** @jsx jsx */
|
|
1956
1797
|
const Popover = (p) => {
|
|
1957
1798
|
var _a, _b;
|
|
@@ -2067,19 +1908,19 @@ const formatLocalValue = (value, type) => {
|
|
|
2067
1908
|
}
|
|
2068
1909
|
return newValue;
|
|
2069
1910
|
};
|
|
2070
|
-
const Input = (props) => {
|
|
1911
|
+
const Input = React__namespace.forwardRef((props, ref) => {
|
|
2071
1912
|
var _a, _b, _c;
|
|
2072
1913
|
const [localValue, setLocalValue] = React__namespace.useState(formatLocalValue(props.value, props.type));
|
|
2073
1914
|
const debounceMs = (_a = props.debounceMs) !== null && _a !== void 0 ? _a : DEFAULT_DEBOUNCE_MS;
|
|
2074
1915
|
const autoComplete = (_b = props.autoComplete) !== null && _b !== void 0 ? _b : 'off';
|
|
2075
1916
|
const vars = React__namespace.useRef({
|
|
2076
|
-
wrappedOnChange: (props.onChange && debounceMs) ? lodash.debounce((value) => {
|
|
1917
|
+
wrappedOnChange: (props.onChange && debounceMs) ? lodash.debounce((value, name) => {
|
|
2077
1918
|
var _a;
|
|
2078
|
-
(_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);
|
|
2079
1920
|
}, debounceMs) : undefined,
|
|
2080
1921
|
focused: false
|
|
2081
1922
|
});
|
|
2082
|
-
const
|
|
1923
|
+
const outerOnChange = (_c = vars.current.wrappedOnChange) !== null && _c !== void 0 ? _c : props.onChange;
|
|
2083
1924
|
const trySyncLocalValue = () => {
|
|
2084
1925
|
if (vars.current.focused) {
|
|
2085
1926
|
return;
|
|
@@ -2092,53 +1933,49 @@ const Input = (props) => {
|
|
|
2092
1933
|
};
|
|
2093
1934
|
React__namespace.useEffect(() => {
|
|
2094
1935
|
trySyncLocalValue();
|
|
2095
|
-
});
|
|
1936
|
+
}, [props.value]);
|
|
2096
1937
|
const theme = useThemeSafely();
|
|
2097
|
-
const inputStyles = react.css
|
|
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
|
-
|
|
2138
|
-
${props.rightControl && props.type !== 'textarea' && `
|
|
2139
|
-
padding-right: ${theme.controls.height};
|
|
2140
|
-
`}
|
|
2141
|
-
`;
|
|
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
|
+
});
|
|
2142
1979
|
let inputElement;
|
|
2143
1980
|
const onFocus = (e) => {
|
|
2144
1981
|
var _a;
|
|
@@ -2151,78 +1988,84 @@ const Input = (props) => {
|
|
|
2151
1988
|
trySyncLocalValue();
|
|
2152
1989
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
2153
1990
|
};
|
|
1991
|
+
let localOnChange;
|
|
2154
1992
|
if (props.type === 'number') {
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
if (
|
|
2160
|
-
|
|
2161
|
-
if (props.min && numValue < props.min) {
|
|
2162
|
-
numValue = props.min;
|
|
2163
|
-
}
|
|
2164
|
-
if (props.max && numValue > props.max) {
|
|
2165
|
-
numValue = props.max;
|
|
2166
|
-
}
|
|
2167
|
-
setLocalValue(numValue);
|
|
2168
|
-
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;
|
|
2169
1999
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(undefined);
|
|
2000
|
+
if (props.max && numValue > props.max) {
|
|
2001
|
+
numValue = props.max;
|
|
2173
2002
|
}
|
|
2174
|
-
|
|
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
|
+
};
|
|
2175
2011
|
}
|
|
2176
2012
|
else if (props.type === 'date') {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
}
|
|
2194
|
-
if (props.max && ms > props.max) {
|
|
2195
|
-
ms = props.max;
|
|
2196
|
-
}
|
|
2197
|
-
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;
|
|
2198
2029
|
}
|
|
2199
|
-
|
|
2200
|
-
|
|
2030
|
+
if (props.max && ms > props.max) {
|
|
2031
|
+
ms = props.max;
|
|
2201
2032
|
}
|
|
2033
|
+
outerOnChange(ms, props.name);
|
|
2034
|
+
}
|
|
2035
|
+
else {
|
|
2036
|
+
outerOnChange(undefined, props.name);
|
|
2202
2037
|
}
|
|
2203
2038
|
}
|
|
2204
|
-
}
|
|
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 });
|
|
2205
2056
|
}
|
|
2206
2057
|
else if (props.type === 'textarea') {
|
|
2207
|
-
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 `
|
|
2208
2059
|
${inputStyles}
|
|
2209
2060
|
max-width: 100%;
|
|
2210
2061
|
min-height: ${theme.controls.height};
|
|
2211
2062
|
padding-top: 0.75rem;
|
|
2212
2063
|
height:auto;
|
|
2213
|
-
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange:
|
|
2214
|
-
const value = e.target.value;
|
|
2215
|
-
setLocalValue(value);
|
|
2216
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
2217
|
-
} });
|
|
2064
|
+
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2218
2065
|
}
|
|
2219
2066
|
else {
|
|
2220
|
-
// text
|
|
2221
|
-
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:
|
|
2222
|
-
const value = e.target.value;
|
|
2223
|
-
setLocalValue(value);
|
|
2224
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
2225
|
-
} });
|
|
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 });
|
|
2226
2069
|
}
|
|
2227
2070
|
const inputWrapperStyles = react.css `
|
|
2228
2071
|
width:100%;
|
|
@@ -2244,7 +2087,7 @@ const Input = (props) => {
|
|
|
2244
2087
|
return (react.jsx("div", { css: inputWrapperStyles, className: mergeClassNames('input', props.className) },
|
|
2245
2088
|
inputElement,
|
|
2246
2089
|
props.rightControl && props.type !== 'textarea' && react.jsx("div", { css: rightControlStyles }, props.rightControl)));
|
|
2247
|
-
};
|
|
2090
|
+
});
|
|
2248
2091
|
|
|
2249
2092
|
/** @jsx jsx */
|
|
2250
2093
|
const List = (props) => {
|
|
@@ -3060,65 +2903,217 @@ const GlobalStyles = (p) => {
|
|
|
3060
2903
|
}) }));
|
|
3061
2904
|
};
|
|
3062
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
|
+
|
|
3063
2956
|
/** @jsx jsx */
|
|
3064
2957
|
const DEFAULT_FAILURE_MESSAGE = 'Upload failed.';
|
|
2958
|
+
const hoverClass = css.css({
|
|
2959
|
+
backgroundColor: 'rgba(0,0,0,0.25) !important'
|
|
2960
|
+
});
|
|
3065
2961
|
const FileUploader = (p) => {
|
|
3066
|
-
var _a;
|
|
2962
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3067
2963
|
const [message, setMessage] = React.useState(undefined);
|
|
3068
2964
|
const [canUpload, setCanUpload] = React.useState(false);
|
|
3069
2965
|
const [uploading, setUploading] = React.useState(false);
|
|
3070
2966
|
const [files, setFiles] = React.useState(undefined);
|
|
3071
2967
|
const [fullFailureMessage, setFullFailureMessage] = React.useState(undefined);
|
|
3072
|
-
const
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
const
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
(
|
|
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));
|
|
3079
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
|
+
});
|
|
3080
2999
|
};
|
|
3081
|
-
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 => {
|
|
3082
3026
|
if (!files) {
|
|
3083
3027
|
return;
|
|
3084
3028
|
}
|
|
3085
3029
|
setUploading(true);
|
|
3086
|
-
p.onUpload(files).then(() => {
|
|
3030
|
+
p.onUpload(files.raw).then(() => {
|
|
3087
3031
|
setMessage('success');
|
|
3088
|
-
|
|
3089
|
-
clearFilePickerHandler.current();
|
|
3090
|
-
}
|
|
3032
|
+
setAllFiles(undefined);
|
|
3091
3033
|
}).catch(err => {
|
|
3034
|
+
var _a;
|
|
3092
3035
|
setMessage('failure');
|
|
3093
|
-
setFullFailureMessage(`${failureMessage !== null &&
|
|
3036
|
+
setFullFailureMessage(`${(_a = p.failureMessage) !== null && _a !== void 0 ? _a : DEFAULT_FAILURE_MESSAGE} Error: ${err instanceof Error ? err.message : err}`);
|
|
3094
3037
|
}).finally(() => {
|
|
3095
3038
|
setUploading(false);
|
|
3096
3039
|
setCanUpload(false);
|
|
3097
3040
|
});
|
|
3098
3041
|
} },
|
|
3099
|
-
react.jsx(
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
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);
|
|
3106
3058
|
}
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
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) }))));
|
|
3113
3093
|
};
|
|
3114
3094
|
const UploadInfoPanel = (p) => {
|
|
3115
|
-
|
|
3116
|
-
return (react.jsx(InfoPanel, { variant: p.variant },
|
|
3095
|
+
return (react.jsx(InfoPanel, { variant: p.variant, css: { zIndex: 1 } },
|
|
3117
3096
|
p.message,
|
|
3118
|
-
react.jsx(Button, { block: true,
|
|
3097
|
+
react.jsx(Button, { block: true, css: {
|
|
3119
3098
|
color: 'inherit',
|
|
3120
3099
|
marginTop: '1rem'
|
|
3121
|
-
}
|
|
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
|
+
}
|
|
3122
3117
|
};
|
|
3123
3118
|
|
|
3124
3119
|
const CopyButton = (props) => {
|
|
@@ -3174,8 +3169,9 @@ const BoundStaticPager = (p) => {
|
|
|
3174
3169
|
const Slider = (p) => {
|
|
3175
3170
|
const theme = useThemeSafely();
|
|
3176
3171
|
const currentValue = React.useRef(p.value);
|
|
3172
|
+
const sliderContainer = React.useRef(null);
|
|
3177
3173
|
const height = p.showValue ? `calc(${theme.controls.height} + 1.5rem)` : theme.controls.height;
|
|
3178
|
-
return (react.jsx("div", { css: {
|
|
3174
|
+
return (react.jsx("div", { ref: sliderContainer, css: {
|
|
3179
3175
|
width: '100%',
|
|
3180
3176
|
height,
|
|
3181
3177
|
} },
|
|
@@ -3218,23 +3214,46 @@ const Slider = (p) => {
|
|
|
3218
3214
|
'&:hover': {
|
|
3219
3215
|
filter: theme.controls.hoverBrightness
|
|
3220
3216
|
}
|
|
3221
|
-
} }, 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 }))));
|
|
3222
3218
|
} })));
|
|
3223
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
|
+
};
|
|
3224
3229
|
const HandleText = (p) => {
|
|
3225
|
-
var _a, _b, _c
|
|
3230
|
+
var _a, _b, _c;
|
|
3226
3231
|
const theme = useThemeSafely();
|
|
3227
|
-
const
|
|
3228
|
-
const
|
|
3229
|
-
const
|
|
3230
|
-
|
|
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
|
+
});
|
|
3231
3249
|
return (react.jsx(Text, { ellipsis: true, css: {
|
|
3232
3250
|
width: renderValueWidth,
|
|
3233
3251
|
left: renderValueLeft,
|
|
3234
|
-
|
|
3252
|
+
top: flipText ? undefined : theme.controls.height,
|
|
3253
|
+
bottom: flipText ? theme.controls.height : undefined,
|
|
3235
3254
|
position: 'absolute',
|
|
3236
3255
|
overflow: 'hidden',
|
|
3237
|
-
}, tag: "div", align: "center" }, displayValue));
|
|
3256
|
+
}, className: "slider-handle", tag: "div", align: "center" }, displayValue));
|
|
3238
3257
|
};
|
|
3239
3258
|
|
|
3240
3259
|
/** @jsx jsx */
|
|
@@ -3366,7 +3385,6 @@ exports.CopyButton = CopyButton;
|
|
|
3366
3385
|
exports.DatePicker = DatePicker;
|
|
3367
3386
|
exports.Divider = Divider;
|
|
3368
3387
|
exports.ErrorModal = ErrorModal;
|
|
3369
|
-
exports.FilePicker = FilePicker;
|
|
3370
3388
|
exports.FileUploader = FileUploader;
|
|
3371
3389
|
exports.Form = Form;
|
|
3372
3390
|
exports.FormColumnRow = FormColumnRow;
|