@uppy/dashboard
Advanced tools
Comparing version 2.2.0 to 2.3.0
# @uppy/dashboard | ||
## 2.3.0 | ||
Released: 2022-05-30 | ||
Included in: Uppy v2.11.0 | ||
- @uppy/angular,@uppy/audio,@uppy/aws-s3-multipart,@uppy/aws-s3,@uppy/box,@uppy/core,@uppy/dashboard,@uppy/drag-drop,@uppy/dropbox,@uppy/facebook,@uppy/file-input,@uppy/form,@uppy/golden-retriever,@uppy/google-drive,@uppy/image-editor,@uppy/informer,@uppy/instagram,@uppy/onedrive,@uppy/progress-bar,@uppy/react,@uppy/redux-dev-tools,@uppy/robodog,@uppy/screen-capture,@uppy/status-bar,@uppy/store-default,@uppy/store-redux,@uppy/thumbnail-generator,@uppy/transloadit,@uppy/tus,@uppy/unsplash,@uppy/url,@uppy/vue,@uppy/webcam,@uppy/xhr-upload,@uppy/zoom: doc: update bundler recommendation (Antoine du Hamel / #3763) | ||
- @uppy/dashboard: refactor to ESM (Antoine du Hamel / #3701) | ||
- @uppy/dashboard: use webkitRelativePath when querying a file's relative path (Eduard Müller / taktik / #3766) | ||
## 2.1.4 | ||
@@ -4,0 +13,0 @@ |
@@ -0,11 +1,10 @@ | ||
"use strict"; | ||
var _preact = require("preact"); | ||
let _Symbol$for; | ||
const { | ||
h, | ||
Component | ||
} = require('preact'); | ||
_Symbol$for = Symbol.for('uppy test: disable unused locale key warning'); | ||
class AddFiles extends Component { | ||
class AddFiles extends _preact.Component { | ||
constructor() { | ||
@@ -30,7 +29,7 @@ super(...arguments); | ||
event.target.value = null; | ||
event.target.value = null; // eslint-disable-line no-param-reassign | ||
}; | ||
this.renderHiddenInput = (isFolder, refCallback) => { | ||
return h("input", { | ||
return (0, _preact.h)("input", { | ||
className: "uppy-Dashboard-input", | ||
@@ -51,7 +50,7 @@ hidden: true, | ||
this.renderMyDeviceAcquirer = () => { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-DashboardTab", | ||
role: "presentation", | ||
"data-uppy-acquirer-id": "MyDevice" | ||
}, h("button", { | ||
}, (0, _preact.h)("button", { | ||
type: "button", | ||
@@ -63,3 +62,3 @@ className: "uppy-u-reset uppy-c-btn uppy-DashboardTab-btn", | ||
onClick: this.triggerFileInputClick | ||
}, h("svg", { | ||
}, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -70,6 +69,6 @@ focusable: "false", | ||
viewBox: "0 0 32 32" | ||
}, h("g", { | ||
}, (0, _preact.h)("g", { | ||
fill: "none", | ||
fillRule: "evenodd" | ||
}, h("rect", { | ||
}, (0, _preact.h)("rect", { | ||
className: "uppy-ProviderIconBg", | ||
@@ -80,6 +79,6 @@ width: "32", | ||
fill: "#2275D7" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
d: "M21.973 21.152H9.863l-1.108-5.087h14.464l-1.246 5.087zM9.935 11.37h3.958l.886 1.444a.673.673 0 0 0 .585.316h6.506v1.37H9.935v-3.13zm14.898 3.44a.793.793 0 0 0-.616-.31h-.978v-2.126c0-.379-.275-.613-.653-.613H15.75l-.886-1.445a.673.673 0 0 0-.585-.316H9.232c-.378 0-.667.209-.667.587V14.5h-.782a.793.793 0 0 0-.61.303.795.795 0 0 0-.155.663l1.45 6.633c.078.36.396.618.764.618h13.354c.36 0 .674-.246.76-.595l1.631-6.636a.795.795 0 0 0-.144-.675z", | ||
fill: "#FFF" | ||
}))), h("div", { | ||
}))), (0, _preact.h)("div", { | ||
className: "uppy-DashboardTab-name" | ||
@@ -91,3 +90,3 @@ }, this.props.i18n('myDevice')))); | ||
const numberOfAcquirers = this.props.acquirers.length; | ||
return h("button", { | ||
return (0, _preact.h)("button", { | ||
type: "button", | ||
@@ -108,3 +107,3 @@ className: "uppy-u-reset uppy-Dashboard-browse", | ||
const camelFMSelectionType = lowerFMSelectionType.charAt(0).toUpperCase() + lowerFMSelectionType.slice(1); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
class: "uppy-Dashboard-AddFiles-title" | ||
@@ -124,7 +123,7 @@ }, // eslint-disable-next-line no-nested-ternary | ||
this.renderAcquirer = acquirer => { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-DashboardTab", | ||
role: "presentation", | ||
"data-uppy-acquirer-id": acquirer.id | ||
}, h("button", { | ||
}, (0, _preact.h)("button", { | ||
type: "button", | ||
@@ -139,3 +138,3 @@ className: "uppy-u-reset uppy-c-btn uppy-DashboardTab-btn", | ||
onClick: () => this.props.showPanel(acquirer.id) | ||
}, acquirer.icon(), h("div", { | ||
}, acquirer.icon(), (0, _preact.h)("div", { | ||
className: "uppy-DashboardTab-name" | ||
@@ -150,6 +149,6 @@ }, acquirer.name))); | ||
const lastTwoAcquirers = acquirersWithoutLastTwo.splice(acquirers.length - 2, acquirers.length); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-AddFiles-list", | ||
role: "tablist" | ||
}, !disableLocalFiles && this.renderMyDeviceAcquirer(), acquirersWithoutLastTwo.map(acquirer => this.renderAcquirer(acquirer)), h("span", { | ||
}, !disableLocalFiles && this.renderMyDeviceAcquirer(), acquirersWithoutLastTwo.map(acquirer => this.renderAcquirer(acquirer)), (0, _preact.h)("span", { | ||
role: "presentation", | ||
@@ -177,3 +176,3 @@ style: { | ||
} = this.props; | ||
const uppyBranding = h("span", null, h("svg", { | ||
const uppyBranding = (0, _preact.h)("span", null, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -185,6 +184,6 @@ focusable: "false", | ||
viewBox: "0 0 11 11" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M7.365 10.5l-.01-4.045h2.612L5.5.806l-4.467 5.65h2.604l.01 4.044h3.718z", | ||
fillRule: "evenodd" | ||
})), h("span", { | ||
})), (0, _preact.h)("span", { | ||
className: "uppy-Dashboard-poweredByUppy" | ||
@@ -195,3 +194,3 @@ }, "Uppy")); | ||
}); | ||
return h("a", { | ||
return (0, _preact.h)("a", { | ||
tabIndex: "-1", | ||
@@ -206,3 +205,3 @@ href: "https://uppy.io", | ||
render() { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-AddFiles" | ||
@@ -213,5 +212,5 @@ }, this.renderHiddenInput(false, ref => { | ||
this.folderInput = ref; | ||
}), this.renderDropPasteBrowseTagline(), this.props.acquirers.length > 0 && this.renderAcquirers(this.props.acquirers, this.props.disableLocalFiles), h("div", { | ||
}), this.renderDropPasteBrowseTagline(), this.props.acquirers.length > 0 && this.renderAcquirers(this.props.acquirers, this.props.disableLocalFiles), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-AddFiles-info" | ||
}, this.props.note && h("div", { | ||
}, this.props.note && (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-note" | ||
@@ -218,0 +217,0 @@ }, this.props.note), this.props.proudlyDisplayPoweredByUppy && this.renderPoweredByUppy(this.props))); |
@@ -1,27 +0,27 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const AddFiles = require('./AddFiles'); | ||
const classNames = require("classnames"); | ||
const AddFiles = require("./AddFiles.js"); | ||
const AddFilesPanel = props => { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: classNames('uppy-Dashboard-AddFilesPanel', props.className), | ||
"data-uppy-panelType": "AddFiles", | ||
"aria-hidden": props.showAddFilesPanel | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-bar" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-title", | ||
role: "heading", | ||
"aria-level": "1" | ||
}, props.i18n('addingMoreFiles')), h("button", { | ||
}, props.i18n('addingMoreFiles')), (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-back", | ||
type: "button", | ||
onClick: () => props.toggleAddFilesPanel(false) | ||
}, props.i18n('back'))), h(AddFiles, props)); | ||
}, props.i18n('back'))), (0, _preact.h)(AddFiles, props)); | ||
}; | ||
module.exports = AddFilesPanel; |
@@ -0,26 +1,26 @@ | ||
"use strict"; | ||
var _preact = require("preact"); | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
const { | ||
h | ||
} = require('preact'); | ||
const classNames = require("classnames"); | ||
const classNames = require('classnames'); | ||
const isDragDropSupported = require("@uppy/utils/lib/isDragDropSupported"); | ||
const isDragDropSupported = require('@uppy/utils/lib/isDragDropSupported'); | ||
const FileList = require("./FileList.js"); | ||
const FileList = require('./FileList'); | ||
const AddFiles = require("./AddFiles.js"); | ||
const AddFiles = require('./AddFiles'); | ||
const AddFilesPanel = require("./AddFilesPanel.js"); | ||
const AddFilesPanel = require('./AddFilesPanel'); | ||
const PickerPanelContent = require("./PickerPanelContent.js"); | ||
const PickerPanelContent = require('./PickerPanelContent'); | ||
const EditorPanel = require("./EditorPanel.js"); | ||
const EditorPanel = require('./EditorPanel'); | ||
const PanelTopBar = require("./PickerPanelTopBar.js"); | ||
const PanelTopBar = require('./PickerPanelTopBar'); | ||
const FileCard = require("./FileCard/index.js"); | ||
const FileCard = require('./FileCard'); | ||
const Slide = require('./Slide'); // http://dev.edenspiekermann.com/2016/02/11/introducing-accessible-modal-dialog | ||
const Slide = require("./Slide.js"); // http://dev.edenspiekermann.com/2016/02/11/introducing-accessible-modal-dialog | ||
// https://github.com/ghosh/micromodal | ||
@@ -34,3 +34,3 @@ | ||
module.exports = function Dashboard(props) { | ||
function Dashboard(props) { | ||
const noFiles = props.totalFileCount === 0; | ||
@@ -77,3 +77,3 @@ const isSizeMD = props.containerWidth > WIDTH_MD; | ||
const dashboard = h("div", { | ||
const dashboard = (0, _preact.h)("div", { | ||
className: dashboardClassName, | ||
@@ -90,3 +90,3 @@ "data-uppy-theme": props.theme, | ||
onDrop: props.handleDrop | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
"aria-hidden": "true", | ||
@@ -96,3 +96,3 @@ className: "uppy-Dashboard-overlay", | ||
onClick: props.handleClickOutside | ||
}), h("div", { | ||
}), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-inner", | ||
@@ -105,3 +105,3 @@ "aria-modal": !props.inline && 'true', | ||
} | ||
}, !props.inline ? h("button", { | ||
}, !props.inline ? (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-close", | ||
@@ -112,11 +112,11 @@ type: "button", | ||
onClick: props.closeModal | ||
}, h("span", { | ||
}, (0, _preact.h)("span", { | ||
"aria-hidden": "true" | ||
}, "\xD7")) : null, h("div", { | ||
}, "\xD7")) : null, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-innerWrap" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-dropFilesHereHint" | ||
}, props.i18n('dropHint')), showFileList && h(PanelTopBar, props), numberOfFilesForRecovery && h("div", { | ||
}, props.i18n('dropHint')), showFileList && (0, _preact.h)(PanelTopBar, props), numberOfFilesForRecovery && (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-serviceMsg" | ||
}, h("svg", { | ||
}, (0, _preact.h)("svg", { | ||
className: "uppy-Dashboard-serviceMsg-icon", | ||
@@ -128,13 +128,13 @@ "aria-hidden": "true", | ||
viewBox: "0 0 24 19" | ||
}, h("g", { | ||
}, (0, _preact.h)("g", { | ||
transform: "translate(0 -1)", | ||
fill: "none", | ||
fillRule: "evenodd" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M12.857 1.43l10.234 17.056A1 1 0 0122.234 20H1.766a1 1 0 01-.857-1.514L11.143 1.429a1 1 0 011.714 0z", | ||
fill: "#FFD300" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
fill: "#000", | ||
d: "M11 6h2l-.3 8h-1.4z" | ||
}), h("circle", { | ||
}), (0, _preact.h)("circle", { | ||
fill: "#000", | ||
@@ -144,21 +144,23 @@ cx: "12", | ||
r: "1" | ||
}))), h("strong", { | ||
}))), (0, _preact.h)("strong", { | ||
className: "uppy-Dashboard-serviceMsg-title" | ||
}, props.i18n('sessionRestored')), h("div", { | ||
}, props.i18n('sessionRestored')), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-serviceMsg-text" | ||
}, renderRestoredText())), showFileList ? h(FileList, _extends({}, props, { | ||
}, renderRestoredText())), showFileList ? (0, _preact.h)(FileList // eslint-disable-next-line react/jsx-props-no-spreading | ||
, _extends({}, props, { | ||
itemsPerRow: itemsPerRow | ||
})) : h(AddFiles, _extends({}, props, { | ||
})) : // eslint-disable-next-line react/jsx-props-no-spreading | ||
(0, _preact.h)(AddFiles, _extends({}, props, { | ||
isSizeMD: isSizeMD | ||
})), h(Slide, null, props.showAddFilesPanel ? h(AddFilesPanel, _extends({ | ||
})), (0, _preact.h)(Slide, null, props.showAddFilesPanel ? (0, _preact.h)(AddFilesPanel, _extends({ | ||
key: "AddFiles" | ||
}, props, { | ||
isSizeMD: isSizeMD | ||
})) : null), h(Slide, null, props.fileCardFor ? h(FileCard, _extends({ | ||
})) : null), (0, _preact.h)(Slide, null, props.fileCardFor ? (0, _preact.h)(FileCard, _extends({ | ||
key: "FileCard" | ||
}, props)) : null), h(Slide, null, props.activePickerPanel ? h(PickerPanelContent, _extends({ | ||
}, props)) : null), (0, _preact.h)(Slide, null, props.activePickerPanel ? (0, _preact.h)(PickerPanelContent, _extends({ | ||
key: "Picker" | ||
}, props)) : null), h(Slide, null, props.showFileEditor ? h(EditorPanel, _extends({ | ||
}, props)) : null), (0, _preact.h)(Slide, null, props.showFileEditor ? (0, _preact.h)(EditorPanel, _extends({ | ||
key: "Editor" | ||
}, props)) : null), h("div", { | ||
}, props)) : null), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-progressindicators" | ||
@@ -169,2 +171,4 @@ }, props.progressindicators.map(target => { | ||
return dashboard; | ||
}; | ||
} | ||
module.exports = Dashboard; |
@@ -1,10 +0,10 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const classNames = require("classnames"); | ||
function EditorPanel(props) { | ||
const file = props.files[props.fileCardFor]; | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: classNames('uppy-DashboardContent-panel', props.className), | ||
@@ -14,5 +14,5 @@ role: "tabpanel", | ||
id: "uppy-DashboardContent-panel--editor" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-bar" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-title", | ||
@@ -22,14 +22,14 @@ role: "heading", | ||
}, props.i18nArray('editing', { | ||
file: h("span", { | ||
file: (0, _preact.h)("span", { | ||
className: "uppy-DashboardContent-titleFile" | ||
}, file.meta ? file.meta.name : file.name) | ||
})), h("button", { | ||
})), (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-back", | ||
type: "button", | ||
onClick: props.hideAllPanels | ||
}, props.i18n('cancel')), h("button", { | ||
}, props.i18n('cancel')), (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-save", | ||
type: "button", | ||
onClick: props.saveFileEditor | ||
}, props.i18n('save'))), h("div", { | ||
}, props.i18n('save'))), (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-panelBody" | ||
@@ -36,0 +36,0 @@ }, props.editors.map(target => { |
@@ -1,19 +0,16 @@ | ||
const { | ||
h, | ||
Component | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const { | ||
nanoid | ||
} = require('nanoid/non-secure'); | ||
var _nonSecure = require("nanoid/non-secure"); | ||
const getFileTypeIcon = require('../../utils/getFileTypeIcon'); | ||
const classNames = require("classnames"); | ||
const ignoreEvent = require('../../utils/ignoreEvent.js'); | ||
const getFileTypeIcon = require("../../utils/getFileTypeIcon.js"); | ||
const FilePreview = require('../FilePreview'); | ||
const ignoreEvent = require("../../utils/ignoreEvent.js"); | ||
class FileCard extends Component { | ||
const FilePreview = require("../FilePreview.js"); | ||
class FileCard extends _preact.Component { | ||
constructor(props) { | ||
@@ -63,6 +60,6 @@ super(props); | ||
const required = this.props.requiredMetaFields.includes(field.id); | ||
return h("fieldset", { | ||
return (0, _preact.h)("fieldset", { | ||
key: field.id, | ||
className: "uppy-Dashboard-FileCard-fieldset" | ||
}, h("label", { | ||
}, (0, _preact.h)("label", { | ||
className: "uppy-Dashboard-FileCard-label", | ||
@@ -76,3 +73,3 @@ htmlFor: id | ||
form: this.form.id | ||
}, h) : h("input", { | ||
}, _preact.h) : (0, _preact.h)("input", { | ||
className: fieldCSSClasses.text, | ||
@@ -109,3 +106,3 @@ id: id, | ||
}; | ||
this.form.id = nanoid(); | ||
this.form.id = (0, _nonSecure.nanoid)(); | ||
} // TODO(aduh95): move this to `UNSAFE_componentWillMount` when updating to Preact X+. | ||
@@ -132,3 +129,3 @@ | ||
const showEditButton = this.props.canEditFile(file); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: classNames('uppy-Dashboard-FileCard', this.props.className), | ||
@@ -140,5 +137,5 @@ "data-uppy-panelType": "FileCard", | ||
onPaste: ignoreEvent | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-bar" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-title", | ||
@@ -148,6 +145,6 @@ role: "heading", | ||
}, this.props.i18nArray('editing', { | ||
file: h("span", { | ||
file: (0, _preact.h)("span", { | ||
className: "uppy-DashboardContent-titleFile" | ||
}, file.meta ? file.meta.name : file.name) | ||
})), h("button", { | ||
})), (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-back", | ||
@@ -158,5 +155,5 @@ type: "button", | ||
onClick: this.handleCancel | ||
}, this.props.i18n('cancel'))), h("div", { | ||
}, this.props.i18n('cancel'))), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-FileCard-inner" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-FileCard-preview", | ||
@@ -166,5 +163,5 @@ style: { | ||
} | ||
}, h(FilePreview, { | ||
}, (0, _preact.h)(FilePreview, { | ||
file: file | ||
}), showEditButton && h("button", { | ||
}), showEditButton && (0, _preact.h)("button", { | ||
type: "button", | ||
@@ -181,7 +178,7 @@ className: "uppy-u-reset uppy-c-btn uppy-Dashboard-FileCard-edit", | ||
form: this.form.id | ||
}, this.props.i18n('editFile'))), h("div", { | ||
}, this.props.i18n('editFile'))), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-FileCard-info" | ||
}, this.renderMetaFields()), h("div", { | ||
}, this.renderMetaFields()), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-FileCard-actions" | ||
}, h("button", { | ||
}, (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-c-btn uppy-c-btn-primary uppy-Dashboard-FileCard-actionsBtn" // If `form` attribute is supported, we want a submit button to trigger the form validation. | ||
@@ -193,3 +190,3 @@ // Otherwise, fallback to a classic button with a onClick event handler. | ||
form: this.form.id | ||
}, this.props.i18n('saveChanges')), h("button", { | ||
}, this.props.i18n('saveChanges')), (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-c-btn uppy-c-btn-link uppy-Dashboard-FileCard-actionsBtn", | ||
@@ -196,0 +193,0 @@ type: "button", |
@@ -1,7 +0,7 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const copyToClipboard = require('../../../utils/copyToClipboard'); | ||
var _preact = require("preact"); | ||
const copyToClipboard = require("../../../utils/copyToClipboard.js"); | ||
function EditButton(_ref) { | ||
@@ -18,3 +18,3 @@ let { | ||
if (!uploadInProgressOrComplete && metaFields && metaFields.length > 0 || !uploadInProgressOrComplete && canEditFile(file)) { | ||
return h("button", { | ||
return (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-Item-action uppy-Dashboard-Item-action--edit", | ||
@@ -29,3 +29,3 @@ type: "button", | ||
onClick: () => onClick() | ||
}, h("svg", { | ||
}, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -37,8 +37,8 @@ focusable: "false", | ||
viewBox: "0 0 14 14" | ||
}, h("g", { | ||
}, (0, _preact.h)("g", { | ||
fillRule: "evenodd" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M1.5 10.793h2.793A1 1 0 0 0 5 10.5L11.5 4a1 1 0 0 0 0-1.414L9.707.793a1 1 0 0 0-1.414 0l-6.5 6.5A1 1 0 0 0 1.5 8v2.793zm1-1V8L9 1.5l1.793 1.793-6.5 6.5H2.5z", | ||
fillRule: "nonzero" | ||
}), h("rect", { | ||
}), (0, _preact.h)("rect", { | ||
x: "1", | ||
@@ -49,3 +49,3 @@ y: "12.293", | ||
rx: ".5" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
fillRule: "nonzero", | ||
@@ -65,3 +65,3 @@ d: "M6.793 2.5L9.5 5.207l.707-.707L7.5 1.793z" | ||
} = _ref2; | ||
return h("button", { | ||
return (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-Item-action uppy-Dashboard-Item-action--remove", | ||
@@ -76,3 +76,3 @@ type: "button", | ||
onClick: () => onClick() | ||
}, h("svg", { | ||
}, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -84,5 +84,5 @@ focusable: "false", | ||
viewBox: "0 0 18 18" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M9 0C4.034 0 0 4.034 0 9s4.034 9 9 9 9-4.034 9-9-4.034-9-9-9z" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
fill: "#FFF", | ||
@@ -107,3 +107,3 @@ d: "M13 12.222l-.778.778L9 9.778 5.778 13 5 12.222 8.222 9 5 5.778 5.778 5 9 8.222 12.222 5l.778.778L9.778 9z" | ||
} = props; | ||
return h("button", { | ||
return (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-Item-action uppy-Dashboard-Item-action--copyLink", | ||
@@ -114,3 +114,3 @@ type: "button", | ||
onClick: event => copyLinkToClipboard(event, props) | ||
}, h("svg", { | ||
}, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -122,3 +122,3 @@ focusable: "false", | ||
viewBox: "0 0 14 12" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M7.94 7.703a2.613 2.613 0 0 1-.626 2.681l-.852.851a2.597 2.597 0 0 1-1.849.766A2.616 2.616 0 0 1 2.764 7.54l.852-.852a2.596 2.596 0 0 1 2.69-.625L5.267 7.099a1.44 1.44 0 0 0-.833.407l-.852.851a1.458 1.458 0 0 0 1.03 2.486c.39 0 .755-.152 1.03-.426l.852-.852c.231-.231.363-.522.406-.824l1.04-1.038zm4.295-5.937A2.596 2.596 0 0 0 10.387 1c-.698 0-1.355.272-1.849.766l-.852.851a2.614 2.614 0 0 0-.624 2.688l1.036-1.036c.041-.304.173-.6.407-.833l.852-.852c.275-.275.64-.426 1.03-.426a1.458 1.458 0 0 1 1.03 2.486l-.852.851a1.442 1.442 0 0 1-.824.406l-1.04 1.04a2.596 2.596 0 0 0 2.683-.628l.851-.85a2.616 2.616 0 0 0 0-3.697zm-6.88 6.883a.577.577 0 0 0 .82 0l3.474-3.474a.579.579 0 1 0-.819-.82L5.355 7.83a.579.579 0 0 0 0 .819z" | ||
@@ -128,3 +128,3 @@ }))); | ||
module.exports = function Buttons(props) { | ||
function Buttons(props) { | ||
const { | ||
@@ -151,5 +151,5 @@ uppy, | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-actionWrapper" | ||
}, h(EditButton, { | ||
}, (0, _preact.h)(EditButton, { | ||
i18n: i18n, | ||
@@ -161,7 +161,7 @@ file: file, | ||
onClick: editAction | ||
}), showLinkToFileUploadResult && file.uploadURL ? h(CopyLinkButton, { | ||
}), showLinkToFileUploadResult && file.uploadURL ? (0, _preact.h)(CopyLinkButton, { | ||
file: file, | ||
uppy: uppy, | ||
i18n: i18n | ||
}) : null, showRemoveButton ? h(RemoveButton, { | ||
}) : null, showRemoveButton ? (0, _preact.h)(RemoveButton, { | ||
i18n: i18n, | ||
@@ -172,2 +172,4 @@ file: file, | ||
}) : null); | ||
}; | ||
} | ||
module.exports = Buttons; |
@@ -1,12 +0,11 @@ | ||
const { | ||
h, | ||
Fragment | ||
} = require('preact'); | ||
"use strict"; | ||
const prettierBytes = require('@transloadit/prettier-bytes'); | ||
var _preact = require("preact"); | ||
const truncateString = require('@uppy/utils/lib/truncateString'); | ||
const prettierBytes = require("@transloadit/prettier-bytes"); | ||
const MetaErrorMessage = require('../MetaErrorMessage'); | ||
const truncateString = require("@uppy/utils/lib/truncateString"); | ||
const MetaErrorMessage = require("../MetaErrorMessage.js"); | ||
const renderFileName = props => { | ||
@@ -33,3 +32,3 @@ const { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-name", | ||
@@ -53,16 +52,16 @@ title: name | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-author" | ||
}, h("a", { | ||
}, (0, _preact.h)("a", { | ||
href: `${author.url}?utm_source=Companion&utm_medium=referral`, | ||
target: "_blank", | ||
rel: "noopener noreferrer" | ||
}, truncateString(author.name, 13)), providerName ? h(Fragment, null, ` ${dot} `, providerName, ` ${dot} `) : null); | ||
}, truncateString(author.name, 13)), providerName ? (0, _preact.h)(_preact.Fragment, null, ` ${dot} `, providerName, ` ${dot} `) : null); | ||
}; | ||
const renderFileSize = props => props.file.size && h("div", { | ||
const renderFileSize = props => props.file.size && (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-statusSize" | ||
}, prettierBytes(props.file.size)); | ||
const ReSelectButton = props => props.file.isGhost && h("span", null, ' \u2022 ', h("button", { | ||
const ReSelectButton = props => props.file.isGhost && (0, _preact.h)("span", null, ' \u2022 ', (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-c-btn uppy-Dashboard-Item-reSelect", | ||
@@ -80,3 +79,3 @@ type: "button", | ||
if (file.error) { | ||
return h("button", { | ||
return (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-Item-errorDetails", | ||
@@ -94,12 +93,12 @@ "aria-label": file.error, | ||
module.exports = function FileInfo(props) { | ||
function FileInfo(props) { | ||
const { | ||
file | ||
} = props; | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-fileInfo", | ||
"data-uppy-file-source": file.source | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-fileName" | ||
}, renderFileName(props), h(ErrorButton, { | ||
}, renderFileName(props), (0, _preact.h)(ErrorButton, { | ||
file: props.file // eslint-disable-next-line no-alert | ||
@@ -109,5 +108,5 @@ , | ||
})), h("div", { | ||
})), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-status" | ||
}, renderAuthor(props), renderFileSize(props), ReSelectButton(props)), h(MetaErrorMessage, { | ||
}, renderAuthor(props), renderFileSize(props), ReSelectButton(props)), (0, _preact.h)(MetaErrorMessage, { | ||
file: props.file, | ||
@@ -118,2 +117,4 @@ i18n: props.i18n, | ||
})); | ||
}; | ||
} | ||
module.exports = FileInfo; |
@@ -1,13 +0,13 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const FilePreview = require('../../FilePreview'); | ||
var _preact = require("preact"); | ||
const MetaErrorMessage = require('../MetaErrorMessage'); | ||
const FilePreview = require("../../FilePreview.js"); | ||
const getFileTypeIcon = require('../../../utils/getFileTypeIcon'); | ||
const MetaErrorMessage = require("../MetaErrorMessage.js"); | ||
module.exports = function FilePreviewAndLink(props) { | ||
return h("div", { | ||
const getFileTypeIcon = require("../../../utils/getFileTypeIcon.js"); | ||
function FilePreviewAndLink(props) { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-previewInnerWrap", | ||
@@ -17,3 +17,3 @@ style: { | ||
} | ||
}, props.showLinkToFileUploadResult && props.file.uploadURL && h("a", { | ||
}, props.showLinkToFileUploadResult && props.file.uploadURL && (0, _preact.h)("a", { | ||
className: "uppy-Dashboard-Item-previewLink", | ||
@@ -24,7 +24,7 @@ href: props.file.uploadURL, | ||
"aria-label": props.file.meta.name | ||
}, h("span", { | ||
}, (0, _preact.h)("span", { | ||
hidden: true | ||
}, props.file.meta.name)), h(FilePreview, { | ||
}, props.file.meta.name)), (0, _preact.h)(FilePreview, { | ||
file: props.file | ||
}), h(MetaErrorMessage, { | ||
}), (0, _preact.h)(MetaErrorMessage, { | ||
file: props.file, | ||
@@ -35,2 +35,4 @@ i18n: props.i18n, | ||
})); | ||
}; | ||
} | ||
module.exports = FilePreviewAndLink; |
@@ -1,5 +0,5 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
var _preact = require("preact"); | ||
function onPauseResumeCancelRetry(props) { | ||
@@ -45,5 +45,5 @@ if (props.isUploaded) return; | ||
function ProgressIndicatorButton(props) { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-progress" | ||
}, h("button", { | ||
}, (0, _preact.h)("button", { | ||
className: "uppy-u-reset uppy-Dashboard-Item-progressIndicator", | ||
@@ -61,3 +61,3 @@ type: "button", | ||
} = _ref; | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -78,3 +78,3 @@ focusable: "false", | ||
const circleLength = 2 * Math.PI * 15; | ||
return h("g", null, h("circle", { | ||
return (0, _preact.h)("g", null, (0, _preact.h)("circle", { | ||
className: "uppy-Dashboard-Item-progressIcon--bg", | ||
@@ -86,3 +86,3 @@ r: "15", | ||
fill: "none" | ||
}), h("circle", { | ||
}), (0, _preact.h)("circle", { | ||
className: "uppy-Dashboard-Item-progressIcon--progress", | ||
@@ -100,3 +100,3 @@ r: "15", | ||
module.exports = function FileProgress(props) { | ||
function FileProgress(props) { | ||
// Nothing if upload has not started | ||
@@ -109,7 +109,7 @@ if (!props.file.progress.uploadStarted) { | ||
if (props.isUploaded) { | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-progress" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-progressIndicator" | ||
}, h(ProgressCircleContainer, null, h("circle", { | ||
}, (0, _preact.h)(ProgressCircleContainer, null, (0, _preact.h)("circle", { | ||
r: "15", | ||
@@ -119,3 +119,3 @@ cx: "18", | ||
fill: "#1bb240" | ||
}), h("polygon", { | ||
}), (0, _preact.h)("polygon", { | ||
className: "uppy-Dashboard-Item-progressIcon--check", | ||
@@ -128,3 +128,3 @@ transform: "translate(2, 3)", | ||
if (props.recoveredState) { | ||
return; | ||
return undefined; | ||
} // Retry button for error | ||
@@ -134,18 +134,20 @@ | ||
if (props.error && !props.hideRetryButton) { | ||
return h(ProgressIndicatorButton, props, h("svg", { | ||
"aria-hidden": "true", | ||
focusable: "false", | ||
className: "uppy-c-icon uppy-Dashboard-Item-progressIcon--retry", | ||
width: "28", | ||
height: "31", | ||
viewBox: "0 0 16 19" | ||
}, h("path", { | ||
d: "M16 11a8 8 0 1 1-8-8v2a6 6 0 1 0 6 6h2z" | ||
}), h("path", { | ||
d: "M7.9 3H10v2H7.9z" | ||
}), h("path", { | ||
d: "M8.536.5l3.535 3.536-1.414 1.414L7.12 1.914z" | ||
}), h("path", { | ||
d: "M10.657 2.621l1.414 1.415L8.536 7.57 7.12 6.157z" | ||
}))); | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
(0, _preact.h)(ProgressIndicatorButton, props, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
focusable: "false", | ||
className: "uppy-c-icon uppy-Dashboard-Item-progressIcon--retry", | ||
width: "28", | ||
height: "31", | ||
viewBox: "0 0 16 19" | ||
}, (0, _preact.h)("path", { | ||
d: "M16 11a8 8 0 1 1-8-8v2a6 6 0 1 0 6 6h2z" | ||
}), (0, _preact.h)("path", { | ||
d: "M7.9 3H10v2H7.9z" | ||
}), (0, _preact.h)("path", { | ||
d: "M8.536.5l3.535 3.536-1.414 1.414L7.12 1.914z" | ||
}), (0, _preact.h)("path", { | ||
d: "M10.657 2.621l1.414 1.415L8.536 7.57 7.12 6.157z" | ||
}))) | ||
); | ||
} // Pause/resume button for resumable uploads | ||
@@ -155,24 +157,26 @@ | ||
if (props.resumableUploads && !props.hidePauseResumeButton) { | ||
return h(ProgressIndicatorButton, props, h(ProgressCircleContainer, null, h(ProgressCircle, { | ||
progress: props.file.progress.percentage | ||
}), props.file.isPaused ? h("polygon", { | ||
className: "uppy-Dashboard-Item-progressIcon--play", | ||
transform: "translate(3, 3)", | ||
points: "12 20 12 10 20 15" | ||
}) : h("g", { | ||
className: "uppy-Dashboard-Item-progressIcon--pause", | ||
transform: "translate(14.5, 13)" | ||
}, h("rect", { | ||
x: "0", | ||
y: "0", | ||
width: "2", | ||
height: "10", | ||
rx: "0" | ||
}), h("rect", { | ||
x: "5", | ||
y: "0", | ||
width: "2", | ||
height: "10", | ||
rx: "0" | ||
})))); | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
(0, _preact.h)(ProgressIndicatorButton, props, (0, _preact.h)(ProgressCircleContainer, null, (0, _preact.h)(ProgressCircle, { | ||
progress: props.file.progress.percentage | ||
}), props.file.isPaused ? (0, _preact.h)("polygon", { | ||
className: "uppy-Dashboard-Item-progressIcon--play", | ||
transform: "translate(3, 3)", | ||
points: "12 20 12 10 20 15" | ||
}) : (0, _preact.h)("g", { | ||
className: "uppy-Dashboard-Item-progressIcon--pause", | ||
transform: "translate(14.5, 13)" | ||
}, (0, _preact.h)("rect", { | ||
x: "0", | ||
y: "0", | ||
width: "2", | ||
height: "10", | ||
rx: "0" | ||
}), (0, _preact.h)("rect", { | ||
x: "5", | ||
y: "0", | ||
width: "2", | ||
height: "10", | ||
rx: "0" | ||
})))) | ||
); | ||
} // Cancel button for non-resumable uploads if individualCancellation is supported (not bundled) | ||
@@ -182,19 +186,23 @@ | ||
if (!props.resumableUploads && props.individualCancellation && !props.hideCancelButton) { | ||
return h(ProgressIndicatorButton, props, h(ProgressCircleContainer, null, h(ProgressCircle, { | ||
progress: props.file.progress.percentage | ||
}), h("polygon", { | ||
className: "cancel", | ||
transform: "translate(2, 2)", | ||
points: "19.8856516 11.0625 16 14.9481516 12.1019737 11.0625 11.0625 12.1143484 14.9481516 16 11.0625 19.8980263 12.1019737 20.9375 16 17.0518484 19.8856516 20.9375 20.9375 19.8980263 17.0518484 16 20.9375 12" | ||
}))); | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
(0, _preact.h)(ProgressIndicatorButton, props, (0, _preact.h)(ProgressCircleContainer, null, (0, _preact.h)(ProgressCircle, { | ||
progress: props.file.progress.percentage | ||
}), (0, _preact.h)("polygon", { | ||
className: "cancel", | ||
transform: "translate(2, 2)", | ||
points: "19.8856516 11.0625 16 14.9481516 12.1019737 11.0625 11.0625 12.1143484 14.9481516 16 11.0625 19.8980263 12.1019737 20.9375 16 17.0518484 19.8856516 20.9375 20.9375 19.8980263 17.0518484 16 20.9375 12" | ||
}))) | ||
); | ||
} // Just progress when buttons are disabled | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-progress" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-progressIndicator" | ||
}, h(ProgressCircleContainer, null, h(ProgressCircle, { | ||
}, (0, _preact.h)(ProgressCircleContainer, null, (0, _preact.h)(ProgressCircle, { | ||
progress: props.file.progress.percentage | ||
})))); | ||
}; | ||
} | ||
module.exports = FileProgress; |
@@ -1,19 +0,18 @@ | ||
const { | ||
h, | ||
Component | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const shallowEqual = require('is-shallow-equal'); | ||
const classNames = require("classnames"); | ||
const FilePreviewAndLink = require('./FilePreviewAndLink'); | ||
const shallowEqual = require("is-shallow-equal"); | ||
const FileProgress = require('./FileProgress'); | ||
const FilePreviewAndLink = require("./FilePreviewAndLink/index.js"); | ||
const FileInfo = require('./FileInfo'); | ||
const FileProgress = require("./FileProgress/index.js"); | ||
const Buttons = require('./Buttons'); | ||
const FileInfo = require("./FileInfo/index.js"); | ||
module.exports = class FileItem extends Component { | ||
const Buttons = require("./Buttons/index.js"); | ||
class FileItem extends _preact.Component { | ||
componentDidMount() { | ||
@@ -85,9 +84,9 @@ const { | ||
}); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: dashboardItemClass, | ||
id: `uppy_${file.id}`, | ||
role: this.props.role | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-preview" | ||
}, h(FilePreviewAndLink, { | ||
}, (0, _preact.h)(FilePreviewAndLink, { | ||
file: file, | ||
@@ -98,3 +97,3 @@ showLinkToFileUploadResult: this.props.showLinkToFileUploadResult, | ||
metaFields: this.props.metaFields | ||
}), h(FileProgress, { | ||
}), (0, _preact.h)(FileProgress, { | ||
uppy: this.props.uppy, | ||
@@ -112,5 +111,5 @@ file: file, | ||
i18n: this.props.i18n | ||
})), h("div", { | ||
})), (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-fileInfoAndButtons" | ||
}, h(FileInfo, { | ||
}, (0, _preact.h)(FileInfo, { | ||
file: file, | ||
@@ -124,3 +123,3 @@ id: this.props.id, | ||
metaFields: this.props.metaFields | ||
}), h(Buttons, { | ||
}), (0, _preact.h)(Buttons, { | ||
file: file, | ||
@@ -139,2 +138,4 @@ metaFields: this.props.metaFields, | ||
}; | ||
} | ||
module.exports = FileItem; |
@@ -1,5 +0,5 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
var _preact = require("preact"); | ||
const metaFieldIdToName = (metaFieldId, metaFields) => { | ||
@@ -10,3 +10,3 @@ const field = metaFields.filter(f => f.id === metaFieldId); | ||
module.exports = function renderMissingMetaFieldsError(props) { | ||
function renderMissingMetaFieldsError(props) { | ||
const { | ||
@@ -27,3 +27,3 @@ file, | ||
const metaFieldsString = missingRequiredMetaFields.map(missingMetaField => metaFieldIdToName(missingMetaField, metaFields)).join(', '); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-errorMessage" | ||
@@ -33,3 +33,3 @@ }, i18n('missingRequiredMetaFields', { | ||
fields: metaFieldsString | ||
}), ' ', h("button", { | ||
}), ' ', (0, _preact.h)("button", { | ||
type: "button", | ||
@@ -39,2 +39,4 @@ class: "uppy-u-reset uppy-Dashboard-Item-errorMessageBtn", | ||
}, i18n('editFile'))); | ||
}; | ||
} | ||
module.exports = renderMissingMetaFieldsError; |
@@ -0,13 +1,13 @@ | ||
"use strict"; | ||
var _preact = require("preact"); | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
const classNames = require('classnames'); | ||
const classNames = require("classnames"); | ||
const { | ||
h | ||
} = require('preact'); | ||
const FileItem = require("./FileItem/index.js"); | ||
const FileItem = require('./FileItem/index.js'); | ||
const VirtualList = require("./VirtualList.js"); | ||
const VirtualList = require('./VirtualList'); | ||
function chunks(list, size) { | ||
@@ -76,9 +76,10 @@ const chunked = []; | ||
// We use the first file ID as the key—this should not change across scroll rerenders | ||
h("div", { | ||
(0, _preact.h)("div", { | ||
role: "presentation", | ||
key: row[0] | ||
}, row.map(fileID => h(FileItem, _extends({ | ||
}, row.map(fileID => (0, _preact.h)(FileItem, _extends({ | ||
key: fileID, | ||
uppy: props.uppy | ||
}, fileProps, { | ||
// eslint-disable-line react/jsx-props-no-spreading | ||
role: "listitem", | ||
@@ -91,3 +92,3 @@ openFileEditor: props.openFileEditor, | ||
return h(VirtualList, { | ||
return (0, _preact.h)(VirtualList, { | ||
class: dashboardFilesClass, | ||
@@ -94,0 +95,0 @@ role: "list", |
@@ -1,8 +0,8 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const getFileTypeIcon = require('../utils/getFileTypeIcon'); | ||
var _preact = require("preact"); | ||
module.exports = function FilePreview(props) { | ||
const getFileTypeIcon = require("../utils/getFileTypeIcon.js"); | ||
function FilePreview(props) { | ||
const { | ||
@@ -13,3 +13,3 @@ file | ||
if (file.preview) { | ||
return h("img", { | ||
return (0, _preact.h)("img", { | ||
className: "uppy-Dashboard-Item-previewImg", | ||
@@ -25,5 +25,5 @@ alt: file.name, | ||
} = getFileTypeIcon(file.type); | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-Dashboard-Item-previewIconWrap" | ||
}, h("span", { | ||
}, (0, _preact.h)("span", { | ||
className: "uppy-Dashboard-Item-previewIcon", | ||
@@ -33,3 +33,3 @@ style: { | ||
} | ||
}, icon), h("svg", { | ||
}, icon), (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -41,3 +41,3 @@ focusable: "false", | ||
viewBox: "0 0 58 76" | ||
}, h("rect", { | ||
}, (0, _preact.h)("rect", { | ||
fill: "#FFF", | ||
@@ -49,2 +49,4 @@ width: "58", | ||
}))); | ||
}; | ||
} | ||
module.exports = FilePreview; |
@@ -1,15 +0,23 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const ignoreEvent = require('../utils/ignoreEvent.js'); | ||
const classNames = require("classnames"); | ||
function PickerPanelContent(props) { | ||
return h("div", { | ||
className: classNames('uppy-DashboardContent-panel', props.className), | ||
const ignoreEvent = require("../utils/ignoreEvent.js"); | ||
function PickerPanelContent(_ref) { | ||
let { | ||
activePickerPanel, | ||
className, | ||
hideAllPanels, | ||
i18n, | ||
state, | ||
uppy | ||
} = _ref; | ||
return (0, _preact.h)("div", { | ||
className: classNames('uppy-DashboardContent-panel', className), | ||
role: "tabpanel", | ||
"data-uppy-panelType": "PickerPanel", | ||
id: `uppy-DashboardContent-panel--${props.activePickerPanel.id}`, | ||
id: `uppy-DashboardContent-panel--${activePickerPanel.id}`, | ||
onDragOver: ignoreEvent, | ||
@@ -19,19 +27,19 @@ onDragLeave: ignoreEvent, | ||
onPaste: ignoreEvent | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-bar" | ||
}, h("div", { | ||
}, (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-title", | ||
role: "heading", | ||
"aria-level": "1" | ||
}, props.i18n('importFrom', { | ||
name: props.activePickerPanel.name | ||
})), h("button", { | ||
}, i18n('importFrom', { | ||
name: activePickerPanel.name | ||
})), (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-back", | ||
type: "button", | ||
onClick: props.hideAllPanels | ||
}, props.i18n('cancel'))), h("div", { | ||
onClick: hideAllPanels | ||
}, i18n('cancel'))), (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-panelBody" | ||
}, props.uppy.getPlugin(props.activePickerPanel.id).render(props.state))); | ||
}, uppy.getPlugin(activePickerPanel.id).render(state))); | ||
} | ||
module.exports = PickerPanelContent; |
@@ -1,5 +0,5 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
var _preact = require("preact"); | ||
const uploadStates = { | ||
@@ -60,9 +60,19 @@ STATE_ERROR: 'error', | ||
function UploadStatus(props) { | ||
const uploadingState = getUploadingState(props.isAllErrored, props.isAllComplete, props.isAllPaused, props.files); | ||
function UploadStatus(_ref) { | ||
let { | ||
files, | ||
i18n, | ||
isAllComplete, | ||
isAllErrored, | ||
isAllPaused, | ||
inProgressNotPausedFiles, | ||
newFiles, | ||
processingFiles | ||
} = _ref; | ||
const uploadingState = getUploadingState(isAllErrored, isAllComplete, isAllPaused, files); | ||
switch (uploadingState) { | ||
case 'uploading': | ||
return props.i18n('uploadingXFiles', { | ||
smart_count: props.inProgressNotPausedFiles.length | ||
return i18n('uploadingXFiles', { | ||
smart_count: inProgressNotPausedFiles.length | ||
}); | ||
@@ -72,16 +82,18 @@ | ||
case 'postprocessing': | ||
return props.i18n('processingXFiles', { | ||
smart_count: props.processingFiles.length | ||
return i18n('processingXFiles', { | ||
smart_count: processingFiles.length | ||
}); | ||
case 'paused': | ||
return props.i18n('uploadPaused'); | ||
return i18n('uploadPaused'); | ||
case 'waiting': | ||
return props.i18n('xFilesSelected', { | ||
smart_count: props.newFiles.length | ||
return i18n('xFilesSelected', { | ||
smart_count: newFiles.length | ||
}); | ||
case 'complete': | ||
return props.i18n('uploadComplete'); | ||
return i18n('uploadComplete'); | ||
default: | ||
} | ||
@@ -91,27 +103,36 @@ } | ||
function PanelTopBar(props) { | ||
const { | ||
i18n, | ||
isAllComplete, | ||
hideCancelButton, | ||
maxNumberOfFiles, | ||
toggleAddFilesPanel, | ||
uppy | ||
} = props; | ||
let { | ||
allowNewUpload | ||
} = props; // TODO maybe this should be done in ../index.js, then just pass that down as `allowNewUpload` | ||
} = props; // TODO maybe this should be done in ../Dashboard.jsx, then just pass that down as `allowNewUpload` | ||
if (allowNewUpload && props.maxNumberOfFiles) { | ||
if (allowNewUpload && maxNumberOfFiles) { | ||
// eslint-disable-next-line react/destructuring-assignment | ||
allowNewUpload = props.totalFileCount < props.maxNumberOfFiles; | ||
} | ||
return h("div", { | ||
return (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-bar" | ||
}, !props.isAllComplete && !props.hideCancelButton ? h("button", { | ||
}, !isAllComplete && !hideCancelButton ? (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-back", | ||
type: "button", | ||
onClick: () => props.uppy.cancelAll() | ||
}, props.i18n('cancel')) : h("div", null), h("div", { | ||
onClick: () => uppy.cancelAll() | ||
}, i18n('cancel')) : (0, _preact.h)("div", null), (0, _preact.h)("div", { | ||
className: "uppy-DashboardContent-title", | ||
role: "heading", | ||
"aria-level": "1" | ||
}, h(UploadStatus, props)), allowNewUpload ? h("button", { | ||
}, (0, _preact.h)(UploadStatus, props)), allowNewUpload ? (0, _preact.h)("button", { | ||
className: "uppy-DashboardContent-addMore", | ||
type: "button", | ||
"aria-label": props.i18n('addMoreFiles'), | ||
title: props.i18n('addMoreFiles'), | ||
onClick: () => props.toggleAddFilesPanel(true) | ||
}, h("svg", { | ||
"aria-label": i18n('addMoreFiles'), | ||
title: i18n('addMoreFiles'), | ||
onClick: () => toggleAddFilesPanel(true) | ||
}, (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -123,9 +144,9 @@ focusable: "false", | ||
viewBox: "0 0 15 15" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M8 6.5h6a.5.5 0 0 1 .5.5v.5a.5.5 0 0 1-.5.5H8v6a.5.5 0 0 1-.5.5H7a.5.5 0 0 1-.5-.5V8h-6a.5.5 0 0 1-.5-.5V7a.5.5 0 0 1 .5-.5h6v-6A.5.5 0 0 1 7 0h.5a.5.5 0 0 1 .5.5v6z" | ||
})), h("span", { | ||
})), (0, _preact.h)("span", { | ||
className: "uppy-DashboardContent-addMoreCaption" | ||
}, props.i18n('addMore'))) : h("div", null)); | ||
}, i18n('addMore'))) : (0, _preact.h)("div", null)); | ||
} | ||
module.exports = PanelTopBar; |
@@ -1,9 +0,7 @@ | ||
const { | ||
cloneElement, | ||
Component, | ||
toChildArray | ||
} = require('preact'); | ||
"use strict"; | ||
const classNames = require('classnames'); | ||
var _preact = require("preact"); | ||
const classNames = require("classnames"); | ||
const transitionName = 'uppy-transition-slideDownUp'; | ||
@@ -21,3 +19,3 @@ const duration = 250; | ||
class Slide extends Component { | ||
class Slide extends _preact.Component { | ||
constructor(props) { | ||
@@ -37,3 +35,3 @@ super(props); | ||
} = this.state; | ||
const child = toChildArray(nextProps.children)[0]; | ||
const child = (0, _preact.toChildArray)(nextProps.children)[0]; | ||
if (cachedChildren === child) return null; | ||
@@ -97,3 +95,3 @@ const patch = { | ||
return cloneElement(cachedChildren, { | ||
return (0, _preact.cloneElement)(cachedChildren, { | ||
className: classNames(className, cachedChildren.props.className) | ||
@@ -100,0 +98,0 @@ }); |
@@ -0,35 +1,7 @@ | ||
"use strict"; | ||
var _preact = require("preact"); | ||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } | ||
/** | ||
* Adapted from preact-virtual-list: https://github.com/developit/preact-virtual-list | ||
* | ||
* © 2016 Jason Miller | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in all | ||
* copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
* SOFTWARE. | ||
* | ||
* Adaptations: | ||
* - Added role=presentation to helper elements | ||
* - Tweaked styles for Uppy's Dashboard use case | ||
*/ | ||
const { | ||
h, | ||
Component | ||
} = require('preact'); | ||
const STYLE_INNER = { | ||
@@ -57,3 +29,3 @@ position: 'relative', | ||
class VirtualList extends Component { | ||
class VirtualList extends _preact.Component { | ||
constructor(props) { | ||
@@ -154,11 +126,13 @@ super(props); // The currently focused node, used to retain focus when the visible rows change. | ||
return h("div", _extends({ | ||
onScroll: this.handleScroll | ||
}, props), h("div", { | ||
role: "presentation", | ||
style: styleInner | ||
}, h("div", { | ||
role: "presentation", | ||
style: styleContent | ||
}, selection.map(renderRow)))); | ||
return (// eslint-disable-next-line react/jsx-props-no-spreading | ||
(0, _preact.h)("div", _extends({ | ||
onScroll: this.handleScroll | ||
}, props), (0, _preact.h)("div", { | ||
role: "presentation", | ||
style: styleInner | ||
}, (0, _preact.h)("div", { | ||
role: "presentation", | ||
style: styleContent | ||
}, selection.map(renderRow)))) | ||
); | ||
} | ||
@@ -165,0 +139,0 @@ |
1165
lib/index.js
@@ -1,1164 +0,3 @@ | ||
var _class, _openFileEditorWhenFilesAdded, _attachRenderFunctionToTarget, _isTargetSupported, _getAcquirers, _getProgressIndicators, _getEditors, _temp; | ||
"use strict"; | ||
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; } | ||
var id = 0; | ||
function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; } | ||
const { | ||
h | ||
} = require('preact'); | ||
const { | ||
UIPlugin | ||
} = require('@uppy/core'); | ||
const StatusBar = require('@uppy/status-bar'); | ||
const Informer = require('@uppy/informer'); | ||
const ThumbnailGenerator = require('@uppy/thumbnail-generator'); | ||
const findAllDOMElements = require('@uppy/utils/lib/findAllDOMElements'); | ||
const toArray = require('@uppy/utils/lib/toArray'); | ||
const getDroppedFiles = require('@uppy/utils/lib/getDroppedFiles'); | ||
const { | ||
nanoid | ||
} = require('nanoid/non-secure'); | ||
const trapFocus = require('./utils/trapFocus'); | ||
const createSuperFocus = require('./utils/createSuperFocus'); | ||
const memoize = require('memoize-one').default || require('memoize-one'); | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS'); | ||
const DashboardUI = require('./components/Dashboard'); | ||
const locale = require('./locale'); | ||
const TAB_KEY = 9; | ||
const ESC_KEY = 27; | ||
function createPromise() { | ||
const o = {}; | ||
o.promise = new Promise((resolve, reject) => { | ||
o.resolve = resolve; | ||
o.reject = reject; | ||
}); | ||
return o; | ||
} | ||
function defaultPickerIcon() { | ||
return h("svg", { | ||
"aria-hidden": "true", | ||
focusable: "false", | ||
width: "30", | ||
height: "30", | ||
viewBox: "0 0 30 30" | ||
}, h("path", { | ||
d: "M15 30c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15C6.716 0 0 6.716 0 15c0 8.284 6.716 15 15 15zm4.258-12.676v6.846h-8.426v-6.846H5.204l9.82-12.364 9.82 12.364H19.26z" | ||
})); | ||
} | ||
/** | ||
* Dashboard UI with previews, metadata editing, tabs for various services and more | ||
*/ | ||
module.exports = (_temp = (_openFileEditorWhenFilesAdded = /*#__PURE__*/_classPrivateFieldLooseKey("openFileEditorWhenFilesAdded"), _attachRenderFunctionToTarget = /*#__PURE__*/_classPrivateFieldLooseKey("attachRenderFunctionToTarget"), _isTargetSupported = /*#__PURE__*/_classPrivateFieldLooseKey("isTargetSupported"), _getAcquirers = /*#__PURE__*/_classPrivateFieldLooseKey("getAcquirers"), _getProgressIndicators = /*#__PURE__*/_classPrivateFieldLooseKey("getProgressIndicators"), _getEditors = /*#__PURE__*/_classPrivateFieldLooseKey("getEditors"), _class = class Dashboard extends UIPlugin { | ||
constructor(uppy, _opts) { | ||
var _this; | ||
super(uppy, _opts); | ||
_this = this; | ||
this.removeTarget = plugin => { | ||
const pluginState = this.getPluginState(); // filter out the one we want to remove | ||
const newTargets = pluginState.targets.filter(target => target.id !== plugin.id); | ||
this.setPluginState({ | ||
targets: newTargets | ||
}); | ||
}; | ||
this.addTarget = plugin => { | ||
const callerPluginId = plugin.id || plugin.constructor.name; | ||
const callerPluginName = plugin.title || callerPluginId; | ||
const callerPluginType = plugin.type; | ||
if (callerPluginType !== 'acquirer' && callerPluginType !== 'progressindicator' && callerPluginType !== 'editor') { | ||
const msg = 'Dashboard: can only be targeted by plugins of types: acquirer, progressindicator, editor'; | ||
this.uppy.log(msg, 'error'); | ||
return; | ||
} | ||
const target = { | ||
id: callerPluginId, | ||
name: callerPluginName, | ||
type: callerPluginType | ||
}; | ||
const state = this.getPluginState(); | ||
const newTargets = state.targets.slice(); | ||
newTargets.push(target); | ||
this.setPluginState({ | ||
targets: newTargets | ||
}); | ||
return this.el; | ||
}; | ||
this.hideAllPanels = () => { | ||
const state = this.getPluginState(); | ||
const update = { | ||
activePickerPanel: false, | ||
showAddFilesPanel: false, | ||
activeOverlayType: null, | ||
fileCardFor: null, | ||
showFileEditor: false | ||
}; | ||
if (state.activePickerPanel === update.activePickerPanel && state.showAddFilesPanel === update.showAddFilesPanel && state.showFileEditor === update.showFileEditor && state.activeOverlayType === update.activeOverlayType) { | ||
// avoid doing a state update if nothing changed | ||
return; | ||
} | ||
this.setPluginState(update); | ||
}; | ||
this.showPanel = id => { | ||
const { | ||
targets | ||
} = this.getPluginState(); | ||
const activePickerPanel = targets.filter(target => { | ||
return target.type === 'acquirer' && target.id === id; | ||
})[0]; | ||
this.setPluginState({ | ||
activePickerPanel, | ||
activeOverlayType: 'PickerPanel' | ||
}); | ||
}; | ||
this.canEditFile = file => { | ||
const { | ||
targets | ||
} = this.getPluginState(); | ||
const editors = _classPrivateFieldLooseBase(this, _getEditors)[_getEditors](targets); | ||
return editors.some(target => this.uppy.getPlugin(target.id).canEditFile(file)); | ||
}; | ||
this.openFileEditor = file => { | ||
const { | ||
targets | ||
} = this.getPluginState(); | ||
const editors = _classPrivateFieldLooseBase(this, _getEditors)[_getEditors](targets); | ||
this.setPluginState({ | ||
showFileEditor: true, | ||
fileCardFor: file.id || null, | ||
activeOverlayType: 'FileEditor' | ||
}); | ||
editors.forEach(editor => { | ||
this.uppy.getPlugin(editor.id).selectFile(file); | ||
}); | ||
}; | ||
this.saveFileEditor = () => { | ||
const { | ||
targets | ||
} = this.getPluginState(); | ||
const editors = _classPrivateFieldLooseBase(this, _getEditors)[_getEditors](targets); | ||
editors.forEach(editor => { | ||
this.uppy.getPlugin(editor.id).save(); | ||
}); | ||
this.hideAllPanels(); | ||
}; | ||
this.openModal = () => { | ||
const { | ||
promise, | ||
resolve | ||
} = createPromise(); // save scroll position | ||
this.savedScrollPosition = window.pageYOffset; // save active element, so we can restore focus when modal is closed | ||
this.savedActiveElement = document.activeElement; | ||
if (this.opts.disablePageScrollWhenModalOpen) { | ||
document.body.classList.add('uppy-Dashboard-isFixed'); | ||
} | ||
if (this.opts.animateOpenClose && this.getPluginState().isClosing) { | ||
const handler = () => { | ||
this.setPluginState({ | ||
isHidden: false | ||
}); | ||
this.el.removeEventListener('animationend', handler, false); | ||
resolve(); | ||
}; | ||
this.el.addEventListener('animationend', handler, false); | ||
} else { | ||
this.setPluginState({ | ||
isHidden: false | ||
}); | ||
resolve(); | ||
} | ||
if (this.opts.browserBackButtonClose) { | ||
this.updateBrowserHistory(); | ||
} // handle ESC and TAB keys in modal dialog | ||
document.addEventListener('keydown', this.handleKeyDownInModal); | ||
this.uppy.emit('dashboard:modal-open'); | ||
return promise; | ||
}; | ||
this.closeModal = function (opts) { | ||
if (opts === void 0) { | ||
opts = {}; | ||
} | ||
const { | ||
// Whether the modal is being closed by the user (`true`) or by other means (e.g. browser back button) | ||
manualClose = true | ||
} = opts; | ||
const { | ||
isHidden, | ||
isClosing | ||
} = _this.getPluginState(); | ||
if (isHidden || isClosing) { | ||
// short-circuit if animation is ongoing | ||
return; | ||
} | ||
const { | ||
promise, | ||
resolve | ||
} = createPromise(); | ||
if (_this.opts.disablePageScrollWhenModalOpen) { | ||
document.body.classList.remove('uppy-Dashboard-isFixed'); | ||
} | ||
if (_this.opts.animateOpenClose) { | ||
_this.setPluginState({ | ||
isClosing: true | ||
}); | ||
const handler = () => { | ||
_this.setPluginState({ | ||
isHidden: true, | ||
isClosing: false | ||
}); | ||
_this.superFocus.cancel(); | ||
_this.savedActiveElement.focus(); | ||
_this.el.removeEventListener('animationend', handler, false); | ||
resolve(); | ||
}; | ||
_this.el.addEventListener('animationend', handler, false); | ||
} else { | ||
_this.setPluginState({ | ||
isHidden: true | ||
}); | ||
_this.superFocus.cancel(); | ||
_this.savedActiveElement.focus(); | ||
resolve(); | ||
} // handle ESC and TAB keys in modal dialog | ||
document.removeEventListener('keydown', _this.handleKeyDownInModal); | ||
if (manualClose) { | ||
if (_this.opts.browserBackButtonClose) { | ||
var _history$state; | ||
// Make sure that the latest entry in the history state is our modal name | ||
// eslint-disable-next-line no-restricted-globals | ||
if ((_history$state = history.state) != null && _history$state[_this.modalName]) { | ||
// Go back in history to clear out the entry we created (ultimately closing the modal) | ||
// eslint-disable-next-line no-restricted-globals | ||
history.back(); | ||
} | ||
} | ||
} | ||
_this.uppy.emit('dashboard:modal-closed'); | ||
return promise; | ||
}; | ||
this.isModalOpen = () => { | ||
return !this.getPluginState().isHidden || false; | ||
}; | ||
this.requestCloseModal = () => { | ||
if (this.opts.onRequestCloseModal) { | ||
return this.opts.onRequestCloseModal(); | ||
} | ||
return this.closeModal(); | ||
}; | ||
this.setDarkModeCapability = isDarkModeOn => { | ||
const { | ||
capabilities | ||
} = this.uppy.getState(); | ||
this.uppy.setState({ | ||
capabilities: { ...capabilities, | ||
darkMode: isDarkModeOn | ||
} | ||
}); | ||
}; | ||
this.handleSystemDarkModeChange = event => { | ||
const isDarkModeOnNow = event.matches; | ||
this.uppy.log(`[Dashboard] Dark mode is ${isDarkModeOnNow ? 'on' : 'off'}`); | ||
this.setDarkModeCapability(isDarkModeOnNow); | ||
}; | ||
this.toggleFileCard = (show, fileID) => { | ||
const file = this.uppy.getFile(fileID); | ||
if (show) { | ||
this.uppy.emit('dashboard:file-edit-start', file); | ||
} else { | ||
this.uppy.emit('dashboard:file-edit-complete', file); | ||
} | ||
this.setPluginState({ | ||
fileCardFor: show ? fileID : null, | ||
activeOverlayType: show ? 'FileCard' : null | ||
}); | ||
}; | ||
this.toggleAddFilesPanel = show => { | ||
this.setPluginState({ | ||
showAddFilesPanel: show, | ||
activeOverlayType: show ? 'AddFiles' : null | ||
}); | ||
}; | ||
this.addFiles = files => { | ||
const descriptors = files.map(file => ({ | ||
source: this.id, | ||
name: file.name, | ||
type: file.type, | ||
data: file, | ||
meta: { | ||
// path of the file relative to the ancestor directory the user selected. | ||
// e.g. 'docs/Old Prague/airbnb.pdf' | ||
relativePath: file.relativePath || null | ||
} | ||
})); | ||
try { | ||
this.uppy.addFiles(descriptors); | ||
} catch (err) { | ||
this.uppy.log(err); | ||
} | ||
}; | ||
this.startListeningToResize = () => { | ||
// Watch for Dashboard container (`.uppy-Dashboard-inner`) resize | ||
// and update containerWidth/containerHeight in plugin state accordingly. | ||
// Emits first event on initialization. | ||
this.resizeObserver = new ResizeObserver(entries => { | ||
const uppyDashboardInnerEl = entries[0]; | ||
const { | ||
width, | ||
height | ||
} = uppyDashboardInnerEl.contentRect; | ||
this.uppy.log(`[Dashboard] resized: ${width} / ${height}`, 'debug'); | ||
this.setPluginState({ | ||
containerWidth: width, | ||
containerHeight: height, | ||
areInsidesReadyToBeVisible: true | ||
}); | ||
}); | ||
this.resizeObserver.observe(this.el.querySelector('.uppy-Dashboard-inner')); // If ResizeObserver fails to emit an event telling us what size to use - default to the mobile view | ||
this.makeDashboardInsidesVisibleAnywayTimeout = setTimeout(() => { | ||
const pluginState = this.getPluginState(); | ||
const isModalAndClosed = !this.opts.inline && pluginState.isHidden; | ||
if ( // if ResizeObserver hasn't yet fired, | ||
!pluginState.areInsidesReadyToBeVisible // and it's not due to the modal being closed | ||
&& !isModalAndClosed) { | ||
this.uppy.log("[Dashboard] resize event didn't fire on time: defaulted to mobile layout", 'debug'); | ||
this.setPluginState({ | ||
areInsidesReadyToBeVisible: true | ||
}); | ||
} | ||
}, 1000); | ||
}; | ||
this.stopListeningToResize = () => { | ||
this.resizeObserver.disconnect(); | ||
clearTimeout(this.makeDashboardInsidesVisibleAnywayTimeout); | ||
}; | ||
this.recordIfFocusedOnUppyRecently = event => { | ||
if (this.el.contains(event.target)) { | ||
this.ifFocusedOnUppyRecently = true; | ||
} else { | ||
this.ifFocusedOnUppyRecently = false; // ___Why run this.superFocus.cancel here when it already runs in superFocusOnEachUpdate? | ||
// Because superFocus is debounced, when we move from Uppy to some other element on the page, | ||
// previously run superFocus sometimes hits and moves focus back to Uppy. | ||
this.superFocus.cancel(); | ||
} | ||
}; | ||
this.disableAllFocusableElements = disable => { | ||
const focusableNodes = toArray(this.el.querySelectorAll(FOCUSABLE_ELEMENTS)); | ||
if (disable) { | ||
focusableNodes.forEach(node => { | ||
// save previous tabindex in a data-attribute, to restore when enabling | ||
const currentTabIndex = node.getAttribute('tabindex'); | ||
if (currentTabIndex) { | ||
node.dataset.inertTabindex = currentTabIndex; | ||
} | ||
node.setAttribute('tabindex', '-1'); | ||
}); | ||
} else { | ||
focusableNodes.forEach(node => { | ||
if ('inertTabindex' in node.dataset) { | ||
node.setAttribute('tabindex', node.dataset.inertTabindex); | ||
} else { | ||
node.removeAttribute('tabindex'); | ||
} | ||
}); | ||
} | ||
this.dashboardIsDisabled = disable; | ||
}; | ||
this.updateBrowserHistory = () => { | ||
var _history$state2; | ||
// Ensure history state does not already contain our modal name to avoid double-pushing | ||
// eslint-disable-next-line no-restricted-globals | ||
if (!((_history$state2 = history.state) != null && _history$state2[this.modalName])) { | ||
// Push to history so that the page is not lost on browser back button press | ||
// eslint-disable-next-line no-restricted-globals | ||
history.pushState({ // eslint-disable-next-line no-restricted-globals | ||
...history.state, | ||
[this.modalName]: true | ||
}, ''); | ||
} // Listen for back button presses | ||
window.addEventListener('popstate', this.handlePopState, false); | ||
}; | ||
this.handlePopState = event => { | ||
var _event$state; | ||
// Close the modal if the history state no longer contains our modal name | ||
if (this.isModalOpen() && (!event.state || !event.state[this.modalName])) { | ||
this.closeModal({ | ||
manualClose: false | ||
}); | ||
} // When the browser back button is pressed and uppy is now the latest entry | ||
// in the history but the modal is closed, fix the history by removing the | ||
// uppy history entry. | ||
// This occurs when another entry is added into the history state while the | ||
// modal is open, and then the modal gets manually closed. | ||
// Solves PR #575 (https://github.com/transloadit/uppy/pull/575) | ||
if (!this.isModalOpen() && (_event$state = event.state) != null && _event$state[this.modalName]) { | ||
// eslint-disable-next-line no-restricted-globals | ||
history.back(); | ||
} | ||
}; | ||
this.handleKeyDownInModal = event => { | ||
// close modal on esc key press | ||
if (event.keyCode === ESC_KEY) this.requestCloseModal(event); // trap focus on tab key press | ||
if (event.keyCode === TAB_KEY) trapFocus.forModal(event, this.getPluginState().activeOverlayType, this.el); | ||
}; | ||
this.handleClickOutside = () => { | ||
if (this.opts.closeModalOnClickOutside) this.requestCloseModal(); | ||
}; | ||
this.handlePaste = event => { | ||
// Let any acquirer plugin (Url/Webcam/etc.) handle pastes to the root | ||
this.uppy.iteratePlugins(plugin => { | ||
if (plugin.type === 'acquirer') { | ||
// Every Plugin with .type acquirer can define handleRootPaste(event) | ||
plugin.handleRootPaste == null ? void 0 : plugin.handleRootPaste(event); | ||
} | ||
}); // Add all dropped files | ||
const files = toArray(event.clipboardData.files); | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files pasted'); | ||
this.addFiles(files); | ||
} | ||
}; | ||
this.handleInputChange = event => { | ||
event.preventDefault(); | ||
const files = toArray(event.target.files); | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files selected through input'); | ||
this.addFiles(files); | ||
} | ||
}; | ||
this.handleDragOver = event => { | ||
var _this$opts$onDragOver, _this$opts; | ||
event.preventDefault(); | ||
event.stopPropagation(); // Check if some plugin can handle the datatransfer without files — | ||
// for instance, the Url plugin can import a url | ||
const canSomePluginHandleRootDrop = () => { | ||
let somePluginCanHandleRootDrop = true; | ||
this.uppy.iteratePlugins(plugin => { | ||
if (plugin.canHandleRootDrop != null && plugin.canHandleRootDrop(event)) { | ||
somePluginCanHandleRootDrop = true; | ||
} | ||
}); | ||
return somePluginCanHandleRootDrop; | ||
}; // Check if the "type" of the datatransfer object includes files | ||
const doesEventHaveFiles = () => { | ||
const { | ||
types | ||
} = event.dataTransfer; | ||
return types.some(type => type === 'Files'); | ||
}; // Deny drop, if no plugins can handle datatransfer, there are no files, | ||
// or when opts.disabled is set, or new uploads are not allowed | ||
const somePluginCanHandleRootDrop = canSomePluginHandleRootDrop(event); | ||
const hasFiles = doesEventHaveFiles(event); | ||
if (!somePluginCanHandleRootDrop && !hasFiles || this.opts.disabled // opts.disableLocalFiles should only be taken into account if no plugins | ||
// can handle the datatransfer | ||
|| this.opts.disableLocalFiles && (hasFiles || !somePluginCanHandleRootDrop) || !this.uppy.getState().allowNewUpload) { | ||
event.dataTransfer.dropEffect = 'none'; | ||
clearTimeout(this.removeDragOverClassTimeout); | ||
return; | ||
} // Add a small (+) icon on drop | ||
// (and prevent browsers from interpreting this as files being _moved_ into the | ||
// browser, https://github.com/transloadit/uppy/issues/1978). | ||
event.dataTransfer.dropEffect = 'copy'; | ||
clearTimeout(this.removeDragOverClassTimeout); | ||
this.setPluginState({ | ||
isDraggingOver: true | ||
}); | ||
(_this$opts$onDragOver = (_this$opts = this.opts).onDragOver) == null ? void 0 : _this$opts$onDragOver.call(_this$opts, event); | ||
}; | ||
this.handleDragLeave = event => { | ||
var _this$opts$onDragLeav, _this$opts2; | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
clearTimeout(this.removeDragOverClassTimeout); // Timeout against flickering, this solution is taken from drag-drop library. | ||
// Solution with 'pointer-events: none' didn't work across browsers. | ||
this.removeDragOverClassTimeout = setTimeout(() => { | ||
this.setPluginState({ | ||
isDraggingOver: false | ||
}); | ||
}, 50); | ||
(_this$opts$onDragLeav = (_this$opts2 = this.opts).onDragLeave) == null ? void 0 : _this$opts$onDragLeav.call(_this$opts2, event); | ||
}; | ||
this.handleDrop = async event => { | ||
var _this$opts$onDrop, _this$opts3; | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
clearTimeout(this.removeDragOverClassTimeout); | ||
this.setPluginState({ | ||
isDraggingOver: false | ||
}); // Let any acquirer plugin (Url/Webcam/etc.) handle drops to the root | ||
this.uppy.iteratePlugins(plugin => { | ||
if (plugin.type === 'acquirer') { | ||
// Every Plugin with .type acquirer can define handleRootDrop(event) | ||
plugin.handleRootDrop == null ? void 0 : plugin.handleRootDrop(event); | ||
} | ||
}); // Add all dropped files | ||
let executedDropErrorOnce = false; | ||
const logDropError = error => { | ||
this.uppy.log(error, 'error'); // In practice all drop errors are most likely the same, | ||
// so let's just show one to avoid overwhelming the user | ||
if (!executedDropErrorOnce) { | ||
this.uppy.info(error.message, 'error'); | ||
executedDropErrorOnce = true; | ||
} | ||
}; // Add all dropped files | ||
const files = await getDroppedFiles(event.dataTransfer, { | ||
logDropError | ||
}); | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files dropped'); | ||
this.addFiles(files); | ||
} | ||
(_this$opts$onDrop = (_this$opts3 = this.opts).onDrop) == null ? void 0 : _this$opts$onDrop.call(_this$opts3, event); | ||
}; | ||
this.handleRequestThumbnail = file => { | ||
if (!this.opts.waitForThumbnailsBeforeUpload) { | ||
this.uppy.emit('thumbnail:request', file); | ||
} | ||
}; | ||
this.handleCancelThumbnail = file => { | ||
if (!this.opts.waitForThumbnailsBeforeUpload) { | ||
this.uppy.emit('thumbnail:cancel', file); | ||
} | ||
}; | ||
this.handleKeyDownInInline = event => { | ||
// Trap focus on tab key press. | ||
if (event.keyCode === TAB_KEY) trapFocus.forInline(event, this.getPluginState().activeOverlayType, this.el); | ||
}; | ||
this.handlePasteOnBody = event => { | ||
const isFocusInOverlay = this.el.contains(document.activeElement); | ||
if (isFocusInOverlay) { | ||
this.handlePaste(event); | ||
} | ||
}; | ||
this.handleComplete = _ref => { | ||
let { | ||
failed | ||
} = _ref; | ||
if (this.opts.closeAfterFinish && failed.length === 0) { | ||
// All uploads are done | ||
this.requestCloseModal(); | ||
} | ||
}; | ||
this.handleCancelRestore = () => { | ||
this.uppy.emit('restore-canceled'); | ||
}; | ||
Object.defineProperty(this, _openFileEditorWhenFilesAdded, { | ||
writable: true, | ||
value: files => { | ||
const firstFile = files[0]; | ||
if (this.canEditFile(firstFile)) { | ||
this.openFileEditor(firstFile); | ||
} | ||
} | ||
}); | ||
this.initEvents = () => { | ||
// Modal open button | ||
if (this.opts.trigger && !this.opts.inline) { | ||
const showModalTrigger = findAllDOMElements(this.opts.trigger); | ||
if (showModalTrigger) { | ||
showModalTrigger.forEach(trigger => trigger.addEventListener('click', this.openModal)); | ||
} else { | ||
this.uppy.log('Dashboard modal trigger not found. Make sure `trigger` is set in Dashboard options, unless you are planning to call `dashboard.openModal()` method yourself', 'warning'); | ||
} | ||
} | ||
this.startListeningToResize(); | ||
document.addEventListener('paste', this.handlePasteOnBody); | ||
this.uppy.on('plugin-remove', this.removeTarget); | ||
this.uppy.on('file-added', this.hideAllPanels); | ||
this.uppy.on('dashboard:modal-closed', this.hideAllPanels); | ||
this.uppy.on('file-editor:complete', this.hideAllPanels); | ||
this.uppy.on('complete', this.handleComplete); // ___Why fire on capture? | ||
// Because this.ifFocusedOnUppyRecently needs to change before onUpdate() fires. | ||
document.addEventListener('focus', this.recordIfFocusedOnUppyRecently, true); | ||
document.addEventListener('click', this.recordIfFocusedOnUppyRecently, true); | ||
if (this.opts.inline) { | ||
this.el.addEventListener('keydown', this.handleKeyDownInInline); | ||
} | ||
if (this.opts.autoOpenFileEditor) { | ||
this.uppy.on('files-added', _classPrivateFieldLooseBase(this, _openFileEditorWhenFilesAdded)[_openFileEditorWhenFilesAdded]); | ||
} | ||
}; | ||
this.removeEvents = () => { | ||
const showModalTrigger = findAllDOMElements(this.opts.trigger); | ||
if (!this.opts.inline && showModalTrigger) { | ||
showModalTrigger.forEach(trigger => trigger.removeEventListener('click', this.openModal)); | ||
} | ||
this.stopListeningToResize(); | ||
document.removeEventListener('paste', this.handlePasteOnBody); | ||
window.removeEventListener('popstate', this.handlePopState, false); | ||
this.uppy.off('plugin-remove', this.removeTarget); | ||
this.uppy.off('file-added', this.hideAllPanels); | ||
this.uppy.off('dashboard:modal-closed', this.hideAllPanels); | ||
this.uppy.off('file-editor:complete', this.hideAllPanels); | ||
this.uppy.off('complete', this.handleComplete); | ||
document.removeEventListener('focus', this.recordIfFocusedOnUppyRecently); | ||
document.removeEventListener('click', this.recordIfFocusedOnUppyRecently); | ||
if (this.opts.inline) { | ||
this.el.removeEventListener('keydown', this.handleKeyDownInInline); | ||
} | ||
if (this.opts.autoOpenFileEditor) { | ||
this.uppy.off('files-added', _classPrivateFieldLooseBase(this, _openFileEditorWhenFilesAdded)[_openFileEditorWhenFilesAdded]); | ||
} | ||
}; | ||
this.superFocusOnEachUpdate = () => { | ||
const isFocusInUppy = this.el.contains(document.activeElement); // When focus is lost on the page (== focus is on body for most browsers, or focus is null for IE11) | ||
const isFocusNowhere = document.activeElement === document.body || document.activeElement === null; | ||
const isInformerHidden = this.uppy.getState().info.length === 0; | ||
const isModal = !this.opts.inline; | ||
if ( // If update is connected to showing the Informer - let the screen reader calmly read it. | ||
isInformerHidden && ( // If we are in a modal - always superfocus without concern for other elements | ||
// on the page (user is unlikely to want to interact with the rest of the page) | ||
isModal // If we are already inside of Uppy, or | ||
|| isFocusInUppy // If we are not focused on anything BUT we have already, at least once, focused on uppy | ||
// 1. We focus when isFocusNowhere, because when the element we were focused | ||
// on disappears (e.g. an overlay), - focus gets lost. If user is typing | ||
// something somewhere else on the page, - focus won't be 'nowhere'. | ||
// 2. We only focus when focus is nowhere AND this.ifFocusedOnUppyRecently, | ||
// to avoid focus jumps if we do something else on the page. | ||
// [Practical check] Without '&& this.ifFocusedOnUppyRecently', in Safari, in inline mode, | ||
// when file is uploading, - navigate via tab to the checkbox, | ||
// try to press space multiple times. Focus will jump to Uppy. | ||
|| isFocusNowhere && this.ifFocusedOnUppyRecently)) { | ||
this.superFocus(this.el, this.getPluginState().activeOverlayType); | ||
} else { | ||
this.superFocus.cancel(); | ||
} | ||
}; | ||
this.afterUpdate = () => { | ||
if (this.opts.disabled && !this.dashboardIsDisabled) { | ||
this.disableAllFocusableElements(true); | ||
return; | ||
} | ||
if (!this.opts.disabled && this.dashboardIsDisabled) { | ||
this.disableAllFocusableElements(false); | ||
} | ||
this.superFocusOnEachUpdate(); | ||
}; | ||
this.saveFileCard = (meta, fileID) => { | ||
this.uppy.setFileMeta(fileID, meta); | ||
this.toggleFileCard(false, fileID); | ||
}; | ||
Object.defineProperty(this, _attachRenderFunctionToTarget, { | ||
writable: true, | ||
value: target => { | ||
const plugin = this.uppy.getPlugin(target.id); | ||
return { ...target, | ||
icon: plugin.icon || this.opts.defaultPickerIcon, | ||
render: plugin.render | ||
}; | ||
} | ||
}); | ||
Object.defineProperty(this, _isTargetSupported, { | ||
writable: true, | ||
value: target => { | ||
const plugin = this.uppy.getPlugin(target.id); // If the plugin does not provide a `supported` check, assume the plugin works everywhere. | ||
if (typeof plugin.isSupported !== 'function') { | ||
return true; | ||
} | ||
return plugin.isSupported(); | ||
} | ||
}); | ||
Object.defineProperty(this, _getAcquirers, { | ||
writable: true, | ||
value: memoize(targets => { | ||
return targets.filter(target => target.type === 'acquirer' && _classPrivateFieldLooseBase(this, _isTargetSupported)[_isTargetSupported](target)).map(_classPrivateFieldLooseBase(this, _attachRenderFunctionToTarget)[_attachRenderFunctionToTarget]); | ||
}) | ||
}); | ||
Object.defineProperty(this, _getProgressIndicators, { | ||
writable: true, | ||
value: memoize(targets => { | ||
return targets.filter(target => target.type === 'progressindicator').map(_classPrivateFieldLooseBase(this, _attachRenderFunctionToTarget)[_attachRenderFunctionToTarget]); | ||
}) | ||
}); | ||
Object.defineProperty(this, _getEditors, { | ||
writable: true, | ||
value: memoize(targets => { | ||
return targets.filter(target => target.type === 'editor').map(_classPrivateFieldLooseBase(this, _attachRenderFunctionToTarget)[_attachRenderFunctionToTarget]); | ||
}) | ||
}); | ||
this.render = state => { | ||
const pluginState = this.getPluginState(); | ||
const { | ||
files, | ||
capabilities, | ||
allowNewUpload | ||
} = state; | ||
const { | ||
newFiles, | ||
uploadStartedFiles, | ||
completeFiles, | ||
erroredFiles, | ||
inProgressFiles, | ||
inProgressNotPausedFiles, | ||
processingFiles, | ||
isUploadStarted, | ||
isAllComplete, | ||
isAllErrored, | ||
isAllPaused | ||
} = this.uppy.getObjectOfFilesPerState(); | ||
const acquirers = _classPrivateFieldLooseBase(this, _getAcquirers)[_getAcquirers](pluginState.targets); | ||
const progressindicators = _classPrivateFieldLooseBase(this, _getProgressIndicators)[_getProgressIndicators](pluginState.targets); | ||
const editors = _classPrivateFieldLooseBase(this, _getEditors)[_getEditors](pluginState.targets); | ||
let theme; | ||
if (this.opts.theme === 'auto') { | ||
theme = capabilities.darkMode ? 'dark' : 'light'; | ||
} else { | ||
theme = this.opts.theme; | ||
} | ||
if (['files', 'folders', 'both'].indexOf(this.opts.fileManagerSelectionType) < 0) { | ||
this.opts.fileManagerSelectionType = 'files'; // eslint-disable-next-line no-console | ||
console.warn(`Unsupported option for "fileManagerSelectionType". Using default of "${this.opts.fileManagerSelectionType}".`); | ||
} | ||
return DashboardUI({ | ||
state, | ||
isHidden: pluginState.isHidden, | ||
files, | ||
newFiles, | ||
uploadStartedFiles, | ||
completeFiles, | ||
erroredFiles, | ||
inProgressFiles, | ||
inProgressNotPausedFiles, | ||
processingFiles, | ||
isUploadStarted, | ||
isAllComplete, | ||
isAllErrored, | ||
isAllPaused, | ||
totalFileCount: Object.keys(files).length, | ||
totalProgress: state.totalProgress, | ||
allowNewUpload, | ||
acquirers, | ||
theme, | ||
disabled: this.opts.disabled, | ||
disableLocalFiles: this.opts.disableLocalFiles, | ||
direction: this.opts.direction, | ||
activePickerPanel: pluginState.activePickerPanel, | ||
showFileEditor: pluginState.showFileEditor, | ||
saveFileEditor: this.saveFileEditor, | ||
disableAllFocusableElements: this.disableAllFocusableElements, | ||
animateOpenClose: this.opts.animateOpenClose, | ||
isClosing: pluginState.isClosing, | ||
progressindicators, | ||
editors, | ||
autoProceed: this.uppy.opts.autoProceed, | ||
id: this.id, | ||
closeModal: this.requestCloseModal, | ||
handleClickOutside: this.handleClickOutside, | ||
handleInputChange: this.handleInputChange, | ||
handlePaste: this.handlePaste, | ||
inline: this.opts.inline, | ||
showPanel: this.showPanel, | ||
hideAllPanels: this.hideAllPanels, | ||
i18n: this.i18n, | ||
i18nArray: this.i18nArray, | ||
uppy: this.uppy, | ||
note: this.opts.note, | ||
recoveredState: state.recoveredState, | ||
metaFields: pluginState.metaFields, | ||
resumableUploads: capabilities.resumableUploads || false, | ||
individualCancellation: capabilities.individualCancellation, | ||
isMobileDevice: capabilities.isMobileDevice, | ||
fileCardFor: pluginState.fileCardFor, | ||
toggleFileCard: this.toggleFileCard, | ||
toggleAddFilesPanel: this.toggleAddFilesPanel, | ||
showAddFilesPanel: pluginState.showAddFilesPanel, | ||
saveFileCard: this.saveFileCard, | ||
openFileEditor: this.openFileEditor, | ||
canEditFile: this.canEditFile, | ||
width: this.opts.width, | ||
height: this.opts.height, | ||
showLinkToFileUploadResult: this.opts.showLinkToFileUploadResult, | ||
fileManagerSelectionType: this.opts.fileManagerSelectionType, | ||
proudlyDisplayPoweredByUppy: this.opts.proudlyDisplayPoweredByUppy, | ||
hideCancelButton: this.opts.hideCancelButton, | ||
hideRetryButton: this.opts.hideRetryButton, | ||
hidePauseResumeButton: this.opts.hidePauseResumeButton, | ||
showRemoveButtonAfterComplete: this.opts.showRemoveButtonAfterComplete, | ||
containerWidth: pluginState.containerWidth, | ||
containerHeight: pluginState.containerHeight, | ||
areInsidesReadyToBeVisible: pluginState.areInsidesReadyToBeVisible, | ||
isTargetDOMEl: this.isTargetDOMEl, | ||
parentElement: this.el, | ||
allowedFileTypes: this.uppy.opts.restrictions.allowedFileTypes, | ||
maxNumberOfFiles: this.uppy.opts.restrictions.maxNumberOfFiles, | ||
requiredMetaFields: this.uppy.opts.restrictions.requiredMetaFields, | ||
showSelectedFiles: this.opts.showSelectedFiles, | ||
handleCancelRestore: this.handleCancelRestore, | ||
handleRequestThumbnail: this.handleRequestThumbnail, | ||
handleCancelThumbnail: this.handleCancelThumbnail, | ||
// drag props | ||
isDraggingOver: pluginState.isDraggingOver, | ||
handleDragOver: this.handleDragOver, | ||
handleDragLeave: this.handleDragLeave, | ||
handleDrop: this.handleDrop | ||
}); | ||
}; | ||
this.discoverProviderPlugins = () => { | ||
this.uppy.iteratePlugins(plugin => { | ||
if (plugin && !plugin.target && plugin.opts && plugin.opts.target === this.constructor) { | ||
this.addTarget(plugin); | ||
} | ||
}); | ||
}; | ||
this.install = () => { | ||
// Set default state for Dashboard | ||
this.setPluginState({ | ||
isHidden: true, | ||
fileCardFor: null, | ||
activeOverlayType: null, | ||
showAddFilesPanel: false, | ||
activePickerPanel: false, | ||
showFileEditor: false, | ||
metaFields: this.opts.metaFields, | ||
targets: [], | ||
// We'll make them visible once .containerWidth is determined | ||
areInsidesReadyToBeVisible: false, | ||
isDraggingOver: false | ||
}); | ||
const { | ||
inline, | ||
closeAfterFinish | ||
} = this.opts; | ||
if (inline && closeAfterFinish) { | ||
throw new Error('[Dashboard] `closeAfterFinish: true` cannot be used on an inline Dashboard, because an inline Dashboard cannot be closed at all. Either set `inline: false`, or disable the `closeAfterFinish` option.'); | ||
} | ||
const { | ||
allowMultipleUploads, | ||
allowMultipleUploadBatches | ||
} = this.uppy.opts; | ||
if ((allowMultipleUploads || allowMultipleUploadBatches) && closeAfterFinish) { | ||
this.uppy.log('[Dashboard] When using `closeAfterFinish`, we recommended setting the `allowMultipleUploadBatches` option to `false` in the Uppy constructor. See https://uppy.io/docs/uppy/#allowMultipleUploads-true', 'warning'); | ||
} | ||
const { | ||
target | ||
} = this.opts; | ||
if (target) { | ||
this.mount(target, this); | ||
} | ||
const plugins = this.opts.plugins || []; | ||
plugins.forEach(pluginID => { | ||
const plugin = this.uppy.getPlugin(pluginID); | ||
if (plugin) { | ||
plugin.mount(this, plugin); | ||
} | ||
}); | ||
if (!this.opts.disableStatusBar) { | ||
this.uppy.use(StatusBar, { | ||
id: `${this.id}:StatusBar`, | ||
target: this, | ||
hideUploadButton: this.opts.hideUploadButton, | ||
hideRetryButton: this.opts.hideRetryButton, | ||
hidePauseResumeButton: this.opts.hidePauseResumeButton, | ||
hideCancelButton: this.opts.hideCancelButton, | ||
showProgressDetails: this.opts.showProgressDetails, | ||
hideAfterFinish: this.opts.hideProgressAfterFinish, | ||
locale: this.opts.locale, | ||
doneButtonHandler: this.opts.doneButtonHandler | ||
}); | ||
} | ||
if (!this.opts.disableInformer) { | ||
this.uppy.use(Informer, { | ||
id: `${this.id}:Informer`, | ||
target: this | ||
}); | ||
} | ||
if (!this.opts.disableThumbnailGenerator) { | ||
this.uppy.use(ThumbnailGenerator, { | ||
id: `${this.id}:ThumbnailGenerator`, | ||
thumbnailWidth: this.opts.thumbnailWidth, | ||
thumbnailHeight: this.opts.thumbnailHeight, | ||
thumbnailType: this.opts.thumbnailType, | ||
waitForThumbnailsBeforeUpload: this.opts.waitForThumbnailsBeforeUpload, | ||
// If we don't block on thumbnails, we can lazily generate them | ||
lazy: !this.opts.waitForThumbnailsBeforeUpload | ||
}); | ||
} // Dark Mode / theme | ||
this.darkModeMediaQuery = typeof window !== 'undefined' && window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null; | ||
const isDarkModeOnFromTheStart = this.darkModeMediaQuery ? this.darkModeMediaQuery.matches : false; | ||
this.uppy.log(`[Dashboard] Dark mode is ${isDarkModeOnFromTheStart ? 'on' : 'off'}`); | ||
this.setDarkModeCapability(isDarkModeOnFromTheStart); | ||
if (this.opts.theme === 'auto') { | ||
this.darkModeMediaQuery.addListener(this.handleSystemDarkModeChange); | ||
} | ||
this.discoverProviderPlugins(); | ||
this.initEvents(); | ||
}; | ||
this.uninstall = () => { | ||
if (!this.opts.disableInformer) { | ||
const informer = this.uppy.getPlugin(`${this.id}:Informer`); // Checking if this plugin exists, in case it was removed by uppy-core | ||
// before the Dashboard was. | ||
if (informer) this.uppy.removePlugin(informer); | ||
} | ||
if (!this.opts.disableStatusBar) { | ||
const statusBar = this.uppy.getPlugin(`${this.id}:StatusBar`); | ||
if (statusBar) this.uppy.removePlugin(statusBar); | ||
} | ||
if (!this.opts.disableThumbnailGenerator) { | ||
const thumbnail = this.uppy.getPlugin(`${this.id}:ThumbnailGenerator`); | ||
if (thumbnail) this.uppy.removePlugin(thumbnail); | ||
} | ||
const plugins = this.opts.plugins || []; | ||
plugins.forEach(pluginID => { | ||
const plugin = this.uppy.getPlugin(pluginID); | ||
if (plugin) plugin.unmount(); | ||
}); | ||
if (this.opts.theme === 'auto') { | ||
this.darkModeMediaQuery.removeListener(this.handleSystemDarkModeChange); | ||
} | ||
this.unmount(); | ||
this.removeEvents(); | ||
}; | ||
this.id = this.opts.id || 'Dashboard'; | ||
this.title = 'Dashboard'; | ||
this.type = 'orchestrator'; | ||
this.modalName = `uppy-Dashboard-${nanoid()}`; | ||
this.defaultLocale = locale; // set default options | ||
const defaultOptions = { | ||
target: 'body', | ||
metaFields: [], | ||
trigger: null, | ||
inline: false, | ||
width: 750, | ||
height: 550, | ||
thumbnailWidth: 280, | ||
thumbnailType: 'image/jpeg', | ||
waitForThumbnailsBeforeUpload: false, | ||
defaultPickerIcon, | ||
showLinkToFileUploadResult: false, | ||
showProgressDetails: false, | ||
hideUploadButton: false, | ||
hideCancelButton: false, | ||
hideRetryButton: false, | ||
hidePauseResumeButton: false, | ||
hideProgressAfterFinish: false, | ||
doneButtonHandler: () => { | ||
this.uppy.reset(); | ||
this.requestCloseModal(); | ||
}, | ||
note: null, | ||
closeModalOnClickOutside: false, | ||
closeAfterFinish: false, | ||
disableStatusBar: false, | ||
disableInformer: false, | ||
disableThumbnailGenerator: false, | ||
disablePageScrollWhenModalOpen: true, | ||
animateOpenClose: true, | ||
fileManagerSelectionType: 'files', | ||
proudlyDisplayPoweredByUppy: true, | ||
onRequestCloseModal: () => this.closeModal(), | ||
showSelectedFiles: true, | ||
showRemoveButtonAfterComplete: false, | ||
browserBackButtonClose: false, | ||
theme: 'light', | ||
autoOpenFileEditor: false, | ||
disabled: false, | ||
disableLocalFiles: false | ||
}; // merge default options with the ones set by user | ||
this.opts = { ...defaultOptions, | ||
..._opts | ||
}; | ||
this.i18nInit(); | ||
this.superFocus = createSuperFocus(); | ||
this.ifFocusedOnUppyRecently = false; // Timeouts | ||
this.makeDashboardInsidesVisibleAnywayTimeout = null; | ||
this.removeDragOverClassTimeout = null; | ||
} | ||
}), _class.VERSION = "2.2.0", _temp); | ||
module.exports = require("./Dashboard.js"); |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
module.exports = { | ||
@@ -2,0 +4,0 @@ strings: { |
@@ -1,13 +0,7 @@ | ||
/** | ||
* Copies text to clipboard by creating an almost invisible textarea, | ||
* adding text there, then running execCommand('copy'). | ||
* Falls back to prompt() when the easy way fails (hello, Safari!) | ||
* From http://stackoverflow.com/a/30810322 | ||
* | ||
* @param {string} textToCopy | ||
* @param {string} fallbackString | ||
* @returns {Promise} | ||
*/ | ||
module.exports = function copyToClipboard(textToCopy, fallbackString) { | ||
fallbackString = fallbackString || 'Copy the URL below'; | ||
"use strict"; | ||
function copyToClipboard(textToCopy, fallbackString) { | ||
// TODO: make `fallbackString` an optional parameter instead. | ||
fallbackString || (fallbackString = 'Copy the URL below'); // eslint-disable-line no-param-reassign | ||
return new Promise(resolve => { | ||
@@ -52,2 +46,14 @@ const textArea = document.createElement('textarea'); | ||
}); | ||
}; | ||
} | ||
/** | ||
* Copies text to clipboard by creating an almost invisible textarea, | ||
* adding text there, then running execCommand('copy'). | ||
* Falls back to prompt() when the easy way fails (hello, Safari!) | ||
* From http://stackoverflow.com/a/30810322 | ||
* | ||
* @param {string} textToCopy | ||
* @param {string} fallbackString | ||
* @returns {Promise} | ||
*/ | ||
module.exports = copyToClipboard; |
@@ -1,6 +0,8 @@ | ||
const debounce = require('lodash.debounce'); | ||
"use strict"; | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS'); | ||
const debounce = require("lodash.debounce"); | ||
const getActiveOverlayEl = require('./getActiveOverlayEl'); | ||
const FOCUSABLE_ELEMENTS = require("@uppy/utils/lib/FOCUSABLE_ELEMENTS"); | ||
const getActiveOverlayEl = require("./getActiveOverlayEl.js"); | ||
/* | ||
@@ -18,3 +20,3 @@ Focuses on some element in the currently topmost overlay. | ||
module.exports = function createSuperFocus() { | ||
function createSuperFocus() { | ||
let lastFocusWasOnSuperFocusableEl = false; | ||
@@ -56,2 +58,4 @@ | ||
return debounce(superFocus, 260); | ||
}; | ||
} | ||
module.exports = createSuperFocus; |
@@ -1,5 +0,4 @@ | ||
/** | ||
* @returns {HTMLElement} - either dashboard element, or the overlay that's most on top | ||
*/ | ||
module.exports = function getActiveOverlayEl(dashboardEl, activeOverlayType) { | ||
"use strict"; | ||
function getActiveOverlayEl(dashboardEl, activeOverlayType) { | ||
if (activeOverlayType) { | ||
@@ -12,2 +11,7 @@ const overlayEl = dashboardEl.querySelector(`[data-uppy-paneltype="${activeOverlayType}"]`); // if an overlay is already mounted | ||
return dashboardEl; | ||
}; | ||
} | ||
/** | ||
* @returns {HTMLElement} - either dashboard element, or the overlay that's most on top | ||
*/ | ||
module.exports = getActiveOverlayEl; |
@@ -1,7 +0,7 @@ | ||
const { | ||
h | ||
} = require('preact'); | ||
"use strict"; | ||
var _preact = require("preact"); | ||
function iconImage() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -12,12 +12,12 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("g", { | ||
}, (0, _preact.h)("g", { | ||
fill: "#686DE0", | ||
fillRule: "evenodd" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M5 7v10h15V7H5zm0-1h15a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z", | ||
fillRule: "nonzero" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
d: "M6.35 17.172l4.994-5.026a.5.5 0 0 1 .707 0l2.16 2.16 3.505-3.505a.5.5 0 0 1 .707 0l2.336 2.31-.707.72-1.983-1.97-3.505 3.505a.5.5 0 0 1-.707 0l-2.16-2.159-3.938 3.939-1.409.026z", | ||
fillRule: "nonzero" | ||
}), h("circle", { | ||
}), (0, _preact.h)("circle", { | ||
cx: "7.5", | ||
@@ -30,3 +30,3 @@ cy: "9.5", | ||
function iconAudio() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -38,3 +38,3 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M9.5 18.64c0 1.14-1.145 2-2.5 2s-2.5-.86-2.5-2c0-1.14 1.145-2 2.5-2 .557 0 1.079.145 1.5.396V7.25a.5.5 0 0 1 .379-.485l9-2.25A.5.5 0 0 1 18.5 5v11.64c0 1.14-1.145 2-2.5 2s-2.5-.86-2.5-2c0-1.14 1.145-2 2.5-2 .557 0 1.079.145 1.5.396V8.67l-8 2v7.97zm8-11v-2l-8 2v2l8-2zM7 19.64c.855 0 1.5-.484 1.5-1s-.645-1-1.5-1-1.5.484-1.5 1 .645 1 1.5 1zm9-2c.855 0 1.5-.484 1.5-1s-.645-1-1.5-1-1.5.484-1.5 1 .645 1 1.5 1z", | ||
@@ -47,3 +47,3 @@ fill: "#049BCF", | ||
function iconVideo() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -55,3 +55,3 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M16 11.834l4.486-2.691A1 1 0 0 1 22 10v6a1 1 0 0 1-1.514.857L16 14.167V17a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v2.834zM15 9H5v8h10V9zm1 4l5 3v-6l-5 3z", | ||
@@ -64,3 +64,3 @@ fill: "#19AF67", | ||
function iconPDF() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -72,3 +72,3 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M9.766 8.295c-.691-1.843-.539-3.401.747-3.726 1.643-.414 2.505.938 2.39 3.299-.039.79-.194 1.662-.537 3.148.324.49.66.967 1.055 1.51.17.231.382.488.629.757 1.866-.128 3.653.114 4.918.655 1.487.635 2.192 1.685 1.614 2.84-.566 1.133-1.839 1.084-3.416.249-1.141-.604-2.457-1.634-3.51-2.707a13.467 13.467 0 0 0-2.238.426c-1.392 4.051-4.534 6.453-5.707 4.572-.986-1.58 1.38-4.206 4.914-5.375.097-.322.185-.656.264-1.001.08-.353.306-1.31.407-1.737-.678-1.059-1.2-2.031-1.53-2.91zm2.098 4.87c-.033.144-.068.287-.104.427l.033-.01-.012.038a14.065 14.065 0 0 1 1.02-.197l-.032-.033.052-.004a7.902 7.902 0 0 1-.208-.271c-.197-.27-.38-.526-.555-.775l-.006.028-.002-.003c-.076.323-.148.632-.186.8zm5.77 2.978c1.143.605 1.832.632 2.054.187.26-.519-.087-1.034-1.113-1.473-.911-.39-2.175-.608-3.55-.608.845.766 1.787 1.459 2.609 1.894zM6.559 18.789c.14.223.693.16 1.425-.413.827-.648 1.61-1.747 2.208-3.206-2.563 1.064-4.102 2.867-3.633 3.62zm5.345-10.97c.088-1.793-.351-2.48-1.146-2.28-.473.119-.564 1.05-.056 2.405.213.566.52 1.188.908 1.859.18-.858.268-1.453.294-1.984z", | ||
@@ -81,3 +81,3 @@ fill: "#E2514A", | ||
function iconArchive() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -88,3 +88,3 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M10.45 2.05h1.05a.5.5 0 0 1 .5.5v.024a.5.5 0 0 1-.5.5h-1.05a.5.5 0 0 1-.5-.5V2.55a.5.5 0 0 1 .5-.5zm2.05 1.024h1.05a.5.5 0 0 1 .5.5V3.6a.5.5 0 0 1-.5.5H12.5a.5.5 0 0 1-.5-.5v-.025a.5.5 0 0 1 .5-.5v-.001zM10.45 0h1.05a.5.5 0 0 1 .5.5v.025a.5.5 0 0 1-.5.5h-1.05a.5.5 0 0 1-.5-.5V.5a.5.5 0 0 1 .5-.5zm2.05 1.025h1.05a.5.5 0 0 1 .5.5v.024a.5.5 0 0 1-.5.5H12.5a.5.5 0 0 1-.5-.5v-.024a.5.5 0 0 1 .5-.5zm-2.05 3.074h1.05a.5.5 0 0 1 .5.5v.025a.5.5 0 0 1-.5.5h-1.05a.5.5 0 0 1-.5-.5v-.025a.5.5 0 0 1 .5-.5zm2.05 1.025h1.05a.5.5 0 0 1 .5.5v.024a.5.5 0 0 1-.5.5H12.5a.5.5 0 0 1-.5-.5v-.024a.5.5 0 0 1 .5-.5zm-2.05 1.024h1.05a.5.5 0 0 1 .5.5v.025a.5.5 0 0 1-.5.5h-1.05a.5.5 0 0 1-.5-.5v-.025a.5.5 0 0 1 .5-.5zm2.05 1.025h1.05a.5.5 0 0 1 .5.5v.025a.5.5 0 0 1-.5.5H12.5a.5.5 0 0 1-.5-.5v-.025a.5.5 0 0 1 .5-.5zm-2.05 1.025h1.05a.5.5 0 0 1 .5.5v.025a.5.5 0 0 1-.5.5h-1.05a.5.5 0 0 1-.5-.5v-.025a.5.5 0 0 1 .5-.5zm2.05 1.025h1.05a.5.5 0 0 1 .5.5v.024a.5.5 0 0 1-.5.5H12.5a.5.5 0 0 1-.5-.5v-.024a.5.5 0 0 1 .5-.5zm-1.656 3.074l-.82 5.946c.52.302 1.174.458 1.976.458.803 0 1.455-.156 1.975-.458l-.82-5.946h-2.311zm0-1.025h2.312c.512 0 .946.378 1.015.885l.82 5.946c.056.412-.142.817-.501 1.026-.686.398-1.515.597-2.49.597-.974 0-1.804-.199-2.49-.597a1.025 1.025 0 0 1-.5-1.026l.819-5.946c.07-.507.503-.885 1.015-.885zm.545 6.6a.5.5 0 0 1-.397-.561l.143-.999a.5.5 0 0 1 .495-.429h.74a.5.5 0 0 1 .495.43l.143.998a.5.5 0 0 1-.397.561c-.404.08-.819.08-1.222 0z", | ||
@@ -97,3 +97,3 @@ fill: "#00C469", | ||
function iconFile() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -105,8 +105,8 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("g", { | ||
}, (0, _preact.h)("g", { | ||
fill: "#A7AFB7", | ||
fillRule: "nonzero" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M5.5 22a.5.5 0 0 1-.5-.5v-18a.5.5 0 0 1 .5-.5h10.719a.5.5 0 0 1 .367.16l3.281 3.556a.5.5 0 0 1 .133.339V21.5a.5.5 0 0 1-.5.5h-14zm.5-1h13V7.25L16 4H6v17z" | ||
}), h("path", { | ||
}), (0, _preact.h)("path", { | ||
d: "M15 4v3a1 1 0 0 0 1 1h3V7h-3V4h-1z" | ||
@@ -117,3 +117,3 @@ }))); | ||
function iconText() { | ||
return h("svg", { | ||
return (0, _preact.h)("svg", { | ||
"aria-hidden": "true", | ||
@@ -125,3 +125,3 @@ focusable: "false", | ||
viewBox: "0 0 25 25" | ||
}, h("path", { | ||
}, (0, _preact.h)("path", { | ||
d: "M4.5 7h13a.5.5 0 1 1 0 1h-13a.5.5 0 0 1 0-1zm0 3h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1zm0 3h15a.5.5 0 1 1 0 1h-15a.5.5 0 1 1 0-1zm0 3h10a.5.5 0 1 1 0 1h-10a.5.5 0 1 1 0-1z", | ||
@@ -133,3 +133,3 @@ fill: "#5A5E69", | ||
module.exports = function getIconByMime(fileType) { | ||
function getIconByMime(fileType) { | ||
const defaultChoice = { | ||
@@ -193,2 +193,4 @@ color: '#838999', | ||
return defaultChoice; | ||
}; | ||
} | ||
module.exports = getIconByMime; |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
// ignore drop/paste events if they are not in input or textarea — | ||
@@ -2,0 +4,0 @@ // otherwise when Url plugin adds drop/paste listeners to this.el, |
@@ -1,7 +0,15 @@ | ||
const toArray = require('@uppy/utils/lib/toArray'); | ||
"use strict"; | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS'); | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.forInline = forInline; | ||
exports.forModal = trapFocus; | ||
const getActiveOverlayEl = require('./getActiveOverlayEl'); | ||
const toArray = require("@uppy/utils/lib/toArray"); | ||
const FOCUSABLE_ELEMENTS = require("@uppy/utils/lib/FOCUSABLE_ELEMENTS"); | ||
const getActiveOverlayEl = require("./getActiveOverlayEl.js"); | ||
function focusOnFirstNode(event, nodes) { | ||
@@ -50,21 +58,16 @@ const node = nodes[0]; | ||
} | ||
} | ||
} // Traps focus inside of the currently open overlay (e.g. Dashboard, or e.g. Instagram), | ||
// never lets focus disappear from the modal. | ||
module.exports = { | ||
// Traps focus inside of the currently open overlay (e.g. Dashboard, or e.g. Instagram), | ||
// never lets focus disappear from the modal. | ||
forModal: (event, activeOverlayType, dashboardEl) => { | ||
// Traps focus inside of the currently open overlay, unless overlay is null - then let the user tab away. | ||
function forInline(event, activeOverlayType, dashboardEl) { | ||
// ___When we're in the bare 'Drop files here, paste, browse or import from' screen | ||
if (activeOverlayType === null) {// Do nothing and let the browser handle it, user can tab away from Uppy to other elements on the page | ||
// ___When there is some overlay with 'Done' button | ||
} else { | ||
// Trap the focus inside this overlay! | ||
// User can close the overlay (click 'Done') if they want to travel away from Uppy. | ||
trapFocus(event, activeOverlayType, dashboardEl); | ||
}, | ||
// Traps focus inside of the currently open overlay, unless overlay is null - then let the user tab away. | ||
forInline: (event, activeOverlayType, dashboardEl) => { | ||
// ___When we're in the bare 'Drop files here, paste, browse or import from' screen | ||
if (activeOverlayType === null) {// Do nothing and let the browser handle it, user can tab away from Uppy to other elements on the page | ||
// ___When there is some overlay with 'Done' button | ||
} else { | ||
// Trap the focus inside this overlay! | ||
// User can close the overlay (click 'Done') if they want to travel away from Uppy. | ||
trapFocus(event, activeOverlayType, dashboardEl); | ||
} | ||
} | ||
}; | ||
} |
{ | ||
"name": "@uppy/dashboard", | ||
"description": "Universal UI plugin for Uppy.", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"license": "MIT", | ||
@@ -9,2 +9,3 @@ "main": "lib/index.js", | ||
"types": "types/index.d.ts", | ||
"type": "module", | ||
"keywords": [ | ||
@@ -27,7 +28,7 @@ "file uploader", | ||
"@transloadit/prettier-bytes": "0.0.7", | ||
"@uppy/informer": "^2.0.5", | ||
"@uppy/provider-views": "^2.1.0", | ||
"@uppy/status-bar": "^2.2.0", | ||
"@uppy/thumbnail-generator": "^2.1.1", | ||
"@uppy/utils": "^4.0.7", | ||
"@uppy/informer": "^2.1.0", | ||
"@uppy/provider-views": "^2.1.1", | ||
"@uppy/status-bar": "^2.2.1", | ||
"@uppy/thumbnail-generator": "^2.2.0", | ||
"@uppy/utils": "^4.1.0", | ||
"classnames": "^2.2.6", | ||
@@ -41,9 +42,10 @@ "is-shallow-equal": "^1.0.1", | ||
"devDependencies": { | ||
"@uppy/google-drive": "^2.1.0", | ||
"@uppy/status-bar": "^2.2.0", | ||
"@jest/globals": "^27.4.2", | ||
"@uppy/google-drive": "^2.1.1", | ||
"@uppy/status-bar": "^2.2.1", | ||
"resize-observer-polyfill": "^1.5.0" | ||
}, | ||
"peerDependencies": { | ||
"@uppy/core": "^2.2.0" | ||
"@uppy/core": "^2.3.0" | ||
} | ||
} |
@@ -42,4 +42,2 @@ # @uppy/dashboard | ||
We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/). | ||
Alternatively, you can also use this plugin in a pre-built bundle from Transloadit’s CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object. See the [main Uppy documentation](https://uppy.io/docs/#Installation) for instructions. | ||
@@ -46,0 +44,0 @@ |
1110
src/index.js
@@ -1,1109 +0,1 @@ | ||
const { h } = require('preact') | ||
const { UIPlugin } = require('@uppy/core') | ||
const StatusBar = require('@uppy/status-bar') | ||
const Informer = require('@uppy/informer') | ||
const ThumbnailGenerator = require('@uppy/thumbnail-generator') | ||
const findAllDOMElements = require('@uppy/utils/lib/findAllDOMElements') | ||
const toArray = require('@uppy/utils/lib/toArray') | ||
const getDroppedFiles = require('@uppy/utils/lib/getDroppedFiles') | ||
const { nanoid } = require('nanoid/non-secure') | ||
const trapFocus = require('./utils/trapFocus') | ||
const createSuperFocus = require('./utils/createSuperFocus') | ||
const memoize = require('memoize-one').default || require('memoize-one') | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS') | ||
const DashboardUI = require('./components/Dashboard') | ||
const locale = require('./locale') | ||
const TAB_KEY = 9 | ||
const ESC_KEY = 27 | ||
function createPromise () { | ||
const o = {} | ||
o.promise = new Promise((resolve, reject) => { | ||
o.resolve = resolve | ||
o.reject = reject | ||
}) | ||
return o | ||
} | ||
function defaultPickerIcon () { | ||
return ( | ||
<svg aria-hidden="true" focusable="false" width="30" height="30" viewBox="0 0 30 30"> | ||
<path d="M15 30c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15C6.716 0 0 6.716 0 15c0 8.284 6.716 15 15 15zm4.258-12.676v6.846h-8.426v-6.846H5.204l9.82-12.364 9.82 12.364H19.26z" /> | ||
</svg> | ||
) | ||
} | ||
/** | ||
* Dashboard UI with previews, metadata editing, tabs for various services and more | ||
*/ | ||
module.exports = class Dashboard extends UIPlugin { | ||
static VERSION = require('../package.json').version | ||
constructor (uppy, opts) { | ||
super(uppy, opts) | ||
this.id = this.opts.id || 'Dashboard' | ||
this.title = 'Dashboard' | ||
this.type = 'orchestrator' | ||
this.modalName = `uppy-Dashboard-${nanoid()}` | ||
this.defaultLocale = locale | ||
// set default options | ||
const defaultOptions = { | ||
target: 'body', | ||
metaFields: [], | ||
trigger: null, | ||
inline: false, | ||
width: 750, | ||
height: 550, | ||
thumbnailWidth: 280, | ||
thumbnailType: 'image/jpeg', | ||
waitForThumbnailsBeforeUpload: false, | ||
defaultPickerIcon, | ||
showLinkToFileUploadResult: false, | ||
showProgressDetails: false, | ||
hideUploadButton: false, | ||
hideCancelButton: false, | ||
hideRetryButton: false, | ||
hidePauseResumeButton: false, | ||
hideProgressAfterFinish: false, | ||
doneButtonHandler: () => { | ||
this.uppy.reset() | ||
this.requestCloseModal() | ||
}, | ||
note: null, | ||
closeModalOnClickOutside: false, | ||
closeAfterFinish: false, | ||
disableStatusBar: false, | ||
disableInformer: false, | ||
disableThumbnailGenerator: false, | ||
disablePageScrollWhenModalOpen: true, | ||
animateOpenClose: true, | ||
fileManagerSelectionType: 'files', | ||
proudlyDisplayPoweredByUppy: true, | ||
onRequestCloseModal: () => this.closeModal(), | ||
showSelectedFiles: true, | ||
showRemoveButtonAfterComplete: false, | ||
browserBackButtonClose: false, | ||
theme: 'light', | ||
autoOpenFileEditor: false, | ||
disabled: false, | ||
disableLocalFiles: false, | ||
} | ||
// merge default options with the ones set by user | ||
this.opts = { ...defaultOptions, ...opts } | ||
this.i18nInit() | ||
this.superFocus = createSuperFocus() | ||
this.ifFocusedOnUppyRecently = false | ||
// Timeouts | ||
this.makeDashboardInsidesVisibleAnywayTimeout = null | ||
this.removeDragOverClassTimeout = null | ||
} | ||
removeTarget = (plugin) => { | ||
const pluginState = this.getPluginState() | ||
// filter out the one we want to remove | ||
const newTargets = pluginState.targets.filter(target => target.id !== plugin.id) | ||
this.setPluginState({ | ||
targets: newTargets, | ||
}) | ||
} | ||
addTarget = (plugin) => { | ||
const callerPluginId = plugin.id || plugin.constructor.name | ||
const callerPluginName = plugin.title || callerPluginId | ||
const callerPluginType = plugin.type | ||
if (callerPluginType !== 'acquirer' | ||
&& callerPluginType !== 'progressindicator' | ||
&& callerPluginType !== 'editor') { | ||
const msg = 'Dashboard: can only be targeted by plugins of types: acquirer, progressindicator, editor' | ||
this.uppy.log(msg, 'error') | ||
return | ||
} | ||
const target = { | ||
id: callerPluginId, | ||
name: callerPluginName, | ||
type: callerPluginType, | ||
} | ||
const state = this.getPluginState() | ||
const newTargets = state.targets.slice() | ||
newTargets.push(target) | ||
this.setPluginState({ | ||
targets: newTargets, | ||
}) | ||
return this.el | ||
} | ||
hideAllPanels = () => { | ||
const state = this.getPluginState() | ||
const update = { | ||
activePickerPanel: false, | ||
showAddFilesPanel: false, | ||
activeOverlayType: null, | ||
fileCardFor: null, | ||
showFileEditor: false, | ||
} | ||
if (state.activePickerPanel === update.activePickerPanel | ||
&& state.showAddFilesPanel === update.showAddFilesPanel | ||
&& state.showFileEditor === update.showFileEditor | ||
&& state.activeOverlayType === update.activeOverlayType) { | ||
// avoid doing a state update if nothing changed | ||
return | ||
} | ||
this.setPluginState(update) | ||
} | ||
showPanel = (id) => { | ||
const { targets } = this.getPluginState() | ||
const activePickerPanel = targets.filter((target) => { | ||
return target.type === 'acquirer' && target.id === id | ||
})[0] | ||
this.setPluginState({ | ||
activePickerPanel, | ||
activeOverlayType: 'PickerPanel', | ||
}) | ||
} | ||
canEditFile = (file) => { | ||
const { targets } = this.getPluginState() | ||
const editors = this.#getEditors(targets) | ||
return editors.some((target) => ( | ||
this.uppy.getPlugin(target.id).canEditFile(file) | ||
)) | ||
} | ||
openFileEditor = (file) => { | ||
const { targets } = this.getPluginState() | ||
const editors = this.#getEditors(targets) | ||
this.setPluginState({ | ||
showFileEditor: true, | ||
fileCardFor: file.id || null, | ||
activeOverlayType: 'FileEditor', | ||
}) | ||
editors.forEach((editor) => { | ||
this.uppy.getPlugin(editor.id).selectFile(file) | ||
}) | ||
} | ||
saveFileEditor = () => { | ||
const { targets } = this.getPluginState() | ||
const editors = this.#getEditors(targets) | ||
editors.forEach((editor) => { | ||
this.uppy.getPlugin(editor.id).save() | ||
}) | ||
this.hideAllPanels() | ||
} | ||
openModal = () => { | ||
const { promise, resolve } = createPromise() | ||
// save scroll position | ||
this.savedScrollPosition = window.pageYOffset | ||
// save active element, so we can restore focus when modal is closed | ||
this.savedActiveElement = document.activeElement | ||
if (this.opts.disablePageScrollWhenModalOpen) { | ||
document.body.classList.add('uppy-Dashboard-isFixed') | ||
} | ||
if (this.opts.animateOpenClose && this.getPluginState().isClosing) { | ||
const handler = () => { | ||
this.setPluginState({ | ||
isHidden: false, | ||
}) | ||
this.el.removeEventListener('animationend', handler, false) | ||
resolve() | ||
} | ||
this.el.addEventListener('animationend', handler, false) | ||
} else { | ||
this.setPluginState({ | ||
isHidden: false, | ||
}) | ||
resolve() | ||
} | ||
if (this.opts.browserBackButtonClose) { | ||
this.updateBrowserHistory() | ||
} | ||
// handle ESC and TAB keys in modal dialog | ||
document.addEventListener('keydown', this.handleKeyDownInModal) | ||
this.uppy.emit('dashboard:modal-open') | ||
return promise | ||
} | ||
closeModal = (opts = {}) => { | ||
const { | ||
// Whether the modal is being closed by the user (`true`) or by other means (e.g. browser back button) | ||
manualClose = true, | ||
} = opts | ||
const { isHidden, isClosing } = this.getPluginState() | ||
if (isHidden || isClosing) { | ||
// short-circuit if animation is ongoing | ||
return | ||
} | ||
const { promise, resolve } = createPromise() | ||
if (this.opts.disablePageScrollWhenModalOpen) { | ||
document.body.classList.remove('uppy-Dashboard-isFixed') | ||
} | ||
if (this.opts.animateOpenClose) { | ||
this.setPluginState({ | ||
isClosing: true, | ||
}) | ||
const handler = () => { | ||
this.setPluginState({ | ||
isHidden: true, | ||
isClosing: false, | ||
}) | ||
this.superFocus.cancel() | ||
this.savedActiveElement.focus() | ||
this.el.removeEventListener('animationend', handler, false) | ||
resolve() | ||
} | ||
this.el.addEventListener('animationend', handler, false) | ||
} else { | ||
this.setPluginState({ | ||
isHidden: true, | ||
}) | ||
this.superFocus.cancel() | ||
this.savedActiveElement.focus() | ||
resolve() | ||
} | ||
// handle ESC and TAB keys in modal dialog | ||
document.removeEventListener('keydown', this.handleKeyDownInModal) | ||
if (manualClose) { | ||
if (this.opts.browserBackButtonClose) { | ||
// Make sure that the latest entry in the history state is our modal name | ||
// eslint-disable-next-line no-restricted-globals | ||
if (history.state?.[this.modalName]) { | ||
// Go back in history to clear out the entry we created (ultimately closing the modal) | ||
// eslint-disable-next-line no-restricted-globals | ||
history.back() | ||
} | ||
} | ||
} | ||
this.uppy.emit('dashboard:modal-closed') | ||
return promise | ||
} | ||
isModalOpen = () => { | ||
return !this.getPluginState().isHidden || false | ||
} | ||
requestCloseModal = () => { | ||
if (this.opts.onRequestCloseModal) { | ||
return this.opts.onRequestCloseModal() | ||
} | ||
return this.closeModal() | ||
} | ||
setDarkModeCapability = (isDarkModeOn) => { | ||
const { capabilities } = this.uppy.getState() | ||
this.uppy.setState({ | ||
capabilities: { | ||
...capabilities, | ||
darkMode: isDarkModeOn, | ||
}, | ||
}) | ||
} | ||
handleSystemDarkModeChange = (event) => { | ||
const isDarkModeOnNow = event.matches | ||
this.uppy.log(`[Dashboard] Dark mode is ${isDarkModeOnNow ? 'on' : 'off'}`) | ||
this.setDarkModeCapability(isDarkModeOnNow) | ||
} | ||
toggleFileCard = (show, fileID) => { | ||
const file = this.uppy.getFile(fileID) | ||
if (show) { | ||
this.uppy.emit('dashboard:file-edit-start', file) | ||
} else { | ||
this.uppy.emit('dashboard:file-edit-complete', file) | ||
} | ||
this.setPluginState({ | ||
fileCardFor: show ? fileID : null, | ||
activeOverlayType: show ? 'FileCard' : null, | ||
}) | ||
} | ||
toggleAddFilesPanel = (show) => { | ||
this.setPluginState({ | ||
showAddFilesPanel: show, | ||
activeOverlayType: show ? 'AddFiles' : null, | ||
}) | ||
} | ||
addFiles = (files) => { | ||
const descriptors = files.map((file) => ({ | ||
source: this.id, | ||
name: file.name, | ||
type: file.type, | ||
data: file, | ||
meta: { | ||
// path of the file relative to the ancestor directory the user selected. | ||
// e.g. 'docs/Old Prague/airbnb.pdf' | ||
relativePath: file.relativePath || null, | ||
}, | ||
})) | ||
try { | ||
this.uppy.addFiles(descriptors) | ||
} catch (err) { | ||
this.uppy.log(err) | ||
} | ||
} | ||
// ___Why make insides of Dashboard invisible until first ResizeObserver event is emitted? | ||
// ResizeOberserver doesn't emit the first resize event fast enough, users can see the jump from one .uppy-size-- to | ||
// another (e.g. in Safari) | ||
// ___Why not apply visibility property to .uppy-Dashboard-inner? | ||
// Because ideally, acc to specs, ResizeObserver should see invisible elements as of width 0. So even though applying | ||
// invisibility to .uppy-Dashboard-inner works now, it may not work in the future. | ||
startListeningToResize = () => { | ||
// Watch for Dashboard container (`.uppy-Dashboard-inner`) resize | ||
// and update containerWidth/containerHeight in plugin state accordingly. | ||
// Emits first event on initialization. | ||
this.resizeObserver = new ResizeObserver((entries) => { | ||
const uppyDashboardInnerEl = entries[0] | ||
const { width, height } = uppyDashboardInnerEl.contentRect | ||
this.uppy.log(`[Dashboard] resized: ${width} / ${height}`, 'debug') | ||
this.setPluginState({ | ||
containerWidth: width, | ||
containerHeight: height, | ||
areInsidesReadyToBeVisible: true, | ||
}) | ||
}) | ||
this.resizeObserver.observe(this.el.querySelector('.uppy-Dashboard-inner')) | ||
// If ResizeObserver fails to emit an event telling us what size to use - default to the mobile view | ||
this.makeDashboardInsidesVisibleAnywayTimeout = setTimeout(() => { | ||
const pluginState = this.getPluginState() | ||
const isModalAndClosed = !this.opts.inline && pluginState.isHidden | ||
if ( | ||
// if ResizeObserver hasn't yet fired, | ||
!pluginState.areInsidesReadyToBeVisible | ||
// and it's not due to the modal being closed | ||
&& !isModalAndClosed | ||
) { | ||
this.uppy.log("[Dashboard] resize event didn't fire on time: defaulted to mobile layout", 'debug') | ||
this.setPluginState({ | ||
areInsidesReadyToBeVisible: true, | ||
}) | ||
} | ||
}, 1000) | ||
} | ||
stopListeningToResize = () => { | ||
this.resizeObserver.disconnect() | ||
clearTimeout(this.makeDashboardInsidesVisibleAnywayTimeout) | ||
} | ||
// Records whether we have been interacting with uppy right now, | ||
// which is then used to determine whether state updates should trigger a refocusing. | ||
recordIfFocusedOnUppyRecently = (event) => { | ||
if (this.el.contains(event.target)) { | ||
this.ifFocusedOnUppyRecently = true | ||
} else { | ||
this.ifFocusedOnUppyRecently = false | ||
// ___Why run this.superFocus.cancel here when it already runs in superFocusOnEachUpdate? | ||
// Because superFocus is debounced, when we move from Uppy to some other element on the page, | ||
// previously run superFocus sometimes hits and moves focus back to Uppy. | ||
this.superFocus.cancel() | ||
} | ||
} | ||
disableAllFocusableElements = (disable) => { | ||
const focusableNodes = toArray(this.el.querySelectorAll(FOCUSABLE_ELEMENTS)) | ||
if (disable) { | ||
focusableNodes.forEach((node) => { | ||
// save previous tabindex in a data-attribute, to restore when enabling | ||
const currentTabIndex = node.getAttribute('tabindex') | ||
if (currentTabIndex) { | ||
node.dataset.inertTabindex = currentTabIndex | ||
} | ||
node.setAttribute('tabindex', '-1') | ||
}) | ||
} else { | ||
focusableNodes.forEach((node) => { | ||
if ('inertTabindex' in node.dataset) { | ||
node.setAttribute('tabindex', node.dataset.inertTabindex) | ||
} else { | ||
node.removeAttribute('tabindex') | ||
} | ||
}) | ||
} | ||
this.dashboardIsDisabled = disable | ||
} | ||
updateBrowserHistory = () => { | ||
// Ensure history state does not already contain our modal name to avoid double-pushing | ||
// eslint-disable-next-line no-restricted-globals | ||
if (!history.state?.[this.modalName]) { | ||
// Push to history so that the page is not lost on browser back button press | ||
// eslint-disable-next-line no-restricted-globals | ||
history.pushState({ | ||
// eslint-disable-next-line no-restricted-globals | ||
...history.state, | ||
[this.modalName]: true, | ||
}, '') | ||
} | ||
// Listen for back button presses | ||
window.addEventListener('popstate', this.handlePopState, false) | ||
} | ||
handlePopState = (event) => { | ||
// Close the modal if the history state no longer contains our modal name | ||
if (this.isModalOpen() && (!event.state || !event.state[this.modalName])) { | ||
this.closeModal({ manualClose: false }) | ||
} | ||
// When the browser back button is pressed and uppy is now the latest entry | ||
// in the history but the modal is closed, fix the history by removing the | ||
// uppy history entry. | ||
// This occurs when another entry is added into the history state while the | ||
// modal is open, and then the modal gets manually closed. | ||
// Solves PR #575 (https://github.com/transloadit/uppy/pull/575) | ||
if (!this.isModalOpen() && event.state?.[this.modalName]) { | ||
// eslint-disable-next-line no-restricted-globals | ||
history.back() | ||
} | ||
} | ||
handleKeyDownInModal = (event) => { | ||
// close modal on esc key press | ||
if (event.keyCode === ESC_KEY) this.requestCloseModal(event) | ||
// trap focus on tab key press | ||
if (event.keyCode === TAB_KEY) trapFocus.forModal(event, this.getPluginState().activeOverlayType, this.el) | ||
} | ||
handleClickOutside = () => { | ||
if (this.opts.closeModalOnClickOutside) this.requestCloseModal() | ||
} | ||
handlePaste = (event) => { | ||
// Let any acquirer plugin (Url/Webcam/etc.) handle pastes to the root | ||
this.uppy.iteratePlugins((plugin) => { | ||
if (plugin.type === 'acquirer') { | ||
// Every Plugin with .type acquirer can define handleRootPaste(event) | ||
plugin.handleRootPaste?.(event) | ||
} | ||
}) | ||
// Add all dropped files | ||
const files = toArray(event.clipboardData.files) | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files pasted') | ||
this.addFiles(files) | ||
} | ||
} | ||
handleInputChange = (event) => { | ||
event.preventDefault() | ||
const files = toArray(event.target.files) | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files selected through input') | ||
this.addFiles(files) | ||
} | ||
} | ||
handleDragOver = (event) => { | ||
event.preventDefault() | ||
event.stopPropagation() | ||
// Check if some plugin can handle the datatransfer without files — | ||
// for instance, the Url plugin can import a url | ||
const canSomePluginHandleRootDrop = () => { | ||
let somePluginCanHandleRootDrop = true | ||
this.uppy.iteratePlugins((plugin) => { | ||
if (plugin.canHandleRootDrop?.(event)) { | ||
somePluginCanHandleRootDrop = true | ||
} | ||
}) | ||
return somePluginCanHandleRootDrop | ||
} | ||
// Check if the "type" of the datatransfer object includes files | ||
const doesEventHaveFiles = () => { | ||
const { types } = event.dataTransfer | ||
return types.some(type => type === 'Files') | ||
} | ||
// Deny drop, if no plugins can handle datatransfer, there are no files, | ||
// or when opts.disabled is set, or new uploads are not allowed | ||
const somePluginCanHandleRootDrop = canSomePluginHandleRootDrop(event) | ||
const hasFiles = doesEventHaveFiles(event) | ||
if ( | ||
(!somePluginCanHandleRootDrop && !hasFiles) | ||
|| this.opts.disabled | ||
// opts.disableLocalFiles should only be taken into account if no plugins | ||
// can handle the datatransfer | ||
|| (this.opts.disableLocalFiles && (hasFiles || !somePluginCanHandleRootDrop)) | ||
|| !this.uppy.getState().allowNewUpload | ||
) { | ||
event.dataTransfer.dropEffect = 'none' | ||
clearTimeout(this.removeDragOverClassTimeout) | ||
return | ||
} | ||
// Add a small (+) icon on drop | ||
// (and prevent browsers from interpreting this as files being _moved_ into the | ||
// browser, https://github.com/transloadit/uppy/issues/1978). | ||
event.dataTransfer.dropEffect = 'copy' | ||
clearTimeout(this.removeDragOverClassTimeout) | ||
this.setPluginState({ isDraggingOver: true }) | ||
this.opts.onDragOver?.(event) | ||
} | ||
handleDragLeave = (event) => { | ||
event.preventDefault() | ||
event.stopPropagation() | ||
clearTimeout(this.removeDragOverClassTimeout) | ||
// Timeout against flickering, this solution is taken from drag-drop library. | ||
// Solution with 'pointer-events: none' didn't work across browsers. | ||
this.removeDragOverClassTimeout = setTimeout(() => { | ||
this.setPluginState({ isDraggingOver: false }) | ||
}, 50) | ||
this.opts.onDragLeave?.(event) | ||
} | ||
handleDrop = async (event) => { | ||
event.preventDefault() | ||
event.stopPropagation() | ||
clearTimeout(this.removeDragOverClassTimeout) | ||
this.setPluginState({ isDraggingOver: false }) | ||
// Let any acquirer plugin (Url/Webcam/etc.) handle drops to the root | ||
this.uppy.iteratePlugins((plugin) => { | ||
if (plugin.type === 'acquirer') { | ||
// Every Plugin with .type acquirer can define handleRootDrop(event) | ||
plugin.handleRootDrop?.(event) | ||
} | ||
}) | ||
// Add all dropped files | ||
let executedDropErrorOnce = false | ||
const logDropError = (error) => { | ||
this.uppy.log(error, 'error') | ||
// In practice all drop errors are most likely the same, | ||
// so let's just show one to avoid overwhelming the user | ||
if (!executedDropErrorOnce) { | ||
this.uppy.info(error.message, 'error') | ||
executedDropErrorOnce = true | ||
} | ||
} | ||
// Add all dropped files | ||
const files = await getDroppedFiles(event.dataTransfer, { logDropError }) | ||
if (files.length > 0) { | ||
this.uppy.log('[Dashboard] Files dropped') | ||
this.addFiles(files) | ||
} | ||
this.opts.onDrop?.(event) | ||
} | ||
handleRequestThumbnail = (file) => { | ||
if (!this.opts.waitForThumbnailsBeforeUpload) { | ||
this.uppy.emit('thumbnail:request', file) | ||
} | ||
} | ||
/** | ||
* We cancel thumbnail requests when a file item component unmounts to avoid | ||
* clogging up the queue when the user scrolls past many elements. | ||
*/ | ||
handleCancelThumbnail = (file) => { | ||
if (!this.opts.waitForThumbnailsBeforeUpload) { | ||
this.uppy.emit('thumbnail:cancel', file) | ||
} | ||
} | ||
handleKeyDownInInline = (event) => { | ||
// Trap focus on tab key press. | ||
if (event.keyCode === TAB_KEY) trapFocus.forInline(event, this.getPluginState().activeOverlayType, this.el) | ||
} | ||
// ___Why do we listen to the 'paste' event on a document instead of onPaste={props.handlePaste} prop, | ||
// or this.el.addEventListener('paste')? | ||
// Because (at least) Chrome doesn't handle paste if focus is on some button, e.g. 'My Device'. | ||
// => Therefore, the best option is to listen to all 'paste' events, and only react to them when we are focused on our | ||
// particular Uppy instance. | ||
// ___Why do we still need onPaste={props.handlePaste} for the DashboardUi? | ||
// Because if we click on the 'Drop files here' caption e.g., `document.activeElement` will be 'body'. Which means our | ||
// standard determination of whether we're pasting into our Uppy instance won't work. | ||
// => Therefore, we need a traditional onPaste={props.handlePaste} handler too. | ||
handlePasteOnBody = (event) => { | ||
const isFocusInOverlay = this.el.contains(document.activeElement) | ||
if (isFocusInOverlay) { | ||
this.handlePaste(event) | ||
} | ||
} | ||
handleComplete = ({ failed }) => { | ||
if (this.opts.closeAfterFinish && failed.length === 0) { | ||
// All uploads are done | ||
this.requestCloseModal() | ||
} | ||
} | ||
handleCancelRestore = () => { | ||
this.uppy.emit('restore-canceled') | ||
} | ||
#openFileEditorWhenFilesAdded = (files) => { | ||
const firstFile = files[0] | ||
if (this.canEditFile(firstFile)) { | ||
this.openFileEditor(firstFile) | ||
} | ||
} | ||
initEvents = () => { | ||
// Modal open button | ||
if (this.opts.trigger && !this.opts.inline) { | ||
const showModalTrigger = findAllDOMElements(this.opts.trigger) | ||
if (showModalTrigger) { | ||
showModalTrigger.forEach(trigger => trigger.addEventListener('click', this.openModal)) | ||
} else { | ||
this.uppy.log('Dashboard modal trigger not found. Make sure `trigger` is set in Dashboard options, unless you are planning to call `dashboard.openModal()` method yourself', 'warning') | ||
} | ||
} | ||
this.startListeningToResize() | ||
document.addEventListener('paste', this.handlePasteOnBody) | ||
this.uppy.on('plugin-remove', this.removeTarget) | ||
this.uppy.on('file-added', this.hideAllPanels) | ||
this.uppy.on('dashboard:modal-closed', this.hideAllPanels) | ||
this.uppy.on('file-editor:complete', this.hideAllPanels) | ||
this.uppy.on('complete', this.handleComplete) | ||
// ___Why fire on capture? | ||
// Because this.ifFocusedOnUppyRecently needs to change before onUpdate() fires. | ||
document.addEventListener('focus', this.recordIfFocusedOnUppyRecently, true) | ||
document.addEventListener('click', this.recordIfFocusedOnUppyRecently, true) | ||
if (this.opts.inline) { | ||
this.el.addEventListener('keydown', this.handleKeyDownInInline) | ||
} | ||
if (this.opts.autoOpenFileEditor) { | ||
this.uppy.on('files-added', this.#openFileEditorWhenFilesAdded) | ||
} | ||
} | ||
removeEvents = () => { | ||
const showModalTrigger = findAllDOMElements(this.opts.trigger) | ||
if (!this.opts.inline && showModalTrigger) { | ||
showModalTrigger.forEach(trigger => trigger.removeEventListener('click', this.openModal)) | ||
} | ||
this.stopListeningToResize() | ||
document.removeEventListener('paste', this.handlePasteOnBody) | ||
window.removeEventListener('popstate', this.handlePopState, false) | ||
this.uppy.off('plugin-remove', this.removeTarget) | ||
this.uppy.off('file-added', this.hideAllPanels) | ||
this.uppy.off('dashboard:modal-closed', this.hideAllPanels) | ||
this.uppy.off('file-editor:complete', this.hideAllPanels) | ||
this.uppy.off('complete', this.handleComplete) | ||
document.removeEventListener('focus', this.recordIfFocusedOnUppyRecently) | ||
document.removeEventListener('click', this.recordIfFocusedOnUppyRecently) | ||
if (this.opts.inline) { | ||
this.el.removeEventListener('keydown', this.handleKeyDownInInline) | ||
} | ||
if (this.opts.autoOpenFileEditor) { | ||
this.uppy.off('files-added', this.#openFileEditorWhenFilesAdded) | ||
} | ||
} | ||
superFocusOnEachUpdate = () => { | ||
const isFocusInUppy = this.el.contains(document.activeElement) | ||
// When focus is lost on the page (== focus is on body for most browsers, or focus is null for IE11) | ||
const isFocusNowhere = document.activeElement === document.body || document.activeElement === null | ||
const isInformerHidden = this.uppy.getState().info.length === 0 | ||
const isModal = !this.opts.inline | ||
if ( | ||
// If update is connected to showing the Informer - let the screen reader calmly read it. | ||
isInformerHidden | ||
&& ( | ||
// If we are in a modal - always superfocus without concern for other elements | ||
// on the page (user is unlikely to want to interact with the rest of the page) | ||
isModal | ||
// If we are already inside of Uppy, or | ||
|| isFocusInUppy | ||
// If we are not focused on anything BUT we have already, at least once, focused on uppy | ||
// 1. We focus when isFocusNowhere, because when the element we were focused | ||
// on disappears (e.g. an overlay), - focus gets lost. If user is typing | ||
// something somewhere else on the page, - focus won't be 'nowhere'. | ||
// 2. We only focus when focus is nowhere AND this.ifFocusedOnUppyRecently, | ||
// to avoid focus jumps if we do something else on the page. | ||
// [Practical check] Without '&& this.ifFocusedOnUppyRecently', in Safari, in inline mode, | ||
// when file is uploading, - navigate via tab to the checkbox, | ||
// try to press space multiple times. Focus will jump to Uppy. | ||
|| (isFocusNowhere && this.ifFocusedOnUppyRecently) | ||
) | ||
) { | ||
this.superFocus(this.el, this.getPluginState().activeOverlayType) | ||
} else { | ||
this.superFocus.cancel() | ||
} | ||
} | ||
afterUpdate = () => { | ||
if (this.opts.disabled && !this.dashboardIsDisabled) { | ||
this.disableAllFocusableElements(true) | ||
return | ||
} | ||
if (!this.opts.disabled && this.dashboardIsDisabled) { | ||
this.disableAllFocusableElements(false) | ||
} | ||
this.superFocusOnEachUpdate() | ||
} | ||
saveFileCard = (meta, fileID) => { | ||
this.uppy.setFileMeta(fileID, meta) | ||
this.toggleFileCard(false, fileID) | ||
} | ||
#attachRenderFunctionToTarget = (target) => { | ||
const plugin = this.uppy.getPlugin(target.id) | ||
return { | ||
...target, | ||
icon: plugin.icon || this.opts.defaultPickerIcon, | ||
render: plugin.render, | ||
} | ||
} | ||
#isTargetSupported = (target) => { | ||
const plugin = this.uppy.getPlugin(target.id) | ||
// If the plugin does not provide a `supported` check, assume the plugin works everywhere. | ||
if (typeof plugin.isSupported !== 'function') { | ||
return true | ||
} | ||
return plugin.isSupported() | ||
} | ||
#getAcquirers = memoize((targets) => { | ||
return targets | ||
.filter(target => target.type === 'acquirer' && this.#isTargetSupported(target)) | ||
.map(this.#attachRenderFunctionToTarget) | ||
}) | ||
#getProgressIndicators = memoize((targets) => { | ||
return targets | ||
.filter(target => target.type === 'progressindicator') | ||
.map(this.#attachRenderFunctionToTarget) | ||
}) | ||
#getEditors = memoize((targets) => { | ||
return targets | ||
.filter(target => target.type === 'editor') | ||
.map(this.#attachRenderFunctionToTarget) | ||
}) | ||
render = (state) => { | ||
const pluginState = this.getPluginState() | ||
const { files, capabilities, allowNewUpload } = state | ||
const { | ||
newFiles, | ||
uploadStartedFiles, | ||
completeFiles, | ||
erroredFiles, | ||
inProgressFiles, | ||
inProgressNotPausedFiles, | ||
processingFiles, | ||
isUploadStarted, | ||
isAllComplete, | ||
isAllErrored, | ||
isAllPaused, | ||
} = this.uppy.getObjectOfFilesPerState() | ||
const acquirers = this.#getAcquirers(pluginState.targets) | ||
const progressindicators = this.#getProgressIndicators(pluginState.targets) | ||
const editors = this.#getEditors(pluginState.targets) | ||
let theme | ||
if (this.opts.theme === 'auto') { | ||
theme = capabilities.darkMode ? 'dark' : 'light' | ||
} else { | ||
theme = this.opts.theme | ||
} | ||
if (['files', 'folders', 'both'].indexOf(this.opts.fileManagerSelectionType) < 0) { | ||
this.opts.fileManagerSelectionType = 'files' | ||
// eslint-disable-next-line no-console | ||
console.warn(`Unsupported option for "fileManagerSelectionType". Using default of "${this.opts.fileManagerSelectionType}".`) | ||
} | ||
return DashboardUI({ | ||
state, | ||
isHidden: pluginState.isHidden, | ||
files, | ||
newFiles, | ||
uploadStartedFiles, | ||
completeFiles, | ||
erroredFiles, | ||
inProgressFiles, | ||
inProgressNotPausedFiles, | ||
processingFiles, | ||
isUploadStarted, | ||
isAllComplete, | ||
isAllErrored, | ||
isAllPaused, | ||
totalFileCount: Object.keys(files).length, | ||
totalProgress: state.totalProgress, | ||
allowNewUpload, | ||
acquirers, | ||
theme, | ||
disabled: this.opts.disabled, | ||
disableLocalFiles: this.opts.disableLocalFiles, | ||
direction: this.opts.direction, | ||
activePickerPanel: pluginState.activePickerPanel, | ||
showFileEditor: pluginState.showFileEditor, | ||
saveFileEditor: this.saveFileEditor, | ||
disableAllFocusableElements: this.disableAllFocusableElements, | ||
animateOpenClose: this.opts.animateOpenClose, | ||
isClosing: pluginState.isClosing, | ||
progressindicators, | ||
editors, | ||
autoProceed: this.uppy.opts.autoProceed, | ||
id: this.id, | ||
closeModal: this.requestCloseModal, | ||
handleClickOutside: this.handleClickOutside, | ||
handleInputChange: this.handleInputChange, | ||
handlePaste: this.handlePaste, | ||
inline: this.opts.inline, | ||
showPanel: this.showPanel, | ||
hideAllPanels: this.hideAllPanels, | ||
i18n: this.i18n, | ||
i18nArray: this.i18nArray, | ||
uppy: this.uppy, | ||
note: this.opts.note, | ||
recoveredState: state.recoveredState, | ||
metaFields: pluginState.metaFields, | ||
resumableUploads: capabilities.resumableUploads || false, | ||
individualCancellation: capabilities.individualCancellation, | ||
isMobileDevice: capabilities.isMobileDevice, | ||
fileCardFor: pluginState.fileCardFor, | ||
toggleFileCard: this.toggleFileCard, | ||
toggleAddFilesPanel: this.toggleAddFilesPanel, | ||
showAddFilesPanel: pluginState.showAddFilesPanel, | ||
saveFileCard: this.saveFileCard, | ||
openFileEditor: this.openFileEditor, | ||
canEditFile: this.canEditFile, | ||
width: this.opts.width, | ||
height: this.opts.height, | ||
showLinkToFileUploadResult: this.opts.showLinkToFileUploadResult, | ||
fileManagerSelectionType: this.opts.fileManagerSelectionType, | ||
proudlyDisplayPoweredByUppy: this.opts.proudlyDisplayPoweredByUppy, | ||
hideCancelButton: this.opts.hideCancelButton, | ||
hideRetryButton: this.opts.hideRetryButton, | ||
hidePauseResumeButton: this.opts.hidePauseResumeButton, | ||
showRemoveButtonAfterComplete: this.opts.showRemoveButtonAfterComplete, | ||
containerWidth: pluginState.containerWidth, | ||
containerHeight: pluginState.containerHeight, | ||
areInsidesReadyToBeVisible: pluginState.areInsidesReadyToBeVisible, | ||
isTargetDOMEl: this.isTargetDOMEl, | ||
parentElement: this.el, | ||
allowedFileTypes: this.uppy.opts.restrictions.allowedFileTypes, | ||
maxNumberOfFiles: this.uppy.opts.restrictions.maxNumberOfFiles, | ||
requiredMetaFields: this.uppy.opts.restrictions.requiredMetaFields, | ||
showSelectedFiles: this.opts.showSelectedFiles, | ||
handleCancelRestore: this.handleCancelRestore, | ||
handleRequestThumbnail: this.handleRequestThumbnail, | ||
handleCancelThumbnail: this.handleCancelThumbnail, | ||
// drag props | ||
isDraggingOver: pluginState.isDraggingOver, | ||
handleDragOver: this.handleDragOver, | ||
handleDragLeave: this.handleDragLeave, | ||
handleDrop: this.handleDrop, | ||
}) | ||
} | ||
discoverProviderPlugins = () => { | ||
this.uppy.iteratePlugins((plugin) => { | ||
if (plugin && !plugin.target && plugin.opts && plugin.opts.target === this.constructor) { | ||
this.addTarget(plugin) | ||
} | ||
}) | ||
} | ||
install = () => { | ||
// Set default state for Dashboard | ||
this.setPluginState({ | ||
isHidden: true, | ||
fileCardFor: null, | ||
activeOverlayType: null, | ||
showAddFilesPanel: false, | ||
activePickerPanel: false, | ||
showFileEditor: false, | ||
metaFields: this.opts.metaFields, | ||
targets: [], | ||
// We'll make them visible once .containerWidth is determined | ||
areInsidesReadyToBeVisible: false, | ||
isDraggingOver: false, | ||
}) | ||
const { inline, closeAfterFinish } = this.opts | ||
if (inline && closeAfterFinish) { | ||
throw new Error('[Dashboard] `closeAfterFinish: true` cannot be used on an inline Dashboard, because an inline Dashboard cannot be closed at all. Either set `inline: false`, or disable the `closeAfterFinish` option.') | ||
} | ||
const { allowMultipleUploads, allowMultipleUploadBatches } = this.uppy.opts | ||
if ((allowMultipleUploads || allowMultipleUploadBatches) && closeAfterFinish) { | ||
this.uppy.log('[Dashboard] When using `closeAfterFinish`, we recommended setting the `allowMultipleUploadBatches` option to `false` in the Uppy constructor. See https://uppy.io/docs/uppy/#allowMultipleUploads-true', 'warning') | ||
} | ||
const { target } = this.opts | ||
if (target) { | ||
this.mount(target, this) | ||
} | ||
const plugins = this.opts.plugins || [] | ||
plugins.forEach((pluginID) => { | ||
const plugin = this.uppy.getPlugin(pluginID) | ||
if (plugin) { | ||
plugin.mount(this, plugin) | ||
} | ||
}) | ||
if (!this.opts.disableStatusBar) { | ||
this.uppy.use(StatusBar, { | ||
id: `${this.id}:StatusBar`, | ||
target: this, | ||
hideUploadButton: this.opts.hideUploadButton, | ||
hideRetryButton: this.opts.hideRetryButton, | ||
hidePauseResumeButton: this.opts.hidePauseResumeButton, | ||
hideCancelButton: this.opts.hideCancelButton, | ||
showProgressDetails: this.opts.showProgressDetails, | ||
hideAfterFinish: this.opts.hideProgressAfterFinish, | ||
locale: this.opts.locale, | ||
doneButtonHandler: this.opts.doneButtonHandler, | ||
}) | ||
} | ||
if (!this.opts.disableInformer) { | ||
this.uppy.use(Informer, { | ||
id: `${this.id}:Informer`, | ||
target: this, | ||
}) | ||
} | ||
if (!this.opts.disableThumbnailGenerator) { | ||
this.uppy.use(ThumbnailGenerator, { | ||
id: `${this.id}:ThumbnailGenerator`, | ||
thumbnailWidth: this.opts.thumbnailWidth, | ||
thumbnailHeight: this.opts.thumbnailHeight, | ||
thumbnailType: this.opts.thumbnailType, | ||
waitForThumbnailsBeforeUpload: this.opts.waitForThumbnailsBeforeUpload, | ||
// If we don't block on thumbnails, we can lazily generate them | ||
lazy: !this.opts.waitForThumbnailsBeforeUpload, | ||
}) | ||
} | ||
// Dark Mode / theme | ||
this.darkModeMediaQuery = (typeof window !== 'undefined' && window.matchMedia) | ||
? window.matchMedia('(prefers-color-scheme: dark)') | ||
: null | ||
const isDarkModeOnFromTheStart = this.darkModeMediaQuery ? this.darkModeMediaQuery.matches : false | ||
this.uppy.log(`[Dashboard] Dark mode is ${isDarkModeOnFromTheStart ? 'on' : 'off'}`) | ||
this.setDarkModeCapability(isDarkModeOnFromTheStart) | ||
if (this.opts.theme === 'auto') { | ||
this.darkModeMediaQuery.addListener(this.handleSystemDarkModeChange) | ||
} | ||
this.discoverProviderPlugins() | ||
this.initEvents() | ||
} | ||
uninstall = () => { | ||
if (!this.opts.disableInformer) { | ||
const informer = this.uppy.getPlugin(`${this.id}:Informer`) | ||
// Checking if this plugin exists, in case it was removed by uppy-core | ||
// before the Dashboard was. | ||
if (informer) this.uppy.removePlugin(informer) | ||
} | ||
if (!this.opts.disableStatusBar) { | ||
const statusBar = this.uppy.getPlugin(`${this.id}:StatusBar`) | ||
if (statusBar) this.uppy.removePlugin(statusBar) | ||
} | ||
if (!this.opts.disableThumbnailGenerator) { | ||
const thumbnail = this.uppy.getPlugin(`${this.id}:ThumbnailGenerator`) | ||
if (thumbnail) this.uppy.removePlugin(thumbnail) | ||
} | ||
const plugins = this.opts.plugins || [] | ||
plugins.forEach((pluginID) => { | ||
const plugin = this.uppy.getPlugin(pluginID) | ||
if (plugin) plugin.unmount() | ||
}) | ||
if (this.opts.theme === 'auto') { | ||
this.darkModeMediaQuery.removeListener(this.handleSystemDarkModeChange) | ||
} | ||
this.unmount() | ||
this.removeEvents() | ||
} | ||
} | ||
export { default } from './Dashboard.jsx' |
@@ -1,9 +0,12 @@ | ||
const Core = require('@uppy/core') | ||
const StatusBarPlugin = require('@uppy/status-bar') | ||
const GoogleDrivePlugin = require('@uppy/google-drive') // eslint-disable-line | ||
const DashboardPlugin = require('./index') | ||
import { afterAll, beforeAll, describe, it, expect } from '@jest/globals' | ||
import Core from '@uppy/core' | ||
import StatusBarPlugin from '@uppy/status-bar' | ||
import GoogleDrivePlugin from '@uppy/google-drive' | ||
import resizeObserverPolyfill from 'resize-observer-polyfill' | ||
import DashboardPlugin from '../lib/index.js' | ||
describe('Dashboard', () => { | ||
beforeAll(() => { | ||
globalThis.ResizeObserver = require('resize-observer-polyfill').default || require('resize-observer-polyfill') | ||
globalThis.ResizeObserver = resizeObserverPolyfill.default || resizeObserverPolyfill | ||
}) | ||
@@ -10,0 +13,0 @@ afterAll(() => { |
@@ -1,2 +0,2 @@ | ||
module.exports = { | ||
export default { | ||
strings: { | ||
@@ -3,0 +3,0 @@ // When `inline: false`, used as the screen reader label for the button that closes the modal. |
@@ -11,4 +11,5 @@ /** | ||
*/ | ||
module.exports = function copyToClipboard (textToCopy, fallbackString) { | ||
fallbackString = fallbackString || 'Copy the URL below' | ||
export default function copyToClipboard (textToCopy, fallbackString) { | ||
// TODO: make `fallbackString` an optional parameter instead. | ||
fallbackString ||= 'Copy the URL below' // eslint-disable-line no-param-reassign | ||
@@ -15,0 +16,0 @@ return new Promise((resolve) => { |
@@ -1,2 +0,3 @@ | ||
const copyToClipboard = require('./copyToClipboard') | ||
import { describe, xit, expect } from '@jest/globals' | ||
import copyToClipboard from './copyToClipboard.js' | ||
@@ -3,0 +4,0 @@ describe('copyToClipboard', () => { |
@@ -1,4 +0,4 @@ | ||
const debounce = require('lodash.debounce') | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS') | ||
const getActiveOverlayEl = require('./getActiveOverlayEl') | ||
import debounce from 'lodash.debounce' | ||
import FOCUSABLE_ELEMENTS from '@uppy/utils/lib/FOCUSABLE_ELEMENTS' | ||
import getActiveOverlayEl from './getActiveOverlayEl.js' | ||
@@ -15,3 +15,3 @@ /* | ||
*/ | ||
module.exports = function createSuperFocus () { | ||
export default function createSuperFocus () { | ||
let lastFocusWasOnSuperFocusableEl = false | ||
@@ -18,0 +18,0 @@ |
@@ -1,2 +0,3 @@ | ||
const createSuperFocus = require('./createSuperFocus') | ||
import { describe, it, expect } from '@jest/globals' | ||
import createSuperFocus from './createSuperFocus.js' | ||
@@ -3,0 +4,0 @@ describe('createSuperFocus', () => { |
/** | ||
* @returns {HTMLElement} - either dashboard element, or the overlay that's most on top | ||
*/ | ||
module.exports = function getActiveOverlayEl (dashboardEl, activeOverlayType) { | ||
export default function getActiveOverlayEl (dashboardEl, activeOverlayType) { | ||
if (activeOverlayType) { | ||
@@ -6,0 +6,0 @@ const overlayEl = dashboardEl.querySelector(`[data-uppy-paneltype="${activeOverlayType}"]`) |
@@ -17,2 +17,2 @@ // ignore drop/paste events if they are not in input or textarea — | ||
module.exports = ignoreEvent | ||
export default ignoreEvent |
@@ -1,4 +0,4 @@ | ||
const toArray = require('@uppy/utils/lib/toArray') | ||
const FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS') | ||
const getActiveOverlayEl = require('./getActiveOverlayEl') | ||
import toArray from '@uppy/utils/lib/toArray' | ||
import FOCUSABLE_ELEMENTS from '@uppy/utils/lib/FOCUSABLE_ELEMENTS' | ||
import getActiveOverlayEl from './getActiveOverlayEl.js' | ||
@@ -52,21 +52,17 @@ function focusOnFirstNode (event, nodes) { | ||
module.exports = { | ||
// Traps focus inside of the currently open overlay (e.g. Dashboard, or e.g. Instagram), | ||
// never lets focus disappear from the modal. | ||
forModal: (event, activeOverlayType, dashboardEl) => { | ||
trapFocus(event, activeOverlayType, dashboardEl) | ||
}, | ||
// Traps focus inside of the currently open overlay (e.g. Dashboard, or e.g. Instagram), | ||
// never lets focus disappear from the modal. | ||
export { trapFocus as forModal } | ||
// Traps focus inside of the currently open overlay, unless overlay is null - then let the user tab away. | ||
forInline: (event, activeOverlayType, dashboardEl) => { | ||
// ___When we're in the bare 'Drop files here, paste, browse or import from' screen | ||
if (activeOverlayType === null) { | ||
// Do nothing and let the browser handle it, user can tab away from Uppy to other elements on the page | ||
// Traps focus inside of the currently open overlay, unless overlay is null - then let the user tab away. | ||
export function forInline (event, activeOverlayType, dashboardEl) { | ||
// ___When we're in the bare 'Drop files here, paste, browse or import from' screen | ||
if (activeOverlayType === null) { | ||
// Do nothing and let the browser handle it, user can tab away from Uppy to other elements on the page | ||
// ___When there is some overlay with 'Done' button | ||
} else { | ||
// Trap the focus inside this overlay! | ||
// User can close the overlay (click 'Done') if they want to travel away from Uppy. | ||
trapFocus(event, activeOverlayType, dashboardEl) | ||
} | ||
}, | ||
} else { | ||
// Trap the focus inside this overlay! | ||
// User can close the overlay (click 'Done') if they want to travel away from Uppy. | ||
trapFocus(event, activeOverlayType, dashboardEl) | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
649307
98
9536
2
Yes
4
51
Updated@uppy/informer@^2.1.0
Updated@uppy/provider-views@^2.1.1
Updated@uppy/status-bar@^2.2.1
Updated@uppy/utils@^4.1.0