@cherrystudio/file-preview 0.0.0-stage → 0.1.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 (215) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +247 -2
  3. package/dist/Combination-BLg27FvF.js +1044 -0
  4. package/dist/EchartsChartRenderer-e2b5JysX.js +39859 -0
  5. package/dist/FilePreviewTooLarge-DkHa6toZ.js +27 -0
  6. package/dist/ImageFilePreview-BO8rLRZv.js +2171 -0
  7. package/dist/PdfFilePreview-D3Ie0_mm.js +29747 -0
  8. package/dist/PowerPointFilePreview-BLfF0zcm.js +58032 -0
  9. package/dist/SpreadsheetFilePreview-DJdoyeis.js +3217 -0
  10. package/dist/WordFilePreview-DSqt7Uq2.js +4137 -0
  11. package/dist/assets/cmaps/78-EUC-H.bcmap +0 -0
  12. package/dist/assets/cmaps/78-EUC-V.bcmap +0 -0
  13. package/dist/assets/cmaps/78-H.bcmap +0 -0
  14. package/dist/assets/cmaps/78-RKSJ-H.bcmap +0 -0
  15. package/dist/assets/cmaps/78-RKSJ-V.bcmap +0 -0
  16. package/dist/assets/cmaps/78-V.bcmap +0 -0
  17. package/dist/assets/cmaps/78ms-RKSJ-H.bcmap +0 -0
  18. package/dist/assets/cmaps/78ms-RKSJ-V.bcmap +0 -0
  19. package/dist/assets/cmaps/83pv-RKSJ-H.bcmap +0 -0
  20. package/dist/assets/cmaps/90ms-RKSJ-H.bcmap +0 -0
  21. package/dist/assets/cmaps/90ms-RKSJ-V.bcmap +0 -0
  22. package/dist/assets/cmaps/90msp-RKSJ-H.bcmap +0 -0
  23. package/dist/assets/cmaps/90msp-RKSJ-V.bcmap +0 -0
  24. package/dist/assets/cmaps/90pv-RKSJ-H.bcmap +0 -0
  25. package/dist/assets/cmaps/90pv-RKSJ-V.bcmap +0 -0
  26. package/dist/assets/cmaps/Add-H.bcmap +0 -0
  27. package/dist/assets/cmaps/Add-RKSJ-H.bcmap +0 -0
  28. package/dist/assets/cmaps/Add-RKSJ-V.bcmap +0 -0
  29. package/dist/assets/cmaps/Add-V.bcmap +0 -0
  30. package/dist/assets/cmaps/Adobe-CNS1-0.bcmap +0 -0
  31. package/dist/assets/cmaps/Adobe-CNS1-1.bcmap +0 -0
  32. package/dist/assets/cmaps/Adobe-CNS1-2.bcmap +0 -0
  33. package/dist/assets/cmaps/Adobe-CNS1-3.bcmap +0 -0
  34. package/dist/assets/cmaps/Adobe-CNS1-4.bcmap +0 -0
  35. package/dist/assets/cmaps/Adobe-CNS1-5.bcmap +0 -0
  36. package/dist/assets/cmaps/Adobe-CNS1-6.bcmap +0 -0
  37. package/dist/assets/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  38. package/dist/assets/cmaps/Adobe-GB1-0.bcmap +0 -0
  39. package/dist/assets/cmaps/Adobe-GB1-1.bcmap +0 -0
  40. package/dist/assets/cmaps/Adobe-GB1-2.bcmap +0 -0
  41. package/dist/assets/cmaps/Adobe-GB1-3.bcmap +0 -0
  42. package/dist/assets/cmaps/Adobe-GB1-4.bcmap +0 -0
  43. package/dist/assets/cmaps/Adobe-GB1-5.bcmap +0 -0
  44. package/dist/assets/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  45. package/dist/assets/cmaps/Adobe-Japan1-0.bcmap +0 -0
  46. package/dist/assets/cmaps/Adobe-Japan1-1.bcmap +0 -0
  47. package/dist/assets/cmaps/Adobe-Japan1-2.bcmap +0 -0
  48. package/dist/assets/cmaps/Adobe-Japan1-3.bcmap +0 -0
  49. package/dist/assets/cmaps/Adobe-Japan1-4.bcmap +0 -0
  50. package/dist/assets/cmaps/Adobe-Japan1-5.bcmap +0 -0
  51. package/dist/assets/cmaps/Adobe-Japan1-6.bcmap +0 -0
  52. package/dist/assets/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  53. package/dist/assets/cmaps/Adobe-Korea1-0.bcmap +0 -0
  54. package/dist/assets/cmaps/Adobe-Korea1-1.bcmap +0 -0
  55. package/dist/assets/cmaps/Adobe-Korea1-2.bcmap +0 -0
  56. package/dist/assets/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  57. package/dist/assets/cmaps/B5-H.bcmap +0 -0
  58. package/dist/assets/cmaps/B5-V.bcmap +0 -0
  59. package/dist/assets/cmaps/B5pc-H.bcmap +0 -0
  60. package/dist/assets/cmaps/B5pc-V.bcmap +0 -0
  61. package/dist/assets/cmaps/CNS-EUC-H.bcmap +0 -0
  62. package/dist/assets/cmaps/CNS-EUC-V.bcmap +0 -0
  63. package/dist/assets/cmaps/CNS1-H.bcmap +0 -0
  64. package/dist/assets/cmaps/CNS1-V.bcmap +0 -0
  65. package/dist/assets/cmaps/CNS2-H.bcmap +0 -0
  66. package/dist/assets/cmaps/CNS2-V.bcmap +3 -0
  67. package/dist/assets/cmaps/ETHK-B5-H.bcmap +0 -0
  68. package/dist/assets/cmaps/ETHK-B5-V.bcmap +0 -0
  69. package/dist/assets/cmaps/ETen-B5-H.bcmap +0 -0
  70. package/dist/assets/cmaps/ETen-B5-V.bcmap +0 -0
  71. package/dist/assets/cmaps/ETenms-B5-H.bcmap +3 -0
  72. package/dist/assets/cmaps/ETenms-B5-V.bcmap +0 -0
  73. package/dist/assets/cmaps/EUC-H.bcmap +0 -0
  74. package/dist/assets/cmaps/EUC-V.bcmap +0 -0
  75. package/dist/assets/cmaps/Ext-H.bcmap +0 -0
  76. package/dist/assets/cmaps/Ext-RKSJ-H.bcmap +0 -0
  77. package/dist/assets/cmaps/Ext-RKSJ-V.bcmap +0 -0
  78. package/dist/assets/cmaps/Ext-V.bcmap +0 -0
  79. package/dist/assets/cmaps/GB-EUC-H.bcmap +0 -0
  80. package/dist/assets/cmaps/GB-EUC-V.bcmap +0 -0
  81. package/dist/assets/cmaps/GB-H.bcmap +4 -0
  82. package/dist/assets/cmaps/GB-V.bcmap +0 -0
  83. package/dist/assets/cmaps/GBK-EUC-H.bcmap +0 -0
  84. package/dist/assets/cmaps/GBK-EUC-V.bcmap +0 -0
  85. package/dist/assets/cmaps/GBK2K-H.bcmap +0 -0
  86. package/dist/assets/cmaps/GBK2K-V.bcmap +0 -0
  87. package/dist/assets/cmaps/GBKp-EUC-H.bcmap +0 -0
  88. package/dist/assets/cmaps/GBKp-EUC-V.bcmap +0 -0
  89. package/dist/assets/cmaps/GBT-EUC-H.bcmap +0 -0
  90. package/dist/assets/cmaps/GBT-EUC-V.bcmap +0 -0
  91. package/dist/assets/cmaps/GBT-H.bcmap +0 -0
  92. package/dist/assets/cmaps/GBT-V.bcmap +0 -0
  93. package/dist/assets/cmaps/GBTpc-EUC-H.bcmap +0 -0
  94. package/dist/assets/cmaps/GBTpc-EUC-V.bcmap +0 -0
  95. package/dist/assets/cmaps/GBpc-EUC-H.bcmap +0 -0
  96. package/dist/assets/cmaps/GBpc-EUC-V.bcmap +0 -0
  97. package/dist/assets/cmaps/H.bcmap +0 -0
  98. package/dist/assets/cmaps/HKdla-B5-H.bcmap +0 -0
  99. package/dist/assets/cmaps/HKdla-B5-V.bcmap +0 -0
  100. package/dist/assets/cmaps/HKdlb-B5-H.bcmap +0 -0
  101. package/dist/assets/cmaps/HKdlb-B5-V.bcmap +0 -0
  102. package/dist/assets/cmaps/HKgccs-B5-H.bcmap +0 -0
  103. package/dist/assets/cmaps/HKgccs-B5-V.bcmap +0 -0
  104. package/dist/assets/cmaps/HKm314-B5-H.bcmap +0 -0
  105. package/dist/assets/cmaps/HKm314-B5-V.bcmap +0 -0
  106. package/dist/assets/cmaps/HKm471-B5-H.bcmap +0 -0
  107. package/dist/assets/cmaps/HKm471-B5-V.bcmap +0 -0
  108. package/dist/assets/cmaps/HKscs-B5-H.bcmap +0 -0
  109. package/dist/assets/cmaps/HKscs-B5-V.bcmap +0 -0
  110. package/dist/assets/cmaps/Hankaku.bcmap +0 -0
  111. package/dist/assets/cmaps/Hiragana.bcmap +0 -0
  112. package/dist/assets/cmaps/KSC-EUC-H.bcmap +0 -0
  113. package/dist/assets/cmaps/KSC-EUC-V.bcmap +0 -0
  114. package/dist/assets/cmaps/KSC-H.bcmap +0 -0
  115. package/dist/assets/cmaps/KSC-Johab-H.bcmap +0 -0
  116. package/dist/assets/cmaps/KSC-Johab-V.bcmap +0 -0
  117. package/dist/assets/cmaps/KSC-V.bcmap +0 -0
  118. package/dist/assets/cmaps/KSCms-UHC-H.bcmap +0 -0
  119. package/dist/assets/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  120. package/dist/assets/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  121. package/dist/assets/cmaps/KSCms-UHC-V.bcmap +0 -0
  122. package/dist/assets/cmaps/KSCpc-EUC-H.bcmap +0 -0
  123. package/dist/assets/cmaps/KSCpc-EUC-V.bcmap +0 -0
  124. package/dist/assets/cmaps/Katakana.bcmap +0 -0
  125. package/dist/assets/cmaps/LICENSE +36 -0
  126. package/dist/assets/cmaps/NWP-H.bcmap +0 -0
  127. package/dist/assets/cmaps/NWP-V.bcmap +0 -0
  128. package/dist/assets/cmaps/RKSJ-H.bcmap +0 -0
  129. package/dist/assets/cmaps/RKSJ-V.bcmap +0 -0
  130. package/dist/assets/cmaps/Roman.bcmap +0 -0
  131. package/dist/assets/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  132. package/dist/assets/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  133. package/dist/assets/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  134. package/dist/assets/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  135. package/dist/assets/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  136. package/dist/assets/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  137. package/dist/assets/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  138. package/dist/assets/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  139. package/dist/assets/cmaps/UniGB-UCS2-H.bcmap +0 -0
  140. package/dist/assets/cmaps/UniGB-UCS2-V.bcmap +0 -0
  141. package/dist/assets/cmaps/UniGB-UTF16-H.bcmap +0 -0
  142. package/dist/assets/cmaps/UniGB-UTF16-V.bcmap +0 -0
  143. package/dist/assets/cmaps/UniGB-UTF32-H.bcmap +0 -0
  144. package/dist/assets/cmaps/UniGB-UTF32-V.bcmap +0 -0
  145. package/dist/assets/cmaps/UniGB-UTF8-H.bcmap +0 -0
  146. package/dist/assets/cmaps/UniGB-UTF8-V.bcmap +0 -0
  147. package/dist/assets/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  148. package/dist/assets/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  149. package/dist/assets/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  150. package/dist/assets/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  151. package/dist/assets/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  152. package/dist/assets/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  153. package/dist/assets/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  154. package/dist/assets/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  155. package/dist/assets/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  156. package/dist/assets/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  157. package/dist/assets/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  158. package/dist/assets/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  159. package/dist/assets/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  160. package/dist/assets/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  161. package/dist/assets/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  162. package/dist/assets/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  163. package/dist/assets/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  164. package/dist/assets/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  165. package/dist/assets/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  166. package/dist/assets/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  167. package/dist/assets/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  168. package/dist/assets/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  169. package/dist/assets/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  170. package/dist/assets/cmaps/UniKS-UCS2-H.bcmap +0 -0
  171. package/dist/assets/cmaps/UniKS-UCS2-V.bcmap +0 -0
  172. package/dist/assets/cmaps/UniKS-UTF16-H.bcmap +0 -0
  173. package/dist/assets/cmaps/UniKS-UTF16-V.bcmap +0 -0
  174. package/dist/assets/cmaps/UniKS-UTF32-H.bcmap +0 -0
  175. package/dist/assets/cmaps/UniKS-UTF32-V.bcmap +0 -0
  176. package/dist/assets/cmaps/UniKS-UTF8-H.bcmap +0 -0
  177. package/dist/assets/cmaps/UniKS-UTF8-V.bcmap +0 -0
  178. package/dist/assets/cmaps/V.bcmap +0 -0
  179. package/dist/assets/cmaps/WP-Symbol.bcmap +0 -0
  180. package/dist/assets/pdf.worker.js +77187 -0
  181. package/dist/assets/standard_fonts/FoxitDingbats.pfb +0 -0
  182. package/dist/assets/standard_fonts/FoxitFixed.pfb +0 -0
  183. package/dist/assets/standard_fonts/FoxitFixedBold.pfb +0 -0
  184. package/dist/assets/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  185. package/dist/assets/standard_fonts/FoxitFixedItalic.pfb +0 -0
  186. package/dist/assets/standard_fonts/FoxitSerif.pfb +0 -0
  187. package/dist/assets/standard_fonts/FoxitSerifBold.pfb +0 -0
  188. package/dist/assets/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  189. package/dist/assets/standard_fonts/FoxitSerifItalic.pfb +0 -0
  190. package/dist/assets/standard_fonts/FoxitSymbol.pfb +0 -0
  191. package/dist/assets/standard_fonts/LICENSE_FOXIT +27 -0
  192. package/dist/assets/standard_fonts/LICENSE_LIBERATION +102 -0
  193. package/dist/assets/standard_fonts/LiberationSans-Bold.ttf +0 -0
  194. package/dist/assets/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  195. package/dist/assets/standard_fonts/LiberationSans-Italic.ttf +0 -0
  196. package/dist/assets/standard_fonts/LiberationSans-Regular.ttf +0 -0
  197. package/dist/assets/xlsx.worker.js +61444 -0
  198. package/dist/core.d.ts +2 -0
  199. package/dist/core.js +3 -0
  200. package/dist/documentAnchor-J7GGLU15.js +69 -0
  201. package/dist/imageFilePreviewPlugin-CxIUlEmg.js +29 -0
  202. package/dist/jszip.min-uwqlc4KL.js +3108 -0
  203. package/dist/react.d.ts +105 -0
  204. package/dist/react.js +3114 -0
  205. package/dist/rolldown-runtime-B-lAHAz2.js +37 -0
  206. package/dist/rotate-ccw-YWx7RzY9.js +36 -0
  207. package/dist/selection-CQPD5a6C.js +47 -0
  208. package/dist/source-DjjzeN4t.d.ts +58 -0
  209. package/dist/source-Rx3etU3y.js +28 -0
  210. package/dist/styles.css +8778 -0
  211. package/dist/styles.js +0 -0
  212. package/dist/touchPinch-C4fl-9fg.js +34 -0
  213. package/dist/useTranslation-DMhY277o.js +7056 -0
  214. package/dist/zoom-out-DLOQGt1e.js +66 -0
  215. package/package.json +69 -3
@@ -0,0 +1,2171 @@
1
+ import { r as readPreviewDocument, t as PreviewError } from "./source-Rx3etU3y.js";
2
+ import { A as dispatchDiscreteCustomEvent, B as createSlot, C as createPopperScope, E as DismissableLayer, F as cn, I as LoaderCircle, M as composeEventHandlers, N as EmptyState, O as useCallbackRef, R as createLucideIcon, S as Root2$1, T as useLayoutEffect2, V as useComposedRefs, _ as Presence, b as Arrow, c as FilePreviewToolbar, g as useControllableState, h as usePortalContainer, i as FilePreviewLayout, j as createContextScope, k as Primitive, o as usePreviewHost, r as FilePreviewToolbarButton, t as useTranslation, v as Portal$1, w as useId$1, x as Content, y as Anchor, z as cva } from "./useTranslation-DMhY277o.js";
3
+ import { n as ZoomIn, t as ZoomOut } from "./zoom-out-DLOQGt1e.js";
4
+ import { i as useFocusGuards, n as hideOthers, r as FocusScope, t as ReactRemoveScroll } from "./Combination-BLg27FvF.js";
5
+ import { t as imageFilePreviewPlugin } from "./imageFilePreviewPlugin-CxIUlEmg.js";
6
+ import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DkHa6toZ.js";
7
+ import * as React$1 from "react";
8
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ /**
11
+ * @license lucide-react v0.545.0 - ISC
12
+ *
13
+ * This source code is licensed under the ISC license.
14
+ * See the LICENSE file in the root directory of this source tree.
15
+ */
16
+ var FlipHorizontal = createLucideIcon("flip-horizontal", [
17
+ ["path", {
18
+ d: "M8 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h3",
19
+ key: "1i73f7"
20
+ }],
21
+ ["path", {
22
+ d: "M16 3h3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-3",
23
+ key: "saxlbk"
24
+ }],
25
+ ["path", {
26
+ d: "M12 20v2",
27
+ key: "1lh1kg"
28
+ }],
29
+ ["path", {
30
+ d: "M12 14v2",
31
+ key: "8jcxud"
32
+ }],
33
+ ["path", {
34
+ d: "M12 8v2",
35
+ key: "1woqiv"
36
+ }],
37
+ ["path", {
38
+ d: "M12 2v2",
39
+ key: "tus03m"
40
+ }]
41
+ ]);
42
+ /**
43
+ * @license lucide-react v0.545.0 - ISC
44
+ *
45
+ * This source code is licensed under the ISC license.
46
+ * See the LICENSE file in the root directory of this source tree.
47
+ */
48
+ var FlipVertical = createLucideIcon("flip-vertical", [
49
+ ["path", {
50
+ d: "M21 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v3",
51
+ key: "14bfxa"
52
+ }],
53
+ ["path", {
54
+ d: "M21 16v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-3",
55
+ key: "14rx03"
56
+ }],
57
+ ["path", {
58
+ d: "M4 12H2",
59
+ key: "rhcxmi"
60
+ }],
61
+ ["path", {
62
+ d: "M10 12H8",
63
+ key: "s88cx1"
64
+ }],
65
+ ["path", {
66
+ d: "M16 12h-2",
67
+ key: "10asgb"
68
+ }],
69
+ ["path", {
70
+ d: "M22 12h-2",
71
+ key: "14jgyd"
72
+ }]
73
+ ]);
74
+ /**
75
+ * @license lucide-react v0.545.0 - ISC
76
+ *
77
+ * This source code is licensed under the ISC license.
78
+ * See the LICENSE file in the root directory of this source tree.
79
+ */
80
+ var ImageOff = createLucideIcon("image-off", [
81
+ ["line", {
82
+ x1: "2",
83
+ x2: "22",
84
+ y1: "2",
85
+ y2: "22",
86
+ key: "a6p6uj"
87
+ }],
88
+ ["path", {
89
+ d: "M10.41 10.41a2 2 0 1 1-2.83-2.83",
90
+ key: "1bzlo9"
91
+ }],
92
+ ["line", {
93
+ x1: "13.5",
94
+ x2: "6",
95
+ y1: "13.5",
96
+ y2: "21",
97
+ key: "1q0aeu"
98
+ }],
99
+ ["line", {
100
+ x1: "18",
101
+ x2: "21",
102
+ y1: "12",
103
+ y2: "15",
104
+ key: "5mozeu"
105
+ }],
106
+ ["path", {
107
+ d: "M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59",
108
+ key: "mmje98"
109
+ }],
110
+ ["path", {
111
+ d: "M21 15V5a2 2 0 0 0-2-2H9",
112
+ key: "43el77"
113
+ }]
114
+ ]);
115
+ /**
116
+ * @license lucide-react v0.545.0 - ISC
117
+ *
118
+ * This source code is licensed under the ISC license.
119
+ * See the LICENSE file in the root directory of this source tree.
120
+ */
121
+ var RefreshCcw = createLucideIcon("refresh-ccw", [
122
+ ["path", {
123
+ d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
124
+ key: "14sxne"
125
+ }],
126
+ ["path", {
127
+ d: "M3 3v5h5",
128
+ key: "1xhq8a"
129
+ }],
130
+ ["path", {
131
+ d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",
132
+ key: "1hlbsb"
133
+ }],
134
+ ["path", {
135
+ d: "M16 16h5v5",
136
+ key: "ccwih5"
137
+ }]
138
+ ]);
139
+ /**
140
+ * @license lucide-react v0.545.0 - ISC
141
+ *
142
+ * This source code is licensed under the ISC license.
143
+ * See the LICENSE file in the root directory of this source tree.
144
+ */
145
+ var RotateCcwSquare = createLucideIcon("rotate-ccw-square", [
146
+ ["path", {
147
+ d: "M20 9V7a2 2 0 0 0-2-2h-6",
148
+ key: "19z8uc"
149
+ }],
150
+ ["path", {
151
+ d: "m15 2-3 3 3 3",
152
+ key: "177bxs"
153
+ }],
154
+ ["path", {
155
+ d: "M20 13v5a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2",
156
+ key: "d36hnl"
157
+ }]
158
+ ]);
159
+ /**
160
+ * @license lucide-react v0.545.0 - ISC
161
+ *
162
+ * This source code is licensed under the ISC license.
163
+ * See the LICENSE file in the root directory of this source tree.
164
+ */
165
+ var RotateCwSquare = createLucideIcon("rotate-cw-square", [
166
+ ["path", {
167
+ d: "M12 5H6a2 2 0 0 0-2 2v3",
168
+ key: "l96uqu"
169
+ }],
170
+ ["path", {
171
+ d: "m9 8 3-3-3-3",
172
+ key: "1gzgc3"
173
+ }],
174
+ ["path", {
175
+ d: "M4 14v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2",
176
+ key: "1w2k5h"
177
+ }]
178
+ ]);
179
+ //#endregion
180
+ //#region ../../node_modules/.pnpm/@radix-ui+react-collection@1.1.12_@types+react-dom@19.2.3_@types+react@19.2.7__@types+r_112705cebe8c9609e851d37f1704b3cb/node_modules/@radix-ui/react-collection/dist/index.mjs
181
+ function createCollection(name) {
182
+ const PROVIDER_NAME = name + "CollectionProvider";
183
+ const [createCollectionContext, createCollectionScope] = createContextScope(PROVIDER_NAME);
184
+ const [CollectionProviderImpl, useCollectionContext] = createCollectionContext(PROVIDER_NAME, {
185
+ collectionRef: { current: null },
186
+ itemMap: /* @__PURE__ */ new Map()
187
+ });
188
+ const CollectionProvider = (props) => {
189
+ const { scope, children } = props;
190
+ const ref = React$1.useRef(null);
191
+ const itemMap = React$1.useRef(/* @__PURE__ */ new Map()).current;
192
+ return /* @__PURE__ */ jsx(CollectionProviderImpl, {
193
+ scope,
194
+ itemMap,
195
+ collectionRef: ref,
196
+ children
197
+ });
198
+ };
199
+ CollectionProvider.displayName = PROVIDER_NAME;
200
+ const COLLECTION_SLOT_NAME = name + "CollectionSlot";
201
+ const CollectionSlotImpl = createSlot(COLLECTION_SLOT_NAME);
202
+ const CollectionSlot = React$1.forwardRef((props, forwardedRef) => {
203
+ const { scope, children } = props;
204
+ const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
205
+ const composedRefs = useComposedRefs(forwardedRef, context.collectionRef);
206
+ return /* @__PURE__ */ jsx(CollectionSlotImpl, {
207
+ ref: composedRefs,
208
+ children
209
+ });
210
+ });
211
+ CollectionSlot.displayName = COLLECTION_SLOT_NAME;
212
+ const ITEM_SLOT_NAME = name + "CollectionItemSlot";
213
+ const ITEM_DATA_ATTR = "data-radix-collection-item";
214
+ const CollectionItemSlotImpl = createSlot(ITEM_SLOT_NAME);
215
+ const CollectionItemSlot = React$1.forwardRef((props, forwardedRef) => {
216
+ const { scope, children, ...itemData } = props;
217
+ const ref = React$1.useRef(null);
218
+ const composedRefs = useComposedRefs(forwardedRef, ref);
219
+ const context = useCollectionContext(ITEM_SLOT_NAME, scope);
220
+ React$1.useEffect(() => {
221
+ context.itemMap.set(ref, {
222
+ ref,
223
+ ...itemData
224
+ });
225
+ return () => void context.itemMap.delete(ref);
226
+ });
227
+ return /* @__PURE__ */ jsx(CollectionItemSlotImpl, {
228
+ [ITEM_DATA_ATTR]: "",
229
+ ref: composedRefs,
230
+ children
231
+ });
232
+ });
233
+ CollectionItemSlot.displayName = ITEM_SLOT_NAME;
234
+ function useCollection(scope) {
235
+ const context = useCollectionContext(name + "CollectionConsumer", scope);
236
+ return React$1.useCallback(() => {
237
+ const collectionNode = context.collectionRef.current;
238
+ if (!collectionNode) return [];
239
+ const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
240
+ return Array.from(context.itemMap.values()).sort((a, b) => orderedNodes.indexOf(a.ref.current) - orderedNodes.indexOf(b.ref.current));
241
+ }, [context.collectionRef, context.itemMap]);
242
+ }
243
+ return [
244
+ {
245
+ Provider: CollectionProvider,
246
+ Slot: CollectionSlot,
247
+ ItemSlot: CollectionItemSlot
248
+ },
249
+ useCollection,
250
+ createCollectionScope
251
+ ];
252
+ }
253
+ //#endregion
254
+ //#region ../../node_modules/.pnpm/@radix-ui+react-direction@1.1.2_@types+react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-direction/dist/index.mjs
255
+ var DirectionContext = React$1.createContext(void 0);
256
+ function useDirection(localDir) {
257
+ const globalDir = React$1.useContext(DirectionContext);
258
+ return localDir || globalDir || "ltr";
259
+ }
260
+ //#endregion
261
+ //#region ../../node_modules/.pnpm/@radix-ui+react-use-is-hydrated@0.1.1_@types+react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-is-hydrated/dist/index.mjs
262
+ var _isHydrated = false;
263
+ function useIsHydrated() {
264
+ const [isHydrated, setIsHydrated] = React$1.useState(_isHydrated);
265
+ React$1.useEffect(() => {
266
+ if (!_isHydrated) {
267
+ _isHydrated = true;
268
+ setIsHydrated(true);
269
+ }
270
+ }, []);
271
+ return isHydrated;
272
+ }
273
+ var useReactSyncExternalStore = React$1[" useSyncExternalStore ".trim().toString()];
274
+ function subscribe() {
275
+ return () => {};
276
+ }
277
+ function useIsHydratedModern() {
278
+ return useReactSyncExternalStore(subscribe, () => true, () => false);
279
+ }
280
+ var useIsHydrated2 = typeof useReactSyncExternalStore === "function" ? useIsHydratedModern : useIsHydrated;
281
+ //#endregion
282
+ //#region ../../node_modules/.pnpm/@radix-ui+react-roving-focus@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.7__@types_a3e7181ca1ddf9f417a9ee1ec3a8ec52/node_modules/@radix-ui/react-roving-focus/dist/index.mjs
283
+ var ENTRY_FOCUS = "rovingFocusGroup.onEntryFocus";
284
+ var EVENT_OPTIONS = {
285
+ bubbles: false,
286
+ cancelable: true
287
+ };
288
+ var GROUP_NAME$2 = "RovingFocusGroup";
289
+ var [Collection$1, useCollection$1, createCollectionScope$1] = createCollection(GROUP_NAME$2);
290
+ var [createRovingFocusGroupContext, createRovingFocusGroupScope] = createContextScope(GROUP_NAME$2, [createCollectionScope$1]);
291
+ var [RovingFocusProvider, useRovingFocusContext] = createRovingFocusGroupContext(GROUP_NAME$2);
292
+ var RovingFocusGroup = React$1.forwardRef((props, forwardedRef) => {
293
+ return /* @__PURE__ */ jsx(Collection$1.Provider, {
294
+ scope: props.__scopeRovingFocusGroup,
295
+ children: /* @__PURE__ */ jsx(Collection$1.Slot, {
296
+ scope: props.__scopeRovingFocusGroup,
297
+ children: /* @__PURE__ */ jsx(RovingFocusGroupImpl, {
298
+ ...props,
299
+ ref: forwardedRef
300
+ })
301
+ })
302
+ });
303
+ });
304
+ RovingFocusGroup.displayName = GROUP_NAME$2;
305
+ var RovingFocusGroupImpl = React$1.forwardRef((props, forwardedRef) => {
306
+ const { __scopeRovingFocusGroup, orientation, loop = false, dir, currentTabStopId: currentTabStopIdProp, defaultCurrentTabStopId, onCurrentTabStopIdChange, onEntryFocus, preventScrollOnEntryFocus = false, ...groupProps } = props;
307
+ const ref = React$1.useRef(null);
308
+ const composedRefs = useComposedRefs(forwardedRef, ref);
309
+ const direction = useDirection(dir);
310
+ const [currentTabStopId, setCurrentTabStopId] = useControllableState({
311
+ prop: currentTabStopIdProp,
312
+ defaultProp: defaultCurrentTabStopId ?? null,
313
+ onChange: onCurrentTabStopIdChange,
314
+ caller: GROUP_NAME$2
315
+ });
316
+ const [isTabbingBackOut, setIsTabbingBackOut] = React$1.useState(false);
317
+ const handleEntryFocus = useCallbackRef(onEntryFocus);
318
+ const getItems = useCollection$1(__scopeRovingFocusGroup);
319
+ const isClickFocusRef = React$1.useRef(false);
320
+ const [focusableItemsCount, setFocusableItemsCount] = React$1.useState(0);
321
+ React$1.useEffect(() => {
322
+ const node = ref.current;
323
+ if (node) {
324
+ node.addEventListener(ENTRY_FOCUS, handleEntryFocus);
325
+ return () => node.removeEventListener(ENTRY_FOCUS, handleEntryFocus);
326
+ }
327
+ }, [handleEntryFocus]);
328
+ return /* @__PURE__ */ jsx(RovingFocusProvider, {
329
+ scope: __scopeRovingFocusGroup,
330
+ orientation,
331
+ dir: direction,
332
+ loop,
333
+ currentTabStopId,
334
+ onItemFocus: React$1.useCallback((tabStopId) => setCurrentTabStopId(tabStopId), [setCurrentTabStopId]),
335
+ onItemShiftTab: React$1.useCallback(() => setIsTabbingBackOut(true), []),
336
+ onFocusableItemAdd: React$1.useCallback(() => setFocusableItemsCount((prevCount) => prevCount + 1), []),
337
+ onFocusableItemRemove: React$1.useCallback(() => setFocusableItemsCount((prevCount) => prevCount - 1), []),
338
+ children: /* @__PURE__ */ jsx(Primitive.div, {
339
+ tabIndex: isTabbingBackOut || focusableItemsCount === 0 ? -1 : 0,
340
+ "data-orientation": orientation,
341
+ ...groupProps,
342
+ ref: composedRefs,
343
+ style: {
344
+ outline: "none",
345
+ ...props.style
346
+ },
347
+ onMouseDown: composeEventHandlers(props.onMouseDown, () => {
348
+ isClickFocusRef.current = true;
349
+ }),
350
+ onFocus: composeEventHandlers(props.onFocus, (event) => {
351
+ const isKeyboardFocus = !isClickFocusRef.current;
352
+ if (event.target === event.currentTarget && isKeyboardFocus && !isTabbingBackOut) {
353
+ const entryFocusEvent = new CustomEvent(ENTRY_FOCUS, EVENT_OPTIONS);
354
+ event.currentTarget.dispatchEvent(entryFocusEvent);
355
+ if (!entryFocusEvent.defaultPrevented) {
356
+ const items = getItems().filter((item) => item.focusable);
357
+ focusFirst$1([
358
+ items.find((item) => item.active),
359
+ items.find((item) => item.id === currentTabStopId),
360
+ ...items
361
+ ].filter(Boolean).map((item) => item.ref.current), preventScrollOnEntryFocus);
362
+ }
363
+ }
364
+ isClickFocusRef.current = false;
365
+ }),
366
+ onBlur: composeEventHandlers(props.onBlur, () => setIsTabbingBackOut(false))
367
+ })
368
+ });
369
+ });
370
+ var ITEM_NAME$2 = "RovingFocusGroupItem";
371
+ var RovingFocusGroupItem = React$1.forwardRef((props, forwardedRef) => {
372
+ const { __scopeRovingFocusGroup, focusable = true, active = false, tabStopId, children, ...itemProps } = props;
373
+ const autoId = useId$1();
374
+ const id = tabStopId || autoId;
375
+ const context = useRovingFocusContext(ITEM_NAME$2, __scopeRovingFocusGroup);
376
+ const isCurrentTabStop = context.currentTabStopId === id;
377
+ const getItems = useCollection$1(__scopeRovingFocusGroup);
378
+ const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;
379
+ const isHydrated = useIsHydrated2();
380
+ useLayoutEffect2(() => {
381
+ if (!isHydrated || !focusable) return;
382
+ onFocusableItemAdd();
383
+ return () => onFocusableItemRemove();
384
+ }, [
385
+ isHydrated,
386
+ focusable,
387
+ onFocusableItemAdd,
388
+ onFocusableItemRemove
389
+ ]);
390
+ React$1.useEffect(() => {
391
+ if (isHydrated || !focusable) return;
392
+ onFocusableItemAdd();
393
+ return () => onFocusableItemRemove();
394
+ }, [
395
+ isHydrated,
396
+ focusable,
397
+ onFocusableItemAdd,
398
+ onFocusableItemRemove
399
+ ]);
400
+ return /* @__PURE__ */ jsx(Collection$1.ItemSlot, {
401
+ scope: __scopeRovingFocusGroup,
402
+ id,
403
+ focusable,
404
+ active,
405
+ children: /* @__PURE__ */ jsx(Primitive.span, {
406
+ tabIndex: isCurrentTabStop ? 0 : -1,
407
+ "data-orientation": context.orientation,
408
+ ...itemProps,
409
+ ref: forwardedRef,
410
+ onMouseDown: composeEventHandlers(props.onMouseDown, (event) => {
411
+ if (!focusable) event.preventDefault();
412
+ else context.onItemFocus(id);
413
+ }),
414
+ onFocus: composeEventHandlers(props.onFocus, () => context.onItemFocus(id)),
415
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
416
+ if (event.key === "Tab" && event.shiftKey) {
417
+ context.onItemShiftTab();
418
+ return;
419
+ }
420
+ if (event.target !== event.currentTarget) return;
421
+ const focusIntent = getFocusIntent(event, context.orientation, context.dir);
422
+ if (focusIntent !== void 0) {
423
+ if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
424
+ event.preventDefault();
425
+ let candidateNodes = getItems().filter((item) => item.focusable).map((item) => item.ref.current);
426
+ if (focusIntent === "last") candidateNodes.reverse();
427
+ else if (focusIntent === "prev" || focusIntent === "next") {
428
+ if (focusIntent === "prev") candidateNodes.reverse();
429
+ const currentIndex = candidateNodes.indexOf(event.currentTarget);
430
+ candidateNodes = context.loop ? wrapArray$1(candidateNodes, currentIndex + 1) : candidateNodes.slice(currentIndex + 1);
431
+ }
432
+ setTimeout(() => focusFirst$1(candidateNodes));
433
+ }
434
+ }),
435
+ children: typeof children === "function" ? children({
436
+ isCurrentTabStop,
437
+ hasTabStop: currentTabStopId != null
438
+ }) : children
439
+ })
440
+ });
441
+ });
442
+ RovingFocusGroupItem.displayName = ITEM_NAME$2;
443
+ var MAP_KEY_TO_FOCUS_INTENT = {
444
+ ArrowLeft: "prev",
445
+ ArrowUp: "prev",
446
+ ArrowRight: "next",
447
+ ArrowDown: "next",
448
+ PageUp: "first",
449
+ Home: "first",
450
+ PageDown: "last",
451
+ End: "last"
452
+ };
453
+ function getDirectionAwareKey(key, dir) {
454
+ if (dir !== "rtl") return key;
455
+ return key === "ArrowLeft" ? "ArrowRight" : key === "ArrowRight" ? "ArrowLeft" : key;
456
+ }
457
+ function getFocusIntent(event, orientation, dir) {
458
+ const key = getDirectionAwareKey(event.key, dir);
459
+ if (orientation === "vertical" && ["ArrowLeft", "ArrowRight"].includes(key)) return void 0;
460
+ if (orientation === "horizontal" && ["ArrowUp", "ArrowDown"].includes(key)) return void 0;
461
+ return MAP_KEY_TO_FOCUS_INTENT[key];
462
+ }
463
+ function focusFirst$1(candidates, preventScroll = false) {
464
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
465
+ for (const candidate of candidates) {
466
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
467
+ candidate.focus({ preventScroll });
468
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
469
+ }
470
+ }
471
+ function wrapArray$1(array, startIndex) {
472
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
473
+ }
474
+ var Root = RovingFocusGroup;
475
+ var Item = RovingFocusGroupItem;
476
+ //#endregion
477
+ //#region ../../node_modules/.pnpm/@radix-ui+react-menu@2.1.20_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@1_810a3a7c2c9e98b2fe6701e5c5df7684/node_modules/@radix-ui/react-menu/dist/index.mjs
478
+ var SELECTION_KEYS = ["Enter", " "];
479
+ var FIRST_KEYS = [
480
+ "ArrowDown",
481
+ "PageUp",
482
+ "Home"
483
+ ];
484
+ var LAST_KEYS = [
485
+ "ArrowUp",
486
+ "PageDown",
487
+ "End"
488
+ ];
489
+ var FIRST_LAST_KEYS = [...FIRST_KEYS, ...LAST_KEYS];
490
+ var SUB_OPEN_KEYS = {
491
+ ltr: [...SELECTION_KEYS, "ArrowRight"],
492
+ rtl: [...SELECTION_KEYS, "ArrowLeft"]
493
+ };
494
+ var SUB_CLOSE_KEYS = {
495
+ ltr: ["ArrowLeft"],
496
+ rtl: ["ArrowRight"]
497
+ };
498
+ var MENU_NAME = "Menu";
499
+ var [Collection, useCollection, createCollectionScope] = createCollection(MENU_NAME);
500
+ var [createMenuContext, createMenuScope] = createContextScope(MENU_NAME, [
501
+ createCollectionScope,
502
+ createPopperScope,
503
+ createRovingFocusGroupScope
504
+ ]);
505
+ var usePopperScope = createPopperScope();
506
+ var useRovingFocusGroupScope = createRovingFocusGroupScope();
507
+ var [MenuProvider, useMenuContext] = createMenuContext(MENU_NAME);
508
+ var [MenuRootProvider, useMenuRootContext] = createMenuContext(MENU_NAME);
509
+ var Menu = (props) => {
510
+ const { __scopeMenu, open = false, children, dir, onOpenChange, modal = true } = props;
511
+ const popperScope = usePopperScope(__scopeMenu);
512
+ const [content, setContent] = React$1.useState(null);
513
+ const isUsingKeyboardRef = React$1.useRef(false);
514
+ const handleOpenChange = useCallbackRef(onOpenChange);
515
+ const direction = useDirection(dir);
516
+ React$1.useEffect(() => {
517
+ const handleKeyDown = () => {
518
+ isUsingKeyboardRef.current = true;
519
+ document.addEventListener("pointerdown", handlePointer, {
520
+ capture: true,
521
+ once: true
522
+ });
523
+ document.addEventListener("pointermove", handlePointer, {
524
+ capture: true,
525
+ once: true
526
+ });
527
+ };
528
+ const handlePointer = () => isUsingKeyboardRef.current = false;
529
+ document.addEventListener("keydown", handleKeyDown, { capture: true });
530
+ return () => {
531
+ document.removeEventListener("keydown", handleKeyDown, { capture: true });
532
+ document.removeEventListener("pointerdown", handlePointer, { capture: true });
533
+ document.removeEventListener("pointermove", handlePointer, { capture: true });
534
+ };
535
+ }, []);
536
+ React$1.useEffect(() => {
537
+ if (!open) return;
538
+ const handleBlur = () => handleOpenChange(false);
539
+ window.addEventListener("blur", handleBlur);
540
+ return () => window.removeEventListener("blur", handleBlur);
541
+ }, [open, handleOpenChange]);
542
+ return /* @__PURE__ */ jsx(Root2$1, {
543
+ ...popperScope,
544
+ children: /* @__PURE__ */ jsx(MenuProvider, {
545
+ scope: __scopeMenu,
546
+ open,
547
+ onOpenChange: handleOpenChange,
548
+ content,
549
+ onContentChange: setContent,
550
+ children: /* @__PURE__ */ jsx(MenuRootProvider, {
551
+ scope: __scopeMenu,
552
+ onClose: React$1.useCallback(() => handleOpenChange(false), [handleOpenChange]),
553
+ isUsingKeyboardRef,
554
+ dir: direction,
555
+ modal,
556
+ children
557
+ })
558
+ })
559
+ });
560
+ };
561
+ Menu.displayName = MENU_NAME;
562
+ var ANCHOR_NAME = "MenuAnchor";
563
+ var MenuAnchor = React$1.forwardRef((props, forwardedRef) => {
564
+ const { __scopeMenu, ...anchorProps } = props;
565
+ const popperScope = usePopperScope(__scopeMenu);
566
+ return /* @__PURE__ */ jsx(Anchor, {
567
+ ...popperScope,
568
+ ...anchorProps,
569
+ ref: forwardedRef
570
+ });
571
+ });
572
+ MenuAnchor.displayName = ANCHOR_NAME;
573
+ var PORTAL_NAME$1 = "MenuPortal";
574
+ var [PortalProvider, usePortalContext] = createMenuContext(PORTAL_NAME$1, { forceMount: void 0 });
575
+ var MenuPortal = (props) => {
576
+ const { __scopeMenu, forceMount, children, container } = props;
577
+ const context = useMenuContext(PORTAL_NAME$1, __scopeMenu);
578
+ return /* @__PURE__ */ jsx(PortalProvider, {
579
+ scope: __scopeMenu,
580
+ forceMount,
581
+ children: /* @__PURE__ */ jsx(Presence, {
582
+ present: forceMount || context.open,
583
+ children: /* @__PURE__ */ jsx(Portal$1, {
584
+ asChild: true,
585
+ container,
586
+ children
587
+ })
588
+ })
589
+ });
590
+ };
591
+ MenuPortal.displayName = PORTAL_NAME$1;
592
+ var CONTENT_NAME$1 = "MenuContent";
593
+ var [MenuContentProvider, useMenuContentContext] = createMenuContext(CONTENT_NAME$1);
594
+ var MenuContent = React$1.forwardRef((props, forwardedRef) => {
595
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
596
+ const { forceMount = portalContext.forceMount, ...contentProps } = props;
597
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
598
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
599
+ return /* @__PURE__ */ jsx(Collection.Provider, {
600
+ scope: props.__scopeMenu,
601
+ children: /* @__PURE__ */ jsx(Presence, {
602
+ present: forceMount || context.open,
603
+ children: /* @__PURE__ */ jsx(Collection.Slot, {
604
+ scope: props.__scopeMenu,
605
+ children: rootContext.modal ? /* @__PURE__ */ jsx(MenuRootContentModal, {
606
+ ...contentProps,
607
+ ref: forwardedRef
608
+ }) : /* @__PURE__ */ jsx(MenuRootContentNonModal, {
609
+ ...contentProps,
610
+ ref: forwardedRef
611
+ })
612
+ })
613
+ })
614
+ });
615
+ });
616
+ var MenuRootContentModal = React$1.forwardRef((props, forwardedRef) => {
617
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
618
+ const ref = React$1.useRef(null);
619
+ const composedRefs = useComposedRefs(forwardedRef, ref);
620
+ React$1.useEffect(() => {
621
+ const content = ref.current;
622
+ if (content) return hideOthers(content);
623
+ }, []);
624
+ return /* @__PURE__ */ jsx(MenuContentImpl, {
625
+ ...props,
626
+ ref: composedRefs,
627
+ trapFocus: context.open,
628
+ disableOutsidePointerEvents: context.open,
629
+ disableOutsideScroll: true,
630
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, (event) => event.preventDefault(), { checkForDefaultPrevented: false }),
631
+ onDismiss: () => context.onOpenChange(false)
632
+ });
633
+ });
634
+ var MenuRootContentNonModal = React$1.forwardRef((props, forwardedRef) => {
635
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
636
+ return /* @__PURE__ */ jsx(MenuContentImpl, {
637
+ ...props,
638
+ ref: forwardedRef,
639
+ trapFocus: false,
640
+ disableOutsidePointerEvents: false,
641
+ disableOutsideScroll: false,
642
+ onDismiss: () => context.onOpenChange(false)
643
+ });
644
+ });
645
+ var Slot = createSlot("MenuContent.ScrollLock");
646
+ var MenuContentImpl = React$1.forwardRef((props, forwardedRef) => {
647
+ const { __scopeMenu, loop = false, trapFocus, onOpenAutoFocus, onCloseAutoFocus, disableOutsidePointerEvents, onEntryFocus, onEscapeKeyDown, onPointerDownOutside, onFocusOutside, onInteractOutside, onDismiss, disableOutsideScroll, ...contentProps } = props;
648
+ const context = useMenuContext(CONTENT_NAME$1, __scopeMenu);
649
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, __scopeMenu);
650
+ const popperScope = usePopperScope(__scopeMenu);
651
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
652
+ const getItems = useCollection(__scopeMenu);
653
+ const [currentItemId, setCurrentItemId] = React$1.useState(null);
654
+ const contentRef = React$1.useRef(null);
655
+ const composedRefs = useComposedRefs(forwardedRef, contentRef, context.onContentChange);
656
+ const timerRef = React$1.useRef(0);
657
+ const searchRef = React$1.useRef("");
658
+ const pointerGraceTimerRef = React$1.useRef(0);
659
+ const pointerGraceIntentRef = React$1.useRef(null);
660
+ const pointerDirRef = React$1.useRef("right");
661
+ const lastPointerXRef = React$1.useRef(0);
662
+ const ScrollLockWrapper = disableOutsideScroll ? ReactRemoveScroll : React$1.Fragment;
663
+ const scrollLockWrapperProps = disableOutsideScroll ? {
664
+ as: Slot,
665
+ allowPinchZoom: true
666
+ } : void 0;
667
+ const handleTypeaheadSearch = (key) => {
668
+ const search = searchRef.current + key;
669
+ const items = getItems().filter((item) => !item.disabled);
670
+ const currentItem = document.activeElement;
671
+ const currentMatch = items.find((item) => item.ref.current === currentItem)?.textValue;
672
+ const nextMatch = getNextMatch(items.map((item) => item.textValue), search, currentMatch);
673
+ const newItem = items.find((item) => item.textValue === nextMatch)?.ref.current;
674
+ (function updateSearch(value) {
675
+ searchRef.current = value;
676
+ window.clearTimeout(timerRef.current);
677
+ if (value !== "") timerRef.current = window.setTimeout(() => updateSearch(""), 1e3);
678
+ })(search);
679
+ if (newItem) setTimeout(() => newItem.focus());
680
+ };
681
+ React$1.useEffect(() => {
682
+ return () => window.clearTimeout(timerRef.current);
683
+ }, []);
684
+ useFocusGuards();
685
+ const isPointerMovingToSubmenu = React$1.useCallback((event) => {
686
+ return pointerDirRef.current === pointerGraceIntentRef.current?.side && isPointerInGraceArea(event, pointerGraceIntentRef.current?.area);
687
+ }, []);
688
+ return /* @__PURE__ */ jsx(MenuContentProvider, {
689
+ scope: __scopeMenu,
690
+ searchRef,
691
+ onItemEnter: React$1.useCallback((event) => {
692
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
693
+ }, [isPointerMovingToSubmenu]),
694
+ onItemLeave: React$1.useCallback((event) => {
695
+ if (isPointerMovingToSubmenu(event)) return;
696
+ contentRef.current?.focus();
697
+ setCurrentItemId(null);
698
+ }, [isPointerMovingToSubmenu]),
699
+ onTriggerLeave: React$1.useCallback((event) => {
700
+ if (isPointerMovingToSubmenu(event)) event.preventDefault();
701
+ }, [isPointerMovingToSubmenu]),
702
+ pointerGraceTimerRef,
703
+ onPointerGraceIntentChange: React$1.useCallback((intent) => {
704
+ pointerGraceIntentRef.current = intent;
705
+ }, []),
706
+ children: /* @__PURE__ */ jsx(ScrollLockWrapper, {
707
+ ...scrollLockWrapperProps,
708
+ children: /* @__PURE__ */ jsx(FocusScope, {
709
+ asChild: true,
710
+ trapped: trapFocus,
711
+ onMountAutoFocus: composeEventHandlers(onOpenAutoFocus, (event) => {
712
+ event.preventDefault();
713
+ contentRef.current?.focus({ preventScroll: true });
714
+ }),
715
+ onUnmountAutoFocus: onCloseAutoFocus,
716
+ children: /* @__PURE__ */ jsx(DismissableLayer, {
717
+ asChild: true,
718
+ disableOutsidePointerEvents,
719
+ onEscapeKeyDown,
720
+ onPointerDownOutside,
721
+ onFocusOutside,
722
+ onInteractOutside,
723
+ onDismiss,
724
+ children: /* @__PURE__ */ jsx(Root, {
725
+ asChild: true,
726
+ ...rovingFocusGroupScope,
727
+ dir: rootContext.dir,
728
+ orientation: "vertical",
729
+ loop,
730
+ currentTabStopId: currentItemId,
731
+ onCurrentTabStopIdChange: setCurrentItemId,
732
+ onEntryFocus: composeEventHandlers(onEntryFocus, (event) => {
733
+ if (!rootContext.isUsingKeyboardRef.current) event.preventDefault();
734
+ }),
735
+ preventScrollOnEntryFocus: true,
736
+ children: /* @__PURE__ */ jsx(Content, {
737
+ role: "menu",
738
+ "aria-orientation": "vertical",
739
+ "data-state": getOpenState(context.open),
740
+ "data-radix-menu-content": "",
741
+ dir: rootContext.dir,
742
+ ...popperScope,
743
+ ...contentProps,
744
+ ref: composedRefs,
745
+ style: {
746
+ outline: "none",
747
+ ...contentProps.style
748
+ },
749
+ onKeyDown: composeEventHandlers(contentProps.onKeyDown, (event) => {
750
+ const isKeyDownInside = event.target.closest("[data-radix-menu-content]") === event.currentTarget;
751
+ const isModifierKey = event.ctrlKey || event.altKey || event.metaKey;
752
+ const isCharacterKey = event.key.length === 1;
753
+ if (isKeyDownInside) {
754
+ if (event.key === "Tab") event.preventDefault();
755
+ if (!isModifierKey && isCharacterKey) handleTypeaheadSearch(event.key);
756
+ }
757
+ const content = contentRef.current;
758
+ if (event.target !== content) return;
759
+ if (!FIRST_LAST_KEYS.includes(event.key)) return;
760
+ event.preventDefault();
761
+ const candidateNodes = getItems().filter((item) => !item.disabled).map((item) => item.ref.current);
762
+ if (LAST_KEYS.includes(event.key)) candidateNodes.reverse();
763
+ focusFirst(candidateNodes);
764
+ }),
765
+ onBlur: composeEventHandlers(props.onBlur, (event) => {
766
+ if (!event.currentTarget.contains(event.target)) {
767
+ window.clearTimeout(timerRef.current);
768
+ searchRef.current = "";
769
+ }
770
+ }),
771
+ onPointerMove: composeEventHandlers(props.onPointerMove, whenMouse((event) => {
772
+ const target = event.target;
773
+ const pointerXHasChanged = lastPointerXRef.current !== event.clientX;
774
+ if (event.currentTarget.contains(target) && pointerXHasChanged) {
775
+ const newDir = event.clientX > lastPointerXRef.current ? "right" : "left";
776
+ pointerDirRef.current = newDir;
777
+ lastPointerXRef.current = event.clientX;
778
+ }
779
+ }))
780
+ })
781
+ })
782
+ })
783
+ })
784
+ })
785
+ });
786
+ });
787
+ MenuContent.displayName = CONTENT_NAME$1;
788
+ var GROUP_NAME$1 = "MenuGroup";
789
+ var MenuGroup = React$1.forwardRef((props, forwardedRef) => {
790
+ const { __scopeMenu, ...groupProps } = props;
791
+ return /* @__PURE__ */ jsx(Primitive.div, {
792
+ role: "group",
793
+ ...groupProps,
794
+ ref: forwardedRef
795
+ });
796
+ });
797
+ MenuGroup.displayName = GROUP_NAME$1;
798
+ var LABEL_NAME$1 = "MenuLabel";
799
+ var MenuLabel = React$1.forwardRef((props, forwardedRef) => {
800
+ const { __scopeMenu, ...labelProps } = props;
801
+ return /* @__PURE__ */ jsx(Primitive.div, {
802
+ ...labelProps,
803
+ ref: forwardedRef
804
+ });
805
+ });
806
+ MenuLabel.displayName = LABEL_NAME$1;
807
+ var ITEM_NAME$1 = "MenuItem";
808
+ var ITEM_SELECT = "menu.itemSelect";
809
+ var MenuItem = React$1.forwardRef((props, forwardedRef) => {
810
+ const { disabled = false, onSelect, ...itemProps } = props;
811
+ const ref = React$1.useRef(null);
812
+ const rootContext = useMenuRootContext(ITEM_NAME$1, props.__scopeMenu);
813
+ const contentContext = useMenuContentContext(ITEM_NAME$1, props.__scopeMenu);
814
+ const composedRefs = useComposedRefs(forwardedRef, ref);
815
+ const isPointerDownRef = React$1.useRef(false);
816
+ const handleSelect = () => {
817
+ const menuItem = ref.current;
818
+ if (!disabled && menuItem) {
819
+ const itemSelectEvent = new CustomEvent(ITEM_SELECT, {
820
+ bubbles: true,
821
+ cancelable: true
822
+ });
823
+ menuItem.addEventListener(ITEM_SELECT, (event) => onSelect?.(event), { once: true });
824
+ dispatchDiscreteCustomEvent(menuItem, itemSelectEvent);
825
+ if (itemSelectEvent.defaultPrevented) isPointerDownRef.current = false;
826
+ else rootContext.onClose();
827
+ }
828
+ };
829
+ return /* @__PURE__ */ jsx(MenuItemImpl, {
830
+ ...itemProps,
831
+ ref: composedRefs,
832
+ disabled,
833
+ onClick: composeEventHandlers(props.onClick, handleSelect),
834
+ onPointerDown: (event) => {
835
+ props.onPointerDown?.(event);
836
+ isPointerDownRef.current = true;
837
+ },
838
+ onPointerUp: composeEventHandlers(props.onPointerUp, (event) => {
839
+ if (!isPointerDownRef.current) event.currentTarget?.click();
840
+ }),
841
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
842
+ if (disabled || event.target !== event.currentTarget) return;
843
+ if (contentContext.searchRef.current !== "" && event.key === " ") return;
844
+ if (SELECTION_KEYS.includes(event.key)) {
845
+ event.currentTarget.click();
846
+ event.preventDefault();
847
+ }
848
+ })
849
+ });
850
+ });
851
+ MenuItem.displayName = ITEM_NAME$1;
852
+ var MenuItemImpl = React$1.forwardRef((props, forwardedRef) => {
853
+ const { __scopeMenu, disabled = false, textValue, ...itemProps } = props;
854
+ const contentContext = useMenuContentContext(ITEM_NAME$1, __scopeMenu);
855
+ const rovingFocusGroupScope = useRovingFocusGroupScope(__scopeMenu);
856
+ const ref = React$1.useRef(null);
857
+ const composedRefs = useComposedRefs(forwardedRef, ref);
858
+ const [isFocused, setIsFocused] = React$1.useState(false);
859
+ const [textContent, setTextContent] = React$1.useState("");
860
+ React$1.useEffect(() => {
861
+ const menuItem = ref.current;
862
+ if (menuItem) setTextContent((menuItem.textContent ?? "").trim());
863
+ }, [itemProps.children]);
864
+ return /* @__PURE__ */ jsx(Collection.ItemSlot, {
865
+ scope: __scopeMenu,
866
+ disabled,
867
+ textValue: textValue ?? textContent,
868
+ children: /* @__PURE__ */ jsx(Item, {
869
+ asChild: true,
870
+ ...rovingFocusGroupScope,
871
+ focusable: !disabled,
872
+ children: /* @__PURE__ */ jsx(Primitive.div, {
873
+ role: "menuitem",
874
+ "data-highlighted": isFocused ? "" : void 0,
875
+ "aria-disabled": disabled || void 0,
876
+ "data-disabled": disabled ? "" : void 0,
877
+ ...itemProps,
878
+ ref: composedRefs,
879
+ onPointerMove: composeEventHandlers(props.onPointerMove, whenMouse((event) => {
880
+ if (disabled) contentContext.onItemLeave(event);
881
+ else {
882
+ contentContext.onItemEnter(event);
883
+ if (!event.defaultPrevented) event.currentTarget.focus({ preventScroll: true });
884
+ }
885
+ })),
886
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, whenMouse((event) => contentContext.onItemLeave(event))),
887
+ onFocus: composeEventHandlers(props.onFocus, () => setIsFocused(true)),
888
+ onBlur: composeEventHandlers(props.onBlur, () => setIsFocused(false))
889
+ })
890
+ })
891
+ });
892
+ });
893
+ var CHECKBOX_ITEM_NAME$1 = "MenuCheckboxItem";
894
+ var MenuCheckboxItem = React$1.forwardRef((props, forwardedRef) => {
895
+ const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
896
+ return /* @__PURE__ */ jsx(ItemIndicatorProvider, {
897
+ scope: props.__scopeMenu,
898
+ checked,
899
+ children: /* @__PURE__ */ jsx(MenuItem, {
900
+ role: "menuitemcheckbox",
901
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
902
+ ...checkboxItemProps,
903
+ ref: forwardedRef,
904
+ "data-state": getCheckedState(checked),
905
+ onSelect: composeEventHandlers(checkboxItemProps.onSelect, () => onCheckedChange?.(isIndeterminate(checked) ? true : !checked), { checkForDefaultPrevented: false })
906
+ })
907
+ });
908
+ });
909
+ MenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME$1;
910
+ var RADIO_GROUP_NAME$1 = "MenuRadioGroup";
911
+ var [RadioGroupProvider, useRadioGroupContext] = createMenuContext(RADIO_GROUP_NAME$1, {
912
+ value: void 0,
913
+ onValueChange: () => {}
914
+ });
915
+ var MenuRadioGroup = React$1.forwardRef((props, forwardedRef) => {
916
+ const { value, onValueChange, ...groupProps } = props;
917
+ const handleValueChange = useCallbackRef(onValueChange);
918
+ return /* @__PURE__ */ jsx(RadioGroupProvider, {
919
+ scope: props.__scopeMenu,
920
+ value,
921
+ onValueChange: handleValueChange,
922
+ children: /* @__PURE__ */ jsx(MenuGroup, {
923
+ ...groupProps,
924
+ ref: forwardedRef
925
+ })
926
+ });
927
+ });
928
+ MenuRadioGroup.displayName = RADIO_GROUP_NAME$1;
929
+ var RADIO_ITEM_NAME$1 = "MenuRadioItem";
930
+ var MenuRadioItem = React$1.forwardRef((props, forwardedRef) => {
931
+ const { value, ...radioItemProps } = props;
932
+ const context = useRadioGroupContext(RADIO_ITEM_NAME$1, props.__scopeMenu);
933
+ const checked = value === context.value;
934
+ return /* @__PURE__ */ jsx(ItemIndicatorProvider, {
935
+ scope: props.__scopeMenu,
936
+ checked,
937
+ children: /* @__PURE__ */ jsx(MenuItem, {
938
+ role: "menuitemradio",
939
+ "aria-checked": checked,
940
+ ...radioItemProps,
941
+ ref: forwardedRef,
942
+ "data-state": getCheckedState(checked),
943
+ onSelect: composeEventHandlers(radioItemProps.onSelect, () => context.onValueChange?.(value), { checkForDefaultPrevented: false })
944
+ })
945
+ });
946
+ });
947
+ MenuRadioItem.displayName = RADIO_ITEM_NAME$1;
948
+ var ITEM_INDICATOR_NAME = "MenuItemIndicator";
949
+ var [ItemIndicatorProvider, useItemIndicatorContext] = createMenuContext(ITEM_INDICATOR_NAME, { checked: false });
950
+ var MenuItemIndicator = React$1.forwardRef((props, forwardedRef) => {
951
+ const { __scopeMenu, forceMount, ...itemIndicatorProps } = props;
952
+ const indicatorContext = useItemIndicatorContext(ITEM_INDICATOR_NAME, __scopeMenu);
953
+ return /* @__PURE__ */ jsx(Presence, {
954
+ present: forceMount || isIndeterminate(indicatorContext.checked) || indicatorContext.checked === true,
955
+ children: /* @__PURE__ */ jsx(Primitive.span, {
956
+ ...itemIndicatorProps,
957
+ ref: forwardedRef,
958
+ "data-state": getCheckedState(indicatorContext.checked)
959
+ })
960
+ });
961
+ });
962
+ MenuItemIndicator.displayName = ITEM_INDICATOR_NAME;
963
+ var SEPARATOR_NAME$1 = "MenuSeparator";
964
+ var MenuSeparator = React$1.forwardRef((props, forwardedRef) => {
965
+ const { __scopeMenu, ...separatorProps } = props;
966
+ return /* @__PURE__ */ jsx(Primitive.div, {
967
+ role: "separator",
968
+ "aria-orientation": "horizontal",
969
+ ...separatorProps,
970
+ ref: forwardedRef
971
+ });
972
+ });
973
+ MenuSeparator.displayName = SEPARATOR_NAME$1;
974
+ var ARROW_NAME$1 = "MenuArrow";
975
+ var MenuArrow = React$1.forwardRef((props, forwardedRef) => {
976
+ const { __scopeMenu, ...arrowProps } = props;
977
+ const popperScope = usePopperScope(__scopeMenu);
978
+ return /* @__PURE__ */ jsx(Arrow, {
979
+ ...popperScope,
980
+ ...arrowProps,
981
+ ref: forwardedRef
982
+ });
983
+ });
984
+ MenuArrow.displayName = ARROW_NAME$1;
985
+ var SUB_NAME$1 = "MenuSub";
986
+ var [MenuSubProvider, useMenuSubContext] = createMenuContext(SUB_NAME$1);
987
+ var MenuSub = (props) => {
988
+ const { __scopeMenu, children, open = false, onOpenChange } = props;
989
+ const parentMenuContext = useMenuContext(SUB_NAME$1, __scopeMenu);
990
+ const popperScope = usePopperScope(__scopeMenu);
991
+ const [trigger, setTrigger] = React$1.useState(null);
992
+ const [content, setContent] = React$1.useState(null);
993
+ const handleOpenChange = useCallbackRef(onOpenChange);
994
+ React$1.useEffect(() => {
995
+ if (parentMenuContext.open === false) handleOpenChange(false);
996
+ return () => handleOpenChange(false);
997
+ }, [parentMenuContext.open, handleOpenChange]);
998
+ return /* @__PURE__ */ jsx(Root2$1, {
999
+ ...popperScope,
1000
+ children: /* @__PURE__ */ jsx(MenuProvider, {
1001
+ scope: __scopeMenu,
1002
+ open,
1003
+ onOpenChange: handleOpenChange,
1004
+ content,
1005
+ onContentChange: setContent,
1006
+ children: /* @__PURE__ */ jsx(MenuSubProvider, {
1007
+ scope: __scopeMenu,
1008
+ contentId: useId$1(),
1009
+ triggerId: useId$1(),
1010
+ trigger,
1011
+ onTriggerChange: setTrigger,
1012
+ children
1013
+ })
1014
+ })
1015
+ });
1016
+ };
1017
+ MenuSub.displayName = SUB_NAME$1;
1018
+ var SUB_TRIGGER_NAME$1 = "MenuSubTrigger";
1019
+ var MenuSubTrigger = React$1.forwardRef((props, forwardedRef) => {
1020
+ const context = useMenuContext(SUB_TRIGGER_NAME$1, props.__scopeMenu);
1021
+ const rootContext = useMenuRootContext(SUB_TRIGGER_NAME$1, props.__scopeMenu);
1022
+ const subContext = useMenuSubContext(SUB_TRIGGER_NAME$1, props.__scopeMenu);
1023
+ const contentContext = useMenuContentContext(SUB_TRIGGER_NAME$1, props.__scopeMenu);
1024
+ const openTimerRef = React$1.useRef(null);
1025
+ const { pointerGraceTimerRef, onPointerGraceIntentChange } = contentContext;
1026
+ const scope = { __scopeMenu: props.__scopeMenu };
1027
+ const clearOpenTimer = React$1.useCallback(() => {
1028
+ if (openTimerRef.current) window.clearTimeout(openTimerRef.current);
1029
+ openTimerRef.current = null;
1030
+ }, []);
1031
+ React$1.useEffect(() => clearOpenTimer, [clearOpenTimer]);
1032
+ React$1.useEffect(() => {
1033
+ const pointerGraceTimer = pointerGraceTimerRef.current;
1034
+ return () => {
1035
+ window.clearTimeout(pointerGraceTimer);
1036
+ onPointerGraceIntentChange(null);
1037
+ };
1038
+ }, [pointerGraceTimerRef, onPointerGraceIntentChange]);
1039
+ const composedRefs = useComposedRefs(forwardedRef, subContext.onTriggerChange);
1040
+ return /* @__PURE__ */ jsx(MenuAnchor, {
1041
+ asChild: true,
1042
+ ...scope,
1043
+ children: /* @__PURE__ */ jsx(MenuItemImpl, {
1044
+ id: subContext.triggerId,
1045
+ "aria-haspopup": "menu",
1046
+ "aria-expanded": context.open,
1047
+ "aria-controls": context.open ? subContext.contentId : void 0,
1048
+ "data-state": getOpenState(context.open),
1049
+ ...props,
1050
+ ref: composedRefs,
1051
+ onClick: (event) => {
1052
+ props.onClick?.(event);
1053
+ if (props.disabled || event.defaultPrevented) return;
1054
+ event.currentTarget.focus();
1055
+ if (!context.open) context.onOpenChange(true);
1056
+ },
1057
+ onPointerMove: composeEventHandlers(props.onPointerMove, whenMouse((event) => {
1058
+ contentContext.onItemEnter(event);
1059
+ if (event.defaultPrevented) return;
1060
+ if (!props.disabled && !context.open && !openTimerRef.current) {
1061
+ contentContext.onPointerGraceIntentChange(null);
1062
+ openTimerRef.current = window.setTimeout(() => {
1063
+ context.onOpenChange(true);
1064
+ clearOpenTimer();
1065
+ }, 100);
1066
+ }
1067
+ })),
1068
+ onPointerLeave: composeEventHandlers(props.onPointerLeave, whenMouse((event) => {
1069
+ clearOpenTimer();
1070
+ const contentRect = context.content?.getBoundingClientRect();
1071
+ if (contentRect) {
1072
+ const side = context.content?.dataset.side;
1073
+ const rightSide = side === "right";
1074
+ const bleed = rightSide ? -5 : 5;
1075
+ const contentNearEdge = contentRect[rightSide ? "left" : "right"];
1076
+ const contentFarEdge = contentRect[rightSide ? "right" : "left"];
1077
+ contentContext.onPointerGraceIntentChange({
1078
+ area: [
1079
+ {
1080
+ x: event.clientX + bleed,
1081
+ y: event.clientY
1082
+ },
1083
+ {
1084
+ x: contentNearEdge,
1085
+ y: contentRect.top
1086
+ },
1087
+ {
1088
+ x: contentFarEdge,
1089
+ y: contentRect.top
1090
+ },
1091
+ {
1092
+ x: contentFarEdge,
1093
+ y: contentRect.bottom
1094
+ },
1095
+ {
1096
+ x: contentNearEdge,
1097
+ y: contentRect.bottom
1098
+ }
1099
+ ],
1100
+ side
1101
+ });
1102
+ window.clearTimeout(pointerGraceTimerRef.current);
1103
+ pointerGraceTimerRef.current = window.setTimeout(() => contentContext.onPointerGraceIntentChange(null), 300);
1104
+ } else {
1105
+ contentContext.onTriggerLeave(event);
1106
+ if (event.defaultPrevented) return;
1107
+ contentContext.onPointerGraceIntentChange(null);
1108
+ }
1109
+ })),
1110
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
1111
+ if (props.disabled || event.target !== event.currentTarget) return;
1112
+ if (contentContext.searchRef.current !== "" && event.key === " ") return;
1113
+ if (SUB_OPEN_KEYS[rootContext.dir].includes(event.key)) {
1114
+ context.onOpenChange(true);
1115
+ context.content?.focus();
1116
+ event.preventDefault();
1117
+ }
1118
+ })
1119
+ })
1120
+ });
1121
+ });
1122
+ MenuSubTrigger.displayName = SUB_TRIGGER_NAME$1;
1123
+ var SUB_CONTENT_NAME$1 = "MenuSubContent";
1124
+ var MenuSubContent = React$1.forwardRef((props, forwardedRef) => {
1125
+ const portalContext = usePortalContext(CONTENT_NAME$1, props.__scopeMenu);
1126
+ const { forceMount = portalContext.forceMount, align = "start", ...subContentProps } = props;
1127
+ const context = useMenuContext(CONTENT_NAME$1, props.__scopeMenu);
1128
+ const rootContext = useMenuRootContext(CONTENT_NAME$1, props.__scopeMenu);
1129
+ const subContext = useMenuSubContext(SUB_CONTENT_NAME$1, props.__scopeMenu);
1130
+ const ref = React$1.useRef(null);
1131
+ const composedRefs = useComposedRefs(forwardedRef, ref);
1132
+ return /* @__PURE__ */ jsx(Collection.Provider, {
1133
+ scope: props.__scopeMenu,
1134
+ children: /* @__PURE__ */ jsx(Presence, {
1135
+ present: forceMount || context.open,
1136
+ children: /* @__PURE__ */ jsx(Collection.Slot, {
1137
+ scope: props.__scopeMenu,
1138
+ children: /* @__PURE__ */ jsx(MenuContentImpl, {
1139
+ id: subContext.contentId,
1140
+ "aria-labelledby": subContext.triggerId,
1141
+ ...subContentProps,
1142
+ ref: composedRefs,
1143
+ align,
1144
+ side: rootContext.dir === "rtl" ? "left" : "right",
1145
+ disableOutsidePointerEvents: false,
1146
+ disableOutsideScroll: false,
1147
+ trapFocus: false,
1148
+ onOpenAutoFocus: (event) => {
1149
+ if (rootContext.isUsingKeyboardRef.current) ref.current?.focus();
1150
+ event.preventDefault();
1151
+ },
1152
+ onCloseAutoFocus: (event) => event.preventDefault(),
1153
+ onFocusOutside: composeEventHandlers(props.onFocusOutside, (event) => {
1154
+ if (event.target !== subContext.trigger) context.onOpenChange(false);
1155
+ }),
1156
+ onEscapeKeyDown: composeEventHandlers(props.onEscapeKeyDown, (event) => {
1157
+ rootContext.onClose();
1158
+ event.preventDefault();
1159
+ }),
1160
+ onKeyDown: composeEventHandlers(props.onKeyDown, (event) => {
1161
+ const isKeyDownInside = event.currentTarget.contains(event.target);
1162
+ const isCloseKey = SUB_CLOSE_KEYS[rootContext.dir].includes(event.key);
1163
+ if (isKeyDownInside && isCloseKey) {
1164
+ context.onOpenChange(false);
1165
+ subContext.trigger?.focus();
1166
+ event.preventDefault();
1167
+ }
1168
+ })
1169
+ })
1170
+ })
1171
+ })
1172
+ });
1173
+ });
1174
+ MenuSubContent.displayName = SUB_CONTENT_NAME$1;
1175
+ function getOpenState(open) {
1176
+ return open ? "open" : "closed";
1177
+ }
1178
+ function isIndeterminate(checked) {
1179
+ return checked === "indeterminate";
1180
+ }
1181
+ function getCheckedState(checked) {
1182
+ return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked";
1183
+ }
1184
+ function focusFirst(candidates) {
1185
+ const PREVIOUSLY_FOCUSED_ELEMENT = document.activeElement;
1186
+ for (const candidate of candidates) {
1187
+ if (candidate === PREVIOUSLY_FOCUSED_ELEMENT) return;
1188
+ candidate.focus();
1189
+ if (document.activeElement !== PREVIOUSLY_FOCUSED_ELEMENT) return;
1190
+ }
1191
+ }
1192
+ function wrapArray(array, startIndex) {
1193
+ return array.map((_, index) => array[(startIndex + index) % array.length]);
1194
+ }
1195
+ function getNextMatch(values, search, currentMatch) {
1196
+ const normalizedSearch = search.length > 1 && Array.from(search).every((char) => char === search[0]) ? search[0] : search;
1197
+ const currentMatchIndex = currentMatch ? values.indexOf(currentMatch) : -1;
1198
+ let wrappedValues = wrapArray(values, Math.max(currentMatchIndex, 0));
1199
+ if (normalizedSearch.length === 1) wrappedValues = wrappedValues.filter((v) => v !== currentMatch);
1200
+ const nextMatch = wrappedValues.find((value) => value.toLowerCase().startsWith(normalizedSearch.toLowerCase()));
1201
+ return nextMatch !== currentMatch ? nextMatch : void 0;
1202
+ }
1203
+ function isPointInPolygon(point, polygon) {
1204
+ const { x, y } = point;
1205
+ let inside = false;
1206
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
1207
+ const ii = polygon[i];
1208
+ const jj = polygon[j];
1209
+ const xi = ii.x;
1210
+ const yi = ii.y;
1211
+ const xj = jj.x;
1212
+ const yj = jj.y;
1213
+ if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) inside = !inside;
1214
+ }
1215
+ return inside;
1216
+ }
1217
+ function isPointerInGraceArea(event, area) {
1218
+ if (!area) return false;
1219
+ return isPointInPolygon({
1220
+ x: event.clientX,
1221
+ y: event.clientY
1222
+ }, area);
1223
+ }
1224
+ function whenMouse(handler) {
1225
+ return (event) => event.pointerType === "mouse" ? handler(event) : void 0;
1226
+ }
1227
+ var Root3 = Menu;
1228
+ var Anchor2 = MenuAnchor;
1229
+ var Portal = MenuPortal;
1230
+ var Content2$1 = MenuContent;
1231
+ var Group = MenuGroup;
1232
+ var Label = MenuLabel;
1233
+ var Item2$1 = MenuItem;
1234
+ var CheckboxItem = MenuCheckboxItem;
1235
+ var RadioGroup = MenuRadioGroup;
1236
+ var RadioItem = MenuRadioItem;
1237
+ var ItemIndicator = MenuItemIndicator;
1238
+ var Separator = MenuSeparator;
1239
+ var Arrow2 = MenuArrow;
1240
+ var Sub = MenuSub;
1241
+ var SubTrigger = MenuSubTrigger;
1242
+ var SubContent = MenuSubContent;
1243
+ //#endregion
1244
+ //#region ../../node_modules/.pnpm/@radix-ui+react-context-menu@2.3.3_@types+react-dom@19.2.3_@types+react@19.2.7__@types+_a190ddd7d7713593b8ead5b8958933b1/node_modules/@radix-ui/react-context-menu/dist/index.mjs
1245
+ var CONTEXT_MENU_NAME = "ContextMenu";
1246
+ var [createContextMenuContext, createContextMenuScope] = createContextScope(CONTEXT_MENU_NAME, [createMenuScope]);
1247
+ var useMenuScope = createMenuScope();
1248
+ var [ContextMenuProvider, useContextMenuContext] = createContextMenuContext(CONTEXT_MENU_NAME);
1249
+ var ContextMenu$1 = (props) => {
1250
+ const { __scopeContextMenu, children, onOpenChange, open: openProp, dir, modal = true } = props;
1251
+ const hasInteractedRef = React$1.useRef(false);
1252
+ {
1253
+ const hasWarnedRef = React$1.useRef(false);
1254
+ React$1.useEffect(() => {
1255
+ if (openProp === true && !hasInteractedRef.current && !hasWarnedRef.current) {
1256
+ hasWarnedRef.current = true;
1257
+ console.warn("ContextMenu: The `open` prop has been set to `true` before the user has interacted with the trigger, so its position is indeterminate. This is likely unintended and will result in the menu being anchored to the top-left corner of the viewport.");
1258
+ }
1259
+ }, [openProp]);
1260
+ }
1261
+ const [open, setOpen] = useControllableState({
1262
+ prop: openProp,
1263
+ defaultProp: false,
1264
+ onChange: onOpenChange,
1265
+ caller: CONTEXT_MENU_NAME
1266
+ });
1267
+ const menuScope = useMenuScope(__scopeContextMenu);
1268
+ return /* @__PURE__ */ jsx(ContextMenuProvider, {
1269
+ scope: __scopeContextMenu,
1270
+ open,
1271
+ onOpenChange: setOpen,
1272
+ modal,
1273
+ hasInteractedRef,
1274
+ children: /* @__PURE__ */ jsx(Root3, {
1275
+ ...menuScope,
1276
+ dir,
1277
+ open,
1278
+ onOpenChange: setOpen,
1279
+ modal,
1280
+ children
1281
+ })
1282
+ });
1283
+ };
1284
+ ContextMenu$1.displayName = CONTEXT_MENU_NAME;
1285
+ var TRIGGER_NAME = "ContextMenuTrigger";
1286
+ var ContextMenuTrigger$1 = React$1.forwardRef((props, forwardedRef) => {
1287
+ const { __scopeContextMenu, disabled = false, ...triggerProps } = props;
1288
+ const context = useContextMenuContext(TRIGGER_NAME, __scopeContextMenu);
1289
+ const menuScope = useMenuScope(__scopeContextMenu);
1290
+ const [point, setPoint] = React$1.useState({
1291
+ x: 0,
1292
+ y: 0
1293
+ });
1294
+ const virtualRef = React$1.useMemo(() => ({ current: { getBoundingClientRect: () => DOMRect.fromRect({
1295
+ width: 0,
1296
+ height: 0,
1297
+ ...point
1298
+ }) } }), [point]);
1299
+ const longPressTimerRef = React$1.useRef(0);
1300
+ const clearLongPress = React$1.useCallback(() => window.clearTimeout(longPressTimerRef.current), []);
1301
+ const handleOpen = (event) => {
1302
+ context.hasInteractedRef.current = true;
1303
+ setPoint({
1304
+ x: event.clientX,
1305
+ y: event.clientY
1306
+ });
1307
+ context.onOpenChange(true);
1308
+ };
1309
+ React$1.useEffect(() => clearLongPress, [clearLongPress]);
1310
+ React$1.useEffect(() => void (disabled && clearLongPress()), [disabled, clearLongPress]);
1311
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Anchor2, {
1312
+ ...menuScope,
1313
+ virtualRef
1314
+ }), /* @__PURE__ */ jsx(Primitive.span, {
1315
+ "data-state": context.open ? "open" : "closed",
1316
+ "data-disabled": disabled ? "" : void 0,
1317
+ ...triggerProps,
1318
+ ref: forwardedRef,
1319
+ style: {
1320
+ WebkitTouchCallout: "none",
1321
+ ...props.style
1322
+ },
1323
+ onContextMenu: disabled ? props.onContextMenu : composeEventHandlers(props.onContextMenu, (event) => {
1324
+ clearLongPress();
1325
+ handleOpen(event);
1326
+ event.preventDefault();
1327
+ }),
1328
+ onPointerDown: disabled ? props.onPointerDown : composeEventHandlers(props.onPointerDown, whenTouchOrPen((event) => {
1329
+ clearLongPress();
1330
+ if (context.open) context.onOpenChange(false);
1331
+ longPressTimerRef.current = window.setTimeout(() => handleOpen(event), 700);
1332
+ })),
1333
+ onPointerMove: disabled ? props.onPointerMove : composeEventHandlers(props.onPointerMove, whenTouchOrPen(clearLongPress)),
1334
+ onPointerCancel: disabled ? props.onPointerCancel : composeEventHandlers(props.onPointerCancel, whenTouchOrPen(clearLongPress)),
1335
+ onPointerUp: disabled ? props.onPointerUp : composeEventHandlers(props.onPointerUp, whenTouchOrPen(clearLongPress))
1336
+ })] });
1337
+ });
1338
+ ContextMenuTrigger$1.displayName = TRIGGER_NAME;
1339
+ var PORTAL_NAME = "ContextMenuPortal";
1340
+ var ContextMenuPortal = (props) => {
1341
+ const { __scopeContextMenu, ...portalProps } = props;
1342
+ const menuScope = useMenuScope(__scopeContextMenu);
1343
+ return /* @__PURE__ */ jsx(Portal, {
1344
+ ...menuScope,
1345
+ ...portalProps
1346
+ });
1347
+ };
1348
+ ContextMenuPortal.displayName = PORTAL_NAME;
1349
+ var CONTENT_NAME = "ContextMenuContent";
1350
+ var ContextMenuContent$1 = React$1.forwardRef((props, forwardedRef) => {
1351
+ const { __scopeContextMenu, ...contentProps } = props;
1352
+ const context = useContextMenuContext(CONTENT_NAME, __scopeContextMenu);
1353
+ const menuScope = useMenuScope(__scopeContextMenu);
1354
+ const hasInteractedOutsideRef = React$1.useRef(false);
1355
+ return /* @__PURE__ */ jsx(Content2$1, {
1356
+ ...menuScope,
1357
+ ...contentProps,
1358
+ ref: forwardedRef,
1359
+ side: "right",
1360
+ sideOffset: 2,
1361
+ align: "start",
1362
+ onCloseAutoFocus: (event) => {
1363
+ props.onCloseAutoFocus?.(event);
1364
+ if (!event.defaultPrevented && hasInteractedOutsideRef.current) event.preventDefault();
1365
+ hasInteractedOutsideRef.current = false;
1366
+ },
1367
+ onInteractOutside: (event) => {
1368
+ props.onInteractOutside?.(event);
1369
+ if (!event.defaultPrevented && !context.modal) hasInteractedOutsideRef.current = true;
1370
+ },
1371
+ style: {
1372
+ ...props.style,
1373
+ "--radix-context-menu-content-transform-origin": "var(--radix-popper-transform-origin)",
1374
+ "--radix-context-menu-content-available-width": "var(--radix-popper-available-width)",
1375
+ "--radix-context-menu-content-available-height": "var(--radix-popper-available-height)",
1376
+ "--radix-context-menu-trigger-width": "var(--radix-popper-anchor-width)",
1377
+ "--radix-context-menu-trigger-height": "var(--radix-popper-anchor-height)"
1378
+ }
1379
+ });
1380
+ });
1381
+ ContextMenuContent$1.displayName = CONTENT_NAME;
1382
+ var GROUP_NAME = "ContextMenuGroup";
1383
+ var ContextMenuGroup = React$1.forwardRef((props, forwardedRef) => {
1384
+ const { __scopeContextMenu, ...groupProps } = props;
1385
+ const menuScope = useMenuScope(__scopeContextMenu);
1386
+ return /* @__PURE__ */ jsx(Group, {
1387
+ ...menuScope,
1388
+ ...groupProps,
1389
+ ref: forwardedRef
1390
+ });
1391
+ });
1392
+ ContextMenuGroup.displayName = GROUP_NAME;
1393
+ var LABEL_NAME = "ContextMenuLabel";
1394
+ var ContextMenuLabel = React$1.forwardRef((props, forwardedRef) => {
1395
+ const { __scopeContextMenu, ...labelProps } = props;
1396
+ const menuScope = useMenuScope(__scopeContextMenu);
1397
+ return /* @__PURE__ */ jsx(Label, {
1398
+ ...menuScope,
1399
+ ...labelProps,
1400
+ ref: forwardedRef
1401
+ });
1402
+ });
1403
+ ContextMenuLabel.displayName = LABEL_NAME;
1404
+ var ITEM_NAME = "ContextMenuItem";
1405
+ var ContextMenuItem$1 = React$1.forwardRef((props, forwardedRef) => {
1406
+ const { __scopeContextMenu, ...itemProps } = props;
1407
+ const menuScope = useMenuScope(__scopeContextMenu);
1408
+ return /* @__PURE__ */ jsx(Item2$1, {
1409
+ ...menuScope,
1410
+ ...itemProps,
1411
+ ref: forwardedRef
1412
+ });
1413
+ });
1414
+ ContextMenuItem$1.displayName = ITEM_NAME;
1415
+ var CHECKBOX_ITEM_NAME = "ContextMenuCheckboxItem";
1416
+ var ContextMenuCheckboxItem = React$1.forwardRef((props, forwardedRef) => {
1417
+ const { __scopeContextMenu, ...checkboxItemProps } = props;
1418
+ const menuScope = useMenuScope(__scopeContextMenu);
1419
+ return /* @__PURE__ */ jsx(CheckboxItem, {
1420
+ ...menuScope,
1421
+ ...checkboxItemProps,
1422
+ ref: forwardedRef
1423
+ });
1424
+ });
1425
+ ContextMenuCheckboxItem.displayName = CHECKBOX_ITEM_NAME;
1426
+ var RADIO_GROUP_NAME = "ContextMenuRadioGroup";
1427
+ var ContextMenuRadioGroup = React$1.forwardRef((props, forwardedRef) => {
1428
+ const { __scopeContextMenu, ...radioGroupProps } = props;
1429
+ const menuScope = useMenuScope(__scopeContextMenu);
1430
+ return /* @__PURE__ */ jsx(RadioGroup, {
1431
+ ...menuScope,
1432
+ ...radioGroupProps,
1433
+ ref: forwardedRef
1434
+ });
1435
+ });
1436
+ ContextMenuRadioGroup.displayName = RADIO_GROUP_NAME;
1437
+ var RADIO_ITEM_NAME = "ContextMenuRadioItem";
1438
+ var ContextMenuRadioItem = React$1.forwardRef((props, forwardedRef) => {
1439
+ const { __scopeContextMenu, ...radioItemProps } = props;
1440
+ const menuScope = useMenuScope(__scopeContextMenu);
1441
+ return /* @__PURE__ */ jsx(RadioItem, {
1442
+ ...menuScope,
1443
+ ...radioItemProps,
1444
+ ref: forwardedRef
1445
+ });
1446
+ });
1447
+ ContextMenuRadioItem.displayName = RADIO_ITEM_NAME;
1448
+ var INDICATOR_NAME = "ContextMenuItemIndicator";
1449
+ var ContextMenuItemIndicator = React$1.forwardRef((props, forwardedRef) => {
1450
+ const { __scopeContextMenu, ...itemIndicatorProps } = props;
1451
+ const menuScope = useMenuScope(__scopeContextMenu);
1452
+ return /* @__PURE__ */ jsx(ItemIndicator, {
1453
+ ...menuScope,
1454
+ ...itemIndicatorProps,
1455
+ ref: forwardedRef
1456
+ });
1457
+ });
1458
+ ContextMenuItemIndicator.displayName = INDICATOR_NAME;
1459
+ var SEPARATOR_NAME = "ContextMenuSeparator";
1460
+ var ContextMenuSeparator = React$1.forwardRef((props, forwardedRef) => {
1461
+ const { __scopeContextMenu, ...separatorProps } = props;
1462
+ const menuScope = useMenuScope(__scopeContextMenu);
1463
+ return /* @__PURE__ */ jsx(Separator, {
1464
+ ...menuScope,
1465
+ ...separatorProps,
1466
+ ref: forwardedRef
1467
+ });
1468
+ });
1469
+ ContextMenuSeparator.displayName = SEPARATOR_NAME;
1470
+ var ARROW_NAME = "ContextMenuArrow";
1471
+ var ContextMenuArrow = React$1.forwardRef((props, forwardedRef) => {
1472
+ const { __scopeContextMenu, ...arrowProps } = props;
1473
+ const menuScope = useMenuScope(__scopeContextMenu);
1474
+ return /* @__PURE__ */ jsx(Arrow2, {
1475
+ ...menuScope,
1476
+ ...arrowProps,
1477
+ ref: forwardedRef
1478
+ });
1479
+ });
1480
+ ContextMenuArrow.displayName = ARROW_NAME;
1481
+ var SUB_NAME = "ContextMenuSub";
1482
+ var ContextMenuSub = (props) => {
1483
+ const { __scopeContextMenu, children, onOpenChange, open: openProp, defaultOpen } = props;
1484
+ const menuScope = useMenuScope(__scopeContextMenu);
1485
+ const [open, setOpen] = useControllableState({
1486
+ prop: openProp,
1487
+ defaultProp: defaultOpen ?? false,
1488
+ onChange: onOpenChange,
1489
+ caller: SUB_NAME
1490
+ });
1491
+ return /* @__PURE__ */ jsx(Sub, {
1492
+ ...menuScope,
1493
+ open,
1494
+ onOpenChange: setOpen,
1495
+ children
1496
+ });
1497
+ };
1498
+ ContextMenuSub.displayName = SUB_NAME;
1499
+ var SUB_TRIGGER_NAME = "ContextMenuSubTrigger";
1500
+ var ContextMenuSubTrigger = React$1.forwardRef((props, forwardedRef) => {
1501
+ const { __scopeContextMenu, ...triggerItemProps } = props;
1502
+ const menuScope = useMenuScope(__scopeContextMenu);
1503
+ return /* @__PURE__ */ jsx(SubTrigger, {
1504
+ ...menuScope,
1505
+ ...triggerItemProps,
1506
+ ref: forwardedRef
1507
+ });
1508
+ });
1509
+ ContextMenuSubTrigger.displayName = SUB_TRIGGER_NAME;
1510
+ var SUB_CONTENT_NAME = "ContextMenuSubContent";
1511
+ var ContextMenuSubContent = React$1.forwardRef((props, forwardedRef) => {
1512
+ const { __scopeContextMenu, ...subContentProps } = props;
1513
+ const menuScope = useMenuScope(__scopeContextMenu);
1514
+ return /* @__PURE__ */ jsx(SubContent, {
1515
+ ...menuScope,
1516
+ ...subContentProps,
1517
+ ref: forwardedRef,
1518
+ style: {
1519
+ ...props.style,
1520
+ "--radix-context-menu-content-transform-origin": "var(--radix-popper-transform-origin)",
1521
+ "--radix-context-menu-content-available-width": "var(--radix-popper-available-width)",
1522
+ "--radix-context-menu-content-available-height": "var(--radix-popper-available-height)",
1523
+ "--radix-context-menu-trigger-width": "var(--radix-popper-anchor-width)",
1524
+ "--radix-context-menu-trigger-height": "var(--radix-popper-anchor-height)"
1525
+ }
1526
+ });
1527
+ });
1528
+ ContextMenuSubContent.displayName = SUB_CONTENT_NAME;
1529
+ function whenTouchOrPen(handler) {
1530
+ return (event) => event.pointerType !== "mouse" ? handler(event) : void 0;
1531
+ }
1532
+ var Root2 = ContextMenu$1;
1533
+ var Trigger = ContextMenuTrigger$1;
1534
+ var Portal2 = ContextMenuPortal;
1535
+ var Content2 = ContextMenuContent$1;
1536
+ var Item2 = ContextMenuItem$1;
1537
+ //#endregion
1538
+ //#region ../ui/src/components/primitives/context-menu.tsx
1539
+ var menuContentStyles = cn("z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md [-webkit-app-region:no-drag]", "data-[state=closed]:animate-out data-[state=open]:animate-in", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95");
1540
+ cn("z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg [-webkit-app-region:no-drag]", "data-[state=closed]:animate-out data-[state=open]:animate-in", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95");
1541
+ var menuItemVariants = cva(cn("relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none", "focus:bg-accent focus:text-accent-foreground", "data-disabled:pointer-events-none data-disabled:opacity-50", "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "[&_svg:not([class*='text-'])]:text-muted-foreground"), {
1542
+ variants: {
1543
+ variant: {
1544
+ default: "",
1545
+ destructive: "text-destructive focus:bg-destructive/10 focus:text-destructive dark:focus:bg-destructive/20 data-[variant=destructive]:[&_svg:not([class*='text-'])]:text-destructive!"
1546
+ },
1547
+ inset: {
1548
+ true: "pl-8",
1549
+ false: ""
1550
+ }
1551
+ },
1552
+ defaultVariants: {
1553
+ variant: "default",
1554
+ inset: false
1555
+ }
1556
+ });
1557
+ var ContextMenuOpeningPointerUpGuardContext = React$1.createContext(null);
1558
+ function ContextMenu({ onOpenChange, ...props }) {
1559
+ const shouldStopOpeningPointerUpRef = React$1.useRef(false);
1560
+ const clearOpeningPointerUpListenerRef = React$1.useRef(null);
1561
+ const clearOpeningPointerUpTimerRef = React$1.useRef(null);
1562
+ const clearOpeningPointerUp = React$1.useCallback(() => {
1563
+ shouldStopOpeningPointerUpRef.current = false;
1564
+ clearOpeningPointerUpListenerRef.current?.();
1565
+ clearOpeningPointerUpListenerRef.current = null;
1566
+ if (clearOpeningPointerUpTimerRef.current !== null) {
1567
+ window.clearTimeout(clearOpeningPointerUpTimerRef.current);
1568
+ clearOpeningPointerUpTimerRef.current = null;
1569
+ }
1570
+ }, []);
1571
+ const pointerUpGuard = React$1.useMemo(() => ({
1572
+ consumeOpeningPointerUp: () => {
1573
+ const shouldStop = shouldStopOpeningPointerUpRef.current;
1574
+ clearOpeningPointerUp();
1575
+ return shouldStop;
1576
+ },
1577
+ markOpeningPointerUp: () => {
1578
+ shouldStopOpeningPointerUpRef.current = true;
1579
+ clearOpeningPointerUpListenerRef.current?.();
1580
+ const handleOpeningPointerUp = () => clearOpeningPointerUp();
1581
+ window.addEventListener("pointerup", handleOpeningPointerUp, { once: true });
1582
+ clearOpeningPointerUpListenerRef.current = () => {
1583
+ window.removeEventListener("pointerup", handleOpeningPointerUp);
1584
+ };
1585
+ if (clearOpeningPointerUpTimerRef.current !== null) window.clearTimeout(clearOpeningPointerUpTimerRef.current);
1586
+ clearOpeningPointerUpTimerRef.current = window.setTimeout(clearOpeningPointerUp, 1e3);
1587
+ }
1588
+ }), [clearOpeningPointerUp]);
1589
+ const handleOpenChange = React$1.useCallback((open) => {
1590
+ if (!open) clearOpeningPointerUp();
1591
+ onOpenChange?.(open);
1592
+ }, [clearOpeningPointerUp, onOpenChange]);
1593
+ React$1.useEffect(() => clearOpeningPointerUp, [clearOpeningPointerUp]);
1594
+ return /* @__PURE__ */ jsx(ContextMenuOpeningPointerUpGuardContext, {
1595
+ value: pointerUpGuard,
1596
+ children: /* @__PURE__ */ jsx(Root2, {
1597
+ "data-slot": "context-menu",
1598
+ onOpenChange: handleOpenChange,
1599
+ ...props
1600
+ })
1601
+ });
1602
+ }
1603
+ function ContextMenuTrigger({ onContextMenu, disabled, ...props }) {
1604
+ const pointerUpGuard = React$1.use(ContextMenuOpeningPointerUpGuardContext);
1605
+ return /* @__PURE__ */ jsx(Trigger, {
1606
+ "data-slot": "context-menu-trigger",
1607
+ disabled,
1608
+ onContextMenu: (event) => {
1609
+ if (!disabled) pointerUpGuard?.markOpeningPointerUp();
1610
+ onContextMenu?.(event);
1611
+ },
1612
+ ...props
1613
+ });
1614
+ }
1615
+ function stopOpeningPointerUp(event, pointerUpGuard) {
1616
+ const isOpeningPointerUp = pointerUpGuard?.consumeOpeningPointerUp() ?? false;
1617
+ if (event.button !== 2 && !isOpeningPointerUp) return;
1618
+ event.preventDefault();
1619
+ event.stopPropagation();
1620
+ }
1621
+ function ContextMenuContent({ className, onPointerUpCapture, portalContainer, ...props }) {
1622
+ const pointerUpGuard = React$1.use(ContextMenuOpeningPointerUpGuardContext);
1623
+ const defaultPortalContainer = usePortalContainer();
1624
+ return /* @__PURE__ */ jsx(Portal2, {
1625
+ container: portalContainer ?? defaultPortalContainer ?? void 0,
1626
+ children: /* @__PURE__ */ jsx(Content2, {
1627
+ "data-slot": "context-menu-content",
1628
+ className: cn(menuContentStyles, "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2", "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className),
1629
+ onPointerUpCapture: (event) => {
1630
+ onPointerUpCapture?.(event);
1631
+ stopOpeningPointerUp(event, pointerUpGuard);
1632
+ },
1633
+ ...props
1634
+ })
1635
+ });
1636
+ }
1637
+ function ContextMenuItem({ className, inset, variant, ...props }) {
1638
+ return /* @__PURE__ */ jsx(Item2, {
1639
+ "data-slot": "context-menu-item",
1640
+ "data-inset": inset,
1641
+ "data-variant": variant,
1642
+ className: cn(menuItemVariants({
1643
+ variant,
1644
+ inset
1645
+ }), className),
1646
+ ...props
1647
+ });
1648
+ }
1649
+ //#endregion
1650
+ //#region ../ui/src/components/composites/image-preview/image-preview-context-menu.tsx
1651
+ function ImagePreviewContextMenu({ actions = [], children, context, item, onActionError }) {
1652
+ if (actions.length === 0) return /* @__PURE__ */ jsx(Fragment, { children });
1653
+ return /* @__PURE__ */ jsxs(ContextMenu, { children: [/* @__PURE__ */ jsx(ContextMenuTrigger, {
1654
+ asChild: true,
1655
+ children
1656
+ }), /* @__PURE__ */ jsx(ContextMenuContent, { children: actions.map((action) => /* @__PURE__ */ jsxs(ContextMenuItem, {
1657
+ disabled: action.disabled,
1658
+ onSelect: (event) => {
1659
+ event.preventDefault();
1660
+ Promise.resolve().then(() => action.onSelect(item, context)).catch((error) => onActionError?.(error, action, item));
1661
+ },
1662
+ children: [action.icon, action.label]
1663
+ }, action.id)) })] });
1664
+ }
1665
+ //#endregion
1666
+ //#region ../ui/src/components/composites/image-preview/image-preview-image.tsx
1667
+ function ImagePreviewImage({ className, fitScale = 1, item, style, transform, ...props }) {
1668
+ const transformValue = [
1669
+ `translate3d(${transform.offsetX}px, ${transform.offsetY}px, 0)`,
1670
+ `rotate(${transform.rotation}deg)`,
1671
+ `scale(${fitScale * transform.zoom})`,
1672
+ `scaleX(${transform.flipX ? -1 : 1})`,
1673
+ `scaleY(${transform.flipY ? -1 : 1})`
1674
+ ].join(" ");
1675
+ return /* @__PURE__ */ jsx("img", {
1676
+ alt: item.alt ?? item.title ?? "",
1677
+ className: cn("block max-h-full max-w-full object-contain select-none", className),
1678
+ draggable: false,
1679
+ src: item.src,
1680
+ style: {
1681
+ ...style,
1682
+ transform: transformValue,
1683
+ transformOrigin: "center",
1684
+ willChange: "transform"
1685
+ },
1686
+ ...props
1687
+ });
1688
+ }
1689
+ //#endregion
1690
+ //#region ../ui/src/components/composites/image-preview/image-preview-viewport.tsx
1691
+ var EMPTY_SIZE = {
1692
+ height: 0,
1693
+ width: 0
1694
+ };
1695
+ var clamp$1 = (value, min, max) => Math.min(max, Math.max(min, value));
1696
+ var getItemKey = (item) => `${item.id}\0${item.src}`;
1697
+ var touchSpan = (points) => {
1698
+ const [first, second] = [...points.values()];
1699
+ return {
1700
+ span: Math.hypot(first.x - second.x, first.y - second.y),
1701
+ midX: (first.x + second.x) / 2,
1702
+ midY: (first.y + second.y) / 2
1703
+ };
1704
+ };
1705
+ var getGeometry = (imageSize, viewportSize, transform) => {
1706
+ if (imageSize.width <= 0 || imageSize.height <= 0 || viewportSize.width <= 0 || viewportSize.height <= 0) return {
1707
+ fitScale: 1,
1708
+ maxOffsetX: 0,
1709
+ maxOffsetY: 0
1710
+ };
1711
+ const swapsDimensions = transform.rotation % 180 !== 0;
1712
+ const rotatedWidth = swapsDimensions ? imageSize.height : imageSize.width;
1713
+ const rotatedHeight = swapsDimensions ? imageSize.width : imageSize.height;
1714
+ const fitScale = Math.min(1, viewportSize.width / rotatedWidth, viewportSize.height / rotatedHeight);
1715
+ const renderedWidth = rotatedWidth * fitScale * transform.zoom;
1716
+ const renderedHeight = rotatedHeight * fitScale * transform.zoom;
1717
+ return {
1718
+ fitScale,
1719
+ maxOffsetX: Math.max(0, (renderedWidth - viewportSize.width) / 2),
1720
+ maxOffsetY: Math.max(0, (renderedHeight - viewportSize.height) / 2)
1721
+ };
1722
+ };
1723
+ var clampOffsets = (transform, imageSize, viewportSize) => {
1724
+ const { maxOffsetX, maxOffsetY } = getGeometry(imageSize, viewportSize, transform);
1725
+ return {
1726
+ offsetX: clamp$1(transform.offsetX, -maxOffsetX, maxOffsetX),
1727
+ offsetY: clamp$1(transform.offsetY, -maxOffsetY, maxOffsetY)
1728
+ };
1729
+ };
1730
+ function ImagePreviewViewport({ actionContext, actions = [], className, imageClassName, item, onActionError, onBackdropClick, onError, onLoad, transformControls, ...props }) {
1731
+ const viewportRef = React$1.useRef(null);
1732
+ const dragRef = React$1.useRef(null);
1733
+ const touchPointsRef = React$1.useRef(/* @__PURE__ */ new Map());
1734
+ const pinchRef = React$1.useRef(null);
1735
+ const [isDragging, setIsDragging] = React$1.useState(false);
1736
+ const [viewportSize, setViewportSize] = React$1.useState(EMPTY_SIZE);
1737
+ const [loadedImage, setLoadedImage] = React$1.useState(null);
1738
+ const itemKey = getItemKey(item);
1739
+ const imageSize = loadedImage?.itemKey === itemKey ? loadedImage.size : EMPTY_SIZE;
1740
+ const { transform, update } = transformControls;
1741
+ const geometry = getGeometry(imageSize, viewportSize, transform);
1742
+ const canPan = geometry.maxOffsetX > 0 || geometry.maxOffsetY > 0;
1743
+ const isGeometryReady = imageSize.width > 0 && imageSize.height > 0 && viewportSize.width > 0 && viewportSize.height > 0;
1744
+ React$1.useLayoutEffect(() => {
1745
+ const viewport = viewportRef.current;
1746
+ if (!viewport) return;
1747
+ const updateSize = () => {
1748
+ const rect = viewport.getBoundingClientRect();
1749
+ setViewportSize((current) => current.width === rect.width && current.height === rect.height ? current : {
1750
+ width: rect.width,
1751
+ height: rect.height
1752
+ });
1753
+ };
1754
+ updateSize();
1755
+ if (typeof ResizeObserver === "undefined") return;
1756
+ const observer = new ResizeObserver(updateSize);
1757
+ observer.observe(viewport);
1758
+ return () => observer.disconnect();
1759
+ }, []);
1760
+ React$1.useLayoutEffect(() => {
1761
+ const offsets = clampOffsets(transform, imageSize, viewportSize);
1762
+ update(offsets);
1763
+ }, [
1764
+ imageSize,
1765
+ transform,
1766
+ update,
1767
+ viewportSize
1768
+ ]);
1769
+ const zoomAt = React$1.useCallback((nextZoom, clientX, clientY) => {
1770
+ const viewport = viewportRef.current;
1771
+ if (!viewport) return;
1772
+ const rect = viewport.getBoundingClientRect();
1773
+ const anchorX = clientX - rect.left - rect.width / 2;
1774
+ const anchorY = clientY - rect.top - rect.height / 2;
1775
+ update((current) => {
1776
+ const zoom = clamp$1(nextZoom, transformControls.minZoom, transformControls.maxZoom);
1777
+ const ratio = zoom / current.zoom;
1778
+ const next = {
1779
+ ...current,
1780
+ offsetX: anchorX - (anchorX - current.offsetX) * ratio,
1781
+ offsetY: anchorY - (anchorY - current.offsetY) * ratio,
1782
+ zoom
1783
+ };
1784
+ return {
1785
+ ...next,
1786
+ ...clampOffsets(next, imageSize, viewportSize)
1787
+ };
1788
+ });
1789
+ }, [
1790
+ imageSize,
1791
+ transformControls.maxZoom,
1792
+ transformControls.minZoom,
1793
+ update,
1794
+ viewportSize
1795
+ ]);
1796
+ const handleWheel = React$1.useCallback((event) => {
1797
+ event.preventDefault();
1798
+ const nextZoom = transform.zoom * Math.exp(-event.deltaY * .002);
1799
+ zoomAt(nextZoom, event.clientX, event.clientY);
1800
+ }, [transform.zoom, zoomAt]);
1801
+ const handleTouchPointerDown = React$1.useCallback((event) => {
1802
+ if (event.pointerType !== "touch") return;
1803
+ touchPointsRef.current.set(event.pointerId, {
1804
+ x: event.clientX,
1805
+ y: event.clientY
1806
+ });
1807
+ if (touchPointsRef.current.size !== 2) return;
1808
+ dragRef.current = null;
1809
+ setIsDragging(false);
1810
+ pinchRef.current = {
1811
+ span: touchSpan(touchPointsRef.current).span,
1812
+ zoom: transform.zoom
1813
+ };
1814
+ }, [transform.zoom]);
1815
+ const handleTouchPointerMove = React$1.useCallback((event) => {
1816
+ if (!touchPointsRef.current.has(event.pointerId)) return;
1817
+ touchPointsRef.current.set(event.pointerId, {
1818
+ x: event.clientX,
1819
+ y: event.clientY
1820
+ });
1821
+ const pinch = pinchRef.current;
1822
+ if (!pinch || touchPointsRef.current.size !== 2) return;
1823
+ const { span, midX, midY } = touchSpan(touchPointsRef.current);
1824
+ if (pinch.span > 0) zoomAt(pinch.zoom * span / pinch.span, midX, midY);
1825
+ }, [zoomAt]);
1826
+ const handleTouchPointerEnd = React$1.useCallback((event) => {
1827
+ touchPointsRef.current.delete(event.pointerId);
1828
+ if (touchPointsRef.current.size < 2) pinchRef.current = null;
1829
+ }, []);
1830
+ const handlePointerDown = React$1.useCallback((event) => {
1831
+ event.stopPropagation();
1832
+ if (event.button !== 0 || !canPan || pinchRef.current) return;
1833
+ dragRef.current = {
1834
+ offsetX: transform.offsetX,
1835
+ offsetY: transform.offsetY,
1836
+ pointerId: event.pointerId,
1837
+ startX: event.clientX,
1838
+ startY: event.clientY
1839
+ };
1840
+ event.currentTarget.setPointerCapture(event.pointerId);
1841
+ setIsDragging(true);
1842
+ event.preventDefault();
1843
+ }, [
1844
+ canPan,
1845
+ transform.offsetX,
1846
+ transform.offsetY
1847
+ ]);
1848
+ const handlePointerMove = React$1.useCallback((event) => {
1849
+ const drag = dragRef.current;
1850
+ if (!drag || drag.pointerId !== event.pointerId) return;
1851
+ const next = {
1852
+ ...transform,
1853
+ offsetX: drag.offsetX + event.clientX - drag.startX,
1854
+ offsetY: drag.offsetY + event.clientY - drag.startY
1855
+ };
1856
+ update(clampOffsets(next, imageSize, viewportSize));
1857
+ }, [
1858
+ imageSize,
1859
+ transform,
1860
+ update,
1861
+ viewportSize
1862
+ ]);
1863
+ const stopDragging = React$1.useCallback((event) => {
1864
+ const drag = dragRef.current;
1865
+ if (!drag || drag.pointerId !== event.pointerId) return;
1866
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
1867
+ dragRef.current = null;
1868
+ setIsDragging(false);
1869
+ }, []);
1870
+ const image = /* @__PURE__ */ jsx(ImagePreviewImage, {
1871
+ className: cn("max-h-none max-w-none shrink-0", canPan && (isDragging ? "cursor-grabbing transition-none" : "cursor-grab"), imageClassName),
1872
+ fitScale: geometry.fitScale,
1873
+ item,
1874
+ onClick: (event) => event.stopPropagation(),
1875
+ onDoubleClick: (event) => {
1876
+ event.stopPropagation();
1877
+ zoomAt(transform.zoom > transformControls.minZoom ? transformControls.minZoom : 2, event.clientX, event.clientY);
1878
+ },
1879
+ onError,
1880
+ onLoad: (event) => {
1881
+ setLoadedImage({
1882
+ itemKey,
1883
+ size: {
1884
+ height: event.currentTarget.naturalHeight,
1885
+ width: event.currentTarget.naturalWidth
1886
+ }
1887
+ });
1888
+ onLoad?.(event);
1889
+ },
1890
+ onPointerCancel: stopDragging,
1891
+ onPointerDown: handlePointerDown,
1892
+ onPointerMove: handlePointerMove,
1893
+ onPointerUp: stopDragging,
1894
+ style: {
1895
+ ...imageSize.width > 0 ? {
1896
+ height: imageSize.height,
1897
+ width: imageSize.width
1898
+ } : {},
1899
+ visibility: isGeometryReady ? "visible" : "hidden"
1900
+ },
1901
+ transform
1902
+ }, itemKey);
1903
+ return /* @__PURE__ */ jsx("div", {
1904
+ ...props,
1905
+ ref: viewportRef,
1906
+ className: cn("relative flex h-full w-full touch-none items-center justify-center overflow-hidden", className),
1907
+ "data-testid": "image-preview-viewport",
1908
+ onClick: (event) => {
1909
+ if (event.target === event.currentTarget) onBackdropClick?.();
1910
+ },
1911
+ onPointerCancelCapture: handleTouchPointerEnd,
1912
+ onPointerDownCapture: handleTouchPointerDown,
1913
+ onPointerMoveCapture: handleTouchPointerMove,
1914
+ onPointerUpCapture: handleTouchPointerEnd,
1915
+ onWheel: handleWheel,
1916
+ children: actionContext && actions.length > 0 ? /* @__PURE__ */ jsx(ImagePreviewContextMenu, {
1917
+ actions,
1918
+ context: actionContext,
1919
+ item,
1920
+ onActionError,
1921
+ children: image
1922
+ }) : image
1923
+ });
1924
+ }
1925
+ //#endregion
1926
+ //#region ../ui/src/components/composites/image-preview/use-image-preview-transform.ts
1927
+ var DEFAULT_TRANSFORM = {
1928
+ flipX: false,
1929
+ flipY: false,
1930
+ offsetX: 0,
1931
+ offsetY: 0,
1932
+ rotation: 0,
1933
+ zoom: 1
1934
+ };
1935
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
1936
+ var normalizeRotate = (value) => (value % 360 + 360) % 360;
1937
+ var toFiniteNumber = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
1938
+ var normalizeTransform = (transform, minZoom, maxZoom) => ({
1939
+ flipX: transform?.flipX ?? DEFAULT_TRANSFORM.flipX,
1940
+ flipY: transform?.flipY ?? DEFAULT_TRANSFORM.flipY,
1941
+ offsetX: toFiniteNumber(transform?.offsetX, DEFAULT_TRANSFORM.offsetX),
1942
+ offsetY: toFiniteNumber(transform?.offsetY, DEFAULT_TRANSFORM.offsetY),
1943
+ rotation: normalizeRotate(toFiniteNumber(transform?.rotation, DEFAULT_TRANSFORM.rotation)),
1944
+ zoom: clamp(toFiniteNumber(transform?.zoom, DEFAULT_TRANSFORM.zoom), minZoom, maxZoom)
1945
+ });
1946
+ var transformsEqual = (left, right) => left.flipX === right.flipX && left.flipY === right.flipY && left.offsetX === right.offsetX && left.offsetY === right.offsetY && left.rotation === right.rotation && left.zoom === right.zoom;
1947
+ function useImagePreviewTransform({ initialTransform, maxZoom = 5, minZoom = 1, zoomStep = .25 } = {}) {
1948
+ if (minZoom > maxZoom) throw new Error("useImagePreviewTransform requires minZoom <= maxZoom");
1949
+ if (zoomStep <= 0 || !Number.isFinite(zoomStep)) throw new Error("useImagePreviewTransform requires zoomStep > 0");
1950
+ const initialValue = React$1.useMemo(() => normalizeTransform(initialTransform, minZoom, maxZoom), [
1951
+ initialTransform,
1952
+ maxZoom,
1953
+ minZoom
1954
+ ]);
1955
+ const [transform, setTransform] = React$1.useState(initialValue);
1956
+ const update = React$1.useCallback((nextUpdate) => {
1957
+ setTransform((current) => {
1958
+ const patch = typeof nextUpdate === "function" ? nextUpdate(current) : nextUpdate;
1959
+ const next = normalizeTransform({
1960
+ ...current,
1961
+ ...patch
1962
+ }, minZoom, maxZoom);
1963
+ return transformsEqual(current, next) ? current : next;
1964
+ });
1965
+ }, [maxZoom, minZoom]);
1966
+ const reset = React$1.useCallback(() => {
1967
+ setTransform(initialValue);
1968
+ }, [initialValue]);
1969
+ const zoomIn = React$1.useCallback(() => {
1970
+ update((current) => ({ zoom: current.zoom + zoomStep }));
1971
+ }, [update, zoomStep]);
1972
+ const zoomOut = React$1.useCallback(() => {
1973
+ update((current) => ({ zoom: current.zoom - zoomStep }));
1974
+ }, [update, zoomStep]);
1975
+ const rotateLeft = React$1.useCallback(() => {
1976
+ update((current) => ({
1977
+ offsetX: 0,
1978
+ offsetY: 0,
1979
+ rotation: current.rotation - 90
1980
+ }));
1981
+ }, [update]);
1982
+ const rotateRight = React$1.useCallback(() => {
1983
+ update((current) => ({
1984
+ offsetX: 0,
1985
+ offsetY: 0,
1986
+ rotation: current.rotation + 90
1987
+ }));
1988
+ }, [update]);
1989
+ const flipHorizontal = React$1.useCallback(() => {
1990
+ update((current) => ({
1991
+ flipX: !current.flipX,
1992
+ rotation: -current.rotation
1993
+ }));
1994
+ }, [update]);
1995
+ const flipVertical = React$1.useCallback(() => {
1996
+ update((current) => ({
1997
+ flipY: !current.flipY,
1998
+ rotation: -current.rotation
1999
+ }));
2000
+ }, [update]);
2001
+ return {
2002
+ canZoomIn: transform.zoom < maxZoom,
2003
+ canZoomOut: transform.zoom > minZoom,
2004
+ flipHorizontal,
2005
+ flipVertical,
2006
+ maxZoom,
2007
+ minZoom,
2008
+ reset,
2009
+ rotateLeft,
2010
+ rotateRight,
2011
+ transform,
2012
+ update,
2013
+ zoomIn,
2014
+ zoomOut
2015
+ };
2016
+ }
2017
+ //#endregion
2018
+ //#region src/plugins/image/ImageFilePreviewToolbar.tsx
2019
+ function ImageFilePreviewToolbar({ disabled, transformControls }) {
2020
+ const { t } = useTranslation();
2021
+ return /* @__PURE__ */ jsxs(FilePreviewToolbar, {
2022
+ "aria-label": t("preview.label"),
2023
+ children: [
2024
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2025
+ label: t("preview.zoom_out"),
2026
+ disabled: disabled || !transformControls.canZoomOut,
2027
+ onClick: transformControls.zoomOut,
2028
+ children: /* @__PURE__ */ jsx(ZoomOut, { "aria-hidden": true })
2029
+ }),
2030
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2031
+ label: t("preview.zoom_in"),
2032
+ disabled: disabled || !transformControls.canZoomIn,
2033
+ onClick: transformControls.zoomIn,
2034
+ children: /* @__PURE__ */ jsx(ZoomIn, { "aria-hidden": true })
2035
+ }),
2036
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2037
+ label: t("preview.rotate_left"),
2038
+ disabled,
2039
+ onClick: transformControls.rotateLeft,
2040
+ children: /* @__PURE__ */ jsx(RotateCcwSquare, { "aria-hidden": true })
2041
+ }),
2042
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2043
+ label: t("preview.rotate_right"),
2044
+ disabled,
2045
+ onClick: transformControls.rotateRight,
2046
+ children: /* @__PURE__ */ jsx(RotateCwSquare, { "aria-hidden": true })
2047
+ }),
2048
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2049
+ label: t("preview.flip_horizontal"),
2050
+ disabled,
2051
+ onClick: transformControls.flipHorizontal,
2052
+ pressed: transformControls.transform.flipX,
2053
+ children: /* @__PURE__ */ jsx(FlipHorizontal, { "aria-hidden": true })
2054
+ }),
2055
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2056
+ label: t("preview.flip_vertical"),
2057
+ disabled,
2058
+ onClick: transformControls.flipVertical,
2059
+ pressed: transformControls.transform.flipY,
2060
+ children: /* @__PURE__ */ jsx(FlipVertical, { "aria-hidden": true })
2061
+ }),
2062
+ /* @__PURE__ */ jsx(FilePreviewToolbarButton, {
2063
+ label: t("preview.reset"),
2064
+ disabled,
2065
+ onClick: transformControls.reset,
2066
+ children: /* @__PURE__ */ jsx(RefreshCcw, { "aria-hidden": true })
2067
+ })
2068
+ ]
2069
+ });
2070
+ }
2071
+ //#endregion
2072
+ //#region src/plugins/image/ImageFilePreview.tsx
2073
+ var IMAGE_PREVIEW_MAX_SIZE_BYTES = 67108864;
2074
+ var IMAGE_MEDIA_TYPE_BY_EXTENSION = {
2075
+ svg: "image/svg+xml",
2076
+ jpg: "image/jpeg",
2077
+ ico: "image/x-icon"
2078
+ };
2079
+ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
2080
+ const { t } = useTranslation();
2081
+ const { failDocument } = usePreviewHost();
2082
+ const [url, setUrl] = useState(null);
2083
+ const objectUrlRef = useRef(null);
2084
+ const [status, setStatus] = useState("loading");
2085
+ const transformControls = useImagePreviewTransform();
2086
+ const releaseImageUrl = useCallback(() => {
2087
+ if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
2088
+ objectUrlRef.current = null;
2089
+ }, []);
2090
+ const item = useMemo(() => ({
2091
+ id: `${sourceId}:${document.revision}`,
2092
+ src: url ?? "",
2093
+ alt: fileName,
2094
+ title: fileName
2095
+ }), [
2096
+ fileName,
2097
+ sourceId,
2098
+ document.revision,
2099
+ url
2100
+ ]);
2101
+ useEffect(() => {
2102
+ const controller = new AbortController();
2103
+ setStatus("loading");
2104
+ setUrl(null);
2105
+ readPreviewDocument(document, IMAGE_PREVIEW_MAX_SIZE_BYTES, controller.signal).then((bytes) => {
2106
+ if (controller.signal.aborted) return;
2107
+ const extension = fileName.split(".").at(-1)?.toLowerCase();
2108
+ const normalizedMediaType = mediaType?.split(";", 1)[0].trim().toLowerCase();
2109
+ const mime = normalizedMediaType && imageFilePreviewPlugin.mediaTypes.includes(normalizedMediaType) ? normalizedMediaType : IMAGE_MEDIA_TYPE_BY_EXTENSION[extension ?? ""] ?? `image/${extension}`;
2110
+ objectUrlRef.current = URL.createObjectURL(new Blob([bytes], { type: mime }));
2111
+ setUrl(objectUrlRef.current);
2112
+ }).catch((error) => {
2113
+ if (controller.signal.aborted) return;
2114
+ failDocument?.(error);
2115
+ setStatus(error instanceof PreviewError && error.code === "too_large" ? "too_large" : "error");
2116
+ });
2117
+ return () => {
2118
+ controller.abort();
2119
+ releaseImageUrl();
2120
+ };
2121
+ }, [
2122
+ document,
2123
+ fileName,
2124
+ mediaType,
2125
+ failDocument,
2126
+ releaseImageUrl
2127
+ ]);
2128
+ if (status === "too_large") return /* @__PURE__ */ jsx(FilePreviewLayout.Frame, { children: /* @__PURE__ */ jsx(FilePreviewLayout.Content, { children: /* @__PURE__ */ jsx(FilePreviewTooLarge, {
2129
+ sizeBytes: document.size,
2130
+ limitBytes: IMAGE_PREVIEW_MAX_SIZE_BYTES
2131
+ }) }) });
2132
+ if (status === "error") return /* @__PURE__ */ jsx(FilePreviewLayout.Frame, { children: /* @__PURE__ */ jsx(FilePreviewLayout.Content, { children: /* @__PURE__ */ jsx("div", {
2133
+ role: "alert",
2134
+ className: "h-full",
2135
+ children: /* @__PURE__ */ jsx(EmptyState, {
2136
+ icon: ImageOff,
2137
+ title: t("file_preview.load_error.title"),
2138
+ description: t("file_preview.load_error.description"),
2139
+ className: "h-full"
2140
+ })
2141
+ }) }) });
2142
+ return /* @__PURE__ */ jsxs(FilePreviewLayout.Frame, { children: [/* @__PURE__ */ jsx(ImageFilePreviewToolbar, {
2143
+ disabled: status !== "ready",
2144
+ transformControls
2145
+ }), /* @__PURE__ */ jsx(FilePreviewLayout.Content, { children: /* @__PURE__ */ jsxs("div", {
2146
+ className: "relative flex h-full min-h-full min-w-full items-center justify-center p-4",
2147
+ children: [status === "loading" && /* @__PURE__ */ jsxs("div", {
2148
+ role: "status",
2149
+ className: "absolute inset-0 flex items-center justify-center gap-2 text-sm text-muted-foreground",
2150
+ children: [/* @__PURE__ */ jsx(LoaderCircle, {
2151
+ className: "size-4 animate-spin",
2152
+ "aria-hidden": true
2153
+ }), /* @__PURE__ */ jsx("span", { children: t("file_preview.loading") })]
2154
+ }), url ? /* @__PURE__ */ jsx(ImagePreviewViewport, {
2155
+ className: "h-full min-h-full w-full",
2156
+ imageClassName: status === "loading" ? "opacity-0" : void 0,
2157
+ item,
2158
+ transformControls,
2159
+ onLoad: () => setStatus("ready"),
2160
+ onError: () => {
2161
+ const error = /* @__PURE__ */ new Error(`Failed to load image preview: ${sourceId}`);
2162
+ failDocument?.(error);
2163
+ releaseImageUrl();
2164
+ setUrl(null);
2165
+ setStatus("error");
2166
+ }
2167
+ }) : null]
2168
+ }) })] });
2169
+ }
2170
+ //#endregion
2171
+ export { ImageFilePreview as default };