Skip to content

Commit

Permalink
Merge pull request #216 from solidjs-community/permission-in-firefox
Browse files Browse the repository at this point in the history
permission: fix in firefox
  • Loading branch information
thetarnav authored Sep 28, 2022
2 parents 2ec068b + c7ace0f commit 65b6c30
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/healthy-radios-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solid-primitives/permission": minor
---

fix in firefox
35 changes: 35 additions & 0 deletions packages/permission/dev/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Solid App</title>
<style>
html {
font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
}

body {
padding: 0;
margin: 0;
}

a,
button {
cursor: pointer;
}

* {
margin: 0;
}
</style>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<script src="./index.tsx" type="module"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions packages/permission/dev/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Component } from "solid-js";
import { render } from "solid-js/web";
import { createPermission } from "../src";
import "uno.css";

const App: Component = () => {
const micPermission = createPermission("microphone");
const camPermission = createPermission("camera");

const requestPermission = (constraints: MediaStreamConstraints) =>
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => stream.getTracks().forEach(track => track.stop()))
.catch(console.warn);

return (
<div class="p-24 box-border w-full min-h-screen flex flex-col justify-center items-center space-y-4 bg-gray-800 text-white">
<div class="wrapper-v">
<h4>Microphone permission:</h4>
<p>{micPermission}</p>
<h4>Camera permission:</h4>
<p>{camPermission}</p>
<h4>Request permissions:</h4>
<button onClick={() => requestPermission({ audio: true })}>Microphone</button>
<button onClick={() => requestPermission({ video: true })}>Camera</button>
<button onClick={() => requestPermission({ audio: true, video: true })}>Both</button>
</div>
</div>
);
};

render(() => <App />, document.getElementById("root")!);
2 changes: 2 additions & 0 deletions packages/permission/dev/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { viteConfig } from "../../../vite.config";
export default viteConfig;
6 changes: 5 additions & 1 deletion packages/permission/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"scripts": {
"build": "tsup",
"dev": "vite serve dev --host",
"test": "uvu -r solid-register"
},
"keywords": [
Expand All @@ -53,7 +54,10 @@
"tslib": "2.3.1",
"tsup": "^6.2.3",
"typescript": "^4.8.2",
"uvu": "^0.5.6"
"unocss": "^0.45.15",
"uvu": "^0.5.6",
"vite": "^3.0.9",
"vite-plugin-solid": "^2.3.0"
},
"peerDependencies": {
"solid-js": ">= 1.0.0"
Expand Down
46 changes: 37 additions & 9 deletions packages/permission/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,50 @@
import { Accessor, createSignal, onCleanup } from "solid-js";
import { Accessor, createEffect, createSignal, on, onCleanup } from "solid-js";

/**
* Querying the permission API
*
* @param name permission name (e.g. "microphone") or a PermissionDescriptor object (`{ name: ... }`)
* @returns "unknown" | "pending" | "granted" | "rejected"
* @returns "unknown" | "denied" | "granted" | "prompt"
*/
export const createPermission = (
name: PermissionDescriptor | PermissionName
name: PermissionDescriptor | PermissionName | "microphone" | "camera"
): Accessor<PermissionState | "unknown"> => {
const [permission, setPermission] = createSignal<PermissionState | "unknown">("unknown");
const [status, setStatus] = createSignal<PermissionStatus>();
if (navigator) {
navigator.permissions.query(typeof name === "string" ? { name } : name).then(status => {
setPermission(status.state);
const listener = () => setPermission(status.state);
status.addEventListener("change", listener);
onCleanup(() => status.removeEventListener("change", listener));
});
navigator.permissions
.query(typeof name === "string" ? { name: name as PermissionName } : name)
.then(setStatus)
.catch(error => {
if (error.name !== "TypeError" || (name !== "microphone" && name !== "camera")) {
return;
}
// firefox will not allow us to read media permissions,
// so we need to wrap getUserMedia in order to get them:
// TODO: only set to prompt if devices are available
setPermission("prompt");
const constraint = name === "camera" ? "video" : "audio";
const getUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
navigator.mediaDevices.getUserMedia = constraints =>
constraints?.[constraint]
? getUserMedia(constraints)
.then(stream => (setPermission("granted"), stream))
.catch(error => {
if (/not allowed/.test(error.message)) {
setPermission("denied");
}
return Promise.reject(error);
})
: getUserMedia(constraints);
});
createEffect(on(status, (status) => {
if (status) {
setPermission(status.state);
const listener = () => setPermission(status.state);
status.addEventListener("change", listener);
onCleanup(() => status.removeEventListener("change", listener));
}
}))
}
return permission;
};
14 changes: 2 additions & 12 deletions packages/permission/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
import { Accessor } from "solid-js";
import * as API from ".";

/**
* Querying the permission API
*
* @param name permission name (e.g. "microphone") or a PermissionDescriptor object (`{ name: ... }`)
* @returns "unknown" | "pending" | "granted" | "rejected"
*/
export const createPermission = (
_name: PermissionDescriptor | PermissionName
): Accessor<PermissionState | "unknown"> => {
return () => "unknown";
};
export const createPermission: typeof API.createPermission = () => () => "unknown";
7 changes: 2 additions & 5 deletions packages/permission/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"emitDeclarationOnly": false
},
"include": ["./src"]
"include": ["./src", "./test", "./dev"],
"exclude": ["node_modules", "./dist"]
}

0 comments on commit 65b6c30

Please sign in to comment.