@san-siva/blogkit 1.1.28 → 1.1.29

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.
@@ -1,4 +1,4 @@
1
- var styles = {"margin-top--1":"Mermaid-module_margin-top--1__W10B7","margin-bottom--2":"Mermaid-module_margin-bottom--2__w3Zct","mermaid":"Mermaid-module_mermaid__02iRo"};
1
+ var styles = {"margin-top--1":"Mermaid-module_margin-top--1__W10B7","margin-bottom--2":"Mermaid-module_margin-bottom--2__w3Zct","mermaid":"Mermaid-module_mermaid__02iRo","mermaid__controls":"Mermaid-module_mermaid__controls__0YNFR","mermaid__controls__btn":"Mermaid-module_mermaid__controls__btn__w04sa","mermaid__viewport":"Mermaid-module_mermaid__viewport__KVL-A","mermaid__viewport--dragging":"Mermaid-module_mermaid__viewport--dragging__WjBzf"};
2
2
 
3
3
  export { styles as default };
4
4
  //# sourceMappingURL=Mermaid.module.scss.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MermaidDynamic.d.ts","sourceRoot":"","sources":["../../../src/dynamicComponents/MermaidDynamic.tsx"],"names":[],"mappings":"AASA,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAmBD,QAAA,MAAM,OAAO,GAAI,2CAKd,iBAAiB,4CAsDnB,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"MermaidDynamic.d.ts","sourceRoot":"","sources":["../../../src/dynamicComponents/MermaidDynamic.tsx"],"names":[],"mappings":"AASA,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAuBD,QAAA,MAAM,OAAO,GAAI,2CAKd,iBAAiB,4CAkMnB,CAAC;AAEF,eAAe,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@san-siva/blogkit",
3
- "version": "1.1.28",
3
+ "version": "1.1.29",
4
4
  "description": "A reusable blog component library for React/Next.js applications with code highlighting, diagrams, and rich content features",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -31,6 +31,10 @@ mermaid.initialize({
31
31
  },
32
32
  });
33
33
 
34
+ const MIN_SCALE = 0.5;
35
+ const MAX_SCALE = 4;
36
+ const ZOOM_STEP = 0.15;
37
+
34
38
  const Mermaid = ({
35
39
  code = '',
36
40
  id = '',
@@ -39,8 +43,33 @@ const Mermaid = ({
39
43
  }: MermaidProperties) => {
40
44
  const [enabled, setEnabled] = useState(false);
41
45
  const [error, setError] = useState<string | null>(null);
46
+ const [transform, setTransform] = useState({ scale: 1, x: 0, y: 0 });
47
+ const [isDragging, setIsDragging] = useState(false);
48
+
42
49
  const mermaidReference = useRef<HTMLDivElement>(null);
50
+ const viewportRef = useRef<HTMLDivElement>(null);
43
51
  const renderCount = useRef(0);
52
+ const transformRef = useRef({ scale: 1, x: 0, y: 0 });
53
+ const isDraggingRef = useRef(false);
54
+ const dragStart = useRef({
55
+ mouseX: 0,
56
+ mouseY: 0,
57
+ transformX: 0,
58
+ transformY: 0,
59
+ });
60
+
61
+ const applyTransform = useCallback(
62
+ (
63
+ updater: (
64
+ prev: typeof transformRef.current
65
+ ) => typeof transformRef.current
66
+ ) => {
67
+ const next = updater(transformRef.current);
68
+ transformRef.current = next;
69
+ setTransform(next);
70
+ },
71
+ []
72
+ );
44
73
 
45
74
  const initializeMermaid = useCallback(async () => {
46
75
  if (!mermaidReference.current || !code) return;
@@ -62,9 +91,90 @@ const Mermaid = ({
62
91
  useEffect(() => {
63
92
  if (!code) return;
64
93
  setError(null);
94
+ applyTransform(() => ({ scale: 1, x: 0, y: 0 }));
65
95
  const timer = setTimeout(initializeMermaid, 100);
66
96
  return () => clearTimeout(timer);
67
- }, [code, initializeMermaid]);
97
+ }, [code, initializeMermaid, applyTransform]);
98
+
99
+ const handleWheel = useCallback(
100
+ (e: WheelEvent) => {
101
+ e.preventDefault();
102
+ const factor = e.deltaY < 0 ? 1 + ZOOM_STEP : 1 - ZOOM_STEP;
103
+ applyTransform(prev => {
104
+ const newScale = Math.min(
105
+ Math.max(prev.scale * factor, MIN_SCALE),
106
+ MAX_SCALE
107
+ );
108
+ if (!viewportRef.current) return { ...prev, scale: newScale };
109
+ const rect = viewportRef.current.getBoundingClientRect();
110
+ const cursorX = e.clientX - rect.left;
111
+ const cursorY = e.clientY - rect.top;
112
+ const ratio = newScale / prev.scale;
113
+ return {
114
+ scale: newScale,
115
+ x: cursorX - (cursorX - prev.x) * ratio,
116
+ y: cursorY - (cursorY - prev.y) * ratio,
117
+ };
118
+ });
119
+ },
120
+ [applyTransform]
121
+ );
122
+
123
+ useEffect(() => {
124
+ const viewport = viewportRef.current;
125
+ if (!viewport || !enabled) return;
126
+ viewport.addEventListener('wheel', handleWheel, { passive: false });
127
+ return () => viewport.removeEventListener('wheel', handleWheel);
128
+ }, [handleWheel, enabled]);
129
+
130
+ const handleMouseDown = useCallback((e: React.MouseEvent) => {
131
+ e.preventDefault();
132
+ isDraggingRef.current = true;
133
+ setIsDragging(true);
134
+ dragStart.current = {
135
+ mouseX: e.clientX,
136
+ mouseY: e.clientY,
137
+ transformX: transformRef.current.x,
138
+ transformY: transformRef.current.y,
139
+ };
140
+ }, []);
141
+
142
+ const handleMouseMove = useCallback(
143
+ (e: React.MouseEvent) => {
144
+ if (!isDraggingRef.current) return;
145
+ applyTransform(prev => ({
146
+ ...prev,
147
+ x:
148
+ dragStart.current.transformX + (e.clientX - dragStart.current.mouseX),
149
+ y:
150
+ dragStart.current.transformY + (e.clientY - dragStart.current.mouseY),
151
+ }));
152
+ },
153
+ [applyTransform]
154
+ );
155
+
156
+ const handleMouseUp = useCallback(() => {
157
+ isDraggingRef.current = false;
158
+ setIsDragging(false);
159
+ }, []);
160
+
161
+ const zoomIn = useCallback(() => {
162
+ applyTransform(prev => ({
163
+ ...prev,
164
+ scale: Math.min(prev.scale * (1 + ZOOM_STEP), MAX_SCALE),
165
+ }));
166
+ }, [applyTransform]);
167
+
168
+ const zoomOut = useCallback(() => {
169
+ applyTransform(prev => ({
170
+ ...prev,
171
+ scale: Math.max(prev.scale * (1 - ZOOM_STEP), MIN_SCALE),
172
+ }));
173
+ }, [applyTransform]);
174
+
175
+ const resetView = useCallback(() => {
176
+ applyTransform(() => ({ scale: 1, x: 0, y: 0 }));
177
+ }, [applyTransform]);
68
178
 
69
179
  return (
70
180
  <div
@@ -82,12 +192,46 @@ const Mermaid = ({
82
192
  <CalloutStatic type="info">
83
193
  <p>Rendering diagram...</p>
84
194
  </CalloutStatic>
85
- ) : null}
195
+ ) : (
196
+ <div className={styles['mermaid__controls']}>
197
+ <button className={styles['mermaid__controls__btn']} onClick={zoomIn}>
198
+ +
199
+ </button>
200
+ <button
201
+ className={styles['mermaid__controls__btn']}
202
+ onClick={zoomOut}
203
+ >
204
+
205
+ </button>
206
+ <button
207
+ className={styles['mermaid__controls__btn']}
208
+ onClick={resetView}
209
+ >
210
+ Reset
211
+ </button>
212
+ </div>
213
+ )}
86
214
  <div
87
- ref={mermaidReference}
88
- id={id}
215
+ ref={viewportRef}
216
+ className={`${styles['mermaid__viewport']} ${
217
+ isDragging ? styles['mermaid__viewport--dragging'] : ''
218
+ }`}
89
219
  style={enabled ? undefined : { display: 'none' }}
90
- />
220
+ onMouseDown={handleMouseDown}
221
+ onMouseMove={handleMouseMove}
222
+ onMouseUp={handleMouseUp}
223
+ onMouseLeave={handleMouseUp}
224
+ >
225
+ <div
226
+ style={{
227
+ transform: `translate(${transform.x}px, ${transform.y}px) scale(${transform.scale})`,
228
+ transformOrigin: '0 0',
229
+ transition: isDragging ? 'none' : 'transform 0.1s ease',
230
+ }}
231
+ >
232
+ <div ref={mermaidReference} id={id} />
233
+ </div>
234
+ </div>
91
235
  </div>
92
236
  );
93
237
  };
@@ -6,12 +6,54 @@
6
6
  > * {
7
7
  background-color: unset;
8
8
  }
9
+
10
+ &__controls {
11
+ display: flex;
12
+ flex-direction: row;
13
+ gap: styles.rem(4);
14
+ justify-content: flex-end;
15
+ margin-bottom: styles.rem(6);
16
+ opacity: 0;
17
+
18
+ &__btn {
19
+ background: none;
20
+ border: 1px solid styles.$color--grey-medium;
21
+ color: styles.$color--dark;
22
+ cursor: pointer;
23
+ font-size: styles.$font-size--very-small;
24
+ font-weight: styles.$font-weight--500;
25
+ line-height: 1;
26
+ padding: styles.rem(4) styles.rem(8);
27
+ border-radius: styles.rem(2);
28
+
29
+ &:hover {
30
+ background-color: rgba(0, 0, 0, 0.05);
31
+ }
32
+ }
33
+ }
34
+
35
+ &__viewport {
36
+ overflow: hidden;
37
+ cursor: grab;
38
+ user-select: none;
39
+ -webkit-user-select: none;
40
+
41
+ &--dragging {
42
+ cursor: grabbing;
43
+ }
44
+ }
45
+
46
+ &:hover {
47
+ .mermaid__controls {
48
+ opacity: 1;
49
+ }
50
+ }
9
51
  }
10
52
 
11
53
  .margin-top--1 {
12
- margin-top: styles.space(1);
54
+ margin-top: styles.space(1);
13
55
  }
14
56
 
15
57
  .margin-bottom--2 {
16
- margin-bottom: styles.space(2);
58
+ margin-bottom: styles.space(2);
17
59
  }
@@ -1,5 +1,9 @@
1
1
  declare const styles: {
2
2
  readonly mermaid: string;
3
+ readonly 'mermaid__controls': string;
4
+ readonly 'mermaid__controls__btn': string;
5
+ readonly 'mermaid__viewport': string;
6
+ readonly 'mermaid__viewport--dragging': string;
3
7
  readonly 'margin-top--1': string;
4
8
  readonly 'margin-bottom--2': string;
5
9
  };