@mackin.com/styleguide 6.0.1 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +13 -26
- package/index.js +365 -352
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -262,29 +262,11 @@ declare const ErrorModal: (props: {
|
|
|
262
262
|
|
|
263
263
|
/** @jsx jsx */
|
|
264
264
|
|
|
265
|
-
interface FilePickerProps {
|
|
266
|
-
maxBytes?: number;
|
|
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
265
|
interface IProps extends React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> {
|
|
284
266
|
inline?: boolean;
|
|
285
267
|
}
|
|
286
268
|
/** 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:
|
|
269
|
+
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<unknown>>;
|
|
288
270
|
declare const FormFlexRow: (props: {
|
|
289
271
|
children: React.ReactNode;
|
|
290
272
|
className?: string;
|
|
@@ -374,9 +356,10 @@ declare const InfoTip: (props: InfoTipProps) => jsx.JSX.Element;
|
|
|
374
356
|
/** @jsx jsx */
|
|
375
357
|
|
|
376
358
|
declare type InputValue = string | number | undefined;
|
|
377
|
-
declare type InputType = 'text' | 'number' | 'textarea' | 'date' | 'password';
|
|
359
|
+
declare type InputType = 'text' | 'number' | 'textarea' | 'date' | 'password' | 'url' | 'email';
|
|
378
360
|
interface InputProps {
|
|
379
361
|
type: InputType;
|
|
362
|
+
name?: string;
|
|
380
363
|
style?: React.CSSProperties;
|
|
381
364
|
value?: InputValue;
|
|
382
365
|
rounded?: boolean;
|
|
@@ -392,7 +375,7 @@ interface InputProps {
|
|
|
392
375
|
/** Defaults to 'off'. */
|
|
393
376
|
autoComplete?: string;
|
|
394
377
|
/** Called with debounce when the input changes. */
|
|
395
|
-
onChange?: (value: InputValue) => void;
|
|
378
|
+
onChange?: (value: InputValue, name?: string) => void;
|
|
396
379
|
onFocus?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
397
380
|
onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
398
381
|
/** Defaults to 100. Ignored for type=number and type=date. */
|
|
@@ -407,8 +390,9 @@ interface InputProps {
|
|
|
407
390
|
max?: number;
|
|
408
391
|
/** Only used for type=textarea. Defaults to 10. */
|
|
409
392
|
rows?: number;
|
|
393
|
+
pattern?: string;
|
|
410
394
|
}
|
|
411
|
-
declare const Input:
|
|
395
|
+
declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<any>>;
|
|
412
396
|
|
|
413
397
|
/** @jsx jsx */
|
|
414
398
|
|
|
@@ -816,7 +800,7 @@ declare const TabLocker: (props: {
|
|
|
816
800
|
|
|
817
801
|
/** @jsx jsx */
|
|
818
802
|
|
|
819
|
-
interface FileUploaderProps
|
|
803
|
+
interface FileUploaderProps {
|
|
820
804
|
onUpload: (files: FileList) => Promise<void>;
|
|
821
805
|
/** Defaults to 'Upload'. */
|
|
822
806
|
buttonText?: string;
|
|
@@ -828,8 +812,9 @@ interface FileUploaderProps extends FilePickerProps {
|
|
|
828
812
|
buttonWidth?: string;
|
|
829
813
|
/** Defaults to 'primary'. */
|
|
830
814
|
buttonVariant?: ButtonVariant;
|
|
831
|
-
|
|
832
|
-
|
|
815
|
+
maxBytes?: number;
|
|
816
|
+
multiple?: boolean;
|
|
817
|
+
accept?: string;
|
|
833
818
|
}
|
|
834
819
|
declare const FileUploader: (p: FileUploaderProps) => jsx.JSX.Element;
|
|
835
820
|
|
|
@@ -939,6 +924,8 @@ interface SliderProps<T extends SliderValue> {
|
|
|
939
924
|
onUpdate?: (value: T) => void;
|
|
940
925
|
/** Used with showValue. Will be called to render the display string. */
|
|
941
926
|
renderValue?: (value: number) => string;
|
|
927
|
+
/** Used with renderValue for the custom element width. Defaults to theme.controls.height * 2. */
|
|
928
|
+
renderValueWidth?: string;
|
|
942
929
|
}
|
|
943
930
|
declare const Slider: <T extends SliderValue>(p: SliderProps<T>) => jsx.JSX.Element;
|
|
944
931
|
|
|
@@ -972,4 +959,4 @@ declare const Backdrop: (p: {
|
|
|
972
959
|
|
|
973
960
|
declare const useMediaQuery: (query: string) => boolean;
|
|
974
961
|
|
|
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,
|
|
962
|
+
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,18 +1908,19 @@ const formatLocalValue = (value, type) => {
|
|
|
2066
1908
|
}
|
|
2067
1909
|
return newValue;
|
|
2068
1910
|
};
|
|
2069
|
-
const Input = (props) => {
|
|
2070
|
-
var _a, _b;
|
|
1911
|
+
const Input = React__namespace.forwardRef((props, ref) => {
|
|
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);
|
|
2078
|
-
}, debounceMs) :
|
|
1919
|
+
(_a = props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, value, name);
|
|
1920
|
+
}, debounceMs) : undefined,
|
|
2079
1921
|
focused: false
|
|
2080
1922
|
});
|
|
1923
|
+
const outerOnChange = (_c = vars.current.wrappedOnChange) !== null && _c !== void 0 ? _c : props.onChange;
|
|
2081
1924
|
const trySyncLocalValue = () => {
|
|
2082
1925
|
if (vars.current.focused) {
|
|
2083
1926
|
return;
|
|
@@ -2090,53 +1933,49 @@ const Input = (props) => {
|
|
|
2090
1933
|
};
|
|
2091
1934
|
React__namespace.useEffect(() => {
|
|
2092
1935
|
trySyncLocalValue();
|
|
2093
|
-
});
|
|
1936
|
+
}, [props.value]);
|
|
2094
1937
|
const theme = useThemeSafely();
|
|
2095
|
-
const inputStyles = react.css
|
|
2096
|
-
|
|
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
|
-
${props.rightControl && props.type !== 'textarea' && `
|
|
2137
|
-
padding-right: ${theme.controls.height};
|
|
2138
|
-
`}
|
|
2139
|
-
`;
|
|
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
|
+
});
|
|
2140
1979
|
let inputElement;
|
|
2141
1980
|
const onFocus = (e) => {
|
|
2142
1981
|
var _a;
|
|
@@ -2149,86 +1988,84 @@ const Input = (props) => {
|
|
|
2149
1988
|
trySyncLocalValue();
|
|
2150
1989
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
2151
1990
|
};
|
|
1991
|
+
let localOnChange;
|
|
2152
1992
|
if (props.type === 'number') {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
if (
|
|
2158
|
-
|
|
2159
|
-
if (props.min && numValue < props.min) {
|
|
2160
|
-
numValue = props.min;
|
|
2161
|
-
}
|
|
2162
|
-
if (props.max && numValue > props.max) {
|
|
2163
|
-
numValue = props.max;
|
|
2164
|
-
}
|
|
2165
|
-
setLocalValue(numValue);
|
|
2166
|
-
if (vars.current.wrappedOnChange) {
|
|
2167
|
-
vars.current.wrappedOnChange(numValue);
|
|
2168
|
-
}
|
|
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
|
-
if (vars.current.wrappedOnChange) {
|
|
2173
|
-
vars.current.wrappedOnChange(undefined);
|
|
2174
|
-
}
|
|
2000
|
+
if (props.max && numValue > props.max) {
|
|
2001
|
+
numValue = props.max;
|
|
2175
2002
|
}
|
|
2176
|
-
|
|
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
|
+
};
|
|
2177
2011
|
}
|
|
2178
2012
|
else if (props.type === 'date') {
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
}
|
|
2196
|
-
if (props.max && ms > props.max) {
|
|
2197
|
-
ms = props.max;
|
|
2198
|
-
}
|
|
2199
|
-
vars.current.wrappedOnChange(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;
|
|
2200
2029
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2030
|
+
if (props.max && ms > props.max) {
|
|
2031
|
+
ms = props.max;
|
|
2203
2032
|
}
|
|
2033
|
+
outerOnChange(ms, props.name);
|
|
2034
|
+
}
|
|
2035
|
+
else {
|
|
2036
|
+
outerOnChange(undefined, props.name);
|
|
2204
2037
|
}
|
|
2205
2038
|
}
|
|
2206
|
-
}
|
|
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 });
|
|
2207
2056
|
}
|
|
2208
2057
|
else if (props.type === 'textarea') {
|
|
2209
|
-
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 `
|
|
2210
2059
|
${inputStyles}
|
|
2211
2060
|
max-width: 100%;
|
|
2212
2061
|
min-height: ${theme.controls.height};
|
|
2213
2062
|
padding-top: 0.75rem;
|
|
2214
2063
|
height:auto;
|
|
2215
|
-
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange:
|
|
2216
|
-
const value = e.target.value;
|
|
2217
|
-
setLocalValue(value);
|
|
2218
|
-
if (vars.current.wrappedOnChange) {
|
|
2219
|
-
vars.current.wrappedOnChange(value);
|
|
2220
|
-
}
|
|
2221
|
-
} });
|
|
2064
|
+
`, className: props.inputClassName, placeholder: props.placeholder, value: localValue, onFocus: onFocus, onBlur: onBlur, onChange: localOnChange });
|
|
2222
2065
|
}
|
|
2223
2066
|
else {
|
|
2224
|
-
// text
|
|
2225
|
-
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:
|
|
2226
|
-
const value = e.target.value;
|
|
2227
|
-
setLocalValue(value);
|
|
2228
|
-
if (vars.current.wrappedOnChange) {
|
|
2229
|
-
vars.current.wrappedOnChange(value);
|
|
2230
|
-
}
|
|
2231
|
-
} });
|
|
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 });
|
|
2232
2069
|
}
|
|
2233
2070
|
const inputWrapperStyles = react.css `
|
|
2234
2071
|
width:100%;
|
|
@@ -2250,7 +2087,7 @@ const Input = (props) => {
|
|
|
2250
2087
|
return (react.jsx("div", { css: inputWrapperStyles, className: mergeClassNames('input', props.className) },
|
|
2251
2088
|
inputElement,
|
|
2252
2089
|
props.rightControl && props.type !== 'textarea' && react.jsx("div", { css: rightControlStyles }, props.rightControl)));
|
|
2253
|
-
};
|
|
2090
|
+
});
|
|
2254
2091
|
|
|
2255
2092
|
/** @jsx jsx */
|
|
2256
2093
|
const List = (props) => {
|
|
@@ -3066,65 +2903,217 @@ const GlobalStyles = (p) => {
|
|
|
3066
2903
|
}) }));
|
|
3067
2904
|
};
|
|
3068
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
|
+
|
|
3069
2956
|
/** @jsx jsx */
|
|
3070
2957
|
const DEFAULT_FAILURE_MESSAGE = 'Upload failed.';
|
|
2958
|
+
const hoverClass = css.css({
|
|
2959
|
+
backgroundColor: 'rgba(0,0,0,0.25) !important'
|
|
2960
|
+
});
|
|
3071
2961
|
const FileUploader = (p) => {
|
|
3072
|
-
var _a;
|
|
2962
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3073
2963
|
const [message, setMessage] = React.useState(undefined);
|
|
3074
2964
|
const [canUpload, setCanUpload] = React.useState(false);
|
|
3075
2965
|
const [uploading, setUploading] = React.useState(false);
|
|
3076
2966
|
const [files, setFiles] = React.useState(undefined);
|
|
3077
2967
|
const [fullFailureMessage, setFullFailureMessage] = React.useState(undefined);
|
|
3078
|
-
const
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
const
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
(
|
|
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));
|
|
3085
2990
|
setMessage(undefined);
|
|
2991
|
+
setFullFailureMessage(undefined);
|
|
3086
2992
|
};
|
|
3087
|
-
|
|
2993
|
+
const createFileList = (rawFiles) => {
|
|
2994
|
+
return new FileListPlus(rawFiles, {
|
|
2995
|
+
accept: p.accept,
|
|
2996
|
+
multiple: p.multiple,
|
|
2997
|
+
maxBytes: p.maxBytes
|
|
2998
|
+
});
|
|
2999
|
+
};
|
|
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 => {
|
|
3088
3026
|
if (!files) {
|
|
3089
3027
|
return;
|
|
3090
3028
|
}
|
|
3091
3029
|
setUploading(true);
|
|
3092
|
-
p.onUpload(files).then(() => {
|
|
3030
|
+
p.onUpload(files.raw).then(() => {
|
|
3093
3031
|
setMessage('success');
|
|
3094
|
-
|
|
3095
|
-
clearFilePickerHandler.current();
|
|
3096
|
-
}
|
|
3032
|
+
setAllFiles(undefined);
|
|
3097
3033
|
}).catch(err => {
|
|
3034
|
+
var _a;
|
|
3098
3035
|
setMessage('failure');
|
|
3099
|
-
setFullFailureMessage(`${failureMessage !== null &&
|
|
3036
|
+
setFullFailureMessage(`${(_a = p.failureMessage) !== null && _a !== void 0 ? _a : DEFAULT_FAILURE_MESSAGE} Error: ${err instanceof Error ? err.message : err}`);
|
|
3100
3037
|
}).finally(() => {
|
|
3101
3038
|
setUploading(false);
|
|
3102
3039
|
setCanUpload(false);
|
|
3103
3040
|
});
|
|
3104
3041
|
} },
|
|
3105
|
-
react.jsx(
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
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);
|
|
3112
3058
|
}
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
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) }))));
|
|
3119
3093
|
};
|
|
3120
3094
|
const UploadInfoPanel = (p) => {
|
|
3121
|
-
|
|
3122
|
-
return (react.jsx(InfoPanel, { variant: p.variant },
|
|
3095
|
+
return (react.jsx(InfoPanel, { variant: p.variant, css: { zIndex: 1 } },
|
|
3123
3096
|
p.message,
|
|
3124
|
-
react.jsx(Button, { block: true,
|
|
3097
|
+
react.jsx(Button, { block: true, css: {
|
|
3125
3098
|
color: 'inherit',
|
|
3126
3099
|
marginTop: '1rem'
|
|
3127
|
-
}
|
|
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
|
+
}
|
|
3128
3117
|
};
|
|
3129
3118
|
|
|
3130
3119
|
const CopyButton = (props) => {
|
|
@@ -3180,8 +3169,9 @@ const BoundStaticPager = (p) => {
|
|
|
3180
3169
|
const Slider = (p) => {
|
|
3181
3170
|
const theme = useThemeSafely();
|
|
3182
3171
|
const currentValue = React.useRef(p.value);
|
|
3172
|
+
const sliderContainer = React.useRef(null);
|
|
3183
3173
|
const height = p.showValue ? `calc(${theme.controls.height} + 1.5rem)` : theme.controls.height;
|
|
3184
|
-
return (react.jsx("div", { css: {
|
|
3174
|
+
return (react.jsx("div", { ref: sliderContainer, css: {
|
|
3185
3175
|
width: '100%',
|
|
3186
3176
|
height,
|
|
3187
3177
|
} },
|
|
@@ -3224,22 +3214,46 @@ const Slider = (p) => {
|
|
|
3224
3214
|
'&:hover': {
|
|
3225
3215
|
filter: theme.controls.hoverBrightness
|
|
3226
3216
|
}
|
|
3227
|
-
} }, 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 }))));
|
|
3228
3218
|
} })));
|
|
3229
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
|
+
};
|
|
3230
3229
|
const HandleText = (p) => {
|
|
3231
3230
|
var _a, _b, _c;
|
|
3232
3231
|
const theme = useThemeSafely();
|
|
3233
|
-
const
|
|
3234
|
-
const
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
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,
|
|
3240
3254
|
position: 'absolute',
|
|
3241
|
-
overflow: 'hidden'
|
|
3242
|
-
}, tag: "div", align: "center" }, displayValue));
|
|
3255
|
+
overflow: 'hidden',
|
|
3256
|
+
}, className: "slider-handle", tag: "div", align: "center" }, displayValue));
|
|
3243
3257
|
};
|
|
3244
3258
|
|
|
3245
3259
|
/** @jsx jsx */
|
|
@@ -3371,7 +3385,6 @@ exports.CopyButton = CopyButton;
|
|
|
3371
3385
|
exports.DatePicker = DatePicker;
|
|
3372
3386
|
exports.Divider = Divider;
|
|
3373
3387
|
exports.ErrorModal = ErrorModal;
|
|
3374
|
-
exports.FilePicker = FilePicker;
|
|
3375
3388
|
exports.FileUploader = FileUploader;
|
|
3376
3389
|
exports.Form = Form;
|
|
3377
3390
|
exports.FormColumnRow = FormColumnRow;
|