capacitor-camera-multicapture 0.12.2
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/CameraMultiCapture.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +551 -0
- package/android/build.gradle +69 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfig.java +45 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfigMapper.java +98 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapture.java +10 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapturePlugin.java +1340 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ExifWrapper.java +108 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/GenericUploadWorker.java +173 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ImageUtils.java +215 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/PluginVersion.java +6 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ThumbnailGenerator.java +48 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/esm/controllers/camera-controller.d.ts +127 -0
- package/dist/esm/controllers/camera-controller.js +388 -0
- package/dist/esm/controllers/camera-controller.js.map +1 -0
- package/dist/esm/controllers/gallery-controller.d.ts +66 -0
- package/dist/esm/controllers/gallery-controller.js +333 -0
- package/dist/esm/controllers/gallery-controller.js.map +1 -0
- package/dist/esm/definitions.d.ts +372 -0
- package/dist/esm/definitions.js +6 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/overlay-manager.d.ts +124 -0
- package/dist/esm/overlay-manager.js +732 -0
- package/dist/esm/overlay-manager.js.map +1 -0
- package/dist/esm/overlay.d.ts +2 -0
- package/dist/esm/overlay.js +39 -0
- package/dist/esm/overlay.js.map +1 -0
- package/dist/esm/registration.d.ts +5 -0
- package/dist/esm/registration.js +8 -0
- package/dist/esm/registration.js.map +1 -0
- package/dist/esm/types/ui-types.d.ts +78 -0
- package/dist/esm/types/ui-types.js +2 -0
- package/dist/esm/types/ui-types.js.map +1 -0
- package/dist/esm/ui/capture-gesture-handler.d.ts +15 -0
- package/dist/esm/ui/capture-gesture-handler.js +87 -0
- package/dist/esm/ui/capture-gesture-handler.js.map +1 -0
- package/dist/esm/ui/default-styles.d.ts +27 -0
- package/dist/esm/ui/default-styles.js +134 -0
- package/dist/esm/ui/default-styles.js.map +1 -0
- package/dist/esm/ui/image-editor.d.ts +10 -0
- package/dist/esm/ui/image-editor.js +103 -0
- package/dist/esm/ui/image-editor.js.map +1 -0
- package/dist/esm/ui/layout-manager.d.ts +42 -0
- package/dist/esm/ui/layout-manager.js +199 -0
- package/dist/esm/ui/layout-manager.js.map +1 -0
- package/dist/esm/ui/media-viewer.d.ts +2 -0
- package/dist/esm/ui/media-viewer.js +267 -0
- package/dist/esm/ui/media-viewer.js.map +1 -0
- package/dist/esm/ui/pinch-zoom-handler.d.ts +37 -0
- package/dist/esm/ui/pinch-zoom-handler.js +118 -0
- package/dist/esm/ui/pinch-zoom-handler.js.map +1 -0
- package/dist/esm/ui/ui-factory.d.ts +39 -0
- package/dist/esm/ui/ui-factory.js +272 -0
- package/dist/esm/ui/ui-factory.js.map +1 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +3 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/esm/web.d.ts +69 -0
- package/dist/esm/web.js +122 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +6274 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +6276 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapture.swift +8 -0
- package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapturePlugin.swift +1551 -0
- package/ios/Sources/CameraMultiCapturePlugin/PluginVersion.swift +2 -0
- package/ios/Tests/CameraMultiCapturePluginTests/CameraMultiCapturePluginTests.swift +15 -0
- package/package.json +93 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Activator, MarkerArea } from 'markerjs2';
|
|
2
|
+
const EDITOR_STYLES_ID = 'cmmc-image-editor-styles';
|
|
3
|
+
let editorOpen = false;
|
|
4
|
+
function ensureEditorStyles() {
|
|
5
|
+
if (document.getElementById(EDITOR_STYLES_ID))
|
|
6
|
+
return;
|
|
7
|
+
const style = document.createElement('style');
|
|
8
|
+
style.id = EDITOR_STYLES_ID;
|
|
9
|
+
style.textContent = `
|
|
10
|
+
.cmmc-editor-backdrop {
|
|
11
|
+
position: fixed;
|
|
12
|
+
inset: 0;
|
|
13
|
+
z-index: 99999;
|
|
14
|
+
background: #000;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
justify-content: center;
|
|
18
|
+
padding-top: env(safe-area-inset-top);
|
|
19
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
}
|
|
22
|
+
.cmmc-editor-backdrop img {
|
|
23
|
+
max-width: 100%;
|
|
24
|
+
max-height: 100%;
|
|
25
|
+
object-fit: contain;
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
document.head.appendChild(style);
|
|
29
|
+
}
|
|
30
|
+
function loadImageElement(src) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const img = new Image();
|
|
33
|
+
img.crossOrigin = 'anonymous';
|
|
34
|
+
img.onload = () => resolve(img);
|
|
35
|
+
img.onerror = () => reject(new Error(`Failed to load image: ${src}`));
|
|
36
|
+
img.src = src;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Opens the Marker.js 2 annotation editor on a given image source.
|
|
41
|
+
* Resolves with the annotated image data-URL and editor state, or null if cancelled.
|
|
42
|
+
*/
|
|
43
|
+
export function openImageEditor(src, previousState, licenseKey) {
|
|
44
|
+
if (editorOpen)
|
|
45
|
+
return Promise.resolve(null);
|
|
46
|
+
editorOpen = true;
|
|
47
|
+
ensureEditorStyles();
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
let settled = false;
|
|
50
|
+
const finish = (value) => {
|
|
51
|
+
if (settled)
|
|
52
|
+
return;
|
|
53
|
+
settled = true;
|
|
54
|
+
editorOpen = false;
|
|
55
|
+
resolve(value);
|
|
56
|
+
};
|
|
57
|
+
void (async () => {
|
|
58
|
+
let backdrop = null;
|
|
59
|
+
try {
|
|
60
|
+
backdrop = document.createElement('div');
|
|
61
|
+
backdrop.className = 'cmmc-editor-backdrop';
|
|
62
|
+
document.body.appendChild(backdrop);
|
|
63
|
+
if (licenseKey && licenseKey.trim()) {
|
|
64
|
+
Activator.addKey(licenseKey.trim());
|
|
65
|
+
}
|
|
66
|
+
const img = await loadImageElement(src);
|
|
67
|
+
backdrop.appendChild(img);
|
|
68
|
+
const markerArea = new MarkerArea(img);
|
|
69
|
+
markerArea.targetRoot = backdrop;
|
|
70
|
+
markerArea.renderAtNaturalSize = true;
|
|
71
|
+
markerArea.renderImageType = 'image/jpeg';
|
|
72
|
+
markerArea.renderImageQuality = 1;
|
|
73
|
+
markerArea.addEventListener('render', (event) => {
|
|
74
|
+
backdrop === null || backdrop === void 0 ? void 0 : backdrop.remove();
|
|
75
|
+
backdrop = null;
|
|
76
|
+
finish({ dataUrl: event.dataUrl, state: event.state });
|
|
77
|
+
});
|
|
78
|
+
markerArea.addEventListener('close', () => {
|
|
79
|
+
backdrop === null || backdrop === void 0 ? void 0 : backdrop.remove();
|
|
80
|
+
backdrop = null;
|
|
81
|
+
finish(null);
|
|
82
|
+
});
|
|
83
|
+
markerArea.show();
|
|
84
|
+
if (previousState) {
|
|
85
|
+
try {
|
|
86
|
+
markerArea.restoreState(previousState);
|
|
87
|
+
}
|
|
88
|
+
catch (_a) {
|
|
89
|
+
/* e.g. state from an older editor version */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (_err) {
|
|
94
|
+
backdrop === null || backdrop === void 0 ? void 0 : backdrop.remove();
|
|
95
|
+
finish(null);
|
|
96
|
+
}
|
|
97
|
+
})();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
export function isEditorActive() {
|
|
101
|
+
return editorOpen;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=image-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-editor.js","sourceRoot":"","sources":["../../../src/ui/image-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { Activator, MarkerArea } from 'markerjs2';\n\nconst EDITOR_STYLES_ID = 'cmmc-image-editor-styles';\n\nexport type ImageEditorResult = {\n dataUrl: string;\n state: unknown;\n};\n\nlet editorOpen = false;\n\nfunction ensureEditorStyles(): void {\n if (document.getElementById(EDITOR_STYLES_ID)) return;\n\n const style = document.createElement('style');\n style.id = EDITOR_STYLES_ID;\n style.textContent = `\n .cmmc-editor-backdrop {\n position: fixed;\n inset: 0;\n z-index: 99999;\n background: #000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding-top: env(safe-area-inset-top);\n padding-bottom: env(safe-area-inset-bottom);\n box-sizing: border-box;\n }\n .cmmc-editor-backdrop img {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n }\n `;\n document.head.appendChild(style);\n}\n\nfunction loadImageElement(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(`Failed to load image: ${src}`));\n img.src = src;\n });\n}\n\n/**\n * Opens the Marker.js 2 annotation editor on a given image source.\n * Resolves with the annotated image data-URL and editor state, or null if cancelled.\n */\nexport function openImageEditor(\n src: string,\n previousState?: unknown,\n licenseKey?: string,\n): Promise<ImageEditorResult | null> {\n if (editorOpen) return Promise.resolve(null);\n\n editorOpen = true;\n ensureEditorStyles();\n\n return new Promise<ImageEditorResult | null>((resolve) => {\n let settled = false;\n\n const finish = (value: ImageEditorResult | null) => {\n if (settled) return;\n settled = true;\n editorOpen = false;\n resolve(value);\n };\n\n void (async () => {\n let backdrop: HTMLElement | null = null;\n\n try {\n backdrop = document.createElement('div');\n backdrop.className = 'cmmc-editor-backdrop';\n document.body.appendChild(backdrop);\n\n if (licenseKey && licenseKey.trim()) {\n Activator.addKey(licenseKey.trim());\n }\n\n const img = await loadImageElement(src);\n backdrop.appendChild(img);\n\n const markerArea = new MarkerArea(img);\n markerArea.targetRoot = backdrop;\n markerArea.renderAtNaturalSize = true;\n markerArea.renderImageType = 'image/jpeg';\n markerArea.renderImageQuality = 1;\n\n markerArea.addEventListener('render', (event: { dataUrl: string; state: unknown }) => {\n backdrop?.remove();\n backdrop = null;\n finish({ dataUrl: event.dataUrl, state: event.state });\n });\n\n markerArea.addEventListener('close', () => {\n backdrop?.remove();\n backdrop = null;\n finish(null);\n });\n\n markerArea.show();\n\n if (previousState) {\n try {\n markerArea.restoreState(previousState as never);\n } catch {\n /* e.g. state from an older editor version */\n }\n }\n } catch (_err) {\n backdrop?.remove();\n finish(null);\n }\n })();\n });\n}\n\nexport function isEditorActive(): boolean {\n return editorOpen;\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout manager for camera overlay UI
|
|
3
|
+
*/
|
|
4
|
+
import { UIPosition } from '../types/ui-types';
|
|
5
|
+
/**
|
|
6
|
+
* Interface for position containers
|
|
7
|
+
*/
|
|
8
|
+
export interface PositionContainers {
|
|
9
|
+
topLeft: HTMLElement;
|
|
10
|
+
topRight: HTMLElement;
|
|
11
|
+
center: HTMLElement;
|
|
12
|
+
bottomGrid: HTMLElement;
|
|
13
|
+
zoomRow: HTMLElement;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Interface for bottom grid cells
|
|
17
|
+
*/
|
|
18
|
+
export interface BottomGridCells {
|
|
19
|
+
left: HTMLElement;
|
|
20
|
+
middle: HTMLElement;
|
|
21
|
+
right: HTMLElement;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates and styles the overlay container
|
|
25
|
+
*/
|
|
26
|
+
export declare function createOverlayContainer(containerId: string): HTMLElement;
|
|
27
|
+
/**
|
|
28
|
+
* Creates the position containers for UI elements
|
|
29
|
+
*/
|
|
30
|
+
export declare function createPositionContainers(overlay: HTMLElement): PositionContainers;
|
|
31
|
+
/**
|
|
32
|
+
* Creates the bottom grid cells
|
|
33
|
+
*/
|
|
34
|
+
export declare function createBottomGridCells(bottomGrid: HTMLElement): BottomGridCells;
|
|
35
|
+
/**
|
|
36
|
+
* Creates the gallery container for thumbnails
|
|
37
|
+
*/
|
|
38
|
+
export declare function createGallery(overlay: HTMLElement): HTMLElement;
|
|
39
|
+
/**
|
|
40
|
+
* Gets the position container based on the specified position
|
|
41
|
+
*/
|
|
42
|
+
export declare function getPositionContainer(positions: PositionContainers, position?: UIPosition): HTMLElement;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates and styles the overlay container
|
|
3
|
+
*/
|
|
4
|
+
export function createOverlayContainer(containerId) {
|
|
5
|
+
const container = document.getElementById(containerId);
|
|
6
|
+
if (!container) {
|
|
7
|
+
throw new Error(`Container element with ID '${containerId}' not found`);
|
|
8
|
+
}
|
|
9
|
+
// Make sure the container has position relative for proper positioning of child elements
|
|
10
|
+
if (getComputedStyle(container).position === 'static') {
|
|
11
|
+
container.style.position = 'relative';
|
|
12
|
+
}
|
|
13
|
+
const overlay = document.createElement('div');
|
|
14
|
+
overlay.id = 'camera-overlay';
|
|
15
|
+
Object.assign(overlay.style, {
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
top: '0', left: '0', width: '100%', height: '100%',
|
|
18
|
+
background: 'transparent',
|
|
19
|
+
zIndex: '1',
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'column',
|
|
22
|
+
justifyContent: 'flex-end',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
padding: '10px',
|
|
25
|
+
color: '#000',
|
|
26
|
+
boxSizing: 'border-box'
|
|
27
|
+
});
|
|
28
|
+
container.appendChild(overlay);
|
|
29
|
+
return overlay;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates the position containers for UI elements
|
|
33
|
+
*/
|
|
34
|
+
export function createPositionContainers(overlay) {
|
|
35
|
+
const positions = {
|
|
36
|
+
topLeft: document.createElement('div'),
|
|
37
|
+
topRight: document.createElement('div'),
|
|
38
|
+
center: document.createElement('div'),
|
|
39
|
+
bottomGrid: document.createElement('div'),
|
|
40
|
+
zoomRow: document.createElement('div')
|
|
41
|
+
};
|
|
42
|
+
Object.assign(positions.topLeft.style, {
|
|
43
|
+
position: 'absolute',
|
|
44
|
+
top: '10px',
|
|
45
|
+
left: '10px',
|
|
46
|
+
display: 'flex',
|
|
47
|
+
gap: '10px',
|
|
48
|
+
zIndex: '2'
|
|
49
|
+
});
|
|
50
|
+
Object.assign(positions.topRight.style, {
|
|
51
|
+
position: 'absolute',
|
|
52
|
+
top: '10px',
|
|
53
|
+
right: '10px',
|
|
54
|
+
display: 'flex',
|
|
55
|
+
flexDirection: 'column',
|
|
56
|
+
alignItems: 'flex-end',
|
|
57
|
+
gap: '10px',
|
|
58
|
+
zIndex: '2'
|
|
59
|
+
});
|
|
60
|
+
Object.assign(positions.center.style, {
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
top: '50%',
|
|
63
|
+
left: '50%',
|
|
64
|
+
transform: 'translate(-50%, -50%)',
|
|
65
|
+
display: 'flex',
|
|
66
|
+
gap: '10px',
|
|
67
|
+
zIndex: '2'
|
|
68
|
+
});
|
|
69
|
+
Object.assign(positions.bottomGrid.style, {
|
|
70
|
+
position: 'absolute',
|
|
71
|
+
bottom: '20px',
|
|
72
|
+
left: '0',
|
|
73
|
+
width: '100%',
|
|
74
|
+
display: 'grid',
|
|
75
|
+
gridTemplateColumns: '1fr 1fr 1fr', // 3 equal columns
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
padding: '0 10px',
|
|
78
|
+
boxSizing: 'border-box',
|
|
79
|
+
zIndex: '2',
|
|
80
|
+
height: '70px' // Fixed height to prevent overlap
|
|
81
|
+
});
|
|
82
|
+
Object.assign(positions.zoomRow.style, {
|
|
83
|
+
position: 'absolute',
|
|
84
|
+
bottom: '110px', // Increased distance from bottom grid
|
|
85
|
+
left: '0',
|
|
86
|
+
width: '100%',
|
|
87
|
+
display: 'flex',
|
|
88
|
+
justifyContent: 'center',
|
|
89
|
+
alignItems: 'center',
|
|
90
|
+
gap: '10px',
|
|
91
|
+
padding: '10px',
|
|
92
|
+
boxSizing: 'border-box',
|
|
93
|
+
zIndex: '2',
|
|
94
|
+
height: '40px' // Fixed height for zoom row
|
|
95
|
+
});
|
|
96
|
+
Object.values(positions).forEach(posContainer => {
|
|
97
|
+
overlay.appendChild(posContainer);
|
|
98
|
+
});
|
|
99
|
+
return positions;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Creates the bottom grid cells
|
|
103
|
+
*/
|
|
104
|
+
export function createBottomGridCells(bottomGrid) {
|
|
105
|
+
const cells = {
|
|
106
|
+
left: document.createElement('div'),
|
|
107
|
+
middle: document.createElement('div'),
|
|
108
|
+
right: document.createElement('div')
|
|
109
|
+
};
|
|
110
|
+
Object.assign(cells.left.style, {
|
|
111
|
+
display: 'flex',
|
|
112
|
+
justifyContent: 'center',
|
|
113
|
+
alignItems: 'center'
|
|
114
|
+
});
|
|
115
|
+
Object.assign(cells.middle.style, {
|
|
116
|
+
display: 'flex',
|
|
117
|
+
justifyContent: 'center',
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
position: 'relative'
|
|
120
|
+
});
|
|
121
|
+
Object.assign(cells.right.style, {
|
|
122
|
+
display: 'flex',
|
|
123
|
+
justifyContent: 'center',
|
|
124
|
+
alignItems: 'center'
|
|
125
|
+
});
|
|
126
|
+
bottomGrid.appendChild(cells.left);
|
|
127
|
+
bottomGrid.appendChild(cells.middle);
|
|
128
|
+
bottomGrid.appendChild(cells.right);
|
|
129
|
+
return cells;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Creates the gallery container for thumbnails
|
|
133
|
+
*/
|
|
134
|
+
export function createGallery(overlay) {
|
|
135
|
+
const gallery = document.createElement('div');
|
|
136
|
+
Object.assign(gallery.style, {
|
|
137
|
+
position: 'absolute',
|
|
138
|
+
bottom: '160px',
|
|
139
|
+
left: '0',
|
|
140
|
+
width: '100%',
|
|
141
|
+
display: 'flex',
|
|
142
|
+
gap: '10px',
|
|
143
|
+
padding: '10px',
|
|
144
|
+
overflowX: 'auto',
|
|
145
|
+
overflowY: 'hidden',
|
|
146
|
+
whiteSpace: 'nowrap',
|
|
147
|
+
justifyContent: 'center',
|
|
148
|
+
zIndex: '2',
|
|
149
|
+
scrollbarWidth: 'none',
|
|
150
|
+
WebkitOverflowScrolling: 'touch',
|
|
151
|
+
flexWrap: 'nowrap'
|
|
152
|
+
});
|
|
153
|
+
gallery.style.setProperty('-ms-overflow-style', 'none');
|
|
154
|
+
// Function to update justify-content based on content overflow
|
|
155
|
+
const updateJustification = () => {
|
|
156
|
+
if (gallery.scrollWidth > gallery.clientWidth) {
|
|
157
|
+
gallery.style.justifyContent = 'flex-start';
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
gallery.style.justifyContent = 'center';
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
// Create a MutationObserver to watch for content changes
|
|
164
|
+
const observer = new MutationObserver(updateJustification);
|
|
165
|
+
observer.observe(gallery, { childList: true, subtree: true });
|
|
166
|
+
// Also update on resize (with fallback for browsers without ResizeObserver)
|
|
167
|
+
if (typeof window.ResizeObserver !== 'undefined') {
|
|
168
|
+
const resizeObserver = new window.ResizeObserver(updateJustification);
|
|
169
|
+
resizeObserver.observe(gallery);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Fallback: use window resize event
|
|
173
|
+
window.addEventListener('resize', updateJustification);
|
|
174
|
+
}
|
|
175
|
+
gallery.addEventListener('mouseenter', () => {
|
|
176
|
+
gallery.style.overflow = 'auto';
|
|
177
|
+
});
|
|
178
|
+
gallery.addEventListener('mouseleave', () => {
|
|
179
|
+
gallery.style.overflow = 'hidden';
|
|
180
|
+
});
|
|
181
|
+
overlay.appendChild(gallery);
|
|
182
|
+
return gallery;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Gets the position container based on the specified position
|
|
186
|
+
*/
|
|
187
|
+
export function getPositionContainer(positions, position) {
|
|
188
|
+
switch (position) {
|
|
189
|
+
case 'topLeft':
|
|
190
|
+
return positions.topLeft;
|
|
191
|
+
case 'topRight':
|
|
192
|
+
return positions.topRight;
|
|
193
|
+
case 'center':
|
|
194
|
+
return positions.center;
|
|
195
|
+
default:
|
|
196
|
+
return positions.topRight; // Default fallback
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=layout-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout-manager.js","sourceRoot":"","sources":["../../../src/ui/layout-manager.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Layout manager for camera overlay UI\n */\nimport { UIPosition } from '../types/ui-types';\n\n/**\n * Interface for position containers\n */\nexport interface PositionContainers {\n topLeft: HTMLElement;\n topRight: HTMLElement;\n center: HTMLElement;\n bottomGrid: HTMLElement;\n zoomRow: HTMLElement;\n}\n\n/**\n * Interface for bottom grid cells\n */\nexport interface BottomGridCells {\n left: HTMLElement;\n middle: HTMLElement;\n right: HTMLElement;\n}\n\n/**\n * Creates and styles the overlay container\n */\nexport function createOverlayContainer(containerId: string): HTMLElement {\n const container = document.getElementById(containerId);\n if (!container) {\n throw new Error(`Container element with ID '${containerId}' not found`);\n }\n \n // Make sure the container has position relative for proper positioning of child elements\n if (getComputedStyle(container).position === 'static') {\n container.style.position = 'relative';\n }\n \n const overlay = document.createElement('div');\n overlay.id = 'camera-overlay';\n Object.assign(overlay.style, {\n position: 'absolute',\n top: '0', left: '0', width: '100%', height: '100%',\n background: 'transparent', \n zIndex: '1',\n display: 'flex', \n flexDirection: 'column', \n justifyContent: 'flex-end', \n alignItems: 'center', \n padding: '10px',\n color: '#000',\n boxSizing: 'border-box'\n });\n \n container.appendChild(overlay);\n \n return overlay;\n}\n\n/**\n * Creates the position containers for UI elements\n */\nexport function createPositionContainers(overlay: HTMLElement): PositionContainers {\n const positions: PositionContainers = {\n topLeft: document.createElement('div'),\n topRight: document.createElement('div'),\n center: document.createElement('div'),\n bottomGrid: document.createElement('div'),\n zoomRow: document.createElement('div')\n };\n \n Object.assign(positions.topLeft.style, {\n position: 'absolute',\n top: '10px',\n left: '10px',\n display: 'flex',\n gap: '10px',\n zIndex: '2'\n });\n \n Object.assign(positions.topRight.style, {\n position: 'absolute',\n top: '10px',\n right: '10px',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-end',\n gap: '10px',\n zIndex: '2'\n });\n \n Object.assign(positions.center.style, {\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n display: 'flex',\n gap: '10px',\n zIndex: '2'\n });\n \n Object.assign(positions.bottomGrid.style, {\n position: 'absolute',\n bottom: '20px',\n left: '0',\n width: '100%',\n display: 'grid',\n gridTemplateColumns: '1fr 1fr 1fr', // 3 equal columns\n alignItems: 'center',\n padding: '0 10px',\n boxSizing: 'border-box',\n zIndex: '2',\n height: '70px' // Fixed height to prevent overlap\n });\n \n Object.assign(positions.zoomRow.style, {\n position: 'absolute',\n bottom: '110px', // Increased distance from bottom grid\n left: '0',\n width: '100%',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n gap: '10px',\n padding: '10px',\n boxSizing: 'border-box',\n zIndex: '2',\n height: '40px' // Fixed height for zoom row\n });\n \n Object.values(positions).forEach(posContainer => {\n overlay.appendChild(posContainer);\n });\n \n return positions;\n}\n\n/**\n * Creates the bottom grid cells\n */\nexport function createBottomGridCells(bottomGrid: HTMLElement): BottomGridCells {\n const cells: BottomGridCells = {\n left: document.createElement('div'),\n middle: document.createElement('div'),\n right: document.createElement('div')\n };\n \n Object.assign(cells.left.style, {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center'\n });\n \n Object.assign(cells.middle.style, {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n position: 'relative'\n });\n \n Object.assign(cells.right.style, {\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center'\n });\n \n bottomGrid.appendChild(cells.left);\n bottomGrid.appendChild(cells.middle);\n bottomGrid.appendChild(cells.right);\n \n return cells;\n}\n\n/**\n * Creates the gallery container for thumbnails\n */\nexport function createGallery(overlay: HTMLElement): HTMLElement {\n const gallery = document.createElement('div');\n Object.assign(gallery.style, {\n position: 'absolute',\n bottom: '160px',\n left: '0',\n width: '100%',\n display: 'flex', \n gap: '10px', \n padding: '10px',\n overflowX: 'auto',\n overflowY: 'hidden',\n whiteSpace: 'nowrap',\n justifyContent: 'center',\n zIndex: '2',\n scrollbarWidth: 'none',\n WebkitOverflowScrolling: 'touch',\n flexWrap: 'nowrap'\n });\n \n gallery.style.setProperty('-ms-overflow-style', 'none');\n \n // Function to update justify-content based on content overflow\n const updateJustification = () => {\n if (gallery.scrollWidth > gallery.clientWidth) {\n gallery.style.justifyContent = 'flex-start';\n } else {\n gallery.style.justifyContent = 'center';\n }\n };\n \n // Create a MutationObserver to watch for content changes\n const observer = new MutationObserver(updateJustification);\n observer.observe(gallery, { childList: true, subtree: true });\n \n // Also update on resize (with fallback for browsers without ResizeObserver)\n if (typeof (window as any).ResizeObserver !== 'undefined') {\n const resizeObserver = new (window as any).ResizeObserver(updateJustification);\n resizeObserver.observe(gallery);\n } else {\n // Fallback: use window resize event\n window.addEventListener('resize', updateJustification);\n }\n \n gallery.addEventListener('mouseenter', () => {\n gallery.style.overflow = 'auto';\n });\n gallery.addEventListener('mouseleave', () => {\n gallery.style.overflow = 'hidden';\n });\n \n overlay.appendChild(gallery);\n \n return gallery;\n}\n\n/**\n * Gets the position container based on the specified position\n */\nexport function getPositionContainer(\n positions: PositionContainers,\n position?: UIPosition\n): HTMLElement {\n switch (position) {\n case 'topLeft':\n return positions.topLeft;\n case 'topRight':\n return positions.topRight;\n case 'center':\n return positions.center;\n default:\n return positions.topRight; // Default fallback\n }\n}\n"]}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import BiggerPicture from 'bigger-picture';
|
|
2
|
+
import bpCss from 'bigger-picture/css-text';
|
|
3
|
+
const BP_STYLES_ID = 'cmmc-bigger-picture-styles';
|
|
4
|
+
let bpInstance = null;
|
|
5
|
+
let activeBackHandler = null;
|
|
6
|
+
const DEFAULT_MEDIA_WIDTH = 1920;
|
|
7
|
+
const DEFAULT_MEDIA_HEIGHT = 1080;
|
|
8
|
+
function ensureStyles() {
|
|
9
|
+
const existing = document.getElementById(BP_STYLES_ID);
|
|
10
|
+
if (existing && existing.tagName.toLowerCase() !== 'style') {
|
|
11
|
+
existing.remove();
|
|
12
|
+
}
|
|
13
|
+
const style = document.getElementById(BP_STYLES_ID);
|
|
14
|
+
if (style) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const styleEl = document.createElement('style');
|
|
18
|
+
styleEl.id = BP_STYLES_ID;
|
|
19
|
+
styleEl.textContent = `${bpCss}
|
|
20
|
+
.bp-wrap,
|
|
21
|
+
.bp-wrap * {
|
|
22
|
+
animation-duration: 0ms !important;
|
|
23
|
+
transition-duration: 0ms !important;
|
|
24
|
+
transition-delay: 0ms !important;
|
|
25
|
+
}
|
|
26
|
+
.bp-wrap {
|
|
27
|
+
--cmmc-safe-top-extra: 0px;
|
|
28
|
+
--cmmc-safe-bottom-extra: 0px;
|
|
29
|
+
}
|
|
30
|
+
.bp-wrap > div:first-child {
|
|
31
|
+
background: #000 !important;
|
|
32
|
+
}
|
|
33
|
+
.bp-x {
|
|
34
|
+
top: env(safe-area-inset-top) !important;
|
|
35
|
+
}
|
|
36
|
+
.bp-img-wrap {
|
|
37
|
+
top: calc(env(safe-area-inset-top) + var(--cmmc-safe-top-extra)) !important;
|
|
38
|
+
bottom: calc(env(safe-area-inset-bottom) + var(--cmmc-safe-bottom-extra)) !important;
|
|
39
|
+
height: auto !important;
|
|
40
|
+
}
|
|
41
|
+
.bp-vid,
|
|
42
|
+
.bp-if {
|
|
43
|
+
max-height: calc(100% - env(safe-area-inset-top) - env(safe-area-inset-bottom) - var(--cmmc-safe-top-extra) - var(--cmmc-safe-bottom-extra)) !important;
|
|
44
|
+
margin-top: calc(env(safe-area-inset-top) + var(--cmmc-safe-top-extra)) !important;
|
|
45
|
+
margin-bottom: calc(env(safe-area-inset-bottom) + var(--cmmc-safe-bottom-extra)) !important;
|
|
46
|
+
}
|
|
47
|
+
.bp-controls .cmmc-bp-edit {
|
|
48
|
+
position: absolute;
|
|
49
|
+
top: env(safe-area-inset-top);
|
|
50
|
+
left: 0;
|
|
51
|
+
z-index: 10;
|
|
52
|
+
width: 48px;
|
|
53
|
+
height: 48px;
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
background: none;
|
|
58
|
+
border: none;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
color: #fff;
|
|
61
|
+
padding: 0;
|
|
62
|
+
-webkit-tap-highlight-color: transparent;
|
|
63
|
+
}
|
|
64
|
+
.bp-controls .cmmc-bp-edit:hover {
|
|
65
|
+
background: none;
|
|
66
|
+
}
|
|
67
|
+
.bp-controls .cmmc-bp-edit svg {
|
|
68
|
+
filter: drop-shadow(0 1px 3px rgba(0,0,0,0.6));
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
document.head.appendChild(styleEl);
|
|
72
|
+
}
|
|
73
|
+
function getInstance() {
|
|
74
|
+
if (bpInstance) {
|
|
75
|
+
return bpInstance;
|
|
76
|
+
}
|
|
77
|
+
bpInstance = BiggerPicture({
|
|
78
|
+
target: document.body,
|
|
79
|
+
});
|
|
80
|
+
return bpInstance;
|
|
81
|
+
}
|
|
82
|
+
function getMimeType(src) {
|
|
83
|
+
const normalized = src.toLowerCase();
|
|
84
|
+
if (normalized.endsWith('.webm'))
|
|
85
|
+
return 'video/webm';
|
|
86
|
+
if (normalized.endsWith('.mov'))
|
|
87
|
+
return 'video/quicktime';
|
|
88
|
+
return 'video/mp4';
|
|
89
|
+
}
|
|
90
|
+
function readSafeAreaInset(property) {
|
|
91
|
+
const probe = document.createElement('div');
|
|
92
|
+
probe.style.position = 'fixed';
|
|
93
|
+
probe.style.visibility = 'hidden';
|
|
94
|
+
probe.style.pointerEvents = 'none';
|
|
95
|
+
probe.style.zIndex = '-1';
|
|
96
|
+
if (property === 'top') {
|
|
97
|
+
probe.style.top = '0';
|
|
98
|
+
probe.style.paddingTop = 'env(safe-area-inset-top)';
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
probe.style.bottom = '0';
|
|
102
|
+
probe.style.paddingBottom = 'env(safe-area-inset-bottom)';
|
|
103
|
+
}
|
|
104
|
+
document.body.appendChild(probe);
|
|
105
|
+
const computed = window.getComputedStyle(probe);
|
|
106
|
+
const raw = property === 'top' ? computed.paddingTop : computed.paddingBottom;
|
|
107
|
+
probe.remove();
|
|
108
|
+
const parsed = Number.parseFloat(raw);
|
|
109
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
110
|
+
}
|
|
111
|
+
function applyDynamicSafeArea(container) {
|
|
112
|
+
const closeButton = container.querySelector('.bp-x');
|
|
113
|
+
const media = container.querySelector('.bp-vid, .bp-if, .bp-img');
|
|
114
|
+
if (!closeButton || !media) {
|
|
115
|
+
container.style.setProperty('--cmmc-safe-top-extra', '0px');
|
|
116
|
+
container.style.setProperty('--cmmc-safe-bottom-extra', '0px');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const closeRect = closeButton.getBoundingClientRect();
|
|
120
|
+
const mediaRect = media.getBoundingClientRect();
|
|
121
|
+
const safeBottom = readSafeAreaInset('bottom');
|
|
122
|
+
const topOverlap = Math.max(0, closeRect.bottom - mediaRect.top);
|
|
123
|
+
const bottomLimit = window.innerHeight - safeBottom;
|
|
124
|
+
const bottomOverlap = Math.max(0, mediaRect.bottom - bottomLimit);
|
|
125
|
+
container.style.setProperty('--cmmc-safe-top-extra', `${topOverlap}px`);
|
|
126
|
+
container.style.setProperty('--cmmc-safe-bottom-extra', `${bottomOverlap}px`);
|
|
127
|
+
}
|
|
128
|
+
function getImageDimensions(src) {
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
const img = new Image();
|
|
131
|
+
img.onload = () => {
|
|
132
|
+
if (img.naturalWidth > 0 && img.naturalHeight > 0) {
|
|
133
|
+
resolve({ width: img.naturalWidth, height: img.naturalHeight });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
resolve(null);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
img.onerror = () => resolve(null);
|
|
140
|
+
img.src = src;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function getVideoDimensions(src) {
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
const video = document.createElement('video');
|
|
146
|
+
video.preload = 'metadata';
|
|
147
|
+
video.playsInline = true;
|
|
148
|
+
const cleanup = () => {
|
|
149
|
+
video.removeAttribute('src');
|
|
150
|
+
video.load();
|
|
151
|
+
};
|
|
152
|
+
video.onloadedmetadata = () => {
|
|
153
|
+
const width = video.videoWidth;
|
|
154
|
+
const height = video.videoHeight;
|
|
155
|
+
cleanup();
|
|
156
|
+
if (width > 0 && height > 0) {
|
|
157
|
+
resolve({ width, height });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
resolve(null);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
video.onerror = () => {
|
|
164
|
+
cleanup();
|
|
165
|
+
resolve(null);
|
|
166
|
+
};
|
|
167
|
+
video.src = src;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function injectEditButton(container, onEdit) {
|
|
171
|
+
const controls = container.querySelector('.bp-controls');
|
|
172
|
+
if (!controls || controls.querySelector('.cmmc-bp-edit'))
|
|
173
|
+
return;
|
|
174
|
+
const btn = document.createElement('button');
|
|
175
|
+
btn.className = 'cmmc-bp-edit';
|
|
176
|
+
btn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/></svg>`;
|
|
177
|
+
btn.onclick = (e) => {
|
|
178
|
+
e.stopPropagation();
|
|
179
|
+
getInstance().close();
|
|
180
|
+
onEdit();
|
|
181
|
+
};
|
|
182
|
+
controls.appendChild(btn);
|
|
183
|
+
}
|
|
184
|
+
function registerBackHandler() {
|
|
185
|
+
removeBackHandler();
|
|
186
|
+
const handler = () => {
|
|
187
|
+
getInstance().close();
|
|
188
|
+
};
|
|
189
|
+
activeBackHandler = handler;
|
|
190
|
+
document.addEventListener('backbutton', handler);
|
|
191
|
+
}
|
|
192
|
+
function removeBackHandler() {
|
|
193
|
+
if (activeBackHandler) {
|
|
194
|
+
document.removeEventListener('backbutton', activeBackHandler);
|
|
195
|
+
activeBackHandler = null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export function openImagePreview(src, thumb, onEdit) {
|
|
199
|
+
void (async () => {
|
|
200
|
+
var _a, _b;
|
|
201
|
+
ensureStyles();
|
|
202
|
+
const dimensions = await getImageDimensions(src);
|
|
203
|
+
const items = [
|
|
204
|
+
{
|
|
205
|
+
img: src,
|
|
206
|
+
thumb: thumb || src,
|
|
207
|
+
width: (_a = dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== null && _a !== void 0 ? _a : DEFAULT_MEDIA_WIDTH,
|
|
208
|
+
height: (_b = dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) !== null && _b !== void 0 ? _b : DEFAULT_MEDIA_HEIGHT,
|
|
209
|
+
},
|
|
210
|
+
];
|
|
211
|
+
getInstance().open({
|
|
212
|
+
items,
|
|
213
|
+
el: document.body,
|
|
214
|
+
scale: 1,
|
|
215
|
+
intro: 'fadeup',
|
|
216
|
+
onOpen: (container) => {
|
|
217
|
+
applyDynamicSafeArea(container);
|
|
218
|
+
registerBackHandler();
|
|
219
|
+
if (onEdit) {
|
|
220
|
+
injectEditButton(container, onEdit);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
onClose: () => {
|
|
224
|
+
removeBackHandler();
|
|
225
|
+
},
|
|
226
|
+
onResize: (container) => {
|
|
227
|
+
if (!container)
|
|
228
|
+
return;
|
|
229
|
+
applyDynamicSafeArea(container);
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
})();
|
|
233
|
+
}
|
|
234
|
+
export function openVideoPreview(src, thumb) {
|
|
235
|
+
void (async () => {
|
|
236
|
+
var _a, _b;
|
|
237
|
+
ensureStyles();
|
|
238
|
+
const dimensions = await getVideoDimensions(src);
|
|
239
|
+
const items = [
|
|
240
|
+
{
|
|
241
|
+
thumb: thumb || src,
|
|
242
|
+
sources: [{ src, type: getMimeType(src) }],
|
|
243
|
+
width: (_a = dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== null && _a !== void 0 ? _a : DEFAULT_MEDIA_WIDTH,
|
|
244
|
+
height: (_b = dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) !== null && _b !== void 0 ? _b : DEFAULT_MEDIA_HEIGHT,
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
getInstance().open({
|
|
248
|
+
items,
|
|
249
|
+
el: document.body,
|
|
250
|
+
scale: 1,
|
|
251
|
+
intro: 'fadeup',
|
|
252
|
+
onOpen: (container) => {
|
|
253
|
+
applyDynamicSafeArea(container);
|
|
254
|
+
registerBackHandler();
|
|
255
|
+
},
|
|
256
|
+
onClose: () => {
|
|
257
|
+
removeBackHandler();
|
|
258
|
+
},
|
|
259
|
+
onResize: (container) => {
|
|
260
|
+
if (!container)
|
|
261
|
+
return;
|
|
262
|
+
applyDynamicSafeArea(container);
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
})();
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=media-viewer.js.map
|