@whereby.com/browser-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "env": {
3
+ "browser": true,
4
+ "es6": true,
5
+ "jest": true,
6
+ "node": true
7
+ },
8
+ "ignorePatterns": ["dist/*"],
9
+ "parserOptions": {
10
+ "ecmaVersion": "latest",
11
+ "sourceType": "module",
12
+ "ecmaFeatures": {
13
+ "experimentalObjectRestSpread": true
14
+ }
15
+ },
16
+ "extends": ["eslint:recommended"],
17
+ "plugins": ["jest"],
18
+ "rules": {
19
+ "no-console": ["error", { "allow": ["warn", "error"] }]
20
+ }
21
+ }
@@ -0,0 +1,7 @@
1
+ build/
2
+ dist/
3
+ node_modules/
4
+ *.css
5
+ *.json
6
+ *.html
7
+ *.md
package/.prettierrc ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "tabWidth": 4,
3
+ "printWidth": 120
4
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
3
+ addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
4
+ framework: "@storybook/web-components",
5
+ };
@@ -0,0 +1,9 @@
1
+ export const parameters = {
2
+ actions: { argTypesRegex: "^on[A-Z].*" },
3
+ controls: {
4
+ matchers: {
5
+ color: /(background|color)$/i,
6
+ date: /Date$/,
7
+ },
8
+ },
9
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
3
+ "editor.formatOnSave": true
4
+ }
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ ## MIT License
2
+
3
+ Copyright (c) 2022 Whereby AS (https://www.whereby.com)
4
+ Permission is hereby granted, free of charge, to any person
5
+ obtaining a copy of this software and associated documentation
6
+ files (the "Software"), to deal in the Software without
7
+ restriction, including without limitation the rights to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following
11
+ conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @whereby.com/browser-sdk
2
+
3
+ Clientside library defining a web component to allow embedding Whereby video rooms in web applications. Only normal iframe under the hood, the web component adds syntactic sugar to make it easier to customize the Whereby experience and hook into powerful features such as listening to room events and sending co.mmands to the room from the host application.
4
+
5
+ ## Usage
6
+
7
+ ### React + a bundler (webpack, rollup, parcel etc)
8
+ ```
9
+ import "@whereby.com/browser-sdk"
10
+
11
+ const MyComponent = ({ roomUrl }) => {
12
+ return <whereby-embed room={roomUrl} />
13
+ }
14
+
15
+ export default MyComponent
16
+
17
+ ```
18
+
19
+ ### Directly using a script tag
20
+ ```
21
+ <html>
22
+ <head>
23
+ <script src="...."></script>
24
+ </head>
25
+ <body>
26
+ <div class="container">
27
+ <whereby-embed room="some-room" />
28
+ </div>
29
+ </body>
30
+ </html>
31
+ ```
32
+
33
+ **Note**
34
+
35
+ Although we have just higlighted two combinations of how to load and use the web component, it should be possible to use this library with all the major frontend frameworks.
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ var heresy = require('heresy');
4
+
5
+ const boolAttrs = [
6
+ "audio",
7
+ "background",
8
+ "chat",
9
+ "people",
10
+ "embed",
11
+ "emptyRoomInvitation",
12
+ "help",
13
+ "leaveButton",
14
+ "precallReview",
15
+ "screenshare",
16
+ "video",
17
+ "floatSelf",
18
+ "recording",
19
+ "logo",
20
+ "locking",
21
+ "participantCount",
22
+ "settingsButton",
23
+ "pipButton",
24
+ "moreButton",
25
+ "personality",
26
+ "subgridLabels",
27
+ "lowData",
28
+ ];
29
+
30
+ heresy.define("WherebyEmbed", {
31
+ oninit() {
32
+ this.iframe = heresy.ref();
33
+ },
34
+ onconnected() {
35
+ window.addEventListener("message", this);
36
+ },
37
+ ondisconnected() {
38
+ window.removeEventListener("message", this);
39
+ },
40
+ observedAttributes: ["displayName", "minimal", "room", "subdomain", "groups", "lang", "metadata", ...boolAttrs].map(
41
+ (a) => a.toLowerCase()
42
+ ),
43
+ onattributechanged({ attributeName, oldValue }) {
44
+ if (["room", "subdomain"].includes(attributeName) && oldValue == null) return;
45
+ this.render();
46
+ },
47
+ style(self) {
48
+ return `
49
+ ${self} {
50
+ display: block;
51
+ }
52
+ ${self} iframe {
53
+ border: none;
54
+ height: 100%;
55
+ width: 100%;
56
+ }
57
+ `;
58
+ },
59
+
60
+ // Commands
61
+ toggleCamera(enabled) {
62
+ if (this.iframe.current) {
63
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
64
+ this.iframe.current.contentWindow.postMessage({ command: "toggle_camera", args: [enabled] }, url.origin);
65
+ }
66
+ },
67
+ toggleMicrophone(enabled) {
68
+ if (this.iframe.current) {
69
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
70
+ this.iframe.current.contentWindow.postMessage(
71
+ { command: "toggle_microphone", args: [enabled] },
72
+ url.origin
73
+ );
74
+ }
75
+ },
76
+
77
+ onmessage({ origin, data }) {
78
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
79
+ if (origin !== url.origin) return;
80
+ const { type, payload: detail } = data;
81
+ this.dispatchEvent(new CustomEvent(type, { detail }));
82
+ },
83
+ render() {
84
+ const { displayname: displayName, lang, metadata, minimal, room } = this;
85
+ if (!room) return this.html`Whereby: Missing room attr.`;
86
+ // Get subdomain from room URL, or use it specified
87
+ let m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
88
+ const subdomain = (m && m[1]) || this.subdomain;
89
+ if (!subdomain) return this.html`Whereby: Missing subdomain attr.`;
90
+ const url = new URL(room, `https://${subdomain}.whereby.com`);
91
+ Object.entries({
92
+ jsApi: true,
93
+ we: "0.1.0",
94
+ iframeSource: subdomain,
95
+ ...(displayName && { displayName }),
96
+ ...(lang && { lang: lang }),
97
+ ...(metadata && { metadata: metadata }),
98
+ // the original ?embed name was confusing, so we give minimal
99
+ ...(minimal != null && { embed: minimal }),
100
+ ...boolAttrs.reduce(
101
+ // add to URL if set in any way
102
+ (o, v) => (this[v.toLowerCase()] != null ? { ...o, [v]: this[v.toLowerCase()] } : o),
103
+ {}
104
+ ),
105
+ }).forEach(([k, v]) => {
106
+ if (!url.searchParams.has(k)) {
107
+ url.searchParams.set(k, v);
108
+ }
109
+ });
110
+ this.html`
111
+ <iframe
112
+ ref=${this.iframe}
113
+ src=${url}
114
+ allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
115
+ `;
116
+ },
117
+ });
118
+
119
+ var index = { sdkVersion: "0.1.0" };
120
+
121
+ module.exports = index;
@@ -0,0 +1,119 @@
1
+ import { define, ref } from 'heresy';
2
+
3
+ const boolAttrs = [
4
+ "audio",
5
+ "background",
6
+ "chat",
7
+ "people",
8
+ "embed",
9
+ "emptyRoomInvitation",
10
+ "help",
11
+ "leaveButton",
12
+ "precallReview",
13
+ "screenshare",
14
+ "video",
15
+ "floatSelf",
16
+ "recording",
17
+ "logo",
18
+ "locking",
19
+ "participantCount",
20
+ "settingsButton",
21
+ "pipButton",
22
+ "moreButton",
23
+ "personality",
24
+ "subgridLabels",
25
+ "lowData",
26
+ ];
27
+
28
+ define("WherebyEmbed", {
29
+ oninit() {
30
+ this.iframe = ref();
31
+ },
32
+ onconnected() {
33
+ window.addEventListener("message", this);
34
+ },
35
+ ondisconnected() {
36
+ window.removeEventListener("message", this);
37
+ },
38
+ observedAttributes: ["displayName", "minimal", "room", "subdomain", "groups", "lang", "metadata", ...boolAttrs].map(
39
+ (a) => a.toLowerCase()
40
+ ),
41
+ onattributechanged({ attributeName, oldValue }) {
42
+ if (["room", "subdomain"].includes(attributeName) && oldValue == null) return;
43
+ this.render();
44
+ },
45
+ style(self) {
46
+ return `
47
+ ${self} {
48
+ display: block;
49
+ }
50
+ ${self} iframe {
51
+ border: none;
52
+ height: 100%;
53
+ width: 100%;
54
+ }
55
+ `;
56
+ },
57
+
58
+ // Commands
59
+ toggleCamera(enabled) {
60
+ if (this.iframe.current) {
61
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
62
+ this.iframe.current.contentWindow.postMessage({ command: "toggle_camera", args: [enabled] }, url.origin);
63
+ }
64
+ },
65
+ toggleMicrophone(enabled) {
66
+ if (this.iframe.current) {
67
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
68
+ this.iframe.current.contentWindow.postMessage(
69
+ { command: "toggle_microphone", args: [enabled] },
70
+ url.origin
71
+ );
72
+ }
73
+ },
74
+
75
+ onmessage({ origin, data }) {
76
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
77
+ if (origin !== url.origin) return;
78
+ const { type, payload: detail } = data;
79
+ this.dispatchEvent(new CustomEvent(type, { detail }));
80
+ },
81
+ render() {
82
+ const { displayname: displayName, lang, metadata, minimal, room } = this;
83
+ if (!room) return this.html`Whereby: Missing room attr.`;
84
+ // Get subdomain from room URL, or use it specified
85
+ let m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
86
+ const subdomain = (m && m[1]) || this.subdomain;
87
+ if (!subdomain) return this.html`Whereby: Missing subdomain attr.`;
88
+ const url = new URL(room, `https://${subdomain}.whereby.com`);
89
+ Object.entries({
90
+ jsApi: true,
91
+ we: "0.1.0",
92
+ iframeSource: subdomain,
93
+ ...(displayName && { displayName }),
94
+ ...(lang && { lang: lang }),
95
+ ...(metadata && { metadata: metadata }),
96
+ // the original ?embed name was confusing, so we give minimal
97
+ ...(minimal != null && { embed: minimal }),
98
+ ...boolAttrs.reduce(
99
+ // add to URL if set in any way
100
+ (o, v) => (this[v.toLowerCase()] != null ? { ...o, [v]: this[v.toLowerCase()] } : o),
101
+ {}
102
+ ),
103
+ }).forEach(([k, v]) => {
104
+ if (!url.searchParams.has(k)) {
105
+ url.searchParams.set(k, v);
106
+ }
107
+ });
108
+ this.html`
109
+ <iframe
110
+ ref=${this.iframe}
111
+ src=${url}
112
+ allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
113
+ `;
114
+ },
115
+ });
116
+
117
+ var index = { sdkVersion: "0.1.0" };
118
+
119
+ export { index as default };
package/dist/v0.js ADDED
@@ -0,0 +1,15 @@
1
+ /*! (c) Andrea Giammarchi - ISC */
2
+ var e={};try{e.WeakMap=WeakMap}catch(t){e.WeakMap=function(e,t){var n=t.defineProperty,r=t.hasOwnProperty,s=o.prototype;return s.delete=function(e){return this.has(e)&&delete e[this._]},s.get=function(e){return this.has(e)?e[this._]:void 0},s.has=function(e){return r.call(e,this._)},s.set=function(e,t){return n(e,this._,{configurable:!0,value:t}),this},o;function o(t){n(this,"_",{value:"_@ungap/weakmap"+e++}),t&&t.forEach(a,this)}function a(e){this.set(e[0],e[1])}}(Math.random(),Object)}var t=e.WeakMap,n={};try{n.Event=new Event(".").constructor}catch(e){try{n.Event=new CustomEvent(".").constructor}catch(e){n.Event=function(e,t){t||(t={});var n=document.createEvent("Event"),r=!!t.bubbles,s=!!t.cancelable;n.initEvent(e,r,s);try{n.bubbles=r,n.cancelable=s}catch(n){}return n}}}var r=n.Event,s={};
3
+ /*! (c) Andrea Giammarchi - ISC */try{s.WeakSet=WeakSet}catch(e){!function(e){var t=new e,n=r.prototype;function r(n){t.set(this,new e),n&&n.forEach(this.add,this)}n.add=function(e){return t.get(this).set(e,1),this},n.delete=function(e){return t.get(this).delete(e)},n.has=function(e){return t.get(this).has(e)},s.WeakSet=r}(WeakMap)}var o,a,i=s.WeakSet,c="-"+Math.random().toFixed(6)+"%",l=!1;
4
+ /*! (c) Andrea Giammarchi - ISC */try{o=document.createElement("template"),a="tabindex","content"in o&&(o.innerHTML='<p tabindex="'+c+'"></p>',o.content.childNodes[0].getAttribute(a)==c)||(c="_dt: "+c.slice(1,-1)+";",l=!0)}catch(e){}var u="\x3c!--"+c+"--\x3e",h=/^(?:plaintext|script|style|textarea|title|xmp)$/i,f=/^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i;
5
+ /*! (c) Andrea Giammarchi - ISC */
6
+ function p(e){return e.join(u).replace(w,C).replace(y,x)}var d=" \\f\\n\\r\\t",m="[^ \\f\\n\\r\\t\\/>\"'=]+",g="[ \\f\\n\\r\\t]+"+m,v="<([A-Za-z]+[A-Za-z0-9:._-]*)((?:",b="(?:\\s*=\\s*(?:'[^']*?'|\"[^\"]*?\"|<[^>]*?>|"+m.replace("\\/","")+"))?)",y=new RegExp(v+g+b+"+)(["+d+"]*/?>)","g"),w=new RegExp(v+g+b+"*)(["+d+"]*/>)","g"),E=new RegExp("("+g+"\\s*=\\s*)(['\"]?)"+u+"\\2","gi");function x(e,t,n,r){return"<"+t+n.replace(E,N)+r}function N(e,t,n){return t+(n||'"')+c+(n||'"')}function C(e,t,n){return f.test(t)?e:"<"+t+n+"></"+t+">"}const{isArray:k}=Array,{indexOf:A,slice:$}=[];var S=e=>({get:t=>e.get(t),set:(t,n)=>(e.set(t,n),n)});const _=(e,t)=>111===e.nodeType?1/t<0?t?(({firstChild:e,lastChild:t})=>{const n=document.createRange();return n.setStartAfter(e),n.setEndAfter(t),n.deleteContents(),e})(e):e.lastChild:t?e.valueOf():e.firstChild:e,L=e=>{const{childNodes:t}=e,{length:n}=t;if(n<2)return n?t[0]:e;const r=$.call(t,0);return{ELEMENT_NODE:1,nodeType:111,firstChild:r[0],lastChild:r[n-1],valueOf(){if(t.length!==n){let t=0;for(;t<n;)e.appendChild(r[t++])}return e}}};
7
+ /*! (c) Andrea Giammarchi - ISC */
8
+ var M=function(e){var t="fragment",n="template",r="content"in o(n)?function(e){var t=o(n);return t.innerHTML=e,t.content}:function(e){var r=o(t),a=o(n),i=null;if(/^[^\S]*?<(col(?:group)?|t(?:head|body|foot|r|d|h))/i.test(e)){var c=RegExp.$1;a.innerHTML="<table>"+e+"</table>",i=a.querySelectorAll(c)}else a.innerHTML=e,i=a.childNodes;return s(r,i),r};return function(e,t){return("svg"===t?a:r)(e)};function s(e,t){for(var n=t.length;n--;)e.appendChild(t[0])}function o(n){return n===t?e.createDocumentFragment():e.createElementNS("http://www.w3.org/1999/xhtml",n)}function a(e){var n=o(t),r=o("div");return r.innerHTML='<svg xmlns="http://www.w3.org/2000/svg">'+e+"</svg>",s(n,r.firstChild.childNodes),n}}(document),j=(e,t,n,r,s)=>{const o=n.length;let a=t.length,i=o,c=0,l=0,u=null;for(;c<a||l<i;)if(a===c){const t=i<o?l?r(n[l-1],-0).nextSibling:r(n[i-l],0):s;for(;l<i;)e.insertBefore(r(n[l++],1),t)}else if(i===l)for(;c<a;)u&&u.has(t[c])||e.removeChild(r(t[c],-1)),c++;else if(t[c]===n[l])c++,l++;else if(t[a-1]===n[i-1])a--,i--;else if(t[c]===n[i-1]&&n[l]===t[a-1]){const s=r(t[--a],-1).nextSibling;e.insertBefore(r(n[l++],1),r(t[c++],-1).nextSibling),e.insertBefore(r(n[--i],1),s),t[a]=n[i]}else{if(!u){u=new Map;let e=l;for(;e<i;)u.set(n[e],e++)}if(u.has(t[c])){const s=u.get(t[c]);if(l<s&&s<i){let o=c,h=1;for(;++o<a&&o<i&&u.get(t[o])===s+h;)h++;if(h>s-l){const o=r(t[c],0);for(;l<s;)e.insertBefore(r(n[l++],1),o)}else e.replaceChild(r(n[l++],1),r(t[c++],-1))}else c++}else e.removeChild(r(t[c++],-1))}return n},O=function(e,t,n,r,s){var o=s in e,a=e.createDocumentFragment();return a.appendChild(e.createTextNode("g")),a.appendChild(e.createTextNode("")),(o?e.importNode(a,!0):a.cloneNode(!0)).childNodes.length<2?function e(t,n){for(var r=t.cloneNode(),s=t.childNodes||[],o=s.length,a=0;n&&a<o;a++)r.appendChild(e(s[a],n));return r}:o?e.importNode:function(e,t){return e.cloneNode(!!t)}}(document,0,0,0,"importNode"),T="".trim||function(){return String(this).replace(/^\s+|\s+/g,"")},R=l?function(e,t){var n=t.join(" ");return t.slice.call(e,0).sort((function(e,t){return n.indexOf(e.name)<=n.indexOf(t.name)?-1:1}))}:function(e,t){return t.slice.call(e,0)};function W(e,t){for(var n=t.length,r=0;r<n;)e=e.childNodes[t[r++]];return e}function P(e,t,n,r){for(var s=e.childNodes,o=s.length,a=0;a<o;){var i=s[a];switch(i.nodeType){case 1:var l=r.concat(a);Z(i,t,n,l),P(i,t,n,l);break;case 8:var f=i.textContent;if(f===c)n.shift(),t.push(h.test(e.nodeName)?D(e,r):z(i,r.concat(a)));else switch(f.slice(0,2)){case"/*":if("*/"!==f.slice(-2))break;case"👻":e.removeChild(i),a--,o--}break;case 3:h.test(e.nodeName)&&T.call(i.textContent)===u&&(n.shift(),t.push(D(e,r)))}a++}}function Z(e,t,n,r){for(var s=e.attributes,o=[],a=[],i=R(s,n),h=i.length,f=0;f<h;){var p,d=i[f++],m=d.value===c;if(m||1<(p=d.value.split(u)).length){var g=d.name;if(o.indexOf(g)<0){o.push(g);var v=n.shift().replace(m?/^(?:|[\S\s]*?\s)(\S+?)\s*=\s*('|")?$/:new RegExp("^(?:|[\\S\\s]*?\\s)("+g+")\\s*=\\s*('|\")[\\S\\s]*","i"),"$1"),b=s[v]||s[v.toLowerCase()];if(m)t.push(B(b,r,v,null));else{for(var y=p.length-2;y--;)n.shift();t.push(B(b,r,v,p))}}a.push(d)}}f=0;for(var w=(0<(h=a.length)&&l&&!("ownerSVGElement"in e));f<h;){var E=a[f++];w&&(E.value=""),e.removeAttribute(E.name)}var x=e.nodeName;if(/^script$/i.test(x)){var N=document.createElement(x);for(h=s.length,f=0;f<h;)N.setAttributeNode(s[f++].cloneNode(!0));N.textContent=e.textContent,e.parentNode.replaceChild(N,e)}}function z(e,t){return{type:"any",node:e,path:t}}function B(e,t,n,r){return{type:"attr",node:e,path:t,name:n,sparse:r}}function D(e,t){return{type:"text",node:e,path:t}}var F=S(new t);function H(e,t){var n=(e.convert||p)(t),r=e.transform;r&&(n=r(n));var s=M(n,e.type);q(s);var o=[];return P(s,o,t.slice(0),[]),{content:s,updates:function(n){for(var r=[],s=o.length,a=0,i=0;a<s;){var c=o[a++],l=W(n,c.path);switch(c.type){case"any":r.push({fn:e.any(l,[]),sparse:!1});break;case"attr":var u=c.sparse,h=e.attribute(l,c.name,c.node);null===u?r.push({fn:h,sparse:!1}):(i+=u.length-2,r.push({fn:h,sparse:!0,values:u}));break;case"text":r.push({fn:e.text(l),sparse:!1}),l.textContent=""}}return s+=i,function(){var e=arguments.length;if(s!==e-1)throw new Error(e-1+" values instead of "+s+"\n"+t.join("${value}"));for(var o=1,a=1;o<e;){var i=r[o-a];if(i.sparse){var c=i.values,l=c[0],u=1,h=c.length;for(a+=h-2;u<h;)l+=arguments[o++]+c[u++];i.fn(l)}else i.fn(arguments[o++])}return n}}}}function V(e,t){var n=F.get(t)||F.set(t,H(e,t));return n.updates(O.call(document,n.content,!0))}var U=[];function q(e){for(var t=e.childNodes,n=t.length;n--;){var r=t[n];1!==r.nodeType&&0===T.call(r.textContent).length&&e.removeChild(r)}}
9
+ /*! (c) Andrea Giammarchi - ISC */var I=function(){var e=/acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i,t=/([^A-Z])([A-Z]+)/g;return function(e,t){return"ownerSVGElement"in e?function(e,t){var n;t?n=t.cloneNode(!0):(e.setAttribute("style","--hyper:style;"),n=e.getAttributeNode("style"));return n.value="",e.setAttributeNode(n),r(n,!0)}(e,t):r(e.style,!1)};function n(e,t,n){return t+"-"+n.toLowerCase()}function r(r,s){var o,a;return function(i){var c,l,u,h;switch(typeof i){case"object":if(i){if("object"===o){if(!s&&a!==i)for(l in a)l in i||(r[l]="")}else s?r.value="":r.cssText="";for(l in c=s?{}:r,i)u="number"!=typeof(h=i[l])||e.test(l)?h:h+"px",!s&&/^--/.test(l)?c.setProperty(l,u):c[l]=u;o="object",s?r.value=function(e){var r,s=[];for(r in e)s.push(r.replace(t,n),":",e[r],";");return s.join("")}(a=c):a=i;break}default:a!=i&&(o="string",a=i,s?r.value=i||"":r.cssText=i||"")}}}}();const G=(e,t)=>{let n,r=!0;const s=document.createAttributeNS(null,t);return t=>{n!==t&&(n=t,null==n?r||(e.removeAttributeNode(s),r=!0):(s.value=t,r&&(e.setAttributeNodeNS(s),r=!1)))}},J=({dataset:e})=>t=>{for(const n in t){const r=t[n];null==r?delete e[n]:e[n]=r}},K=(e,t)=>"dataset"===t?J(e):n=>{e[t]=n},Q=/^(?:form|list)$/i,X=(e,t)=>e.ownerDocument.createTextNode(t);function Y(e){return this.type=e,function(e){var t=U,n=q;return function(r){return t!==r&&(n=V(e,t=r)),n.apply(null,arguments)}}(this)}function ee(e){return e(this)}Y.prototype={attribute(e,t,n){const r="svg"===this.type;switch(t){case"class":if(r)return G(e,t);t="className";case"props":return K(e,t);case"aria":return(e=>t=>{for(const n in t){const r="role"===n?n:`aria-${n}`,s=t[n];null==s?e.removeAttribute(r):e.setAttribute(r,s)}})(e);case"style":return I(e,n,r);case"ref":return(e=>t=>{"function"==typeof t?t(e):t.current=e})(e);case".dataset":return J(e);default:return"."===t.slice(0,1)?K(e,t.slice(1)):"?"===t.slice(0,1)?((e,t,n)=>r=>{n!==!!r&&((n=!!r)?e.setAttribute(t,""):e.removeAttribute(t))})(e,t.slice(1)):"on"===t.slice(0,2)?((e,t)=>{let n,r=t.slice(2);return!(t in e)&&t.toLowerCase()in e&&(r=r.toLowerCase()),t=>{const s=k(t)?t:[t,!1];n!==s[0]&&(n&&e.removeEventListener(r,n,s[1]),(n=s[0])&&e.addEventListener(r,n,s[1]))}})(e,t):!(t in e)||r||Q.test(t)?G(e,t):((e,t)=>{let n;return r=>{n!==r&&(n=r,e[t]!==r&&(null==r?(e[t]="",e.removeAttribute(t)):e[t]=r))}})(e,t)}},any(e,t){const{type:n}=this;let r,s=!1;const o=a=>{switch(typeof a){case"string":case"number":case"boolean":s?r!==a&&(r=a,t[0].textContent=a):(s=!0,r=a,t=j(e.parentNode,t,[X(e,a)],_,e));break;case"function":o(a(e));break;case"object":case"undefined":if(null==a){s=!1,t=j(e.parentNode,t,[],_,e);break}default:if(s=!1,r=a,k(a))if(0===a.length)t.length&&(t=j(e.parentNode,t,[],_,e));else switch(typeof a[0]){case"string":case"number":case"boolean":o(String(a));break;case"function":o(a.map(ee,e));break;case"object":k(a[0])&&(a=a.concat.apply([],a));default:t=j(e.parentNode,t,a,_,e)}else"ELEMENT_NODE"in a?t=j(e.parentNode,t,11===a.nodeType?$.call(a.childNodes):[a],_,e):"text"in a?o(String(a.text)):"any"in a?o(a.any):"html"in a?t=j(e.parentNode,t,$.call(M([].concat(a.html).join(""),n).childNodes),_,e):"length"in a&&o($.call(a))}};return o},text(e){let t;const n=r=>{if(t!==r){t=r;const s=typeof r;"object"===s&&r?"text"in r?n(String(r.text)):"any"in r?n(r.any):"html"in r?n([].concat(r.html).join("")):"length"in r&&n($.call(r).join("")):"function"===s?n(r(e)):e.textContent=null==r?"":r}};return n}};const{create:te,freeze:ne,keys:re}=Object,se=Y.prototype,oe=S(new t),ae=e=>({html:ce("html",e),svg:ce("svg",e),render(t,n){const r="function"==typeof n?n():n,s=oe.get(t)||oe.set(t,ie()),o=r instanceof he?le(e,s,r):r;return o!==s.wire&&(s.wire=o,t.textContent="",t.appendChild(o.valueOf())),t}}),ie=()=>({stack:[],entry:null,wire:null}),ce=(e,n)=>{const r=S(new t);return s.for=(e,t)=>{const o=r.get(e)||r.set(e,te(null));return o[t]||(o[t]=(e=>function(){return le(n,e,s.apply(null,arguments))})(ie()))},s.node=function(){return le(n,ie(),s.apply(null,arguments)).valueOf()},s;function s(){return new he(e,pe.apply(null,arguments))}},le=(e,t,{type:n,template:r,values:s})=>{const{length:o}=s;ue(e,t,s,o);let{entry:a}=t;if(a&&a.template===r&&a.type===n)a.tag(r,...s);else{const o=new e(n);t.entry=a={type:n,template:r,tag:o,wire:L(o(r,...s))}}return a.wire},ue=(e,{stack:t},n,r)=>{for(let s=0;s<r;s++){const r=n[s];r instanceof fe?n[s]=le(e,t[s]||(t[s]=ie()),r):k(r)?ue(e,t[s]||(t[s]=ie()),r,r.length):t[s]=null}r<t.length&&t.splice(r)};function he(e,t){this.type=e,this.template=t.shift(),this.values=t}ne(he);const fe=he;function pe(){let e=[],t=0,{length:n}=arguments;for(;t<n;)e.push(arguments[t++]);return e}ae(Y);var de="function"==typeof cancelAnimationFrame,me=de?cancelAnimationFrame:clearTimeout,ge=de?requestAnimationFrame:setTimeout;function ve(e){var t,n,r,s,o;return i(),function(e,i,l){return r=e,s=i,o=l,n||(n=ge(a)),--t<0&&c(!0),c};function a(){i(),r.apply(s,o||[])}function i(){t=e||1/0,n=de?0:null}function c(e){var t=!!n;return t&&(me(n),e&&a()),t}}
10
+ /*! (c) Andrea Giammarchi - ISC */let be=null;const ye=S(new WeakMap),we=(e,t,n)=>{e.apply(t,n)},Ee={async:!1,always:!1},xe=(e,t)=>"function"==typeof t?t(e):t,Ne=(e,t,n,r)=>{const s=be.i++,{hook:o,args:a,stack:i,length:c}=be;s===c&&(be.length=i.push({}));const l=i[s];if(l.args=a,s===c){const s="function"==typeof n,{async:a,always:i}=(s?r:n)||r||Ee;l.$=s?n(t):xe(void 0,t),l._=a?ye.get(o)||ye.set(o,ve()):we,l.f=t=>{const n=e(l.$,t);(i||l.$!==n)&&(l.$=n,l._(o,null,l.args))}}return[l.$,l.f]},Ce=new WeakMap;function ke({hook:e}){return e===this.hook}const Ae=new WeakMap,$e=S(Ae),Se=()=>{},_e=e=>(t,n)=>{const r=be.i++,{hook:s,after:o,stack:a,length:i}=be;if(r<i){const s=a[r],{update:i,values:c,stop:l}=s;if(!n||n.some(Te,c)){s.values=n,e&&l(e);const{clean:r}=s;r&&(s.clean=null,r());const a=()=>{s.clean=t()};e?i(a):o.push(a)}}else{const r=e?ve():Se,i={clean:null,update:r,values:n,stop:Se};be.length=a.push(i),($e.get(s)||$e.set(s,[])).push(i);const c=()=>{i.clean=t()};e?i.stop=r(c):o.push(c)}},Le=e=>{(Ae.get(e)||[]).forEach((e=>{const{clean:t,stop:n}=e;n(),t&&(e.clean=null,t())}))};Ae.has.bind(Ae);const Me=_e(!0),je=_e(!1),Oe=(e,t)=>{const n=be.i++,{stack:r,length:s}=be;return n===s?be.length=r.push({$:e(),_:t}):t&&!t.some(Te,r[n]._)||(r[n]={$:e(),_:t}),r[n].$};function Te(e,t){return e!==this[t]}let Re=null;try{Re=new{o(){}}.o}catch(Ot){}let We=e=>class extends e{};if(Re){const{getPrototypeOf:e,setPrototypeOf:t}=Object,{construct:n}="object"==typeof Reflect?Reflect:{construct(e,n,r){const s=[null];for(let e=0;e<n.length;e++)s.push(n[e]);const o=e.bind.apply(e,s);return t(new o,r.prototype)}};We=function(r,s){function o(){return n(s?e(r):r,arguments,o)}return t(o.prototype,r.prototype),t(o,r)}}const Pe={map:{},re:null},Ze=e=>new RegExp(`<(/)?(${e.join("|")})([^A-Za-z0-9:._-])`,"g");let ze=null;const Be=(e,t)=>{const{map:n,re:r}=ze||t;return e.replace(r,((e,t,r,s)=>{const{tagName:o,is:a,element:i}=n[r];return i?t?`</${a}>`:`<${a}${s}`:t?`</${o}>`:`<${o} is="${a}"${s}`}))},De=({tagName:e,is:t,element:n})=>n?t:`${e}[is="${t}"]`,Fe=()=>ze,He=e=>{ze=e},Ve={useCallback:(e,t)=>Oe((()=>e),t),useContext:e=>{const{hook:t,args:n}=be,r=Ce.get(e),s={hook:t,args:n};return r.some(ke,s)||r.push(s),e.value},useEffect:Me,useLayoutEffect:je,useMemo:Oe,useReducer:Ne,useRef:e=>{const t=be.i++,{stack:n,length:r}=be;return t===r&&(be.length=n.push({current:e})),n[t]},useState:(e,t)=>Ne(xe,e,void 0,t)},{render:Ue,html:qe,svg:Ie}=(e=>{const t=te(se);return re(e).forEach((n=>{t[n]=e[n](t[n]||("convert"===n?p:String))})),n.prototype=t,ae(n);function n(){return Y.apply(this,arguments)}})({transform:()=>e=>Be(e,Pe)}),{defineProperties:Ge}=Object,Je=new t,Ke=new t,Qe=new t,Xe=new i,Ye="attributeChangedCallback",et="connectedCallback",tt=`dis${et}`,nt=(e,t,n)=>{if(n in e){const r=e[n];t[n]={configurable:true,value(){return dt.call(this),r.apply(this,arguments)}}}else t[n]={configurable:true,value:dt}},rt=e=>{const{prototype:n}=e,r=[],s={html:{configurable:true,get:ht},svg:{configurable:true,get:ft}};if(s["_🔥"]={value:{events:r,info:null}},"handleEvent"in n||(s.handleEvent={configurable:true,value:pt}),"render"in n&&n.render.length){const{oninit:e}=n;Ge(n,{oninit:{configurable:true,value(){const t=(e=>{const t=[];return function n(){const r=be,s=[];be={hook:n,args:arguments,stack:t,i:0,length:t.length,after:s};try{return e.apply(null,arguments)}finally{be=r;for(let e=0,{length:t}=s;e<t;e++)s[e]()}}})(this.render.bind(this,Ve));Ge(this,{render:{configurable:true,value:t}}),this.addEventListener("disconnected",Le.bind(null,t),!1),e&&e.apply(this,arguments)}}})}"oninit"in n&&(r.push("init"),nt(n,s,"render")),nt(n,s,Ye),nt(n,s,et),nt(n,s,tt),[[Ye,"onattributechanged",mt],[et,"onconnected",gt],[tt,"ondisconnected",bt],[et,"render",vt]].forEach((([e,t,o])=>{if(!(e in n)&&t in n)if("render"!==t&&r.push(t.slice(2)),e in s){const t=s[e].value;s[e]={configurable:true,value(){return t.apply(this,arguments),o.apply(this,arguments)}}}else s[e]={configurable:true,value:o}}));const o=e.booleanAttributes||[];o.forEach((e=>{e in n||(s[e]={configurable:true,get(){return this.hasAttribute(e)},set(t){t&&"false"!==t?this.setAttribute(e,t):this.removeAttribute(e)}})}));const a=e.observedAttributes||[];a.forEach((e=>{e in n||(s[e]={configurable:true,get(){return this.getAttribute(e)},set(t){null==t?this.removeAttribute(e):this.setAttribute(e,t)}})}));(e.mappedAttributes||[]).forEach((e=>{const o=new t,a="on"+e in n;a&&r.push(e),s[e]={configurable:true,get(){return o.get(this)},set(t){if(o.set(this,t),a){const n=st(e);if(n.detail=t,Xe.has(this))this.dispatchEvent(n);else{const e=Qe.get(this);e?e.push(n):Qe.set(this,[n])}}}}})),Ge(n,s);const i=o.concat(a);return i.length?Ge(e,{observedAttributes:{configurable:true,get:()=>i}}):e},st=e=>new r(e),ot=(...e)=>new fe("html",e);ot.for=qe.for;const at=(...e)=>new fe("svg",e);at.for=Ie.for;const it=(e,n,r)=>{const s=ct(e,n,new t);return r.set(e,s),s},ct=(e,t,n)=>(r,...s)=>{const o=n.get(r)||((e,t,{info:n})=>{const r=n?Be(t.join("_🔥"),n).split("_🔥"):t;return e.set(t,r),r})(n,r,e["_🔥"]);return Ue(e,(()=>t(o,...s)))};function lt(e){this.addEventListener(e,this)}function ut(e){this.dispatchEvent(e)}function ht(){return Je.get(this)||it(this,ot,Je)}function ft(){return Ke.get(this)||it(this,at,Ke)}function pt(e){this[`on${e.type}`](e)}function dt(){if(!Xe.has(this)){Xe.add(this),this["_🔥"].events.forEach(lt,this),this.dispatchEvent(st("init"));const e=Qe.get(this);e&&(Qe.delete(this),e.forEach(ut,this))}}function mt(e,t,n){const r=st("attributechanged");r.attributeName=e,r.oldValue=t,r.newValue=n,this.dispatchEvent(r)}function gt(){this.dispatchEvent(st("connected"))}function vt(){this.render()}function bt(){this.dispatchEvent(st("disconnected"))}const{create:yt,defineProperty:wt,defineProperties:Et,getOwnPropertyNames:xt,getOwnPropertySymbols:Nt,getOwnPropertyDescriptor:Ct,keys:kt}=Object,At={element:HTMLElement},$t=new t;new t;const St=new t;new t;const _t=e=>{const t=yt(null),n=yt(null),r={prototype:n,statics:t};return xt(e).concat(Nt(e)).forEach((r=>{const s=Ct(e,r);switch(s.enumerable=!1,r){case"extends":r="tagName";case"contains":case"includes":case"name":case"booleanAttributes":case"mappedAttributes":case"observedAttributes":case"style":case"tagName":t[r]=s;break;default:n[r]=s}})),r},Lt=(e,t,n)=>{if(!/^([A-Z][A-Za-z0-9_]*)(<([A-Za-z0-9:._-]+)>|:([A-Za-z0-9:._-]+))?$/.test(e))throw"Invalid name";const{$1:r,$3:s,$4:o}=RegExp;let a=s||o||t.tagName||t.extends||"element";const i="fragment"===a;if(i)a="element";else if(!/^[A-Za-z0-9:._-]+$/.test(a))throw"Invalid tag";let c="",l="";a.indexOf("-")<0?(c=r.replace(/(([A-Z0-9])([A-Z0-9][a-z]))|(([a-z])([A-Z]))/g,"$2$5-$3$6").toLowerCase()+n,c.indexOf("-")<0&&(l="-heresy")):(c=a+n,a="element");const u=c+l;if(customElements.get(u))throw`Duplicated ${u} definition`;const h=We("object"==typeof t?St.get(t)||((e,t)=>{const{statics:n,prototype:r}=_t(e),s=We(At[t]||(At[t]=document.createElement(t).constructor),!1);return Et(s.prototype,r),Et(s,n),St.set(e,rt(s)),s})(t,a):$t.get(t)||(e=>{const t=We(e,!1);return $t.set(e,rt(t)),t})(t),!0),f="element"===a;if(wt(h,"new",{value:f?()=>document.createElement(u):()=>document.createElement(a,{is:u})}),wt(h.prototype,"is",{value:u}),""===n){const e=(e=>{const{length:t}=e;let n=0,r=0;for(;r<t;)n=(n<<5)-n+e.charCodeAt(r++),n&=n;return n.toString(36)})(c.toUpperCase());Pe.map[r]=Mt(h,a,u,{id:e,i:0}),Pe.re=Ze(kt(Pe.map))}if(i){const{render:e}=h.prototype;wt(h.prototype,"render",{configurable:!0,value(){if(e&&e.apply(this,arguments),this.parentNode){const{firstChild:e}=this;let t=null;if(e){const n=document.createRange();n.setStartBefore(e),n.setEndAfter(this.lastChild),t=n.extractContents(),this.parentNode.replaceChild(t,this)}}}})}const p=[u,h];return f||p.push({extends:a}),customElements.define(...p),{Class:h,is:u,name:r,tagName:a}},Mt=(e,t,n,r)=>{const{prototype:s}=e,o=((e,t)=>({tagName:e,is:t,element:"element"===e}))(t,n),a=[De(o)],i=e.includes||e.contains;if(i){const e={};kt(i).forEach((t=>{const n=`-${r.id}-${r.i++}`,{Class:s,is:o,name:c,tagName:l}=Lt(t,i[t],n);a.push(De(e[c]=Mt(s,l,o,r)))}));const t=Ze(kt(e)),{events:n}=s["_🔥"],o={events:n,info:{map:e,re:t}};if(wt(s,"_🔥",{value:o}),"render"in s){const{render:e}=s,{info:t}=o;wt(s,"render",{configurable:!0,value(){const n=Fe();He(t);const r=e.apply(this,arguments);return He(n),r}})}}return"style"in e&&(e=>{if((e||"").length){const t=document.createElement("style");t.type="text/css",t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document.createTextNode(e));const n=document.head||document.querySelector("head");n.insertBefore(t,n.lastChild)}})(e.style(...a)),o},jt=["audio","background","chat","people","embed","emptyRoomInvitation","help","leaveButton","precallReview","screenshare","video","floatSelf","recording","logo","locking","participantCount","settingsButton","pipButton","moreButton","personality","subgridLabels","lowData"];var Ot,Tt;Ot="WherebyEmbed",Tt={oninit(){this.iframe=((e,t)=>e?e[t]||(e[t]={current:null}):{current:null})()},onconnected(){window.addEventListener("message",this)},ondisconnected(){window.removeEventListener("message",this)},observedAttributes:["displayName","minimal","room","subdomain","groups","lang","metadata",...jt].map((e=>e.toLowerCase())),onattributechanged({attributeName:e,oldValue:t}){["room","subdomain"].includes(e)&&null==t||this.render()},style:e=>`\n ${e} {\n display: block;\n }\n ${e} iframe {\n border: none;\n height: 100%;\n width: 100%;\n }\n `,toggleCamera(e){if(this.iframe.current){const t=new URL(this.room,`https://${this.subdomain}.whereby.com`);this.iframe.current.contentWindow.postMessage({command:"toggle_camera",args:[e]},t.origin)}},toggleMicrophone(e){if(this.iframe.current){const t=new URL(this.room,`https://${this.subdomain}.whereby.com`);this.iframe.current.contentWindow.postMessage({command:"toggle_microphone",args:[e]},t.origin)}},onmessage({origin:e,data:t}){if(e!==new URL(this.room,`https://${this.subdomain}.whereby.com`).origin)return;const{type:n,payload:r}=t;this.dispatchEvent(new CustomEvent(n,{detail:r}))},render(){const{displayname:e,lang:t,metadata:n,minimal:r,room:s}=this;if(!s)return this.html`Whereby: Missing room attr.`;let o=/https:\/\/([^.]+)\.whereby.com\/.+/.exec(s);const a=o&&o[1]||this.subdomain;if(!a)return this.html`Whereby: Missing subdomain attr.`;const i=new URL(s,`https://${a}.whereby.com`);Object.entries({jsApi:!0,we:"0.1.0",iframeSource:a,...e&&{displayName:e},...t&&{lang:t},...n&&{metadata:n},...null!=r&&{embed:r},...jt.reduce(((e,t)=>null!=this[t.toLowerCase()]?{...e,[t]:this[t.toLowerCase()]}:e),{})}).forEach((([e,t])=>{i.searchParams.has(e)||i.searchParams.set(e,t)})),this.html`
11
+ <iframe
12
+ ref=${this.iframe}
13
+ src=${i}
14
+ allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
15
+ `}},("string"==typeof Ot?Lt(Ot,Tt,""):Lt(Ot.name,Ot,"")).Class;var Rt={sdkVersion:"0.1.0"};export{Rt as default};
package/jest.config.js ADDED
@@ -0,0 +1,4 @@
1
+ export default {
2
+ testEnvironment: "jest-environment-node",
3
+ transform: {},
4
+ };
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@whereby.com/browser-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Configurable web component for embedding Whereby video rooms in web applications",
5
+ "author": "Whereby AS",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/whereby/browser-sdk.git"
10
+ },
11
+ "browserslist": "> 0.5%, last 2 versions, not dead",
12
+ "source": "src/index.js",
13
+ "main": "dist/lib.cjs.js",
14
+ "module": "dist/lib.esm.js",
15
+ "type": "module",
16
+ "scripts": {
17
+ "prebuild": "rimraf dist",
18
+ "build": "rollup -c",
19
+ "build:storybook": "build-storybook",
20
+ "dev": "start-storybook -p 6006",
21
+ "test": "yarn test:lint && yarn test:unit",
22
+ "test:lint": "eslint src/",
23
+ "test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
24
+ },
25
+ "devDependencies": {
26
+ "@babel/core": "^7.18.5",
27
+ "@rollup/plugin-node-resolve": "^13.3.0",
28
+ "@rollup/plugin-replace": "^4.0.0",
29
+ "@storybook/addon-actions": "^6.5.9",
30
+ "@storybook/addon-essentials": "^6.5.9",
31
+ "@storybook/addon-links": "^6.5.9",
32
+ "@storybook/builder-webpack4": "^6.5.9",
33
+ "@storybook/manager-webpack4": "^6.5.9",
34
+ "@storybook/web-components": "^6.5.9",
35
+ "babel-loader": "^8.2.5",
36
+ "eslint": "^8.18.0",
37
+ "eslint-plugin-jest": "^26.5.3",
38
+ "jest": "^28.1.1",
39
+ "jest-environment-jsdom": "^28.1.1",
40
+ "lit-html": "^2.2.6",
41
+ "prettier": "^2.7.1",
42
+ "rimraf": "^3.0.2",
43
+ "rollup": "^2.75.6",
44
+ "rollup-plugin-terser": "^7.0.2",
45
+ "storybook": "^6.5.9"
46
+ },
47
+ "dependencies": {
48
+ "@swc/helpers": "^0.3.13",
49
+ "heresy": "^1.0.4"
50
+ }
51
+ }
@@ -0,0 +1,46 @@
1
+ import nodeResolve from "@rollup/plugin-node-resolve";
2
+ import replace from "@rollup/plugin-replace";
3
+ import { terser } from "rollup-plugin-terser";
4
+ import pkg from "./package.json";
5
+
6
+ const replaceValues = {
7
+ preventAssignment: true,
8
+ values: {
9
+ __SDK_VERSION__: pkg.version,
10
+ },
11
+ };
12
+
13
+ export default [
14
+ // Commonjs build of lib, to be used with bundlers
15
+ {
16
+ input: "src/lib/index.js",
17
+ output: {
18
+ exports: "default",
19
+ file: "dist/lib.cjs.js",
20
+ format: "cjs",
21
+ },
22
+ external: ["heresy"],
23
+ plugins: [replace(replaceValues)],
24
+ },
25
+ // Esm build of lib, to be used with bundlers
26
+ {
27
+ input: "src/lib/index.js",
28
+ output: {
29
+ exports: "default",
30
+ file: "dist/lib.esm.js",
31
+ format: "esm",
32
+ },
33
+ external: ["heresy"],
34
+ plugins: [replace(replaceValues)],
35
+ },
36
+ // Legacy build of lib in ES format, bundling the dependencies
37
+ {
38
+ input: "src/lib/index.js",
39
+ output: {
40
+ exports: "default",
41
+ file: `dist/v${pkg.version.split(".")[0]}.js`,
42
+ format: "esm",
43
+ },
44
+ plugins: [nodeResolve(), terser(), replace(replaceValues)],
45
+ },
46
+ ];
@@ -0,0 +1,110 @@
1
+ import { html } from "lit-html";
2
+ import "./lib";
3
+
4
+ /**
5
+
6
+
7
+
8
+
9
+ "embed",
10
+
11
+ "locking",
12
+ "participantCount",
13
+ "settingsButton",
14
+ "pipButton",
15
+ "moreButton",
16
+ "personality",
17
+ "subgridLabels",
18
+ "topToolbar",
19
+ */
20
+
21
+ export default {
22
+ title: "Examples/<whereby-embed>",
23
+ argTypes: {
24
+ audio: { control: "boolean" },
25
+ background: { control: "boolean" },
26
+ chat: { control: "boolean" },
27
+ displayName: { control: "text", description: "The name to use for the local participant" },
28
+ embed: { control: "boolean" },
29
+ emptyRoomInvitation: { control: "boolean" },
30
+ floatSelf: { control: "boolean" },
31
+ help: { control: "boolean" },
32
+ leaveButton: { control: "boolean" },
33
+ locking: { control: "boolean" },
34
+ logo: { control: "boolean" },
35
+ people: { control: "boolean" },
36
+ precallReview: { control: "boolean" },
37
+ recording: { control: "boolean" },
38
+ room: { control: "text" },
39
+ screenshare: { control: "boolean" },
40
+ topToolbar: { control: "boolean" },
41
+ video: { control: "boolean" },
42
+ },
43
+ };
44
+
45
+ const offOn = (arg) => (arg ? "on" : "off");
46
+
47
+ const WherebyEmbed = ({
48
+ audio,
49
+ background,
50
+ chat,
51
+ displayName,
52
+ emptyRoomInvitation,
53
+ floatSelf,
54
+ help,
55
+ leaveButton,
56
+ logo,
57
+ people,
58
+ precallReview,
59
+ recording,
60
+ room,
61
+ screenshare,
62
+ video,
63
+ }) => {
64
+ return html`<whereby-embed
65
+ audio=${offOn(audio)}
66
+ background=${offOn(background)}
67
+ chat=${offOn(chat)}
68
+ displayName=${displayName}
69
+ emptyRoomInvitation=${emptyRoomInvitation}
70
+ floatSelf=${offOn(floatSelf)}
71
+ help=${offOn(help)}
72
+ leaveButton=${offOn(leaveButton)}
73
+ logo=${offOn(logo)}
74
+ people=${offOn(people)}
75
+ precallReview=${offOn(precallReview)}
76
+ recording=${offOn(recording)}
77
+ screenshare=${offOn(screenshare)}
78
+ video=${offOn(video)}
79
+ room="${room}"
80
+ style="height: 100vh"
81
+ />`;
82
+ };
83
+
84
+ const Template = (args) => WherebyEmbed(args);
85
+ export const Primary = Template.bind({});
86
+
87
+ Primary.args = {
88
+ audio: true,
89
+ background: true,
90
+ chat: true,
91
+ displayName: "Your name",
92
+ emptyRoomInvitation: true,
93
+ floatSelf: false,
94
+ help: true,
95
+ leaveButton: true,
96
+ logo: true,
97
+ people: true,
98
+ precallReview: true,
99
+ room: process.env.STORYBOOK_ROOM,
100
+ screenshare: true,
101
+ video: true,
102
+ };
103
+
104
+ Primary.parameters = {
105
+ docs: {
106
+ transformSource: (src) => {
107
+ return (src || "").replace(/><iframe(.+)$/, " />");
108
+ },
109
+ },
110
+ };
@@ -0,0 +1,75 @@
1
+ import { jest } from "@jest/globals";
2
+
3
+ const define = jest.fn();
4
+ const ref = jest.fn();
5
+ jest.mock("heresy", () => ({
6
+ __esModule: true,
7
+ define,
8
+ ref,
9
+ }));
10
+
11
+ describe("@whereby/browser-sdk", () => {
12
+ it("should export sdk version", async () => {
13
+ const whereby = await import("../");
14
+ expect(whereby.default.sdkVersion).toEqual(expect.any(String));
15
+ });
16
+
17
+ describe("web component", () => {
18
+ it("should define <whereby-embed />", async () => {
19
+ await import("../");
20
+ expect(define).toBeCalledWith("WherebyEmbed", expect.any(Object));
21
+ });
22
+
23
+ it("should expose attributes", async () => {
24
+ await import("..");
25
+ expect(define).toBeCalledWith(
26
+ expect.any(String),
27
+ expect.objectContaining({
28
+ observedAttributes: [
29
+ "displayname",
30
+ "minimal",
31
+ "room",
32
+ "subdomain",
33
+ "groups",
34
+ "lang",
35
+ "metadata",
36
+ "audio",
37
+ "background",
38
+ "chat",
39
+ "people",
40
+ "embed",
41
+ "emptyroominvitation",
42
+ "help",
43
+ "leavebutton",
44
+ "precallreview",
45
+ "screenshare",
46
+ "video",
47
+ "floatself",
48
+ "recording",
49
+ "logo",
50
+ "locking",
51
+ "participantcount",
52
+ "settingsbutton",
53
+ "pipbutton",
54
+ "morebutton",
55
+ "personality",
56
+ "subgridlabels",
57
+ "lowdata",
58
+ ],
59
+ })
60
+ );
61
+ });
62
+
63
+ it("should expose commands", async () => {
64
+ await import("../");
65
+
66
+ expect(define).toBeCalledWith(
67
+ expect.any(String),
68
+ expect.objectContaining({
69
+ toggleCamera: expect.any(Function),
70
+ toggleMicrophone: expect.any(Function),
71
+ })
72
+ );
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,117 @@
1
+ import { define, ref } from "heresy";
2
+
3
+ const boolAttrs = [
4
+ "audio",
5
+ "background",
6
+ "chat",
7
+ "people",
8
+ "embed",
9
+ "emptyRoomInvitation",
10
+ "help",
11
+ "leaveButton",
12
+ "precallReview",
13
+ "screenshare",
14
+ "video",
15
+ "floatSelf",
16
+ "recording",
17
+ "logo",
18
+ "locking",
19
+ "participantCount",
20
+ "settingsButton",
21
+ "pipButton",
22
+ "moreButton",
23
+ "personality",
24
+ "subgridLabels",
25
+ "lowData",
26
+ ];
27
+
28
+ define("WherebyEmbed", {
29
+ oninit() {
30
+ this.iframe = ref();
31
+ },
32
+ onconnected() {
33
+ window.addEventListener("message", this);
34
+ },
35
+ ondisconnected() {
36
+ window.removeEventListener("message", this);
37
+ },
38
+ observedAttributes: ["displayName", "minimal", "room", "subdomain", "groups", "lang", "metadata", ...boolAttrs].map(
39
+ (a) => a.toLowerCase()
40
+ ),
41
+ onattributechanged({ attributeName, oldValue }) {
42
+ if (["room", "subdomain"].includes(attributeName) && oldValue == null) return;
43
+ this.render();
44
+ },
45
+ style(self) {
46
+ return `
47
+ ${self} {
48
+ display: block;
49
+ }
50
+ ${self} iframe {
51
+ border: none;
52
+ height: 100%;
53
+ width: 100%;
54
+ }
55
+ `;
56
+ },
57
+
58
+ // Commands
59
+ toggleCamera(enabled) {
60
+ if (this.iframe.current) {
61
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
62
+ this.iframe.current.contentWindow.postMessage({ command: "toggle_camera", args: [enabled] }, url.origin);
63
+ }
64
+ },
65
+ toggleMicrophone(enabled) {
66
+ if (this.iframe.current) {
67
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
68
+ this.iframe.current.contentWindow.postMessage(
69
+ { command: "toggle_microphone", args: [enabled] },
70
+ url.origin
71
+ );
72
+ }
73
+ },
74
+
75
+ onmessage({ origin, data }) {
76
+ const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
77
+ if (origin !== url.origin) return;
78
+ const { type, payload: detail } = data;
79
+ this.dispatchEvent(new CustomEvent(type, { detail }));
80
+ },
81
+ render() {
82
+ const { displayname: displayName, lang, metadata, minimal, room } = this;
83
+ if (!room) return this.html`Whereby: Missing room attr.`;
84
+ // Get subdomain from room URL, or use it specified
85
+ let m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
86
+ const subdomain = (m && m[1]) || this.subdomain;
87
+ if (!subdomain) return this.html`Whereby: Missing subdomain attr.`;
88
+ const url = new URL(room, `https://${subdomain}.whereby.com`);
89
+ Object.entries({
90
+ jsApi: true,
91
+ we: "__SDK_VERSION__",
92
+ iframeSource: subdomain,
93
+ ...(displayName && { displayName }),
94
+ ...(lang && { lang: lang }),
95
+ ...(metadata && { metadata: metadata }),
96
+ // the original ?embed name was confusing, so we give minimal
97
+ ...(minimal != null && { embed: minimal }),
98
+ ...boolAttrs.reduce(
99
+ // add to URL if set in any way
100
+ (o, v) => (this[v.toLowerCase()] != null ? { ...o, [v]: this[v.toLowerCase()] } : o),
101
+ {}
102
+ ),
103
+ }).forEach(([k, v]) => {
104
+ if (!url.searchParams.has(k)) {
105
+ url.searchParams.set(k, v);
106
+ }
107
+ });
108
+ this.html`
109
+ <iframe
110
+ ref=${this.iframe}
111
+ src=${url}
112
+ allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
113
+ `;
114
+ },
115
+ });
116
+
117
+ export default { sdkVersion: "__SDK_VERSION__" };