tokimeki-image-editor 0.2.3 → 0.2.4

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.
@@ -15,10 +15,11 @@ const colorPresets = ['#FF6B6B', '#FFA94D', '#FFD93D', '#6BCB77', '#4D96FF', '#9
15
15
  // Drawing state
16
16
  let isDrawing = $state(false);
17
17
  let currentAnnotation = $state(null);
18
- // Panning state (Space + drag)
18
+ // Panning state (Space + drag on desktop, 2-finger drag on mobile)
19
19
  let isSpaceHeld = $state(false);
20
20
  let isPanning = $state(false);
21
21
  let panStart = $state(null);
22
+ let isTwoFingerTouch = $state(false);
22
23
  // Helper to get coordinates from mouse or touch event
23
24
  function getEventCoords(event) {
24
25
  if ('touches' in event && event.touches.length > 0) {
@@ -289,12 +290,79 @@ function pointToSegmentDistance(px, py, a, b) {
289
290
  function handleClearAll() {
290
291
  onUpdate([]);
291
292
  }
292
- const handleTouchStart = handleMouseDown;
293
- const handleTouchMove = handleMouseMove;
293
+ function handleTouchStart(event) {
294
+ // Two-finger touch starts panning
295
+ if (event.touches.length === 2) {
296
+ event.preventDefault();
297
+ isTwoFingerTouch = true;
298
+ // Use the midpoint of the two touches
299
+ const touch1 = event.touches[0];
300
+ const touch2 = event.touches[1];
301
+ const midX = (touch1.clientX + touch2.clientX) / 2;
302
+ const midY = (touch1.clientY + touch2.clientY) / 2;
303
+ // Cancel any current drawing
304
+ if (isDrawing) {
305
+ isDrawing = false;
306
+ currentAnnotation = null;
307
+ }
308
+ isPanning = true;
309
+ panStart = {
310
+ x: midX,
311
+ y: midY,
312
+ offsetX: viewport.offsetX,
313
+ offsetY: viewport.offsetY
314
+ };
315
+ return;
316
+ }
317
+ // Single finger - normal drawing (only if not already in two-finger mode)
318
+ if (event.touches.length === 1 && !isTwoFingerTouch) {
319
+ handleMouseDown(event);
320
+ }
321
+ }
322
+ function handleTouchMove(event) {
323
+ // Two-finger panning
324
+ if (event.touches.length === 2 && isPanning && panStart && onViewportChange) {
325
+ event.preventDefault();
326
+ const touch1 = event.touches[0];
327
+ const touch2 = event.touches[1];
328
+ const midX = (touch1.clientX + touch2.clientX) / 2;
329
+ const midY = (touch1.clientY + touch2.clientY) / 2;
330
+ const dx = midX - panStart.x;
331
+ const dy = midY - panStart.y;
332
+ onViewportChange({
333
+ offsetX: panStart.offsetX + dx,
334
+ offsetY: panStart.offsetY + dy
335
+ });
336
+ return;
337
+ }
338
+ // Single finger drawing (only if not in two-finger mode)
339
+ if (event.touches.length === 1 && !isTwoFingerTouch) {
340
+ handleMouseMove(event);
341
+ }
342
+ }
294
343
  function handleTouchEnd(event) {
344
+ // When all fingers are lifted
295
345
  if (event.touches.length === 0) {
346
+ if (isPanning) {
347
+ isPanning = false;
348
+ panStart = null;
349
+ }
350
+ isTwoFingerTouch = false;
296
351
  handleMouseUp();
297
352
  }
353
+ // When going from 2 fingers to 1, stay in pan mode but don't draw
354
+ else if (event.touches.length === 1 && isTwoFingerTouch) {
355
+ // Update pan start to the remaining finger position
356
+ if (isPanning && onViewportChange) {
357
+ const touch = event.touches[0];
358
+ panStart = {
359
+ x: touch.clientX,
360
+ y: touch.clientY,
361
+ offsetX: viewport.offsetX,
362
+ offsetY: viewport.offsetY
363
+ };
364
+ }
365
+ }
298
366
  }
299
367
  // Generate smooth SVG path using quadratic bezier curves
300
368
  function generateSmoothPath(points) {
@@ -350,7 +418,7 @@ let currentAnnotationCanvas = $derived.by(() => {
350
418
  <div
351
419
  bind:this={containerElement}
352
420
  class="annotation-tool-overlay"
353
- class:panning={isSpaceHeld}
421
+ class:panning={isSpaceHeld || isTwoFingerTouch}
354
422
  onmousedown={handleMouseDown}
355
423
  role="button"
356
424
  tabindex="-1"
@@ -103,7 +103,7 @@ function handleSheetDragEnd() {
103
103
 
104
104
  @media (max-width: 767px) {
105
105
  .tool-panel {
106
- position: absolute;
106
+ position: fixed;
107
107
  left: 0;
108
108
  right: 0;
109
109
  top: auto;
@@ -112,10 +112,11 @@ function handleSheetDragEnd() {
112
112
  min-width: auto;
113
113
  height: var(--sheet-max-height, 400px);
114
114
  border-radius: 16px 16px 0 0;
115
- z-index: 1001;
115
+ z-index: 9999;
116
116
  overflow-y: auto;
117
117
  overscroll-behavior: contain;
118
118
  padding-top: 0;
119
+ padding-bottom: 1.5rem;
119
120
  transform: translateY(var(--sheet-offset, 0px));
120
121
  will-change: transform;
121
122
  backdrop-filter: none
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokimeki-image-editor",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "A image editor for svelte.",
5
5
  "type": "module",
6
6
  "license": "MIT",