@tutti-os/workbench-surface 0.0.16 → 0.0.18

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/dist/index.js CHANGED
@@ -1708,9 +1708,16 @@ function WorkbenchDockFrame({
1708
1708
  const nodes = useWorkbenchSelector(
1709
1709
  selectDockNodes
1710
1710
  );
1711
+ const minimizedNodesWithPending = useMemo2(
1712
+ () => mergePendingMinimizedDockNode(
1713
+ nodes.filter((node) => node.isMinimized),
1714
+ genie.pendingMinimizedNode
1715
+ ),
1716
+ [genie.pendingMinimizedNode, nodes]
1717
+ );
1711
1718
  const minimizedNodes = useMemo2(
1712
- () => nodes.filter((node) => node.isMinimized),
1713
- [nodes]
1719
+ () => minimizedNodesWithPending.filter((node) => node.isMinimized),
1720
+ [minimizedNodesWithPending]
1714
1721
  );
1715
1722
  const focusedNodeId = useWorkbenchSelector(
1716
1723
  (state) => selectFocusedWorkbenchNode(state)?.id ?? null
@@ -1752,6 +1759,9 @@ function WorkbenchDockFrame({
1752
1759
  },
1753
1760
  shouldAnimateMinimizedDockEnter: (nodeID) => {
1754
1761
  return genie.shouldAnimateMinimizedDockEnter(nodeID);
1762
+ },
1763
+ isPendingMinimizedDockNode: (nodeID) => {
1764
+ return genie.isPendingMinimizedDockNode(nodeID);
1755
1765
  }
1756
1766
  },
1757
1767
  minimizedNodes,
@@ -1761,6 +1771,16 @@ function WorkbenchDockFrame({
1761
1771
  )
1762
1772
  ] });
1763
1773
  }
1774
+ function mergePendingMinimizedDockNode(nodes, pendingNode) {
1775
+ if (!pendingNode) {
1776
+ return nodes;
1777
+ }
1778
+ const existingNode = nodes.find((node) => node.id === pendingNode.id);
1779
+ if (existingNode?.isMinimized) {
1780
+ return nodes;
1781
+ }
1782
+ return [...nodes.filter((node) => node.id !== pendingNode.id), pendingNode];
1783
+ }
1764
1784
 
1765
1785
  // src/react/WorkbenchNodeLayer.tsx
1766
1786
  import { memo, useMemo as useMemo3 } from "react";
@@ -2635,6 +2655,7 @@ function renderGenieScanlines(context, viewportWidth, viewportHeight, frame) {
2635
2655
  // src/react/useWorkbenchGenieAnimation.tsx
2636
2656
  import { jsx as jsx7 } from "react/jsx-runtime";
2637
2657
  var genieDurationMs = 400;
2658
+ var scaleMinimizeDurationMs = 220;
2638
2659
  var genieMaxDevicePixelRatio = 2;
2639
2660
  var genieSnapshotScale = 1;
2640
2661
  var minimizedDockSlotEnterAnimationMs = 720;
@@ -2864,20 +2885,16 @@ async function captureWorkbenchNodePreviewImage(nodeID, options = {}) {
2864
2885
  writeCachedWorkbenchNodePreviewImage(nodeID, previewImageUrl);
2865
2886
  return previewImageUrl;
2866
2887
  }
2867
- async function captureWorkbenchNodePreviewImageForNode(node, input = {}) {
2888
+ async function captureProvidedWorkbenchNodePreviewImageForNode(node, input = {}) {
2868
2889
  const previewImageUrl = await Promise.resolve(
2869
2890
  input.captureNodePreviewImage?.(node) ?? null
2870
2891
  ).catch(() => null);
2871
- if (previewImageUrl) {
2872
- writeCachedWorkbenchNodePreviewImage(node.id, previewImageUrl);
2873
- persistWorkbenchNodePreviewImage(node, previewImageUrl, input);
2874
- return previewImageUrl;
2892
+ if (!previewImageUrl) {
2893
+ return null;
2875
2894
  }
2876
- const capturedPreviewImageUrl = await captureWorkbenchNodePreviewImage(
2877
- node.id
2878
- );
2879
- persistWorkbenchNodePreviewImage(node, capturedPreviewImageUrl, input);
2880
- return capturedPreviewImageUrl;
2895
+ writeCachedWorkbenchNodePreviewImage(node.id, previewImageUrl);
2896
+ persistWorkbenchNodePreviewImage(node, previewImageUrl, input);
2897
+ return previewImageUrl;
2881
2898
  }
2882
2899
  function persistWorkbenchNodePreviewImage(node, previewImageUrl, input) {
2883
2900
  if (!previewImageUrl || !input.dockPreviewCache) {
@@ -2917,8 +2934,10 @@ function useWorkbenchGenieAnimation({
2917
2934
  captureNodePreviewImage,
2918
2935
  controller,
2919
2936
  dockPreviewCache,
2937
+ minimizeAnimation = "scale",
2920
2938
  resolveDockAnchorKey,
2921
- resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
2939
+ resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
2940
+ shouldCaptureNodePreviewImage
2922
2941
  }) {
2923
2942
  const dockAnchorElementsRef = useRef4(/* @__PURE__ */ new Map());
2924
2943
  const canvasRef = useRef4(null);
@@ -2933,6 +2952,7 @@ function useWorkbenchGenieAnimation({
2933
2952
  const [genieHiddenNodeIDs, setGenieHiddenNodeIDs] = useState4(
2934
2953
  () => /* @__PURE__ */ new Set()
2935
2954
  );
2955
+ const [pendingMinimizedNode, setPendingMinimizedNode] = useState4(null);
2936
2956
  const registerDockAnchor = useCallback6(
2937
2957
  (anchorKey, element) => {
2938
2958
  if (element) {
@@ -3008,6 +3028,11 @@ function useWorkbenchGenieAnimation({
3008
3028
  return next;
3009
3029
  });
3010
3030
  }, []);
3031
+ const clearPendingMinimizedNode = useCallback6((nodeID) => {
3032
+ setPendingMinimizedNode(
3033
+ (current) => current?.id === nodeID ? null : current
3034
+ );
3035
+ }, []);
3011
3036
  const setupCanvas = useCallback6(() => {
3012
3037
  const canvas = canvasRef.current;
3013
3038
  if (!canvas) {
@@ -3120,10 +3145,102 @@ function useWorkbenchGenieAnimation({
3120
3145
  },
3121
3146
  [setupCanvas, stopAnimation]
3122
3147
  );
3148
+ const runScaleWindowAnimation = useCallback6(
3149
+ ({
3150
+ direction,
3151
+ dockRect,
3152
+ nodeElement,
3153
+ onCancel,
3154
+ onComplete,
3155
+ skipStop
3156
+ }) => {
3157
+ if (!skipStop) {
3158
+ stopAnimation();
3159
+ }
3160
+ const windowRect = viewportRectFromElement(nodeElement);
3161
+ if (!isUsableGenieRect(windowRect) || !isUsableGenieRect(dockRect)) {
3162
+ onComplete();
3163
+ return;
3164
+ }
3165
+ const generation = animationGenerationRef.current;
3166
+ const fromCenter = centerPointFromRect(windowRect);
3167
+ const toCenter = centerPointFromRect(dockRect);
3168
+ const targetScale = Math.max(
3169
+ 0.04,
3170
+ Math.min(
3171
+ 0.32,
3172
+ dockRect.width / Math.max(1, windowRect.width),
3173
+ dockRect.height / Math.max(1, windowRect.height)
3174
+ )
3175
+ );
3176
+ const previousPointerEvents = nodeElement.style.pointerEvents;
3177
+ const previousTransformOrigin = nodeElement.style.transformOrigin;
3178
+ const previousVisibility = nodeElement.style.visibility;
3179
+ const previousZIndex = nodeElement.style.zIndex;
3180
+ nodeElement.style.pointerEvents = "none";
3181
+ nodeElement.style.transformOrigin = "center center";
3182
+ nodeElement.style.visibility = "visible";
3183
+ nodeElement.style.zIndex = "var(--z-workbench-genie)";
3184
+ const dockTransform = `translate3d(${toCenter.x - fromCenter.x}px, ${toCenter.y - fromCenter.y}px, 0) scale(${targetScale})`;
3185
+ const windowTransform = "translate3d(0, 0, 0) scale(1)";
3186
+ const keyframes = direction === "open" ? [
3187
+ {
3188
+ opacity: 0,
3189
+ transform: dockTransform
3190
+ },
3191
+ {
3192
+ opacity: 1,
3193
+ transform: windowTransform
3194
+ }
3195
+ ] : [
3196
+ {
3197
+ opacity: 1,
3198
+ transform: windowTransform
3199
+ },
3200
+ {
3201
+ opacity: 0,
3202
+ transform: dockTransform
3203
+ }
3204
+ ];
3205
+ const animation = nodeElement.animate(keyframes, {
3206
+ duration: scaleMinimizeDurationMs,
3207
+ easing: "cubic-bezier(0.4, 0, 0.2, 1)",
3208
+ fill: "forwards"
3209
+ });
3210
+ const restoreElement = () => {
3211
+ animation.cancel();
3212
+ nodeElement.style.pointerEvents = previousPointerEvents;
3213
+ nodeElement.style.transformOrigin = previousTransformOrigin;
3214
+ nodeElement.style.visibility = previousVisibility;
3215
+ nodeElement.style.zIndex = previousZIndex;
3216
+ };
3217
+ animationCleanupRef.current = () => {
3218
+ restoreElement();
3219
+ onCancel();
3220
+ };
3221
+ animation.finished.then(() => {
3222
+ if (generation !== animationGenerationRef.current) {
3223
+ return;
3224
+ }
3225
+ animationCleanupRef.current = null;
3226
+ restoreElement();
3227
+ onComplete();
3228
+ }).catch(() => {
3229
+ if (generation !== animationGenerationRef.current) {
3230
+ return;
3231
+ }
3232
+ animationCleanupRef.current = null;
3233
+ restoreElement();
3234
+ onComplete();
3235
+ });
3236
+ },
3237
+ [stopAnimation]
3238
+ );
3123
3239
  useEffect3(() => () => stopAnimation(false), [stopAnimation]);
3124
3240
  const startOpenOrRestoreAnimation = useCallback6(
3125
3241
  async (nodeID, anchorKey, generation, dockRectFallback) => {
3126
- if (shouldReduceMotion()) {
3242
+ const effectiveMinimizeAnimation = shouldReduceMotion() ? "off" : minimizeAnimation;
3243
+ if (effectiveMinimizeAnimation === "off") {
3127
3244
  animationCleanupRef.current = null;
3128
3245
  showNodeForGenie(nodeID);
3129
3246
  return;
@@ -3135,6 +3252,32 @@ function useWorkbenchGenieAnimation({
3135
3252
  const resolvedDockRect = resolveDockAnchorRect(anchorKey);
3136
3253
  const dockRect = resolvedDockRect && isUsableGenieRect(resolvedDockRect) ? resolvedDockRect : dockRectFallback;
3137
3254
  const nodeElement = resolveNodeElement(nodeID);
3255
+ if (effectiveMinimizeAnimation === "scale") {
3256
+ if (!dockRect || !nodeElement || !isUsableGenieRect(dockRect)) {
3257
+ animationCleanupRef.current = null;
3258
+ showNodeForGenie(nodeID);
3259
+ return;
3260
+ }
3261
+ flushSync(() => {
3262
+ showNodeForGenie(nodeID);
3263
+ });
3264
+ runScaleWindowAnimation({
3265
+ direction: "open",
3266
+ dockRect,
3267
+ nodeElement,
3268
+ onCancel: () => {
3269
+ flushSync(() => {
3270
+ showNodeForGenie(nodeID);
3271
+ });
3272
+ },
3273
+ onComplete: () => {
3274
+ flushSync(() => {
3275
+ showNodeForGenie(nodeID);
3276
+ });
3277
+ }
3278
+ });
3279
+ return;
3280
+ }
3138
3281
  const captureTarget = nodeElement ? resolveWorkbenchCaptureElement(nodeElement) : null;
3139
3282
  if (!dockRect || !nodeElement || !captureTarget || !isUsableGenieRect(dockRect)) {
3140
3283
  animationCleanupRef.current = null;
@@ -3173,9 +3316,11 @@ function useWorkbenchGenieAnimation({
3173
3316
  },
3174
3317
  [
3175
3318
  clearCanvas,
3319
+ minimizeAnimation,
3176
3320
  resolveDockAnchorRect,
3177
3321
  resolveNodeElement,
3178
3322
  runGenieAnimation,
3323
+ runScaleWindowAnimation,
3179
3324
  showNodeForGenie
3180
3325
  ]
3181
3326
  );
@@ -3192,6 +3337,16 @@ function useWorkbenchGenieAnimation({
3192
3337
  });
3193
3338
  return;
3194
3339
  }
3340
+ const effectiveMinimizeAnimation = shouldReduceMotion() ? "off" : minimizeAnimation;
3341
+ if (effectiveMinimizeAnimation === "off") {
3342
+ stopAnimation();
3343
+ flushSync(() => {
3344
+ showNodeForGenie(nodeID);
3345
+ });
3346
+ void Promise.resolve(launch()).catch(() => {
3347
+ });
3348
+ return;
3349
+ }
3195
3350
  stopAnimation();
3196
3351
  const dockRectFallback = resolveDockAnchorRect(anchorKey);
3197
3352
  hideNodeForGenie(nodeID);
@@ -3216,6 +3371,7 @@ function useWorkbenchGenieAnimation({
3216
3371
  clearCanvas,
3217
3372
  controller,
3218
3373
  hideNodeForGenie,
3374
+ minimizeAnimation,
3219
3375
  resolveDockAnchorRect,
3220
3376
  showNodeForGenie,
3221
3377
  startOpenOrRestoreAnimation,
@@ -3230,23 +3386,137 @@ function useWorkbenchGenieAnimation({
3230
3386
  return;
3231
3387
  }
3232
3388
  const runMinimize = minimize ?? (() => controller.commands.minimizeNode(nodeID));
3233
- if (shouldReduceMotion()) {
3234
- const wasFocusedForCapture2 = isFocusedWorkbenchNode(
3235
- controller,
3236
- nodeID
3237
- );
3238
- if (!wasFocusedForCapture2) {
3389
+ const effectiveMinimizeAnimation = shouldReduceMotion() ? "off" : minimizeAnimation;
3390
+ const shouldCapturePreview = shouldCaptureNodePreviewImage?.(target) ?? true;
3391
+ if (effectiveMinimizeAnimation === "off") {
3392
+ stopAnimation();
3393
+ let frameID = null;
3394
+ let timerID = null;
3395
+ let minimizeCommitted2 = false;
3396
+ const commitMinimize2 = () => {
3397
+ if (minimizeCommitted2) {
3398
+ return;
3399
+ }
3400
+ minimizeCommitted2 = true;
3401
+ if (frameID !== null) {
3402
+ window.cancelAnimationFrame(frameID);
3403
+ frameID = null;
3404
+ }
3405
+ if (timerID !== null) {
3406
+ clearTimeout(timerID);
3407
+ timerID = null;
3408
+ }
3409
+ animationCleanupRef.current = null;
3410
+ flushSync(() => {
3411
+ clearPendingMinimizedNode(nodeID);
3412
+ showNodeForGenie(nodeID);
3413
+ runMinimize();
3414
+ });
3415
+ scheduleReleaseMinimizedDockEnterAnimation(nodeID);
3416
+ };
3417
+ animationCleanupRef.current = () => {
3418
+ releaseMinimizedDockEnterAnimation(nodeID);
3419
+ commitMinimize2();
3420
+ };
3421
+ registerMinimizedDockEnterAnimation(nodeID);
3422
+ flushSync(() => {
3423
+ hideNodeForGenie(nodeID);
3424
+ setPendingMinimizedNode({
3425
+ ...target,
3426
+ isMinimized: true,
3427
+ minimizedAtUnixMs: Date.now()
3428
+ });
3429
+ });
3430
+ if (shouldCapturePreview) {
3431
+ void captureProvidedWorkbenchNodePreviewImageForNode(target, {
3432
+ captureNodePreviewImage,
3433
+ dockPreviewCache,
3434
+ resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
3435
+ });
3436
+ }
3437
+ frameID = window.requestAnimationFrame(() => {
3438
+ frameID = null;
3439
+ timerID = setTimeout(commitMinimize2, 0);
3440
+ });
3441
+ return;
3442
+ }
3443
+ if (effectiveMinimizeAnimation === "scale") {
3444
+ stopAnimation();
3445
+ const generation2 = animationGenerationRef.current;
3446
+ const nodeElement2 = resolveNodeElement(nodeID);
3447
+ if (!nodeElement2) {
3448
+ runMinimize();
3449
+ return;
3450
+ }
3451
+ const wasFocusedForCapture2 = shouldCapturePreview && isFocusedWorkbenchNode(controller, nodeID);
3452
+ if (shouldCapturePreview && !wasFocusedForCapture2) {
3239
3453
  flushSync(() => {
3240
3454
  controller.commands.focusNode(nodeID);
3241
3455
  });
3242
3456
  await waitForNextAnimationFrame();
3457
+ if (generation2 !== animationGenerationRef.current) {
3458
+ return;
3459
+ }
3243
3460
  }
3244
- await captureWorkbenchNodePreviewImageForNode(target, {
3245
- captureNodePreviewImage,
3246
- dockPreviewCache,
3247
- resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
3461
+ if (shouldCapturePreview) {
3462
+ void captureProvidedWorkbenchNodePreviewImageForNode(target, {
3463
+ captureNodePreviewImage,
3464
+ dockPreviewCache,
3465
+ resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
3466
+ });
3467
+ }
3468
+ let minimizeCommitted2 = false;
3469
+ const commitMinimize2 = () => {
3470
+ if (minimizeCommitted2) {
3471
+ return;
3472
+ }
3473
+ minimizeCommitted2 = true;
3474
+ runMinimize();
3475
+ };
3476
+ const cleanupPendingMinimize = () => {
3477
+ releaseMinimizedDockEnterAnimation(nodeID);
3478
+ flushSync(() => {
3479
+ clearPendingMinimizedNode(nodeID);
3480
+ commitMinimize2();
3481
+ });
3482
+ };
3483
+ const pendingMinimizedNode3 = {
3484
+ ...target,
3485
+ isMinimized: true,
3486
+ minimizedAtUnixMs: Date.now()
3487
+ };
3488
+ registerMinimizedDockEnterAnimation(nodeID);
3489
+ flushSync(() => {
3490
+ setPendingMinimizedNode(pendingMinimizedNode3);
3491
+ });
3492
+ animationCleanupRef.current = cleanupPendingMinimize;
3493
+ await waitForNextAnimationFrame();
3494
+ if (generation2 !== animationGenerationRef.current) {
3495
+ return;
3496
+ }
3497
+ const anchorKey2 = resolveAnchorKeyForNode(pendingMinimizedNode3);
3498
+ const dockRect2 = resolveDockAnchorRect(anchorKey2);
3499
+ if (!nodeElement2.isConnected || !dockRect2 || !isUsableGenieRect(dockRect2)) {
3500
+ cleanupPendingMinimize();
3501
+ return;
3502
+ }
3503
+ runScaleWindowAnimation({
3504
+ direction: "minimize",
3505
+ dockRect: dockRect2,
3506
+ nodeElement: nodeElement2,
3507
+ onCancel: () => {
3508
+ cleanupPendingMinimize();
3509
+ },
3510
+ onComplete: () => {
3511
+ animationCleanupRef.current = null;
3512
+ flushSync(() => {
3513
+ clearPendingMinimizedNode(nodeID);
3514
+ commitMinimize2();
3515
+ });
3516
+ scheduleReleaseMinimizedDockEnterAnimation(nodeID);
3517
+ },
3518
+ skipStop: true
3248
3519
  });
3249
- runMinimize();
3250
3520
  return;
3251
3521
  }
3252
3522
  stopAnimation();
@@ -3309,46 +3579,57 @@ function useWorkbenchGenieAnimation({
3309
3579
  resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
3310
3580
  });
3311
3581
  }
3312
- const cleanupHiddenNode = () => {
3582
+ let minimizeCommitted = false;
3583
+ const commitMinimize = () => {
3584
+ if (minimizeCommitted) {
3585
+ return;
3586
+ }
3587
+ minimizeCommitted = true;
3588
+ runMinimize();
3589
+ };
3590
+ const pendingMinimizedNode2 = {
3591
+ ...target,
3592
+ isMinimized: true,
3593
+ minimizedAtUnixMs: Date.now()
3594
+ };
3595
+ const cleanupPendingGenieMinimize = () => {
3596
+ releaseMinimizedDockEnterAnimation(nodeID);
3313
3597
  flushSync(() => {
3598
+ clearPendingMinimizedNode(nodeID);
3314
3599
  showNodeForGenie(nodeID);
3600
+ commitMinimize();
3315
3601
  });
3316
3602
  clearCanvas();
3317
3603
  };
3318
- animationCleanupRef.current = cleanupHiddenNode;
3604
+ animationCleanupRef.current = cleanupPendingGenieMinimize;
3319
3605
  registerMinimizedDockEnterAnimation(nodeID);
3320
3606
  flushSync(() => {
3607
+ setPendingMinimizedNode(pendingMinimizedNode2);
3321
3608
  hideNodeForGenie(nodeID);
3322
- runMinimize();
3323
3609
  });
3324
3610
  await waitForNextAnimationFrame();
3325
3611
  if (generation !== animationGenerationRef.current) {
3326
- releaseMinimizedDockEnterAnimation(nodeID);
3327
3612
  return;
3328
3613
  }
3329
- const minimizedTarget = controller.getSnapshot().nodes.find((node) => node.id === nodeID) ?? target;
3330
- const anchorKey = resolveAnchorKeyForNode(minimizedTarget);
3614
+ const anchorKey = resolveAnchorKeyForNode(pendingMinimizedNode2);
3331
3615
  const dockRect = resolveDockAnchorRect(anchorKey);
3332
3616
  if (!dockRect || !isUsableGenieRect(dockRect)) {
3333
- releaseMinimizedDockEnterAnimation(nodeID);
3334
3617
  animationCleanupRef.current = null;
3335
- cleanupHiddenNode();
3618
+ cleanupPendingGenieMinimize();
3336
3619
  return;
3337
3620
  }
3338
3621
  runGenieAnimation({
3339
3622
  direction: "minimize",
3340
3623
  dockRect,
3341
3624
  onCancel: () => {
3342
- releaseMinimizedDockEnterAnimation(nodeID);
3343
- flushSync(() => {
3344
- showNodeForGenie(nodeID);
3345
- });
3346
- clearCanvas();
3625
+ cleanupPendingGenieMinimize();
3347
3626
  },
3348
3627
  onComplete: () => {
3349
3628
  scheduleReleaseMinimizedDockEnterAnimation(nodeID);
3350
3629
  flushSync(() => {
3630
+ clearPendingMinimizedNode(nodeID);
3351
3631
  showNodeForGenie(nodeID);
3632
+ commitMinimize();
3352
3633
  });
3353
3634
  clearCanvas();
3354
3635
  },
@@ -3361,8 +3642,10 @@ function useWorkbenchGenieAnimation({
3361
3642
  clearCanvas,
3362
3643
  controller,
3363
3644
  captureNodePreviewImage,
3645
+ clearPendingMinimizedNode,
3364
3646
  dockPreviewCache,
3365
3647
  hideNodeForGenie,
3648
+ minimizeAnimation,
3366
3649
  registerMinimizedDockEnterAnimation,
3367
3650
  releaseMinimizedDockEnterAnimation,
3368
3651
  resolveAnchorKeyForNode,
@@ -3370,7 +3653,9 @@ function useWorkbenchGenieAnimation({
3370
3653
  resolveDockAnchorRect,
3371
3654
  resolveNodeElement,
3372
3655
  runGenieAnimation,
3656
+ runScaleWindowAnimation,
3373
3657
  scheduleReleaseMinimizedDockEnterAnimation,
3658
+ shouldCaptureNodePreviewImage,
3374
3659
  setupCanvas,
3375
3660
  showNodeForGenie,
3376
3661
  stopAnimation
@@ -3403,8 +3688,13 @@ function useWorkbenchGenieAnimation({
3403
3688
  (nodeID) => genieHiddenNodeIDs.has(nodeID),
3404
3689
  [genieHiddenNodeIDs]
3405
3690
  ),
3691
+ isPendingMinimizedDockNode: useCallback6(
3692
+ (nodeID) => pendingMinimizedNode?.id === nodeID,
3693
+ [pendingMinimizedNode]
3694
+ ),
3406
3695
  launchNodeFromAnchor,
3407
3696
  minimizeNodeToAnchor,
3697
+ pendingMinimizedNode,
3408
3698
  registerDockAnchor,
3409
3699
  shouldAnimateMinimizedDockEnter
3410
3700
  };
@@ -3421,6 +3711,7 @@ function WorkbenchSurface({
3421
3711
  interactive,
3422
3712
  layoutConstraints,
3423
3713
  missionControlPhase,
3714
+ minimizeAnimation,
3424
3715
  presentation,
3425
3716
  renderBackdrop,
3426
3717
  renderBottomChrome,
@@ -3435,6 +3726,7 @@ function WorkbenchSurface({
3435
3726
  resolveDockAnchorKey,
3436
3727
  resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
3437
3728
  shortcutsEnabled,
3729
+ shouldCaptureNodePreviewImage,
3438
3730
  wallpaper,
3439
3731
  windowChromeMode,
3440
3732
  windowChromeI18n
@@ -3449,6 +3741,7 @@ function WorkbenchSurface({
3449
3741
  interactive,
3450
3742
  layoutConstraints,
3451
3743
  missionControlPhase,
3744
+ minimizeAnimation,
3452
3745
  presentation,
3453
3746
  renderBackdrop,
3454
3747
  renderBottomChrome,
@@ -3463,6 +3756,7 @@ function WorkbenchSurface({
3463
3756
  resolveDockAnchorKey,
3464
3757
  resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
3465
3758
  shortcutsEnabled,
3759
+ shouldCaptureNodePreviewImage,
3466
3760
  wallpaper,
3467
3761
  windowChromeMode,
3468
3762
  windowChromeI18n
@@ -3477,6 +3771,7 @@ function WorkbenchSurfaceInner({
3477
3771
  interactive = true,
3478
3772
  layoutConstraints,
3479
3773
  missionControlPhase,
3774
+ minimizeAnimation,
3480
3775
  presentation,
3481
3776
  renderBackdrop,
3482
3777
  renderBottomChrome,
@@ -3491,6 +3786,7 @@ function WorkbenchSurfaceInner({
3491
3786
  resolveDockAnchorKey,
3492
3787
  resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
3493
3788
  shortcutsEnabled,
3789
+ shouldCaptureNodePreviewImage,
3494
3790
  wallpaper,
3495
3791
  windowChromeMode,
3496
3792
  windowChromeI18n
@@ -3507,8 +3803,10 @@ function WorkbenchSurfaceInner({
3507
3803
  captureNodePreviewImage,
3508
3804
  controller,
3509
3805
  dockPreviewCache,
3806
+ minimizeAnimation,
3510
3807
  resolveDockAnchorKey,
3511
- resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2
3808
+ resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
3809
+ shouldCaptureNodePreviewImage
3512
3810
  });
3513
3811
  useWorkbenchShortcuts((shortcutsEnabled ?? true) && interactive);
3514
3812
  useEffect4(() => {
@@ -4769,6 +5067,11 @@ var WorkbenchHostSessionController = class {
4769
5067
  this.restoreAndFocusNode(nodeId);
4770
5068
  });
4771
5069
  }
5070
+ minimizeNode(nodeId) {
5071
+ this.runWhenReady(this.loadGeneration, () => {
5072
+ this.controller.commands.minimizeNode(nodeId);
5073
+ });
5074
+ }
4772
5075
  exitFullscreenNode(nodeId) {
4773
5076
  this.runWhenReady(this.loadGeneration, () => {
4774
5077
  this.controller.commands.exitFullscreen(nodeId);
@@ -6244,7 +6547,7 @@ function resolveWorkbenchMinimizedDockAnchorKeyForNode(input) {
6244
6547
  }
6245
6548
  function isWorkbenchMinimizedDockEligibleNode(input) {
6246
6549
  const definition = input.nodeDefinitions.get(input.node.data.typeId);
6247
- return definition?.window?.minimizedDock?.kind === "snapshot";
6550
+ return definition?.window?.minimizedDock !== void 0;
6248
6551
  }
6249
6552
  function orderWorkbenchMinimizedDockNodes(input) {
6250
6553
  return input.nodes.map((node, index) => ({ index, node })).filter(
@@ -7435,11 +7738,16 @@ function WorkbenchHostDock({
7435
7738
  const hoverPanelOpenTimerRef = useRef8(
7436
7739
  null
7437
7740
  );
7741
+ const labelTooltipOpenTimerRef = useRef8(
7742
+ null
7743
+ );
7438
7744
  const hoverPanelScheduledPointRef = useRef8(null);
7745
+ const labelTooltipScheduledPointRef = useRef8(null);
7439
7746
  const hoverPanelRestTargetRef = useRef8(null);
7440
7747
  const activeHoverPanelRef = useRef8(
7441
7748
  null
7442
7749
  );
7750
+ const activeLabelTooltipRef = useRef8(null);
7443
7751
  const pendingDockStateRefreshRef = useRef8(false);
7444
7752
  const slotRefs = useRef8(/* @__PURE__ */ new Map());
7445
7753
  const wallpaperToneElementRefs = useRef8(/* @__PURE__ */ new Map());
@@ -7447,12 +7755,14 @@ function WorkbenchHostDock({
7447
7755
  /* @__PURE__ */ new Map()
7448
7756
  );
7449
7757
  const previousAttentionTokenByEntryId = useRef8(/* @__PURE__ */ new Map());
7758
+ const dockEntryClickThrottleUntilRef = useRef8(/* @__PURE__ */ new Map());
7450
7759
  const attentionTimeouts = useRef8(
7451
7760
  /* @__PURE__ */ new Map()
7452
7761
  );
7453
7762
  const [activeAttentionEntryIds, setActiveAttentionEntryIds] = useState8(/* @__PURE__ */ new Set());
7454
7763
  const [activePopup, setActivePopup] = useState8(null);
7455
7764
  const [activeHoverPanel, setActiveHoverPanel] = useState8(null);
7765
+ const [activeLabelTooltip, setActiveLabelTooltip] = useState8(null);
7456
7766
  const [activeMinimizedStackPopup, setActiveMinimizedStackPopup] = useState8(null);
7457
7767
  const [pendingActionKeys, setPendingActionKeys] = useState8(
7458
7768
  () => /* @__PURE__ */ new Set()
@@ -7488,16 +7798,29 @@ function WorkbenchHostDock({
7488
7798
  hoverPanelOpenTimerRef.current = null;
7489
7799
  hoverPanelScheduledPointRef.current = null;
7490
7800
  }, []);
7801
+ const clearLabelTooltipOpenTimer = useCallback10(() => {
7802
+ if (labelTooltipOpenTimerRef.current === null) {
7803
+ return;
7804
+ }
7805
+ clearTimeout(labelTooltipOpenTimerRef.current);
7806
+ labelTooltipOpenTimerRef.current = null;
7807
+ labelTooltipScheduledPointRef.current = null;
7808
+ }, []);
7491
7809
  useEffect9(
7492
7810
  () => () => {
7493
7811
  clearHoverPanelCloseTimer();
7494
7812
  clearHoverPanelOpenTimer();
7813
+ clearLabelTooltipOpenTimer();
7495
7814
  for (const timer of collapsingMinimizedLaunchTimerRef.current.values()) {
7496
7815
  clearTimeout(timer);
7497
7816
  }
7498
7817
  collapsingMinimizedLaunchTimerRef.current.clear();
7499
7818
  },
7500
- [clearHoverPanelCloseTimer, clearHoverPanelOpenTimer]
7819
+ [
7820
+ clearHoverPanelCloseTimer,
7821
+ clearHoverPanelOpenTimer,
7822
+ clearLabelTooltipOpenTimer
7823
+ ]
7501
7824
  );
7502
7825
  const clearCollapsingMinimizedLaunch = useCallback10((anchorKey) => {
7503
7826
  const timer = collapsingMinimizedLaunchTimerRef.current.get(anchorKey);
@@ -7607,9 +7930,9 @@ function WorkbenchHostDock({
7607
7930
  const minimizedDockSlots = useMemo5(
7608
7931
  () => resolveWorkbenchMinimizedDockSlots({
7609
7932
  nodeDefinitions,
7610
- nodes: context.nodes
7933
+ nodes: context.minimizedNodes
7611
7934
  }),
7612
- [context.nodes, nodeDefinitions]
7935
+ [context.minimizedNodes, nodeDefinitions]
7613
7936
  );
7614
7937
  const { promotedNodeId, stackDispatching } = useMinimizedDockStackPromotion(minimizedDockSlots);
7615
7938
  const dockItems = useMemo5(
@@ -7684,6 +8007,23 @@ function WorkbenchHostDock({
7684
8007
  useEffect9(() => {
7685
8008
  activeHoverPanelRef.current = activeHoverPanel;
7686
8009
  }, [activeHoverPanel]);
8010
+ useEffect9(() => {
8011
+ activeLabelTooltipRef.current = activeLabelTooltip;
8012
+ }, [activeLabelTooltip]);
8013
+ const closeLabelTooltipImmediate = useCallback10(
8014
+ (targetKey) => {
8015
+ clearLabelTooltipOpenTimer();
8016
+ if (targetKey !== void 0 && activeLabelTooltipRef.current?.key !== targetKey) {
8017
+ return;
8018
+ }
8019
+ if (activeLabelTooltipRef.current === null) {
8020
+ return;
8021
+ }
8022
+ activeLabelTooltipRef.current = null;
8023
+ setActiveLabelTooltip(null);
8024
+ },
8025
+ [clearLabelTooltipOpenTimer]
8026
+ );
7687
8027
  const closeHoverPanelImmediate = useCallback10(
7688
8028
  (entryId) => {
7689
8029
  clearHoverPanelOpenTimer();
@@ -7771,6 +8111,50 @@ function WorkbenchHostDock({
7771
8111
  },
7772
8112
  [clearHoverPanelOpenTimer, showHoverPanel]
7773
8113
  );
8114
+ const showLabelTooltip = useCallback10(
8115
+ (target, anchorKey, anchorElement) => {
8116
+ const dockElement = dockMeasureRef.current;
8117
+ if (!dockElement) {
8118
+ return;
8119
+ }
8120
+ const dockRect = dockElement.getBoundingClientRect();
8121
+ const anchorRect = resolveDockLabelTooltipAnchorRect({
8122
+ dockPlacement,
8123
+ slotElement: anchorElement
8124
+ });
8125
+ clearLabelTooltipOpenTimer();
8126
+ const nextTooltip = {
8127
+ anchorKey,
8128
+ anchorRect: {
8129
+ height: anchorRect.height,
8130
+ left: anchorRect.left - dockRect.left,
8131
+ top: anchorRect.top - dockRect.top,
8132
+ width: anchorRect.width
8133
+ },
8134
+ key: target.key,
8135
+ label: target.label
8136
+ };
8137
+ activeLabelTooltipRef.current = nextTooltip;
8138
+ setActiveLabelTooltip(nextTooltip);
8139
+ },
8140
+ [clearLabelTooltipOpenTimer, dockPlacement]
8141
+ );
8142
+ const scheduleLabelTooltipAfterRest = useCallback10(
8143
+ (target, anchorKey) => {
8144
+ clearLabelTooltipOpenTimer();
8145
+ labelTooltipScheduledPointRef.current = null;
8146
+ labelTooltipOpenTimerRef.current = setTimeout(() => {
8147
+ labelTooltipOpenTimerRef.current = null;
8148
+ labelTooltipScheduledPointRef.current = null;
8149
+ const slotElement = slotRefs.current.get(anchorKey);
8150
+ if (!slotElement) {
8151
+ return;
8152
+ }
8153
+ showLabelTooltip(target, anchorKey, slotElement);
8154
+ }, dockHoverPanelOpenDelayMs);
8155
+ },
8156
+ [clearLabelTooltipOpenTimer, showLabelTooltip]
8157
+ );
7774
8158
  const resolveHoverPanelTargetAtPoint = useCallback10(
7775
8159
  (clientX, clientY) => {
7776
8160
  for (const [anchorKey, slotElement] of slotRefs.current) {
@@ -7787,6 +8171,33 @@ function WorkbenchHostDock({
7787
8171
  },
7788
8172
  []
7789
8173
  );
8174
+ const resolveLabelTooltipTargetAtPoint = useCallback10(
8175
+ (clientX, clientY) => {
8176
+ for (const [anchorKey, slotElement] of slotRefs.current) {
8177
+ if (slotElement.dataset.dockHoverPanelEntryId) {
8178
+ continue;
8179
+ }
8180
+ const key = slotElement.dataset.dockLabelTooltipKey;
8181
+ const label = slotElement.dataset.dockLabelTooltipLabel?.trim() ?? "";
8182
+ if (!key || !label) {
8183
+ continue;
8184
+ }
8185
+ const rect = slotElement.getBoundingClientRect();
8186
+ if (clientX >= rect.left - dockHoverPanelHitSlopPx && clientX <= rect.right + dockHoverPanelHitSlopPx && clientY >= rect.top - dockHoverPanelHitSlopPx && clientY <= rect.bottom + dockHoverPanelHitSlopPx) {
8187
+ return {
8188
+ anchorKey,
8189
+ slotElement,
8190
+ target: {
8191
+ key,
8192
+ label
8193
+ }
8194
+ };
8195
+ }
8196
+ }
8197
+ return null;
8198
+ },
8199
+ []
8200
+ );
7790
8201
  const isPointerInsideActiveHoverPanelRegion = useCallback10(
7791
8202
  (clientX, clientY) => {
7792
8203
  const activeHoverPanel2 = activeHoverPanelRef.current;
@@ -7847,19 +8258,70 @@ function WorkbenchHostDock({
7847
8258
  },
7848
8259
  [clearHoverPanelOpenTimer, resolveHoverPanelTargetAtPoint, showHoverPanel]
7849
8260
  );
8261
+ const scheduleLabelTooltipAtPointAfterRest = useCallback10(
8262
+ (clientX, clientY) => {
8263
+ if (activeLabelTooltipRef.current !== null) {
8264
+ return;
8265
+ }
8266
+ const scheduledPoint = labelTooltipScheduledPointRef.current;
8267
+ if (labelTooltipOpenTimerRef.current !== null && scheduledPoint && Math.abs(clientX - scheduledPoint.clientX) <= dockHoverPanelPointerRestTolerancePx && Math.abs(clientY - scheduledPoint.clientY) <= dockHoverPanelPointerRestTolerancePx) {
8268
+ return;
8269
+ }
8270
+ clearLabelTooltipOpenTimer();
8271
+ labelTooltipScheduledPointRef.current = { clientX, clientY };
8272
+ labelTooltipOpenTimerRef.current = setTimeout(() => {
8273
+ labelTooltipOpenTimerRef.current = null;
8274
+ labelTooltipScheduledPointRef.current = null;
8275
+ if (activeHoverPanelRef.current !== null) {
8276
+ return;
8277
+ }
8278
+ const target = resolveLabelTooltipTargetAtPoint(clientX, clientY);
8279
+ if (!target) {
8280
+ return;
8281
+ }
8282
+ showLabelTooltip(target.target, target.anchorKey, target.slotElement);
8283
+ }, dockHoverPanelOpenDelayMs);
8284
+ },
8285
+ [
8286
+ clearLabelTooltipOpenTimer,
8287
+ resolveLabelTooltipTargetAtPoint,
8288
+ showLabelTooltip
8289
+ ]
8290
+ );
7850
8291
  const beginDockIconInteraction = useCallback10(
7851
8292
  (anchorKey) => {
7852
8293
  hoverPanelRestTargetRef.current = null;
7853
8294
  clearHoverPanelOpenTimer();
8295
+ closeLabelTooltipImmediate();
7854
8296
  closeHoverPanelImmediate();
7855
8297
  triggerDockBounce(anchorKey);
7856
8298
  },
7857
- [clearHoverPanelOpenTimer, closeHoverPanelImmediate, triggerDockBounce]
8299
+ [
8300
+ clearHoverPanelOpenTimer,
8301
+ closeHoverPanelImmediate,
8302
+ closeLabelTooltipImmediate,
8303
+ triggerDockBounce
8304
+ ]
7858
8305
  );
8306
+ const isDockEntryClickThrottled = useCallback10(
8307
+ (anchorKey) => {
8308
+ const throttledUntil = dockEntryClickThrottleUntilRef.current.get(anchorKey);
8309
+ return throttledUntil !== void 0 && Date.now() < throttledUntil;
8310
+ },
8311
+ []
8312
+ );
8313
+ const claimDockEntryClick = useCallback10((anchorKey) => {
8314
+ dockEntryClickThrottleUntilRef.current.set(
8315
+ anchorKey,
8316
+ Date.now() + DOCK_ENTRY_CLICK_THROTTLE_MS
8317
+ );
8318
+ }, []);
7859
8319
  const beginDockMinimizedInteraction = useCallback10(
7860
8320
  (anchorKey) => {
7861
8321
  hoverPanelRestTargetRef.current = null;
7862
8322
  clearHoverPanelOpenTimer();
8323
+ clearLabelTooltipOpenTimer();
8324
+ closeLabelTooltipImmediate();
7863
8325
  closeHoverPanelImmediate();
7864
8326
  pauseDockMagnification();
7865
8327
  if (!anchorKey) {
@@ -7887,8 +8349,10 @@ function WorkbenchHostDock({
7887
8349
  },
7888
8350
  [
7889
8351
  clearHoverPanelOpenTimer,
8352
+ clearLabelTooltipOpenTimer,
7890
8353
  clearSlotMagnification,
7891
8354
  closeHoverPanelImmediate,
8355
+ closeLabelTooltipImmediate,
7892
8356
  pauseDockMagnification
7893
8357
  ]
7894
8358
  );
@@ -7916,6 +8380,7 @@ function WorkbenchHostDock({
7916
8380
  const handleDockPointerTravel = useCallback10(
7917
8381
  (clientX, clientY) => {
7918
8382
  if (activeHoverPanelRef.current !== null) {
8383
+ closeLabelTooltipImmediate();
7919
8384
  if (isPointerInsideActiveHoverPanelRegion(clientX, clientY)) {
7920
8385
  clearHoverPanelCloseTimer();
7921
8386
  return;
@@ -7924,16 +8389,27 @@ function WorkbenchHostDock({
7924
8389
  handleDockPointerLeave();
7925
8390
  return;
7926
8391
  }
8392
+ const activeLabelTooltip2 = activeLabelTooltipRef.current;
8393
+ if (activeLabelTooltip2) {
8394
+ const target = resolveLabelTooltipTargetAtPoint(clientX, clientY);
8395
+ if (target?.target.key !== activeLabelTooltip2.key) {
8396
+ closeLabelTooltipImmediate(activeLabelTooltip2.key);
8397
+ }
8398
+ }
7927
8399
  handleDockPointerMove(clientX, clientY);
7928
8400
  scheduleHoverPanelAtPointAfterRest(clientX, clientY);
8401
+ scheduleLabelTooltipAtPointAfterRest(clientX, clientY);
7929
8402
  },
7930
8403
  [
7931
8404
  clearHoverPanelCloseTimer,
8405
+ closeLabelTooltipImmediate,
7932
8406
  handleDockPointerMove,
7933
8407
  handleDockPointerLeave,
7934
8408
  isPointerInsideActiveHoverPanelRegion,
8409
+ resolveLabelTooltipTargetAtPoint,
7935
8410
  scheduleHoverPanelClose,
7936
- scheduleHoverPanelAtPointAfterRest
8411
+ scheduleHoverPanelAtPointAfterRest,
8412
+ scheduleLabelTooltipAtPointAfterRest
7937
8413
  ]
7938
8414
  );
7939
8415
  const updateDockScrollState = useCallback10(() => {
@@ -7997,9 +8473,13 @@ function WorkbenchHostDock({
7997
8473
  }, [dockPlacement, presentDockItems.length, updateDockScrollState]);
7998
8474
  const hasMinimizedPreviewCapture = minimizedDockSlots.some(
7999
8475
  (slot) => minimizedDockSlotNodes(slot).some(
8000
- (node) => Boolean(
8001
- nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock?.capturePreview
8002
- )
8476
+ (node) => (() => {
8477
+ if (context.genie.isPendingMinimizedDockNode(node.id)) {
8478
+ return false;
8479
+ }
8480
+ const minimizedDock = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock;
8481
+ return minimizedDock?.kind === "snapshot" && Boolean(minimizedDock.capturePreview);
8482
+ })()
8003
8483
  )
8004
8484
  );
8005
8485
  useEffect9(() => {
@@ -8063,7 +8543,8 @@ function WorkbenchHostDock({
8063
8543
  );
8064
8544
  const captureMinimizedNodePreview = useCallback10(
8065
8545
  async (node) => {
8066
- const capturePreview = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock?.capturePreview;
8546
+ const minimizedDock = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock;
8547
+ const capturePreview = minimizedDock?.kind === "snapshot" ? minimizedDock.capturePreview : void 0;
8067
8548
  const externalState = readWorkbenchHostExternalState({
8068
8549
  externalStateSource,
8069
8550
  node,
@@ -8091,16 +8572,53 @@ function WorkbenchHostDock({
8091
8572
  workspaceId
8092
8573
  ]
8093
8574
  );
8575
+ const provideMinimizedNodePreview = useCallback10(
8576
+ (node) => {
8577
+ const minimizedDock = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock;
8578
+ if (minimizedDock?.kind !== "component") {
8579
+ return null;
8580
+ }
8581
+ const externalState = readWorkbenchHostExternalState({
8582
+ externalStateSource,
8583
+ node,
8584
+ workspaceId
8585
+ });
8586
+ return minimizedDock.providePreview({
8587
+ externalNodeState: externalState.externalNodeState,
8588
+ externalWorkspaceState: externalState.externalWorkspaceState,
8589
+ host,
8590
+ isFocused: context.focusedNodeId === node.id,
8591
+ isMinimized: node.isMinimized,
8592
+ node
8593
+ });
8594
+ },
8595
+ [
8596
+ context.focusedNodeId,
8597
+ externalStateSource,
8598
+ host,
8599
+ nodeDefinitions,
8600
+ workspaceId
8601
+ ]
8602
+ );
8603
+ const provideMinimizedNodePreviewForNode = useCallback10(
8604
+ (node) => {
8605
+ const minimizedDock = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock;
8606
+ return minimizedDock?.kind === "component" ? provideMinimizedNodePreview : void 0;
8607
+ },
8608
+ [nodeDefinitions, provideMinimizedNodePreview]
8609
+ );
8094
8610
  if (dockItems.length === 0 && presentDockItems.length === 0) {
8095
8611
  return null;
8096
8612
  }
8097
8613
  const closePopup = () => {
8098
8614
  clearHoverPanelCloseTimer();
8099
8615
  clearHoverPanelOpenTimer();
8616
+ clearLabelTooltipOpenTimer();
8100
8617
  hoverPanelRestTargetRef.current = null;
8101
8618
  setDockHoverPanelOpen(false);
8102
8619
  setActivePopup(null);
8103
8620
  setActiveHoverPanel(null);
8621
+ closeLabelTooltipImmediate();
8104
8622
  setActiveMinimizedStackPopup(null);
8105
8623
  };
8106
8624
  const scrollDockItems = (direction) => {
@@ -8110,6 +8628,7 @@ function WorkbenchHostDock({
8110
8628
  }
8111
8629
  resetDockMagnification();
8112
8630
  closeHoverPanelImmediate();
8631
+ closeLabelTooltipImmediate();
8113
8632
  hoverPanelRestTargetRef.current = null;
8114
8633
  const isVertical = dockPlacement === "left";
8115
8634
  const viewportSize = isVertical ? element.clientHeight : element.clientWidth;
@@ -8174,6 +8693,8 @@ function WorkbenchHostDock({
8174
8693
  onPointerLeave: () => {
8175
8694
  hoverPanelRestTargetRef.current = null;
8176
8695
  clearHoverPanelOpenTimer();
8696
+ clearLabelTooltipOpenTimer();
8697
+ closeLabelTooltipImmediate();
8177
8698
  closeHoverPanelImmediate();
8178
8699
  handleDockPointerLeave();
8179
8700
  flushPendingDockStateRefresh();
@@ -8234,6 +8755,7 @@ function WorkbenchHostDock({
8234
8755
  matchedNodes: resolvedEntry.matchedNodes
8235
8756
  });
8236
8757
  const hasHoverPanel = dockEntryHasHoverPanel(entry);
8758
+ const labelTooltipTarget2 = hasHoverPanel ? null : dockLabelTooltipTarget(`entry:${entry.id}`, entry.label);
8237
8759
  const dockButton2 = /* @__PURE__ */ jsx10(
8238
8760
  "button",
8239
8761
  {
@@ -8243,15 +8765,24 @@ function WorkbenchHostDock({
8243
8765
  "aria-disabled": clickResolution.kind === "blocked" ? true : void 0,
8244
8766
  className: "desktop-dock__btn",
8245
8767
  "data-interactive": clickResolution.kind === "blocked" ? "false" : "true",
8246
- title: entry.label,
8247
8768
  type: "button",
8248
8769
  onPointerDown: () => {
8249
8770
  if (clickResolution.kind === "blocked") {
8250
8771
  return;
8251
8772
  }
8773
+ if (isDockEntryClickThrottled(anchorKey)) {
8774
+ return;
8775
+ }
8252
8776
  beginDockIconInteraction(anchorKey);
8253
8777
  },
8254
8778
  onClick: (event) => {
8779
+ if (clickResolution.kind === "blocked") {
8780
+ return;
8781
+ }
8782
+ if (isDockEntryClickThrottled(anchorKey)) {
8783
+ return;
8784
+ }
8785
+ claimDockEntryClick(anchorKey);
8255
8786
  logWorkbenchDockDebug("dock.click", debugDiagnostics, {
8256
8787
  anchorKey,
8257
8788
  clickResolution,
@@ -8345,8 +8876,6 @@ function WorkbenchHostDock({
8345
8876
  })
8346
8877
  );
8347
8878
  return;
8348
- case "blocked":
8349
- return;
8350
8879
  }
8351
8880
  },
8352
8881
  children: /* @__PURE__ */ jsxs6(
@@ -8377,6 +8906,8 @@ function WorkbenchHostDock({
8377
8906
  "data-desktop-dock-slot": "true",
8378
8907
  "data-entry-state": entry.state?.kind ?? "enabled",
8379
8908
  "data-dock-hover-panel-entry-id": hasHoverPanel ? entry.id : void 0,
8909
+ "data-dock-label-tooltip-key": labelTooltipTarget2?.key,
8910
+ "data-dock-label-tooltip-label": labelTooltipTarget2?.label,
8380
8911
  "data-icon-size": entry.iconSize ?? "default",
8381
8912
  "data-node-state": resolvedEntry.dockNodeState,
8382
8913
  "data-popup-active": currentPopup ? "true" : void 0,
@@ -8387,6 +8918,9 @@ function WorkbenchHostDock({
8387
8918
  if (hasHoverPanel && !event.currentTarget.contains(event.relatedTarget)) {
8388
8919
  closeHoverPanelImmediate(entry.id);
8389
8920
  }
8921
+ if (labelTooltipTarget2 && !event.currentTarget.contains(event.relatedTarget)) {
8922
+ closeLabelTooltipImmediate(labelTooltipTarget2.key);
8923
+ }
8390
8924
  },
8391
8925
  onFocus: (event) => {
8392
8926
  if (hasHoverPanel) {
@@ -8395,15 +8929,41 @@ function WorkbenchHostDock({
8395
8929
  anchorKey,
8396
8930
  event.currentTarget
8397
8931
  );
8932
+ return;
8933
+ }
8934
+ if (labelTooltipTarget2) {
8935
+ showLabelTooltip(
8936
+ labelTooltipTarget2,
8937
+ anchorKey,
8938
+ event.currentTarget
8939
+ );
8398
8940
  }
8399
8941
  },
8400
8942
  onPointerEnter: () => {
8401
8943
  if (hasHoverPanel) {
8402
8944
  scheduleHoverPanelAfterRest(entry.id, anchorKey);
8945
+ return;
8946
+ }
8947
+ if (labelTooltipTarget2) {
8948
+ scheduleLabelTooltipAfterRest(
8949
+ labelTooltipTarget2,
8950
+ anchorKey
8951
+ );
8403
8952
  }
8404
8953
  },
8405
8954
  onPointerLeave: (event) => {
8406
8955
  if (!hasHoverPanel) {
8956
+ if (labelTooltipTarget2) {
8957
+ clearLabelTooltipOpenTimer();
8958
+ closeLabelTooltipImmediate(labelTooltipTarget2.key);
8959
+ const relatedTarget2 = event.relatedTarget;
8960
+ if (relatedTarget2 instanceof Node && dockMeasureRef.current?.contains(relatedTarget2)) {
8961
+ scheduleLabelTooltipAtPointAfterRest(
8962
+ event.clientX,
8963
+ event.clientY
8964
+ );
8965
+ }
8966
+ }
8407
8967
  return;
8408
8968
  }
8409
8969
  const relatedTarget = event.relatedTarget;
@@ -8432,15 +8992,19 @@ function WorkbenchHostDock({
8432
8992
  const slot = dockItem.item.slot;
8433
8993
  if (slot.kind === "stack") {
8434
8994
  const stackPopupActive = activeMinimizedStackPopup !== null ? true : void 0;
8995
+ const stackLabel = i18n.t("minimizedWindows");
8996
+ const labelTooltipTarget2 = dockLabelTooltipTarget(
8997
+ `minimized-stack:${slot.anchorKey}`,
8998
+ stackLabel
8999
+ );
8435
9000
  const stackButton = /* @__PURE__ */ jsx10(
8436
9001
  "button",
8437
9002
  {
8438
9003
  "aria-expanded": stackPopupActive,
8439
9004
  "aria-haspopup": "dialog",
8440
- "aria-label": i18n.t("minimizedWindows"),
9005
+ "aria-label": stackLabel,
8441
9006
  className: "desktop-dock__btn desktop-dock__minimized-btn",
8442
9007
  "data-interactive": "true",
8443
- title: i18n.t("minimizedWindows"),
8444
9008
  type: "button",
8445
9009
  onPointerDown: () => {
8446
9010
  beginDockMinimizedInteraction();
@@ -8484,9 +9048,12 @@ function WorkbenchHostDock({
8484
9048
  className: `desktop-dock__minimized-stack-layer desktop-dock__minimized-stack-layer--${index}`,
8485
9049
  dockPreviewCache,
8486
9050
  node: node2,
9051
+ providePreview: provideMinimizedNodePreviewForNode(
9052
+ node2
9053
+ ),
8487
9054
  workspaceId
8488
9055
  },
8489
- node2.id
9056
+ minimizedDockPreviewFreezeKey(node2)
8490
9057
  );
8491
9058
  }
8492
9059
  return /* @__PURE__ */ jsx10(
@@ -8512,26 +9079,65 @@ function WorkbenchHostDock({
8512
9079
  className: "desktop-dock__slot desktop-dock__slot--minimized",
8513
9080
  "data-desktop-dock-anchor-key": slot.anchorKey,
8514
9081
  "data-desktop-dock-slot": "true",
9082
+ "data-dock-label-tooltip-key": labelTooltipTarget2.key,
9083
+ "data-dock-label-tooltip-label": labelTooltipTarget2.label,
8515
9084
  "data-node-state": "minimized",
8516
9085
  "data-popup-active": stackPopupActive,
8517
9086
  "data-presence": dockItem.presence,
8518
9087
  "data-section-id": "minimized",
8519
9088
  "data-stack-dispatching": stackDispatching ? "true" : void 0,
9089
+ onBlur: (event) => {
9090
+ if (!event.currentTarget.contains(event.relatedTarget)) {
9091
+ closeLabelTooltipImmediate(labelTooltipTarget2.key);
9092
+ }
9093
+ },
9094
+ onFocus: (event) => {
9095
+ showLabelTooltip(
9096
+ labelTooltipTarget2,
9097
+ slot.anchorKey,
9098
+ event.currentTarget
9099
+ );
9100
+ },
9101
+ onPointerEnter: () => {
9102
+ scheduleLabelTooltipAfterRest(
9103
+ labelTooltipTarget2,
9104
+ slot.anchorKey
9105
+ );
9106
+ },
9107
+ onPointerLeave: (event) => {
9108
+ clearLabelTooltipOpenTimer();
9109
+ closeLabelTooltipImmediate(labelTooltipTarget2.key);
9110
+ const relatedTarget = event.relatedTarget;
9111
+ if (relatedTarget instanceof Node && dockMeasureRef.current?.contains(relatedTarget)) {
9112
+ scheduleLabelTooltipAtPointAfterRest(
9113
+ event.clientX,
9114
+ event.clientY
9115
+ );
9116
+ }
9117
+ },
8520
9118
  children: stackButton
8521
9119
  },
8522
9120
  dockItem.key
8523
9121
  );
8524
9122
  }
8525
9123
  const node = slot.node;
9124
+ const isPendingMinimizedNode = context.genie.isPendingMinimizedDockNode(node.id);
9125
+ const labelTooltipTarget = dockLabelTooltipTarget(
9126
+ `minimized-node:${node.id}`,
9127
+ node.title
9128
+ );
8526
9129
  const dockButton = /* @__PURE__ */ jsx10(
8527
9130
  "button",
8528
9131
  {
8529
9132
  "aria-label": i18n.t("launch", { title: node.title }),
8530
9133
  className: "desktop-dock__btn desktop-dock__minimized-btn",
8531
9134
  "data-interactive": "true",
8532
- title: node.title,
9135
+ disabled: isPendingMinimizedNode,
8533
9136
  type: "button",
8534
9137
  onPointerDown: () => {
9138
+ if (isPendingMinimizedNode) {
9139
+ return;
9140
+ }
8535
9141
  const restoreIntent = resolveWorkbenchMinimizedDockRestoreIntent({
8536
9142
  nodeId: node.id,
8537
9143
  slots: minimizedDockSlots,
@@ -8547,6 +9153,9 @@ function WorkbenchHostDock({
8547
9153
  beginDockMinimizedInteraction();
8548
9154
  },
8549
9155
  onClick: () => {
9156
+ if (isPendingMinimizedNode) {
9157
+ return;
9158
+ }
8550
9159
  const restoreIntent = resolveWorkbenchMinimizedDockRestoreIntent({
8551
9160
  nodeId: node.id,
8552
9161
  slots: minimizedDockSlots,
@@ -8576,11 +9185,14 @@ function WorkbenchHostDock({
8576
9185
  children: /* @__PURE__ */ jsx10(
8577
9186
  WorkbenchHostDockMinimizedNodePreview,
8578
9187
  {
8579
- capturePreview: captureMinimizedNodePreview,
8580
- dockPreviewCache,
9188
+ capturePreview: isPendingMinimizedNode ? void 0 : captureMinimizedNodePreview,
9189
+ deferPreview: isPendingMinimizedNode,
9190
+ dockPreviewCache: isPendingMinimizedNode ? void 0 : dockPreviewCache,
8581
9191
  node,
9192
+ providePreview: isPendingMinimizedNode ? void 0 : provideMinimizedNodePreviewForNode(node),
8582
9193
  workspaceId
8583
- }
9194
+ },
9195
+ minimizedDockPreviewFreezeKey(node)
8584
9196
  )
8585
9197
  }
8586
9198
  );
@@ -8592,10 +9204,42 @@ function WorkbenchHostDock({
8592
9204
  "data-collapsing": collapsingMinimizedLaunchAnchorKeys.has(slot.anchorKey) ? "true" : void 0,
8593
9205
  "data-desktop-dock-anchor-key": slot.anchorKey,
8594
9206
  "data-desktop-dock-slot": "true",
9207
+ "data-dock-label-tooltip-key": labelTooltipTarget.key,
9208
+ "data-dock-label-tooltip-label": labelTooltipTarget.label,
8595
9209
  "data-node-state": "minimized",
9210
+ "data-pending-minimize": isPendingMinimizedNode ? "true" : void 0,
8596
9211
  "data-presence": dockItem.presence,
8597
9212
  "data-promoted-from-stack": promotedNodeId === node.id ? "true" : void 0,
8598
9213
  "data-section-id": "minimized",
9214
+ onBlur: (event) => {
9215
+ if (!event.currentTarget.contains(event.relatedTarget)) {
9216
+ closeLabelTooltipImmediate(labelTooltipTarget.key);
9217
+ }
9218
+ },
9219
+ onFocus: (event) => {
9220
+ showLabelTooltip(
9221
+ labelTooltipTarget,
9222
+ slot.anchorKey,
9223
+ event.currentTarget
9224
+ );
9225
+ },
9226
+ onPointerEnter: () => {
9227
+ scheduleLabelTooltipAfterRest(
9228
+ labelTooltipTarget,
9229
+ slot.anchorKey
9230
+ );
9231
+ },
9232
+ onPointerLeave: (event) => {
9233
+ clearLabelTooltipOpenTimer();
9234
+ closeLabelTooltipImmediate(labelTooltipTarget.key);
9235
+ const relatedTarget = event.relatedTarget;
9236
+ if (relatedTarget instanceof Node && dockMeasureRef.current?.contains(relatedTarget)) {
9237
+ scheduleLabelTooltipAtPointAfterRest(
9238
+ event.clientX,
9239
+ event.clientY
9240
+ );
9241
+ }
9242
+ },
8599
9243
  children: dockButton
8600
9244
  },
8601
9245
  dockItem.key
@@ -8647,6 +9291,13 @@ function WorkbenchHostDock({
8647
9291
  handleDockPointerLeave();
8648
9292
  }
8649
9293
  }
9294
+ ) : null,
9295
+ activeLabelTooltip ? /* @__PURE__ */ jsx10(
9296
+ WorkbenchHostDockLabelTooltip,
9297
+ {
9298
+ placement: dockPlacement,
9299
+ state: activeLabelTooltip
9300
+ }
8650
9301
  ) : null
8651
9302
  ]
8652
9303
  }
@@ -8784,6 +9435,7 @@ function WorkbenchHostDock({
8784
9435
  node,
8785
9436
  workspaceId
8786
9437
  });
9438
+ const minimizedDock = nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock;
8787
9439
  return {
8788
9440
  externalNodeState: externalState.externalNodeState,
8789
9441
  externalWorkspaceState: externalState.externalWorkspaceState,
@@ -8791,10 +9443,8 @@ function WorkbenchHostDock({
8791
9443
  isFocused: context.focusedNodeId === node.id,
8792
9444
  isMinimized: true,
8793
9445
  node,
8794
- preview: nodeDefinitions.get(node.data.typeId)?.window?.minimizedDock?.capturePreview ? null : (() => {
8795
- const previewImageUrl = readCachedWorkbenchNodePreviewImage(
8796
- node.id
8797
- );
9446
+ preview: minimizedDock?.kind === "component" ? provideMinimizedNodePreview(node) ?? null : minimizedDock?.kind === "snapshot" && minimizedDock.capturePreview ? null : (() => {
9447
+ const previewImageUrl = readCachedWorkbenchNodePreviewImage(node.id);
8798
9448
  return previewImageUrl ? { kind: "image", src: previewImageUrl } : null;
8799
9449
  })(),
8800
9450
  previewRevision: null,
@@ -8862,14 +9512,69 @@ function WorkbenchHostDock({
8862
9512
  function WorkbenchHostDockMinimizedNodePreview({
8863
9513
  capturePreview,
8864
9514
  className,
9515
+ deferPreview = false,
8865
9516
  dockPreviewCache,
8866
9517
  node,
9518
+ providePreview,
8867
9519
  workspaceId
8868
9520
  }) {
9521
+ const [componentPreview, setComponentPreview] = useState8(void 0);
8869
9522
  const [previewImageUrl, setPreviewImageUrl] = useState8(
8870
- () => readCachedWorkbenchNodePreviewImage(node.id)
9523
+ () => deferPreview || providePreview ? null : readCachedWorkbenchNodePreviewImage(node.id)
8871
9524
  );
8872
9525
  useEffect9(() => {
9526
+ if (deferPreview || !providePreview || componentPreview !== void 0) {
9527
+ return void 0;
9528
+ }
9529
+ let cancelled = false;
9530
+ let frameId = null;
9531
+ let idleId = null;
9532
+ let timeoutId = null;
9533
+ const setDeferredComponentPreview = () => {
9534
+ if (cancelled) {
9535
+ return;
9536
+ }
9537
+ setComponentPreview(providePreview(node) ?? null);
9538
+ };
9539
+ const scheduler = globalThis;
9540
+ if (typeof scheduler.requestIdleCallback === "function") {
9541
+ idleId = scheduler.requestIdleCallback(setDeferredComponentPreview, {
9542
+ timeout: 250
9543
+ });
9544
+ } else if (typeof scheduler.requestAnimationFrame === "function") {
9545
+ frameId = scheduler.requestAnimationFrame(() => {
9546
+ frameId = null;
9547
+ timeoutId = globalThis.setTimeout(setDeferredComponentPreview, 0);
9548
+ });
9549
+ } else {
9550
+ timeoutId = globalThis.setTimeout(setDeferredComponentPreview, 0);
9551
+ }
9552
+ return () => {
9553
+ cancelled = true;
9554
+ if (idleId !== null && typeof scheduler.cancelIdleCallback === "function") {
9555
+ scheduler.cancelIdleCallback(idleId);
9556
+ }
9557
+ if (frameId !== null && typeof scheduler.cancelAnimationFrame === "function") {
9558
+ scheduler.cancelAnimationFrame(frameId);
9559
+ }
9560
+ if (timeoutId !== null) {
9561
+ globalThis.clearTimeout(timeoutId);
9562
+ }
9563
+ };
9564
+ }, [
9565
+ componentPreview,
9566
+ deferPreview,
9567
+ node.data.instanceId,
9568
+ node.data.instanceKey,
9569
+ node.data.typeId,
9570
+ node.id,
9571
+ node.minimizedAtUnixMs,
9572
+ providePreview
9573
+ ]);
9574
+ useEffect9(() => {
9575
+ if (deferPreview || providePreview) {
9576
+ return void 0;
9577
+ }
8873
9578
  let cancelled = false;
8874
9579
  const cachedPreviewImageUrl = readCachedWorkbenchNodePreviewImage(node.id);
8875
9580
  setPreviewImageUrl(cachedPreviewImageUrl);
@@ -8911,14 +9616,22 @@ function WorkbenchHostDockMinimizedNodePreview({
8911
9616
  };
8912
9617
  }, [
8913
9618
  capturePreview,
9619
+ deferPreview,
8914
9620
  dockPreviewCache,
8915
9621
  node.data.instanceId,
8916
9622
  node.data.instanceKey,
8917
9623
  node.data.typeId,
8918
9624
  node.id,
8919
9625
  node.minimizedAtUnixMs,
9626
+ providePreview,
8920
9627
  workspaceId
8921
9628
  ]);
9629
+ if (deferPreview) {
9630
+ return renderMinimizedDockPreviewPlaceholder(className);
9631
+ }
9632
+ if (componentPreview) {
9633
+ return renderMinimizedDockPreviewContent(componentPreview, className);
9634
+ }
8922
9635
  if (previewImageUrl) {
8923
9636
  return /* @__PURE__ */ jsx10(
8924
9637
  "span",
@@ -8941,6 +9654,9 @@ function WorkbenchHostDockMinimizedNodePreview({
8941
9654
  }
8942
9655
  );
8943
9656
  }
9657
+ return renderMinimizedDockPreviewPlaceholder(className);
9658
+ }
9659
+ function renderMinimizedDockPreviewPlaceholder(className) {
8944
9660
  return /* @__PURE__ */ jsxs6(
8945
9661
  "span",
8946
9662
  {
@@ -8954,9 +9670,104 @@ function WorkbenchHostDockMinimizedNodePreview({
8954
9670
  }
8955
9671
  );
8956
9672
  }
9673
+ function renderMinimizedDockPreviewContent(preview, className) {
9674
+ if (preview.kind === "image") {
9675
+ return /* @__PURE__ */ jsx10(
9676
+ "span",
9677
+ {
9678
+ className: [
9679
+ "desktop-dock__minimized-preview",
9680
+ "desktop-dock__minimized-preview--snapshot",
9681
+ className
9682
+ ].filter(Boolean).join(" "),
9683
+ "aria-hidden": "true",
9684
+ children: /* @__PURE__ */ jsx10(
9685
+ "img",
9686
+ {
9687
+ alt: "",
9688
+ className: "desktop-dock__minimized-preview-image",
9689
+ draggable: false,
9690
+ src: preview.src
9691
+ }
9692
+ )
9693
+ }
9694
+ );
9695
+ }
9696
+ return /* @__PURE__ */ jsx10(
9697
+ WorkbenchHostDockFrozenComponentPreview,
9698
+ {
9699
+ className,
9700
+ preview
9701
+ }
9702
+ );
9703
+ }
9704
+ function WorkbenchHostDockFrozenComponentPreview({
9705
+ className,
9706
+ preview
9707
+ }) {
9708
+ const sourceRef = useRef8(null);
9709
+ const [frozenMarkup, setFrozenMarkup] = useState8(null);
9710
+ useLayoutEffect5(() => {
9711
+ if (frozenMarkup !== null) {
9712
+ return;
9713
+ }
9714
+ setFrozenMarkup(sourceRef.current?.innerHTML ?? "");
9715
+ }, [frozenMarkup]);
9716
+ return /* @__PURE__ */ jsx10(
9717
+ "span",
9718
+ {
9719
+ className: [
9720
+ "desktop-dock__minimized-preview",
9721
+ "desktop-dock__minimized-preview--component",
9722
+ className
9723
+ ].filter(Boolean).join(" "),
9724
+ "aria-hidden": "true",
9725
+ children: frozenMarkup === null ? /* @__PURE__ */ jsx10(
9726
+ "span",
9727
+ {
9728
+ ref: sourceRef,
9729
+ className: "desktop-dock__minimized-preview-freeze-source",
9730
+ children: preview.element
9731
+ }
9732
+ ) : /* @__PURE__ */ jsx10(
9733
+ "span",
9734
+ {
9735
+ className: "desktop-dock__minimized-preview-frozen-content",
9736
+ dangerouslySetInnerHTML: { __html: frozenMarkup }
9737
+ }
9738
+ )
9739
+ }
9740
+ );
9741
+ }
9742
+ function minimizedDockPreviewFreezeKey(node) {
9743
+ return `${node.id}:${node.minimizedAtUnixMs ?? "pending"}`;
9744
+ }
8957
9745
  function dockEntryHasHoverPanel(entry) {
8958
9746
  return Boolean(entry.state?.reason?.trim()) || (entry.hoverActions?.length ?? 0) > 0;
8959
9747
  }
9748
+ function dockLabelTooltipTarget(key, label) {
9749
+ return { key, label: label.trim() };
9750
+ }
9751
+ function resolveDockLabelTooltipAnchorRect({
9752
+ dockPlacement,
9753
+ slotElement
9754
+ }) {
9755
+ const slotRect = slotElement.getBoundingClientRect();
9756
+ if (dockPlacement === "left") {
9757
+ return {
9758
+ height: DOCK_ICON_BASE_SIZE,
9759
+ left: slotRect.left,
9760
+ top: slotRect.top + (slotRect.height - DOCK_ICON_BASE_SIZE) / 2,
9761
+ width: DOCK_ICON_BASE_SIZE
9762
+ };
9763
+ }
9764
+ return {
9765
+ height: DOCK_ICON_BASE_SIZE,
9766
+ left: slotRect.left + (slotRect.width - DOCK_ICON_BASE_SIZE) / 2,
9767
+ top: slotRect.bottom - DOCK_ICON_BASE_SIZE,
9768
+ width: DOCK_ICON_BASE_SIZE
9769
+ };
9770
+ }
8960
9771
  function renderDockBadge(entry, matchedNodeCount) {
8961
9772
  const badge = entry.badge ?? (matchedNodeCount > 1 ? {
8962
9773
  kind: "count",
@@ -8973,6 +9784,26 @@ function renderDockBadge(entry, matchedNodeCount) {
8973
9784
  }
8974
9785
  return /* @__PURE__ */ jsx10("span", { className: "desktop-dock__status-badge", "data-status": badge.status });
8975
9786
  }
9787
+ function WorkbenchHostDockLabelTooltip({
9788
+ placement,
9789
+ state
9790
+ }) {
9791
+ return /* @__PURE__ */ jsx10(
9792
+ "div",
9793
+ {
9794
+ className: "desktop-dock__label-tooltip",
9795
+ "data-dock-placement": placement,
9796
+ role: "tooltip",
9797
+ style: {
9798
+ "--desktop-dock-label-tooltip-anchor-height": `${state.anchorRect.height}px`,
9799
+ "--desktop-dock-label-tooltip-anchor-left": `${state.anchorRect.left}px`,
9800
+ "--desktop-dock-label-tooltip-anchor-top": `${state.anchorRect.top}px`,
9801
+ "--desktop-dock-label-tooltip-anchor-width": `${state.anchorRect.width}px`
9802
+ },
9803
+ children: state.label
9804
+ }
9805
+ );
9806
+ }
8976
9807
  function WorkbenchHostDockHoverPanel({
8977
9808
  entry,
8978
9809
  host,
@@ -9524,6 +10355,7 @@ function dockWallpaperToneMapsEqual(left, right) {
9524
10355
  return true;
9525
10356
  }
9526
10357
  var DOCK_BOUNCE_MS = 600;
10358
+ var DOCK_ENTRY_CLICK_THROTTLE_MS = DOCK_BOUNCE_MS;
9527
10359
  function useDockBounce(slotRefs) {
9528
10360
  const timeoutsRef = useRef8(/* @__PURE__ */ new Map());
9529
10361
  const clearDockBounce = useCallback10(
@@ -9826,7 +10658,8 @@ function useWorkbenchHostSurfaceRenderers(input) {
9826
10658
  const captureNodePreviewImage = useCallback11(
9827
10659
  async (node) => {
9828
10660
  const definition = input.nodeDefinitionByType.get(node.data.typeId);
9829
- const capturePreview = definition?.window?.minimizedDock?.capturePreview;
10661
+ const minimizedDock = definition?.window?.minimizedDock;
10662
+ const capturePreview = minimizedDock?.kind === "snapshot" ? minimizedDock.capturePreview : void 0;
9830
10663
  const snapshot = input.hostSession.getSnapshot();
9831
10664
  const externalState = readWorkbenchHostExternalState({
9832
10665
  externalStateSource: input.externalStateSource,
@@ -9991,17 +10824,30 @@ function useWorkbenchHostSurfaceRenderers(input) {
9991
10824
  },
9992
10825
  [input.nodeDefinitionByType]
9993
10826
  );
10827
+ const shouldCaptureNodePreviewImage = useCallback11(
10828
+ (node) => {
10829
+ const minimizedDock = input.nodeDefinitionByType.get(node.data.typeId)?.window?.minimizedDock;
10830
+ return minimizedDock?.kind !== "component";
10831
+ },
10832
+ [input.nodeDefinitionByType]
10833
+ );
9994
10834
  const resolveDockAnchorKey = useCallback11(
9995
10835
  (node) => {
9996
10836
  if (node.isMinimized && isWorkbenchMinimizedDockEligibleNode({
9997
10837
  node,
9998
10838
  nodeDefinitions: input.nodeDefinitionByType
9999
10839
  })) {
10840
+ const snapshotNodes = input.hostSession.getSnapshot().nodes;
10841
+ const slotNodes = snapshotNodes.some(
10842
+ (snapshotNode) => snapshotNode.id === node.id
10843
+ ) ? snapshotNodes.map(
10844
+ (snapshotNode) => snapshotNode.id === node.id ? node : snapshotNode
10845
+ ) : [...snapshotNodes, node];
10000
10846
  const minimizedAnchorKey = resolveWorkbenchMinimizedDockAnchorKeyForNode({
10001
10847
  nodeId: node.id,
10002
10848
  slots: resolveWorkbenchMinimizedDockSlots({
10003
10849
  nodeDefinitions: input.nodeDefinitionByType,
10004
- nodes: input.hostSession.getSnapshot().nodes
10850
+ nodes: slotNodes
10005
10851
  })
10006
10852
  });
10007
10853
  if (minimizedAnchorKey) {
@@ -10044,6 +10890,7 @@ function useWorkbenchHostSurfaceRenderers(input) {
10044
10890
  renderTopChrome,
10045
10891
  renderWindowActions,
10046
10892
  renderWindowHeader,
10893
+ shouldCaptureNodePreviewImage,
10047
10894
  shouldKeepMinimizedNodeMounted,
10048
10895
  resolveDockAnchorKey,
10049
10896
  resolveDockPreviewCacheKey: resolveDockPreviewCacheKey2,
@@ -10223,6 +11070,7 @@ function WorkbenchHost({
10223
11070
  i18n,
10224
11071
  layoutConstraints,
10225
11072
  missionControl,
11073
+ minimizeAnimation,
10226
11074
  nodes,
10227
11075
  onDockEntryAction,
10228
11076
  onDockEntryClick,
@@ -10325,6 +11173,7 @@ function WorkbenchHost({
10325
11173
  interactive: !isHydrating,
10326
11174
  layoutConstraints,
10327
11175
  missionControlPhase: missionControlPresence.phase,
11176
+ minimizeAnimation,
10328
11177
  presentation: missionControlState?.presentation ?? null,
10329
11178
  renderBackdrop: missionControlRenderedState ? () => /* @__PURE__ */ jsx13(
10330
11179
  WorkbenchMissionControlBackdrop,
@@ -10352,6 +11201,7 @@ function WorkbenchHost({
10352
11201
  resolveFullscreenHeaderMode: surfaceRenderers.resolveFullscreenHeaderMode,
10353
11202
  resolveDockAnchorKey: surfaceRenderers.resolveDockAnchorKey,
10354
11203
  shortcutsEnabled,
11204
+ shouldCaptureNodePreviewImage: surfaceRenderers.shouldCaptureNodePreviewImage,
10355
11205
  wallpaper,
10356
11206
  windowChromeI18n,
10357
11207
  windowChromeMode: surfaceRenderers.windowChromeMode