Give video display as much space as possible (#84)

* Move room tools to top of page to use full width
Allow messages to be hidden while video is displaying
Allow video display to utilise all available width
Track unread messages while they are hidden
* Better portrait behaviour
* Show room controls by default
* Show room controls at same time as app bar
Improve video height calc.

Co-authored-by: Jeremy Kahn <jeremyckahn@gmail.com>
This commit is contained in:
Nasal Daemon 2023-01-24 03:50:14 +00:00 committed by GitHub
parent fcec242194
commit 8493ddade5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 715 additions and 320 deletions

458
package-lock.json generated
View File

@ -13,6 +13,7 @@
"@emotion/styled": "^11.10.0", "@emotion/styled": "^11.10.0",
"@mui/icons-material": "^5.8.4", "@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.3", "@mui/material": "^5.9.3",
"@react-hook/window-size": "^3.1.1",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0", "@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@ -117,32 +118,32 @@
} }
}, },
"node_modules/@babel/compat-data": { "node_modules/@babel/compat-data": {
"version": "7.18.8", "version": "7.20.10",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
"integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/core": { "node_modules/@babel/core": {
"version": "7.18.10", "version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
"integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.1.0", "@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10", "@babel/generator": "^7.20.7",
"@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-compilation-targets": "^7.20.7",
"@babel/helper-module-transforms": "^7.18.9", "@babel/helper-module-transforms": "^7.20.11",
"@babel/helpers": "^7.18.9", "@babel/helpers": "^7.20.7",
"@babel/parser": "^7.18.10", "@babel/parser": "^7.20.7",
"@babel/template": "^7.18.10", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.10", "@babel/traverse": "^7.20.12",
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
"json5": "^2.2.1", "json5": "^2.2.2",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"engines": { "engines": {
@ -215,11 +216,11 @@
} }
}, },
"node_modules/@babel/generator": { "node_modules/@babel/generator": {
"version": "7.18.12", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
"integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
"dependencies": { "dependencies": {
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/gen-mapping": "^0.3.2",
"jsesc": "^2.5.1" "jsesc": "^2.5.1"
}, },
@ -264,13 +265,14 @@
} }
}, },
"node_modules/@babel/helper-compilation-targets": { "node_modules/@babel/helper-compilation-targets": {
"version": "7.18.9", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
"integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
"dependencies": { "dependencies": {
"@babel/compat-data": "^7.18.8", "@babel/compat-data": "^7.20.5",
"@babel/helper-validator-option": "^7.18.6", "@babel/helper-validator-option": "^7.18.6",
"browserslist": "^4.20.2", "browserslist": "^4.21.3",
"lru-cache": "^5.1.1",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"engines": { "engines": {
@ -280,6 +282,14 @@
"@babel/core": "^7.0.0" "@babel/core": "^7.0.0"
} }
}, },
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"dependencies": {
"yallist": "^3.0.2"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": { "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -288,6 +298,11 @@
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
},
"node_modules/@babel/helper-create-class-features-plugin": { "node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.18.9", "version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz",
@ -367,12 +382,12 @@
} }
}, },
"node_modules/@babel/helper-function-name": { "node_modules/@babel/helper-function-name": {
"version": "7.18.9", "version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"dependencies": { "dependencies": {
"@babel/template": "^7.18.6", "@babel/template": "^7.18.10",
"@babel/types": "^7.18.9" "@babel/types": "^7.19.0"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -412,18 +427,18 @@
} }
}, },
"node_modules/@babel/helper-module-transforms": { "node_modules/@babel/helper-module-transforms": {
"version": "7.18.9", "version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
"integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
"dependencies": { "dependencies": {
"@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6", "@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.18.6", "@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.18.6", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.9", "@babel/traverse": "^7.20.10",
"@babel/types": "^7.18.9" "@babel/types": "^7.20.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -441,9 +456,9 @@
} }
}, },
"node_modules/@babel/helper-plugin-utils": { "node_modules/@babel/helper-plugin-utils": {
"version": "7.18.9", "version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==", "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -481,11 +496,11 @@
} }
}, },
"node_modules/@babel/helper-simple-access": { "node_modules/@babel/helper-simple-access": {
"version": "7.18.6", "version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"dependencies": { "dependencies": {
"@babel/types": "^7.18.6" "@babel/types": "^7.20.2"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -514,17 +529,17 @@
} }
}, },
"node_modules/@babel/helper-string-parser": { "node_modules/@babel/helper-string-parser": {
"version": "7.18.10", "version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.18.6", "version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -552,13 +567,13 @@
} }
}, },
"node_modules/@babel/helpers": { "node_modules/@babel/helpers": {
"version": "7.18.9", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
"integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
"dependencies": { "dependencies": {
"@babel/template": "^7.18.6", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.9", "@babel/traverse": "^7.20.7",
"@babel/types": "^7.18.9" "@babel/types": "^7.20.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -578,9 +593,9 @@
} }
}, },
"node_modules/@babel/parser": { "node_modules/@babel/parser": {
"version": "7.18.11", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
"integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==", "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
"bin": { "bin": {
"parser": "bin/babel-parser.js" "parser": "bin/babel-parser.js"
}, },
@ -1904,31 +1919,31 @@
} }
}, },
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.18.10", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.18.10", "@babel/parser": "^7.20.7",
"@babel/types": "^7.18.10" "@babel/types": "^7.20.7"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/traverse": { "node_modules/@babel/traverse": {
"version": "7.18.11", "version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
"integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10", "@babel/generator": "^7.20.7",
"@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.18.9", "@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.18.11", "@babel/parser": "^7.20.7",
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
}, },
@ -1937,12 +1952,12 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.18.10", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
"integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
"dependencies": { "dependencies": {
"@babel/helper-string-parser": "^7.18.10", "@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
}, },
"engines": { "engines": {
@ -4528,6 +4543,57 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"node_modules/@react-hook/debounce": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
"dependencies": {
"@react-hook/latest": "^1.0.2"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/event": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.6.tgz",
"integrity": "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q==",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/latest": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/throttle": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
"dependencies": {
"@react-hook/latest": "^1.0.2"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@react-hook/window-size": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.1.1.tgz",
"integrity": "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g==",
"dependencies": {
"@react-hook/debounce": "^3.0.0",
"@react-hook/event": "^1.2.1",
"@react-hook/throttle": "^2.2.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/@rollup/plugin-babel": { "node_modules/@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -16620,9 +16686,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@ -21674,9 +21740,9 @@
} }
}, },
"node_modules/promise": { "node_modules/promise": {
"version": "8.1.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"dependencies": { "dependencies": {
"asap": "~2.0.6" "asap": "~2.0.6"
} }
@ -24643,9 +24709,9 @@
} }
}, },
"node_modules/terser": { "node_modules/terser": {
"version": "5.14.2", "version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"dependencies": { "dependencies": {
"@jridgewell/source-map": "^0.3.2", "@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0", "acorn": "^8.5.0",
@ -26842,29 +26908,29 @@
} }
}, },
"@babel/compat-data": { "@babel/compat-data": {
"version": "7.18.8", "version": "7.20.10",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
"integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg=="
}, },
"@babel/core": { "@babel/core": {
"version": "7.18.10", "version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
"integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
"requires": { "requires": {
"@ampproject/remapping": "^2.1.0", "@ampproject/remapping": "^2.1.0",
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10", "@babel/generator": "^7.20.7",
"@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-compilation-targets": "^7.20.7",
"@babel/helper-module-transforms": "^7.18.9", "@babel/helper-module-transforms": "^7.20.11",
"@babel/helpers": "^7.18.9", "@babel/helpers": "^7.20.7",
"@babel/parser": "^7.18.10", "@babel/parser": "^7.20.7",
"@babel/template": "^7.18.10", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.10", "@babel/traverse": "^7.20.12",
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"gensync": "^1.0.0-beta.2", "gensync": "^1.0.0-beta.2",
"json5": "^2.2.1", "json5": "^2.2.2",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"dependencies": { "dependencies": {
@ -26912,11 +26978,11 @@
} }
}, },
"@babel/generator": { "@babel/generator": {
"version": "7.18.12", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
"integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
"requires": { "requires": {
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/gen-mapping": "^0.3.2",
"jsesc": "^2.5.1" "jsesc": "^2.5.1"
}, },
@ -26951,20 +27017,34 @@
} }
}, },
"@babel/helper-compilation-targets": { "@babel/helper-compilation-targets": {
"version": "7.18.9", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
"integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
"requires": { "requires": {
"@babel/compat-data": "^7.18.8", "@babel/compat-data": "^7.20.5",
"@babel/helper-validator-option": "^7.18.6", "@babel/helper-validator-option": "^7.18.6",
"browserslist": "^4.20.2", "browserslist": "^4.21.3",
"lru-cache": "^5.1.1",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"dependencies": { "dependencies": {
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"semver": { "semver": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
} }
} }
}, },
@ -27025,12 +27105,12 @@
} }
}, },
"@babel/helper-function-name": { "@babel/helper-function-name": {
"version": "7.18.9", "version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"requires": { "requires": {
"@babel/template": "^7.18.6", "@babel/template": "^7.18.10",
"@babel/types": "^7.18.9" "@babel/types": "^7.19.0"
} }
}, },
"@babel/helper-hoist-variables": { "@babel/helper-hoist-variables": {
@ -27058,18 +27138,18 @@
} }
}, },
"@babel/helper-module-transforms": { "@babel/helper-module-transforms": {
"version": "7.18.9", "version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
"integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
"requires": { "requires": {
"@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-module-imports": "^7.18.6", "@babel/helper-module-imports": "^7.18.6",
"@babel/helper-simple-access": "^7.18.6", "@babel/helper-simple-access": "^7.20.2",
"@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6",
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1",
"@babel/template": "^7.18.6", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.9", "@babel/traverse": "^7.20.10",
"@babel/types": "^7.18.9" "@babel/types": "^7.20.7"
} }
}, },
"@babel/helper-optimise-call-expression": { "@babel/helper-optimise-call-expression": {
@ -27081,9 +27161,9 @@
} }
}, },
"@babel/helper-plugin-utils": { "@babel/helper-plugin-utils": {
"version": "7.18.9", "version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
"integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ=="
}, },
"@babel/helper-remap-async-to-generator": { "@babel/helper-remap-async-to-generator": {
"version": "7.18.9", "version": "7.18.9",
@ -27109,11 +27189,11 @@
} }
}, },
"@babel/helper-simple-access": { "@babel/helper-simple-access": {
"version": "7.18.6", "version": "7.20.2",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
"integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
"requires": { "requires": {
"@babel/types": "^7.18.6" "@babel/types": "^7.20.2"
} }
}, },
"@babel/helper-skip-transparent-expression-wrappers": { "@babel/helper-skip-transparent-expression-wrappers": {
@ -27133,14 +27213,14 @@
} }
}, },
"@babel/helper-string-parser": { "@babel/helper-string-parser": {
"version": "7.18.10", "version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw=="
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.18.6", "version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
}, },
"@babel/helper-validator-option": { "@babel/helper-validator-option": {
"version": "7.18.6", "version": "7.18.6",
@ -27159,13 +27239,13 @@
} }
}, },
"@babel/helpers": { "@babel/helpers": {
"version": "7.18.9", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
"integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
"requires": { "requires": {
"@babel/template": "^7.18.6", "@babel/template": "^7.20.7",
"@babel/traverse": "^7.18.9", "@babel/traverse": "^7.20.7",
"@babel/types": "^7.18.9" "@babel/types": "^7.20.7"
} }
}, },
"@babel/highlight": { "@babel/highlight": {
@ -27179,9 +27259,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.18.11", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
"integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==" "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg=="
}, },
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.18.6", "version": "7.18.6",
@ -28035,39 +28115,39 @@
} }
}, },
"@babel/template": { "@babel/template": {
"version": "7.18.10", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"requires": { "requires": {
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.18.10", "@babel/parser": "^7.20.7",
"@babel/types": "^7.18.10" "@babel/types": "^7.20.7"
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.18.11", "version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
"integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
"requires": { "requires": {
"@babel/code-frame": "^7.18.6", "@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.18.10", "@babel/generator": "^7.20.7",
"@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.18.9", "@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.18.11", "@babel/parser": "^7.20.7",
"@babel/types": "^7.18.10", "@babel/types": "^7.20.7",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.18.10", "version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
"integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
"requires": { "requires": {
"@babel/helper-string-parser": "^7.18.10", "@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
@ -29990,6 +30070,44 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"@react-hook/debounce": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@react-hook/debounce/-/debounce-3.0.0.tgz",
"integrity": "sha512-ir/kPrSfAzY12Gre0sOHkZ2rkEmM4fS5M5zFxCi4BnCeXh2nvx9Ujd+U4IGpKCuPA+EQD0pg1eK2NGLvfWejag==",
"requires": {
"@react-hook/latest": "^1.0.2"
}
},
"@react-hook/event": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@react-hook/event/-/event-1.2.6.tgz",
"integrity": "sha512-JUL5IluaOdn5w5Afpe/puPa1rj8X6udMlQ9dt4hvMuKmTrBS1Ya6sb4sVgvfe2eU4yDuOfAhik8xhbcCekbg9Q==",
"requires": {}
},
"@react-hook/latest": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
"requires": {}
},
"@react-hook/throttle": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@react-hook/throttle/-/throttle-2.2.0.tgz",
"integrity": "sha512-LJ5eg+yMV8lXtqK3lR+OtOZ2WH/EfWvuiEEu0M3bhR7dZRfTyEJKxH1oK9uyBxiXPtWXiQggWbZirMCXam51tg==",
"requires": {
"@react-hook/latest": "^1.0.2"
}
},
"@react-hook/window-size": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@react-hook/window-size/-/window-size-3.1.1.tgz",
"integrity": "sha512-yWnVS5LKnOUIrEsI44oz3bIIUYqflamPL27n+k/PC//PsX/YeWBky09oPeAoc9As6jSH16Wgo8plI+ECZaHk3g==",
"requires": {
"@react-hook/debounce": "^3.0.0",
"@react-hook/event": "^1.2.1",
"@react-hook/throttle": "^2.2.0"
}
},
"@rollup/plugin-babel": { "@rollup/plugin-babel": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -38958,9 +39076,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
}, },
"json5": { "json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
}, },
"jsonfile": { "jsonfile": {
"version": "6.1.0", "version": "6.1.0",
@ -42491,9 +42609,9 @@
} }
}, },
"promise": { "promise": {
"version": "8.1.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
"integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
"requires": { "requires": {
"asap": "~2.0.6" "asap": "~2.0.6"
} }
@ -44694,9 +44812,9 @@
} }
}, },
"terser": { "terser": {
"version": "5.14.2", "version": "5.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
"integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
"requires": { "requires": {
"@jridgewell/source-map": "^0.3.2", "@jridgewell/source-map": "^0.3.2",
"acorn": "^8.5.0", "acorn": "^8.5.0",

View File

@ -9,6 +9,7 @@
"@emotion/styled": "^11.10.0", "@emotion/styled": "^11.10.0",
"@mui/icons-material": "^5.8.4", "@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.3", "@mui/material": "^5.9.3",
"@react-hook/window-size": "^3.1.1",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0", "@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",

View File

@ -1,7 +1,8 @@
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import Paper from '@mui/material/Paper' import Paper from '@mui/material/Paper'
import Tooltip from '@mui/material/Tooltip'
import { PeerNameDisplay } from 'components/PeerNameDisplay' import { getPeerName } from 'components/PeerNameDisplay'
import { VideoStreamType } from 'models/chat' import { VideoStreamType } from 'models/chat'
import { SelectedPeerStream } from './RoomVideoDisplay' import { SelectedPeerStream } from './RoomVideoDisplay'
@ -48,7 +49,8 @@ export const PeerVideo = ({
video.srcObject = videoStream video.srcObject = videoStream
}, [videoRef, videoStream]) }, [videoRef, videoStream])
const sizePercent = 100 / Math.sqrt(nextPerfectSquare(numberOfVideos - 1)) const cols = Math.sqrt(nextPerfectSquare(numberOfVideos - 1))
const rows = Math.ceil(numberOfVideos / cols)
const handleVideoClick = () => { const handleVideoClick = () => {
onVideoClick?.(userId, videoStreamType, videoStream) onVideoClick?.(userId, videoStreamType, videoStream)
@ -63,44 +65,46 @@ export const PeerVideo = ({
justifyContent: 'center', justifyContent: 'center',
mx: 'auto', mx: 'auto',
overflow: 'auto', overflow: 'auto',
padding: 2, padding: '0px',
marginBottom: '5px',
marginRight: '5px',
...(selectedPeerStream ...(selectedPeerStream
? { ? {
height: '100%', height: 'calc(100% - 5px)',
width: 'calc(100% - 5px)',
} }
: { : {
width: `calc(${sizePercent}% - 1em)`, width: `calc(${100 / cols}% - 5px)`,
height: `calc(${sizePercent}% - 1em)`, height: `calc(${100 / rows}% - 5px)`,
my: 1,
}), }),
...(selectedPeerStream &&
!isSelectedVideo && {
width: 'min-content',
}),
}} }}
elevation={10} elevation={10}
> >
<video <Tooltip
playsInline title={getPeerName(userId)}
ref={videoRef} placement="top"
onClick={handleVideoClick} componentsProps={{
style={{ tooltip: { sx: { position: 'absolute', top: '25px' } },
borderRadius: '.25em',
cursor: 'pointer',
overflow: 'auto',
marginLeft: 'auto',
marginRight: 'auto',
height: '100%',
...(isSelfVideo && {
transform: 'rotateY(180deg)',
}),
}} }}
/>
<PeerNameDisplay
sx={{ textAlign: 'center', display: 'block', marginTop: 1, px: 1 }}
> >
{userId} <video
</PeerNameDisplay> playsInline
ref={videoRef}
onClick={handleVideoClick}
style={{
borderRadius: '.25em',
cursor: 'pointer',
overflow: 'auto',
marginLeft: 'auto',
marginRight: 'auto',
height: '100%',
width: '100%',
...(isSelfVideo && {
transform: 'rotateY(180deg)',
}),
}}
/>
</Tooltip>
</Paper> </Paper>
) )
} }

View File

@ -1,15 +1,18 @@
import Accordion from '@mui/material/Accordion' import { useContext } from 'react'
import AccordionSummary from '@mui/material/AccordionSummary'
import AccordionDetails from '@mui/material/AccordionDetails' import { useWindowSize } from '@react-hook/window-size'
import Collapse from '@mui/material/Collapse'
import Zoom from '@mui/material/Zoom'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider' import Divider from '@mui/material/Divider'
import Typography from '@mui/material/Typography'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import { v4 as uuid } from 'uuid' import { v4 as uuid } from 'uuid'
import { rtcConfig } from 'config/rtcConfig' import { rtcConfig } from 'config/rtcConfig'
import { trackerUrls } from 'config/trackerUrls' import { trackerUrls } from 'config/trackerUrls'
import { RoomContext } from 'contexts/RoomContext' import { RoomContext } from 'contexts/RoomContext'
import { ShellContext } from 'contexts/ShellContext'
import { MessageForm } from 'components/MessageForm' import { MessageForm } from 'components/MessageForm'
import { ChatTranscript } from 'components/ChatTranscript' import { ChatTranscript } from 'components/ChatTranscript'
@ -19,6 +22,8 @@ import { RoomVideoControls } from './RoomVideoControls'
import { RoomScreenShareControls } from './RoomScreenShareControls' import { RoomScreenShareControls } from './RoomScreenShareControls'
import { RoomFileUploadControls } from './RoomFileUploadControls' import { RoomFileUploadControls } from './RoomFileUploadControls'
import { RoomVideoDisplay } from './RoomVideoDisplay' import { RoomVideoDisplay } from './RoomVideoDisplay'
import { RoomShowMessagesControls } from './RoomShowMessagesControls'
import { RoomHideRoomControls } from './RoomHideRoomControls'
export interface RoomProps { export interface RoomProps {
appId?: string appId?: string
@ -61,6 +66,13 @@ export function Room({
await sendMessage(message) await sendMessage(message)
} }
const showMessages = roomContextValue.isShowingMessages
const { showRoomControls } = useContext(ShellContext)
const [windowWidth, windowHeight] = useWindowSize()
const landscape = windowWidth > windowHeight
return ( return (
<RoomContext.Provider value={roomContextValue}> <RoomContext.Provider value={roomContextValue}>
<Box <Box
@ -72,7 +84,6 @@ export function Room({
overflow: 'auto', overflow: 'auto',
}} }}
> >
{showVideoDisplay && <RoomVideoDisplay userId={userId} />}
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
@ -81,50 +92,70 @@ export function Room({
overflow: 'auto', overflow: 'auto',
}} }}
> >
<Accordion> <Collapse in={showRoomControls}>
<AccordionSummary <Box
expandIcon={<ExpandMoreIcon />} sx={{
aria-controls="panel1a-content" alignItems: 'flex-start',
id="panel1a-header" display: 'flex',
justifyContent: 'center',
padding: 1,
overflowX: 'auto',
}}
> >
<Typography <RoomAudioControls peerRoom={peerRoom} />
sx={{ <RoomVideoControls peerRoom={peerRoom} />
color: 'text.secondary', <RoomScreenShareControls peerRoom={peerRoom} />
textAlign: 'center', <RoomFileUploadControls
flexGrow: 1, peerRoom={peerRoom}
}} onInlineMediaUpload={handleInlineMediaUpload}
> />
Room tools <Zoom in={showVideoDisplay} mountOnEnter unmountOnExit>
</Typography> <span>
</AccordionSummary> <RoomShowMessagesControls />
<AccordionDetails> </span>
</Zoom>
<RoomHideRoomControls />
</Box>
</Collapse>
<Box
sx={{
display: 'flex',
flexDirection: landscape ? 'row' : 'column',
height: '100%',
width: '100%',
overflow: 'auto',
}}
>
{showVideoDisplay && (
<RoomVideoDisplay
userId={userId}
width="100%"
height={landscape || !showMessages ? '100%' : '60%'}
/>
)}
{showMessages && (
<Box <Box
sx={{ sx={{
alignItems: 'flex-start',
display: 'flex', display: 'flex',
justifyContent: 'center', flexDirection: 'column',
flexGrow: '1',
width: showVideoDisplay && landscape ? '400px' : '100%',
height: landscape ? '100%' : '40%',
}} }}
> >
<RoomAudioControls peerRoom={peerRoom} /> <ChatTranscript
<RoomVideoControls peerRoom={peerRoom} /> messageLog={messageLog}
<RoomScreenShareControls peerRoom={peerRoom} /> userId={userId}
<RoomFileUploadControls className="grow overflow-auto px-4"
peerRoom={peerRoom} />
onInlineMediaUpload={handleInlineMediaUpload} <Divider />
<MessageForm
onMessageSubmit={handleMessageSubmit}
isMessageSending={isMessageSending}
/> />
</Box> </Box>
</AccordionDetails> )}
</Accordion> </Box>
<ChatTranscript
messageLog={messageLog}
userId={userId}
className="grow overflow-auto px-4"
/>
<Divider />
<MessageForm
onMessageSubmit={handleMessageSubmit}
isMessageSending={isMessageSending}
/>
</Box> </Box>
</Box> </Box>
</RoomContext.Provider> </RoomContext.Provider>

View File

@ -0,0 +1,34 @@
import { useContext } from 'react'
import Fab from '@mui/material/Fab'
import Tooltip from '@mui/material/Tooltip'
import { ExpandLess } from '@mui/icons-material'
import { Box } from '@mui/material'
import { ShellContext } from 'contexts/ShellContext'
export function RoomHideRoomControls() {
const { setShowRoomControls } = useContext(ShellContext)
return (
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
px: 1,
}}
>
<Tooltip title="Hide controls">
<Fab
color="primary"
aria-label="hide controls"
onClick={() => setShowRoomControls(false)}
>
<ExpandLess />
</Fab>
</Tooltip>
</Box>
)
}

View File

@ -0,0 +1,37 @@
import { useContext } from 'react'
import Fab from '@mui/material/Fab'
import Tooltip from '@mui/material/Tooltip'
import { Comment, CommentsDisabled } from '@mui/icons-material'
import { Badge, Box } from '@mui/material'
import { RoomContext } from 'contexts/RoomContext'
export function RoomShowMessagesControls() {
const { isShowingMessages, setIsShowingMessages, unreadMessages } =
useContext(RoomContext)
return (
<Box
sx={{
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
px: 1,
}}
>
<Tooltip title={isShowingMessages ? 'Hide messages' : 'Show messages'}>
<Fab
color={isShowingMessages ? 'error' : 'success'}
aria-label="show messages"
onClick={() => setIsShowingMessages(!isShowingMessages)}
>
<Badge color="error" badgeContent={unreadMessages}>
{isShowingMessages ? <CommentsDisabled /> : <Comment />}
</Badge>
</Fab>
</Tooltip>
</Box>
)
}

View File

@ -22,9 +22,15 @@ export interface SelectedPeerStream {
export interface RoomVideoDisplayProps { export interface RoomVideoDisplayProps {
userId: string userId: string
width: string
height: string
} }
export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => { export const RoomVideoDisplay = ({
userId,
width,
height,
}: RoomVideoDisplayProps) => {
const shellContext = useContext(ShellContext) const shellContext = useContext(ShellContext)
const roomContext = useContext(RoomContext) const roomContext = useContext(RoomContext)
const [selectedPeerStream, setSelectedPeerStream] = const [selectedPeerStream, setSelectedPeerStream] =
@ -121,11 +127,12 @@ export const RoomVideoDisplay = ({ userId }: RoomVideoDisplayProps) => {
flexDirection: 'column', flexDirection: 'column',
overflow: 'auto', overflow: 'auto',
padding: 1, padding: 1,
width: '85%', width: { width },
height: { height },
}} }}
> >
{selectedPeerStream && ( {selectedPeerStream && (
<Box sx={{ height: '80%' }}> <Box sx={{ height: '80%', width: '100%' }}>
<PeerVideo <PeerVideo
isSelectedVideo isSelectedVideo
numberOfVideos={numberOfVideos} numberOfVideos={numberOfVideos}

View File

@ -88,6 +88,9 @@ export function useRoom(
_setMessageLog(messages.slice(-messageTranscriptSizeLimit)) _setMessageLog(messages.slice(-messageTranscriptSizeLimit))
} }
const [isShowingMessages, setIsShowingMessages] = useState(true)
const [unreadMessages, setUnreadMessages] = useState(0)
const [selfVideoStream, setSelfVideoStream] = useState<MediaStream | null>( const [selfVideoStream, setSelfVideoStream] = useState<MediaStream | null>(
null null
) )
@ -110,6 +113,9 @@ export function useRoom(
() => ({ () => ({
isPrivate, isPrivate,
isMessageSending, isMessageSending,
isShowingMessages,
setIsShowingMessages,
unreadMessages,
selfVideoStream, selfVideoStream,
setSelfVideoStream, setSelfVideoStream,
peerVideoStreams, peerVideoStreams,
@ -124,6 +130,9 @@ export function useRoom(
[ [
isPrivate, isPrivate,
isMessageSending, isMessageSending,
isShowingMessages,
setIsShowingMessages,
unreadMessages,
selfVideoStream, selfVideoStream,
setSelfVideoStream, setSelfVideoStream,
peerVideoStreams, peerVideoStreams,
@ -168,6 +177,10 @@ export function useRoom(
} }
}, [setDoShowPeers]) }, [setDoShowPeers])
useEffect(() => {
if (isShowingMessages) setUnreadMessages(0)
}, [isShowingMessages, setUnreadMessages])
const [sendPeerId, receivePeerId] = usePeerRoomAction<string>( const [sendPeerId, receivePeerId] = usePeerRoomAction<string>(
peerRoom, peerRoom,
PeerActions.PEER_NAME PeerActions.PEER_NAME
@ -234,7 +247,11 @@ export function useRoom(
receivePeerMessage(message => { receivePeerMessage(message => {
const userSettings = settingsContext.getUserSettings() const userSettings = settingsContext.getUserSettings()
if (!tabHasFocus) { if (!isShowingMessages) {
setUnreadMessages(unreadMessages + 1)
}
if (!tabHasFocus || !isShowingMessages) {
if (userSettings.playSoundOnNewMessage) { if (userSettings.playSoundOnNewMessage) {
newMessageAudio.play() newMessageAudio.play()
} }
@ -302,6 +319,8 @@ export function useRoom(
Object.values({ ...peerVideoStreams, ...peerScreenStreams }).length > 0 Object.values({ ...peerVideoStreams, ...peerScreenStreams }).length > 0
) )
if (!showVideoDisplay && !isShowingMessages) setIsShowingMessages(true)
const handleInlineMediaUpload = async (files: File[]) => { const handleInlineMediaUpload = async (files: File[]) => {
const fileOfferId = await fileTransfer.offer(files) const fileOfferId = await fileTransfer.offer(files)

View File

@ -1,5 +1,6 @@
import { PropsWithChildren } from 'react' import { PropsWithChildren } from 'react'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Collapse from '@mui/material/Collapse'
import { styled } from '@mui/material/styles' import { styled } from '@mui/material/styles'
import { DrawerHeader } from './DrawerHeader' import { DrawerHeader } from './DrawerHeader'
@ -38,12 +39,14 @@ const Main = styled('main', {
interface RouteContentProps extends PropsWithChildren { interface RouteContentProps extends PropsWithChildren {
isDrawerOpen: boolean isDrawerOpen: boolean
isPeerListOpen: boolean isPeerListOpen: boolean
showAppBar: boolean
} }
export const RouteContent = ({ export const RouteContent = ({
children, children,
isDrawerOpen, isDrawerOpen,
isPeerListOpen, isPeerListOpen,
showAppBar,
}: RouteContentProps) => { }: RouteContentProps) => {
return ( return (
<Main <Main
@ -55,7 +58,9 @@ export const RouteContent = ({
width: '100%', width: '100%',
}} }}
> >
<DrawerHeader /> <Collapse in={showAppBar} sx={{ flex: 'none' }}>
<DrawerHeader />
</Collapse>
<Box sx={{ overflow: 'auto', flexGrow: 1 }}>{children}</Box> <Box sx={{ overflow: 'auto', flexGrow: 1 }}>{children}</Box>
</Main> </Main>
) )

View File

@ -40,6 +40,9 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
const [isRoomShareDialogOpen, setIsRoomShareDialogOpen] = useState(false) const [isRoomShareDialogOpen, setIsRoomShareDialogOpen] = useState(false)
const [doShowPeers, setDoShowPeers] = useState(false) const [doShowPeers, setDoShowPeers] = useState(false)
const [alertSeverity, setAlertSeverity] = useState<AlertColor>('info') const [alertSeverity, setAlertSeverity] = useState<AlertColor>('info')
const [showAppBar, setShowAppBar] = useState(true)
const [showRoomControls, setShowRoomControls] = useState(true)
const [isFullscreen, setIsFullscreen] = useState(false)
const [title, setTitle] = useState('') const [title, setTitle] = useState('')
const [alertText, setAlertText] = useState('') const [alertText, setAlertText] = useState('')
const [numberOfPeers, setNumberOfPeers] = useState(1) const [numberOfPeers, setNumberOfPeers] = useState(1)
@ -67,6 +70,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
tabHasFocus, tabHasFocus,
setDoShowPeers, setDoShowPeers,
setNumberOfPeers, setNumberOfPeers,
showRoomControls,
setShowRoomControls,
setTitle, setTitle,
showAlert, showAlert,
isPeerListOpen, isPeerListOpen,
@ -97,6 +102,8 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
tabHasFocus, tabHasFocus,
setDoShowPeers, setDoShowPeers,
setNumberOfPeers, setNumberOfPeers,
showRoomControls,
setShowRoomControls,
setTitle, setTitle,
showAlert, showAlert,
audioState, audioState,
@ -135,6 +142,57 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
document.title = title document.title = title
}, [title]) }, [title])
const enterFullscreen = async () => {
const body: any = document.body
try {
if (body.requestFullscreen) {
await body.requestFullscreen()
} else if (body.webkitRequestFullscreen) {
await body.webkitRequestFullscreen()
} else if (body.mozRequestFullScreen) {
await body.mozRequestFullScreen()
} else if (body.msRequestFullscreen) {
await body.msRequestFullscreen()
}
} catch (e) {
// Silence harmless errors
}
}
const exitFullscreen = async () => {
const document: any = window.document
try {
if (document.exitFullscreen) {
await document.exitFullscreen()
} else if (document.webkitExitFullscreen) {
await document.webkitExitFullscreen()
} else if (document.mozCancelFullScreen) {
await document.mozCancelFullScreen()
} else if (document.msExitFullScreen) {
await document.msExitFullScreen()
}
} catch (e) {
// Silence harmless errors
}
}
useEffect(() => {
if (isFullscreen) {
enterFullscreen()
setShowRoomControls(false)
setShowAppBar(false)
} else {
exitFullscreen()
setShowAppBar(true)
setShowRoomControls(true)
}
}, [isFullscreen, setShowRoomControls, setShowAppBar])
useEffect(() => {
if (isFullscreen) setShowAppBar(showRoomControls)
}, [isFullscreen, showRoomControls, setShowAppBar])
useEffect(() => { useEffect(() => {
const handleFocus = () => { const handleFocus = () => {
setTabHasFocus(true) setTabHasFocus(true)
@ -142,11 +200,16 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
const handleBlur = () => { const handleBlur = () => {
setTabHasFocus(false) setTabHasFocus(false)
} }
const handleFullscreen = (event: Event) => {
setIsFullscreen(!!document.fullscreenElement)
}
window.addEventListener('focus', handleFocus) window.addEventListener('focus', handleFocus)
window.addEventListener('blur', handleBlur) window.addEventListener('blur', handleBlur)
document.addEventListener('fullscreenchange', handleFullscreen)
return () => { return () => {
window.removeEventListener('focus', handleFocus) window.removeEventListener('focus', handleFocus)
window.removeEventListener('blur', handleBlur) window.removeEventListener('blur', handleBlur)
document.removeEventListener('fullscreenchange', handleFullscreen)
} }
}, []) }, [])
@ -230,7 +293,11 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
numberOfPeers={numberOfPeers} numberOfPeers={numberOfPeers}
title={title} title={title}
onPeerListClick={handlePeerListClick} onPeerListClick={handlePeerListClick}
onRoomControlsClick={() => setShowRoomControls(!showRoomControls)}
setIsQRCodeDialogOpen={setIsQRCodeDialogOpen} setIsQRCodeDialogOpen={setIsQRCodeDialogOpen}
showAppBar={showAppBar}
isFullscreen={isFullscreen}
setIsFullscreen={setIsFullscreen}
/> />
<Drawer <Drawer
isDrawerOpen={isDrawerOpen} isDrawerOpen={isDrawerOpen}
@ -245,6 +312,7 @@ export const Shell = ({ appNeedsUpdate, children, userPeerId }: ShellProps) => {
<RouteContent <RouteContent
isDrawerOpen={isDrawerOpen} isDrawerOpen={isDrawerOpen}
isPeerListOpen={isPeerListOpen} isPeerListOpen={isPeerListOpen}
showAppBar={showAppBar}
> >
<ErrorBoundary>{children}</ErrorBoundary> <ErrorBoundary>{children}</ErrorBoundary>
</RouteContent> </RouteContent>

View File

@ -1,13 +1,22 @@
import { styled } from '@mui/material/styles' import { styled } from '@mui/material/styles'
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
import Toolbar from '@mui/material/Toolbar'
import Typography from '@mui/material/Typography'
import StepIcon from '@mui/material/StepIcon'
import Tooltip from '@mui/material/Tooltip'
import IconButton from '@mui/material/IconButton' import IconButton from '@mui/material/IconButton'
import MenuIcon from '@mui/icons-material/Menu' import MuiAppBar, { AppBarProps as MuiAppBarProps } from '@mui/material/AppBar'
import LinkIcon from '@mui/icons-material/Link' import Fab from '@mui/material/Fab'
import QrCode2Icon from '@mui/icons-material/QrCode2' import StepIcon from '@mui/material/StepIcon'
import Toolbar from '@mui/material/Toolbar'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import Slide from '@mui/material/Slide'
import Zoom from '@mui/material/Zoom'
import ExpandMore from '@mui/icons-material/ExpandMore'
import Fullscreen from '@mui/icons-material/Fullscreen'
import FullscreenExit from '@mui/icons-material/FullscreenExit'
import Link from '@mui/icons-material/Link'
import Menu from '@mui/icons-material/Menu'
import QrCode2 from '@mui/icons-material/QrCode2'
import RoomPreferences from '@mui/icons-material/RoomPreferences'
import { drawerWidth } from './Drawer' import { drawerWidth } from './Drawer'
import { peerListWidth } from './PeerList' import { peerListWidth } from './PeerList'
@ -54,7 +63,11 @@ interface ShellAppBarProps {
numberOfPeers: number numberOfPeers: number
title: string title: string
onPeerListClick: () => void onPeerListClick: () => void
onRoomControlsClick: () => void
setIsQRCodeDialogOpen: (isOpen: boolean) => void setIsQRCodeDialogOpen: (isOpen: boolean) => void
showAppBar: boolean
isFullscreen: boolean
setIsFullscreen: (isFullscreen: boolean) => void
} }
export const ShellAppBar = ({ export const ShellAppBar = ({
@ -67,76 +80,124 @@ export const ShellAppBar = ({
numberOfPeers, numberOfPeers,
title, title,
onPeerListClick, onPeerListClick,
onRoomControlsClick,
showAppBar,
isFullscreen,
setIsFullscreen,
}: ShellAppBarProps) => { }: ShellAppBarProps) => {
const handleQRCodeClick = () => setIsQRCodeDialogOpen(true) const handleQRCodeClick = () => setIsQRCodeDialogOpen(true)
const onClickFullscreen = () => setIsFullscreen(!isFullscreen)
return ( return (
<AppBar <>
position="fixed" <Slide appear={false} in={showAppBar} mountOnEnter unmountOnExit>
isDrawerOpen={isDrawerOpen} <AppBar
isPeerListOpen={isPeerListOpen} position="fixed"
> isDrawerOpen={isDrawerOpen}
<Toolbar isPeerListOpen={isPeerListOpen}
variant="regular"
sx={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="Open menu"
sx={{ mr: 2, ...(isDrawerOpen && { display: 'none' }) }}
onClick={onDrawerOpen}
> >
<MenuIcon /> <Toolbar
</IconButton> variant="regular"
<Typography sx={{
variant="h6" display: 'flex',
noWrap flexDirection: 'row',
component="div" justifyContent: 'space-between',
sx={{ marginRight: 'auto' }} }}
>
{title}
</Typography>
<Tooltip title="Copy current URL">
<IconButton
size="large"
color="inherit"
aria-label="Copy current URL"
onClick={onLinkButtonClick}
> >
<LinkIcon /> <IconButton
</IconButton> size="large"
edge="start"
color="inherit"
aria-label="Open menu"
sx={{ mr: 2, ...(isDrawerOpen && { display: 'none' }) }}
onClick={onDrawerOpen}
>
<Menu />
</IconButton>
<Typography
variant="h6"
noWrap
component="div"
sx={{ marginRight: 'auto' }}
>
{title}
</Typography>
<Tooltip title="Copy current URL">
<IconButton
size="large"
color="inherit"
aria-label="Copy current URL"
onClick={onLinkButtonClick}
>
<Link />
</IconButton>
</Tooltip>
{doShowPeers ? (
<>
<Tooltip title="Show QR Code">
<IconButton
size="large"
color="inherit"
aria-label="Show QR Code"
onClick={handleQRCodeClick}
>
<QrCode2 />
</IconButton>
</Tooltip>
<Tooltip title="Show Room Controls">
<IconButton
size="large"
color="inherit"
aria-label="show room controls"
onClick={onRoomControlsClick}
>
<RoomPreferences />
</IconButton>
</Tooltip>
<Tooltip
title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}
>
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="fullscreen"
onClick={onClickFullscreen}
>
{isFullscreen ? <FullscreenExit /> : <Fullscreen />}
</IconButton>
</Tooltip>
<Tooltip title="Click to show peer list">
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="Peer list"
onClick={onPeerListClick}
>
<StepIcon icon={numberOfPeers} />
</IconButton>
</Tooltip>
</>
) : null}
</Toolbar>
</AppBar>
</Slide>
<Zoom
style={{ position: 'absolute', left: '16px', top: '16px' }}
in={!showAppBar}
unmountOnExit
>
<Tooltip title="Show room controls">
<Fab
size="small"
aria-label="show room controls"
color="primary"
onClick={onRoomControlsClick}
>
<ExpandMore />
</Fab>
</Tooltip> </Tooltip>
{doShowPeers ? ( </Zoom>
<> </>
<Tooltip title="Show QR Code">
<IconButton
size="large"
color="inherit"
aria-label="Show QR Code"
onClick={handleQRCodeClick}
>
<QrCode2Icon />
</IconButton>
</Tooltip>
<Tooltip title="Click to show peer list">
<IconButton
size="large"
edge="end"
color="inherit"
aria-label="Peer list"
onClick={onPeerListClick}
>
<StepIcon icon={numberOfPeers} />
</IconButton>
</Tooltip>
</>
) : null}
</Toolbar>
</AppBar>
) )
} }

View File

@ -4,6 +4,9 @@ import { FileOfferMetadata } from 'models/chat'
interface RoomContextProps { interface RoomContextProps {
isPrivate: boolean isPrivate: boolean
isMessageSending: boolean isMessageSending: boolean
isShowingMessages: boolean
setIsShowingMessages: Dispatch<SetStateAction<boolean>>
unreadMessages: number
selfVideoStream: MediaStream | null selfVideoStream: MediaStream | null
setSelfVideoStream: Dispatch<SetStateAction<MediaStream | null>> setSelfVideoStream: Dispatch<SetStateAction<MediaStream | null>>
peerVideoStreams: Record<string, MediaStream> peerVideoStreams: Record<string, MediaStream>
@ -21,6 +24,9 @@ interface RoomContextProps {
export const RoomContext = createContext<RoomContextProps>({ export const RoomContext = createContext<RoomContextProps>({
isPrivate: false, isPrivate: false,
isMessageSending: false, isMessageSending: false,
isShowingMessages: true,
setIsShowingMessages: () => {},
unreadMessages: 0,
selfVideoStream: null, selfVideoStream: null,
setSelfVideoStream: () => {}, setSelfVideoStream: () => {},
peerVideoStreams: {}, peerVideoStreams: {},

View File

@ -8,6 +8,8 @@ interface ShellContextProps {
tabHasFocus: boolean tabHasFocus: boolean
setDoShowPeers: Dispatch<SetStateAction<boolean>> setDoShowPeers: Dispatch<SetStateAction<boolean>>
setNumberOfPeers: Dispatch<SetStateAction<number>> setNumberOfPeers: Dispatch<SetStateAction<number>>
showRoomControls: boolean
setShowRoomControls: Dispatch<SetStateAction<boolean>>
setTitle: Dispatch<SetStateAction<string>> setTitle: Dispatch<SetStateAction<string>>
showAlert: (message: string, options?: AlertOptions) => void showAlert: (message: string, options?: AlertOptions) => void
roomId?: string roomId?: string
@ -31,6 +33,8 @@ export const ShellContext = createContext<ShellContextProps>({
tabHasFocus: true, tabHasFocus: true,
setDoShowPeers: () => {}, setDoShowPeers: () => {},
setNumberOfPeers: () => {}, setNumberOfPeers: () => {},
showRoomControls: false,
setShowRoomControls: () => {},
setTitle: () => {}, setTitle: () => {},
showAlert: () => {}, showAlert: () => {},
roomId: undefined, roomId: undefined,