ywana-core8 0.2.14 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ywana-core8",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "ywana-core8",
5
5
  "homepage": "https://ywana.github.io/workspace",
6
6
  "author": "Ernesto Roldan Garcia",
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 [draggind, setDragging] = useState(false);
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 (!draggind) {
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 (draggind) {
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, .75);
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 img {
50
+ .viewer>main>.resizer picture {
46
51
  width: 100%;
47
- object-fit: fill;
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: rgb(50, 50, 50);
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: 15rem;
98
+ width: 12rem;
76
99
  position: absolute;
77
- bottom: 1rem;
78
- left: calc(50vw - 4rem);
79
- border-radius: 3px;
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: .5rem;
85
- background-color: rgba(0, 0, 0, .75);
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 = (props) => {
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
- <Viewer src="https://pro.ywanadigital.com/files/2023/63bc36a840364cdd0b4c6670/63bc38f740364cdd0b4c6671/original/52905_TECNOLOG_A%20DICIEMBRE%20II%2043X199_Cart_n_Microcanal%20sencillo_43x199_es_A_1r5v-0.png" />
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 [showDetails, setShowDetails] = useState(false)
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
- const headerTitle = <Text use="headline6">{title}</Text>
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 image={src} />
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
- ) : null }
104
+ )}
53
105
  </div>
54
- )
55
- }
106
+ );
107
+ };