@capturetrue/web-component 0.0.1

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/README.md ADDED
@@ -0,0 +1 @@
1
+ # `@capturetrue/web-component`
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,141 @@
1
+ // index.ts
2
+ var CaptureTrue = class extends HTMLElement {
3
+ liveVideo;
4
+ recordButton;
5
+ imagePreview;
6
+ _cameraStatus = "inactive";
7
+ captureMode = "photo";
8
+ _status = "awaiting_access";
9
+ EVENT_PREFIX = "capture-true";
10
+ blob;
11
+ get cameraStatus() {
12
+ return this._cameraStatus;
13
+ }
14
+ set cameraStatus(value) {
15
+ this._cameraStatus = value;
16
+ this.render();
17
+ }
18
+ get status() {
19
+ return this._status;
20
+ }
21
+ set status(value) {
22
+ this._status = value;
23
+ this.render();
24
+ }
25
+ render() {
26
+ var _a, _b, _c;
27
+ const isCapture = this._status === "capture" && this._cameraStatus === "active";
28
+ (_a = this.recordButton) == null ? void 0 : _a.classList.toggle("hidden", !isCapture);
29
+ (_b = this.liveVideo) == null ? void 0 : _b.classList.toggle("hidden", !isCapture);
30
+ (_c = this.imagePreview) == null ? void 0 : _c.classList.toggle("hidden", isCapture);
31
+ }
32
+ constructor() {
33
+ super();
34
+ this.attachShadow({ mode: "open" });
35
+ }
36
+ connectedCallback() {
37
+ this.shadowRoot.innerHTML = `
38
+ <style>
39
+ .wrapper {
40
+ position: relative;
41
+ width: 100%;
42
+ }
43
+ .recordButton {
44
+ position: absolute;
45
+ bottom: 10px;
46
+ left: 50%;
47
+ transform: translateX(-50%);
48
+ width: 60px;
49
+ height: 60px;
50
+ background-color: white;
51
+ border-radius: 50%;
52
+ cursor: pointer;
53
+ border: 5px solid grey;
54
+ z-index: 1;
55
+ }
56
+ .hidden {
57
+ display: none;
58
+ }
59
+ </style>
60
+ <div class="wrapper">
61
+ <button type="button" class="recordButton hidden"></button>
62
+ <video id="liveVideo"></video>
63
+ <img id="imagePreview" class="hidden" />
64
+ </div>
65
+ `;
66
+ this.liveVideo = this.shadowRoot.getElementById(
67
+ "liveVideo"
68
+ );
69
+ this.recordButton = this.shadowRoot.querySelector(
70
+ ".recordButton"
71
+ );
72
+ this.imagePreview = this.shadowRoot.getElementById(
73
+ "imagePreview"
74
+ );
75
+ this.recordButton.addEventListener("click", () => {
76
+ if (this.cameraStatus === "active") {
77
+ this.capture();
78
+ }
79
+ });
80
+ }
81
+ async initiateMediaStream() {
82
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
83
+ try {
84
+ const stream = await navigator.mediaDevices.getUserMedia({
85
+ video: { facingMode: "environment" }
86
+ });
87
+ const videoTrack = stream.getVideoTracks()[0];
88
+ this.dispatchEvent(
89
+ new CustomEvent(`${this.EVENT_PREFIX}:track-info`, {
90
+ detail: {
91
+ label: videoTrack.label,
92
+ kind: videoTrack.kind,
93
+ id: videoTrack.id,
94
+ settings: videoTrack.getSettings()
95
+ }
96
+ })
97
+ );
98
+ this.setLiveVideoStream(stream);
99
+ return true;
100
+ } catch (error) {
101
+ this.cameraStatus = "error";
102
+ if (error.name === "NotAllowedError" || error.name === "SecurityError") {
103
+ console.error("Camera access permanently blocked or denied by user.");
104
+ } else {
105
+ console.log(error);
106
+ console.error("An unexpected camera error occurred:", error.name);
107
+ }
108
+ }
109
+ } else {
110
+ console.error("getUserMedia is not supported by this browser.");
111
+ }
112
+ }
113
+ capture() {
114
+ if (this.captureMode != "photo") {
115
+ throw new Error("Video capture not implemented yet");
116
+ }
117
+ const canvas = document.createElement("canvas");
118
+ canvas.width = this.liveVideo.videoWidth;
119
+ canvas.height = this.liveVideo.videoHeight;
120
+ const ctx = canvas.getContext("2d");
121
+ ctx.drawImage(this.liveVideo, 0, 0);
122
+ canvas.toBlob((blob) => {
123
+ if (blob) {
124
+ const url = URL.createObjectURL(blob);
125
+ this.imagePreview.src = url;
126
+ this.blob = blob;
127
+ const event = new CustomEvent(`${this.EVENT_PREFIX}:captured`, {
128
+ detail: { blob: this.blob }
129
+ });
130
+ this.dispatchEvent(event);
131
+ }
132
+ }, "image/webp", 1);
133
+ }
134
+ setLiveVideoStream(stream) {
135
+ this.liveVideo.srcObject = stream;
136
+ this.liveVideo.play();
137
+ this.status = "capture";
138
+ this.cameraStatus = "active";
139
+ }
140
+ };
141
+ customElements.define("capture-true", CaptureTrue);
package/dist/index.mjs ADDED
@@ -0,0 +1,141 @@
1
+ // index.ts
2
+ var CaptureTrue = class extends HTMLElement {
3
+ liveVideo;
4
+ recordButton;
5
+ imagePreview;
6
+ _cameraStatus = "inactive";
7
+ captureMode = "photo";
8
+ _status = "awaiting_access";
9
+ EVENT_PREFIX = "capture-true";
10
+ blob;
11
+ get cameraStatus() {
12
+ return this._cameraStatus;
13
+ }
14
+ set cameraStatus(value) {
15
+ this._cameraStatus = value;
16
+ this.render();
17
+ }
18
+ get status() {
19
+ return this._status;
20
+ }
21
+ set status(value) {
22
+ this._status = value;
23
+ this.render();
24
+ }
25
+ render() {
26
+ var _a, _b, _c;
27
+ const isCapture = this._status === "capture" && this._cameraStatus === "active";
28
+ (_a = this.recordButton) == null ? void 0 : _a.classList.toggle("hidden", !isCapture);
29
+ (_b = this.liveVideo) == null ? void 0 : _b.classList.toggle("hidden", !isCapture);
30
+ (_c = this.imagePreview) == null ? void 0 : _c.classList.toggle("hidden", isCapture);
31
+ }
32
+ constructor() {
33
+ super();
34
+ this.attachShadow({ mode: "open" });
35
+ }
36
+ connectedCallback() {
37
+ this.shadowRoot.innerHTML = `
38
+ <style>
39
+ .wrapper {
40
+ position: relative;
41
+ width: 100%;
42
+ }
43
+ .recordButton {
44
+ position: absolute;
45
+ bottom: 10px;
46
+ left: 50%;
47
+ transform: translateX(-50%);
48
+ width: 60px;
49
+ height: 60px;
50
+ background-color: white;
51
+ border-radius: 50%;
52
+ cursor: pointer;
53
+ border: 5px solid grey;
54
+ z-index: 1;
55
+ }
56
+ .hidden {
57
+ display: none;
58
+ }
59
+ </style>
60
+ <div class="wrapper">
61
+ <button type="button" class="recordButton hidden"></button>
62
+ <video id="liveVideo"></video>
63
+ <img id="imagePreview" class="hidden" />
64
+ </div>
65
+ `;
66
+ this.liveVideo = this.shadowRoot.getElementById(
67
+ "liveVideo"
68
+ );
69
+ this.recordButton = this.shadowRoot.querySelector(
70
+ ".recordButton"
71
+ );
72
+ this.imagePreview = this.shadowRoot.getElementById(
73
+ "imagePreview"
74
+ );
75
+ this.recordButton.addEventListener("click", () => {
76
+ if (this.cameraStatus === "active") {
77
+ this.capture();
78
+ }
79
+ });
80
+ }
81
+ async initiateMediaStream() {
82
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
83
+ try {
84
+ const stream = await navigator.mediaDevices.getUserMedia({
85
+ video: { facingMode: "environment" }
86
+ });
87
+ const videoTrack = stream.getVideoTracks()[0];
88
+ this.dispatchEvent(
89
+ new CustomEvent(`${this.EVENT_PREFIX}:track-info`, {
90
+ detail: {
91
+ label: videoTrack.label,
92
+ kind: videoTrack.kind,
93
+ id: videoTrack.id,
94
+ settings: videoTrack.getSettings()
95
+ }
96
+ })
97
+ );
98
+ this.setLiveVideoStream(stream);
99
+ return true;
100
+ } catch (error) {
101
+ this.cameraStatus = "error";
102
+ if (error.name === "NotAllowedError" || error.name === "SecurityError") {
103
+ console.error("Camera access permanently blocked or denied by user.");
104
+ } else {
105
+ console.log(error);
106
+ console.error("An unexpected camera error occurred:", error.name);
107
+ }
108
+ }
109
+ } else {
110
+ console.error("getUserMedia is not supported by this browser.");
111
+ }
112
+ }
113
+ capture() {
114
+ if (this.captureMode != "photo") {
115
+ throw new Error("Video capture not implemented yet");
116
+ }
117
+ const canvas = document.createElement("canvas");
118
+ canvas.width = this.liveVideo.videoWidth;
119
+ canvas.height = this.liveVideo.videoHeight;
120
+ const ctx = canvas.getContext("2d");
121
+ ctx.drawImage(this.liveVideo, 0, 0);
122
+ canvas.toBlob((blob) => {
123
+ if (blob) {
124
+ const url = URL.createObjectURL(blob);
125
+ this.imagePreview.src = url;
126
+ this.blob = blob;
127
+ const event = new CustomEvent(`${this.EVENT_PREFIX}:captured`, {
128
+ detail: { blob: this.blob }
129
+ });
130
+ this.dispatchEvent(event);
131
+ }
132
+ }, "image/webp", 1);
133
+ }
134
+ setLiveVideoStream(stream) {
135
+ this.liveVideo.srcObject = stream;
136
+ this.liveVideo.play();
137
+ this.status = "capture";
138
+ this.cameraStatus = "active";
139
+ }
140
+ };
141
+ customElements.define("capture-true", CaptureTrue);
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@capturetrue/web-component",
3
+ "version": "0.0.1",
4
+ "description": "A web component for capturing live photo, built with TypeScript and Web Components.",
5
+ "private": false,
6
+ "main": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "scripts": {
15
+ "build": "tsup index.ts --format esm,cjs --dts"
16
+ },
17
+ "devDependencies": {
18
+ "tsup": "^8.5.1"
19
+ }
20
+ }