@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
JavaScript
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