@shellui/core 0.2.0-beta.4 → 0.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shellui/core",
3
- "version": "0.2.0-beta.4",
3
+ "version": "0.2.0",
4
4
  "description": "ShellUI Core - Core React application runtime",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -58,7 +58,7 @@
58
58
  "workbox-routing": "^7.4.0",
59
59
  "workbox-strategies": "^7.4.0",
60
60
  "workbox-window": "^7.4.0",
61
- "@shellui/sdk": "0.2.0-beta.4"
61
+ "@shellui/sdk": "0.2.0"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "react": "^18.0.0 || ^19.0.0",
@@ -14,38 +14,37 @@ const TOAST_BUTTON_SELECTOR = '[data-close-button], [data-cancel], [data-action]
14
14
  */
15
15
  function useToastButtonPointerFix() {
16
16
  useEffect(() => {
17
- const onPointerDown: (e: Event) => void = (e) => {
17
+ const onPointerDown = (e: Event) => {
18
18
  const ev = e as PointerEvent;
19
- const target = ev.target as HTMLElement;
20
- const button = target.closest?.(TOAST_BUTTON_SELECTOR);
21
- if (!button || button.getAttribute('data-disabled') === 'true') return;
22
- // Only programmatically click for touch/pen to avoid double-firing on mouse
23
- if (ev.pointerType === 'touch' || ev.pointerType === 'pen') {
24
- (button as HTMLButtonElement).click();
25
- }
19
+ // Only trigger programmatic click for touch/pen (iPad etc.); mouse gets native click.
20
+ if (ev.pointerType !== 'touch' && ev.pointerType !== 'pen') return;
21
+ // When a modal is open (e.g. Radix), body has pointer-events: none so the toaster
22
+ // may never receive the event on iPad. Use document capture + elementFromPoint so we
23
+ // still detect touches over the toaster and trigger the button.
24
+ const toaster = document.querySelector('[data-sonner-toaster]');
25
+ if (!toaster) return;
26
+ const elementUnderPoint = document.elementFromPoint(ev.clientX, ev.clientY);
27
+ if (!elementUnderPoint?.isConnected) return;
28
+ const button = (elementUnderPoint as HTMLElement).closest?.(TOAST_BUTTON_SELECTOR);
29
+ if (!button || !toaster.contains(button) || button.getAttribute('data-disabled') === 'true')
30
+ return;
31
+ ev.preventDefault();
32
+ ev.stopImmediatePropagation();
33
+ const clickEvent = new MouseEvent('click', {
34
+ bubbles: true,
35
+ cancelable: true,
36
+ view: ev.view ?? window,
37
+ detail: 1,
38
+ clientX: ev.clientX,
39
+ clientY: ev.clientY,
40
+ screenX: ev.screenX,
41
+ screenY: ev.screenY,
42
+ });
43
+ button.dispatchEvent(clickEvent);
26
44
  };
27
45
 
28
- function attach(toaster: Element) {
29
- toaster.addEventListener('pointerdown', onPointerDown, true);
30
- return () => toaster.removeEventListener('pointerdown', onPointerDown, true);
31
- }
32
-
33
- let toaster = document.querySelector('[data-sonner-toaster]');
34
- if (!toaster) {
35
- let cancelled = false;
36
- let cleanup: (() => void) | undefined;
37
- const id = requestAnimationFrame(() => {
38
- if (cancelled) return;
39
- toaster = document.querySelector('[data-sonner-toaster]');
40
- if (toaster) cleanup = attach(toaster);
41
- });
42
- return () => {
43
- cancelled = true;
44
- cancelAnimationFrame(id);
45
- cleanup?.();
46
- };
47
- }
48
- return attach(toaster);
46
+ document.addEventListener('pointerdown', onPointerDown, true);
47
+ return () => document.removeEventListener('pointerdown', onPointerDown, true);
49
48
  }, []);
50
49
  }
51
50
 
package/src/index.css CHANGED
@@ -235,6 +235,12 @@
235
235
  outline-color: hsl(var(--ring) / 0.5);
236
236
  }
237
237
 
238
+ /* Toaster must receive pointer events when a modal has body pointer-events: none (e.g. Radix).
239
+ * Without this, pointerdown never fires on iPad when a modal is open. */
240
+ [data-sonner-toaster] {
241
+ pointer-events: auto !important;
242
+ }
243
+
238
244
  /* Ensure Sonner toasts use theme variables - override Sonner defaults */
239
245
  [data-sonner-toast] {
240
246
  background-color: hsl(var(--background)) !important;