@uppy/webcam
Advanced tools
Comparing version 3.3.1 to 3.3.2
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } | ||
/* eslint-disable jsx-a11y/media-has-caption */ | ||
@@ -11,7 +10,5 @@ import { h, Component } from 'preact'; | ||
import DiscardButton from "./DiscardButton.js"; | ||
function isModeAvailable(modes, mode) { | ||
return modes.includes(mode); | ||
} | ||
class CameraScreen extends Component { | ||
@@ -24,3 +21,2 @@ componentDidMount() { | ||
} | ||
componentWillUnmount() { | ||
@@ -32,3 +28,2 @@ const { | ||
} | ||
render() { | ||
@@ -61,8 +56,8 @@ const { | ||
}; | ||
if (recordedVideo) { | ||
videoProps.muted = false; | ||
videoProps.controls = true; | ||
videoProps.src = recordedVideo; // reset srcObject in dom. If not resetted, stream sticks in element | ||
videoProps.src = recordedVideo; | ||
// reset srcObject in dom. If not resetted, stream sticks in element | ||
if (this.videoElement) { | ||
@@ -76,3 +71,2 @@ this.videoElement.srcObject = undefined; | ||
} | ||
return h("div", { | ||
@@ -87,3 +81,2 @@ className: "uppy uppy-Webcam-container" | ||
/* eslint-disable-next-line react/jsx-props-no-spreading */ | ||
}, videoProps))), h("div", { | ||
@@ -116,5 +109,3 @@ className: "uppy-Webcam-footer" | ||
} | ||
} | ||
export default CameraScreen; |
import { h } from 'preact'; | ||
function DiscardButton(_ref) { | ||
@@ -32,3 +31,2 @@ let { | ||
} | ||
export default DiscardButton; |
@@ -9,3 +9,2 @@ import { h } from 'preact'; | ||
} = _ref; | ||
if (recording) { | ||
@@ -33,3 +32,2 @@ return h("button", { | ||
} | ||
return h("button", { | ||
@@ -36,0 +34,0 @@ className: "uppy-u-reset uppy-c-btn uppy-Webcam-button", |
import { h } from 'preact'; | ||
function SubmitButton(_ref) { | ||
@@ -29,3 +28,2 @@ let { | ||
} | ||
export default SubmitButton; |
function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); } | ||
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; } | ||
import { h } from 'preact'; | ||
@@ -20,5 +16,6 @@ import { UIPlugin } from '@uppy/core'; | ||
const packageJson = { | ||
"version": "3.3.1" | ||
"version": "3.3.2" | ||
}; | ||
import locale from './locale.js'; | ||
/** | ||
@@ -30,3 +27,2 @@ * Normalize a MIME type or file extension into a MIME type. | ||
*/ | ||
function toMimeType(fileType) { | ||
@@ -36,5 +32,5 @@ if (fileType[0] === '.') { | ||
} | ||
return fileType; | ||
} | ||
/** | ||
@@ -46,7 +42,6 @@ * Is this MIME type a video? | ||
*/ | ||
function isVideoMimeType(mimeType) { | ||
return /^video\/[^*]+$/.test(mimeType); | ||
} | ||
/** | ||
@@ -58,8 +53,5 @@ * Is this MIME type an image? | ||
*/ | ||
function isImageMimeType(mimeType) { | ||
return /^image\/[^*]+$/.test(mimeType); | ||
} | ||
function getMediaDevices() { | ||
@@ -70,18 +62,15 @@ // bug in the compatibility data | ||
} | ||
function isModeAvailable(modes, mode) { | ||
return modes.includes(mode); | ||
} | ||
/** | ||
* Webcam | ||
*/ | ||
var _enableMirror = /*#__PURE__*/_classPrivateFieldLooseKey("enableMirror"); | ||
export default class Webcam extends UIPlugin { | ||
// enableMirror is used to toggle mirroring, for instance when discarding the video, | ||
// while `opts.mirror` is used to remember the initial user setting | ||
constructor(uppy, opts) { | ||
super(uppy, opts); | ||
// enableMirror is used to toggle mirroring, for instance when discarding the video, | ||
// while `opts.mirror` is used to remember the initial user setting | ||
Object.defineProperty(this, _enableMirror, { | ||
@@ -92,4 +81,4 @@ writable: true, | ||
this.mediaDevices = getMediaDevices(); | ||
this.supportsUserMedia = !!this.mediaDevices; // eslint-disable-next-line no-restricted-globals | ||
this.supportsUserMedia = !!this.mediaDevices; | ||
// eslint-disable-next-line no-restricted-globals | ||
this.protocol = location.protocol.match(/https/i) ? 'https' : 'http'; | ||
@@ -99,3 +88,2 @@ this.id = this.opts.id || 'Webcam'; | ||
this.capturedMediaFile = null; | ||
this.icon = () => h("svg", { | ||
@@ -112,5 +100,5 @@ "aria-hidden": "true", | ||
})); | ||
this.defaultLocale = locale; | ||
this.defaultLocale = locale; // set default options | ||
// set default options | ||
const defaultOptions = { | ||
@@ -132,3 +120,4 @@ onBeforeSnapshot: () => Promise.resolve(), | ||
}; | ||
this.opts = { ...defaultOptions, | ||
this.opts = { | ||
...defaultOptions, | ||
...opts | ||
@@ -141,4 +130,5 @@ }; | ||
this.setPluginState = this.setPluginState.bind(this); | ||
this.render = this.render.bind(this); // Camera controls | ||
this.render = this.render.bind(this); | ||
// Camera controls | ||
this.start = this.start.bind(this); | ||
@@ -155,7 +145,5 @@ this.stop = this.stop.bind(this); | ||
this.webcamActive = false; | ||
if (this.opts.countdown) { | ||
this.opts.onBeforeSnapshot = this.oneTwoThreeSmile; | ||
} | ||
this.setPluginState({ | ||
@@ -170,6 +158,7 @@ hasCamera: false, | ||
} | ||
setOptions(newOpts) { | ||
super.setOptions({ ...newOpts, | ||
videoConstraints: { // May be undefined but ... handles that | ||
super.setOptions({ | ||
...newOpts, | ||
videoConstraints: { | ||
// May be undefined but ... handles that | ||
...this.opts.videoConstraints, | ||
@@ -180,3 +169,2 @@ ...(newOpts == null ? void 0 : newOpts.videoConstraints) | ||
} | ||
hasCameraCheck() { | ||
@@ -186,3 +174,2 @@ if (!this.mediaDevices) { | ||
} | ||
return this.mediaDevices.enumerateDevices().then(devices => { | ||
@@ -192,7 +179,5 @@ return devices.some(device => device.kind === 'videoinput'); | ||
} | ||
isAudioOnly() { | ||
return this.opts.modes.length === 1 && this.opts.modes[0] === 'audio-only'; | ||
} | ||
getConstraints(deviceId) { | ||
@@ -202,6 +187,6 @@ if (deviceId === void 0) { | ||
} | ||
const acceptsAudio = this.opts.modes.indexOf('video-audio') !== -1 || this.opts.modes.indexOf('audio-only') !== -1; | ||
const acceptsVideo = !this.isAudioOnly() && (this.opts.modes.indexOf('video-audio') !== -1 || this.opts.modes.indexOf('video-only') !== -1 || this.opts.modes.indexOf('picture') !== -1); | ||
const videoConstraints = { ...(this.opts.videoConstraints || { | ||
const videoConstraints = { | ||
...(this.opts.videoConstraints || { | ||
facingMode: this.opts.facingMode | ||
@@ -220,5 +205,5 @@ }), | ||
}; | ||
} // eslint-disable-next-line consistent-return | ||
} | ||
// eslint-disable-next-line consistent-return | ||
start(options) { | ||
@@ -228,13 +213,9 @@ if (options === void 0) { | ||
} | ||
if (!this.supportsUserMedia) { | ||
return Promise.reject(new Error('Webcam access not supported')); | ||
} | ||
this.webcamActive = true; | ||
if (this.opts.mirror) { | ||
_classPrivateFieldLooseBase(this, _enableMirror)[_enableMirror] = true; | ||
} | ||
const constraints = this.getConstraints(options && options.deviceId ? options.deviceId : null); | ||
@@ -244,4 +225,5 @@ this.hasCameraCheck().then(hasCamera => { | ||
hasCamera | ||
}); // ask user for access to their camera | ||
}); | ||
// ask user for access to their camera | ||
return this.mediaDevices.getUserMedia(constraints).then(stream => { | ||
@@ -251,3 +233,2 @@ this.stream = stream; | ||
const tracks = this.isAudioOnly() ? stream.getAudioTracks() : stream.getVideoTracks(); | ||
if (!options || !options.deviceId) { | ||
@@ -261,5 +242,5 @@ currentDeviceId = tracks[0].getSettings().deviceId; | ||
}); | ||
} // Update the sources now, so we can access the names. | ||
} | ||
// Update the sources now, so we can access the names. | ||
this.updateVideoSources(); | ||
@@ -279,12 +260,12 @@ this.setPluginState({ | ||
} | ||
/** | ||
* @returns {object} | ||
*/ | ||
getMediaRecorderOptions() { | ||
const options = {}; | ||
getMediaRecorderOptions() { | ||
const options = {}; // Try to use the `opts.preferredVideoMimeType` or one of the `allowedFileTypes` for the recording. | ||
// Try to use the `opts.preferredVideoMimeType` or one of the `allowedFileTypes` for the recording. | ||
// If the browser doesn't support it, we'll fall back to the browser default instead. | ||
// Safari doesn't have the `isTypeSupported` API. | ||
if (MediaRecorder.isTypeSupported) { | ||
@@ -295,3 +276,2 @@ const { | ||
let preferredVideoMimeTypes = []; | ||
if (this.opts.preferredVideoMimeType) { | ||
@@ -302,7 +282,4 @@ preferredVideoMimeTypes = [this.opts.preferredVideoMimeType]; | ||
} | ||
const filterSupportedTypes = candidateType => MediaRecorder.isTypeSupported(candidateType) && getFileTypeExtension(candidateType); | ||
const acceptableMimeTypes = preferredVideoMimeTypes.filter(filterSupportedTypes); | ||
if (acceptableMimeTypes.length > 0) { | ||
@@ -313,6 +290,4 @@ // eslint-disable-next-line prefer-destructuring | ||
} | ||
return options; | ||
} | ||
startRecording() { | ||
@@ -329,10 +304,8 @@ // only used if supportsMediaRecorder() returned true | ||
} = this.uppy.opts; | ||
if (this.recordingChunks.length > 1 && restrictions.maxFileSize != null && !stoppingBecauseOfMaxSize) { | ||
const totalSize = this.recordingChunks.reduce((acc, chunk) => acc + chunk.size, 0); // Exclude the initial chunk from the average size calculation because it is likely to be a very small outlier | ||
const totalSize = this.recordingChunks.reduce((acc, chunk) => acc + chunk.size, 0); | ||
// Exclude the initial chunk from the average size calculation because it is likely to be a very small outlier | ||
const averageChunkSize = (totalSize - this.recordingChunks[0].size) / (this.recordingChunks.length - 1); | ||
const expectedEndChunkSize = averageChunkSize * 3; | ||
const maxSize = Math.max(0, restrictions.maxFileSize - expectedEndChunkSize); | ||
if (totalSize > maxSize) { | ||
@@ -344,7 +317,7 @@ stoppingBecauseOfMaxSize = true; | ||
} | ||
}); // use a "time slice" of 500ms: ondataavailable will be called each 500ms | ||
}); | ||
// use a "time slice" of 500ms: ondataavailable will be called each 500ms | ||
// smaller time slices mean we can more accurately check the max file size restriction | ||
this.recorder.start(500); | ||
if (this.opts.showRecordingLength) { | ||
@@ -359,3 +332,2 @@ // Start the recordingLengthTimer if we are showing the recording length. | ||
} | ||
this.setPluginState({ | ||
@@ -365,3 +337,2 @@ isRecording: true | ||
} | ||
stopRecording() { | ||
@@ -373,3 +344,2 @@ const stopped = new Promise(resolve => { | ||
this.recorder.stop(); | ||
if (this.opts.showRecordingLength) { | ||
@@ -390,4 +360,4 @@ // Stop the recordingLengthTimer if we are showing the recording length. | ||
try { | ||
this.capturedMediaFile = file; // create object url for capture result preview | ||
this.capturedMediaFile = file; | ||
// create object url for capture result preview | ||
this.setPluginState({ | ||
@@ -413,3 +383,2 @@ // eslint-disable-next-line compat/compat | ||
} | ||
discardRecordedVideo() { | ||
@@ -419,10 +388,7 @@ this.setPluginState({ | ||
}); | ||
if (this.opts.mirror) { | ||
_classPrivateFieldLooseBase(this, _enableMirror)[_enableMirror] = true; | ||
} | ||
this.capturedMediaFile = null; | ||
} | ||
submit() { | ||
@@ -440,3 +406,2 @@ try { | ||
} | ||
async stop() { | ||
@@ -448,3 +413,2 @@ if (this.stream) { | ||
} | ||
if (this.recorder) { | ||
@@ -456,3 +420,2 @@ await new Promise(resolve => { | ||
this.recorder.stop(); | ||
if (this.opts.showRecordingLength) { | ||
@@ -463,3 +426,2 @@ clearInterval(this.recordingLengthTimer); | ||
} | ||
this.recordingChunks = null; | ||
@@ -475,11 +437,10 @@ this.recorder = null; | ||
} | ||
getVideoElement() { | ||
return this.el.querySelector('.uppy-Webcam-video'); | ||
} | ||
oneTwoThreeSmile() { | ||
return new Promise((resolve, reject) => { | ||
let count = this.opts.countdown; // eslint-disable-next-line consistent-return | ||
let count = this.opts.countdown; | ||
// eslint-disable-next-line consistent-return | ||
const countDown = setInterval(() => { | ||
@@ -491,3 +452,2 @@ if (!this.webcamActive) { | ||
} | ||
if (count > 0) { | ||
@@ -504,3 +464,2 @@ this.uppy.info(`${count}...`, 'warning', 800); | ||
} | ||
takeSnapshot() { | ||
@@ -517,3 +476,2 @@ if (this.captureInProgress) return; | ||
this.captureInProgress = false; | ||
try { | ||
@@ -532,10 +490,7 @@ this.uppy.addFile(tagFile); | ||
} | ||
getImage() { | ||
const video = this.getVideoElement(); | ||
if (!video) { | ||
return Promise.reject(new Error('No video element found, likely due to the Webcam tab being closed.')); | ||
} | ||
const width = video.videoWidth; | ||
@@ -552,3 +507,2 @@ const height = video.videoHeight; | ||
let preferredImageMimeTypes = []; | ||
if (this.opts.preferredImageMimeType) { | ||
@@ -559,3 +513,2 @@ preferredImageMimeTypes = [this.opts.preferredImageMimeType]; | ||
} | ||
const mimeType = preferredImageMimeTypes[0] || 'image/jpeg'; | ||
@@ -575,3 +528,2 @@ const ext = getFileTypeExtension(mimeType) || 'jpg'; | ||
} | ||
getVideo() { | ||
@@ -583,11 +535,8 @@ // Sometimes in iOS Safari, Blobs (especially the first Blob in the recordingChunks Array) | ||
var _blob$type; | ||
return ((_blob$type = blob.type) == null ? void 0 : _blob$type.length) > 0; | ||
}).type; | ||
const fileExtension = getFileTypeExtension(mimeType); | ||
if (!fileExtension) { | ||
return Promise.reject(new Error(`Could not retrieve recording: Unsupported media type "${mimeType}"`)); | ||
} | ||
const name = `webcam-${Date.now()}.${fileExtension}`; | ||
@@ -607,3 +556,2 @@ const blob = new Blob(this.recordingChunks, { | ||
} | ||
focus() { | ||
@@ -615,3 +563,2 @@ if (!this.opts.countdown) return; | ||
} | ||
changeVideoSource(deviceId) { | ||
@@ -623,3 +570,2 @@ this.stop(); | ||
} | ||
updateVideoSources() { | ||
@@ -632,3 +578,2 @@ this.mediaDevices.enumerateDevices().then(devices => { | ||
} | ||
render() { | ||
@@ -638,5 +583,3 @@ if (!this.webcamActive) { | ||
} | ||
const webcamState = this.getPluginState(); | ||
if (!webcamState.cameraReady || !webcamState.hasCamera) { | ||
@@ -649,4 +592,4 @@ return h(PermissionsScreen, { | ||
} | ||
return h(CameraScreen // eslint-disable-next-line react/jsx-props-no-spreading | ||
return h(CameraScreen | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
, _extends({}, webcamState, { | ||
@@ -671,3 +614,2 @@ onChangeVideoSource: this.changeVideoSource, | ||
} | ||
install() { | ||
@@ -683,6 +625,4 @@ const { | ||
} = this.opts; | ||
if (mobileNativeCamera && target) { | ||
var _this$getTargetPlugin; | ||
(_this$getTargetPlugin = this.getTargetPlugin(target)) == null ? void 0 : _this$getTargetPlugin.setOptions({ | ||
@@ -695,3 +635,2 @@ showNativeVideoCameraButton: isModeAvailable(modes, 'video-only') || isModeAvailable(modes, 'video-audio'), | ||
} | ||
this.setPluginState({ | ||
@@ -701,13 +640,9 @@ cameraReady: false, | ||
}); | ||
if (target) { | ||
this.mount(target, this); | ||
} | ||
if (this.mediaDevices) { | ||
this.updateVideoSources(); | ||
this.mediaDevices.ondevicechange = () => { | ||
this.updateVideoSources(); | ||
if (this.stream) { | ||
@@ -724,3 +659,2 @@ let restartStream = true; | ||
}); | ||
if (restartStream) { | ||
@@ -734,3 +668,2 @@ this.stop(); | ||
} | ||
uninstall() { | ||
@@ -740,8 +673,6 @@ this.stop(); | ||
} | ||
onUnmount() { | ||
this.stop(); | ||
} | ||
} | ||
Webcam.VERSION = packageJson.version; |
{ | ||
"name": "@uppy/webcam", | ||
"description": "Uppy plugin that takes photos or records videos using the device's camera.", | ||
"version": "3.3.1", | ||
"version": "3.3.2", | ||
"license": "MIT", | ||
@@ -30,3 +30,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@uppy/utils": "^5.3.0", | ||
"@uppy/utils": "^5.4.3", | ||
"is-mobile": "^3.1.1", | ||
@@ -39,4 +39,4 @@ "preact": "^10.5.13" | ||
"peerDependencies": { | ||
"@uppy/core": "^3.2.0" | ||
"@uppy/core": "^3.4.0" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import type { PluginOptions, UIPlugin, PluginTarget } from '@uppy/core' | ||
import type { PluginTarget, UIPlugin, UIPluginOptions } from '@uppy/core' | ||
import WebcamLocale from './generatedLocale' | ||
@@ -10,3 +10,3 @@ | ||
export interface WebcamOptions extends PluginOptions { | ||
export interface WebcamOptions extends UIPluginOptions { | ||
target?: PluginTarget | ||
@@ -13,0 +13,0 @@ onBeforeSnapshot?: () => Promise<void> |
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
150792
2146
Updated@uppy/utils@^5.4.3