@pie-players/pie-assessment-toolkit 0.3.45 → 0.3.47

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.
@@ -4316,7 +4316,11 @@ function create_custom_element(Component, props_definition, slots, exports, shad
4316
4316
  import { ContextConsumer } from "@pie-players/pie-context";
4317
4317
  import { createContext as createContext2 } from "@pie-players/pie-context";
4318
4318
  import { sanitizeSvgIcon } from "@pie-players/pie-players-shared/security";
4319
- import { createFocusTrap } from "@pie-players/pie-players-shared";
4319
+ import {
4320
+ createFocusTrap,
4321
+ FOCUSABLE_SELECTOR,
4322
+ isProgrammaticFocusTarget
4323
+ } from "@pie-players/pie-players-shared";
4320
4324
  import { validateCustomElementTag } from "@pie-players/pie-players-shared/pie/tag-names";
4321
4325
  var PUBLIC_VERSION2 = "5";
4322
4326
  if (typeof window !== "undefined") {
@@ -10949,10 +10953,12 @@ var calculatorToolRegistration = {
10949
10953
  draggable: true,
10950
10954
  resizable: true,
10951
10955
  closeable: true,
10952
- initialWidth: 720,
10953
- initialHeight: 620,
10954
- minWidth: 360,
10955
- minHeight: 420
10956
+ initialWidth: 380,
10957
+ initialHeight: 420,
10958
+ minWidth: 380,
10959
+ minHeight: 420,
10960
+ initialAlign: "bottom-right",
10961
+ initialMargin: 16
10956
10962
  }
10957
10963
  }
10958
10964
  ],
@@ -12768,6 +12774,7 @@ function ItemToolBar($$anchor, $$props) {
12768
12774
  const FA_PRO_HREFS = ["/_fa-pro/fontawesome.min.css", "/_fa-pro/light.min.css"];
12769
12775
  const FA_FREE_HREF = "https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/css/all.min.css";
12770
12776
  const ROBOTO_HREF = "https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap";
12777
+ const FA_HREF_PATTERN = /font.?awesome|fa-?pro/i;
12771
12778
  let ndsAssetsInstalled = false;
12772
12779
  const ensureNdsAssets = () => {
12773
12780
  if (!isBrowser || ndsAssetsInstalled)
@@ -12779,6 +12786,9 @@ function ItemToolBar($$anchor, $$props) {
12779
12786
  link2.href = ROBOTO_HREF;
12780
12787
  document.head.appendChild(link2);
12781
12788
  }
12789
+ const hostHasFa = Array.from(document.querySelectorAll('link[rel="stylesheet"][href]')).some((link2) => FA_HREF_PATTERN.test(link2.href));
12790
+ if (hostHasFa)
12791
+ return;
12782
12792
  if (!document.querySelector(`link[href="${FA_FREE_HREF}"]`)) {
12783
12793
  const link2 = document.createElement("link");
12784
12794
  link2.rel = "stylesheet";
@@ -12795,7 +12805,6 @@ function ItemToolBar($$anchor, $$props) {
12795
12805
  }
12796
12806
  };
12797
12807
  const FA_TOOLBAR_SHADOW_INSTALLED = "__pieFaToolbarShadowInstalled";
12798
- const FA_HREF_PATTERN = /font.?awesome|fa-?pro/i;
12799
12808
  const installFaInToolbarShadow = (root) => {
12800
12809
  const shadow = root.getRootNode();
12801
12810
  if (!(shadow instanceof ShadowRoot))
@@ -12817,9 +12826,6 @@ function ItemToolBar($$anchor, $$props) {
12817
12826
  const documentFaLinks = Array.from(document.querySelectorAll('link[rel="stylesheet"][href]')).filter((link2) => FA_HREF_PATTERN.test(link2.href));
12818
12827
  for (const link2 of documentFaLinks)
12819
12828
  appendLink(link2.href);
12820
- const shim = document.createElement("style");
12821
- shim.textContent = '.fa-light{font-family:"Font Awesome 6 Free";font-weight:900;}';
12822
- shadow.appendChild(shim);
12823
12829
  };
12824
12830
  const ndsIconButtonAction = (node) => {
12825
12831
  ensureNdsAssets();
@@ -13396,6 +13402,10 @@ function ItemToolBar($$anchor, $$props) {
13396
13402
  let controlsEl = null;
13397
13403
  let closeButtonEl = null;
13398
13404
  let resizeHandleEl = null;
13405
+ let startFocusGuardEl = null;
13406
+ let endFocusGuardEl = null;
13407
+ let focusGuardRedirecting = false;
13408
+ let calculatorBridgeAttached = false;
13399
13409
  let mountedContentElement = null;
13400
13410
  let dragPointerId = null;
13401
13411
  let resizePointerId = null;
@@ -13405,6 +13415,10 @@ function ItemToolBar($$anchor, $$props) {
13405
13415
  let resizeStartHeight = 0;
13406
13416
  let resizeStartX = 0;
13407
13417
  let resizeStartY = 0;
13418
+ let resizeStartShellX = 0;
13419
+ let resizeStartShellY = 0;
13420
+ let resizeCorner = null;
13421
+ const resizeHandleEls = [];
13408
13422
  let x2 = 0;
13409
13423
  let y2 = 0;
13410
13424
  let width = currentArgs.mounted.entry.shell?.initialWidth ?? 720;
@@ -13591,8 +13605,31 @@ function ItemToolBar($$anchor, $$props) {
13591
13605
  const centerShell = () => {
13592
13606
  const viewportW = window.innerWidth;
13593
13607
  const viewportH = window.innerHeight;
13594
- x2 = Math.max(0, Math.round((viewportW - width) / 2));
13595
- y2 = Math.max(0, Math.round((viewportH - height) / 2));
13608
+ const shellConfig = currentArgs.mounted.entry.shell;
13609
+ const align = shellConfig?.initialAlign ?? "center";
13610
+ const margin = shellConfig?.initialMargin ?? 16;
13611
+ const verticalMargin = margin + 60;
13612
+ switch (align) {
13613
+ case "top-left":
13614
+ x2 = margin;
13615
+ y2 = verticalMargin;
13616
+ break;
13617
+ case "top-right":
13618
+ x2 = Math.max(0, viewportW - width - margin);
13619
+ y2 = verticalMargin;
13620
+ break;
13621
+ case "bottom-left":
13622
+ x2 = margin;
13623
+ y2 = Math.max(0, viewportH - height - verticalMargin);
13624
+ break;
13625
+ case "bottom-right":
13626
+ x2 = Math.max(0, viewportW - width - margin);
13627
+ y2 = Math.max(0, viewportH - height - verticalMargin);
13628
+ break;
13629
+ default:
13630
+ x2 = Math.max(0, Math.round((viewportW - width) / 2));
13631
+ y2 = Math.max(0, Math.round((viewportH - height) / 2));
13632
+ }
13596
13633
  applyPositionAndSize();
13597
13634
  };
13598
13635
  const restoreOpenerFocus = () => {
@@ -13628,14 +13665,113 @@ function ItemToolBar($$anchor, $$props) {
13628
13665
  if (!openerEl && active && !shellEl.contains(active)) {
13629
13666
  openerEl = active;
13630
13667
  }
13668
+ const isCalculatorShellTrap = currentArgs.mounted.toolId === "calculator";
13669
+ if (isCalculatorShellTrap && !calculatorBridgeAttached) {
13670
+ document.addEventListener("keydown", onCalculatorBridgeKeydown, true);
13671
+ calculatorBridgeAttached = true;
13672
+ }
13631
13673
  focusTrapCleanup = createFocusTrap(shellEl, {
13632
13674
  initialFocus: closeButtonEl,
13633
13675
  onEscape: () => {
13634
13676
  closeShell();
13635
- }
13677
+ },
13678
+ wrap: !isCalculatorShellTrap,
13679
+ onTabExit: isCalculatorShellTrap ? (direction, event2) => {
13680
+ if (direction === "backward") {
13681
+ if (openerEl?.isConnected) {
13682
+ event2.preventDefault();
13683
+ try {
13684
+ openerEl.focus();
13685
+ } catch {}
13686
+ }
13687
+ return;
13688
+ }
13689
+ const next22 = findFirstQuestionFocusable();
13690
+ if (next22) {
13691
+ event2.preventDefault();
13692
+ try {
13693
+ next22.focus();
13694
+ } catch {}
13695
+ }
13696
+ } : undefined
13636
13697
  });
13637
13698
  };
13699
+ const findFirstQuestionFocusable = () => {
13700
+ const scope = get22(toolbarContext).getScopeElement?.() ?? null;
13701
+ if (!scope)
13702
+ return null;
13703
+ const isExcluded = (el) => {
13704
+ if (get22(toolbarRootElement) && get22(toolbarRootElement).contains(el))
13705
+ return true;
13706
+ if (shellEl && shellEl.contains(el))
13707
+ return true;
13708
+ return false;
13709
+ };
13710
+ const visit = (node2) => {
13711
+ if (node2 instanceof HTMLElement) {
13712
+ if (isExcluded(node2))
13713
+ return null;
13714
+ if (node2.matches?.(FOCUSABLE_SELECTOR) && isProgrammaticFocusTarget(node2)) {
13715
+ return node2;
13716
+ }
13717
+ }
13718
+ const shadow = node2.shadowRoot;
13719
+ if (shadow) {
13720
+ for (let i = 0;i < shadow.children.length; i++) {
13721
+ const found = visit(shadow.children[i]);
13722
+ if (found)
13723
+ return found;
13724
+ }
13725
+ }
13726
+ for (let i = 0;i < node2.children.length; i++) {
13727
+ const found = visit(node2.children[i]);
13728
+ if (found)
13729
+ return found;
13730
+ }
13731
+ return null;
13732
+ };
13733
+ return visit(scope);
13734
+ };
13735
+ const getShellFocusables = () => {
13736
+ if (!shellEl)
13737
+ return [];
13738
+ return Array.from(shellEl.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el) => el !== startFocusGuardEl && el !== endFocusGuardEl).filter(isProgrammaticFocusTarget);
13739
+ };
13740
+ const onCalculatorBridgeKeydown = (event2) => {
13741
+ if (event2.key !== "Tab")
13742
+ return;
13743
+ if (!shellEl || !currentArgs.active)
13744
+ return;
13745
+ const active = getDeepActiveElement();
13746
+ if (!active)
13747
+ return;
13748
+ if (shellEl.contains(active))
13749
+ return;
13750
+ const focusables = getShellFocusables();
13751
+ if (focusables.length === 0)
13752
+ return;
13753
+ if (event2.shiftKey) {
13754
+ const firstQuestion = findFirstQuestionFocusable();
13755
+ if (active !== firstQuestion)
13756
+ return;
13757
+ event2.preventDefault();
13758
+ try {
13759
+ focusables[focusables.length - 1].focus();
13760
+ } catch {}
13761
+ return;
13762
+ }
13763
+ if (active !== openerEl)
13764
+ return;
13765
+ event2.preventDefault();
13766
+ try {
13767
+ focusables[0].focus();
13768
+ } catch {}
13769
+ };
13638
13770
  const removeFocusTrap = () => {
13771
+ if (calculatorBridgeAttached) {
13772
+ document.removeEventListener("keydown", onCalculatorBridgeKeydown, true);
13773
+ calculatorBridgeAttached = false;
13774
+ }
13639
13775
  if (!focusTrapCleanup)
13640
13776
  return;
13641
13777
  const cleanup = focusTrapCleanup;
@@ -13653,25 +13789,28 @@ function ItemToolBar($$anchor, $$props) {
13653
13789
  if (!currentArgs.mounted.entry.shell?.draggable)
13654
13790
  return;
13655
13791
  const target = event2.target;
13656
- if (target.closest("button"))
13657
- return;
13658
- if (!shellEl)
13792
+ if (target.closest("button") || !shellEl)
13659
13793
  return;
13794
+ event2.preventDefault();
13660
13795
  dragPointerId = event2.pointerId;
13661
13796
  dragOffsetX = event2.clientX - x2;
13662
13797
  dragOffsetY = event2.clientY - y2;
13663
13798
  shellEl.setPointerCapture(event2.pointerId);
13664
13799
  bringToFront();
13665
13800
  };
13666
- const onResizePointerDown = (event2) => {
13801
+ const createResizePointerDownHandler = (corner) => (event2) => {
13667
13802
  if (!shellEl || !currentArgs.mounted.entry.shell?.resizable)
13668
13803
  return;
13804
+ event2.preventDefault();
13669
13805
  event2.stopPropagation();
13670
13806
  resizePointerId = event2.pointerId;
13807
+ resizeCorner = corner;
13671
13808
  resizeStartWidth = width;
13672
13809
  resizeStartHeight = height;
13673
13810
  resizeStartX = event2.clientX;
13674
13811
  resizeStartY = event2.clientY;
13812
+ resizeStartShellX = x2;
13813
+ resizeStartShellY = y2;
13675
13814
  shellEl.setPointerCapture(event2.pointerId);
13676
13815
  bringToFront();
13677
13816
  };
@@ -13679,6 +13818,7 @@ function ItemToolBar($$anchor, $$props) {
13679
13818
  if (!shellEl)
13680
13819
  return;
13681
13820
  if (dragPointerId === event2.pointerId) {
13821
+ event2.preventDefault();
13682
13822
  const maxX = Math.max(0, window.innerWidth - width);
13683
13823
  const maxY = Math.max(0, window.innerHeight - height);
13684
13824
  x2 = clamp(event2.clientX - dragOffsetX, 0, maxX);
@@ -13687,13 +13827,39 @@ function ItemToolBar($$anchor, $$props) {
13687
13827
  return;
13688
13828
  }
13689
13829
  if (resizePointerId === event2.pointerId) {
13830
+ event2.preventDefault();
13690
13831
  const shellConfig = currentArgs.mounted.entry.shell;
13691
13832
  const minWidth = shellConfig?.minWidth ?? 320;
13692
13833
  const minHeight = shellConfig?.minHeight ?? 240;
13693
13834
  const maxWidth = shellConfig?.maxWidth ?? window.innerWidth;
13694
13835
  const maxHeight = shellConfig?.maxHeight ?? window.innerHeight;
13695
- width = clamp(resizeStartWidth + (event2.clientX - resizeStartX), minWidth, Math.max(minWidth, Math.min(maxWidth, window.innerWidth - x2)));
13696
- height = clamp(resizeStartHeight + (event2.clientY - resizeStartY), minHeight, Math.max(minHeight, Math.min(maxHeight, window.innerHeight - y2)));
13836
+ const dx = event2.clientX - resizeStartX;
13837
+ const dy = event2.clientY - resizeStartY;
13838
+ if (resizeCorner === "se") {
13839
+ width = clamp(resizeStartWidth + dx, minWidth, Math.max(minWidth, Math.min(maxWidth, window.innerWidth - x2)));
13840
+ height = clamp(resizeStartHeight + dy, minHeight, Math.max(minHeight, Math.min(maxHeight, window.innerHeight - y2)));
13841
+ } else if (resizeCorner === "sw") {
13842
+ const rightEdge = resizeStartShellX + resizeStartWidth;
13843
+ const newWidth = clamp(resizeStartWidth - dx, minWidth, Math.min(maxWidth, rightEdge));
13844
+ x2 = rightEdge - newWidth;
13845
+ width = newWidth;
13846
+ height = clamp(resizeStartHeight + dy, minHeight, Math.max(minHeight, Math.min(maxHeight, window.innerHeight - y2)));
13847
+ } else if (resizeCorner === "ne") {
13848
+ const bottomEdge = resizeStartShellY + resizeStartHeight;
13849
+ width = clamp(resizeStartWidth + dx, minWidth, Math.max(minWidth, Math.min(maxWidth, window.innerWidth - x2)));
13850
+ const newHeight = clamp(resizeStartHeight - dy, minHeight, Math.min(maxHeight, bottomEdge));
13851
+ y2 = bottomEdge - newHeight;
13852
+ height = newHeight;
13853
+ } else if (resizeCorner === "nw") {
13854
+ const rightEdge = resizeStartShellX + resizeStartWidth;
13855
+ const bottomEdge = resizeStartShellY + resizeStartHeight;
13856
+ const newWidth = clamp(resizeStartWidth - dx, minWidth, Math.min(maxWidth, rightEdge));
13857
+ x2 = rightEdge - newWidth;
13858
+ width = newWidth;
13859
+ const newHeight = clamp(resizeStartHeight - dy, minHeight, Math.min(maxHeight, bottomEdge));
13860
+ y2 = bottomEdge - newHeight;
13861
+ height = newHeight;
13862
+ }
13697
13863
  applyShellStyle();
13698
13864
  notifyHostedResize();
13699
13865
  }
@@ -13726,14 +13892,20 @@ function ItemToolBar($$anchor, $$props) {
13726
13892
  shellEl.style.border = "1px solid var(--pie-border-light, #d1d5db)";
13727
13893
  shellEl.style.borderRadius = "12px";
13728
13894
  shellEl.style.boxShadow = "0 10px 40px color-mix(in srgb, var(--pie-black, #000) 25%, transparent)";
13729
- shellEl.style.overflow = "hidden";
13895
+ shellEl.style.overflow = "visible";
13730
13896
  shellEl.style.display = currentArgs.active ? "flex" : "none";
13731
13897
  shellEl.style.flexDirection = "column";
13898
+ shellEl.style.userSelect = "none";
13899
+ shellEl.style.webkitUserSelect = "none";
13900
+ shellEl.style.touchAction = "none";
13901
+ shellEl.setAttribute("draggable", "false");
13902
+ shellEl.addEventListener("dragstart", (e) => e.preventDefault());
13732
13903
  headerEl = document.createElement("div");
13733
13904
  headerEl.className = "pie-tool-shell__header";
13734
13905
  headerEl.style.display = "flex";
13735
13906
  headerEl.style.alignItems = "center";
13736
13907
  headerEl.style.justifyContent = "space-between";
13908
+ headerEl.style.gap = "6px";
13737
13909
  headerEl.style.padding = isCalculatorShell ? "12px 12px 12px 28px" : "10px 12px";
13738
13910
  if (isCalculatorShell) {
13739
13911
  headerEl.style.minHeight = "48px";
@@ -13748,6 +13920,13 @@ function ItemToolBar($$anchor, $$props) {
13748
13920
  }
13749
13921
  headerEl.style.cursor = currentArgs.mounted.entry.shell.draggable === false ? "default" : "move";
13750
13922
  headerEl.style.flex = "0 0 auto";
13923
+ headerEl.style.borderRadius = "12px 12px 0 0";
13924
+ headerEl.style.overflow = "hidden";
13925
+ headerEl.style.userSelect = "none";
13926
+ headerEl.style.webkitUserSelect = "none";
13927
+ headerEl.style.touchAction = "none";
13928
+ headerEl.setAttribute("draggable", "false");
13929
+ headerEl.addEventListener("dragstart", (e) => e.preventDefault());
13751
13930
  titleEl = document.createElement("span");
13752
13931
  titleEl.className = "pie-tool-shell__title";
13753
13932
  titleEl.textContent = currentArgs.mounted.entry.shell.title || currentArgs.mounted.toolId;
@@ -13894,20 +14073,100 @@ function ItemToolBar($$anchor, $$props) {
13894
14073
  contentEl.style.width = "100%";
13895
14074
  contentEl.style.flex = "1 1 auto";
13896
14075
  contentEl.style.minHeight = "0";
14076
+ contentEl.style.overflow = "hidden";
14077
+ contentEl.style.borderRadius = "0 0 12px 12px";
14078
+ if (isCalculatorShell) {
14079
+ const makeFocusGuard = (label) => {
14080
+ const el = document.createElement("div");
14081
+ el.tabIndex = 0;
14082
+ el.setAttribute("aria-hidden", "true");
14083
+ el.setAttribute("data-pie-tool-shell-focus-guard", label);
14084
+ el.style.position = "absolute";
14085
+ el.style.width = "1px";
14086
+ el.style.height = "1px";
14087
+ el.style.padding = "0";
14088
+ el.style.margin = "-1px";
14089
+ el.style.overflow = "hidden";
14090
+ el.style.clipPath = "inset(50%)";
14091
+ el.style.whiteSpace = "nowrap";
14092
+ el.style.border = "0";
14093
+ return el;
14094
+ };
14095
+ startFocusGuardEl = makeFocusGuard("start");
14096
+ endFocusGuardEl = makeFocusGuard("end");
14097
+ startFocusGuardEl.addEventListener("focus", (event2) => {
14098
+ if (focusGuardRedirecting)
14099
+ return;
14100
+ focusGuardRedirecting = true;
14101
+ try {
14102
+ event2.stopPropagation();
14103
+ if (openerEl?.isConnected) {
14104
+ try {
14105
+ openerEl.focus();
14106
+ } catch {}
14107
+ }
14108
+ } finally {
14109
+ queueMicrotask(() => {
14110
+ focusGuardRedirecting = false;
14111
+ });
14112
+ }
14113
+ });
14114
+ endFocusGuardEl.addEventListener("focus", (event2) => {
14115
+ if (focusGuardRedirecting)
14116
+ return;
14117
+ focusGuardRedirecting = true;
14118
+ try {
14119
+ event2.stopPropagation();
14120
+ const next22 = findFirstQuestionFocusable();
14121
+ if (next22) {
14122
+ try {
14123
+ next22.focus();
14124
+ } catch {}
14125
+ }
14126
+ } finally {
14127
+ queueMicrotask(() => {
14128
+ focusGuardRedirecting = false;
14129
+ });
14130
+ }
14131
+ });
14132
+ shellEl.appendChild(startFocusGuardEl);
14133
+ }
13897
14134
  shellEl.appendChild(headerEl);
13898
14135
  shellEl.appendChild(contentEl);
14136
+ if (isCalculatorShell && endFocusGuardEl) {
14137
+ shellEl.appendChild(endFocusGuardEl);
14138
+ }
13899
14139
  if (currentArgs.mounted.entry.shell.resizable !== false) {
13900
- resizeHandleEl = document.createElement("div");
13901
- resizeHandleEl.className = "pie-tool-shell__resize";
13902
- resizeHandleEl.style.position = "absolute";
13903
- resizeHandleEl.style.right = "0";
13904
- resizeHandleEl.style.bottom = "0";
13905
- resizeHandleEl.style.width = "24px";
13906
- resizeHandleEl.style.height = "24px";
13907
- resizeHandleEl.style.cursor = "nwse-resize";
13908
- resizeHandleEl.style.background = "linear-gradient(135deg, transparent 0%, transparent 40%, rgba(0,0,0,0.35) 40%, rgba(0,0,0,0.35) 60%, transparent 60%, transparent 100%)";
13909
- shellEl.appendChild(resizeHandleEl);
13910
- resizeHandleEl.addEventListener("pointerdown", onResizePointerDown);
14140
+ const addResizeHandle = (corner, top, right, bottom, left, cursor, gradientAngle) => {
14141
+ const el = document.createElement("div");
14142
+ el.className = "pie-tool-shell__resize";
14143
+ el.style.position = "absolute";
14144
+ el.style.width = "24px";
14145
+ el.style.height = "24px";
14146
+ el.style.cursor = cursor;
14147
+ el.style.zIndex = "10";
14148
+ el.style.touchAction = "none";
14149
+ el.setAttribute("draggable", "false");
14150
+ if (top !== null)
14151
+ el.style.top = top;
14152
+ if (right !== null)
14153
+ el.style.right = right;
14154
+ if (bottom !== null)
14155
+ el.style.bottom = bottom;
14156
+ if (left !== null)
14157
+ el.style.left = left;
14158
+ if (gradientAngle !== null) {
14159
+ el.style.background = `linear-gradient(${gradientAngle}, transparent 0%, transparent 40%, rgba(0,0,0,0.35) 40%, rgba(0,0,0,0.35) 60%, transparent 60%, transparent 100%)`;
14160
+ }
14161
+ const handler = createResizePointerDownHandler(corner);
14162
+ el.addEventListener("pointerdown", handler);
14163
+ shellEl.appendChild(el);
14164
+ resizeHandleEls.push({ el, handler });
14165
+ };
14166
+ addResizeHandle("se", null, "0", "0", null, "nwse-resize", null);
14167
+ addResizeHandle("nw", "0", null, null, "0", "nwse-resize", "135deg");
14168
+ addResizeHandle("ne", "0", "0", null, null, "nesw-resize", null);
14169
+ addResizeHandle("sw", null, null, "0", "0", "nesw-resize", null);
13911
14170
  }
13912
14171
  headerEl.addEventListener("pointerdown", onHeaderPointerDown);
13913
14172
  shellEl.addEventListener("pointermove", onShellPointerMove);
@@ -13948,10 +14207,15 @@ function ItemToolBar($$anchor, $$props) {
13948
14207
  if (focusTrapCleanup) {
13949
14208
  removeFocusTrap();
13950
14209
  }
13951
- openerEl = null;
13952
- if (resizeHandleEl) {
13953
- resizeHandleEl.removeEventListener("pointerdown", onResizePointerDown);
14210
+ if (calculatorBridgeAttached) {
14211
+ document.removeEventListener("keydown", onCalculatorBridgeKeydown, true);
14212
+ calculatorBridgeAttached = false;
14213
+ }
14214
+ for (const { el, handler } of resizeHandleEls) {
14215
+ el.removeEventListener("pointerdown", handler);
13954
14216
  }
14217
+ openerEl = null;
14218
+ resizeHandleEls.length = 0;
13955
14219
  if (headerEl) {
13956
14220
  headerEl.removeEventListener("pointerdown", onHeaderPointerDown);
13957
14221
  headerEl.onkeydown = null;
@@ -14158,9 +14422,9 @@ function ItemToolBar($$anchor, $$props) {
14158
14422
  append2($$anchor7, span_4);
14159
14423
  };
14160
14424
  var alternate_1 = ($$anchor7) => {
14161
- var i = root_5();
14162
- template_effect2(() => set_class2(i, 1, `icon icon-${get22(item2).icon}`, "svelte-rnx3ie"));
14163
- append2($$anchor7, i);
14425
+ var i_1 = root_5();
14426
+ template_effect2(() => set_class2(i_1, 1, `icon icon-${get22(item2).icon}`, "svelte-rnx3ie"));
14427
+ append2($$anchor7, i_1);
14164
14428
  };
14165
14429
  if_block2(node_8, ($$render) => {
14166
14430
  if (get22(fallbackIcon))
@@ -14250,9 +14514,9 @@ function ItemToolBar($$anchor, $$props) {
14250
14514
  append2($$anchor7, span_7);
14251
14515
  };
14252
14516
  var alternate_3 = ($$anchor7) => {
14253
- var i_1 = root_5();
14254
- template_effect2(() => set_class2(i_1, 1, `icon icon-${get22(item2).icon}`, "svelte-rnx3ie"));
14255
- append2($$anchor7, i_1);
14517
+ var i_2 = root_5();
14518
+ template_effect2(() => set_class2(i_2, 1, `icon icon-${get22(item2).icon}`, "svelte-rnx3ie"));
14519
+ append2($$anchor7, i_2);
14256
14520
  };
14257
14521
  if_block2(node_11, ($$render) => {
14258
14522
  if (get22(fallbackIcon))
@@ -87,6 +87,11 @@ export interface ToolWindowShellAction {
87
87
  iconSvg?: string;
88
88
  onClick: () => void;
89
89
  }
90
+ /**
91
+ * Alignment corner for the initial shell position.
92
+ * The shell is offset by `initialMargin` (default 16 px) from the chosen corner.
93
+ */
94
+ export type ToolWindowShellAlign = 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
90
95
  export interface ToolWindowShellConfig {
91
96
  title?: string;
92
97
  draggable?: boolean;
@@ -98,6 +103,10 @@ export interface ToolWindowShellConfig {
98
103
  minHeight?: number;
99
104
  maxWidth?: number;
100
105
  maxHeight?: number;
106
+ /** Initial placement of the shell. Defaults to `'center'`. */
107
+ initialAlign?: ToolWindowShellAlign;
108
+ /** Distance (px) from the viewport edge when using a corner align. Defaults to 16. */
109
+ initialMargin?: number;
101
110
  actions?: ToolWindowShellAction[];
102
111
  }
103
112
  export interface HostedToolContext {