@widgetic/creator 0.3.58 → 0.3.60

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.
@@ -763,7 +763,11 @@
763
763
  }
764
764
  let showPreviewModal = false;
765
765
  let previewModalRef: HTMLDivElement | null = null;
766
- let widgetPreviewComponentRef: { getResizeLimits?: () => { maxWidth: number; maxHeight: number }; fitToContainer?: () => void } | undefined;
766
+ let widgetPreviewComponentRef: {
767
+ getResizeLimits?: () => { maxWidth: number; maxHeight: number };
768
+ fitToContainer?: () => void;
769
+ resetPreviewPosition?: () => void;
770
+ } | undefined;
767
771
  let previewIframe: HTMLIFrameElement | null = null;
768
772
  let isLoadingDirectPreviewUrl = false;
769
773
  let previewFetchRetryCount = 0;
@@ -925,27 +929,18 @@
925
929
  const LEFT_COL_MAX_PERCENT = 62;
926
930
  const COL_RESIZER_PX = 10;
927
931
  const PREVIEW_COL_MIN_PX = 420;
928
- /** Chat-first layout: preview column starts collapsed and opens on generate. */
932
+ /** Chat-first: panel preview column is hidden (W3 canvas live preview is primary). */
933
+ const SHOW_PANEL_PREVIEW_COLUMN = false;
934
+ /** Chat-first layout: preview column stays collapsed until the user opens it (W3 canvas shows live preview). */
929
935
  let previewColumnCollapsed = true;
930
936
  let lastAutoExpandForGenerating = false;
931
937
  let widthBeforePreviewExpand = 0;
932
- $: if (isGeneratingCode && !lastAutoExpandForGenerating) {
933
- lastAutoExpandForGenerating = true;
934
- if (previewColumnCollapsed) expandPreviewColumn();
935
- }
938
+ // Do not auto-expand the right preview column — canvas WidgetShape iframes are the live preview.
936
939
  $: if (!isGeneratingCode) {
937
940
  lastAutoExpandForGenerating = false;
938
941
  }
939
- /** Open the live preview column once when this widget already has code (or a loaded iframe). */
940
- $: if (
941
- showWidgetDetails
942
- && !isDraftConvertPanel
943
- && previewColumnCollapsed
944
- && !hasAutoOpenedPreview
945
- && (hasWidgetCode || !!iframeSrc)
946
- ) {
947
- hasAutoOpenedPreview = true;
948
- expandPreviewColumn();
942
+ $: if (!SHOW_PANEL_PREVIEW_COLUMN) {
943
+ previewColumnCollapsed = true;
949
944
  }
950
945
 
951
946
  function maxLeftColPercent(): number {
@@ -974,6 +969,7 @@
974
969
  }
975
970
 
976
971
  function expandPreviewColumn() {
972
+ if (!SHOW_PANEL_PREVIEW_COLUMN) return;
977
973
  if (!previewColumnCollapsed) return;
978
974
  previewColumnCollapsed = false;
979
975
  leftColPercent = clampLeftColPercent(LEFT_COL_DEFAULT_PERCENT);
@@ -982,7 +978,25 @@
982
978
  detailsPanelX = Math.max(8, window.innerWidth - 8 - detailsPanelWidth);
983
979
  }
984
980
  console.log('[WidgetDetails] Open Preview — panel width', detailsPanelWidth);
985
- tick().then(() => requestAnimationFrame(() => fitPreviewToArea()));
981
+ tick().then(() => requestAnimationFrame(async () => {
982
+ // Load panel preview only when the user opens the column (avoid wasted Worker/CDN requests).
983
+ if (selectedWidgetId && !iframeSrc && !showPreviewModal) {
984
+ try {
985
+ if (await loadPublishedPreviewForCurrentStep()) {
986
+ fitPreviewToArea();
987
+ return;
988
+ }
989
+ if (lastCommitId || lastPublishedVersion !== null || normalizeRepositoryId(selectedWidget) || currentRepositoryId) {
990
+ previewLoading = true;
991
+ await runPreviewLoadPipeline(selectedWidgetId);
992
+ previewLoadedForWidgetId = selectedWidgetId;
993
+ }
994
+ } catch (err) {
995
+ console.warn('[WidgetDetails] Deferred preview load on expand failed', err);
996
+ }
997
+ }
998
+ fitPreviewToArea();
999
+ }));
986
1000
  }
987
1001
 
988
1002
  let detailsPanelX = -1;
@@ -1256,6 +1270,14 @@
1256
1270
  return;
1257
1271
  }
1258
1272
 
1273
+ // Chat-first: skip panel Worker/CDN preview while the right column is closed (W3 canvas overlays handle live view).
1274
+ if (previewColumnCollapsed && !showPreviewModal) {
1275
+ previewLoading = false;
1276
+ previewError = null;
1277
+ console.log('[WidgetDetails] Preview column collapsed — skipping panel preview network');
1278
+ return;
1279
+ }
1280
+
1259
1281
  if (await loadPublishedPreviewForCurrentStep()) {
1260
1282
  return;
1261
1283
  }
@@ -2019,7 +2041,8 @@
2019
2041
  stopPreviewTokenAutoRefresh();
2020
2042
  // console.log('[TokenAutoRefresh] Started - checking every', TOKEN_CHECK_INTERVAL_MS / 1000, 'seconds');
2021
2043
  previewTokenRefreshInterval = setInterval(async () => {
2022
- const isPreviewVisible = showPreviewModal || (showWidgetDetails && inlinePanelView === 'preview');
2044
+ const isPreviewVisible = showPreviewModal
2045
+ || (showWidgetDetails && !previewColumnCollapsed && inlinePanelView === 'preview');
2023
2046
  if (!isPreviewVisible || !lastPreviewUrlFetchTime || !directPreviewUrl) return;
2024
2047
  const tokenAge = Date.now() - lastPreviewUrlFetchTime;
2025
2048
  if (tokenAge >= PREVIEW_TOKEN_REFRESH_MS) {
@@ -2536,7 +2559,9 @@
2536
2559
  );
2537
2560
  return;
2538
2561
  }
2539
- detailsPanelWidth = clampPanelWidth(DETAILS_PANEL_DEFAULT_WIDTH);
2562
+ detailsPanelWidth = clampPanelWidth(
2563
+ previewColumnCollapsed ? DETAILS_PANEL_MIN_WIDTH : DETAILS_PANEL_DEFAULT_WIDTH
2564
+ );
2540
2565
  detailsPanelHeight = getDefaultDetailsPanelHeight();
2541
2566
  }
2542
2567
 
@@ -2583,7 +2608,8 @@
2583
2608
  }
2584
2609
 
2585
2610
  /**
2586
- * Center Widget Details in the canvas viewport (X and Y), clamped on-screen.
2611
+ * Park the panel beside a canvas widget shape: right if the shape is left of
2612
+ * viewport center, otherwise left. Chat-first width when preview is collapsed.
2587
2613
  */
2588
2614
  export function positionBesideShape(shapeRect: {
2589
2615
  left: number;
@@ -2596,32 +2622,55 @@
2596
2622
  viewportHeight: number;
2597
2623
  } | null): void {
2598
2624
  if (typeof window === 'undefined') return;
2625
+ previewColumnCollapsed = true;
2599
2626
  resetDetailsPanelSize();
2600
2627
  _hasBeenOpenedOnce = true;
2601
2628
  if (!shapeRect) {
2602
2629
  centerDetailsPanel();
2603
- // console.log('[WidgetDetails] No shape rect — centered floating panel', detailsPanelWidth, detailsPanelHeight);
2630
+ console.log('[WidgetDetails] No shape rect — centered floating panel', detailsPanelWidth, detailsPanelHeight);
2604
2631
  return;
2605
2632
  }
2606
2633
 
2607
- detailsPanelWidth = clampPanelWidth(DETAILS_PANEL_DEFAULT_WIDTH);
2608
- detailsPanelHeight = clampPanelHeight(DETAILS_PANEL_MAX_HEIGHT);
2634
+ const pad = 8;
2635
+ const viewLeft = shapeRect.viewportLeft;
2636
+ const viewRight = shapeRect.viewportLeft + shapeRect.viewportWidth;
2637
+ const availableWidth = Math.max(DETAILS_PANEL_MIN_WIDTH, shapeRect.viewportWidth - pad * 2);
2638
+ detailsPanelWidth = clampPanelWidth(
2639
+ previewColumnCollapsed
2640
+ ? DETAILS_PANEL_MIN_WIDTH
2641
+ : Math.min(DETAILS_PANEL_MAX_WIDTH, availableWidth)
2642
+ );
2643
+ detailsPanelHeight = clampPanelHeight(
2644
+ Math.min(DETAILS_PANEL_MAX_HEIGHT, shapeRect.viewportHeight - pad * 2),
2645
+ );
2609
2646
 
2610
- const viewportLeft = shapeRect.viewportLeft ?? 0;
2611
- const viewportWidth = shapeRect.viewportWidth || window.innerWidth;
2612
- const viewportTop = shapeRect.viewportTop ?? detailsPanelTopOffset;
2613
- const viewportHeight = shapeRect.viewportHeight || (window.innerHeight - viewportTop);
2647
+ const shapeCenterX = shapeRect.left + shapeRect.width / 2;
2648
+ const viewCenterX = shapeRect.viewportLeft + shapeRect.viewportWidth / 2;
2649
+ const openOnRight = shapeCenterX < viewCenterX;
2650
+ if (openOnRight) {
2651
+ detailsPanelX = shapeRect.left + shapeRect.width + DETAILS_PANEL_SHAPE_GAP;
2652
+ if (detailsPanelX + detailsPanelWidth > viewRight - pad) {
2653
+ detailsPanelX = Math.max(viewLeft + pad, viewRight - pad - detailsPanelWidth);
2654
+ }
2655
+ } else {
2656
+ detailsPanelX = shapeRect.left - DETAILS_PANEL_SHAPE_GAP - detailsPanelWidth;
2657
+ if (detailsPanelX < viewLeft + pad) {
2658
+ detailsPanelX = viewLeft + pad;
2659
+ }
2660
+ }
2614
2661
 
2615
- const x = Math.round(viewportLeft + (viewportWidth - detailsPanelWidth) / 2);
2616
- const y = Math.round(viewportTop + Math.max(0, (viewportHeight - detailsPanelHeight) / 2));
2617
- const pos = clampDetailsPanelPosition(x, y);
2618
- detailsPanelX = pos.x;
2619
- detailsPanelY = pos.y;
2620
- console.log('[WidgetDetails] Centered in canvas viewport', {
2662
+ const maxY = window.innerHeight - detailsPanelHeight - pad;
2663
+ detailsPanelY = Math.min(
2664
+ maxY,
2665
+ Math.max(detailsPanelTopOffset, shapeRect.top),
2666
+ );
2667
+ console.log('[WidgetDetails] Positioned beside shape', {
2668
+ openOnRight,
2621
2669
  x: Math.round(detailsPanelX),
2622
2670
  y: Math.round(detailsPanelY),
2623
2671
  w: detailsPanelWidth,
2624
2672
  h: detailsPanelHeight,
2673
+ previewCollapsed: previewColumnCollapsed,
2625
2674
  });
2626
2675
  }
2627
2676
 
@@ -2668,6 +2717,8 @@
2668
2717
  let _hasBeenOpenedOnce = false;
2669
2718
  export function openWidgetDetails() {
2670
2719
  if (showWidgetDetails) return;
2720
+ previewColumnCollapsed = true;
2721
+ hasAutoOpenedPreview = false;
2671
2722
  resetDetailsPanelSize();
2672
2723
  if (fillViewport || (!_hasBeenOpenedOnce && (detailsPanelX < 0 || detailsPanelY < 0))) {
2673
2724
  centerDetailsPanel();
@@ -2676,7 +2727,7 @@
2676
2727
  showWidgetDetails = true;
2677
2728
  dispatch('widgetDetailsToggle', { open: true });
2678
2729
 
2679
- // Clamp preview after DOM is laid out
2730
+ // Clamp preview after DOM is laid out (no-op while column collapsed)
2680
2731
  tick().then(() => {
2681
2732
  requestAnimationFrame(() => {
2682
2733
  fitPreviewToArea();
@@ -2959,6 +3010,7 @@
2959
3010
  /** Expand preview to fill the available panel (fit-to-area). */
2960
3011
  function fitPreviewToArea() {
2961
3012
  widgetPreviewComponentRef?.fitToContainer?.();
3013
+ widgetPreviewComponentRef?.resetPreviewPosition?.();
2962
3014
  }
2963
3015
 
2964
3016
  // Clamp preview to available stage inside WidgetPreview (handles + dimension badge padding)
@@ -3064,8 +3116,8 @@
3064
3116
  previewLoading = false;
3065
3117
  }
3066
3118
 
3067
- // Stop token auto-refresh when no preview is visible
3068
- $: if (!showPreviewModal && !(showWidgetDetails && inlinePanelView === 'preview')) {
3119
+ // Stop token auto-refresh when no preview is visible (collapsed column counts as hidden)
3120
+ $: if (!showPreviewModal && !(showWidgetDetails && !previewColumnCollapsed && inlinePanelView === 'preview')) {
3069
3121
  stopPreviewTokenAutoRefresh();
3070
3122
  }
3071
3123
 
@@ -3444,9 +3496,16 @@
3444
3496
  {/if}
3445
3497
 
3446
3498
  <div
3447
- class="widget-details-debug-buttons relative z-[1] ml-auto flex items-center shrink-0"
3499
+ class="widget-details-header-actions relative z-[1] ml-auto flex items-center gap-2 shrink-0"
3448
3500
  bind:this={widgetDetailsDebugButtonsEl}
3449
3501
  >
3502
+ <div class="widget-details-header-meta flex items-center gap-2 shrink-0 min-w-0">
3503
+ <slot name="header-meta" />
3504
+ <div class="widget-info-version-history-slot relative z-20 shrink-0">
3505
+ <slot name="version-history" />
3506
+ </div>
3507
+ </div>
3508
+ {#if SHOW_PANEL_PREVIEW_COLUMN}
3450
3509
  <HoverTooltip text={previewColumnCollapsed ? 'Open live preview' : 'Close live preview'}>
3451
3510
  <button
3452
3511
  type="button"
@@ -3474,12 +3533,13 @@
3474
3533
  {/if}
3475
3534
  </button>
3476
3535
  </HoverTooltip>
3536
+ {/if}
3477
3537
  </div>
3478
3538
  </div>
3479
3539
  </div>
3480
3540
 
3481
3541
  <!-- Widget Details Content: Two-column layout -->
3482
- <div class="widget-details-content-wrapper relative m-2.5 min-w-[460px] min-h-0 flex-1 overflow-hidden">
3542
+ <div class="widget-details-content-wrapper relative m-0 min-w-[460px] min-h-0 flex-1 overflow-hidden">
3483
3543
  <div class="widget-details-two-col flex h-full min-h-0 min-w-[460px] gap-0 overflow-hidden">
3484
3544
 
3485
3545
  <!-- ═══ LEFT COLUMN: Step Content (scrollable) ═══ -->
@@ -3487,43 +3547,13 @@
3487
3547
  class="widget-details-left-col flex flex-col min-w-[460px] min-h-0 overflow-hidden relative"
3488
3548
  style="width: {previewColumnCollapsed ? 100 : leftColPercent}%; flex: 0 0 {previewColumnCollapsed ? 100 : leftColPercent}%;"
3489
3549
  >
3490
- <div class="widget-details-left-border absolute inset-y-0 left-0 right-0 border border-gray-300 rounded-lg pointer-events-none z-10"></div>
3550
+ <div class="widget-details-left-border absolute inset-y-0 left-0 right-0 border border-gray-300 rounded-none pointer-events-none z-10"></div>
3491
3551
 
3492
3552
  {#if selectedWidgetId}
3493
3553
  <div class="widget-details-left-stack relative z-0 flex flex-col h-full min-h-0 min-w-[460px] overflow-hidden">
3494
- <!-- Sticky Widget Info Bar (always visible above scrollable content) -->
3495
- <div class="widget-info-sticky-bar relative flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 rounded-t-lg shrink-0 gap-2 min-w-0 z-20 overflow-visible">
3496
- <div class="widget-info-name flex items-center min-w-0 gap-1 text-sm text-gray-700">
3497
- <!-- svelte-ignore a11y-click-events-have-key-events -->
3498
- <!-- svelte-ignore a11y-no-static-element-interactions -->
3499
- <span
3500
- class="widget-id-label text-[11px] font-mono text-gray-500 cursor-pointer hover:text-gray-700 truncate"
3501
- title="Click to copy widget ID"
3502
- onclick={() => { navigator.clipboard.writeText(selectedWidgetId); showToast('success', 'Widget ID copied', { duration: 2000 }); }}
3503
- >Widget id: {selectedWidgetId}</span>
3504
- </div>
3505
- <div class="widget-info-meta flex items-center gap-2 shrink-0">
3506
- {#if saveStatus === 'saving'}
3507
- <span class="text-[10px] px-1.5 py-0.5 rounded bg-blue-100 text-blue-700 animate-pulse">Saving...</span>
3508
- {:else if saveStatus === 'saved'}
3509
- <span class="text-[10px] px-1.5 py-0.5 rounded bg-green-100 text-green-700">Saved</span>
3510
- {:else if saveStatus === 'error'}
3511
- <span class="text-[10px] px-1.5 py-0.5 rounded bg-red-100 text-red-700">Save Error</span>
3512
- {/if}
3513
- {#if debugMode}
3514
- <span class="text-[10px] text-gray-500">
3515
- Commit: <span class="font-mono font-medium text-gray-600" title={lastCommitId || ''}>{lastCommitId ? lastCommitId.substring(0, 8) : '—'}</span>
3516
- </span>
3517
- {/if}
3518
- <div class="widget-info-version-history-slot relative z-20 shrink-0">
3519
- <slot name="version-history" />
3520
- </div>
3521
- </div>
3522
- </div>
3523
-
3524
3554
  <!-- Scrollable step content -->
3525
3555
  <div
3526
- class="widget-details-left-content flex flex-col flex-1 min-h-0 relative rounded-b-lg overflow-hidden overflow-x-hidden"
3556
+ class="widget-details-left-content flex flex-col flex-1 min-h-0 relative rounded-none overflow-hidden overflow-x-hidden"
3527
3557
  bind:this={contentContainerEl}
3528
3558
  >
3529
3559
  <div class="actions-panel widget-details-actions-panel relative flex flex-col flex-1 min-h-0">
@@ -3561,7 +3591,7 @@
3561
3591
 
3562
3592
  </div> <!-- end of widget-details-left-col -->
3563
3593
 
3564
- {#if previewColumnCollapsed}
3594
+ {#if SHOW_PANEL_PREVIEW_COLUMN && previewColumnCollapsed}
3565
3595
  <div class="widget-details-preview-expand-strip flex items-center justify-center w-8 shrink-0 border-l border-gray-200 bg-gray-50">
3566
3596
  <button
3567
3597
  type="button"
@@ -3572,7 +3602,7 @@
3572
3602
  <span class="widget-details-preview-expand-label inline-block rotate-180" style="writing-mode: vertical-rl;">Preview</span>
3573
3603
  </button>
3574
3604
  </div>
3575
- {:else}
3605
+ {:else if SHOW_PANEL_PREVIEW_COLUMN}
3576
3606
  <!-- svelte-ignore a11y-no-static-element-interactions -->
3577
3607
  <div
3578
3608
  class="widget-details-col-resizer w-2.5 shrink-0 cursor-col-resize relative z-20 group"
@@ -3645,6 +3675,7 @@
3645
3675
  mode="controlled"
3646
3676
  enableResize={true}
3647
3677
  resizeMode="concentric"
3678
+ defaultStageAlign="center"
3648
3679
  autoFitStage={showPreviewModal}
3649
3680
  src={iframeSrc || getFallbackPreviewUrl()}
3650
3681
  displayUrl={directPreviewUrl || iframeSrc}
@@ -191,6 +191,7 @@ declare const WidgetDetails: $$__sveltets_2_IsomorphicComponent<{
191
191
  } & {
192
192
  [evt: string]: CustomEvent<any>;
193
193
  }, {
194
+ 'header-meta': {};
194
195
  'version-history': {};
195
196
  'code-generation-models': {};
196
197
  'code-generation-status': {};