@widgetic/editor 4.0.4 → 4.0.6

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.
@@ -63,6 +63,11 @@
63
63
  export let enableDrag: boolean = false;
64
64
  /** W×H number inputs in the chrome header, live-synced with resize. */
65
65
  export let showDimensionInputs: boolean = false;
66
+ /**
67
+ * concentric — always resize from center (widget-creator / Canvas).
68
+ * corner — opposite corner fixed; hold Alt for concentric (composition page).
69
+ */
70
+ export let resizeMode: 'concentric' | 'corner' = 'concentric';
66
71
  /** Initial / reset placement inside the stage. */
67
72
  export let defaultStageAlign: 'center' | 'right-half' = 'center';
68
73
  /** Observe stage size and fill it (desktop modal) */
@@ -102,7 +107,8 @@
102
107
  const PREVIEW_STROKE_ALT = '#f97316';
103
108
  let isResizing = false;
104
109
  let isDraggingPreview = false;
105
- let isSymmetricalResize = false;
110
+ /** Alt held — keeps orange stroke on composition even after pointerup. */
111
+ let isAltKeyDown = false;
106
112
  let previewShellLeft = 0;
107
113
  let previewShellTop = 0;
108
114
  let previewPositionReady = false;
@@ -116,7 +122,8 @@
116
122
  $: chromeHeaderHeight = showPreviewChrome ? PREVIEW_CHROME_HEADER_H : 0;
117
123
  $: if (resizeWidth != null) widthInputValue = String(Math.round(resizeWidth));
118
124
  $: if (resizeHeight != null) heightInputValue = String(Math.round(resizeHeight));
119
- $: previewStrokeColor = isSymmetricalResize ? PREVIEW_STROKE_ALT : PREVIEW_STROKE;
125
+ $: showSymmetricalStroke = resizeMode === 'corner' && isAltKeyDown;
126
+ $: previewStrokeColor = showSymmetricalStroke ? PREVIEW_STROKE_ALT : PREVIEW_STROKE;
120
127
 
121
128
  export function getResizeLimits(): { maxWidth: number; maxHeight: number } {
122
129
  const stageEl = resizeStageEl ?? contentContainerEl;
@@ -275,7 +282,7 @@
275
282
  iframeEl.style.height = '';
276
283
  }
277
284
 
278
- /** Fill the available preview stage (e.g. desktop modal) */
285
+ /** Fill the available preview stage (e.g. desktop modal) and re-center. */
279
286
  export function fitToContainer(): void {
280
287
  const attemptFit = (attemptsLeft: number) => {
281
288
  const stageEl = resizeStageEl ?? contentContainerEl;
@@ -289,7 +296,11 @@
289
296
  resizeWidth = limits.maxWidth;
290
297
  resizeHeight = limits.maxHeight;
291
298
  dispatch('resize', { width: limits.maxWidth, height: limits.maxHeight });
292
- requestAnimationFrame(() => nudgeIframePaint());
299
+ previewPositionReady = false;
300
+ requestAnimationFrame(() => {
301
+ resetPreviewPosition();
302
+ nudgeIframePaint();
303
+ });
293
304
  };
294
305
  attemptFit(24);
295
306
  }
@@ -612,7 +623,7 @@
612
623
  event.preventDefault();
613
624
  event.stopPropagation();
614
625
  isResizing = true;
615
- isSymmetricalResize = event.altKey;
626
+ if (event.altKey) isAltKeyDown = true;
616
627
  const startX = event.clientX;
617
628
  const startY = event.clientY;
618
629
  const startLeft = previewShellLeft;
@@ -620,14 +631,15 @@
620
631
  const { maxWidth, maxHeight } = getResizeLimits();
621
632
  const startWidth = resizeWidth ?? maxWidth;
622
633
  const startHeight = resizeHeight ?? maxHeight;
634
+ const alwaysConcentric = resizeMode === 'concentric';
623
635
 
624
636
  function onPointerMove(e: PointerEvent) {
625
- const useAlt = e.altKey;
626
- isSymmetricalResize = useAlt;
637
+ if (e.altKey) isAltKeyDown = true;
638
+ const useConcentric = alwaysConcentric || isAltKeyDown || e.altKey;
627
639
  const dx = e.clientX - startX;
628
640
  const dy = e.clientY - startY;
629
641
 
630
- if (useAlt) {
642
+ if (useConcentric) {
631
643
  const deltaW = signX !== 0 ? dx * signX * 2 : 0;
632
644
  const deltaH = signY !== 0 ? dy * signY * 2 : 0;
633
645
  const nextW = clampDimension(startWidth + deltaW, MIN_WIDTH, maxWidth);
@@ -669,7 +681,7 @@
669
681
 
670
682
  function endResize() {
671
683
  isResizing = false;
672
- isSymmetricalResize = false;
684
+ // Keep orange stroke while Alt remains held (composition corner mode).
673
685
  document.removeEventListener('pointermove', onPointerMove);
674
686
  document.removeEventListener('pointerup', endResize);
675
687
  document.removeEventListener('pointercancel', endResize);
@@ -711,16 +723,25 @@
711
723
  onMount(() => {
712
724
  window.addEventListener('message', handleMessage);
713
725
  const onAltDown = (e: KeyboardEvent) => {
714
- if (e.key === 'Alt') isSymmetricalResize = true;
726
+ if (e.key === 'Alt' || e.code === 'AltLeft' || e.code === 'AltRight') {
727
+ isAltKeyDown = true;
728
+ }
715
729
  };
716
730
  const onAltUp = (e: KeyboardEvent) => {
717
- if (e.key === 'Alt' && !isResizing) isSymmetricalResize = false;
731
+ if (e.key === 'Alt' || e.code === 'AltLeft' || e.code === 'AltRight') {
732
+ isAltKeyDown = false;
733
+ }
734
+ };
735
+ const onWindowBlur = () => {
736
+ isAltKeyDown = false;
718
737
  };
719
738
  window.addEventListener('keydown', onAltDown);
720
739
  window.addEventListener('keyup', onAltUp);
740
+ window.addEventListener('blur', onWindowBlur);
721
741
  return () => {
722
742
  window.removeEventListener('keydown', onAltDown);
723
743
  window.removeEventListener('keyup', onAltUp);
744
+ window.removeEventListener('blur', onWindowBlur);
724
745
  };
725
746
  });
726
747
 
@@ -839,7 +860,7 @@
839
860
  >
840
861
  <div
841
862
  class="preview-iframe-shell relative flex flex-col {enableResize ? 'preview-iframe-shell-positioned' : ''}"
842
- class:preview-iframe-shell-symmetrical={isSymmetricalResize}
863
+ class:preview-iframe-shell-symmetrical={showSymmetricalStroke}
843
864
  style="{enableResize
844
865
  ? `position: absolute; left: ${previewShellLeft}px; top: ${previewShellTop}px; width: ${resizeWidth ? resizeWidth + 'px' : '100%'};`
845
866
  : `width: ${resizeWidth ? resizeWidth + 'px' : '100%'}; height: ${resizeHeight ? resizeHeight + 'px' : '100%'};`} transition: {isResizing || isDraggingPreview ? 'none' : 'width 0.2s, height 0.2s, left 0.15s, top 0.15s'};"
@@ -904,14 +925,6 @@
904
925
  <div class="preview-resize-handle preview-resize-handle-bl" onpointerdown={(e) => startResize(e, -1, 1)}></div>
905
926
  <!-- svelte-ignore a11y-no-static-element-interactions -->
906
927
  <div class="preview-resize-handle preview-resize-handle-br" onpointerdown={(e) => startResize(e, 1, 1)}></div>
907
- <!-- svelte-ignore a11y-no-static-element-interactions -->
908
- <div class="preview-resize-handle preview-resize-handle-t" onpointerdown={(e) => startResize(e, 0, -1)}></div>
909
- <!-- svelte-ignore a11y-no-static-element-interactions -->
910
- <div class="preview-resize-handle preview-resize-handle-r" onpointerdown={(e) => startResize(e, 1, 0)}></div>
911
- <!-- svelte-ignore a11y-no-static-element-interactions -->
912
- <div class="preview-resize-handle preview-resize-handle-b" onpointerdown={(e) => startResize(e, 0, 1)}></div>
913
- <!-- svelte-ignore a11y-no-static-element-interactions -->
914
- <div class="preview-resize-handle preview-resize-handle-l" onpointerdown={(e) => startResize(e, -1, 0)}></div>
915
928
  {/if}
916
929
 
917
930
  {#if (resizeWidth || resizeHeight) && !showDimensionInputs}
@@ -1090,10 +1103,6 @@
1090
1103
  .preview-resize-handle-tr { top: -5px; right: -5px; cursor: nesw-resize; }
1091
1104
  .preview-resize-handle-bl { bottom: -5px; left: -5px; cursor: nesw-resize; }
1092
1105
  .preview-resize-handle-br { bottom: -5px; right: -5px; cursor: nwse-resize; }
1093
- .preview-resize-handle-t { top: -5px; left: 50%; margin-left: -5px; cursor: ns-resize; }
1094
- .preview-resize-handle-b { bottom: -5px; left: 50%; margin-left: -5px; cursor: ns-resize; }
1095
- .preview-resize-handle-l { left: -5px; top: 50%; margin-top: -5px; cursor: ew-resize; }
1096
- .preview-resize-handle-r { right: -5px; top: 50%; margin-top: -5px; cursor: ew-resize; }
1097
1106
 
1098
1107
  .preview-resize-handle:hover {
1099
1108
  background: #eff6ff;
@@ -45,6 +45,10 @@ declare const WidgetPreview: $$__sveltets_2_IsomorphicComponent<{
45
45
  enableResize?: boolean;
46
46
  /** Drag only via the preview chrome header (keeps iframe interactive). */ enableDrag?: boolean;
47
47
  /** W×H number inputs in the chrome header, live-synced with resize. */ showDimensionInputs?: boolean;
48
+ /**
49
+ * concentric — always resize from center (widget-creator / Canvas).
50
+ * corner — opposite corner fixed; hold Alt for concentric (composition page).
51
+ */ resizeMode?: "concentric" | "corner";
48
52
  /** Initial / reset placement inside the stage. */ defaultStageAlign?: "center" | "right-half";
49
53
  /** Observe stage size and fill it (desktop modal) */ autoFitStage?: boolean;
50
54
  /** No padding/border on preview-content-container — matches widget-creator Edit panel */ compactChrome?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widgetic/editor",
3
- "version": "4.0.4",
3
+ "version": "4.0.6",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -116,7 +116,6 @@
116
116
  "dotenv": "^16.4.5",
117
117
  "fontfaceobserver": "^2.3.0",
118
118
  "lowlight": "^3.1.0",
119
- "lucide-svelte": "^0.546.0",
120
119
  "svelte": "^5.27.0",
121
120
  "svelte-awesome-color-picker": "^3.1.4",
122
121
  "svelte-color-select": "^0.0.14",