ywana-core8 0.2.13 → 0.2.15
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/dist/index.css +60 -11
- package/dist/index.js +63 -6
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +64 -7
- package/dist/index.modern.js.map +1 -1
- package/dist/index.umd.js +63 -6
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/desktop/desktop.js +1 -3
- package/src/desktop/window.css +1 -0
- package/src/html/index.js +1 -1
- package/src/widgets/image/ImageViewer.css +14 -1
- package/src/widgets/image/ImageViewer.js +20 -6
- package/src/widgets/viewer/Viewer.css +45 -10
- package/src/widgets/viewer/Viewer.js +71 -19
package/package.json
CHANGED
package/src/desktop/desktop.js
CHANGED
package/src/desktop/window.css
CHANGED
package/src/html/index.js
CHANGED
@@ -9,7 +9,7 @@ export { Header2 } from './header2'
|
|
9
9
|
export { Icon } from './icon'
|
10
10
|
export { List } from './list'
|
11
11
|
export { MenuIcon, Menu, MenuItem, MenuSeparator } from './menu'
|
12
|
-
export { CircularProgress, LinearProgress } from './progress'
|
12
|
+
export { CircularProgress, LinearProgress, StepProgress, RadialProgress, MultiProgress } from './progress'
|
13
13
|
export { Property } from './property'
|
14
14
|
export { RadioButton, RadioGroup } from './radio'
|
15
15
|
export { Section } from './section'
|
@@ -1,5 +1,18 @@
|
|
1
|
-
.image-viewer
|
1
|
+
.image-viewer {
|
2
2
|
display: flex;
|
3
3
|
justify-content: center;
|
4
4
|
align-items: center;
|
5
|
+
width: 100%;
|
6
|
+
height: 100%;
|
7
|
+
overflow: hidden;
|
8
|
+
}
|
9
|
+
|
10
|
+
.image-viewer canvas {
|
11
|
+
cursor: grab;
|
12
|
+
max-width: 100%;
|
13
|
+
max-height: 100%;
|
14
|
+
}
|
15
|
+
|
16
|
+
.image-viewer canvas:active {
|
17
|
+
cursor: grabbing;
|
5
18
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useRef, useMemo, useEffect, useState } from "react";
|
1
|
+
import React, { useRef, useMemo, useEffect, useState, forwardRef, useImperativeHandle } from "react";
|
2
2
|
import './ImageViewer.css'
|
3
3
|
|
4
4
|
const ImageViewerTest = (props) => {
|
@@ -14,10 +14,10 @@ const SCROLL_SENSITIVITY = 0.0005;
|
|
14
14
|
const MAX_ZOOM = 5;
|
15
15
|
const MIN_ZOOM = 0.1;
|
16
16
|
|
17
|
-
export const ImageViewer = ({ image }) => {
|
17
|
+
export const ImageViewer = forwardRef(({ image }, ref) => {
|
18
18
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
19
19
|
const [zoom, setZoom] = useState(1);
|
20
|
-
const [
|
20
|
+
const [dragging, setDragging] = useState(false);
|
21
21
|
|
22
22
|
const touch = useRef({ x: 0, y: 0 });
|
23
23
|
const canvasRef = useRef(null);
|
@@ -27,9 +27,23 @@ export const ImageViewer = ({ image }) => {
|
|
27
27
|
|
28
28
|
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
29
29
|
|
30
|
+
// Expose zoom functions to parent component
|
31
|
+
useImperativeHandle(ref, () => ({
|
32
|
+
zoomIn: () => {
|
33
|
+
setZoom(prevZoom => clamp(prevZoom + 0.2, MIN_ZOOM, MAX_ZOOM));
|
34
|
+
},
|
35
|
+
zoomOut: () => {
|
36
|
+
setZoom(prevZoom => clamp(prevZoom - 0.2, MIN_ZOOM, MAX_ZOOM));
|
37
|
+
},
|
38
|
+
resetZoom: () => {
|
39
|
+
setZoom(1);
|
40
|
+
setOffset({ x: 0, y: 0 });
|
41
|
+
}
|
42
|
+
}), []);
|
43
|
+
|
30
44
|
const handleWheel = (event) => {
|
31
45
|
const { deltaY } = event;
|
32
|
-
if (!
|
46
|
+
if (!dragging) {
|
33
47
|
setZoom((zoom) =>
|
34
48
|
clamp(zoom + deltaY * SCROLL_SENSITIVITY * -1, MIN_ZOOM, MAX_ZOOM)
|
35
49
|
);
|
@@ -37,7 +51,7 @@ export const ImageViewer = ({ image }) => {
|
|
37
51
|
};
|
38
52
|
|
39
53
|
const handleMouseMove = (event) => {
|
40
|
-
if (
|
54
|
+
if (dragging) {
|
41
55
|
const { x, y } = touch.current;
|
42
56
|
const { clientX, clientY } = event;
|
43
57
|
setOffset({
|
@@ -133,7 +147,7 @@ export const ImageViewer = ({ image }) => {
|
|
133
147
|
/>
|
134
148
|
</div>
|
135
149
|
);
|
136
|
-
};
|
150
|
+
});
|
137
151
|
|
138
152
|
|
139
153
|
export default ImageViewer;
|
@@ -1,12 +1,16 @@
|
|
1
1
|
.viewer {
|
2
|
+
position: fixed;
|
3
|
+
top: 0;
|
4
|
+
left: 0;
|
2
5
|
width: 100vw;
|
3
6
|
height: 100vh;
|
4
|
-
background-color: rgba(0, 0, 0, .
|
7
|
+
background-color: rgba(0, 0, 0, .85);
|
5
8
|
display: grid;
|
6
9
|
grid-template-columns: 1fr auto;
|
7
10
|
grid-template-rows: 4rem 1fr;
|
8
11
|
grid-template-areas: "header aside" "main aside";
|
9
12
|
color: #FFF;
|
13
|
+
z-index: 1000;
|
10
14
|
}
|
11
15
|
|
12
16
|
.viewer>header {
|
@@ -34,6 +38,7 @@
|
|
34
38
|
|
35
39
|
.viewer>main>.resizer {
|
36
40
|
width: 100%;
|
41
|
+
height: 100%;
|
37
42
|
overflow: hidden;
|
38
43
|
position: relative;
|
39
44
|
display: flex;
|
@@ -42,9 +47,18 @@
|
|
42
47
|
padding: 1rem;
|
43
48
|
}
|
44
49
|
|
45
|
-
.viewer>main>.resizer
|
50
|
+
.viewer>main>.resizer picture {
|
46
51
|
width: 100%;
|
47
|
-
|
52
|
+
height: 100%;
|
53
|
+
display: flex;
|
54
|
+
justify-content: center;
|
55
|
+
align-items: center;
|
56
|
+
}
|
57
|
+
|
58
|
+
.viewer>main>.resizer img {
|
59
|
+
max-width: 100%;
|
60
|
+
max-height: 100%;
|
61
|
+
object-fit: contain;
|
48
62
|
}
|
49
63
|
|
50
64
|
@media (min-width: 800px) {
|
@@ -56,9 +70,12 @@
|
|
56
70
|
|
57
71
|
.viewer>aside {
|
58
72
|
min-width: 22rem;
|
73
|
+
max-width: 25rem;
|
59
74
|
grid-area: aside;
|
60
75
|
display: none;
|
61
|
-
background-color:
|
76
|
+
background-color: rgba(40, 40, 40, 0.95);
|
77
|
+
backdrop-filter: blur(10px);
|
78
|
+
border-left: 1px solid rgba(255, 255, 255, 0.1);
|
62
79
|
}
|
63
80
|
|
64
81
|
.viewer>aside.open {
|
@@ -67,20 +84,38 @@
|
|
67
84
|
flex-direction: column;
|
68
85
|
}
|
69
86
|
|
87
|
+
.viewer>aside main {
|
88
|
+
flex: 1;
|
89
|
+
overflow-y: auto;
|
90
|
+
padding: 0;
|
91
|
+
}
|
92
|
+
|
70
93
|
.viewer>aside .property>label {
|
71
94
|
color: #AAA;
|
72
95
|
}
|
73
96
|
|
74
97
|
.viewer>footer {
|
75
|
-
width:
|
98
|
+
width: 12rem;
|
76
99
|
position: absolute;
|
77
|
-
bottom:
|
78
|
-
left: calc(50vw -
|
79
|
-
border-radius:
|
100
|
+
bottom: 2rem;
|
101
|
+
left: calc(50vw - 6rem);
|
102
|
+
border-radius: 8px;
|
80
103
|
z-index: 100;
|
81
104
|
display: flex;
|
82
105
|
justify-content: space-between;
|
83
106
|
align-items: center;
|
84
|
-
padding: .
|
85
|
-
background-color: rgba(0, 0, 0, .
|
107
|
+
padding: 0.75rem 1rem;
|
108
|
+
background-color: rgba(0, 0, 0, 0.8);
|
109
|
+
backdrop-filter: blur(10px);
|
110
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
111
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
112
|
+
}
|
113
|
+
|
114
|
+
.viewer>footer .icon {
|
115
|
+
transition: all 0.2s ease;
|
116
|
+
}
|
117
|
+
|
118
|
+
.viewer>footer .icon:hover {
|
119
|
+
transform: scale(1.1);
|
120
|
+
color: #fff;
|
86
121
|
}
|
@@ -3,35 +3,87 @@ import { Icon, Header, Text } from '../../html'
|
|
3
3
|
import { ImageViewer} from '../image/ImageViewer'
|
4
4
|
import './Viewer.css'
|
5
5
|
|
6
|
-
const ViewerTest = (
|
6
|
+
export const ViewerTest = () => {
|
7
|
+
const [showViewer, setShowViewer] = useState(false);
|
8
|
+
|
9
|
+
const sampleInfo = (
|
10
|
+
<div style={{ padding: '1rem' }}>
|
11
|
+
<h3>Sample Image</h3>
|
12
|
+
<p><strong>Size:</strong> 1920x1080</p>
|
13
|
+
<p><strong>Format:</strong> PNG</p>
|
14
|
+
<p><strong>Created:</strong> 2024-01-15</p>
|
15
|
+
</div>
|
16
|
+
);
|
17
|
+
|
18
|
+
const sampleActions = [
|
19
|
+
<Icon key="download" icon="download" clickable title="Download" />,
|
20
|
+
<Icon key="share" icon="share" clickable title="Share" />
|
21
|
+
];
|
22
|
+
|
7
23
|
return (
|
8
|
-
<
|
9
|
-
|
10
|
-
|
24
|
+
<div>
|
25
|
+
<button onClick={() => setShowViewer(true)}>
|
26
|
+
Open Viewer Test
|
27
|
+
</button>
|
28
|
+
{showViewer && (
|
29
|
+
<Viewer
|
30
|
+
title="Sample Image"
|
31
|
+
src="https://concepto.de/wp-content/uploads/2015/03/paisaje-800x409.jpg"
|
32
|
+
info={sampleInfo}
|
33
|
+
actions={sampleActions}
|
34
|
+
tools={true}
|
35
|
+
onClose={() => setShowViewer(false)}
|
36
|
+
/>
|
37
|
+
)}
|
38
|
+
</div>
|
39
|
+
);
|
40
|
+
};
|
11
41
|
|
12
42
|
/**
|
13
43
|
* Viewer
|
14
44
|
*/
|
15
45
|
export const Viewer = ({ title, src, info, actions = [], tools = false, onClose }) => {
|
16
|
-
|
17
|
-
const [
|
46
|
+
const [showDetails, setShowDetails] = useState(false);
|
47
|
+
const [imageViewerRef, setImageViewerRef] = useState(null);
|
18
48
|
|
19
49
|
function toggleDetails() {
|
20
|
-
setShowDetails(!showDetails)
|
50
|
+
setShowDetails(!showDetails);
|
21
51
|
}
|
22
52
|
|
23
|
-
|
53
|
+
function handleZoomIn() {
|
54
|
+
if (imageViewerRef && imageViewerRef.zoomIn) {
|
55
|
+
imageViewerRef.zoomIn();
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
function handleZoomOut() {
|
60
|
+
if (imageViewerRef && imageViewerRef.zoomOut) {
|
61
|
+
imageViewerRef.zoomOut();
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
function handleZoomReset() {
|
66
|
+
if (imageViewerRef && imageViewerRef.resetZoom) {
|
67
|
+
imageViewerRef.resetZoom();
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
const headerTitle = <Text use="headline6">{title}</Text>;
|
72
|
+
|
24
73
|
return (
|
25
74
|
<div className="viewer">
|
26
|
-
<Header icon="view" title={headerTitle}
|
27
|
-
{onClose ? <Icon icon="close" clickable action={onClose} /> : null}
|
28
|
-
{showDetails ? '' : <Icon icon="info" clickable action={toggleDetails} />}
|
75
|
+
<Header icon="view" title={headerTitle}>
|
29
76
|
{actions}
|
77
|
+
{!showDetails && <Icon icon="info" clickable action={toggleDetails} />}
|
78
|
+
{onClose && <Icon icon="close" clickable action={onClose} />}
|
30
79
|
</Header>
|
31
80
|
<main>
|
32
81
|
<div className="resizer">
|
33
82
|
<picture>
|
34
|
-
<ImageViewer
|
83
|
+
<ImageViewer
|
84
|
+
image={src}
|
85
|
+
ref={setImageViewerRef}
|
86
|
+
/>
|
35
87
|
</picture>
|
36
88
|
</div>
|
37
89
|
</main>
|
@@ -43,13 +95,13 @@ export const Viewer = ({ title, src, info, actions = [], tools = false, onClose
|
|
43
95
|
{info}
|
44
96
|
</main>
|
45
97
|
</aside>
|
46
|
-
{tools
|
98
|
+
{tools && (
|
47
99
|
<footer>
|
48
|
-
<Icon clickable icon="zoom_out" />
|
49
|
-
<Icon clickable icon="zoom_out_map" />
|
50
|
-
<Icon clickable icon="zoom_in" />
|
100
|
+
<Icon clickable icon="zoom_out" action={handleZoomOut} />
|
101
|
+
<Icon clickable icon="zoom_out_map" action={handleZoomReset} />
|
102
|
+
<Icon clickable icon="zoom_in" action={handleZoomIn} />
|
51
103
|
</footer>
|
52
|
-
)
|
104
|
+
)}
|
53
105
|
</div>
|
54
|
-
)
|
55
|
-
}
|
106
|
+
);
|
107
|
+
};
|