@zcomponent/core 1.5.0-beta → 1.6.0-beta
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/css/socialshare.css +102 -0
- package/lib/behaviors/DownloadSnapshot.d.ts +21 -0
- package/lib/behaviors/DownloadSnapshot.js +42 -0
- package/lib/behaviors/ShareSnapshot.d.ts +21 -0
- package/lib/behaviors/ShareSnapshot.js +43 -0
- package/lib/behaviors/TakeSnapshot.d.ts +53 -0
- package/lib/behaviors/TakeSnapshot.js +87 -0
- package/lib/components/SnapshotUI.d.ts +52 -0
- package/lib/components/SnapshotUI.js +310 -0
- package/lib/contexts/snapshotContext.d.ts +19 -0
- package/lib/contexts/snapshotContext.js +33 -0
- package/package.json +3 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
.zee-social-share-button {
|
|
2
|
+
width: 50px;
|
|
3
|
+
height: 50px;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
padding: 8px;
|
|
6
|
+
background: rgba(0, 0, 0, 0.4);
|
|
7
|
+
border-radius: 50%;
|
|
8
|
+
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
|
9
|
+
backdrop-filter: blur(5px);
|
|
10
|
+
-webkit-backdrop-filter: blur(5px);
|
|
11
|
+
border: 1px solid rgba(0, 0, 0, 0.11);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.zee-social-share-button img {
|
|
15
|
+
height: 100%;
|
|
16
|
+
object-fit: scale-down;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#zee-social-share-button-wrapper {
|
|
20
|
+
display: flex;
|
|
21
|
+
gap: 12px;
|
|
22
|
+
position: absolute;
|
|
23
|
+
left: 12px;
|
|
24
|
+
bottom: 12px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#zee-social-share-close-wrapper {
|
|
28
|
+
display: flex;
|
|
29
|
+
position: absolute;
|
|
30
|
+
top: 12px;
|
|
31
|
+
left: 12px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.zee-social-share-button:active,
|
|
35
|
+
.zee-social-share-button.touch {
|
|
36
|
+
background: rgba(0, 0, 0, 0.7);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.zee-photo-button {
|
|
40
|
+
width: 100px;
|
|
41
|
+
bottom: 5%;
|
|
42
|
+
height: 100px;
|
|
43
|
+
left: 50%;
|
|
44
|
+
margin-top: -50px;
|
|
45
|
+
margin-left: -50px;
|
|
46
|
+
position: absolute;
|
|
47
|
+
touch-action: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.zee-social-share-circle {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 12%;
|
|
53
|
+
left: 12%;
|
|
54
|
+
bottom: 12%;
|
|
55
|
+
right: 12%;
|
|
56
|
+
border-radius: 100%;
|
|
57
|
+
background-color: #ffffff;
|
|
58
|
+
opacity: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.zee-social-share-ring {
|
|
62
|
+
position: absolute;
|
|
63
|
+
top: 0;
|
|
64
|
+
left: 0;
|
|
65
|
+
bottom: 0;
|
|
66
|
+
right: 0;
|
|
67
|
+
border-radius: 100%;
|
|
68
|
+
border: 0.5em solid #ffffff;
|
|
69
|
+
opacity: 0.8;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.zee-photo-button .zee-social-share-circle .zee-photo-button .zee-social-share-ring {
|
|
73
|
+
transition: all 0.1s;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.zee-photo-button:hover .zee-social-share-circle {
|
|
77
|
+
opacity: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.zee-photo-button:active .zee-social-share-ring {
|
|
81
|
+
opacity: 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.zee-photo-button:active .zee-social-share-circle {
|
|
85
|
+
opacity: 0.5;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.social-share-div {
|
|
89
|
+
width: 100%;
|
|
90
|
+
height: 100%;
|
|
91
|
+
max-height: 100%;
|
|
92
|
+
position: fixed;
|
|
93
|
+
overflow: auto;
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
justify-content: space-between;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.zee-social-share-img {
|
|
100
|
+
width: 100%;
|
|
101
|
+
object-fit: cover;
|
|
102
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ActionBehavior, ActionBehaviorConstructorProps } from '../actionbehavior';
|
|
2
|
+
import { Component } from '../component';
|
|
3
|
+
import { ContextManager } from '../context';
|
|
4
|
+
import { Event } from '../event';
|
|
5
|
+
export type DownloadSnapshotProps = ActionBehaviorConstructorProps;
|
|
6
|
+
/**
|
|
7
|
+
* Downloads the captured canvas as an image.
|
|
8
|
+
*
|
|
9
|
+
* @zbehavior
|
|
10
|
+
* @zicon download
|
|
11
|
+
* @zgroup Actions
|
|
12
|
+
*/
|
|
13
|
+
export declare class DownloadSnapshot extends ActionBehavior<DownloadSnapshotProps> {
|
|
14
|
+
/** @zui */
|
|
15
|
+
onSave: Event<[]>;
|
|
16
|
+
constructor(contextManager: ContextManager, instance: Component, props: DownloadSnapshotProps);
|
|
17
|
+
perform(): void;
|
|
18
|
+
private download;
|
|
19
|
+
/** @zprop */
|
|
20
|
+
preview(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ActionBehavior } from '../actionbehavior';
|
|
2
|
+
import { registerBehaviorRunAtDesignTime } from '../behavior';
|
|
3
|
+
import { SnapshotContext } from '../contexts/snapshotContext';
|
|
4
|
+
import { Event } from '../event';
|
|
5
|
+
/**
|
|
6
|
+
* Downloads the captured canvas as an image.
|
|
7
|
+
*
|
|
8
|
+
* @zbehavior
|
|
9
|
+
* @zicon download
|
|
10
|
+
* @zgroup Actions
|
|
11
|
+
*/
|
|
12
|
+
export class DownloadSnapshot extends ActionBehavior {
|
|
13
|
+
constructor(contextManager, instance, props) {
|
|
14
|
+
super(contextManager, instance, props);
|
|
15
|
+
/** @zui */
|
|
16
|
+
this.onSave = new Event();
|
|
17
|
+
this.download = () => {
|
|
18
|
+
const snapshotContext = this.contextManager.get(SnapshotContext);
|
|
19
|
+
const dataUrl = snapshotContext.canvasImage.value;
|
|
20
|
+
const link = document.createElement('a');
|
|
21
|
+
link.href = dataUrl;
|
|
22
|
+
const file = snapshotContext.canvasFile.value;
|
|
23
|
+
link.download = file.name;
|
|
24
|
+
link.target = '_blank';
|
|
25
|
+
const url = URL.createObjectURL(file);
|
|
26
|
+
link.href = url;
|
|
27
|
+
link.style.display = 'none';
|
|
28
|
+
document.body.appendChild(link);
|
|
29
|
+
link.click();
|
|
30
|
+
document.body.removeChild(link);
|
|
31
|
+
this.onSave.emit();
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
perform() {
|
|
35
|
+
this.download();
|
|
36
|
+
}
|
|
37
|
+
/** @zprop */
|
|
38
|
+
preview() {
|
|
39
|
+
this.perform();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
registerBehaviorRunAtDesignTime(DownloadSnapshot);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ActionBehaviorConstructorProps, ActionBehavior } from '../actionbehavior';
|
|
2
|
+
import { Component } from '../component';
|
|
3
|
+
import { ContextManager } from '../context';
|
|
4
|
+
import { Event } from '../event';
|
|
5
|
+
export type ShareCanvasProps = ActionBehaviorConstructorProps;
|
|
6
|
+
/**
|
|
7
|
+
* Shares the captured canvas using the Web Share API.
|
|
8
|
+
*
|
|
9
|
+
* @zbehavior
|
|
10
|
+
* @zicon share
|
|
11
|
+
* @zgroup Actions
|
|
12
|
+
*/
|
|
13
|
+
export declare class ShareSnapshot extends ActionBehavior<ShareCanvasProps> {
|
|
14
|
+
/** @zui */
|
|
15
|
+
onShare: Event<[]>;
|
|
16
|
+
constructor(contextManager: ContextManager, instance: Component, props: ShareCanvasProps);
|
|
17
|
+
perform(): void;
|
|
18
|
+
private share;
|
|
19
|
+
/** @zprop */
|
|
20
|
+
preview(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ActionBehavior } from '../actionbehavior';
|
|
2
|
+
import { SnapshotContext } from '../contexts/snapshotContext';
|
|
3
|
+
import { Event } from '../event';
|
|
4
|
+
/**
|
|
5
|
+
* Shares the captured canvas using the Web Share API.
|
|
6
|
+
*
|
|
7
|
+
* @zbehavior
|
|
8
|
+
* @zicon share
|
|
9
|
+
* @zgroup Actions
|
|
10
|
+
*/
|
|
11
|
+
export class ShareSnapshot extends ActionBehavior {
|
|
12
|
+
constructor(contextManager, instance, props) {
|
|
13
|
+
super(contextManager, instance, props);
|
|
14
|
+
/** @zui */
|
|
15
|
+
this.onShare = new Event();
|
|
16
|
+
this.share = async () => {
|
|
17
|
+
const sctx = this.contextManager.get(SnapshotContext);
|
|
18
|
+
const snapshotContext = this.contextManager.get(SnapshotContext);
|
|
19
|
+
if (sctx.shareAPISupported.value === false) {
|
|
20
|
+
console.error('Web Share API not supported');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
await navigator.share({
|
|
25
|
+
title: snapshotContext.title.value,
|
|
26
|
+
text: snapshotContext.text.value,
|
|
27
|
+
files: [snapshotContext.canvasFile.value],
|
|
28
|
+
});
|
|
29
|
+
this.onShare.emit();
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
console.error('Error - Sharing', err);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
perform() {
|
|
37
|
+
this.share();
|
|
38
|
+
}
|
|
39
|
+
/** @zprop */
|
|
40
|
+
preview() {
|
|
41
|
+
this.perform();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ActionBehavior, ActionBehaviorConstructorProps } from '../actionbehavior';
|
|
2
|
+
import { Component } from '../component';
|
|
3
|
+
import { ContextManager } from '../context';
|
|
4
|
+
import { Observable } from '../observable';
|
|
5
|
+
export declare enum ImageFormat {
|
|
6
|
+
PNG = "png",
|
|
7
|
+
JPEG = "jpeg"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Captures the canvas as an image.
|
|
11
|
+
* This image can then be shared or downloaded using other behaviors.
|
|
12
|
+
*
|
|
13
|
+
* @zbehavior
|
|
14
|
+
* @zicon photo_camera
|
|
15
|
+
* @zgroup Actions
|
|
16
|
+
*/
|
|
17
|
+
export declare class TakeSnapshot extends ActionBehavior<ActionBehaviorConstructorProps> {
|
|
18
|
+
constructor(contextManager: ContextManager, instance: Component, props: ActionBehaviorConstructorProps);
|
|
19
|
+
/**
|
|
20
|
+
* The format of the image to capture.
|
|
21
|
+
* @zprop
|
|
22
|
+
* @zdefault jpeg
|
|
23
|
+
*/
|
|
24
|
+
format: Observable<ImageFormat, never>;
|
|
25
|
+
/**
|
|
26
|
+
* The quality of the image to capture.
|
|
27
|
+
* @zprop
|
|
28
|
+
* @zdefault 0.92
|
|
29
|
+
*/
|
|
30
|
+
quality: Observable<number, never>;
|
|
31
|
+
/**
|
|
32
|
+
* The name of the file to download.
|
|
33
|
+
* @zprop
|
|
34
|
+
* @zdefault canvas
|
|
35
|
+
*/
|
|
36
|
+
fileName: Observable<string, never>;
|
|
37
|
+
/**
|
|
38
|
+
* The text to share.
|
|
39
|
+
* @zprop
|
|
40
|
+
* @zdefault ''
|
|
41
|
+
*/
|
|
42
|
+
text: Observable<string, never>;
|
|
43
|
+
/**
|
|
44
|
+
* The title to share.
|
|
45
|
+
* @zprop
|
|
46
|
+
* @zdefault ''
|
|
47
|
+
*/
|
|
48
|
+
title: Observable<string, never>;
|
|
49
|
+
private dataUrl;
|
|
50
|
+
perform(): void;
|
|
51
|
+
private capture;
|
|
52
|
+
preview(): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ActionBehavior } from '../actionbehavior';
|
|
2
|
+
import { registerBehaviorRunAtDesignTime } from '../behavior';
|
|
3
|
+
import { useCanvas, useOnAfterRender } from '../contexts/canvascontext';
|
|
4
|
+
import { SnapshotContext } from '../contexts/snapshotContext';
|
|
5
|
+
import { Observable } from '../observable';
|
|
6
|
+
export var ImageFormat;
|
|
7
|
+
(function (ImageFormat) {
|
|
8
|
+
ImageFormat["PNG"] = "png";
|
|
9
|
+
ImageFormat["JPEG"] = "jpeg";
|
|
10
|
+
})(ImageFormat || (ImageFormat = {}));
|
|
11
|
+
/**
|
|
12
|
+
* Captures the canvas as an image.
|
|
13
|
+
* This image can then be shared or downloaded using other behaviors.
|
|
14
|
+
*
|
|
15
|
+
* @zbehavior
|
|
16
|
+
* @zicon photo_camera
|
|
17
|
+
* @zgroup Actions
|
|
18
|
+
*/
|
|
19
|
+
export class TakeSnapshot extends ActionBehavior {
|
|
20
|
+
constructor(contextManager, instance, props) {
|
|
21
|
+
super(contextManager, instance, props);
|
|
22
|
+
/**
|
|
23
|
+
* The format of the image to capture.
|
|
24
|
+
* @zprop
|
|
25
|
+
* @zdefault jpeg
|
|
26
|
+
*/
|
|
27
|
+
this.format = new Observable(ImageFormat.JPEG, format => {
|
|
28
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
29
|
+
ssctx.fileType.value = format === ImageFormat.PNG ? 'image/png' : 'image/jpeg';
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* The quality of the image to capture.
|
|
33
|
+
* @zprop
|
|
34
|
+
* @zdefault 0.92
|
|
35
|
+
*/
|
|
36
|
+
this.quality = new Observable(0.92, quality => {
|
|
37
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
38
|
+
ssctx.quality.value = quality;
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* The name of the file to download.
|
|
42
|
+
* @zprop
|
|
43
|
+
* @zdefault canvas
|
|
44
|
+
*/
|
|
45
|
+
this.fileName = new Observable('canvas', fileName => {
|
|
46
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
47
|
+
ssctx.fileName.value = fileName;
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* The text to share.
|
|
51
|
+
* @zprop
|
|
52
|
+
* @zdefault ''
|
|
53
|
+
*/
|
|
54
|
+
this.text = new Observable('', text => {
|
|
55
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
56
|
+
ssctx.text.value = text;
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* The title to share.
|
|
60
|
+
* @zprop
|
|
61
|
+
* @zdefault ''
|
|
62
|
+
*/
|
|
63
|
+
this.title = new Observable('', title => {
|
|
64
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
65
|
+
ssctx.title.value = title;
|
|
66
|
+
});
|
|
67
|
+
this.dataUrl = '';
|
|
68
|
+
this.capture = () => {
|
|
69
|
+
const canvas = useCanvas(this.contextManager);
|
|
70
|
+
if (!canvas) {
|
|
71
|
+
console.error('No canvas found in context');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const snapshotContext = this.contextManager.get(SnapshotContext);
|
|
75
|
+
const mimeType = snapshotContext.fileType.value === ImageFormat.PNG ? 'image/png' : 'image/jpeg';
|
|
76
|
+
this.dataUrl = canvas.toDataURL(mimeType, this.quality.value);
|
|
77
|
+
snapshotContext.canvasImage.value = this.dataUrl;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
perform() {
|
|
81
|
+
useOnAfterRender(this.contextManager).next.then(this.capture);
|
|
82
|
+
}
|
|
83
|
+
preview() {
|
|
84
|
+
this.perform();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
registerBehaviorRunAtDesignTime(TakeSnapshot);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Observable } from '..';
|
|
2
|
+
import { ImageFormat } from '../behaviors/TakeSnapshot';
|
|
3
|
+
import { Component, ConstructorProps } from '../component';
|
|
4
|
+
import { ContextManager } from '../context';
|
|
5
|
+
import { Event } from '../event';
|
|
6
|
+
/**
|
|
7
|
+
* @zcomponent
|
|
8
|
+
* @zgroup Util
|
|
9
|
+
* @zicon photo_camera
|
|
10
|
+
*/
|
|
11
|
+
export declare class SnapshotUI extends Component {
|
|
12
|
+
private captureButton;
|
|
13
|
+
private socialShareBehaviours;
|
|
14
|
+
private style;
|
|
15
|
+
private shareDiv;
|
|
16
|
+
/** @zui */
|
|
17
|
+
onSave: Event<[]>;
|
|
18
|
+
/** @zui */
|
|
19
|
+
onShare: Event<[]>;
|
|
20
|
+
/**
|
|
21
|
+
* The format of the image to capture.
|
|
22
|
+
* @zprop
|
|
23
|
+
* @zdefault jpeg
|
|
24
|
+
*/
|
|
25
|
+
format: Observable<ImageFormat, never>;
|
|
26
|
+
/**
|
|
27
|
+
* The quality of the image to capture.
|
|
28
|
+
* @zprop
|
|
29
|
+
* @zdefault 0.92
|
|
30
|
+
*/
|
|
31
|
+
quality: Observable<number, never>;
|
|
32
|
+
/**
|
|
33
|
+
* The name of the file to download.
|
|
34
|
+
* @zprop
|
|
35
|
+
* @zdefault canvas
|
|
36
|
+
*/
|
|
37
|
+
fileName: Observable<string, never>;
|
|
38
|
+
/**
|
|
39
|
+
* The text to share.
|
|
40
|
+
* @zprop
|
|
41
|
+
* @zdefault ''
|
|
42
|
+
*/
|
|
43
|
+
text: Observable<string, never>;
|
|
44
|
+
/**
|
|
45
|
+
* The title to share.
|
|
46
|
+
* @zprop
|
|
47
|
+
* @zdefault ''
|
|
48
|
+
*/
|
|
49
|
+
title: Observable<string, never>;
|
|
50
|
+
constructor(contextManager: ContextManager, props: ConstructorProps);
|
|
51
|
+
dispose(): never;
|
|
52
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { CanvasContext, Observable, registerLoadable } from '..';
|
|
2
|
+
import { TakeSnapshot, ImageFormat } from '../behaviors/TakeSnapshot';
|
|
3
|
+
import { DownloadSnapshot } from '../behaviors/DownloadSnapshot';
|
|
4
|
+
import { ShareSnapshot } from '../behaviors/ShareSnapshot';
|
|
5
|
+
import { Component } from '../component';
|
|
6
|
+
import { SnapshotContext } from '../contexts/snapshotContext';
|
|
7
|
+
import { Event } from '../event';
|
|
8
|
+
const style_src = new URL('../../css/socialshare.css', import.meta.url).href;
|
|
9
|
+
const back_src = new URL('../../assets/back.png', import.meta.url).href;
|
|
10
|
+
const download_src = new URL('../../assets/download.png', import.meta.url).href;
|
|
11
|
+
const share_src = new URL('../../assets/share.png', import.meta.url).href;
|
|
12
|
+
/**
|
|
13
|
+
* @zcomponent
|
|
14
|
+
* @zgroup Util
|
|
15
|
+
* @zicon photo_camera
|
|
16
|
+
*/
|
|
17
|
+
export class SnapshotUI extends Component {
|
|
18
|
+
constructor(contextManager, props) {
|
|
19
|
+
super(contextManager, props);
|
|
20
|
+
this.style = document.createElement('link');
|
|
21
|
+
/** @zui */
|
|
22
|
+
this.onSave = new Event();
|
|
23
|
+
/** @zui */
|
|
24
|
+
this.onShare = new Event();
|
|
25
|
+
/**
|
|
26
|
+
* The format of the image to capture.
|
|
27
|
+
* @zprop
|
|
28
|
+
* @zdefault jpeg
|
|
29
|
+
*/
|
|
30
|
+
this.format = new Observable(ImageFormat.JPEG, format => {
|
|
31
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
32
|
+
ssctx.fileType.value = format === ImageFormat.PNG ? 'image/png' : 'image/jpeg';
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* The quality of the image to capture.
|
|
36
|
+
* @zprop
|
|
37
|
+
* @zdefault 0.92
|
|
38
|
+
*/
|
|
39
|
+
this.quality = new Observable(0.92, quality => {
|
|
40
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
41
|
+
ssctx.quality.value = quality;
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* The name of the file to download.
|
|
45
|
+
* @zprop
|
|
46
|
+
* @zdefault canvas
|
|
47
|
+
*/
|
|
48
|
+
this.fileName = new Observable('canvas', fileName => {
|
|
49
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
50
|
+
ssctx.fileName.value = fileName;
|
|
51
|
+
});
|
|
52
|
+
/**
|
|
53
|
+
* The text to share.
|
|
54
|
+
* @zprop
|
|
55
|
+
* @zdefault ''
|
|
56
|
+
*/
|
|
57
|
+
this.text = new Observable('', text => {
|
|
58
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
59
|
+
ssctx.text.value = text;
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* The title to share.
|
|
63
|
+
* @zprop
|
|
64
|
+
* @zdefault ''
|
|
65
|
+
*/
|
|
66
|
+
this.title = new Observable('', title => {
|
|
67
|
+
const ssctx = this.contextManager.get(SnapshotContext);
|
|
68
|
+
ssctx.title.value = title;
|
|
69
|
+
});
|
|
70
|
+
this.socialShareBehaviours = new SocialShareBehaviors(contextManager, this);
|
|
71
|
+
this.socialShareBehaviours.onSave.addListener(() => {
|
|
72
|
+
this.onSave.emit();
|
|
73
|
+
});
|
|
74
|
+
this.socialShareBehaviours.onShare.addListener(() => {
|
|
75
|
+
this.onShare.emit();
|
|
76
|
+
});
|
|
77
|
+
const showShare = this.contextManager.get(SnapshotContext).shareAPISupported.value;
|
|
78
|
+
this.shareDiv = new ShareDivElement(showShare, async () => {
|
|
79
|
+
try {
|
|
80
|
+
this.socialShareBehaviours.share();
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.error('Error sharing:', err);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
this.captureButton = new CaptureButtonElement(this.contextManager);
|
|
87
|
+
registerLoadable(this.contextManager, new Promise(resolve => (this.style.onload = resolve)));
|
|
88
|
+
this.style.rel = 'stylesheet';
|
|
89
|
+
this.style.type = 'text/css';
|
|
90
|
+
this.style.href = style_src;
|
|
91
|
+
document.head.appendChild(this.style);
|
|
92
|
+
this.captureButton.onClick.addListener(() => {
|
|
93
|
+
this.socialShareBehaviours.capture();
|
|
94
|
+
this.shareDiv.show();
|
|
95
|
+
});
|
|
96
|
+
this.shareDiv.onDownload.addListener(() => {
|
|
97
|
+
this.socialShareBehaviours.download();
|
|
98
|
+
});
|
|
99
|
+
this.shareDiv.onClose.addListener(() => {
|
|
100
|
+
this.captureButton.show();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
dispose() {
|
|
104
|
+
if (this.style.parentNode)
|
|
105
|
+
this.style.parentNode.removeChild(this.style);
|
|
106
|
+
this.socialShareBehaviours.dispose();
|
|
107
|
+
return super.dispose();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
class SocialShareBehaviors {
|
|
111
|
+
constructor(contextManager, parent) {
|
|
112
|
+
this.capture_b = new TakeSnapshot(contextManager, parent, { event: 'social-share', runAtEditTime: false });
|
|
113
|
+
this.download_b = new DownloadSnapshot(contextManager, parent, { event: 'social-share', runAtEditTime: false });
|
|
114
|
+
this.share_b = new ShareSnapshot(contextManager, parent, { event: 'social-share', runAtEditTime: false });
|
|
115
|
+
parent.addBehavior(this.capture_b);
|
|
116
|
+
parent.addBehavior(this.download_b);
|
|
117
|
+
parent.addBehavior(this.share_b);
|
|
118
|
+
}
|
|
119
|
+
get onSave() {
|
|
120
|
+
return this.download_b.onSave;
|
|
121
|
+
}
|
|
122
|
+
get onShare() {
|
|
123
|
+
return this.share_b.onShare;
|
|
124
|
+
}
|
|
125
|
+
capture() {
|
|
126
|
+
this.capture_b.perform();
|
|
127
|
+
}
|
|
128
|
+
download() {
|
|
129
|
+
this.download_b.perform();
|
|
130
|
+
}
|
|
131
|
+
share() {
|
|
132
|
+
this.share_b.perform();
|
|
133
|
+
}
|
|
134
|
+
dispose() {
|
|
135
|
+
this.capture_b.dispose();
|
|
136
|
+
this.download_b.dispose();
|
|
137
|
+
this.share_b.dispose();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
class CaptureButtonElement {
|
|
141
|
+
constructor(contextManager) {
|
|
142
|
+
this.contextManager = contextManager;
|
|
143
|
+
this.clickEvent = new Event();
|
|
144
|
+
const template = `
|
|
145
|
+
<div id="zee-photo-button" class="zee-photo-button">
|
|
146
|
+
<div id="zee-social-share-circle" class="zee-social-share-circle"></div>
|
|
147
|
+
<div id="zee-social-share-ring" class="zee-social-share-ring"></div>
|
|
148
|
+
</div>
|
|
149
|
+
`;
|
|
150
|
+
const temporaryElement = document.createElement('div');
|
|
151
|
+
temporaryElement.innerHTML = template.trim();
|
|
152
|
+
this.button = temporaryElement.firstChild;
|
|
153
|
+
// document.body.appendChild(this.button);
|
|
154
|
+
const canvasContext = this.contextManager.get(CanvasContext);
|
|
155
|
+
canvasContext.overlay.value.appendChild(this.button);
|
|
156
|
+
const circle = document.getElementById('zee-social-share-circle');
|
|
157
|
+
const ring = document.getElementById('zee-social-share-ring');
|
|
158
|
+
// Flag to track if click was cancelled
|
|
159
|
+
let isCancelled = false;
|
|
160
|
+
const handleClick = () => {
|
|
161
|
+
if (!isCancelled) {
|
|
162
|
+
this.clickEvent.emit();
|
|
163
|
+
this.hide();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const handleTouchStart = () => {
|
|
167
|
+
isCancelled = false;
|
|
168
|
+
circle.style.opacity = '1';
|
|
169
|
+
ring.style.opacity = '1';
|
|
170
|
+
document.addEventListener('touchmove', handleTouchMove);
|
|
171
|
+
document.addEventListener('touchend', handleTouchEnd);
|
|
172
|
+
};
|
|
173
|
+
const handleTouchMove = event => {
|
|
174
|
+
const touch = event.touches[0];
|
|
175
|
+
const rect = this.button.getBoundingClientRect();
|
|
176
|
+
// Check if touch position is outside the button's boundaries
|
|
177
|
+
if (touch.clientX < rect.left || touch.clientX > rect.right || touch.clientY < rect.top || touch.clientY > rect.bottom) {
|
|
178
|
+
isCancelled = true; // Cancel the click
|
|
179
|
+
circle.style.opacity = '0';
|
|
180
|
+
ring.style.opacity = '0.8';
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const handleTouchEnd = (event) => {
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
document.removeEventListener('touchmove', handleTouchMove);
|
|
186
|
+
document.removeEventListener('touchend', handleTouchEnd);
|
|
187
|
+
circle.style.opacity = '0';
|
|
188
|
+
ring.style.opacity = '0.8';
|
|
189
|
+
handleClick();
|
|
190
|
+
};
|
|
191
|
+
this.button.addEventListener('click', handleClick);
|
|
192
|
+
this.button.addEventListener('touchstart', handleTouchStart);
|
|
193
|
+
this.button.addEventListener('touchstart', () => {
|
|
194
|
+
circle.style.opacity = '1';
|
|
195
|
+
ring.style.opacity = '1';
|
|
196
|
+
});
|
|
197
|
+
this.button.addEventListener('touchend', () => {
|
|
198
|
+
circle.style.opacity = '0';
|
|
199
|
+
ring.style.opacity = '0.8';
|
|
200
|
+
});
|
|
201
|
+
document.body.appendChild(this.button);
|
|
202
|
+
}
|
|
203
|
+
get onClick() {
|
|
204
|
+
return this.clickEvent;
|
|
205
|
+
}
|
|
206
|
+
hide() {
|
|
207
|
+
this.button.style.display = 'none';
|
|
208
|
+
}
|
|
209
|
+
show() {
|
|
210
|
+
this.button.style.display = 'block';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class ShareDivElement {
|
|
214
|
+
constructor(withShareButton, shareFunction) {
|
|
215
|
+
this.shareFunction = shareFunction;
|
|
216
|
+
this.onDownload = new Event();
|
|
217
|
+
// public onShare = new Event();
|
|
218
|
+
this.onClose = new Event();
|
|
219
|
+
const template = `
|
|
220
|
+
<div id="social-share-div" class="social-share-div">
|
|
221
|
+
<img id="zee-social-share-img" class="zee-social-share-img">
|
|
222
|
+
<div id="zee-social-share-button-wrapper">
|
|
223
|
+
<button id="zee-save-button" class="zee-social-share-button">
|
|
224
|
+
<img src="${download_src}">
|
|
225
|
+
</button>
|
|
226
|
+
${withShareButton ? `<zee-social-share-button id="zee-share-button" class="button"><img src="${share_src}"></zee-social-share-button>` : ''}
|
|
227
|
+
</div>
|
|
228
|
+
<div id="zee-social-share-close-wrapper">
|
|
229
|
+
<button id="zee-close-button" class="zee-social-share-button">
|
|
230
|
+
<img src="${back_src}">
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
`;
|
|
235
|
+
const temporaryElement = document.createElement('div');
|
|
236
|
+
temporaryElement.innerHTML = template.trim();
|
|
237
|
+
document.body.appendChild(temporaryElement.firstElementChild);
|
|
238
|
+
const div = document.getElementById('social-share-div');
|
|
239
|
+
div.style.display = 'none';
|
|
240
|
+
const saveButton = document.getElementById('zee-save-button');
|
|
241
|
+
const shareButton = document.getElementById('zee-share-button');
|
|
242
|
+
const closeButton = document.getElementById('zee-close-button');
|
|
243
|
+
const addEvents = (button, event) => {
|
|
244
|
+
let isCancelled = false;
|
|
245
|
+
button.addEventListener('click', () => {
|
|
246
|
+
if (event instanceof Event)
|
|
247
|
+
event.emit();
|
|
248
|
+
else
|
|
249
|
+
event();
|
|
250
|
+
});
|
|
251
|
+
button.addEventListener('mouseenter', () => {
|
|
252
|
+
button.classList.add('hover');
|
|
253
|
+
});
|
|
254
|
+
button.addEventListener('mousedown', () => {
|
|
255
|
+
button.classList.add('active');
|
|
256
|
+
});
|
|
257
|
+
button.addEventListener('mouseup', () => {
|
|
258
|
+
button.classList.remove('active');
|
|
259
|
+
});
|
|
260
|
+
button.addEventListener('touchstart', () => {
|
|
261
|
+
isCancelled = false;
|
|
262
|
+
button.classList.add('active');
|
|
263
|
+
document.addEventListener('touchmove', handleTouchMove);
|
|
264
|
+
document.addEventListener('touchend', handleTouchEnd);
|
|
265
|
+
});
|
|
266
|
+
const handleTouchMove = event => {
|
|
267
|
+
const touch = event.touches[0];
|
|
268
|
+
const rect = button.getBoundingClientRect();
|
|
269
|
+
if (touch.clientX < rect.left || touch.clientX > rect.right || touch.clientY < rect.top || touch.clientY > rect.bottom) {
|
|
270
|
+
isCancelled = true;
|
|
271
|
+
button.classList.remove('active');
|
|
272
|
+
button.classList.remove('hover');
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
const handleTouchEnd = () => {
|
|
276
|
+
document.removeEventListener('touchmove', handleTouchMove);
|
|
277
|
+
document.removeEventListener('touchend', handleTouchEnd);
|
|
278
|
+
if (!isCancelled) {
|
|
279
|
+
button.classList.remove('active');
|
|
280
|
+
button.classList.remove('hover');
|
|
281
|
+
if (event instanceof Event)
|
|
282
|
+
event.emit();
|
|
283
|
+
else
|
|
284
|
+
event();
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
addEvents(saveButton, this.onDownload);
|
|
289
|
+
if (withShareButton) {
|
|
290
|
+
shareButton.addEventListener('click', event => {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
this.shareFunction();
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
addEvents(closeButton, this.onClose);
|
|
296
|
+
closeButton.addEventListener('click', () => {
|
|
297
|
+
div.style.display = 'none';
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
hide() {
|
|
301
|
+
const div = document.querySelector('#social-share-div');
|
|
302
|
+
document.body.style.overflow = 'auto';
|
|
303
|
+
div.style.display = 'none';
|
|
304
|
+
}
|
|
305
|
+
show() {
|
|
306
|
+
const div = document.querySelector('#social-share-div');
|
|
307
|
+
document.body.style.overflow = 'hidden';
|
|
308
|
+
div.style.display = 'block';
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Context, ContextManager } from '../context';
|
|
2
|
+
import { Observable } from '../observable';
|
|
3
|
+
/** @zcontext */
|
|
4
|
+
export declare class SnapshotContext extends Context {
|
|
5
|
+
/** @zui */
|
|
6
|
+
canvasImage: Observable<string, never>;
|
|
7
|
+
/**@zui */
|
|
8
|
+
shareAPISupported: Observable<boolean, never>;
|
|
9
|
+
/** @zui */
|
|
10
|
+
canShare: Observable<boolean, never>;
|
|
11
|
+
canvasFile: Observable<File | null, never>;
|
|
12
|
+
fileName: Observable<string, never>;
|
|
13
|
+
text: Observable<string, never>;
|
|
14
|
+
title: Observable<string, never>;
|
|
15
|
+
fileType: Observable<string, never>;
|
|
16
|
+
quality: Observable<number, never>;
|
|
17
|
+
constructor(contextManager: ContextManager);
|
|
18
|
+
updateFile: () => Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Context } from '../context';
|
|
2
|
+
import { Observable } from '../observable';
|
|
3
|
+
/** @zcontext */
|
|
4
|
+
export class SnapshotContext extends Context {
|
|
5
|
+
constructor(contextManager) {
|
|
6
|
+
super(contextManager, {});
|
|
7
|
+
/** @zui */
|
|
8
|
+
this.canvasImage = new Observable('');
|
|
9
|
+
/**@zui */
|
|
10
|
+
this.shareAPISupported = new Observable('share' in navigator);
|
|
11
|
+
/** @zui */
|
|
12
|
+
this.canShare = new Observable(false);
|
|
13
|
+
this.canvasFile = new Observable(null);
|
|
14
|
+
this.fileName = new Observable('canvas', fileName => this.updateFile());
|
|
15
|
+
this.text = new Observable('Check this out!');
|
|
16
|
+
this.title = new Observable('Canvas');
|
|
17
|
+
this.fileType = new Observable('image/png', fileType => this.updateFile());
|
|
18
|
+
this.quality = new Observable(0.92);
|
|
19
|
+
this.updateFile = async () => {
|
|
20
|
+
const response = await fetch(this.canvasImage.value);
|
|
21
|
+
const blob = await response.blob();
|
|
22
|
+
const format = this.fileType.value === 'image/png' ? 'png' : 'jpeg';
|
|
23
|
+
const fileName = `${this.fileName.value}.${format}`;
|
|
24
|
+
const file = new File([blob], fileName, { type: blob.type });
|
|
25
|
+
this.canShare.value = navigator?.canShare?.({
|
|
26
|
+
title: this.title.value,
|
|
27
|
+
files: [file],
|
|
28
|
+
});
|
|
29
|
+
this.canvasFile.value = file;
|
|
30
|
+
};
|
|
31
|
+
this.canvasImage.addListener(this.updateFile);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zcomponent/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-beta",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "rm -rf lib && tsc",
|
|
23
23
|
"build-animation-tests": "tsc -p ./tsconfig.test.animation.json",
|
|
24
|
-
"test": "env TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha --es-module-specifier-resolution=node"
|
|
24
|
+
"test": "env TS_NODE_PROJECT=\"tsconfig.testing.json\" mocha --es-module-specifier-resolution=node",
|
|
25
|
+
"watch": "tsc -w"
|
|
25
26
|
},
|
|
26
27
|
"author": "Zappar Limited",
|
|
27
28
|
"license": "Proprietary",
|