UNPKG

@daily-co/daily-react

Version:

Daily React makes it easier to integrate [@daily-co/daily-js](https://www.npmjs.com/package/@daily-co/daily-js) in React applications.

1,426 lines (1,382 loc) 158 kB
import { atomFamily, useAtomCallback } from 'jotai/utils'; import React, { createContext, useContext, useDebugValue, useState, useRef, useMemo, useEffect, useCallback, memo, forwardRef, useImperativeHandle } from 'react'; import { atom, useAtomValue, Provider, useAtom } from 'jotai'; import Daily from '@daily-co/daily-js'; function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } var _assign = function __assign() { _assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return _assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function sent() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function next() { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var DailyContext = createContext(null); /** * Returns callObject instance passed to or created by closest <DailyProvider>. */ var useDaily = function useDaily() { var daily = useContext(DailyContext); useDebugValue(daily); return daily; }; var DailyEventContext = createContext({ on: function on() {}, off: function off() {} }); var priorityCounter = -1; var getPriorityUnique = function getPriorityUnique() { return priorityCounter--; }; var uniqueCounter = 1; var getUnique = function getUnique() { return uniqueCounter++; }; /** * Sets up a daily event listener using [on](https://docs.daily.co/reference/daily-js/instance-methods/on) method. * When this hook is unmounted the event listener is unregistered using [off](https://docs.daily.co/reference/daily-js/instance-methods/off). * * Warning: callback has to be a memoized reference (e.g. via [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)). * Otherwise a console error might be thrown indicating a re-render loop issue. * * @param ev The DailyEvent to register. * @param callback A memoized callback reference to run when the event is emitted. */ var useDailyEvent = function useDailyEvent(ev, callback, INTERNAL_priority) { if (INTERNAL_priority === void 0) { INTERNAL_priority = false; } var _a = useContext(DailyEventContext), off = _a.off, on = _a.on; var _b = __read(useState(false), 2), isBlocked = _b[0], setIsBlocked = _b[1]; var reassignCount = useRef(0); var eventId = useMemo(function () { return INTERNAL_priority ? getPriorityUnique() : getUnique(); }, [INTERNAL_priority]); useEffect(function () { if (!ev || isBlocked) return; /** * Check if callback has been reassigned often enough without hitting the 50ms timeout. */ if (reassignCount.current > 100000) { console.error("useDailyEvent called with potentially non-memoized event callback or due to too many re-renders.\n Memoize using useCallback to avoid re-render loop or reduce the amount of state transitions the callback depends on.\n Passed callback for '".concat(ev, "' event is NOT registered."), callback); setIsBlocked(true); return; } reassignCount.current++; var timeout = setTimeout(function () { reassignCount.current = 0; }, 50); on(ev, callback, eventId); return function () { clearTimeout(timeout); off(ev, eventId); }; }, [callback, ev, eventId, isBlocked, off, on]); useDebugValue({ event: ev, eventId: eventId, isBlocked: isBlocked, callback: callback }); }; /** * Compares two variables for deep equality. * Gracefully handles equality checks on MediaStreamTracks by comparing their ids. */ function customDeepEqual(a, b) { var e_1, _a; if (a === b) return true; // Handle arrays separately if (Array.isArray(a) && Array.isArray(b)) { if (a.length !== b.length) return false; for (var i = 0; i < a.length; i++) { if (!customDeepEqual(a[i], b[i])) return false; } return true; } // Handle specific cases like MediaStream, MediaStreamTrack, Date, etc. if (MediaStream) { if (a instanceof MediaStream && b instanceof MediaStream) { return a.id === b.id && a.active === b.active && a.getTracks().length === b.getTracks().length && a.getTracks().every(function (track, idx) { return customDeepEqual(track, b.getTracks()[idx]); }); } } // Handle special case for MediaStreamTrack if (MediaStreamTrack) { if (a instanceof MediaStreamTrack && b instanceof MediaStreamTrack) { return a.id === b.id && a.kind === b.kind && a.readyState === b.readyState; } } // Handle special case for Date if (a instanceof Date && b instanceof Date) { return a.getTime() === b.getTime(); } // Handle special case for RegExp if (a instanceof RegExp && b instanceof RegExp) { return a.source === b.source && a.flags === b.flags; } // Handle Set comparisons if (a instanceof Set && b instanceof Set) { if (a.size !== b.size) return false; var arrA = Array.from(a).sort(); var arrB_1 = Array.from(b).sort(); return arrA.every(function (val, idx) { return customDeepEqual(val, arrB_1[idx]); }); } // Handle Map comparisons if (a instanceof Map && b instanceof Map) { if (a.size !== b.size) return false; try { for (var _b = __values(a.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), key = _d[0], value = _d[1]; if (!b.has(key) || !customDeepEqual(value, b.get(key))) return false; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b["return"])) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return true; } // Primitive types and null checks if (_typeof(a) !== 'object' || a === null || _typeof(b) !== 'object' || b === null) { return false; } // Generic object handling var keysA = Object.keys(a); var keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; for (var i = 0; i < keysA.length; i++) { var key = keysA[i]; if (!Object.prototype.hasOwnProperty.call(b, key) || !customDeepEqual(a[key], b[key])) { return false; } } // All keys and values match -> the objects are deeply equal return true; } /** * Comparison function optimized for comparing arrays. */ function arraysDeepEqual(a, b) { // Check for reference equality if (a === b) return true; // Check if both arrays are of the same length if (a.length !== b.length) return false; // Compare each element in the array for (var i = 0; i < a.length; i++) { var valueA = a[i]; var valueB = b[i]; var isComplexTypeA = valueA !== null && _typeof(valueA) === 'object'; var isComplexTypeB = valueB !== null && _typeof(valueB) === 'object'; // Use customDeepEqual only if either value is a complex type if (isComplexTypeA || isComplexTypeB) { if (!customDeepEqual(valueA, valueB)) return false; } else if (valueA !== valueB) { return false; } } return true; } function jotaiDebugLabel(label) { return 'daily-react-' + label; } function equalAtomFamily(options) { var atomCache = new Map(); var priorValues = new Map(); return function (param) { if (!atomCache.has(param)) { var baseAtom = atom(function (get) { var derivedValue = options.get(param)(get); var prior = priorValues.get(param); if (prior != null && options.equals(derivedValue, prior)) { return prior; } priorValues.set(param, derivedValue); return derivedValue; }); atomCache.set(param, baseAtom); } return atomCache.get(param); }; } var DELIM = '::'; var PATHS_DELIM = ';'; var getPropertyParam = function getPropertyParam(id, property) { return id + DELIM + property; }; var getPropertiesParam = function getPropertiesParam(id, properties) { return id + DELIM + properties.join(PATHS_DELIM); }; var getParticipantPropertyAtom = function getParticipantPropertyAtom(id, property) { return participantPropertyState(getPropertyParam(id, property)); }; /** * Stores all property paths for a given participant. */ var participantPropertyPathsState = atomFamily(function (id) { var participantPropertyPathsAtom = atom([]); participantPropertyPathsAtom.debugLabel = jotaiDebugLabel("participant-property-paths-".concat(id)); return participantPropertyPathsAtom; }); /** * Stores resolved values for each participant and property path. */ var participantPropertyState = atomFamily(function (param) { var participantPropertyAtom = atom(null); participantPropertyAtom.debugLabel = jotaiDebugLabel("participant-property-".concat(param)); return participantPropertyAtom; }); /** * Stores resolved values for each participant and property path. */ var participantPropertiesState = equalAtomFamily({ equals: arraysDeepEqual, get: function get(param) { return function (get) { var _a = __read(param.split(DELIM), 2), id = _a[0], paths = _a[1]; var properties = paths.split(PATHS_DELIM); return properties.map(function (path) { return get(getParticipantPropertyAtom(id, path)); }); }; } }); /** * Returns a participant's property that you subscribe to. * @param participantId The participant's session_id. * @param propertyPaths the array of participant property that you want to subscribe to. */ var useParticipantProperty = function useParticipantProperty(participantId, propertyPaths) { var _a; var properties = useAtomValue(Array.isArray(propertyPaths) ? participantPropertiesState(getPropertiesParam(participantId, propertyPaths)) : participantPropertyState(getPropertyParam(participantId, propertyPaths))); useDebugValue(Array.isArray(propertyPaths) ? propertyPaths.reduce(function (o, path, i) { o[path] = properties[i]; return o; }, {}) : (_a = {}, _a[propertyPaths] = properties, _a)); return properties; }; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var lodash_throttle; var hasRequiredLodash_throttle; function requireLodash_throttle() { if (hasRequiredLodash_throttle) return lodash_throttle; hasRequiredLodash_throttle = 1; /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used as references for various `Number` constants. */ var NAN = 0 / 0; /** `Object#toString` result references. */ var symbolTag = '[object Symbol]'; /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Built-in method references without a dependency on `root`. */ var freeParseInt = parseInt; /** Detect free variable `global` from Node.js. */ var freeGlobal = _typeof(commonjsGlobal) == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; /** Detect free variable `self`. */ var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max, nativeMin = Math.min; /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = function now() { return root.Date.now(); }; /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * // Avoid costly calculations while the window size is in flux. * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait; } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; } /** * Creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. The throttled function comes with a `cancel` * method to cancel delayed `func` invocations and a `flush` method to * immediately invoke them. Provide `options` to indicate whether `func` * should be invoked on the leading and/or trailing edge of the `wait` * timeout. The `func` is invoked with the last arguments provided to the * throttled function. Subsequent calls to the throttled function return the * result of the last `func` invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the throttled function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.throttle` and `_.debounce`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to throttle. * @param {number} [wait=0] The number of milliseconds to throttle invocations to. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=true] * Specify invoking on the leading edge of the timeout. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * // Avoid excessively updating the position while scrolling. * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); * * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); * jQuery(element).on('click', throttled); * * // Cancel the trailing throttled invocation. * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }); } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = _typeof(value); return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && _typeof(value) == 'object'; } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return _typeof(value) == 'symbol' || isObjectLike(value) && objectToString.call(value) == symbolTag; } /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? other + '' : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value; } lodash_throttle = throttle; return lodash_throttle; } var lodash_throttleExports = requireLodash_throttle(); var throttle = /*@__PURE__*/getDefaultExportFromCjs(lodash_throttleExports); /** * Sets up a throttled daily event listener using [on](https://docs.daily.co/reference/daily-js/instance-methods/on) method. * When this hook is unmounted the event listener is unregistered using [off](https://docs.daily.co/reference/daily-js/instance-methods/off). * * In comparison to useDailyEvent the callback passed here will be called with an array of event objects. * * You can pass an array of DailyEvents to register multiple daily events with a single callback handler. * The events returned in the callback parameter are guaranteed to be in the same order as they were emitted. * * @param ev The DailyEvent to register or an array of DailyEvent to register. * @param callback A memoized callback reference to run when throttled events are emitted. * @param throttleTimeout The minimum waiting time until the callback is called again. Default: 500 */ var useThrottledDailyEvent = function useThrottledDailyEvent(ev, callback, throttleTimeout, INTERNAL_priority) { if (throttleTimeout === void 0) { throttleTimeout = 500; } if (INTERNAL_priority === void 0) { INTERNAL_priority = false; } var _a = useContext(DailyEventContext), off = _a.off, on = _a.on; var eventId = useMemo(function () { var _a; if (Array.isArray(ev)) return ev.reduce(function (r, e) { r[e] = INTERNAL_priority ? getPriorityUnique() : getUnique(); return r; }, {}); return _a = {}, _a[ev] = INTERNAL_priority ? getPriorityUnique() : getUnique(), _a; }, [ev, INTERNAL_priority]); var throttledEvents = useRef([]); useDailyEvent('call-instance-destroyed', useCallback(function () { throttledEvents.current.length = 0; }, [])); var emitEvents = useMemo(function () { return throttle(function () { if (throttledEvents.current.length === 0) return; callback(throttledEvents.current); throttledEvents.current.length = 0; }, throttleTimeout, { trailing: true }); }, [callback, throttleTimeout]); useEffect(function () { if (!ev) return; var addEvent = function addEvent(ev) { throttledEvents.current.push(ev); emitEvents(); }; if (Array.isArray(ev)) { ev.forEach(function (e) { return on(e, addEvent, eventId[e]); }); } else { on(ev, addEvent, eventId[ev]); } return function () { if (Array.isArray(ev)) { ev.forEach(function (e) { return off(e, eventId[e]); }); } else { off(ev, eventId[ev]); } }; }, [emitEvents, ev, eventId, off, on]); useDebugValue({ event: ev, eventId: eventId }); }; /** * Returns all property paths for an object. */ var _getPaths = function getPaths(o, currentPath, visited) { if (currentPath === void 0) { currentPath = ''; } if (visited === void 0) { visited = new Set(); } if (_typeof(o) !== 'object' || o === null || visited.has(o)) { return [currentPath]; } visited.add(o); var paths = []; for (var key in o) { if (Object.prototype.hasOwnProperty.call(o, key)) { var newPath = currentPath ? "".concat(currentPath, ".").concat(key) : key; paths.push.apply(paths, __spreadArray([newPath], __read(_getPaths(o[key], newPath, visited)), false)); } } visited["delete"](o); return paths; }; /** * Returns all property paths for a given participant object. */ var getParticipantPaths = function getParticipantPaths(p) { return _getPaths(p); }; var resolvePath = function resolvePath(participant, path) { return String(path).split('.').filter(function (key) { return key.length; }).reduce(function (p, key) { return p && p[key]; }, participant); }; var resolveParticipantPaths = function resolveParticipantPaths(participant, paths) { return paths.map(function (path) { return resolvePath(participant, path); }); }; /** * Stores the most recent peerId as reported from [active-speaker-change](https://docs.daily.co/reference/daily-js/events/meeting-events#active-speaker-change) event. */ var activeIdState = atom(null); activeIdState.debugLabel = jotaiDebugLabel('active-id'); var localIdState = atom(''); localIdState.debugLabel = jotaiDebugLabel('local-id'); var localJoinDateState = atom(null); localJoinDateState.debugLabel = jotaiDebugLabel('local-join-date'); var participantIdsState = atom([]); participantIdsState.debugLabel = jotaiDebugLabel('participant-ids'); var participantState = atomFamily(function (id) { var participantAtom = atom(null); participantAtom.debugLabel = jotaiDebugLabel("participant-".concat(id)); return participantAtom; }); var waitingParticipantsState = atom([]); waitingParticipantsState.debugLabel = jotaiDebugLabel('waiting-participants'); var waitingParticipantState = atomFamily(function (id) { var waitingParticipantAtom = atom({ awaitingAccess: { level: 'full' }, id: id, name: '' }); waitingParticipantAtom.debugLabel = jotaiDebugLabel("waiting-participant-".concat(id)); return waitingParticipantAtom; }); var allWaitingParticipantsSelector = equalAtomFamily({ equals: arraysDeepEqual, get: function get() { return function (get) { var ids = get(waitingParticipantsState); return ids.map(function (id) { return get(waitingParticipantState(id)); }); }; } }); var DailyParticipants = function DailyParticipants(_a) { var children = _a.children; var daily = useDaily(); var _b = __read(useState(false), 2), initialized = _b[0], setInitialized = _b[1]; var initParticipants = useAtomCallback(useCallback(function (_get, set, participants) { set(localIdState, participants.local.session_id); var participantsArray = Object.values(participants); var ids = participantsArray.map(function (p) { return p.session_id; }); set(participantIdsState, ids); participantsArray.forEach(function (p) { set(participantState(p.session_id), p); var paths = getParticipantPaths(p); set(participantPropertyPathsState(p.session_id), paths); paths.forEach(function (property) { var _a = __read(resolveParticipantPaths(p, [property]), 1), value = _a[0]; set(getParticipantPropertyAtom(p.session_id, property), value); }); }); setInitialized(true); }, [])); /** * Initialize participants state based on daily.participants(). * Retries every 100ms to initialize the state, until daily is ready. */ useEffect(function () { if (!daily || initialized) return; var interval = setInterval(function () { var participants = daily.participants(); if (!('local' in participants)) return; initParticipants(participants); clearInterval(interval); }, 100); return function () { clearInterval(interval); }; }, [daily, initialized, initParticipants]); var handleInitEvent = useCallback(function () { if (!daily) return; var participants = daily === null || daily === void 0 ? void 0 : daily.participants(); if (!participants.local) return; initParticipants(participants); }, [daily, initParticipants]); useDailyEvent('started-camera', handleInitEvent, true); useDailyEvent('access-state-updated', handleInitEvent, true); useDailyEvent('joining-meeting', useAtomCallback(useCallback(function (_get, set) { set(localJoinDateState, new Date()); handleInitEvent(); }, [handleInitEvent])), true); useDailyEvent('joined-meeting', useCallback(function (ev) { initParticipants(ev.participants); }, [initParticipants]), true); /** * Reset stored participants, when meeting has ended. */ var handleCleanup = useAtomCallback(useCallback(function (get, set) { set(localIdState, ''); set(activeIdState, null); var ids = get(participantIdsState); ids.forEach(function (id) { return participantState.remove(id); }); set(participantIdsState, []); }, [])); useDailyEvent('call-instance-destroyed', handleCleanup, true); useDailyEvent('left-meeting', handleCleanup, true); useThrottledDailyEvent(['active-speaker-change', 'participant-joined', 'participant-updated', 'participant-left'], useAtomCallback(useCallback(function (get, set, evts) { if (!evts.length) return; evts.forEach(function (ev) { switch (ev.action) { case 'active-speaker-change': { set(activeIdState, ev.activeSpeaker.peerId); set(participantState(ev.activeSpeaker.peerId), function (prev) { if (!prev) return null; return _assign(_assign({}, prev), { last_active: new Date() }); }); break; } case 'participant-joined': { // Update list of ids set(participantIdsState, function (prevIds) { return prevIds.includes(ev.participant.session_id) ? prevIds : __spreadArray(__spreadArray([], __read(prevIds), false), [ev.participant.session_id], false); }); // Store entire object set(participantState(ev.participant.session_id), ev.participant); var paths = getParticipantPaths(ev.participant); // Set list of property paths set(participantPropertyPathsState(ev.participant.session_id), paths); // Set all property path values paths.forEach(function (property) { var _a = __read(resolveParticipantPaths(ev.participant, [property]), 1), value = _a[0]; set(getParticipantPropertyAtom(ev.participant.session_id, property), value); }); break; } case 'participant-updated': { // Update entire object set(participantState(ev.participant.session_id), ev.participant); // Update local session_id if (ev.participant.local) { set(localIdState, ev.participant.session_id); } var paths = getParticipantPaths(ev.participant); var oldPaths_1 = get(participantPropertyPathsState(ev.participant.session_id)); var pathsChanged = paths.length !== oldPaths_1.length || paths.some(function (path) { return !oldPaths_1.includes(path); }); // Set list of property paths if (pathsChanged) { set(participantPropertyPathsState(ev.participant.session_id), paths); } // Create a Set of oldPaths for quick lookup var oldPathSet_1 = new Set(oldPaths_1); // Resolve all path values in one call var resolvedValues_1 = resolveParticipantPaths(ev.participant, paths); paths.forEach(function (property, idx) { var value = resolvedValues_1[idx]; // Remove property from oldPathSet to mark it as processed oldPathSet_1["delete"](property); // Only update if the new value differs from the current one set(getParticipantPropertyAtom(ev.participant.session_id, property), function (prev) { return customDeepEqual(prev, value) ? prev : value; }); }); // Set any remaining paths in oldPathSet to null oldPathSet_1.forEach(function (property) { set(getParticipantPropertyAtom(ev.participant.session_id, property), null); }); break; } case 'participant-left': { // Remove from list of ids set(participantIdsState, function (prevIds) { return prevIds.includes(ev.participant.session_id) ? prevIds.filter(function (id) { return id !== ev.participant.session_id; }) : prevIds; }); // Remove entire object participantState.remove(ev.participant.session_id); var oldPaths = get(participantPropertyPathsState(ev.participant.session_id)); // Remove property path values oldPaths.forEach(function (property) { participantPropertyState.remove(getPropertyParam(ev.participant.session_id, property)); }); // Remove all property paths participantPropertyPathsState.remove(ev.participant.session_id); break; } } }); }, [])), 100, true); useThrottledDailyEvent(['waiting-participant-added', 'waiting-participant-updated', 'waiting-participant-removed'], useAtomCallback(useCallback(function (_get, set, evts) { evts.forEach(function (ev) { switch (ev.action) { case 'waiting-participant-added': set(waitingParticipantsState, function (wps) { return wps.includes(ev.participant.id) ? wps : __spreadArray(__spreadArray([], __read(wps), false), [ev.participant.id], false); }); set(waitingParticipantState(ev.participant.id), ev.participant); break; case 'waiting-participant-updated': set(waitingParticipantState(ev.participant.id), ev.participant); break; case 'waiting-participant-removed': set(waitingParticipantsState, function (wps) { return wps.filter(function (wp) { return wp !== ev.participant.id; }); }); waitingParticipantState.remove(ev.participant.id); break; } }); }, [])), 100, true); return React.createElement(React.Fragment, null, children); }; /** * Returns the local participant's session_id or empty string '', * if the local participant doesn't exist. */ var useLocalSessionId = function useLocalSessionId() { var localId = useAtomValue(localIdState); useDebugValue(localId); return localId; }; var noopFilter = function noopFilter() { return true; }; /** * Returns the most recent speaker id mentioned in an [active-speaker-change](https://docs.daily.co/reference/daily-js/events/meeting-events#active-speaker-change) event. */ var useActiveSpeakerId = function useActiveSpeakerId(_a) { var _b = _a === void 0 ? {} : _a, _c = _b.filter, filter = _c === void 0 ? noopFilter : _c, _d = _b.ignoreLocal, ignoreLocal = _d === void 0 ? false : _d; var localSessionId = useLocalSessionId(); var recentActiveId = useAtomValue(activeIdState); var isIgnoredLocalId = ignoreLocal && recentActiveId === localSessionId; var isFilteredOut = !(filter === null || filter === void 0 ? void 0 : filter(recentActiveId)); var isRecentIdRelevant = !isIgnoredLocalId && !isFilteredOut; var _e = __read(useState(isRecentIdRelevant ? recentActiveId : null), 2), activeId = _e[0], setActiveId = _e[1]; useEffect(function () { if (isIgnoredLocalId || isFilteredOut) return; setActiveId(recentActiveId); }, [isFilteredOut, isIgnoredLocalId, recentActiveId]); useDebugValue(activeId); return activeId; }; var isTrackOff = function isTrackOff(trackState) { return ['blocked', 'off'].includes(trackState); }; var SERIALIZABLE_DELIM = ';'; var getParticipantIdsFilterSortParam = function getParticipantIdsFilterSortParam(filter, sort) { return "".concat(filter).concat(SERIALIZABLE_DELIM).concat(sort); }; /** * Short-cut state selector for useParticipantIds({ filter: 'local' }) */ var participantIdsFilteredAndSortedState = equalAtomFamily({ equals: customDeepEqual, get: function get(param) { return function (get) { var _a = __read(param.split(SERIALIZABLE_DELIM), 2), filter = _a[0], sort = _a[1]; var ids = get(participantIdsState); return ids.filter(function (id) { switch (filter) { /** * Simple boolean fields first. */ case 'local': case 'owner': case 'record': { return get(getParticipantPropertyAtom(id, filter)); } case 'remote': { return !get(getParticipantPropertyAtom(id, 'local')); } case 'screen': { var screenAudioState = get(getParticipantPropertyAtom(id, 'tracks.screenAudio.state')); var screenVideoState = get(getParticipantPropertyAtom(id, 'tracks.screenVideo.state')); return !isTrackOff(screenAudioState) || !isTrackOff(screenVideoState); } default: return true; } }).sort(function (idA, idB) { switch (sort) { case 'joined_at': case 'session_id': case 'user_id': case 'user_name': { var aSort = get(getParticipantPropertyAtom(idA, sort)); var bSort = get(getParticipantPropertyAtom(idB, sort)); if (aSort !== undefined || bSort !== undefined) { if (aSort === undefined) return -1; if (bSort === undefined) return 1; if (aSort > bSort) return 1; if (aSort < bSort) return -1; } return 0; } default: return 0; } }); }; } }); /** * Returns a list of participant ids (= session_id). * The list can optionally be filtered and sorted, using the filter and sort options. */ var useParticipantIds = function useParticipantIds(_a) { var _b = _a === void 0 ? {} : _a, filter = _b.filter, onActiveSpeakerChange = _b.onActiveSpeakerChange, onParticipantJoined = _b.onParticipantJoined, onParticipantLeft = _b.onParticipantLeft, onParticipantUpdated = _b.onParticipantUpdated, sort = _b.sort; /** * For instances of useParticipantIds with string-based filter and sort, * we can immediately return the correct ids from Jotai's state. */ var preFilteredSortedIds = useAtomValue(participantIdsFilteredAndSortedState(getParticipantIdsFilterSortParam(typeof filter === 'string' ? filter : null, typeof sort === 'string' ? sort : null))); var shouldUseCustomIds = typeof filter === 'function' || typeof sort === 'function'; var getCustomFilteredIds = useCallback(function (get) { if ( // Ignore if both filter and sort are not functions. typeof filter !== 'function' && typeof sort !== 'function') return []; var participants = preFilteredSortedIds.map(function (id) { return get(participantState(id)); }); return participants // Make sure we don't accidentally try to filter/sort `null` participants // This can happen when a participant's id is already present in store // but the participant object is not stored, yet. .filter(function (p) { return Boolean(p); }) // Run custom filter, if it's a function. Otherwise don't filter any participants. .filter(typeof filter === 'function' ? filter : function () { return true; }) // Run custom sort, if it's a function. Otherwise don't sort. .sort(typeof sort === 'function' ? sort : function () { return 0; }) // Map back to session_id. .map(function (p) { return p.session_id; }) // Filter any potential null/undefined ids. // This shouldn't really happen, but better safe than sorry. .filter(Boolean); }, [filter, preFilteredSortedIds, sort]); var _c = __read(useState([]), 2), customIds = _c[0], setCustomIds = _c[1]; var maybeUpdateCustomIds = useAtomCallback(useCallback(function (get) { if (!shouldUseCustomIds) return; var newIds = getCustomFilteredIds(get); if (customDeepEqual(newIds, customIds)) return; setCustomIds(newIds); }, [customIds, getCustomFilteredIds, shouldUseCustomIds])); useEffect(function () { maybeUpdateCustomIds(); }, [maybeUpdateCustomIds]); useThrottledDailyEvent(['participant-joined', 'participant-updated', 'active-speaker-change', 'participant-left'], useCallback(function (evts) { if (!evts.length) return; evts.forEach(function (ev) { switch (ev.action) { case 'participant-joined': onParticipantJoined === null || onParticipantJoined === void 0 ? void 0 : onParticipantJoined(ev); break; case 'participant-updated': onParticipantUpdated === null || onParticipantUpdated === void 0 ? void 0 : onParticipantUpdated(ev); break; case 'active-speaker-change': onActiveSpeakerChange === null || onActiveSpeakerChange === void 0 ? void 0 : onActiveSpeakerChange(ev); break; case 'participant-left': onParticipantLeft === null || onParticipantLeft === void 0 ? void 0 : onParticipantLeft(ev); break; } }); maybeUpdateCustomIds(); }, [maybeUpdateCustomIds, onActiveSpeakerChange, onParticipantJoined, onParticipantLeft, onParticipantUpdated])); var result = typeof filter === 'function' || typeof sort === 'fun