@particle-academy/react-fancy 5.61.0 → 5.62.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.
Files changed (156) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/autocomplete.cjs +3 -3
  3. package/dist/autocomplete.js +2 -2
  4. package/dist/breadcrumbs.cjs +3 -3
  5. package/dist/breadcrumbs.js +2 -2
  6. package/dist/{chunk-KNKOSMOQ.cjs → chunk-35S5BTZH.cjs} +4 -4
  7. package/dist/{chunk-KNKOSMOQ.cjs.map → chunk-35S5BTZH.cjs.map} +1 -1
  8. package/dist/{chunk-O4HZVZMY.cjs → chunk-4GOOSZEK.cjs} +86 -24
  9. package/dist/chunk-4GOOSZEK.cjs.map +1 -0
  10. package/dist/{chunk-3I6PE2US.cjs → chunk-4XHG6Q42.cjs} +11 -11
  11. package/dist/{chunk-3I6PE2US.cjs.map → chunk-4XHG6Q42.cjs.map} +1 -1
  12. package/dist/{chunk-3AYRLFNO.js → chunk-A67EDGC7.js} +3 -3
  13. package/dist/{chunk-3AYRLFNO.js.map → chunk-A67EDGC7.js.map} +1 -1
  14. package/dist/{chunk-4HUD33OP.cjs → chunk-A6HWKQ4D.cjs} +4 -4
  15. package/dist/{chunk-4HUD33OP.cjs.map → chunk-A6HWKQ4D.cjs.map} +1 -1
  16. package/dist/{chunk-P6V4QWJK.cjs → chunk-AJPYGRLA.cjs} +4 -4
  17. package/dist/{chunk-P6V4QWJK.cjs.map → chunk-AJPYGRLA.cjs.map} +1 -1
  18. package/dist/{chunk-LMOPAY7Q.js → chunk-ARO2DNGS.js} +3 -3
  19. package/dist/{chunk-LMOPAY7Q.js.map → chunk-ARO2DNGS.js.map} +1 -1
  20. package/dist/{chunk-N7KUGFRG.js → chunk-BTNF3QBR.js} +4 -4
  21. package/dist/{chunk-N7KUGFRG.js.map → chunk-BTNF3QBR.js.map} +1 -1
  22. package/dist/{chunk-K6NADZ7O.cjs → chunk-CMC2TOEQ.cjs} +6 -6
  23. package/dist/{chunk-K6NADZ7O.cjs.map → chunk-CMC2TOEQ.cjs.map} +1 -1
  24. package/dist/{chunk-NDLESFUH.js → chunk-ELFTEJBT.js} +3 -3
  25. package/dist/{chunk-NDLESFUH.js.map → chunk-ELFTEJBT.js.map} +1 -1
  26. package/dist/{chunk-PKFEJWVI.js → chunk-EUVWYDFN.js} +3 -3
  27. package/dist/{chunk-PKFEJWVI.js.map → chunk-EUVWYDFN.js.map} +1 -1
  28. package/dist/{chunk-CEZVKKYW.js → chunk-EVIHLWPG.js} +4 -4
  29. package/dist/{chunk-CEZVKKYW.js.map → chunk-EVIHLWPG.js.map} +1 -1
  30. package/dist/{chunk-ULG4OA2T.js → chunk-FVI4JDLA.js} +3 -3
  31. package/dist/{chunk-ULG4OA2T.js.map → chunk-FVI4JDLA.js.map} +1 -1
  32. package/dist/{chunk-IY6LVALS.js → chunk-GEQKNV7E.js} +3 -3
  33. package/dist/{chunk-IY6LVALS.js.map → chunk-GEQKNV7E.js.map} +1 -1
  34. package/dist/{chunk-4FJWHVC7.js → chunk-GR2WKBER.js} +4 -2
  35. package/dist/chunk-GR2WKBER.js.map +1 -0
  36. package/dist/{chunk-UGXBTIV5.js → chunk-GZ5Z56QK.js} +4 -4
  37. package/dist/{chunk-UGXBTIV5.js.map → chunk-GZ5Z56QK.js.map} +1 -1
  38. package/dist/{chunk-Z5OTOYWI.cjs → chunk-HANQYZW2.cjs} +4 -4
  39. package/dist/{chunk-Z5OTOYWI.cjs.map → chunk-HANQYZW2.cjs.map} +1 -1
  40. package/dist/{chunk-UBEOB55O.js → chunk-JG2DJK5A.js} +3 -3
  41. package/dist/{chunk-UBEOB55O.js.map → chunk-JG2DJK5A.js.map} +1 -1
  42. package/dist/{chunk-J4FKJ4IR.cjs → chunk-LFC2DL6H.cjs} +4 -4
  43. package/dist/{chunk-J4FKJ4IR.cjs.map → chunk-LFC2DL6H.cjs.map} +1 -1
  44. package/dist/{chunk-FU6K7XXZ.cjs → chunk-MKGWHSNV.cjs} +4 -4
  45. package/dist/{chunk-FU6K7XXZ.cjs.map → chunk-MKGWHSNV.cjs.map} +1 -1
  46. package/dist/{chunk-BHUSI56C.js → chunk-MVVHUTXA.js} +3 -3
  47. package/dist/{chunk-BHUSI56C.js.map → chunk-MVVHUTXA.js.map} +1 -1
  48. package/dist/{chunk-UJZJBHMH.js → chunk-NILA2LZY.js} +3 -3
  49. package/dist/{chunk-UJZJBHMH.js.map → chunk-NILA2LZY.js.map} +1 -1
  50. package/dist/{chunk-SHF44YGG.js → chunk-NSJBVV7R.js} +3 -3
  51. package/dist/{chunk-SHF44YGG.js.map → chunk-NSJBVV7R.js.map} +1 -1
  52. package/dist/{chunk-QXMQVLRQ.cjs → chunk-OASSZI6M.cjs} +4 -2
  53. package/dist/chunk-OASSZI6M.cjs.map +1 -0
  54. package/dist/chunk-OUYC6EIL.cjs +66 -0
  55. package/dist/chunk-OUYC6EIL.cjs.map +1 -0
  56. package/dist/{chunk-5JFA7NYE.js → chunk-PXZRYL5I.js} +3 -3
  57. package/dist/{chunk-5JFA7NYE.js.map → chunk-PXZRYL5I.js.map} +1 -1
  58. package/dist/{chunk-TYTENEJQ.cjs → chunk-QNQNGARW.cjs} +6 -6
  59. package/dist/{chunk-TYTENEJQ.cjs.map → chunk-QNQNGARW.cjs.map} +1 -1
  60. package/dist/{chunk-74MEJWMH.js → chunk-QP35Z2WB.js} +3 -3
  61. package/dist/{chunk-74MEJWMH.js.map → chunk-QP35Z2WB.js.map} +1 -1
  62. package/dist/{chunk-NORVXHRU.js → chunk-QTS4Q2NK.js} +3 -3
  63. package/dist/{chunk-NORVXHRU.js.map → chunk-QTS4Q2NK.js.map} +1 -1
  64. package/dist/{chunk-4TTBPEQX.cjs → chunk-QWNZZPFL.cjs} +8 -8
  65. package/dist/{chunk-4TTBPEQX.cjs.map → chunk-QWNZZPFL.cjs.map} +1 -1
  66. package/dist/{chunk-7KTBVKNO.cjs → chunk-R6URPHEP.cjs} +4 -4
  67. package/dist/{chunk-7KTBVKNO.cjs.map → chunk-R6URPHEP.cjs.map} +1 -1
  68. package/dist/{chunk-4JLFIPHZ.js → chunk-RP43ZFZP.js} +8 -3
  69. package/dist/chunk-RP43ZFZP.js.map +1 -0
  70. package/dist/{chunk-RRMQGTVB.cjs → chunk-SYEHWUM5.cjs} +6 -6
  71. package/dist/{chunk-RRMQGTVB.cjs.map → chunk-SYEHWUM5.cjs.map} +1 -1
  72. package/dist/{chunk-IHQHTJNN.js → chunk-SZH7TFME.js} +4 -4
  73. package/dist/{chunk-IHQHTJNN.js.map → chunk-SZH7TFME.js.map} +1 -1
  74. package/dist/{chunk-JOWAS5A5.cjs → chunk-TQGRXJ74.cjs} +9 -9
  75. package/dist/{chunk-JOWAS5A5.cjs.map → chunk-TQGRXJ74.cjs.map} +1 -1
  76. package/dist/{chunk-6GBO7R25.cjs → chunk-UJRMY54A.cjs} +4 -4
  77. package/dist/{chunk-6GBO7R25.cjs.map → chunk-UJRMY54A.cjs.map} +1 -1
  78. package/dist/{chunk-ZPBCZPMD.cjs → chunk-VQJ5LJJH.cjs} +8 -3
  79. package/dist/chunk-VQJ5LJJH.cjs.map +1 -0
  80. package/dist/{chunk-MSGKIWYX.js → chunk-VZNBTCGA.js} +3 -3
  81. package/dist/{chunk-MSGKIWYX.js.map → chunk-VZNBTCGA.js.map} +1 -1
  82. package/dist/{chunk-M6MGQI6G.cjs → chunk-WKPBCB67.cjs} +4 -4
  83. package/dist/{chunk-M6MGQI6G.cjs.map → chunk-WKPBCB67.cjs.map} +1 -1
  84. package/dist/{chunk-QMCMRQ2G.cjs → chunk-WVSHAJKI.cjs} +7 -7
  85. package/dist/{chunk-QMCMRQ2G.cjs.map → chunk-WVSHAJKI.cjs.map} +1 -1
  86. package/dist/chunk-YX6FTJ6N.js +62 -0
  87. package/dist/chunk-YX6FTJ6N.js.map +1 -0
  88. package/dist/{chunk-HRYM76ZE.cjs → chunk-Z6LYBL5L.cjs} +9 -9
  89. package/dist/{chunk-HRYM76ZE.cjs.map → chunk-Z6LYBL5L.cjs.map} +1 -1
  90. package/dist/{chunk-3DMVK74Q.cjs → chunk-Z7SQMQTF.cjs} +4 -4
  91. package/dist/{chunk-3DMVK74Q.cjs.map → chunk-Z7SQMQTF.cjs.map} +1 -1
  92. package/dist/{chunk-NE3BZV3F.js → chunk-ZQ3VXRUY.js} +86 -24
  93. package/dist/chunk-ZQ3VXRUY.js.map +1 -0
  94. package/dist/command.cjs +4 -4
  95. package/dist/command.js +2 -2
  96. package/dist/composer.cjs +6 -6
  97. package/dist/composer.js +4 -4
  98. package/dist/context-menu.cjs +4 -4
  99. package/dist/context-menu.js +2 -2
  100. package/dist/drawer.cjs +4 -4
  101. package/dist/drawer.js +2 -2
  102. package/dist/dropdown.cjs +4 -4
  103. package/dist/dropdown.js +2 -2
  104. package/dist/editor.cjs +6 -6
  105. package/dist/editor.d.cts +1 -1
  106. package/dist/editor.d.ts +1 -1
  107. package/dist/editor.js +4 -4
  108. package/dist/full-screen.cjs +10 -9
  109. package/dist/full-screen.d.cts +5 -2
  110. package/dist/full-screen.d.ts +5 -2
  111. package/dist/full-screen.js +4 -3
  112. package/dist/index.cjs +81 -73
  113. package/dist/index.d.cts +2 -4
  114. package/dist/index.d.ts +2 -4
  115. package/dist/index.js +22 -22
  116. package/dist/input.cjs +5 -5
  117. package/dist/input.js +4 -4
  118. package/dist/inputs.cjs +7 -7
  119. package/dist/inputs.js +5 -5
  120. package/dist/json-editor.cjs +17 -17
  121. package/dist/json-editor.js +6 -6
  122. package/dist/mobile-menu.cjs +5 -5
  123. package/dist/mobile-menu.js +3 -3
  124. package/dist/modal.cjs +4 -4
  125. package/dist/modal.js +2 -2
  126. package/dist/paste-pills.cjs +16 -16
  127. package/dist/paste-pills.js +3 -3
  128. package/dist/popover.cjs +4 -4
  129. package/dist/popover.js +2 -2
  130. package/dist/prompt-input.cjs +6 -6
  131. package/dist/prompt-input.js +5 -5
  132. package/dist/reason-tag.cjs +4 -4
  133. package/dist/reason-tag.js +3 -3
  134. package/dist/select.cjs +3 -3
  135. package/dist/select.js +2 -2
  136. package/dist/sidebar.cjs +2 -2
  137. package/dist/sidebar.js +2 -2
  138. package/dist/styles.css +9 -0
  139. package/dist/styles.css.map +1 -1
  140. package/dist/tooltip.cjs +3 -2
  141. package/dist/tooltip.js +2 -1
  142. package/dist/{use-full-screen-H2j6qXDB.d.ts → use-full-screen-BUke36LI.d.cts} +36 -1
  143. package/dist/{use-full-screen-H2j6qXDB.d.cts → use-full-screen-BUke36LI.d.ts} +36 -1
  144. package/docs/FullScreen.md +15 -4
  145. package/docs/hooks.md +9 -3
  146. package/package.json +1 -1
  147. package/dist/chunk-4FJWHVC7.js.map +0 -1
  148. package/dist/chunk-4JLFIPHZ.js.map +0 -1
  149. package/dist/chunk-JXE5XID6.js +0 -19
  150. package/dist/chunk-JXE5XID6.js.map +0 -1
  151. package/dist/chunk-NE3BZV3F.js.map +0 -1
  152. package/dist/chunk-O4HZVZMY.cjs.map +0 -1
  153. package/dist/chunk-QXMQVLRQ.cjs.map +0 -1
  154. package/dist/chunk-RXDRYWVD.cjs +0 -21
  155. package/dist/chunk-RXDRYWVD.cjs.map +0 -1
  156. package/dist/chunk-ZPBCZPMD.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -11,6 +11,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [5.62.0] - 2026-10-26
15
+
16
+ ### Fixed
17
+
18
+ - **Escape closes the innermost open layer, and only that one.** Found in
19
+ DeckEditor on 5.61.1. In full screen, open the toolbar's Shape menu and
20
+ press Escape: full screen exited and the menu stayed open. The surface's key
21
+ handler ran before the menu's `document` listener, so the menu had not
22
+ claimed the key yet when the surface checked. The same race closed a Modal
23
+ along with a Dropdown opened inside it. Now every
24
+ `useEscapeKey(handler, open)` call registers a layer, and one document
25
+ listener hands each Escape to the innermost layer. The innermost layer is
26
+ the most recently opened one. Layers inside a full-screen surface count as
27
+ inside it whatever order they opened in. The surface yields while any of
28
+ them is open. Covered by tests for Dropdown, listbox Select, Popover,
29
+ Tooltip, a Modal opened inside the surface, and a Dropdown inside a Modal.
30
+ Measured in Chromium, DeckEditor in full screen inside `transform:
31
+ translateX(0)` with the Shape menu open:
32
+ - 5.61.1: Escape #1 exits full screen and leaves the menu open.
33
+ - Now: Escape #1 closes the menu only, with full screen still on and focus
34
+ on the Shape trigger. Escape #2 exits.
35
+ - **`Tooltip` dismisses on Escape** (WCAG 1.4.13), as the innermost layer.
36
+ - **`FullScreen.Toggle` sets its own text colour**: the kit's icon-button
37
+ tokens (`--fancy-text-muted` / `--fancy-text-soft`, light and dark). It
38
+ inherited before, so on a dark toolbar with a dark page text colour it was
39
+ black on black. Plain utilities, so a consumer `text-*` class replaces it.
40
+
41
+ ### Added
42
+
43
+ - `useEscapeLayer(handler, enabled, scope?)` and `EscapeLayerContext`, for
44
+ surfaces in sibling packages that other layers open inside.
45
+ `useFullScreen()` also returns `escapeScope`, which `FullScreenProvider`
46
+ provides.
47
+
48
+ **What to do.** For most apps, nothing. If you used `useEscapeKey` for
49
+ something that should run on every Escape regardless of open layers (a
50
+ page-level "clear selection", for example), it now runs only while no layer
51
+ is open above it. That is usually what you want. If it is not, use your own
52
+ `keydown` listener. A full-screen surface built on `useFullScreen()` should
53
+ render `FullScreenProvider`; without it, a menu opened inside still closes
54
+ first only if it opened after the surface went full screen.
55
+
56
+ ## [5.61.1] - 2026-10-26
57
+
58
+ ### Fixed
59
+
60
+ - **A full-screen surface now covers the viewport even when an ancestor has a
61
+ `transform`, `filter`, `perspective` or `contain: paint`.** Found while
62
+ dogfooding 5.61.0 in the showcase. A `FullScreen` inside a `Tabs` panel came
63
+ out as a 1248x95 box instead of the screen, because the panel's
64
+ `fancy-fade-in` animation, run with `animation-fill-mode: both`, kept
65
+ `transform: matrix(1, 0, 0, 1, 0, 0)` on the panel. That makes the panel the
66
+ box `position: fixed` is measured against. Transform-centred dialogs, the
67
+ usual way MOIC embeds editors, did the same. The overlay is now lifted into
68
+ the browser's top layer with `popover="manual"` + `showPopover()`, whose
69
+ containing block is always the viewport. It falls back to `position: fixed`
70
+ where the popover API does not exist. Measured in Chromium:
71
+ - Tabs panel: [300,359,1320,32] before, [0,0,1920,945] after.
72
+ - `translateX(0)`, `blur(0)` and `contain: paint` parents: confined to their
73
+ parent before, the viewport after.
74
+ - An Editor in a `Modal`, inside a transformed wrapper: 622x2 before, the
75
+ viewport after. A `Dropdown` opened from inside it is now visible.
76
+
77
+ Details:
78
+ - `manual`, so no light dismiss.
79
+ - Escape, focus restore and scroll restore are unchanged.
80
+ - `styles.css` resets the UA popover padding, border, background, colour and
81
+ overflow in a zero-specificity rule in the `base` layer, so your own
82
+ classes still win.
83
+ - In `native` mode the browser's full screen is requested first, because
84
+ Chromium refuses `requestFullscreen()` on an open popover. The popover is
85
+ used only if that request is refused.
86
+ - New handle `data-fullscreen-layer="top" | "fixed"` and `layer` on
87
+ `useFullScreen()`'s result.
88
+
89
+ **Nothing to do.** If you style the full-screen surface without importing
90
+ `styles.css`, the UA popover padding and border show while it is active. Add
91
+ your own padding, border and background classes, or import the stylesheet.
92
+ Overlays rendered from outside the surface while it is active, such as an
93
+ app-level toast, now sit under it.
94
+
14
95
  ## [5.61.0] - 2026-10-26
15
96
 
16
97
  ### Added
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunk7KTBVKNO_cjs = require('./chunk-7KTBVKNO.cjs');
3
+ var chunkR6URPHEP_cjs = require('./chunk-R6URPHEP.cjs');
4
4
  require('./chunk-KJ22KE56.cjs');
5
5
  require('./chunk-L3V3BYVS.cjs');
6
6
  require('./chunk-J2DI6RMR.cjs');
7
7
  require('./chunk-MKHYENKR.cjs');
8
8
  require('./chunk-TI7D4QDM.cjs');
9
9
  require('./chunk-57FQGQJK.cjs');
10
- require('./chunk-RXDRYWVD.cjs');
10
+ require('./chunk-OUYC6EIL.cjs');
11
11
  require('./chunk-SNHU2AI4.cjs');
12
12
  require('./chunk-ZU5Q77OT.cjs');
13
13
 
@@ -15,7 +15,7 @@ require('./chunk-ZU5Q77OT.cjs');
15
15
 
16
16
  Object.defineProperty(exports, "Autocomplete", {
17
17
  enumerable: true,
18
- get: function () { return chunk7KTBVKNO_cjs.Autocomplete; }
18
+ get: function () { return chunkR6URPHEP_cjs.Autocomplete; }
19
19
  });
20
20
  //# sourceMappingURL=autocomplete.cjs.map
21
21
  //# sourceMappingURL=autocomplete.cjs.map
@@ -1,11 +1,11 @@
1
- export { Autocomplete } from './chunk-MSGKIWYX.js';
1
+ export { Autocomplete } from './chunk-VZNBTCGA.js';
2
2
  import './chunk-OL53XYHF.js';
3
3
  import './chunk-NRXK42LO.js';
4
4
  import './chunk-MQ6VGG62.js';
5
5
  import './chunk-5VMILVWD.js';
6
6
  import './chunk-RBCMKPBX.js';
7
7
  import './chunk-RGANGU7X.js';
8
- import './chunk-JXE5XID6.js';
8
+ import './chunk-YX6FTJ6N.js';
9
9
  import './chunk-EDYAXGUM.js';
10
10
  import './chunk-MMW2JGKZ.js';
11
11
  //# sourceMappingURL=autocomplete.js.map
@@ -1,15 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkKNKOSMOQ_cjs = require('./chunk-KNKOSMOQ.cjs');
3
+ var chunk35S5BTZH_cjs = require('./chunk-35S5BTZH.cjs');
4
4
  require('./chunk-57FQGQJK.cjs');
5
- require('./chunk-RXDRYWVD.cjs');
5
+ require('./chunk-OUYC6EIL.cjs');
6
6
  require('./chunk-ZU5Q77OT.cjs');
7
7
 
8
8
 
9
9
 
10
10
  Object.defineProperty(exports, "Breadcrumbs", {
11
11
  enumerable: true,
12
- get: function () { return chunkKNKOSMOQ_cjs.Breadcrumbs; }
12
+ get: function () { return chunk35S5BTZH_cjs.Breadcrumbs; }
13
13
  });
14
14
  //# sourceMappingURL=breadcrumbs.cjs.map
15
15
  //# sourceMappingURL=breadcrumbs.cjs.map
@@ -1,6 +1,6 @@
1
- export { Breadcrumbs } from './chunk-3AYRLFNO.js';
1
+ export { Breadcrumbs } from './chunk-A67EDGC7.js';
2
2
  import './chunk-RGANGU7X.js';
3
- import './chunk-JXE5XID6.js';
3
+ import './chunk-YX6FTJ6N.js';
4
4
  import './chunk-MMW2JGKZ.js';
5
5
  //# sourceMappingURL=breadcrumbs.js.map
6
6
  //# sourceMappingURL=breadcrumbs.js.map
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunk57FQGQJK_cjs = require('./chunk-57FQGQJK.cjs');
4
- var chunkRXDRYWVD_cjs = require('./chunk-RXDRYWVD.cjs');
4
+ var chunkOUYC6EIL_cjs = require('./chunk-OUYC6EIL.cjs');
5
5
  var chunkZU5Q77OT_cjs = require('./chunk-ZU5Q77OT.cjs');
6
6
  var react = require('react');
7
7
  var lucideReact = require('lucide-react');
@@ -55,7 +55,7 @@ function BreadcrumbsDropdown({ items, activeLabel }) {
55
55
  const [open, setOpen] = react.useState(false);
56
56
  const ref = react.useRef(null);
57
57
  chunk57FQGQJK_cjs.useOutsideClick(ref, () => setOpen(false), open);
58
- chunkRXDRYWVD_cjs.useEscapeKey(() => setOpen(false), open);
58
+ chunkOUYC6EIL_cjs.useEscapeKey(() => setOpen(false), open);
59
59
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, "data-react-fancy-breadcrumbs-dropdown": "", className: "relative flex md:hidden", children: [
60
60
  /* @__PURE__ */ jsxRuntime.jsxs(
61
61
  "button",
@@ -137,5 +137,5 @@ var Breadcrumbs = Object.assign(BreadcrumbsRoot, {
137
137
  });
138
138
 
139
139
  exports.Breadcrumbs = Breadcrumbs;
140
- //# sourceMappingURL=chunk-KNKOSMOQ.cjs.map
141
- //# sourceMappingURL=chunk-KNKOSMOQ.cjs.map
140
+ //# sourceMappingURL=chunk-35S5BTZH.cjs.map
141
+ //# sourceMappingURL=chunk-35S5BTZH.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Breadcrumbs/BreadcrumbsItem.tsx","../src/components/Breadcrumbs/BreadcrumbsDropdown.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":["cn","jsx","useState","useRef","useOutsideClick","useEscapeKey","jsxs","ChevronDown","Children","ChevronRight","Fragment"],"mappings":"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","file":"chunk-KNKOSMOQ.cjs","sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nexport function BreadcrumbsItem({\n children,\n href,\n as: As,\n active = false,\n onClick,\n className,\n ...rest\n}: BreadcrumbsItemProps) {\n const baseClass = cn(\n \"text-sm\",\n active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n className,\n );\n\n // The CURRENT crumb stays a <span> even with `as`: it is the page you are on,\n // so a link to it is a link to nowhere, and `aria-current=\"page\"` is the point.\n if ((href || As) && !active) {\n const Link = (As ?? \"a\") as ElementType;\n\n return (\n <Link\n data-react-fancy-breadcrumbs-item=\"\"\n {...(href ? { href } : {})}\n onClick={onClick}\n className={baseClass}\n {...rest}\n >\n {children}\n </Link>\n );\n }\n\n // A crumb that navigates through a callback rather than a URL. Controlled\n // components own their navigation and have no href to give — a repository\n // browser walking directories, a wizard stepping back — and until this\n // existed the only way to make such a crumb clickable was to nest a button\n // inside the span below, which is interactive content inside a non-\n // interactive element.\n if (onClick && !active) {\n return (\n <button\n type=\"button\"\n data-react-fancy-breadcrumbs-item=\"\"\n onClick={onClick}\n className={cn(baseClass, \"cursor-pointer border-0 bg-transparent p-0\")}\n {...rest}\n >\n {children}\n </button>\n );\n }\n\n return (\n <span data-react-fancy-breadcrumbs-item=\"\" className={baseClass} aria-current={active ? \"page\" : undefined} {...rest}>\n {children}\n </span>\n );\n}\n\nBreadcrumbsItem.displayName = \"BreadcrumbsItem\";\n","import { useState, useRef, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useOutsideClick } from \"../../hooks/use-outside-click\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\n\ninterface BreadcrumbsDropdownItem {\n label: ReactNode;\n href?: string;\n active?: boolean;\n}\n\ninterface BreadcrumbsDropdownProps {\n items: BreadcrumbsDropdownItem[];\n activeLabel: ReactNode;\n}\n\nexport function BreadcrumbsDropdown({ items, activeLabel }: BreadcrumbsDropdownProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useOutsideClick(ref, () => setOpen(false), open);\n useEscapeKey(() => setOpen(false), open);\n\n return (\n <div ref={ref} data-react-fancy-breadcrumbs-dropdown=\"\" className=\"relative flex md:hidden\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-zinc-900 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-white dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {activeLabel}\n <ChevronDown size={14} className={cn(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && (\n <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[180px] rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] py-1 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\">\n {items.map((item, i) => {\n const cls = cn(\n \"block w-full px-3 py-1.5 text-left text-sm\",\n item.active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:bg-zinc-50 hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:bg-zinc-800 dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n );\n\n if (item.href && !item.active) {\n return (\n <a key={i} href={item.href} className={cls} onClick={() => setOpen(false)}>\n {item.label}\n </a>\n );\n }\n\n return (\n <span key={i} className={cls}>\n {item.label}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nBreadcrumbsDropdown.displayName = \"BreadcrumbsDropdown\";\n","import { Children, Fragment, useState, type ReactElement } from \"react\";\nimport { ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { BreadcrumbsItem } from \"./BreadcrumbsItem\";\nimport { BreadcrumbsDropdown } from \"./BreadcrumbsDropdown\";\nimport type { BreadcrumbsProps, BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nfunction BreadcrumbsRoot({\n children,\n separator,\n shrink,\n className,\n}: BreadcrumbsProps) {\n const items = Children.toArray(children);\n const [expanded, setExpanded] = useState(false);\n\n const sep = separator ?? (\n <ChevronRight size={12} className=\"text-zinc-400\" />\n );\n\n const lastItem = items[items.length - 1];\n\n // Extract info from children for mobile dropdown\n const dropdownItems = items.map((child) => {\n const el = child as ReactElement<BreadcrumbsItemProps>;\n return {\n label: el.props?.children,\n href: el.props?.href,\n active: el.props?.active,\n };\n });\n\n const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? \"Menu\";\n\n const showShrunk = shrink && !expanded && items.length > 1;\n\n return (\n <>\n {/* Desktop trail */}\n <nav\n data-react-fancy-breadcrumbs=\"\"\n aria-label=\"Breadcrumb\"\n className={cn(\"hidden items-center gap-2 md:flex\", className)}\n onMouseLeave={() => shrink && setExpanded(false)}\n >\n {showShrunk ? (\n <>\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n onMouseEnter={() => setExpanded(true)}\n className=\"text-sm text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\n >\n ...\n </button>\n <span aria-hidden=\"true\">{sep}</span>\n {lastItem}\n </>\n ) : (\n items.map((child, i) => (\n <Fragment key={i}>\n {i > 0 && <span aria-hidden=\"true\">{sep}</span>}\n {child}\n </Fragment>\n ))\n )}\n </nav>\n\n {/* Mobile dropdown */}\n <BreadcrumbsDropdown items={dropdownItems} activeLabel={activeLabel} />\n </>\n );\n}\n\nexport const Breadcrumbs = Object.assign(BreadcrumbsRoot, {\n Item: BreadcrumbsItem,\n});\n"]}
1
+ {"version":3,"sources":["../src/components/Breadcrumbs/BreadcrumbsItem.tsx","../src/components/Breadcrumbs/BreadcrumbsDropdown.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":["cn","jsx","useState","useRef","useOutsideClick","useEscapeKey","jsxs","ChevronDown","Children","ChevronRight","Fragment"],"mappings":"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","file":"chunk-35S5BTZH.cjs","sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nexport function BreadcrumbsItem({\n children,\n href,\n as: As,\n active = false,\n onClick,\n className,\n ...rest\n}: BreadcrumbsItemProps) {\n const baseClass = cn(\n \"text-sm\",\n active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n className,\n );\n\n // The CURRENT crumb stays a <span> even with `as`: it is the page you are on,\n // so a link to it is a link to nowhere, and `aria-current=\"page\"` is the point.\n if ((href || As) && !active) {\n const Link = (As ?? \"a\") as ElementType;\n\n return (\n <Link\n data-react-fancy-breadcrumbs-item=\"\"\n {...(href ? { href } : {})}\n onClick={onClick}\n className={baseClass}\n {...rest}\n >\n {children}\n </Link>\n );\n }\n\n // A crumb that navigates through a callback rather than a URL. Controlled\n // components own their navigation and have no href to give — a repository\n // browser walking directories, a wizard stepping back — and until this\n // existed the only way to make such a crumb clickable was to nest a button\n // inside the span below, which is interactive content inside a non-\n // interactive element.\n if (onClick && !active) {\n return (\n <button\n type=\"button\"\n data-react-fancy-breadcrumbs-item=\"\"\n onClick={onClick}\n className={cn(baseClass, \"cursor-pointer border-0 bg-transparent p-0\")}\n {...rest}\n >\n {children}\n </button>\n );\n }\n\n return (\n <span data-react-fancy-breadcrumbs-item=\"\" className={baseClass} aria-current={active ? \"page\" : undefined} {...rest}>\n {children}\n </span>\n );\n}\n\nBreadcrumbsItem.displayName = \"BreadcrumbsItem\";\n","import { useState, useRef, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useOutsideClick } from \"../../hooks/use-outside-click\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\n\ninterface BreadcrumbsDropdownItem {\n label: ReactNode;\n href?: string;\n active?: boolean;\n}\n\ninterface BreadcrumbsDropdownProps {\n items: BreadcrumbsDropdownItem[];\n activeLabel: ReactNode;\n}\n\nexport function BreadcrumbsDropdown({ items, activeLabel }: BreadcrumbsDropdownProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useOutsideClick(ref, () => setOpen(false), open);\n useEscapeKey(() => setOpen(false), open);\n\n return (\n <div ref={ref} data-react-fancy-breadcrumbs-dropdown=\"\" className=\"relative flex md:hidden\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-zinc-900 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-white dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {activeLabel}\n <ChevronDown size={14} className={cn(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && (\n <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[180px] rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] py-1 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\">\n {items.map((item, i) => {\n const cls = cn(\n \"block w-full px-3 py-1.5 text-left text-sm\",\n item.active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:bg-zinc-50 hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:bg-zinc-800 dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n );\n\n if (item.href && !item.active) {\n return (\n <a key={i} href={item.href} className={cls} onClick={() => setOpen(false)}>\n {item.label}\n </a>\n );\n }\n\n return (\n <span key={i} className={cls}>\n {item.label}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nBreadcrumbsDropdown.displayName = \"BreadcrumbsDropdown\";\n","import { Children, Fragment, useState, type ReactElement } from \"react\";\nimport { ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { BreadcrumbsItem } from \"./BreadcrumbsItem\";\nimport { BreadcrumbsDropdown } from \"./BreadcrumbsDropdown\";\nimport type { BreadcrumbsProps, BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nfunction BreadcrumbsRoot({\n children,\n separator,\n shrink,\n className,\n}: BreadcrumbsProps) {\n const items = Children.toArray(children);\n const [expanded, setExpanded] = useState(false);\n\n const sep = separator ?? (\n <ChevronRight size={12} className=\"text-zinc-400\" />\n );\n\n const lastItem = items[items.length - 1];\n\n // Extract info from children for mobile dropdown\n const dropdownItems = items.map((child) => {\n const el = child as ReactElement<BreadcrumbsItemProps>;\n return {\n label: el.props?.children,\n href: el.props?.href,\n active: el.props?.active,\n };\n });\n\n const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? \"Menu\";\n\n const showShrunk = shrink && !expanded && items.length > 1;\n\n return (\n <>\n {/* Desktop trail */}\n <nav\n data-react-fancy-breadcrumbs=\"\"\n aria-label=\"Breadcrumb\"\n className={cn(\"hidden items-center gap-2 md:flex\", className)}\n onMouseLeave={() => shrink && setExpanded(false)}\n >\n {showShrunk ? (\n <>\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n onMouseEnter={() => setExpanded(true)}\n className=\"text-sm text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\n >\n ...\n </button>\n <span aria-hidden=\"true\">{sep}</span>\n {lastItem}\n </>\n ) : (\n items.map((child, i) => (\n <Fragment key={i}>\n {i > 0 && <span aria-hidden=\"true\">{sep}</span>}\n {child}\n </Fragment>\n ))\n )}\n </nav>\n\n {/* Mobile dropdown */}\n <BreadcrumbsDropdown items={dropdownItems} activeLabel={activeLabel} />\n </>\n );\n}\n\nexport const Breadcrumbs = Object.assign(BreadcrumbsRoot, {\n Item: BreadcrumbsItem,\n});\n"]}
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var chunkOUYC6EIL_cjs = require('./chunk-OUYC6EIL.cjs');
3
4
  var chunkSNHU2AI4_cjs = require('./chunk-SNHU2AI4.cjs');
4
5
  var react = require('react');
5
6
 
@@ -31,7 +32,6 @@ var FOCUSABLE = [
31
32
  "[contenteditable]:not([contenteditable='false'])",
32
33
  "[tabindex]:not([tabindex='-1'])"
33
34
  ].join(", ");
34
- var activeStack = [];
35
35
  var OVERLAY_STYLE = {
36
36
  position: "fixed",
37
37
  top: 0,
@@ -46,6 +46,55 @@ var OVERLAY_STYLE = {
46
46
  borderRadius: 0,
47
47
  boxSizing: "border-box"
48
48
  };
49
+ var promoted = /* @__PURE__ */ new Map();
50
+ function promoteToTopLayer(el, onLost) {
51
+ const p = el;
52
+ if (typeof p.showPopover !== "function" || typeof p.hidePopover !== "function") return null;
53
+ if (el.hasAttribute("popover")) return null;
54
+ el.setAttribute("popover", "manual");
55
+ try {
56
+ p.showPopover();
57
+ } catch {
58
+ el.removeAttribute("popover");
59
+ return null;
60
+ }
61
+ let open = true;
62
+ let raising = false;
63
+ const onToggle = (e) => {
64
+ if (raising || e.newState !== "closed" || !open) return;
65
+ open = false;
66
+ promoted.delete(el);
67
+ el.removeEventListener("toggle", onToggle);
68
+ el.removeAttribute("popover");
69
+ onLost();
70
+ };
71
+ el.addEventListener("toggle", onToggle);
72
+ for (const [other, raise] of promoted) {
73
+ if (other !== el && el.contains(other)) raise();
74
+ }
75
+ promoted.set(el, () => {
76
+ raising = true;
77
+ try {
78
+ p.hidePopover();
79
+ p.showPopover();
80
+ } catch {
81
+ } finally {
82
+ raising = false;
83
+ }
84
+ });
85
+ return () => {
86
+ promoted.delete(el);
87
+ el.removeEventListener("toggle", onToggle);
88
+ if (open) {
89
+ open = false;
90
+ try {
91
+ p.hidePopover();
92
+ } catch {
93
+ }
94
+ }
95
+ el.removeAttribute("popover");
96
+ };
97
+ }
49
98
  function useFullScreen(options = {}) {
50
99
  const {
51
100
  fullScreen: controlled,
@@ -63,6 +112,20 @@ function useFullScreen(options = {}) {
63
112
  const [nativeActive, setNativeActive] = react.useState(false);
64
113
  const [portalContainer, setPortalContainer] = react.useState(null);
65
114
  const [applied, setApplied] = react.useState(fullScreen);
115
+ const [layer, setLayer] = react.useState("fixed");
116
+ const topRelease = react.useRef(null);
117
+ const promote = (el) => {
118
+ if (topRelease.current) return;
119
+ topRelease.current = promoteToTopLayer(el, () => {
120
+ topRelease.current = null;
121
+ setLayer("fixed");
122
+ });
123
+ setLayer(topRelease.current ? "top" : "fixed");
124
+ };
125
+ const demote = () => {
126
+ topRelease.current?.();
127
+ topRelease.current = null;
128
+ };
66
129
  const current = react.useRef(fullScreen);
67
130
  current.current = fullScreen;
68
131
  const setFullScreen = react.useCallback(
@@ -85,12 +148,13 @@ function useFullScreen(options = {}) {
85
148
  const winX = window.scrollX;
86
149
  const winY = window.scrollY;
87
150
  const release = lockScroll ? lockBodyScroll() : null;
88
- activeStack.push(token.current);
89
151
  setPortalContainer(el);
90
152
  setApplied(true);
153
+ const native = mode === "native" && typeof el.requestFullscreen === "function" && document.fullscreenEnabled !== false;
154
+ if (!native) promote(el);
91
155
  return () => {
92
- const i = activeStack.indexOf(token.current);
93
- if (i >= 0) activeStack.splice(i, 1);
156
+ demote();
157
+ setLayer("fixed");
94
158
  release?.();
95
159
  for (const m of scrolled) {
96
160
  if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;
@@ -100,7 +164,7 @@ function useFullScreen(options = {}) {
100
164
  setPortalContainer(null);
101
165
  setApplied(false);
102
166
  };
103
- }, [fullScreen, lockScroll]);
167
+ }, [fullScreen, lockScroll, mode]);
104
168
  react.useEffect(() => {
105
169
  if (!fullScreen) return;
106
170
  const el = ref.current;
@@ -126,17 +190,22 @@ function useFullScreen(options = {}) {
126
190
  if (document.fullscreenElement === el) {
127
191
  entered = true;
128
192
  setNativeActive(true);
193
+ setLayer("top");
129
194
  } else if (entered) {
130
195
  entered = false;
131
196
  setNativeActive(false);
197
+ setLayer("fixed");
132
198
  if (!cancelled) setFullScreen(false);
133
199
  }
134
200
  };
135
201
  document.addEventListener("fullscreenchange", onChange);
202
+ const refused = () => {
203
+ if (!cancelled && current.current && ref.current === el) promote(el);
204
+ };
136
205
  try {
137
- Promise.resolve(el.requestFullscreen()).then(onChange, () => {
138
- });
206
+ Promise.resolve(el.requestFullscreen()).then(onChange, refused);
139
207
  } catch {
208
+ refused();
140
209
  }
141
210
  return () => {
142
211
  cancelled = true;
@@ -151,18 +220,7 @@ function useFullScreen(options = {}) {
151
220
  setNativeActive(false);
152
221
  };
153
222
  }, [fullScreen, mode, setFullScreen]);
154
- react.useEffect(() => {
155
- if (!fullScreen || !closeOnEscape) return;
156
- const onKey = (e) => {
157
- if (e.key !== "Escape" || e.defaultPrevented) return;
158
- const t = e.target;
159
- if (t !== document.body && t !== document.documentElement && t !== document) return;
160
- if (activeStack[activeStack.length - 1] !== token.current) return;
161
- setFullScreen(false);
162
- };
163
- document.addEventListener("keydown", onKey);
164
- return () => document.removeEventListener("keydown", onKey);
165
- }, [fullScreen, closeOnEscape, setFullScreen]);
223
+ const escapeLayer = chunkOUYC6EIL_cjs.useEscapeLayer(() => setFullScreen(false), fullScreen && closeOnEscape, token.current);
166
224
  const onKeyDown = react.useCallback(
167
225
  (e) => {
168
226
  if (!current.current || e.defaultPrevented) return;
@@ -184,12 +242,14 @@ function useFullScreen(options = {}) {
184
242
  return;
185
243
  }
186
244
  if (e.key !== "Escape" || !closeOnEscape) return;
187
- const layer = e.target.closest?.("[data-react-fancy-portal]");
188
- if (layer && !layer.contains(el)) return;
245
+ if (!escapeLayer.isInnermost()) return;
246
+ const layer2 = e.target.closest?.("[data-react-fancy-portal]");
247
+ if (layer2 && !layer2.contains(el)) return;
189
248
  e.preventDefault();
190
249
  e.stopPropagation();
191
250
  setFullScreen(false);
192
251
  },
252
+ // eslint-disable-next-line react-hooks/exhaustive-deps
193
253
  [closeOnEscape, setFullScreen]
194
254
  );
195
255
  const activeMode = fullScreen ? nativeActive ? "native" : "overlay" : null;
@@ -200,12 +260,14 @@ function useFullScreen(options = {}) {
200
260
  setFullScreen,
201
261
  toggle,
202
262
  activeMode,
263
+ layer: activeMode ? layer : null,
203
264
  ref,
204
265
  portalContainer,
266
+ escapeScope: token.current,
205
267
  targetProps: {
206
268
  ref,
207
269
  "data-fullscreen": fullScreen ? "true" : "false",
208
- ...activeMode ? { "data-fullscreen-mode": activeMode } : {},
270
+ ...activeMode ? { "data-fullscreen-mode": activeMode, "data-fullscreen-layer": layer } : {},
209
271
  ...fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {},
210
272
  onKeyDown
211
273
  },
@@ -222,5 +284,5 @@ function useFullScreen(options = {}) {
222
284
  }
223
285
 
224
286
  exports.useFullScreen = useFullScreen;
225
- //# sourceMappingURL=chunk-O4HZVZMY.cjs.map
226
- //# sourceMappingURL=chunk-O4HZVZMY.cjs.map
287
+ //# sourceMappingURL=chunk-4GOOSZEK.cjs.map
288
+ //# sourceMappingURL=chunk-4GOOSZEK.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/scroll-lock.ts","../src/hooks/use-full-screen.ts"],"names":["useControllableState","useRef","useState","useCallback","useLayoutEffect","useEffect","useEscapeLayer","layer"],"mappings":"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","file":"chunk-4GOOSZEK.cjs","sourcesContent":["/**\n * Reference-counted body scroll lock.\n *\n * Two surfaces locking independently with the save-and-restore pattern\n * (`const original = body.style.overflow`) only unwind correctly in strict LIFO\n * order. Exit them out of order and the first one out restores `\"\"` while the\n * second is still covering the viewport, so the page scrolls behind it. Counting\n * holders keeps the lock until the last one lets go, and restores the value that\n * was there before the FIRST took it.\n *\n * Call only from an effect: it touches `document`.\n */\nlet holders = 0;\nlet saved = \"\";\n\nexport function lockBodyScroll(): () => void {\n if (holders === 0) {\n saved = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n }\n holders++;\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n holders--;\n if (holders === 0) document.body.style.overflow = saved;\n };\n}\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type RefObject,\n} from \"react\";\nimport { useControllableState } from \"./use-controllable-state\";\nimport { lockBodyScroll } from \"../utils/scroll-lock\";\nimport { useEscapeLayer, type EscapeScope } from \"./use-escape-key\";\n\n/**\n * How a surface goes full screen.\n *\n * - `\"overlay\"` (default): the element itself becomes `position: fixed` over the\n * viewport, in place. It always works: inside an iframe without\n * `allow=\"fullscreen\"`, inside a dialog, without a user gesture. Nothing is\n * reparented, so an editor keeps its caret, undo stack and DOM.\n * - `\"native\"`: the browser Fullscreen API (`element.requestFullscreen()`),\n * which hides the browser chrome too. The overlay is applied first and stays\n * if the request is rejected or the API is missing, so the user gets full\n * screen either way; `activeMode` reports which one took.\n */\nexport type FullScreenMode = \"overlay\" | \"native\";\n\nexport interface UseFullScreenOptions {\n /** Controlled flag. Pair with `onFullScreenChange`. */\n fullScreen?: boolean;\n /** Initial flag when uncontrolled. @default false */\n defaultFullScreen?: boolean;\n /**\n * Fired with the requested state — from the toggle, Escape, an agent calling\n * `setFullScreen`, or the user leaving the browser's own full screen.\n */\n onFullScreenChange?: (fullScreen: boolean) => void;\n /** @default \"overlay\" */\n mode?: FullScreenMode;\n /** Leave full screen on Escape. @default true */\n closeOnEscape?: boolean;\n /** Stop the page behind from scrolling while active. @default true */\n lockScroll?: boolean;\n /** Stacking order of the overlay. Matches `Modal`. @default 50 */\n zIndex?: number;\n /** Accessible names for the toggle. */\n labels?: { enter?: string; exit?: string };\n}\n\nexport interface FullScreenTargetProps<T extends HTMLElement> {\n ref: RefObject<T | null>;\n \"data-fullscreen\": \"true\" | \"false\";\n \"data-fullscreen-mode\"?: FullScreenMode;\n \"data-fullscreen-layer\"?: FullScreenLayer;\n style?: CSSProperties;\n onKeyDown: (event: ReactKeyboardEvent<T>) => void;\n}\n\nexport interface FullScreenToggleProps {\n type: \"button\";\n onClick: () => void;\n \"aria-pressed\": boolean;\n \"aria-label\": string;\n title: string;\n \"data-react-fancy-fullscreen-toggle\": \"\";\n \"data-fullscreen\": \"true\" | \"false\";\n}\n\nexport interface UseFullScreenResult<T extends HTMLElement = HTMLElement> {\n fullScreen: boolean;\n setFullScreen: (fullScreen: boolean) => void;\n toggle: () => void;\n /** The mechanism in effect while active; `null` when not full screen. */\n activeMode: FullScreenMode | null;\n /**\n * `\"top\"` while the surface is in the browser's top layer (a manual popover,\n * or the native full screen), `\"fixed\"` while it relies on `position: fixed`\n * (no popover API, or the browser refused). `null` when not full screen.\n */\n layer: FullScreenLayer | null;\n /** Attach to the element that goes full screen. Also inside `targetProps`. */\n ref: RefObject<T | null>;\n /**\n * Spread onto the surface's root. Carries the ref, the `data-fullscreen`\n * handle, the overlay style and the Escape/Tab handler. Merge your own\n * `style` / `onKeyDown` if the root has them.\n */\n targetProps: FullScreenTargetProps<T>;\n /** Spread onto a `<button>` to make it the toggle. */\n toggleProps: FullScreenToggleProps;\n /**\n * The element to portal into while active, else `null`. Provide it through\n * `PortalContainerContext` so menus opened inside stay visible.\n */\n portalContainer: HTMLElement | null;\n /**\n * Identity of this surface for Escape routing. Provide it through\n * `EscapeLayerContext` (FullScreenProvider does) so a menu opened inside\n * gets Escape before the surface does.\n */\n escapeScope: EscapeScope;\n}\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"textarea:not([disabled])\",\n \"select:not([disabled])\",\n \"[contenteditable]:not([contenteditable='false'])\",\n \"[tabindex]:not([tabindex='-1'])\",\n].join(\", \");\n\n\nconst OVERLAY_STYLE: CSSProperties = {\n position: \"fixed\",\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n maxWidth: \"none\",\n maxHeight: \"none\",\n margin: 0,\n borderRadius: 0,\n boxSizing: \"border-box\",\n};\n\n/**\n * Lift `el` into the browser's top layer with `popover=\"manual\"`.\n *\n * Why: `position: fixed` is only fixed to the viewport while no ancestor has a\n * transform, filter, perspective or paint containment. With one, the overlay\n * is fixed to THAT box. In the showcase a surface in a Tabs panel came out\n * 1248x95, because `.fancy-fade-in` held `transform: matrix(1,0,0,1,0,0)` via\n * `animation-fill-mode: both`. Transform-centred dialogs do the same. A\n * top-layer element's containing block is the viewport whatever its ancestors\n * do, and the popover API gets it there without moving it in the DOM.\n *\n * `manual` because `auto` light-dismisses on an outside click and on Escape;\n * Escape stays with the surface's own handler.\n *\n * Returns a release function, or `null` where the API is missing or refuses\n * (the caller keeps the fixed overlay). `onLost` fires if something else\n * closes the popover: a `[popover]` that is not open is `display: none`, so the\n * attribute must go at once or the surface vanishes while still \"full screen\".\n */\n/** Surfaces currently in the top layer through a popover, with a \"re-show\" each. */\nconst promoted = new Map<HTMLElement, () => void>();\n\nfunction promoteToTopLayer(el: HTMLElement, onLost: () => void): (() => void) | null {\n const p = el as HTMLElement & { showPopover?: () => void; hidePopover?: () => void };\n if (typeof p.showPopover !== \"function\" || typeof p.hidePopover !== \"function\") return null;\n // The consumer made it a popover themselves; do not fight over it.\n if (el.hasAttribute(\"popover\")) return null;\n\n el.setAttribute(\"popover\", \"manual\");\n try {\n p.showPopover();\n } catch {\n el.removeAttribute(\"popover\");\n return null;\n }\n\n let open = true;\n let raising = false;\n const onToggle = (e: Event) => {\n if (raising || (e as Event & { newState?: string }).newState !== \"closed\" || !open) return;\n open = false;\n promoted.delete(el);\n el.removeEventListener(\"toggle\", onToggle);\n el.removeAttribute(\"popover\");\n onLost();\n };\n el.addEventListener(\"toggle\", onToggle);\n\n // The top layer stacks in SHOW order. React runs a child's layout effects\n // before its parent's, so a surface nested in another that goes full screen\n // in the same commit is shown first and then buried by its parent. Re-show\n // any promoted descendant so the innermost stays on top.\n for (const [other, raise] of promoted) {\n if (other !== el && el.contains(other)) raise();\n }\n promoted.set(el, () => {\n raising = true;\n try {\n p.hidePopover!();\n p.showPopover!();\n } catch {\n /* leave it where it is */\n } finally {\n raising = false;\n }\n });\n\n return () => {\n promoted.delete(el);\n el.removeEventListener(\"toggle\", onToggle);\n if (open) {\n open = false;\n try {\n p.hidePopover!();\n } catch {\n /* already hidden, e.g. removed from the document */\n }\n }\n el.removeAttribute(\"popover\");\n };\n}\n\n/** Which mechanism keeps the surface over the page. */\nexport type FullScreenLayer = \"top\" | \"fixed\";\n\ninterface ScrollMemo {\n el: Element;\n top: number;\n left: number;\n}\n\n/**\n * A controlled full-screen state for any surface: Editor today, DeckEditor and\n * SheetWorkbook next. Render-time output is pure (no `window`/`document`), so it\n * server-renders; everything that touches the DOM runs in effects.\n */\nexport function useFullScreen<T extends HTMLElement = HTMLElement>(\n options: UseFullScreenOptions = {},\n): UseFullScreenResult<T> {\n const {\n fullScreen: controlled,\n defaultFullScreen = false,\n onFullScreenChange,\n mode = \"overlay\",\n closeOnEscape = true,\n lockScroll = true,\n zIndex = 50,\n labels,\n } = options;\n\n const [fullScreen, setState] = useControllableState(controlled, defaultFullScreen, onFullScreenChange);\n const ref = useRef<T | null>(null);\n const token = useRef({});\n const [nativeActive, setNativeActive] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);\n // Whether the overlay STYLE is on. It trails `fullScreen` by one synchronous\n // commit on entry, so the layout effect below reads scroll offsets while the\n // surface is still in flow. Read after the style lands and the browser has\n // already clamped every scroll container around it: a panel at 569 read as\n // 342 in Chromium, and that is where the user was sent back to. The re-render\n // happens inside the layout phase, before paint, so nothing flashes.\n // Initialised from `fullScreen` so a surface that starts full screen renders\n // the overlay on the server and on hydration alike.\n const [applied, setApplied] = useState(fullScreen);\n // \"fixed\" until a layout effect has actually promoted the surface, so the\n // server and the hydrating client agree, and a refused promotion reads true.\n const [layer, setLayer] = useState<FullScreenLayer>(\"fixed\");\n const topRelease = useRef<(() => void) | null>(null);\n\n const promote = (el: HTMLElement) => {\n if (topRelease.current) return;\n topRelease.current = promoteToTopLayer(el, () => {\n topRelease.current = null;\n setLayer(\"fixed\");\n });\n setLayer(topRelease.current ? \"top\" : \"fixed\");\n };\n const demote = () => {\n topRelease.current?.();\n topRelease.current = null;\n };\n\n const current = useRef(fullScreen);\n current.current = fullScreen;\n\n // Only report real transitions: Escape on an inactive surface, or a second\n // click racing a re-render, must not fire `onFullScreenChange(false)` twice.\n const setFullScreen = useCallback(\n (next: boolean) => {\n if (current.current === next) return;\n current.current = next;\n setState(next);\n },\n [setState],\n );\n const toggle = useCallback(() => setFullScreen(!current.current), [setFullScreen]);\n\n // Enter / exit bookkeeping. A LAYOUT effect so the cleanup runs after the\n // overlay style has been removed from the DOM but before paint: scroll offsets\n // restored there never flash, and the surface is back in flow to measure.\n useLayoutEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n // Taking the surface out of flow shrinks every scroll container around it,\n // which clamps their scrollTop. Remember them so exit lands where it began.\n const scrolled: ScrollMemo[] = [];\n for (let p = el.parentElement; p && p !== document.body && p !== document.documentElement; p = p.parentElement) {\n if (p.scrollTop || p.scrollLeft) scrolled.push({ el: p, top: p.scrollTop, left: p.scrollLeft });\n }\n const winX = window.scrollX;\n const winY = window.scrollY;\n\n const release = lockScroll ? lockBodyScroll() : null;\n setPortalContainer(el);\n setApplied(true);\n\n // Native mode asks the browser first: Chromium rejects requestFullscreen()\n // on an element that is already an open popover (\"already open as a\n // Popover, and therefore cannot be opened via the fullscreen API\"). The\n // native effect promotes on refusal instead.\n const native = mode === \"native\" && typeof el.requestFullscreen === \"function\" && document.fullscreenEnabled !== false;\n if (!native) promote(el);\n\n return () => {\n // Out of the top layer first, so the surface is back in flow before the\n // scroll offsets are put back.\n demote();\n setLayer(\"fixed\");\n release?.();\n for (const m of scrolled) {\n if (m.el.scrollTop !== m.top) m.el.scrollTop = m.top;\n if (m.el.scrollLeft !== m.left) m.el.scrollLeft = m.left;\n }\n if (window.scrollX !== winX || window.scrollY !== winY) window.scrollTo(winX, winY);\n setPortalContainer(null);\n setApplied(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fullScreen, lockScroll, mode]);\n\n // Focus in and back out. A PASSIVE effect on purpose: React re-focuses\n // whatever had focus before a commit once the commit's mutations finish, so a\n // focus() issued from a layout-effect cleanup is silently undone.\n useEffect(() => {\n if (!fullScreen) return;\n const el = ref.current;\n if (!el) return;\n\n const opener =\n document.activeElement instanceof HTMLElement && document.activeElement !== document.body\n ? document.activeElement\n : null;\n\n // Focus must not stay behind the overlay, where the user cannot see it.\n if (!el.contains(document.activeElement)) {\n el.querySelector<HTMLElement>(FOCUSABLE)?.focus({ preventScroll: true });\n }\n\n return () => {\n // Give focus back only if it is still ours to give: inside the surface,\n // or lost to <body>. A user who clicked elsewhere keeps their choice.\n const active = document.activeElement;\n if (opener?.isConnected && (!active || active === document.body || el.contains(active))) {\n opener.focus({ preventScroll: true });\n }\n };\n }, [fullScreen]);\n\n // The browser Fullscreen API, on top of the overlay.\n useEffect(() => {\n if (!fullScreen || mode !== \"native\") return;\n const el = ref.current;\n if (!el || typeof el.requestFullscreen !== \"function\" || document.fullscreenEnabled === false) return;\n\n let cancelled = false;\n let entered = false;\n\n const onChange = () => {\n if (document.fullscreenElement === el) {\n entered = true;\n setNativeActive(true);\n // The browser's full screen is the top layer too.\n setLayer(\"top\");\n } else if (entered) {\n // The user left through the browser's own UI (Esc, F11, the close\n // pill). Keep the controlled state honest rather than leaving an\n // overlay up that they believe they dismissed.\n entered = false;\n setNativeActive(false);\n setLayer(\"fixed\");\n if (!cancelled) setFullScreen(false);\n }\n };\n document.addEventListener(\"fullscreenchange\", onChange);\n\n // Blocked requests (iframe without allow=\"fullscreen\", no user gesture, a\n // permissions policy) reject, and some engines throw instead. Either way\n // the user stays full screen in the overlay, lifted into the top layer.\n const refused = () => {\n if (!cancelled && current.current && ref.current === el) promote(el);\n };\n try {\n Promise.resolve(el.requestFullscreen()).then(onChange, refused);\n } catch {\n refused();\n }\n\n return () => {\n cancelled = true;\n document.removeEventListener(\"fullscreenchange\", onChange);\n if (document.fullscreenElement === el) {\n try {\n Promise.resolve(document.exitFullscreen()).catch(() => {});\n } catch {\n /* already left */\n }\n }\n setNativeActive(false);\n };\n }, [fullScreen, mode, setFullScreen]);\n\n // The surface is an Escape LAYER while active, in the same stack as every\n // Dropdown, Select, Popover, Modal and Tooltip. Layers opened inside it\n // register under `token.current` (through EscapeLayerContext, which crosses\n // portals), so the stack knows they are inside and hands them Escape first,\n // whatever order the listeners run in. With nothing focused, or focus\n // outside the surface, the stack's document listener delivers it here.\n const escapeLayer = useEscapeLayer(() => setFullScreen(false), fullScreen && closeOnEscape, token.current);\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<T>) => {\n if (!current.current || e.defaultPrevented) return;\n const el = ref.current;\n if (!el) return;\n\n if (e.key === \"Tab\") {\n // Keep Tab inside the surface; what is behind the overlay is invisible.\n const items = Array.from(el.querySelectorAll<HTMLElement>(FOCUSABLE));\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (e.shiftKey && (active === first || active === el)) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && active === last) {\n e.preventDefault();\n first.focus();\n }\n return;\n }\n\n if (e.key !== \"Escape\" || !closeOnEscape) return;\n // A layer opened from inside this surface is open (a menu, a listbox, a\n // popover, a tooltip, a dialog): it owns this Escape. Let the event go on\n // to the stack's document listener, which closes that layer only. This\n // is a lookup, not a race: in 5.61.1 the surface asked\n // `defaultPrevented`, which a document-level menu had not set yet.\n if (!escapeLayer.isInnermost()) return;\n // Portal content that never registered as a layer (a consumer's own\n // menu in a react-fancy Portal) still gets the benefit of the doubt.\n // React bubbles portal events through the component tree, so check the\n // DOM: a portal wrapper that does not contain this surface is inside it.\n const layer = (e.target as Element).closest?.(\"[data-react-fancy-portal]\");\n if (layer && !layer.contains(el)) return;\n // Stop it here so an enclosing dialog's document listener does not also\n // close: one Escape, one step back.\n e.preventDefault();\n e.stopPropagation();\n setFullScreen(false);\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [closeOnEscape, setFullScreen],\n );\n\n const activeMode: FullScreenMode | null = fullScreen ? (nativeActive ? \"native\" : \"overlay\") : null;\n const enterLabel = labels?.enter ?? \"Enter full screen\";\n const exitLabel = labels?.exit ?? \"Exit full screen\";\n\n return {\n fullScreen,\n setFullScreen,\n toggle,\n activeMode,\n layer: activeMode ? layer : null,\n ref,\n portalContainer,\n escapeScope: token.current,\n targetProps: {\n ref,\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n ...(activeMode ? { \"data-fullscreen-mode\": activeMode, \"data-fullscreen-layer\": layer } : {}),\n ...(fullScreen && applied ? { style: { ...OVERLAY_STYLE, zIndex } } : {}),\n onKeyDown,\n },\n toggleProps: {\n type: \"button\",\n onClick: toggle,\n \"aria-pressed\": fullScreen,\n \"aria-label\": fullScreen ? exitLabel : enterLabel,\n title: fullScreen ? exitLabel : enterLabel,\n \"data-react-fancy-fullscreen-toggle\": \"\",\n \"data-fullscreen\": fullScreen ? \"true\" : \"false\",\n },\n };\n}\n"]}
@@ -2,8 +2,8 @@
2
2
 
3
3
  var chunk2O5UXH5R_cjs = require('./chunk-2O5UXH5R.cjs');
4
4
  var chunkTLRFXSPA_cjs = require('./chunk-TLRFXSPA.cjs');
5
- var chunkK6NADZ7O_cjs = require('./chunk-K6NADZ7O.cjs');
6
- var chunkM6MGQI6G_cjs = require('./chunk-M6MGQI6G.cjs');
5
+ var chunkCMC2TOEQ_cjs = require('./chunk-CMC2TOEQ.cjs');
6
+ var chunkWKPBCB67_cjs = require('./chunk-WKPBCB67.cjs');
7
7
  var chunkMAZEX4EZ_cjs = require('./chunk-MAZEX4EZ.cjs');
8
8
  var chunkP53432AK_cjs = require('./chunk-P53432AK.cjs');
9
9
  var chunkO3F6DYWR_cjs = require('./chunk-O3F6DYWR.cjs');
@@ -522,7 +522,7 @@ function JsonEditorValue({ node, mode, size, readOnly, id, onCommit }) {
522
522
  case "enum": {
523
523
  const options = rule?.options ?? [];
524
524
  return /* @__PURE__ */ jsxRuntime.jsx(
525
- chunkM6MGQI6G_cjs.Select,
525
+ chunkWKPBCB67_cjs.Select,
526
526
  {
527
527
  ...common,
528
528
  list: options,
@@ -572,7 +572,7 @@ function JsonEditorValue({ node, mode, size, readOnly, id, onCommit }) {
572
572
  );
573
573
  case "secret":
574
574
  return /* @__PURE__ */ jsxRuntime.jsx(
575
- chunkK6NADZ7O_cjs.Input,
575
+ chunkCMC2TOEQ_cjs.Input,
576
576
  {
577
577
  ...common,
578
578
  type: "password",
@@ -587,7 +587,7 @@ function JsonEditorValue({ node, mode, size, readOnly, id, onCommit }) {
587
587
  case "string":
588
588
  default:
589
589
  return /* @__PURE__ */ jsxRuntime.jsx(
590
- chunkK6NADZ7O_cjs.Input,
590
+ chunkCMC2TOEQ_cjs.Input,
591
591
  {
592
592
  ...common,
593
593
  type: node.type === "url" ? "url" : node.type === "email" ? "email" : "text",
@@ -639,7 +639,7 @@ function RawValueEditor({
639
639
  );
640
640
  }
641
641
  return /* @__PURE__ */ jsxRuntime.jsx(
642
- chunkK6NADZ7O_cjs.Input,
642
+ chunkCMC2TOEQ_cjs.Input,
643
643
  {
644
644
  id,
645
645
  size,
@@ -712,7 +712,7 @@ function JsonEditorRow({ node }) {
712
712
  className: "w-1/3 min-w-0 shrink-0",
713
713
  children: [
714
714
  renameable ? /* @__PURE__ */ jsxRuntime.jsx(
715
- chunkK6NADZ7O_cjs.Input,
715
+ chunkCMC2TOEQ_cjs.Input,
716
716
  {
717
717
  size: ctx.size,
718
718
  mode: "edit",
@@ -889,7 +889,7 @@ function JsonEditorAddForm({ path, kind, depth, suggestedType }) {
889
889
  style: { paddingInlineStart: depth * INDENT + 32 },
890
890
  children: [
891
891
  kind === "object" && /* @__PURE__ */ jsxRuntime.jsx(
892
- chunkK6NADZ7O_cjs.Input,
892
+ chunkCMC2TOEQ_cjs.Input,
893
893
  {
894
894
  size: ctx.size,
895
895
  mode: "edit",
@@ -902,7 +902,7 @@ function JsonEditorAddForm({ path, kind, depth, suggestedType }) {
902
902
  }
903
903
  ),
904
904
  /* @__PURE__ */ jsxRuntime.jsx(
905
- chunkM6MGQI6G_cjs.Select,
905
+ chunkWKPBCB67_cjs.Select,
906
906
  {
907
907
  size: ctx.size,
908
908
  mode: "edit",
@@ -1350,5 +1350,5 @@ exports.parsePath = parsePath;
1350
1350
  exports.pathToString = pathToString;
1351
1351
  exports.resolveKeyRule = resolveKeyRule;
1352
1352
  exports.typeMatches = typeMatches;
1353
- //# sourceMappingURL=chunk-3I6PE2US.cjs.map
1354
- //# sourceMappingURL=chunk-3I6PE2US.cjs.map
1353
+ //# sourceMappingURL=chunk-4XHG6Q42.cjs.map
1354
+ //# sourceMappingURL=chunk-4XHG6Q42.cjs.map