@djangocfg/ui-tools 2.1.389 → 2.1.393

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 (183) hide show
  1. package/README.md +7 -10
  2. package/dist/chunk-PAWJFY3S.mjs +6 -0
  3. package/dist/{chunk-N2XQF2OL.mjs.map → chunk-PAWJFY3S.mjs.map} +1 -1
  4. package/dist/chunk-PK6SKIKE.cjs +8 -0
  5. package/dist/{chunk-OLISEQHS.cjs.map → chunk-PK6SKIKE.cjs.map} +1 -1
  6. package/dist/file-icon/index.cjs +6 -6
  7. package/dist/file-icon/index.d.cts +1 -1
  8. package/dist/file-icon/index.d.ts +1 -1
  9. package/dist/file-icon/index.mjs +1 -1
  10. package/dist/tree/index.cjs +1372 -143
  11. package/dist/tree/index.cjs.map +1 -1
  12. package/dist/tree/index.d.cts +2 -2
  13. package/dist/tree/index.d.ts +2 -2
  14. package/dist/tree/index.mjs +1322 -3
  15. package/dist/tree/index.mjs.map +1 -1
  16. package/dist/{types-CevSbyfD.d.cts → types-B_zhyAqR.d.cts} +1 -1
  17. package/dist/{types-CevSbyfD.d.ts → types-B_zhyAqR.d.ts} +1 -1
  18. package/package.json +9 -17
  19. package/src/tools/AudioPlayer/README.md +4 -4
  20. package/src/tools/Chat/README.md +6 -6
  21. package/src/tools/CronScheduler/index.tsx +1 -1
  22. package/src/tools/CronScheduler/lazy.tsx +1 -1
  23. package/src/tools/ImageViewer/README.md +1 -1
  24. package/src/tools/JsonForm/README.md +2 -2
  25. package/src/tools/MarkdownEditor/README.md +3 -3
  26. package/src/tools/MarkdownMessage/README.md +2 -2
  27. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +5 -1
  28. package/src/tools/SpeechRecognition/README.md +1 -1
  29. package/dist/ChatRoot-EFNXQXXN.cjs +0 -15
  30. package/dist/ChatRoot-EFNXQXXN.cjs.map +0 -1
  31. package/dist/ChatRoot-FITF5RVP.mjs +0 -6
  32. package/dist/ChatRoot-FITF5RVP.mjs.map +0 -1
  33. package/dist/ChatRoot-PNNGQCYF.css +0 -7
  34. package/dist/ChatRoot-PNNGQCYF.css.map +0 -1
  35. package/dist/CronScheduler.client-DLMXCPAJ.mjs +0 -67
  36. package/dist/CronScheduler.client-DLMXCPAJ.mjs.map +0 -1
  37. package/dist/CronScheduler.client-WEJF4PWQ.cjs +0 -72
  38. package/dist/CronScheduler.client-WEJF4PWQ.cjs.map +0 -1
  39. package/dist/DictationField-AS2F33WI.cjs +0 -13
  40. package/dist/DictationField-AS2F33WI.cjs.map +0 -1
  41. package/dist/DictationField-WPONUCYE.mjs +0 -4
  42. package/dist/DictationField-WPONUCYE.mjs.map +0 -1
  43. package/dist/DocsLayout-EKASBSP7.mjs +0 -3448
  44. package/dist/DocsLayout-EKASBSP7.mjs.map +0 -1
  45. package/dist/DocsLayout-MBFIB4NO.css +0 -7
  46. package/dist/DocsLayout-MBFIB4NO.css.map +0 -1
  47. package/dist/DocsLayout-OURFYWQE.cjs +0 -3455
  48. package/dist/DocsLayout-OURFYWQE.cjs.map +0 -1
  49. package/dist/JsonSchemaForm-DD7CLRIG.cjs +0 -13
  50. package/dist/JsonSchemaForm-DD7CLRIG.cjs.map +0 -1
  51. package/dist/JsonSchemaForm-XKUIVELK.mjs +0 -4
  52. package/dist/JsonSchemaForm-XKUIVELK.mjs.map +0 -1
  53. package/dist/JsonTree-43PQAJKY.mjs +0 -5
  54. package/dist/JsonTree-43PQAJKY.mjs.map +0 -1
  55. package/dist/JsonTree-MLET23ZA.css +0 -7
  56. package/dist/JsonTree-MLET23ZA.css.map +0 -1
  57. package/dist/JsonTree-X6W5YEVY.cjs +0 -11
  58. package/dist/JsonTree-X6W5YEVY.cjs.map +0 -1
  59. package/dist/LottiePlayer.client-2S7ISJ2S.cjs +0 -168
  60. package/dist/LottiePlayer.client-2S7ISJ2S.cjs.map +0 -1
  61. package/dist/LottiePlayer.client-5LDSSJWS.mjs +0 -161
  62. package/dist/LottiePlayer.client-5LDSSJWS.mjs.map +0 -1
  63. package/dist/MapContainer-AKIPABJK.mjs +0 -4
  64. package/dist/MapContainer-AKIPABJK.mjs.map +0 -1
  65. package/dist/MapContainer-STVDMC36.cjs +0 -17
  66. package/dist/MapContainer-STVDMC36.cjs.map +0 -1
  67. package/dist/Mermaid.client-DDXWXZXY.css +0 -7
  68. package/dist/Mermaid.client-DDXWXZXY.css.map +0 -1
  69. package/dist/Mermaid.client-NL4SVR7F.mjs +0 -481
  70. package/dist/Mermaid.client-NL4SVR7F.mjs.map +0 -1
  71. package/dist/Mermaid.client-NNTI6DFX.cjs +0 -487
  72. package/dist/Mermaid.client-NNTI6DFX.cjs.map +0 -1
  73. package/dist/Player-BRV7XTWR.mjs +0 -4
  74. package/dist/Player-BRV7XTWR.mjs.map +0 -1
  75. package/dist/Player-PM7F7DD7.cjs +0 -13
  76. package/dist/Player-PM7F7DD7.cjs.map +0 -1
  77. package/dist/Player-ZGQKKOWI.css +0 -66
  78. package/dist/Player-ZGQKKOWI.css.map +0 -1
  79. package/dist/PrettyCode.client-GWFAIVFN.css +0 -7
  80. package/dist/PrettyCode.client-GWFAIVFN.css.map +0 -1
  81. package/dist/PrettyCode.client-KOHDVPPN.cjs +0 -285
  82. package/dist/PrettyCode.client-KOHDVPPN.cjs.map +0 -1
  83. package/dist/PrettyCode.client-ZGYGKE7G.mjs +0 -283
  84. package/dist/PrettyCode.client-ZGYGKE7G.mjs.map +0 -1
  85. package/dist/TreeRoot-5COOOSWG.mjs +0 -4
  86. package/dist/TreeRoot-5COOOSWG.mjs.map +0 -1
  87. package/dist/TreeRoot-AABP2J6Y.cjs +0 -19
  88. package/dist/TreeRoot-AABP2J6Y.cjs.map +0 -1
  89. package/dist/chunk-2NG4SXEP.mjs +0 -743
  90. package/dist/chunk-2NG4SXEP.mjs.map +0 -1
  91. package/dist/chunk-4LFB7I5K.cjs +0 -1387
  92. package/dist/chunk-4LFB7I5K.cjs.map +0 -1
  93. package/dist/chunk-5D2OCOPQ.cjs +0 -222
  94. package/dist/chunk-5D2OCOPQ.cjs.map +0 -1
  95. package/dist/chunk-5I5QNGUG.cjs +0 -611
  96. package/dist/chunk-5I5QNGUG.cjs.map +0 -1
  97. package/dist/chunk-6ZX2G25W.mjs +0 -1361
  98. package/dist/chunk-6ZX2G25W.mjs.map +0 -1
  99. package/dist/chunk-76NNDZH6.cjs +0 -1061
  100. package/dist/chunk-76NNDZH6.cjs.map +0 -1
  101. package/dist/chunk-7CWGZPO3.mjs +0 -214
  102. package/dist/chunk-7CWGZPO3.mjs.map +0 -1
  103. package/dist/chunk-7EYHNP3E.cjs +0 -965
  104. package/dist/chunk-7EYHNP3E.cjs.map +0 -1
  105. package/dist/chunk-7IYXZUJO.cjs +0 -769
  106. package/dist/chunk-7IYXZUJO.cjs.map +0 -1
  107. package/dist/chunk-ADEN3UA4.cjs +0 -892
  108. package/dist/chunk-ADEN3UA4.cjs.map +0 -1
  109. package/dist/chunk-B6IR5KSC.mjs +0 -59
  110. package/dist/chunk-B6IR5KSC.mjs.map +0 -1
  111. package/dist/chunk-C6GXVH5J.mjs +0 -338
  112. package/dist/chunk-C6GXVH5J.mjs.map +0 -1
  113. package/dist/chunk-DMX7W4XZ.mjs +0 -1113
  114. package/dist/chunk-DMX7W4XZ.mjs.map +0 -1
  115. package/dist/chunk-ECONRHIG.mjs +0 -212
  116. package/dist/chunk-ECONRHIG.mjs.map +0 -1
  117. package/dist/chunk-FEN5S772.cjs +0 -1227
  118. package/dist/chunk-FEN5S772.cjs.map +0 -1
  119. package/dist/chunk-FP2RLYQZ.cjs +0 -187
  120. package/dist/chunk-FP2RLYQZ.cjs.map +0 -1
  121. package/dist/chunk-FVVF7VCD.cjs +0 -1325
  122. package/dist/chunk-FVVF7VCD.cjs.map +0 -1
  123. package/dist/chunk-GYIO7W7M.mjs +0 -1197
  124. package/dist/chunk-GYIO7W7M.mjs.map +0 -1
  125. package/dist/chunk-KNDLV4PI.cjs +0 -1356
  126. package/dist/chunk-KNDLV4PI.cjs.map +0 -1
  127. package/dist/chunk-KNEQRUBA.mjs +0 -181
  128. package/dist/chunk-KNEQRUBA.mjs.map +0 -1
  129. package/dist/chunk-N2XQF2OL.mjs +0 -14
  130. package/dist/chunk-N4MZYNR4.mjs +0 -1342
  131. package/dist/chunk-N4MZYNR4.mjs.map +0 -1
  132. package/dist/chunk-NTVBIIUD.mjs +0 -1439
  133. package/dist/chunk-NTVBIIUD.mjs.map +0 -1
  134. package/dist/chunk-OBRSGM64.mjs +0 -607
  135. package/dist/chunk-OBRSGM64.mjs.map +0 -1
  136. package/dist/chunk-ODO4GMW7.mjs +0 -79
  137. package/dist/chunk-ODO4GMW7.mjs.map +0 -1
  138. package/dist/chunk-OLISEQHS.cjs +0 -18
  139. package/dist/chunk-PVAX67JG.mjs +0 -1041
  140. package/dist/chunk-PVAX67JG.mjs.map +0 -1
  141. package/dist/chunk-QJ6GTUCO.cjs +0 -81
  142. package/dist/chunk-QJ6GTUCO.cjs.map +0 -1
  143. package/dist/chunk-T3MWM23F.cjs +0 -214
  144. package/dist/chunk-T3MWM23F.cjs.map +0 -1
  145. package/dist/chunk-TBSHZO5R.cjs +0 -1134
  146. package/dist/chunk-TBSHZO5R.cjs.map +0 -1
  147. package/dist/chunk-UNCS5V5F.mjs +0 -887
  148. package/dist/chunk-UNCS5V5F.mjs.map +0 -1
  149. package/dist/chunk-VWQ5WOIL.mjs +0 -2059
  150. package/dist/chunk-VWQ5WOIL.mjs.map +0 -1
  151. package/dist/chunk-W75B7Y6C.cjs +0 -1478
  152. package/dist/chunk-W75B7Y6C.cjs.map +0 -1
  153. package/dist/chunk-Y6UTOBF6.mjs +0 -938
  154. package/dist/chunk-Y6UTOBF6.mjs.map +0 -1
  155. package/dist/chunk-YDPDTOSP.cjs +0 -2061
  156. package/dist/chunk-YDPDTOSP.cjs.map +0 -1
  157. package/dist/chunk-YW5IVWHQ.cjs +0 -346
  158. package/dist/chunk-YW5IVWHQ.cjs.map +0 -1
  159. package/dist/chunk-YXZ6GU7H.cjs +0 -63
  160. package/dist/chunk-YXZ6GU7H.cjs.map +0 -1
  161. package/dist/chunk-ZL7FH4NW.mjs +0 -1274
  162. package/dist/chunk-ZL7FH4NW.mjs.map +0 -1
  163. package/dist/components-EHOGXATG.cjs +0 -22
  164. package/dist/components-EHOGXATG.cjs.map +0 -1
  165. package/dist/components-MQ6DR7TX.cjs +0 -26
  166. package/dist/components-MQ6DR7TX.cjs.map +0 -1
  167. package/dist/components-XRX7QGLB.mjs +0 -5
  168. package/dist/components-XRX7QGLB.mjs.map +0 -1
  169. package/dist/components-YATKRWLH.mjs +0 -5
  170. package/dist/components-YATKRWLH.mjs.map +0 -1
  171. package/dist/index.cjs +0 -3674
  172. package/dist/index.cjs.map +0 -1
  173. package/dist/index.css +0 -234
  174. package/dist/index.css.map +0 -1
  175. package/dist/index.d.cts +0 -4929
  176. package/dist/index.d.ts +0 -4929
  177. package/dist/index.mjs +0 -2912
  178. package/dist/index.mjs.map +0 -1
  179. package/dist/launcher-5Y42OBSN.mjs +0 -6
  180. package/dist/launcher-5Y42OBSN.mjs.map +0 -1
  181. package/dist/launcher-PMW2YB24.cjs +0 -59
  182. package/dist/launcher-PMW2YB24.cjs.map +0 -1
  183. package/src/index.ts +0 -157
@@ -1,611 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkYW5IVWHQ_cjs = require('./chunk-YW5IVWHQ.cjs');
4
- var chunkOLISEQHS_cjs = require('./chunk-OLISEQHS.cjs');
5
- var react = require('react');
6
- var lucideReact = require('lucide-react');
7
- var reactZoomPanPinch = require('react-zoom-pan-pinch');
8
- var uiCore = require('@djangocfg/ui-core');
9
- var i18n = require('@djangocfg/i18n');
10
- var hooks = require('@djangocfg/ui-core/hooks');
11
- var components = require('@djangocfg/ui-core/components');
12
- var lib = require('@djangocfg/ui-core/lib');
13
- var jsxRuntime = require('react/jsx-runtime');
14
-
15
- // src/tools/ImageViewer/utils/constants.ts
16
- var MAX_IMAGE_SIZE = 50 * 1024 * 1024;
17
- var WARNING_IMAGE_SIZE = 10 * 1024 * 1024;
18
- var PROGRESSIVE_LOADING_THRESHOLD = 500 * 1024;
19
- var LQIP_SIZE = 32;
20
- var LQIP_QUALITY = 0.5;
21
- var ZOOM_PRESETS = [
22
- { label: "Fit", value: "fit" },
23
- { label: "25%", value: 0.25 },
24
- { label: "50%", value: 0.5 },
25
- { label: "100%", value: 1 },
26
- { label: "200%", value: 2 },
27
- { label: "400%", value: 4 }
28
- ];
29
- var DEFAULT_TRANSFORM = {
30
- rotation: 0,
31
- flipH: false,
32
- flipV: false
33
- };
34
-
35
- // src/tools/ImageViewer/utils/lqip.ts
36
- async function createLQIP(imageSrc) {
37
- try {
38
- const img = new Image();
39
- img.crossOrigin = "anonymous";
40
- await new Promise((resolve, reject) => {
41
- img.onload = () => resolve();
42
- img.onerror = () => reject(new Error("Failed to load image for LQIP"));
43
- img.src = imageSrc;
44
- });
45
- const aspect = img.naturalWidth / img.naturalHeight;
46
- const width = aspect >= 1 ? LQIP_SIZE : Math.round(LQIP_SIZE * aspect);
47
- const height = aspect >= 1 ? Math.round(LQIP_SIZE / aspect) : LQIP_SIZE;
48
- const canvas = document.createElement("canvas");
49
- canvas.width = width;
50
- canvas.height = height;
51
- const ctx = canvas.getContext("2d");
52
- if (!ctx) return null;
53
- ctx.drawImage(img, 0, 0, width, height);
54
- return canvas.toDataURL("image/jpeg", LQIP_QUALITY);
55
- } catch {
56
- return null;
57
- }
58
- }
59
- chunkOLISEQHS_cjs.__name(createLQIP, "createLQIP");
60
- var imageDebug = lib.createMediaLogger("ImageViewer");
61
- function ImageToolbar({
62
- scale,
63
- transform,
64
- onRotate,
65
- onFlipH,
66
- onFlipV,
67
- onZoomPreset,
68
- onExpand
69
- }) {
70
- const t = i18n.useAppT();
71
- const { zoomIn, zoomOut, resetTransform } = reactZoomPanPinch.useControls();
72
- const labels = react.useMemo(() => ({
73
- zoomIn: t("tools.image.zoomIn"),
74
- zoomOut: t("tools.image.zoomOut"),
75
- fitToView: t("tools.image.fitToView"),
76
- flipHorizontal: t("tools.image.flipHorizontal"),
77
- flipVertical: t("tools.image.flipVertical"),
78
- rotate: t("tools.image.rotate"),
79
- fullscreen: t("tools.image.fullscreen")
80
- }), [t]);
81
- const zoomLabel = react.useMemo(() => {
82
- const percent = Math.round(scale * 100);
83
- return `${percent}%`;
84
- }, [scale]);
85
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-0.5 bg-background/90 backdrop-blur-sm border rounded-lg p-1 shadow-lg", children: [
86
- /* @__PURE__ */ jsxRuntime.jsx(
87
- components.Button,
88
- {
89
- variant: "ghost",
90
- size: "icon",
91
- className: "h-7 w-7",
92
- onClick: () => zoomOut(),
93
- title: labels.zoomOut,
94
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { className: "h-3.5 w-3.5" })
95
- }
96
- ),
97
- /* @__PURE__ */ jsxRuntime.jsxs(components.DropdownMenu, { children: [
98
- /* @__PURE__ */ jsxRuntime.jsx(components.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(components.Button, { variant: "ghost", size: "sm", className: "h-7 px-2 min-w-[52px] font-mono text-xs", children: zoomLabel }) }),
99
- /* @__PURE__ */ jsxRuntime.jsx(components.DropdownMenuContent, { align: "center", className: "min-w-[80px]", children: ZOOM_PRESETS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
100
- components.DropdownMenuItem,
101
- {
102
- onClick: () => onZoomPreset(preset.value),
103
- className: "text-xs justify-center",
104
- children: preset.label
105
- },
106
- preset.label
107
- )) })
108
- ] }),
109
- /* @__PURE__ */ jsxRuntime.jsx(
110
- components.Button,
111
- {
112
- variant: "ghost",
113
- size: "icon",
114
- className: "h-7 w-7",
115
- onClick: () => zoomIn(),
116
- title: labels.zoomIn,
117
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { className: "h-3.5 w-3.5" })
118
- }
119
- ),
120
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-border mx-1" }),
121
- /* @__PURE__ */ jsxRuntime.jsx(
122
- components.Button,
123
- {
124
- variant: "ghost",
125
- size: "icon",
126
- className: "h-7 w-7",
127
- onClick: () => resetTransform(),
128
- title: labels.fitToView,
129
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-3.5 w-3.5" })
130
- }
131
- ),
132
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-border mx-1" }),
133
- /* @__PURE__ */ jsxRuntime.jsx(
134
- components.Button,
135
- {
136
- variant: "ghost",
137
- size: "icon",
138
- className: lib.cn("h-7 w-7", transform.flipH && "bg-accent"),
139
- onClick: onFlipH,
140
- title: labels.flipHorizontal,
141
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipHorizontal, { className: "h-3.5 w-3.5" })
142
- }
143
- ),
144
- /* @__PURE__ */ jsxRuntime.jsx(
145
- components.Button,
146
- {
147
- variant: "ghost",
148
- size: "icon",
149
- className: lib.cn("h-7 w-7", transform.flipV && "bg-accent"),
150
- onClick: onFlipV,
151
- title: labels.flipVertical,
152
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipVertical, { className: "h-3.5 w-3.5" })
153
- }
154
- ),
155
- /* @__PURE__ */ jsxRuntime.jsx(
156
- components.Button,
157
- {
158
- variant: "ghost",
159
- size: "icon",
160
- className: "h-7 w-7",
161
- onClick: onRotate,
162
- title: labels.rotate,
163
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "h-3.5 w-3.5" })
164
- }
165
- ),
166
- transform.rotation !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[10px] text-muted-foreground font-mono pl-1", children: [
167
- transform.rotation,
168
- "\xB0"
169
- ] }),
170
- onExpand && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
171
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-px h-4 bg-border mx-1" }),
172
- /* @__PURE__ */ jsxRuntime.jsx(
173
- components.Button,
174
- {
175
- variant: "ghost",
176
- size: "icon",
177
- className: "h-7 w-7",
178
- onClick: onExpand,
179
- title: labels.fullscreen,
180
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Expand, { className: "h-3.5 w-3.5" })
181
- }
182
- )
183
- ] })
184
- ] });
185
- }
186
- chunkOLISEQHS_cjs.__name(ImageToolbar, "ImageToolbar");
187
- function ImageInfo({ src }) {
188
- const { getDimensions, cacheDimensions } = chunkYW5IVWHQ_cjs.useImageCache();
189
- const [dimensions, setDimensions] = react.useState(null);
190
- react.useEffect(() => {
191
- const cached = getDimensions(src);
192
- if (cached) {
193
- setDimensions({ w: cached.width, h: cached.height });
194
- return;
195
- }
196
- const img = new Image();
197
- img.onload = () => {
198
- const dims = { w: img.naturalWidth, h: img.naturalHeight };
199
- setDimensions(dims);
200
- cacheDimensions(src, { width: dims.w, height: dims.h });
201
- };
202
- img.src = src;
203
- }, [src, getDimensions, cacheDimensions]);
204
- if (!dimensions) return null;
205
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-3 right-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono", children: [
206
- dimensions.w,
207
- " \xD7 ",
208
- dimensions.h
209
- ] });
210
- }
211
- chunkOLISEQHS_cjs.__name(ImageInfo, "ImageInfo");
212
- function useImageTransform(options = {}) {
213
- const { resetKey } = options;
214
- const [transform, setTransform] = react.useState(DEFAULT_TRANSFORM);
215
- react.useEffect(() => {
216
- setTransform(DEFAULT_TRANSFORM);
217
- }, [resetKey]);
218
- const rotate = react.useCallback(() => {
219
- setTransform((prev) => ({
220
- ...prev,
221
- rotation: (prev.rotation + 90) % 360
222
- }));
223
- }, []);
224
- const flipH = react.useCallback(() => {
225
- setTransform((prev) => ({
226
- ...prev,
227
- flipH: !prev.flipH
228
- }));
229
- }, []);
230
- const flipV = react.useCallback(() => {
231
- setTransform((prev) => ({
232
- ...prev,
233
- flipV: !prev.flipV
234
- }));
235
- }, []);
236
- const reset = react.useCallback(() => {
237
- setTransform(DEFAULT_TRANSFORM);
238
- }, []);
239
- const transformStyle = react.useMemo(() => {
240
- const transforms = [];
241
- if (transform.rotation !== 0) {
242
- transforms.push(`rotate(${transform.rotation}deg)`);
243
- }
244
- if (transform.flipH) {
245
- transforms.push("scaleX(-1)");
246
- }
247
- if (transform.flipV) {
248
- transforms.push("scaleY(-1)");
249
- }
250
- return transforms.join(" ") || "none";
251
- }, [transform]);
252
- return {
253
- transform,
254
- rotate,
255
- flipH,
256
- flipV,
257
- reset,
258
- transformStyle
259
- };
260
- }
261
- chunkOLISEQHS_cjs.__name(useImageTransform, "useImageTransform");
262
- function useImageLoading(options) {
263
- const { content, mimeType, src: directSrc } = options;
264
- const getOrCreateBlobUrl = chunkYW5IVWHQ_cjs.useMediaCacheStore.getState().getOrCreateBlobUrl;
265
- const releaseBlobUrl = chunkYW5IVWHQ_cjs.useMediaCacheStore.getState().releaseBlobUrl;
266
- const [src, setSrc] = react.useState(null);
267
- const [lqip, setLqip] = react.useState(null);
268
- const [isFullyLoaded, setIsFullyLoaded] = react.useState(false);
269
- const [error, setError] = react.useState(null);
270
- const contentKeyRef = react.useRef(null);
271
- const isMountedRef = react.useRef(true);
272
- const size = content ? typeof content === "string" ? content.length : content.byteLength : 0;
273
- const hasContent = directSrc ? true : size > 0;
274
- const useProgressiveLoading = directSrc ? false : size > PROGRESSIVE_LOADING_THRESHOLD;
275
- react.useEffect(() => {
276
- isMountedRef.current = true;
277
- return () => {
278
- isMountedRef.current = false;
279
- if (contentKeyRef.current) {
280
- chunkYW5IVWHQ_cjs.useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);
281
- contentKeyRef.current = null;
282
- }
283
- };
284
- }, []);
285
- react.useEffect(() => {
286
- setError(null);
287
- if (directSrc) {
288
- imageDebug.load(directSrc, "url");
289
- setSrc(directSrc);
290
- setIsFullyLoaded(true);
291
- return;
292
- }
293
- if (!hasContent) {
294
- setSrc(null);
295
- return;
296
- }
297
- if (size > MAX_IMAGE_SIZE) {
298
- const sizeMB = (size / 1024 / 1024).toFixed(1);
299
- const errorMsg = `Image too large: ${sizeMB}MB (maximum: 50MB)`;
300
- imageDebug.error(errorMsg, { size, sizeMB, maxSize: MAX_IMAGE_SIZE });
301
- setError(errorMsg);
302
- setSrc(null);
303
- return;
304
- }
305
- if (size > WARNING_IMAGE_SIZE) {
306
- const sizeMB = (size / 1024 / 1024).toFixed(1);
307
- imageDebug.warn(`Large image: ${sizeMB}MB - may impact performance`);
308
- }
309
- if (typeof content === "string") {
310
- if (content.startsWith("data:")) {
311
- imageDebug.load(content.slice(0, 50) + "...", "data-url");
312
- setSrc(content);
313
- return;
314
- }
315
- const encoder = new TextEncoder();
316
- const buffer = encoder.encode(content).buffer;
317
- const contentKey2 = chunkYW5IVWHQ_cjs.generateContentKey(buffer);
318
- if (contentKeyRef.current && contentKeyRef.current !== contentKey2) {
319
- releaseBlobUrl(contentKeyRef.current);
320
- }
321
- contentKeyRef.current = contentKey2;
322
- const url2 = getOrCreateBlobUrl(contentKey2, buffer, mimeType || "image/png");
323
- imageDebug.load(url2, "blob");
324
- imageDebug.state("loaded", { size, mimeType, contentKey: contentKey2 });
325
- setSrc(url2);
326
- return;
327
- }
328
- const contentKey = chunkYW5IVWHQ_cjs.generateContentKey(content);
329
- if (contentKeyRef.current && contentKeyRef.current !== contentKey) {
330
- releaseBlobUrl(contentKeyRef.current);
331
- }
332
- contentKeyRef.current = contentKey;
333
- const url = getOrCreateBlobUrl(contentKey, content, mimeType || "image/png");
334
- imageDebug.load(url, "blob");
335
- imageDebug.state("loaded", { size, mimeType, contentKey });
336
- setSrc(url);
337
- }, [content, mimeType, hasContent, size, directSrc]);
338
- react.useEffect(() => {
339
- if (!src || !useProgressiveLoading) {
340
- setLqip(null);
341
- setIsFullyLoaded(true);
342
- return;
343
- }
344
- setIsFullyLoaded(false);
345
- imageDebug.state("progressive loading", { size });
346
- createLQIP(src).then((placeholder) => {
347
- if (placeholder) {
348
- imageDebug.debug("LQIP created");
349
- setLqip(placeholder);
350
- }
351
- });
352
- const img = new Image();
353
- img.onload = () => {
354
- imageDebug.state("fully loaded");
355
- setIsFullyLoaded(true);
356
- };
357
- img.onerror = () => {
358
- imageDebug.error("Failed to load full image");
359
- };
360
- img.src = src;
361
- }, [src, useProgressiveLoading, size]);
362
- return {
363
- src,
364
- lqip,
365
- isFullyLoaded,
366
- useProgressiveLoading,
367
- error,
368
- contentKey: contentKeyRef.current,
369
- size,
370
- hasContent
371
- };
372
- }
373
- chunkOLISEQHS_cjs.__name(useImageLoading, "useImageLoading");
374
- function ImageViewer({
375
- images,
376
- initialIndex = 0,
377
- inDialog = false
378
- }) {
379
- const t = i18n.useAppT();
380
- const [currentIndex, setCurrentIndex] = react.useState(
381
- () => Math.max(0, Math.min(initialIndex, images.length - 1))
382
- );
383
- react.useEffect(() => {
384
- setCurrentIndex(Math.max(0, Math.min(initialIndex, images.length - 1)));
385
- }, [initialIndex, images.length]);
386
- const current = images[currentIndex];
387
- const hasMultiple = images.length > 1;
388
- const [scale, setScale] = react.useState(1);
389
- const [dialogOpen, setDialogOpen] = react.useState(false);
390
- const [loadError, setLoadError] = react.useState(false);
391
- const containerRef = react.useRef(null);
392
- const controlsRef = react.useRef(null);
393
- const labels = react.useMemo(() => ({
394
- noImage: t("tools.image.noImage"),
395
- failedToLoad: t("tools.image.failedToLoad"),
396
- loading: t("ui.form.loading")
397
- }), [t]);
398
- const {
399
- src,
400
- lqip,
401
- isFullyLoaded,
402
- useProgressiveLoading,
403
- error,
404
- hasContent
405
- } = useImageLoading({
406
- content: current?.content ?? "",
407
- mimeType: current?.file.mimeType,
408
- src: current?.src
409
- });
410
- react.useEffect(() => {
411
- setLoadError(false);
412
- }, [src]);
413
- const { transform, rotate, flipH, flipV, transformStyle } = useImageTransform({
414
- resetKey: current?.file.path ?? ""
415
- });
416
- const handleZoomPreset = react.useCallback((value) => {
417
- if (!controlsRef.current) return;
418
- if (value === "fit") controlsRef.current.resetTransform();
419
- else controlsRef.current.setTransform(0, 0, value);
420
- }, []);
421
- const handleExpand = react.useCallback(() => setDialogOpen(true), []);
422
- const prev = react.useCallback(
423
- () => setCurrentIndex((i) => (i - 1 + images.length) % images.length),
424
- [images.length]
425
- );
426
- const next = react.useCallback(
427
- () => setCurrentIndex((i) => (i + 1) % images.length),
428
- [images.length]
429
- );
430
- react.useEffect(() => {
431
- const handleKeyDown = /* @__PURE__ */ chunkOLISEQHS_cjs.__name((e) => {
432
- if (!containerRef.current?.contains(document.activeElement) && document.activeElement !== containerRef.current) return;
433
- const controls = controlsRef.current;
434
- if (!controls) return;
435
- switch (e.key) {
436
- case "+":
437
- case "=":
438
- e.preventDefault();
439
- controls.zoomIn();
440
- break;
441
- case "-":
442
- e.preventDefault();
443
- controls.zoomOut();
444
- break;
445
- case "0":
446
- e.preventDefault();
447
- controls.resetTransform();
448
- break;
449
- case "r":
450
- if (!e.metaKey && !e.ctrlKey) {
451
- e.preventDefault();
452
- rotate();
453
- }
454
- break;
455
- }
456
- }, "handleKeyDown");
457
- window.addEventListener("keydown", handleKeyDown);
458
- return () => window.removeEventListener("keydown", handleKeyDown);
459
- }, [rotate]);
460
- hooks.useHotkey("ArrowLeft", prev, { enabled: hasMultiple, preventDefault: true });
461
- hooks.useHotkey("ArrowRight", next, { enabled: hasMultiple, preventDefault: true });
462
- if (!current) {
463
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30", children: [
464
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ImageIcon, { className: "w-12 h-12 text-muted-foreground/50" }),
465
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: labels.noImage })
466
- ] });
467
- }
468
- if (error || loadError) {
469
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-3 bg-muted/30 p-4", children: [
470
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "w-12 h-12 text-destructive/70" }),
471
- /* @__PURE__ */ jsxRuntime.jsxs(uiCore.Alert, { variant: "destructive", className: "max-w-md", children: [
472
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
473
- /* @__PURE__ */ jsxRuntime.jsx(uiCore.AlertDescription, { children: error || labels.failedToLoad })
474
- ] })
475
- ] });
476
- }
477
- if (!hasContent) {
478
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-2 bg-muted/30", children: [
479
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ImageIcon, { className: "w-12 h-12 text-muted-foreground/50" }),
480
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: labels.noImage })
481
- ] });
482
- }
483
- return /* @__PURE__ */ jsxRuntime.jsxs(
484
- "div",
485
- {
486
- ref: containerRef,
487
- tabIndex: 0,
488
- className: uiCore.cn(
489
- "flex-1 h-full relative overflow-hidden outline-none",
490
- "bg-[length:16px_16px]",
491
- "[background-color:hsl(var(--muted)/0.2)]",
492
- "[background-image:linear-gradient(45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(-45deg,hsl(var(--muted)/0.4)_25%,transparent_25%),linear-gradient(45deg,transparent_75%,hsl(var(--muted)/0.4)_75%),linear-gradient(-45deg,transparent_75%,hsl(var(--muted)/0.4)_75%)]",
493
- "[background-position:0_0,0_8px,8px_-8px,-8px_0px]"
494
- ),
495
- children: [
496
- src && /* @__PURE__ */ jsxRuntime.jsx(ImageInfo, { src }),
497
- useProgressiveLoading && !isFullyLoaded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-3 left-3 z-10 px-2 py-1 bg-background/80 backdrop-blur-sm border rounded text-[10px] text-muted-foreground font-mono flex items-center gap-1.5", children: [
498
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 bg-blue-500 rounded-full animate-pulse" }),
499
- labels.loading
500
- ] }),
501
- /* @__PURE__ */ jsxRuntime.jsxs(
502
- reactZoomPanPinch.TransformWrapper,
503
- {
504
- initialScale: 1,
505
- minScale: 0.1,
506
- maxScale: 8,
507
- centerOnInit: true,
508
- centerZoomedOut: true,
509
- onTransformed: (ref, state) => {
510
- setScale(state.scale);
511
- controlsRef.current = ref;
512
- },
513
- onInit: (ref) => {
514
- controlsRef.current = ref;
515
- },
516
- wheel: { step: 0.1 },
517
- doubleClick: { mode: "toggle", step: 2 },
518
- panning: { velocityDisabled: false },
519
- children: [
520
- /* @__PURE__ */ jsxRuntime.jsx(
521
- ImageToolbar,
522
- {
523
- scale,
524
- transform,
525
- onRotate: rotate,
526
- onFlipH: flipH,
527
- onFlipV: flipV,
528
- onZoomPreset: handleZoomPreset,
529
- onExpand: !inDialog ? handleExpand : void 0
530
- }
531
- ),
532
- /* @__PURE__ */ jsxRuntime.jsx(
533
- reactZoomPanPinch.TransformComponent,
534
- {
535
- wrapperClass: "!w-full !h-full cursor-grab active:cursor-grabbing",
536
- contentClass: "!w-full !h-full flex items-center justify-center",
537
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
538
- useProgressiveLoading && lqip && !isFullyLoaded && /* @__PURE__ */ jsxRuntime.jsx(
539
- "img",
540
- {
541
- src: lqip,
542
- alt: "",
543
- "aria-hidden": "true",
544
- className: "absolute inset-0 max-w-full max-h-full object-contain select-none",
545
- style: { transform: transformStyle, filter: "blur(20px)", transition: "opacity 0.3s ease-out", opacity: isFullyLoaded ? 0 : 1 },
546
- draggable: false
547
- }
548
- ),
549
- src && /* @__PURE__ */ jsxRuntime.jsx(
550
- "img",
551
- {
552
- src,
553
- alt: current.file.name,
554
- className: "max-w-full max-h-full object-contain select-none",
555
- style: {
556
- transform: transformStyle,
557
- transition: useProgressiveLoading ? "transform 0.15s ease-out, opacity 0.3s ease-out" : "transform 0.15s ease-out",
558
- opacity: useProgressiveLoading && !isFullyLoaded ? 0 : 1
559
- },
560
- draggable: false,
561
- crossOrigin: "anonymous",
562
- onError: () => setLoadError(true)
563
- }
564
- )
565
- ] })
566
- }
567
- )
568
- ]
569
- }
570
- ),
571
- hasMultiple && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
572
- /* @__PURE__ */ jsxRuntime.jsx(
573
- "button",
574
- {
575
- type: "button",
576
- onClick: prev,
577
- className: "absolute left-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors",
578
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-5 w-5" })
579
- }
580
- ),
581
- /* @__PURE__ */ jsxRuntime.jsx(
582
- "button",
583
- {
584
- type: "button",
585
- onClick: next,
586
- className: "absolute right-2 top-1/2 -translate-y-1/2 z-10 bg-black/50 hover:bg-black/70 text-white rounded-full p-1.5 transition-colors",
587
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-5 w-5" })
588
- }
589
- ),
590
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 z-10 bg-black/50 text-white text-xs px-2 py-0.5 rounded-full pointer-events-none", children: [
591
- currentIndex + 1,
592
- " / ",
593
- images.length
594
- ] })
595
- ] }),
596
- !inDialog && /* @__PURE__ */ jsxRuntime.jsx(uiCore.Dialog, { open: dialogOpen, onOpenChange: setDialogOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(uiCore.DialogContent, { className: "max-w-[95vw] max-h-[95vh] w-[95vw] h-[95vh] p-0 overflow-hidden [&>button]:hidden flex flex-col", children: [
597
- /* @__PURE__ */ jsxRuntime.jsx(uiCore.DialogTitle, { className: "sr-only", children: current.file.name }),
598
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-4 py-2 border-b shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium truncate", children: current.file.name }) }),
599
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsx(ImageViewer, { images, initialIndex: currentIndex, inDialog: true }) })
600
- ] }) })
601
- ]
602
- }
603
- );
604
- }
605
- chunkOLISEQHS_cjs.__name(ImageViewer, "ImageViewer");
606
-
607
- exports.ImageInfo = ImageInfo;
608
- exports.ImageToolbar = ImageToolbar;
609
- exports.ImageViewer = ImageViewer;
610
- //# sourceMappingURL=chunk-5I5QNGUG.cjs.map
611
- //# sourceMappingURL=chunk-5I5QNGUG.cjs.map