@muten/shadcn 0.2.16 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muten/shadcn",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "shadcn-style component registry for muten - own-the-source parts you add with `muten add`.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -5,12 +5,17 @@
5
5
  // MODALS STACK (a receipt opened over a cita): Back, Esc and the focus trap belong to the TOP one only, and the page's
6
6
  // scroll is unlocked when the last one closes. Each modal used to listen to every Back: closing the receipt went back
7
7
  // in history and that Back also closed the cita under it, leaving the agenda without its buttons (21-10-2026).
8
- const stack = (globalThis.__cxModals ||= { list: [], skip: 0, wired: false });
8
+ // ONE CLOSES AS THE NEXT OPENS («Añadir» → the link's editor): the closing one's history.back() lands after the new one's
9
+ // pushState, and Chrome counts that Back from where it was asked, so it stepped over the new entry. The new modal then
10
+ // closed with a Back that was not its own and took the page one screen back (/shop/import, 31-10-2026). So a modal that
11
+ // opens while a closing Back is still on its way pushes its entry once that Back has landed (`after`).
12
+ const stack = (globalThis.__cxModals ||= { list: [], skip: 0, after: [], wired: false });
13
+ stack.after ||= [];
9
14
  if (!stack.wired) {
10
15
  stack.wired = true;
11
16
  addEventListener('popstate', () => {
12
17
  // the history.back() a modal makes when it closes itself is its own, not a Back for the one under it
13
- if (stack.skip > 0) { stack.skip -= 1; return; }
18
+ if (stack.skip > 0) { stack.skip -= 1; if (stack.skip === 0) stack.after.splice(0).forEach((push) => push()); return; }
14
19
  stack.list.at(-1)?.onPop();
15
20
  });
16
21
  }
@@ -24,7 +29,8 @@ export function mount(el, inputs, on) {
24
29
  // the auto mode is resolved NOW (and again when the width crosses the phone line while closed), never at the moment
25
30
  // of opening: a dialog that only learns it is a dialog as it opens animates its centring from the corner
26
31
  const resolve = () => { if (auto && !isOpen) mdl.dataset.mode = phone.matches ? 'drawer' : 'dialog'; };
27
- let isOpen = false, pushed = false, lastFocus = null;
32
+ // pushedAt: the address when this modal added its step; a page that moves the address to close it took that step's place
33
+ let isOpen = false, pushed = false, pushedAt = '', lastFocus = null;
28
34
  const me = { onPop: () => { if (isOpen) { pushed = false; close(); } } };
29
35
  queueMicrotask(() => resolve()); phone.addEventListener('change', resolve);
30
36
  // the footer sticks under the scrolling body, not inside it
@@ -59,7 +65,8 @@ export function mount(el, inputs, on) {
59
65
  document.documentElement.classList.add('cx-locked');
60
66
  // on the phone, focusing a field would throw the keyboard over the sheet: focus the sheet itself
61
67
  requestAnimationFrame(() => { ((mdl.dataset.mode === 'dialog' && focusables().find((x) => x.matches('input, textarea'))) || mdl).focus({ preventScroll: true }); });
62
- history.pushState({ cxModal: 1 }, ''); pushed = true;
68
+ const push = () => { if (!isOpen || pushed) return; history.pushState({ cxModal: 1 }, ''); pushed = true; pushedAt = location.href; };
69
+ if (stack.skip > 0) stack.after.push(push); else push();
63
70
  };
64
71
  const shut = () => {
65
72
  if (!isOpen) return; isOpen = false;
@@ -67,7 +74,10 @@ export function mount(el, inputs, on) {
67
74
  stack.list = stack.list.filter((one) => one !== me);
68
75
  if (stack.list.length === 0) document.documentElement.classList.remove('cx-locked');
69
76
  lastFocus?.focus?.({ preventScroll: true });
70
- if (pushed) { pushed = false; stack.skip += 1; history.back(); }
77
+ // A PAGE THAT CLOSES IT BY MOVING THE ADDRESS (a sheet kept in ?sheet=, closed with url.set): its new step already
78
+ // stands where the modal's was, and going back from it lands on the address that opened the sheet, which opened it
79
+ // again (Platform's «Avisar» never closed, 1 Nov 2026). The modal goes back only from its own step.
80
+ if (pushed) { pushed = false; if (location.href === pushedAt) { stack.skip += 1; history.back(); } }
71
81
  };
72
82
  mdl.tabIndex = -1;
73
83
  // A link inside (a menu in a drawer): close first, then go. Closing undoes the history entry the modal pushed, and