@embeddr/react-ui 0.1.0 → 0.1.2

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 (131) hide show
  1. package/LICENSE.md +674 -0
  2. package/dist/context/ImageDialogContext.d.ts +4 -4
  3. package/dist/context/ImageDialogContext.d.ts.map +1 -1
  4. package/dist/context/ImageDialogContext.js.map +1 -1
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +113 -116
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/utils.d.ts +2 -2
  10. package/dist/lib/utils.d.ts.map +1 -1
  11. package/dist/lib/utils.js.map +1 -1
  12. package/dist/node_modules/.pnpm/@floating-ui_core@1.7.3/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -1
  13. package/dist/node_modules/.pnpm/@floating-ui_dom@1.7.4/node_modules/@floating-ui/dom/dist/floating-ui.dom.js.map +1 -1
  14. package/dist/node_modules/.pnpm/@floating-ui_react-dom@2.1.6_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.js.map +1 -1
  15. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.10/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -1
  16. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.10/node_modules/@floating-ui/utils/dist/floating-ui.utils.js.map +1 -1
  17. package/dist/node_modules/.pnpm/@radix-ui_primitive@1.1.3/node_modules/@radix-ui/primitive/dist/index.js.map +1 -1
  18. package/dist/node_modules/.pnpm/{@radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@1_2aa610ae3ce517c8615cebea9e24dc5b → @radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7__mszl4mxerbyoklygdzmmz7z344}/node_modules/@radix-ui/react-arrow/dist/index.js +1 -1
  19. package/dist/node_modules/.pnpm/@radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7__mszl4mxerbyoklygdzmmz7z344/node_modules/@radix-ui/react-arrow/dist/index.js.map +1 -0
  20. package/dist/node_modules/.pnpm/@radix-ui_react-compose-refs@1.1.2_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-compose-refs/dist/index.js.map +1 -1
  21. package/dist/node_modules/.pnpm/@radix-ui_react-context@1.1.2_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.js.map +1 -1
  22. package/dist/node_modules/.pnpm/{@radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.7__@_d3b8d348a25db9227f3697eddbb26378 → @radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.7__@types__3rf2o2lqjhudzepmewjxnjpij4}/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +1 -1
  23. package/dist/node_modules/.pnpm/@radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.7__@types__3rf2o2lqjhudzepmewjxnjpij4/node_modules/@radix-ui/react-dismissable-layer/dist/index.js.map +1 -0
  24. package/dist/node_modules/.pnpm/@radix-ui_react-id@1.1.1_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-id/dist/index.js.map +1 -1
  25. package/dist/node_modules/.pnpm/{@radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@_4468d6b8a14aa8e01a5fa6b59b3b35ec → @radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7_khjb2df42vo4osw72fyixnkybq}/node_modules/@radix-ui/react-popper/dist/index.js +2 -2
  26. package/dist/node_modules/.pnpm/@radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7_khjb2df42vo4osw72fyixnkybq/node_modules/@radix-ui/react-popper/dist/index.js.map +1 -0
  27. package/dist/node_modules/.pnpm/{@radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@_7645cc20debbdc3166db2ed8e9fd2af5 → @radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7_wazm3ifinqzsamvsqllqreat3m}/node_modules/@radix-ui/react-portal/dist/index.js +1 -1
  28. package/dist/node_modules/.pnpm/@radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2.7_wazm3ifinqzsamvsqllqreat3m/node_modules/@radix-ui/react-portal/dist/index.js.map +1 -0
  29. package/dist/node_modules/.pnpm/@radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2_g7nvzcflnhogkdp32witcuayfy/node_modules/@radix-ui/react-presence/dist/index.js.map +1 -0
  30. package/dist/node_modules/.pnpm/@radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19._vrijsupjqixawruberrfb56pbm/node_modules/@radix-ui/react-primitive/dist/index.js.map +1 -0
  31. package/dist/node_modules/.pnpm/@radix-ui_react-primitive@2.1.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19._4sfldbbhvd3xapj4euqmtg5wga/node_modules/@radix-ui/react-primitive/dist/index.js.map +1 -0
  32. package/dist/node_modules/.pnpm/{@radix-ui_react-tooltip@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react_61903d443f318e235810cb4023b9ffb4 → @radix-ui_react-tooltip@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2._lz7pdiyrbpqbbsap76pucwgg5i}/node_modules/@radix-ui/react-tooltip/dist/index.js +6 -6
  33. package/dist/node_modules/.pnpm/@radix-ui_react-tooltip@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2._lz7pdiyrbpqbbsap76pucwgg5i/node_modules/@radix-ui/react-tooltip/dist/index.js.map +1 -0
  34. package/dist/node_modules/.pnpm/@radix-ui_react-use-callback-ref@1.1.1_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-callback-ref/dist/index.js.map +1 -1
  35. package/dist/node_modules/.pnpm/@radix-ui_react-use-controllable-state@1.2.2_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-controllable-state/dist/index.js.map +1 -1
  36. package/dist/node_modules/.pnpm/@radix-ui_react-use-escape-keydown@1.1.1_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-escape-keydown/dist/index.js.map +1 -1
  37. package/dist/node_modules/.pnpm/@radix-ui_react-use-layout-effect@1.1.1_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-layout-effect/dist/index.js.map +1 -1
  38. package/dist/node_modules/.pnpm/@radix-ui_react-use-size@1.1.1_@types_react@19.2.7_react@19.2.3/node_modules/@radix-ui/react-use-size/dist/index.js.map +1 -1
  39. package/dist/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.7__@typ_b08a54b8b8cc1e2fcb68c28280b66cb9 → @radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_xyyq4kaffb3s2ucmc374detnx4}/node_modules/@radix-ui/react-visually-hidden/dist/index.js +1 -1
  40. package/dist/node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_xyyq4kaffb3s2ucmc374detnx4/node_modules/@radix-ui/react-visually-hidden/dist/index.js.map +1 -0
  41. package/dist/node_modules/.pnpm/{@radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@typ_7a5b8f185fdc99089c53563f38599d77 → @radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_uxirz2wej36zwyzefmreqngy74}/node_modules/@radix-ui/react-visually-hidden/dist/index.js +1 -1
  42. package/dist/node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_uxirz2wej36zwyzefmreqngy74/node_modules/@radix-ui/react-visually-hidden/dist/index.js.map +1 -0
  43. package/dist/node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js.map +1 -1
  44. package/dist/node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.js.map +1 -1
  45. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/Icon.js.map +1 -1
  46. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/createLucideIcon.js.map +1 -1
  47. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/defaultAttributes.js.map +1 -1
  48. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/check.js.map +1 -1
  49. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/chevron-down.js.map +1 -1
  50. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/chevron-right.js.map +1 -1
  51. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/chevron-up.js.map +1 -1
  52. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/circle-check.js.map +1 -1
  53. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/circle.js.map +1 -1
  54. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/grip-vertical.js.map +1 -1
  55. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/info.js.map +1 -1
  56. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/loader-circle.js.map +1 -1
  57. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/octagon-x.js.map +1 -1
  58. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/pause.js.map +1 -1
  59. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/play.js.map +1 -1
  60. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/rotate-ccw.js.map +1 -1
  61. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/rotate-cw.js.map +1 -1
  62. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/triangle-alert.js.map +1 -1
  63. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/x.js.map +1 -1
  64. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/shared/src/utils.js.map +1 -1
  65. package/dist/node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
  66. package/dist/providers/ExternalNav.js.map +1 -1
  67. package/dist/providers/ImageDialogProvider.d.ts +1 -1
  68. package/dist/providers/ImageDialogProvider.d.ts.map +1 -1
  69. package/dist/providers/ImageDialogProvider.js +7 -7
  70. package/dist/providers/ImageDialogProvider.js.map +1 -1
  71. package/dist/types/gallery.d.ts +3 -3
  72. package/dist/types/gallery.d.ts.map +1 -1
  73. package/dist/ui/badge.d.ts +1 -1
  74. package/dist/ui/badge.d.ts.map +1 -1
  75. package/dist/ui/badge.js.map +1 -1
  76. package/dist/ui/button.d.ts +1 -1
  77. package/dist/ui/button.d.ts.map +1 -1
  78. package/dist/ui/button.js.map +1 -1
  79. package/dist/ui/input-group.d.ts +1 -1
  80. package/dist/ui/input-group.d.ts.map +1 -1
  81. package/dist/ui/input-group.js.map +1 -1
  82. package/dist/ui/lightbox/GalleryPicker.js.map +1 -1
  83. package/dist/ui/lightbox/ImageThumbnailStrip.js.map +1 -1
  84. package/dist/ui/lightbox/LightboxViewer.d.ts +1 -1
  85. package/dist/ui/lightbox/LightboxViewer.d.ts.map +1 -1
  86. package/dist/ui/lightbox/LightboxViewer.js.map +1 -1
  87. package/dist/ui/lightbox/PannableImage.d.ts +2 -2
  88. package/dist/ui/lightbox/PannableImage.d.ts.map +1 -1
  89. package/dist/ui/lightbox/PannableImage.js.map +1 -1
  90. package/dist/ui/resizable.d.ts +1 -1
  91. package/dist/ui/resizable.js.map +1 -1
  92. package/dist/ui/scroll-area.d.ts.map +1 -1
  93. package/dist/ui/scroll-area.js.map +1 -1
  94. package/dist/ui/sonner.d.ts +1 -1
  95. package/dist/ui/sonner.d.ts.map +1 -1
  96. package/dist/ui/sonner.js.map +1 -1
  97. package/dist/ui/tooltip.js +1 -1
  98. package/package.json +10 -10
  99. package/dist/node_modules/.pnpm/@babel_runtime@7.28.4/node_modules/@babel/runtime/helpers/esm/extends.js +0 -13
  100. package/dist/node_modules/.pnpm/@babel_runtime@7.28.4/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
  101. package/dist/node_modules/.pnpm/@radix-ui_react-arrow@1.1.7_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@1_2aa610ae3ce517c8615cebea9e24dc5b/node_modules/@radix-ui/react-arrow/dist/index.js.map +0 -1
  102. package/dist/node_modules/.pnpm/@radix-ui_react-dismissable-layer@1.1.11_@types_react-dom@19.2.3_@types_react@19.2.7__@_d3b8d348a25db9227f3697eddbb26378/node_modules/@radix-ui/react-dismissable-layer/dist/index.js.map +0 -1
  103. package/dist/node_modules/.pnpm/@radix-ui_react-popper@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@_4468d6b8a14aa8e01a5fa6b59b3b35ec/node_modules/@radix-ui/react-popper/dist/index.js.map +0 -1
  104. package/dist/node_modules/.pnpm/@radix-ui_react-portal@1.1.9_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@_7645cc20debbdc3166db2ed8e9fd2af5/node_modules/@radix-ui/react-portal/dist/index.js.map +0 -1
  105. package/dist/node_modules/.pnpm/@radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.7__@types_reac_90b29b5754215655309320557426a63a/node_modules/@radix-ui/react-presence/dist/index.js.map +0 -1
  106. package/dist/node_modules/.pnpm/@radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_5f3d28fea11cf58eed3830d0189b6e2d/node_modules/@radix-ui/react-primitive/dist/index.js.map +0 -1
  107. package/dist/node_modules/.pnpm/@radix-ui_react-primitive@2.1.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_2890c4f0094b3fe96d52c22245e0b989/node_modules/@radix-ui/react-primitive/dist/index.js.map +0 -1
  108. package/dist/node_modules/.pnpm/@radix-ui_react-tooltip@1.2.8_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react_61903d443f318e235810cb4023b9ffb4/node_modules/@radix-ui/react-tooltip/dist/index.js.map +0 -1
  109. package/dist/node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.3_@types_react-dom@19.2.3_@types_react@19.2.7__@typ_b08a54b8b8cc1e2fcb68c28280b66cb9/node_modules/@radix-ui/react-visually-hidden/dist/index.js.map +0 -1
  110. package/dist/node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@typ_7a5b8f185fdc99089c53563f38599d77/node_modules/@radix-ui/react-visually-hidden/dist/index.js.map +0 -1
  111. package/dist/node_modules/.pnpm/@react-three_drei@10.7.7_@react-three_fiber@9.4.2_@types_react@19.2.7_react-dom@19.2.3__e3b6c415d30d21deeb56f01c9fc2836f/node_modules/@react-three/drei/core/OrbitControls.js +0 -51
  112. package/dist/node_modules/.pnpm/@react-three_drei@10.7.7_@react-three_fiber@9.4.2_@types_react@19.2.7_react-dom@19.2.3__e3b6c415d30d21deeb56f01c9fc2836f/node_modules/@react-three/drei/core/OrbitControls.js.map +0 -1
  113. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/chart-scatter.js +0 -14
  114. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/chart-scatter.js.map +0 -1
  115. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/external-link.js +0 -11
  116. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/external-link.js.map +0 -1
  117. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/eye.js +0 -16
  118. package/dist/node_modules/.pnpm/lucide-react@0.562.0_react@19.2.3/node_modules/lucide-react/dist/esm/icons/eye.js.map +0 -1
  119. package/dist/node_modules/.pnpm/three-stdlib@2.36.1_three@0.182.0/node_modules/three-stdlib/controls/EventDispatcher.js +0 -61
  120. package/dist/node_modules/.pnpm/three-stdlib@2.36.1_three@0.182.0/node_modules/three-stdlib/controls/EventDispatcher.js.map +0 -1
  121. package/dist/node_modules/.pnpm/three-stdlib@2.36.1_three@0.182.0/node_modules/three-stdlib/controls/OrbitControls.js +0 -417
  122. package/dist/node_modules/.pnpm/three-stdlib@2.36.1_three@0.182.0/node_modules/three-stdlib/controls/OrbitControls.js.map +0 -1
  123. package/dist/ui/explorers/Umap3DExplorer.d.ts +0 -4
  124. package/dist/ui/explorers/Umap3DExplorer.d.ts.map +0 -1
  125. package/dist/ui/explorers/Umap3DExplorer.js +0 -375
  126. package/dist/ui/explorers/Umap3DExplorer.js.map +0 -1
  127. package/dist/ui/explorers/types.d.ts +0 -16
  128. package/dist/ui/explorers/types.d.ts.map +0 -1
  129. /package/dist/node_modules/.pnpm/{@radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.7__@types_reac_90b29b5754215655309320557426a63a → @radix-ui_react-presence@1.1.5_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19.2_g7nvzcflnhogkdp32witcuayfy}/node_modules/@radix-ui/react-presence/dist/index.js +0 -0
  130. /package/dist/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_5f3d28fea11cf58eed3830d0189b6e2d → @radix-ui_react-primitive@2.1.3_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19._vrijsupjqixawruberrfb56pbm}/node_modules/@radix-ui/react-primitive/dist/index.js +0 -0
  131. /package/dist/node_modules/.pnpm/{@radix-ui_react-primitive@2.1.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_2890c4f0094b3fe96d52c22245e0b989 → @radix-ui_react-primitive@2.1.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_react@19._4sfldbbhvd3xapj4euqmtg5wga}/node_modules/@radix-ui/react-primitive/dist/index.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ExternalNav.js","sources":["../../src/providers/ExternalNav.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n} from \"../ui/dialog\";\nimport { Button } from \"../ui/button\";\nimport { ExternalNavContext } from \"../hooks/useExternalNav\";\n\nexport function ExternalNavProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const [href, setHref] = useState<string | null>(null);\n\n function openExternal(url: string) {\n setHref(url);\n setOpen(true);\n }\n\n function cancel() {\n setOpen(false);\n setHref(null);\n }\n\n function confirm() {\n if (href) {\n window.open(href, \"_blank\", \"noopener,noreferrer\");\n }\n setOpen(false);\n setHref(null);\n }\n\n return (\n <ExternalNavContext.Provider value={{ openExternal }}>\n <Dialog open={open} onOpenChange={(v) => (v ? setOpen(true) : cancel())}>\n {children}\n <DialogContent>\n <DialogTitle>Leaving site</DialogTitle>\n <DialogDescription>\n You are about to open an external site. This will take you off this\n page. Continue?\n <Button\n className=\"p-2 mt-4 flex hover:bg-muted/50 bg-muted/20 text-foreground border w-full hover:underline! justify-start\"\n variant=\"link\"\n size=\"sm\"\n asChild\n >\n {href && (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ textDecoration: \"none\" }}\n >\n {href}\n </a>\n )}\n </Button>\n </DialogDescription>\n <DialogFooter>\n <Button variant=\"outline\" onClick={cancel}>\n Cancel\n </Button>\n <Button onClick={confirm}>Continue</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </ExternalNavContext.Provider>\n );\n}\n"],"names":["ExternalNavProvider","children","open","setOpen","useState","href","setHref","openExternal","url","cancel","confirm","ExternalNavContext","jsxs","Dialog","v","DialogContent","jsx","DialogTitle","DialogDescription","Button","DialogFooter"],"mappings":";;;;;AAWO,SAASA,EAAoB;AAAA,EAClC,UAAAC;AACF,GAEG;AACD,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAK,GAChC,CAACC,GAAMC,CAAO,IAAIF,EAAwB,IAAI;AAEpD,WAASG,EAAaC,GAAa;AACjC,IAAAF,EAAQE,CAAG,GACXL,EAAQ,EAAI;AAAA,EACd;AAEA,WAASM,IAAS;AAChB,IAAAN,EAAQ,EAAK,GACbG,EAAQ,IAAI;AAAA,EACd;AAEA,WAASI,IAAU;AACjB,IAAIL,KACF,OAAO,KAAKA,GAAM,UAAU,qBAAqB,GAEnDF,EAAQ,EAAK,GACbG,EAAQ,IAAI;AAAA,EACd;AAEA,2BACGK,EAAmB,UAAnB,EAA4B,OAAO,EAAE,cAAAJ,KACpC,UAAA,gBAAAK,EAACC,KAAO,MAAAX,GAAY,cAAc,CAACY,MAAOA,IAAIX,EAAQ,EAAI,IAAIM,KAC3D,UAAA;AAAA,IAAAR;AAAA,sBACAc,GAAA,EACC,UAAA;AAAA,MAAA,gBAAAC,EAACC,KAAY,UAAA,eAAA,CAAY;AAAA,wBACxBC,GAAA,EAAkB,UAAA;AAAA,QAAA;AAAA,QAGjB,gBAAAF;AAAA,UAACG;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAO;AAAA,YAEN,UAAAd,KACC,gBAAAW;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAAX;AAAA,gBACA,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,OAAO,EAAE,gBAAgB,OAAA;AAAA,gBAExB,UAAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACH;AAAA,QAAA;AAAA,MAEJ,GACF;AAAA,wBACCe,GAAA,EACC,UAAA;AAAA,QAAA,gBAAAJ,EAACG,GAAA,EAAO,SAAQ,WAAU,SAASV,GAAQ,UAAA,UAE3C;AAAA,QACA,gBAAAO,EAACG,GAAA,EAAO,SAAST,GAAS,UAAA,WAAA,CAAQ;AAAA,MAAA,EAAA,CACpC;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,EAAA,CACF,EAAA,CACF;AAEJ;"}
1
+ {"version":3,"file":"ExternalNav.js","sources":["../../src/providers/ExternalNav.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogTitle,\n} from \"../ui/dialog\";\nimport { Button } from \"../ui/button\";\nimport { ExternalNavContext } from \"../hooks/useExternalNav\";\n\nexport function ExternalNavProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const [href, setHref] = useState<string | null>(null);\n\n function openExternal(url: string) {\n setHref(url);\n setOpen(true);\n }\n\n function cancel() {\n setOpen(false);\n setHref(null);\n }\n\n function confirm() {\n if (href) {\n window.open(href, \"_blank\", \"noopener,noreferrer\");\n }\n setOpen(false);\n setHref(null);\n }\n\n return (\n <ExternalNavContext.Provider value={{ openExternal }}>\n <Dialog open={open} onOpenChange={(v) => (v ? setOpen(true) : cancel())}>\n {children}\n <DialogContent>\n <DialogTitle>Leaving site</DialogTitle>\n <DialogDescription>\n You are about to open an external site. This will take you off this\n page. Continue?\n <Button\n className=\"p-2 mt-4 flex hover:bg-muted/50 bg-muted/20 text-foreground border w-full hover:underline! justify-start\"\n variant=\"link\"\n size=\"sm\"\n asChild\n >\n {href && (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ textDecoration: \"none\" }}\n >\n {href}\n </a>\n )}\n </Button>\n </DialogDescription>\n <DialogFooter>\n <Button variant=\"outline\" onClick={cancel}>\n Cancel\n </Button>\n <Button onClick={confirm}>Continue</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </ExternalNavContext.Provider>\n );\n}\n"],"names":["ExternalNavProvider","children","open","setOpen","useState","href","setHref","openExternal","url","cancel","confirm","ExternalNavContext","jsxs","Dialog","v","DialogContent","jsx","DialogTitle","DialogDescription","Button","DialogFooter"],"mappings":";;;;;AAWO,SAASA,EAAoB;AAAA,EAClC,UAAAC;AACF,GAEG;AACD,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAK,GAChC,CAACC,GAAMC,CAAO,IAAIF,EAAwB,IAAI;AAEpD,WAASG,EAAaC,GAAa;AACjC,IAAAF,EAAQE,CAAG,GACXL,EAAQ,EAAI;AAAA,EACd;AAEA,WAASM,IAAS;AAChB,IAAAN,EAAQ,EAAK,GACbG,EAAQ,IAAI;AAAA,EACd;AAEA,WAASI,IAAU;AACjB,IAAIL,KACF,OAAO,KAAKA,GAAM,UAAU,qBAAqB,GAEnDF,EAAQ,EAAK,GACbG,EAAQ,IAAI;AAAA,EACd;AAEA,2BACGK,EAAmB,UAAnB,EAA4B,OAAO,EAAE,cAAAJ,KACpC,UAAA,gBAAAK,EAACC,KAAO,MAAAX,GAAY,cAAc,CAACY,MAAOA,IAAIX,EAAQ,EAAI,IAAIM,KAC3D,UAAA;AAAA,IAAAR;AAAA,sBACAc,GAAA,EACC,UAAA;AAAA,MAAA,gBAAAC,EAACC,KAAY,UAAA,eAAA,CAAY;AAAA,wBACxBC,GAAA,EAAkB,UAAA;AAAA,QAAA;AAAA,QAGjB,gBAAAF;AAAA,UAACG;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAO;AAAA,YAEN,UAAAd,KACC,gBAAAW;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAAX;AAAA,gBACA,QAAO;AAAA,gBACP,KAAI;AAAA,gBACJ,OAAO,EAAE,gBAAgB,OAAA;AAAA,gBAExB,UAAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACH;AAAA,QAAA;AAAA,MAEJ,GACF;AAAA,wBACCe,GAAA,EACC,UAAA;AAAA,QAAA,gBAAAJ,EAACG,GAAA,EAAO,SAAQ,WAAU,SAASV,GAAQ,UAAA,UAE3C;AAAA,QACA,gBAAAO,EAACG,GAAA,EAAO,SAAST,GAAS,UAAA,WAAA,CAAQ;AAAA,MAAA,EAAA,CACpC;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,EAAA,CACF,EAAA,CACF;AAEJ;"}
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from "react";
1
+ import type { ReactNode } from "react";
2
2
  export declare const ImageDialogProvider: ({ children }: {
3
3
  children: ReactNode;
4
4
  }) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"ImageDialogProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ImageDialogProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAef,eAAO,MAAM,mBAAmB,GAAI,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,4CAqOxE,CAAC"}
1
+ {"version":3,"file":"ImageDialogProvider.d.ts","sourceRoot":"","sources":["../../src/providers/ImageDialogProvider.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,eAAO,MAAM,mBAAmB,GAAI,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,4CAqOxE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsxs as p, jsx as h } from "react/jsx-runtime";
2
2
  import { useRef as R, useState as r, useCallback as y, useEffect as V, useMemo as S } from "react";
3
- import { Dialog as B, DialogContent as H, DialogTitle as K, DialogDescription as N } from "../ui/dialog.js";
4
- import { VisuallyHidden as U } from "../node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@typ_7a5b8f185fdc99089c53563f38599d77/node_modules/@radix-ui/react-visually-hidden/dist/index.js";
3
+ import { VisuallyHidden as B } from "../node_modules/.pnpm/@radix-ui_react-visually-hidden@1.2.4_@types_react-dom@19.2.3_@types_react@19.2.7__@types_rea_uxirz2wej36zwyzefmreqngy74/node_modules/@radix-ui/react-visually-hidden/dist/index.js";
4
+ import { Dialog as H, DialogContent as K, DialogTitle as N, DialogDescription as U } from "../ui/dialog.js";
5
5
  import { LightboxViewer as q } from "../ui/lightbox/LightboxViewer.js";
6
6
  import { ImageDialogContext as z } from "../context/ImageDialogContext.js";
7
7
  const _ = ({ children: A }) => {
@@ -100,15 +100,15 @@ const _ = ({ children: A }) => {
100
100
  );
101
101
  return /* @__PURE__ */ p(z.Provider, { value: T, children: [
102
102
  A,
103
- /* @__PURE__ */ h(B, { open: a, onOpenChange: (e) => !e && u(), children: /* @__PURE__ */ p(
104
- H,
103
+ /* @__PURE__ */ h(H, { open: a, onOpenChange: (e) => !e && u(), children: /* @__PURE__ */ p(
104
+ K,
105
105
  {
106
106
  className: "max-w-[90vw] max-h-[95vh] min-w-[90vw] h-[95vh] w-full overflow-hidden flex items-center justify-center bg-background/95 backdrop-blur-sm p-0 border-2 border-border focus:outline-none data-[state=open]:animate-none data-[state=closed]:animate-none",
107
107
  showCloseButton: !1,
108
108
  children: [
109
- /* @__PURE__ */ p(U, { children: [
110
- /* @__PURE__ */ h(K, { children: "Image Viewer" }),
111
- /* @__PURE__ */ h(N, { children: "View images in a lightbox gallery" })
109
+ /* @__PURE__ */ p(B, { children: [
110
+ /* @__PURE__ */ h(N, { children: "Image Viewer" }),
111
+ /* @__PURE__ */ h(U, { children: "View images in a lightbox gallery" })
112
112
  ] }),
113
113
  /* @__PURE__ */ h(
114
114
  q,
@@ -1 +1 @@
1
- {"version":3,"file":"ImageDialogProvider.js","sources":["../../src/providers/ImageDialogProvider.tsx"],"sourcesContent":["import {\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogTitle,\n DialogDescription,\n} from \"../ui/dialog\";\nimport { VisuallyHidden } from \"@radix-ui/react-visually-hidden\";\nimport { LightboxViewer } from \"../ui/lightbox/LightboxViewer\";\nimport {\n ImageDialogContext,\n type GalleryWithTotal,\n} from \"../context/ImageDialogContext\";\nimport type { Gallery, GalleryImage, ImageAction } from \"../types/gallery\";\n\nexport const ImageDialogProvider = ({ children }: { children: ReactNode }) => {\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const [isOpen, setIsOpen] = useState(false);\n const [imageSrc, setImageSrc] = useState<string | null>(null);\n const [galleries, setGalleries] = useState<Gallery[]>([]);\n const [currentGallery, setCurrentGallery] = useState<GalleryWithTotal | null>(\n null\n );\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n const [pendingIndex, setPendingIndex] = useState<number | null>(null);\n const [actions, setActions] = useState<ImageAction[]>([]);\n\n const openImage = useCallback(\n (\n src: string,\n galleryOrMetadata?: any,\n initialIndex?: number,\n customActions: ImageAction[] = [],\n imagePath?: string\n ) => {\n setImageSrc(src);\n\n // Determine if we have a real gallery or just a single image context\n const isGallery =\n galleryOrMetadata && Array.isArray(galleryOrMetadata.images);\n\n const gallery: GalleryWithTotal = isGallery\n ? (galleryOrMetadata as GalleryWithTotal)\n : {\n id: \"single-image\",\n name: \"Image Viewer\",\n thumbnail: src,\n images: [\n {\n src,\n title: imagePath || src,\n metadata:\n galleryOrMetadata && typeof galleryOrMetadata === \"object\"\n ? galleryOrMetadata\n : { id: galleryOrMetadata },\n },\n ],\n totalImages: 1,\n };\n\n setCurrentGallery(gallery);\n\n const idx =\n isGallery && typeof initialIndex === \"number\"\n ? initialIndex\n : gallery.images.findIndex((img) => img.src === src);\n\n setCurrentImageIndex(idx >= 0 ? idx : 0);\n setActions(customActions);\n setIsOpen(true);\n },\n []\n );\n\n const closeImage = useCallback(() => {\n setIsOpen(false);\n setImageSrc(null);\n }, []);\n\n // Unified image change handler for both keyboard and thumbnail navigation\n const onImageChangeUnified = async (index: number) => {\n if (!currentGallery) return;\n const total = currentGallery.totalImages || currentGallery.images.length;\n const loadedCount = currentGallery.images.length;\n\n // 1. Check if index is completely out of bounds (negative or beyond total)\n if (index < 0 || index >= total) {\n return;\n }\n\n // 2. Check if index is within total but not yet loaded\n if (index >= loadedCount) {\n setPendingIndex(index);\n // Trigger fetch more if available\n if (currentGallery.fetchMore) {\n // Calculate how many pages we need to fetch\n // This is a simple heuristic, assuming we fetch in batches\n await currentGallery.fetchMore(\"next\", loadedCount);\n }\n return;\n }\n\n // 3. Index is loaded\n setCurrentImageIndex(index);\n setPendingIndex(null);\n\n // Debounce the heavy update (src & prefetch)\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(() => {\n const img = currentGallery.images[index];\n if (img) {\n setImageSrc(img.src);\n\n // Prefetch next/prev images\n const nextImg = currentGallery.images[index + 1];\n const prevImg = currentGallery.images[index - 1];\n if (nextImg) {\n const i = new Image();\n i.src = nextImg.src;\n }\n if (prevImg) {\n const i = new Image();\n i.src = prevImg.src;\n }\n\n // Check if we need to fetch more (infinite scroll trigger)\n if (\n currentGallery.fetchMore &&\n index >= currentGallery.images.length - 5 &&\n currentGallery.images.length < total\n ) {\n currentGallery.fetchMore(\"next\", currentGallery.images.length);\n }\n }\n }, 50);\n };\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"ArrowRight\") {\n onImageChangeUnified(currentImageIndex + 1);\n } else if (e.key === \"ArrowLeft\") {\n onImageChangeUnified(currentImageIndex - 1);\n } else if (e.key === \"Escape\") {\n closeImage();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, currentImageIndex, currentGallery]);\n\n // Update imageSrc when pending index becomes available\n useEffect(() => {\n if (\n pendingIndex !== null &&\n currentGallery &&\n pendingIndex < currentGallery.images.length\n ) {\n onImageChangeUnified(pendingIndex);\n }\n }, [currentGallery?.images.length, pendingIndex]);\n\n const setGalleryImages = useCallback(\n (\n images: GalleryImage[] | any,\n replace = true,\n newIndex?: number,\n totalImages?: number\n ) => {\n setCurrentGallery((prev) => {\n if (!prev) return null;\n const newImages = replace ? images : [...prev.images, ...images];\n return {\n ...prev,\n images: newImages,\n totalImages: totalImages ?? prev.totalImages,\n };\n });\n\n if (typeof newIndex === \"number\") {\n setCurrentImageIndex(newIndex);\n }\n },\n []\n );\n\n const contextValue = useMemo(\n () => ({\n openImage,\n closeImage,\n setGalleryImages,\n galleries,\n currentGallery,\n currentImageIndex,\n isOpen,\n }),\n [\n openImage,\n closeImage,\n setGalleryImages,\n galleries,\n currentGallery,\n currentImageIndex,\n isOpen,\n ]\n );\n\n return (\n <ImageDialogContext.Provider value={contextValue}>\n {children}\n <Dialog open={isOpen} onOpenChange={(open) => !open && closeImage()}>\n <DialogContent\n className=\"max-w-[90vw] max-h-[95vh] min-w-[90vw] h-[95vh] w-full overflow-hidden flex items-center justify-center bg-background/95 backdrop-blur-sm p-0 border-2 border-border focus:outline-none data-[state=open]:animate-none data-[state=closed]:animate-none\"\n showCloseButton={false}\n >\n <VisuallyHidden>\n <DialogTitle>Image Viewer</DialogTitle>\n <DialogDescription>\n View images in a lightbox gallery\n </DialogDescription>\n </VisuallyHidden>\n <LightboxViewer\n imageSrc={imageSrc}\n gallery={currentGallery}\n imageIndex={currentImageIndex}\n onGalleryChange={() => {}}\n onImageChange={onImageChangeUnified}\n isOpen={isOpen}\n actions={actions}\n isLoading={pendingIndex !== null}\n onClose={closeImage}\n />\n </DialogContent>\n </Dialog>\n </ImageDialogContext.Provider>\n );\n};\n"],"names":["ImageDialogProvider","children","debounceTimerRef","useRef","isOpen","setIsOpen","useState","imageSrc","setImageSrc","galleries","setGalleries","currentGallery","setCurrentGallery","currentImageIndex","setCurrentImageIndex","pendingIndex","setPendingIndex","actions","setActions","openImage","useCallback","src","galleryOrMetadata","initialIndex","customActions","imagePath","isGallery","gallery","idx","img","closeImage","onImageChangeUnified","index","total","loadedCount","nextImg","prevImg","i","useEffect","handleKeyDown","e","setGalleryImages","images","replace","newIndex","totalImages","prev","newImages","contextValue","useMemo","jsxs","ImageDialogContext","jsx","Dialog","open","DialogContent","VisuallyHidden","DialogTitle","DialogDescription","LightboxViewer"],"mappings":";;;;;;AAsBO,MAAMA,IAAsB,CAAC,EAAE,UAAAC,QAAwC;AAC5E,QAAMC,IAAmBC,EAA6C,IAAI,GAEpE,CAACC,GAAQC,CAAS,IAAIC,EAAS,EAAK,GACpC,CAACC,GAAUC,CAAW,IAAIF,EAAwB,IAAI,GACtD,CAACG,GAAWC,CAAY,IAAIJ,EAAoB,CAAA,CAAE,GAClD,CAACK,GAAgBC,CAAiB,IAAIN;AAAA,IAC1C;AAAA,EAAA,GAEI,CAACO,GAAmBC,CAAoB,IAAIR,EAAS,CAAC,GACtD,CAACS,GAAcC,CAAe,IAAIV,EAAwB,IAAI,GAC9D,CAACW,GAASC,CAAU,IAAIZ,EAAwB,CAAA,CAAE,GAElDa,IAAYC;AAAA,IAChB,CACEC,GACAC,GACAC,GACAC,IAA+B,CAAA,GAC/BC,MACG;AACH,MAAAjB,EAAYa,CAAG;AAGf,YAAMK,IACJJ,KAAqB,MAAM,QAAQA,EAAkB,MAAM,GAEvDK,IAA4BD,IAC7BJ,IACD;AAAA,QACE,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAWD;AAAA,QACX,QAAQ;AAAA,UACN;AAAA,YACE,KAAAA;AAAA,YACA,OAAOI,KAAaJ;AAAA,YACpB,UACEC,KAAqB,OAAOA,KAAsB,WAC9CA,IACA,EAAE,IAAIA,EAAA;AAAA,UAAkB;AAAA,QAChC;AAAA,QAEF,aAAa;AAAA,MAAA;AAGnB,MAAAV,EAAkBe,CAAO;AAEzB,YAAMC,IACJF,KAAa,OAAOH,KAAiB,WACjCA,IACAI,EAAQ,OAAO,UAAU,CAACE,MAAQA,EAAI,QAAQR,CAAG;AAEvD,MAAAP,EAAqBc,KAAO,IAAIA,IAAM,CAAC,GACvCV,EAAWM,CAAa,GACxBnB,EAAU,EAAI;AAAA,IAChB;AAAA,IACA,CAAA;AAAA,EAAC,GAGGyB,IAAaV,EAAY,MAAM;AACnC,IAAAf,EAAU,EAAK,GACfG,EAAY,IAAI;AAAA,EAClB,GAAG,CAAA,CAAE,GAGCuB,IAAuB,OAAOC,MAAkB;AACpD,QAAI,CAACrB,EAAgB;AACrB,UAAMsB,IAAQtB,EAAe,eAAeA,EAAe,OAAO,QAC5DuB,IAAcvB,EAAe,OAAO;AAG1C,QAAI,EAAAqB,IAAQ,KAAKA,KAASC,IAK1B;AAAA,UAAID,KAASE,GAAa;AACxB,QAAAlB,EAAgBgB,CAAK,GAEjBrB,EAAe,aAGjB,MAAMA,EAAe,UAAU,QAAQuB,CAAW;AAEpD;AAAA,MACF;AAGA,MAAApB,EAAqBkB,CAAK,GAC1BhB,EAAgB,IAAI,GAGhBd,EAAiB,WACnB,aAAaA,EAAiB,OAAO,GAGvCA,EAAiB,UAAU,WAAW,MAAM;AAC1C,cAAM2B,IAAMlB,EAAe,OAAOqB,CAAK;AACvC,YAAIH,GAAK;AACP,UAAArB,EAAYqB,EAAI,GAAG;AAGnB,gBAAMM,IAAUxB,EAAe,OAAOqB,IAAQ,CAAC,GACzCI,IAAUzB,EAAe,OAAOqB,IAAQ,CAAC;AAC/C,cAAIG,GAAS;AACX,kBAAME,IAAI,IAAI,MAAA;AACd,YAAAA,EAAE,MAAMF,EAAQ;AAAA,UAClB;AACA,cAAIC,GAAS;AACX,kBAAMC,IAAI,IAAI,MAAA;AACd,YAAAA,EAAE,MAAMD,EAAQ;AAAA,UAClB;AAGA,UACEzB,EAAe,aACfqB,KAASrB,EAAe,OAAO,SAAS,KACxCA,EAAe,OAAO,SAASsB,KAE/BtB,EAAe,UAAU,QAAQA,EAAe,OAAO,MAAM;AAAA,QAEjE;AAAA,MACF,GAAG,EAAE;AAAA;AAAA,EACP;AAGA,EAAA2B,EAAU,MAAM;AACd,QAAI,CAAClC,EAAQ;AAEb,UAAMmC,IAAgB,CAACC,MAAqB;AAC1C,MAAIA,EAAE,QAAQ,eACZT,EAAqBlB,IAAoB,CAAC,IACjC2B,EAAE,QAAQ,cACnBT,EAAqBlB,IAAoB,CAAC,IACjC2B,EAAE,QAAQ,YACnBV,EAAA;AAAA,IAEJ;AAEA,kBAAO,iBAAiB,WAAWS,CAAa,GACzC,MAAM,OAAO,oBAAoB,WAAWA,CAAa;AAAA,EAClE,GAAG,CAACnC,GAAQS,GAAmBF,CAAc,CAAC,GAG9C2B,EAAU,MAAM;AACd,IACEvB,MAAiB,QACjBJ,KACAI,IAAeJ,EAAe,OAAO,UAErCoB,EAAqBhB,CAAY;AAAA,EAErC,GAAG,CAACJ,GAAgB,OAAO,QAAQI,CAAY,CAAC;AAEhD,QAAM0B,IAAmBrB;AAAA,IACvB,CACEsB,GACAC,IAAU,IACVC,GACAC,MACG;AACH,MAAAjC,EAAkB,CAACkC,MAAS;AAC1B,YAAI,CAACA,EAAM,QAAO;AAClB,cAAMC,IAAYJ,IAAUD,IAAS,CAAC,GAAGI,EAAK,QAAQ,GAAGJ,CAAM;AAC/D,eAAO;AAAA,UACL,GAAGI;AAAA,UACH,QAAQC;AAAA,UACR,aAAaF,KAAeC,EAAK;AAAA,QAAA;AAAA,MAErC,CAAC,GAEG,OAAOF,KAAa,YACtB9B,EAAqB8B,CAAQ;AAAA,IAEjC;AAAA,IACA,CAAA;AAAA,EAAC,GAGGI,IAAeC;AAAA,IACnB,OAAO;AAAA,MACL,WAAA9B;AAAA,MACA,YAAAW;AAAA,MACA,kBAAAW;AAAA,MACA,WAAAhC;AAAA,MACA,gBAAAE;AAAA,MACA,mBAAAE;AAAA,MACA,QAAAT;AAAA,IAAA;AAAA,IAEF;AAAA,MACEe;AAAA,MACAW;AAAA,MACAW;AAAA,MACAhC;AAAA,MACAE;AAAA,MACAE;AAAA,MACAT;AAAA,IAAA;AAAA,EACF;AAGF,SACE,gBAAA8C,EAACC,EAAmB,UAAnB,EAA4B,OAAOH,GACjC,UAAA;AAAA,IAAA/C;AAAA,IACD,gBAAAmD,EAACC,GAAA,EAAO,MAAMjD,GAAQ,cAAc,CAACkD,MAAS,CAACA,KAAQxB,EAAA,GACrD,UAAA,gBAAAoB;AAAA,MAACK;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,iBAAiB;AAAA,QAEjB,UAAA;AAAA,UAAA,gBAAAL,EAACM,GAAA,EACC,UAAA;AAAA,YAAA,gBAAAJ,EAACK,KAAY,UAAA,eAAA,CAAY;AAAA,YACzB,gBAAAL,EAACM,KAAkB,UAAA,oCAAA,CAEnB;AAAA,UAAA,GACF;AAAA,UACA,gBAAAN;AAAA,YAACO;AAAA,YAAA;AAAA,cACC,UAAApD;AAAA,cACA,SAASI;AAAA,cACT,YAAYE;AAAA,cACZ,iBAAiB,MAAM;AAAA,cAAC;AAAA,cACxB,eAAekB;AAAA,cACf,QAAA3B;AAAA,cACA,SAAAa;AAAA,cACA,WAAWF,MAAiB;AAAA,cAC5B,SAASe;AAAA,YAAA;AAAA,UAAA;AAAA,QACX;AAAA,MAAA;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"ImageDialogProvider.js","sources":["../../src/providers/ImageDialogProvider.tsx"],"sourcesContent":["import {\n \n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState\n} from \"react\";\nimport { VisuallyHidden } from \"@radix-ui/react-visually-hidden\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogTitle,\n} from \"../ui/dialog\";\nimport { LightboxViewer } from \"../ui/lightbox/LightboxViewer\";\nimport {\n \n ImageDialogContext\n} from \"../context/ImageDialogContext\";\nimport type {GalleryWithTotal} from \"../context/ImageDialogContext\";\nimport type {ReactNode} from \"react\";\nimport type { Gallery, GalleryImage, ImageAction } from \"../types/gallery\";\n\nexport const ImageDialogProvider = ({ children }: { children: ReactNode }) => {\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const [isOpen, setIsOpen] = useState(false);\n const [imageSrc, setImageSrc] = useState<string | null>(null);\n const [galleries, setGalleries] = useState<Array<Gallery>>([]);\n const [currentGallery, setCurrentGallery] = useState<GalleryWithTotal | null>(\n null\n );\n const [currentImageIndex, setCurrentImageIndex] = useState(0);\n const [pendingIndex, setPendingIndex] = useState<number | null>(null);\n const [actions, setActions] = useState<Array<ImageAction>>([]);\n\n const openImage = useCallback(\n (\n src: string,\n galleryOrMetadata?: any,\n initialIndex?: number,\n customActions: Array<ImageAction> = [],\n imagePath?: string\n ) => {\n setImageSrc(src);\n\n // Determine if we have a real gallery or just a single image context\n const isGallery =\n galleryOrMetadata && Array.isArray(galleryOrMetadata.images);\n\n const gallery: GalleryWithTotal = isGallery\n ? (galleryOrMetadata as GalleryWithTotal)\n : {\n id: \"single-image\",\n name: \"Image Viewer\",\n thumbnail: src,\n images: [\n {\n src,\n title: imagePath || src,\n metadata:\n galleryOrMetadata && typeof galleryOrMetadata === \"object\"\n ? galleryOrMetadata\n : { id: galleryOrMetadata },\n },\n ],\n totalImages: 1,\n };\n\n setCurrentGallery(gallery);\n\n const idx =\n isGallery && typeof initialIndex === \"number\"\n ? initialIndex\n : gallery.images.findIndex((img) => img.src === src);\n\n setCurrentImageIndex(idx >= 0 ? idx : 0);\n setActions(customActions);\n setIsOpen(true);\n },\n []\n );\n\n const closeImage = useCallback(() => {\n setIsOpen(false);\n setImageSrc(null);\n }, []);\n\n // Unified image change handler for both keyboard and thumbnail navigation\n const onImageChangeUnified = async (index: number) => {\n if (!currentGallery) return;\n const total = currentGallery.totalImages || currentGallery.images.length;\n const loadedCount = currentGallery.images.length;\n\n // 1. Check if index is completely out of bounds (negative or beyond total)\n if (index < 0 || index >= total) {\n return;\n }\n\n // 2. Check if index is within total but not yet loaded\n if (index >= loadedCount) {\n setPendingIndex(index);\n // Trigger fetch more if available\n if (currentGallery.fetchMore) {\n // Calculate how many pages we need to fetch\n // This is a simple heuristic, assuming we fetch in batches\n await currentGallery.fetchMore(\"next\", loadedCount);\n }\n return;\n }\n\n // 3. Index is loaded\n setCurrentImageIndex(index);\n setPendingIndex(null);\n\n // Debounce the heavy update (src & prefetch)\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(() => {\n const img = currentGallery.images[index];\n if (img) {\n setImageSrc(img.src);\n\n // Prefetch next/prev images\n const nextImg = currentGallery.images[index + 1];\n const prevImg = currentGallery.images[index - 1];\n if (nextImg) {\n const i = new Image();\n i.src = nextImg.src;\n }\n if (prevImg) {\n const i = new Image();\n i.src = prevImg.src;\n }\n\n // Check if we need to fetch more (infinite scroll trigger)\n if (\n currentGallery.fetchMore &&\n index >= currentGallery.images.length - 5 &&\n currentGallery.images.length < total\n ) {\n currentGallery.fetchMore(\"next\", currentGallery.images.length);\n }\n }\n }, 50);\n };\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"ArrowRight\") {\n onImageChangeUnified(currentImageIndex + 1);\n } else if (e.key === \"ArrowLeft\") {\n onImageChangeUnified(currentImageIndex - 1);\n } else if (e.key === \"Escape\") {\n closeImage();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, currentImageIndex, currentGallery]);\n\n // Update imageSrc when pending index becomes available\n useEffect(() => {\n if (\n pendingIndex !== null &&\n currentGallery &&\n pendingIndex < currentGallery.images.length\n ) {\n onImageChangeUnified(pendingIndex);\n }\n }, [currentGallery?.images.length, pendingIndex]);\n\n const setGalleryImages = useCallback(\n (\n images: Array<GalleryImage> | any,\n replace = true,\n newIndex?: number,\n totalImages?: number\n ) => {\n setCurrentGallery((prev) => {\n if (!prev) return null;\n const newImages = replace ? images : [...prev.images, ...images];\n return {\n ...prev,\n images: newImages,\n totalImages: totalImages ?? prev.totalImages,\n };\n });\n\n if (typeof newIndex === \"number\") {\n setCurrentImageIndex(newIndex);\n }\n },\n []\n );\n\n const contextValue = useMemo(\n () => ({\n openImage,\n closeImage,\n setGalleryImages,\n galleries,\n currentGallery,\n currentImageIndex,\n isOpen,\n }),\n [\n openImage,\n closeImage,\n setGalleryImages,\n galleries,\n currentGallery,\n currentImageIndex,\n isOpen,\n ]\n );\n\n return (\n <ImageDialogContext.Provider value={contextValue}>\n {children}\n <Dialog open={isOpen} onOpenChange={(open) => !open && closeImage()}>\n <DialogContent\n className=\"max-w-[90vw] max-h-[95vh] min-w-[90vw] h-[95vh] w-full overflow-hidden flex items-center justify-center bg-background/95 backdrop-blur-sm p-0 border-2 border-border focus:outline-none data-[state=open]:animate-none data-[state=closed]:animate-none\"\n showCloseButton={false}\n >\n <VisuallyHidden>\n <DialogTitle>Image Viewer</DialogTitle>\n <DialogDescription>\n View images in a lightbox gallery\n </DialogDescription>\n </VisuallyHidden>\n <LightboxViewer\n imageSrc={imageSrc}\n gallery={currentGallery}\n imageIndex={currentImageIndex}\n onGalleryChange={() => {}}\n onImageChange={onImageChangeUnified}\n isOpen={isOpen}\n actions={actions}\n isLoading={pendingIndex !== null}\n onClose={closeImage}\n />\n </DialogContent>\n </Dialog>\n </ImageDialogContext.Provider>\n );\n};\n"],"names":["ImageDialogProvider","children","debounceTimerRef","useRef","isOpen","setIsOpen","useState","imageSrc","setImageSrc","galleries","setGalleries","currentGallery","setCurrentGallery","currentImageIndex","setCurrentImageIndex","pendingIndex","setPendingIndex","actions","setActions","openImage","useCallback","src","galleryOrMetadata","initialIndex","customActions","imagePath","isGallery","gallery","idx","img","closeImage","onImageChangeUnified","index","total","loadedCount","nextImg","prevImg","i","useEffect","handleKeyDown","e","setGalleryImages","images","replace","newIndex","totalImages","prev","newImages","contextValue","useMemo","jsxs","ImageDialogContext","jsx","Dialog","open","DialogContent","VisuallyHidden","DialogTitle","DialogDescription","LightboxViewer"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from "react";
1
+ import type { ReactNode } from "react";
2
2
  export interface GalleryImage {
3
3
  src: string;
4
4
  thumbnail?: string;
@@ -11,13 +11,13 @@ export interface Gallery {
11
11
  name: string;
12
12
  description?: string;
13
13
  thumbnail: string;
14
- images: GalleryImage[];
14
+ images: Array<GalleryImage>;
15
15
  customHtml?: string;
16
16
  totalImages?: number;
17
17
  fetchMore?: (direction: "next" | "prev", offset: number) => Promise<void>;
18
18
  }
19
19
  export interface GalleriesData {
20
- galleries: Gallery[];
20
+ galleries: Array<Gallery>;
21
21
  }
22
22
  export interface ImageAction {
23
23
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"gallery.d.ts","sourceRoot":"","sources":["../../src/types/gallery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;CAC9C"}
1
+ {"version":3,"file":"gallery.d.ts","sourceRoot":"","sources":["../../src/types/gallery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;CAC9C"}
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { type VariantProps } from "class-variance-authority";
2
+ import type { VariantProps } from "class-variance-authority";
3
3
  declare const badgeVariants: (props?: {
4
4
  variant?: "default" | "outline" | "secondary" | "destructive";
5
5
  } & import("class-variance-authority/types").ClassProp) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/ui/badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,aAAa;;iEAmBlB,CAAC;AAEF,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,OAAO,EACP,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAC7B,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,2CAU3D;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/ui/badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAG3D,QAAA,MAAM,aAAa;;iEAmBlB,CAAC;AAEF,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,OAAO,EACP,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAC7B,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,2CAU3D;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"badge.js","sources":["../../src/ui/badge.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../lib/utils\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center justify-center border px-2 py-1 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden\",\n {\n variants: {\n variant: {\n default:\n \"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction Badge({\n className,\n variant,\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n data-slot=\"badge\"\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nexport { Badge, badgeVariants };\n"],"names":["badgeVariants","cva","Badge","className","variant","asChild","props","jsx","Slot","cn"],"mappings":";;;;;AAMA,MAAMA,IAAgBC;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,WACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;AAEA,SAASC,EAAM;AAAA,EACb,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,GAAGC;AACL,GAC8D;AAG5D,SACE,gBAAAC;AAAA,IAHWF,IAAUG,IAAO;AAAA,IAG3B;AAAA,MACC,aAAU;AAAA,MACV,WAAWC,EAAGT,EAAc,EAAE,SAAAI,EAAA,CAAS,GAAGD,CAAS;AAAA,MAClD,GAAGG;AAAA,IAAA;AAAA,EAAA;AAGV;"}
1
+ {"version":3,"file":"badge.js","sources":["../../src/ui/badge.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva } from \"class-variance-authority\";\nimport { cn } from \"../lib/utils\";\nimport type {VariantProps} from \"class-variance-authority\";\n\n\nconst badgeVariants = cva(\n \"inline-flex items-center justify-center border px-2 py-1 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden\",\n {\n variants: {\n variant: {\n default:\n \"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction Badge({\n className,\n variant,\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n data-slot=\"badge\"\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nexport { Badge, badgeVariants };\n"],"names":["badgeVariants","cva","Badge","className","variant","asChild","props","jsx","Slot","cn"],"mappings":";;;;;AAOA,MAAMA,IAAgBC;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,WACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;AAEA,SAASC,EAAM;AAAA,EACb,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,GAAGC;AACL,GAC8D;AAG5D,SACE,gBAAAC;AAAA,IAHWF,IAAUG,IAAO;AAAA,IAG3B;AAAA,MACC,aAAU;AAAA,MACV,WAAWC,EAAGT,EAAc,EAAE,SAAAI,EAAA,CAAS,GAAGD,CAAS;AAAA,MAClD,GAAGG;AAAA,IAAA;AAAA,EAAA;AAGV;"}
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { type VariantProps } from "class-variance-authority";
2
+ import type { VariantProps } from "class-variance-authority";
3
3
  declare const buttonVariants: (props?: {
4
4
  variant?: "link" | "default" | "outline" | "secondary" | "ghost" | "destructive";
5
5
  size?: "default" | "sm" | "xs" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg";
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/ui/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKlE,QAAA,MAAM,cAAc;;;iEAiCnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAYF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../src/ui/button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAE3D,QAAA,MAAM,cAAc;;;iEAiCnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAmB,EACnB,IAAgB,EAChB,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,2CAYF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","sources":["../../src/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nimport { cn } from \"../lib/utils\";\n\nconst buttonVariants = cva(\n \"cursor-pointer focus-visible:border-ring ring-1 ring-foreground/20 hover:ring-foreground/40 focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-none border border-transparent bg-clip-padding text-xs font-medium focus-visible:ring-1 aria-invalid:ring-1 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground\",\n destructive:\n \"bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-8\",\n \"icon-xs\": \"size-6 rounded-none [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-7 rounded-none\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n"],"names":["buttonVariants","cva","Button","className","variant","size","asChild","props","jsx","Slot","cn"],"mappings":";;;;;AAMA,MAAMA,IAAiBC;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SACE;AAAA,QACF,WACE;AAAA,QACF,OACE;AAAA,QACF,aACE;AAAA,QACF,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SACE;AAAA,QACF,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAEA,SAASC,EAAO;AAAA,EACd,WAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,GAAGC;AACL,GAGK;AAGH,SACE,gBAAAC;AAAA,IAHWF,IAAUG,IAAO;AAAA,IAG3B;AAAA,MACC,aAAU;AAAA,MACV,gBAAcL;AAAA,MACd,aAAWC;AAAA,MACX,WAAWK,EAAGV,EAAe,EAAE,SAAAI,GAAS,MAAAC,GAAM,WAAAF,EAAA,CAAW,CAAC;AAAA,MACzD,GAAGI;AAAA,IAAA;AAAA,EAAA;AAGV;"}
1
+ {"version":3,"file":"button.js","sources":["../../src/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nimport { cn } from \"../lib/utils\";\nimport type {VariantProps} from \"class-variance-authority\";\n\nconst buttonVariants = cva(\n \"cursor-pointer focus-visible:border-ring ring-1 ring-foreground/20 hover:ring-foreground/40 focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-none border border-transparent bg-clip-padding text-xs font-medium focus-visible:ring-1 aria-invalid:ring-1 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground\",\n destructive:\n \"bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-8\",\n \"icon-xs\": \"size-6 rounded-none [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-7 rounded-none\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n"],"names":["buttonVariants","cva","Button","className","variant","size","asChild","props","jsx","Slot","cn"],"mappings":";;;;;AAOA,MAAMA,IAAiBC;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SACE;AAAA,QACF,WACE;AAAA,QACF,OACE;AAAA,QACF,aACE;AAAA,QACF,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SACE;AAAA,QACF,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAEA,SAASC,EAAO;AAAA,EACd,WAAAC;AAAA,EACA,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,GAAGC;AACL,GAGK;AAGH,SACE,gBAAAC;AAAA,IAHWF,IAAUG,IAAO;AAAA,IAG3B;AAAA,MACC,aAAU;AAAA,MACV,gBAAcL;AAAA,MACd,aAAWC;AAAA,MACX,WAAWK,EAAGV,EAAe,EAAE,SAAAI,GAAS,MAAAC,GAAM,WAAAF,EAAA,CAAW,CAAC;AAAA,MACzD,GAAGI;AAAA,IAAA;AAAA,EAAA;AAGV;"}
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
- import { type VariantProps } from "class-variance-authority";
3
2
  import { Button } from "./button";
3
+ import type { VariantProps } from "class-variance-authority";
4
4
  declare function InputGroup({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
5
5
  declare const inputGroupAddonVariants: (props?: {
6
6
  align?: "inline-start" | "inline-end" | "block-start" | "block-end";
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.d.ts","sourceRoot":"","sources":["../../src/ui/input-group.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIlC,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CA0BvE;AAED,QAAA,MAAM,uBAAuB;;iEAmB5B,CAAC;AAEF,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,KAAsB,EACtB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,uBAAuB,CAAC,2CAgB5E;AAED,QAAA,MAAM,wBAAwB;;iEAgB7B,CAAC;AAEF,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,IAAe,EACf,OAAiB,EACjB,IAAW,EACX,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,MAAM,CAAC,GAClD,YAAY,CAAC,OAAO,wBAAwB,CAAC,2CAU9C;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,2CAU5E;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,2CAW/B;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,2CAWlC;AAED,OAAO,EACL,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,CAAC"}
1
+ {"version":3,"file":"input-group.d.ts","sourceRoot":"","sources":["../../src/ui/input-group.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0BAA0B,CAAC;AAE3D,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CA0BvE;AAED,QAAA,MAAM,uBAAuB;;iEAmB5B,CAAC;AAEF,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,KAAsB,EACtB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,uBAAuB,CAAC,2CAgB5E;AAED,QAAA,MAAM,wBAAwB;;iEAgB7B,CAAC;AAEF,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,IAAe,EACf,OAAiB,EACjB,IAAW,EACX,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,MAAM,CAAC,GAClD,YAAY,CAAC,OAAO,wBAAwB,CAAC,2CAU9C;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,2CAU5E;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,2CAW/B;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,2CAWlC;AAED,OAAO,EACL,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"input-group.js","sources":["../../src/ui/input-group.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\nimport { Textarea } from \"./textarea\";\n\nfunction InputGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n \"group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none\",\n \"h-9 min-w-0 has-[>textarea]:h-auto\",\n\n // Variants based on alignment.\n \"has-[>[data-align=inline-start]]:[&>input]:pl-2\",\n \"has-[>[data-align=inline-end]]:[&>input]:pr-2\",\n \"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3\",\n \"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3\",\n\n // Focus state.\n \"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]\",\n\n // Error state.\n \"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40\",\n\n className\n )}\n {...props}\n />\n );\n}\n\nconst inputGroupAddonVariants = cva(\n \"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n \"inline-end\":\n \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n \"block-start\":\n \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n \"block-end\":\n \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n }\n);\n\nfunction InputGroupAddon({\n className,\n align = \"inline-start\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest(\"button\")) {\n return;\n }\n e.currentTarget.parentElement?.querySelector(\"input\")?.focus();\n }}\n {...props}\n />\n );\n}\n\nconst inputGroupButtonVariants = cva(\n \"text-sm shadow-none flex gap-2 items-center\",\n {\n variants: {\n size: {\n xs: \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n sm: \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n \"icon-xs\":\n \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n },\n },\n defaultVariants: {\n size: \"xs\",\n },\n }\n);\n\nfunction InputGroupButton({\n className,\n type = \"button\",\n variant = \"ghost\",\n size = \"xs\",\n ...props\n}: Omit<React.ComponentProps<typeof Button>, \"size\"> &\n VariantProps<typeof inputGroupButtonVariants>) {\n return (\n <Button\n type={type}\n data-size={size}\n variant={variant}\n className={cn(inputGroupButtonVariants({ size }), className)}\n {...props}\n />\n );\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n className={cn(\n \"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupInput({\n className,\n ...props\n}: React.ComponentProps<\"input\">) {\n return (\n <Input\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupTextarea({\n className,\n ...props\n}: React.ComponentProps<\"textarea\">) {\n return (\n <Textarea\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupText,\n InputGroupInput,\n InputGroupTextarea,\n};\n"],"names":["InputGroup","className","props","jsx","cn","inputGroupAddonVariants","cva","InputGroupAddon","align","e","inputGroupButtonVariants","InputGroupButton","type","variant","size","Button","InputGroupText","InputGroupInput","Input","InputGroupTextarea","Textarea"],"mappings":";;;;;;;AAQA,SAASA,EAAW,EAAE,WAAAC,GAAW,GAAGC,KAAsC;AACxE,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,WAAWC;AAAA,QACT;AAAA,QACA;AAAA;AAAA,QAGA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QAGA;AAAA;AAAA,QAGA;AAAA,QAEAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,MAAMG,IAA0BC;AAAA,EAC9B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,gBACE;AAAA,QACF,cACE;AAAA,QACF,eACE;AAAA,QACF,aACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB;AAAA,MACf,OAAO;AAAA,IAAA;AAAA,EACT;AAEJ;AAEA,SAASC,EAAgB;AAAA,EACvB,WAAAN;AAAA,EACA,OAAAO,IAAQ;AAAA,EACR,GAAGN;AACL,GAA+E;AAC7E,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAYK;AAAA,MACZ,WAAWJ,EAAGC,EAAwB,EAAE,OAAAG,EAAA,CAAO,GAAGP,CAAS;AAAA,MAC3D,SAAS,CAACQ,MAAM;AACd,QAAKA,EAAE,OAAuB,QAAQ,QAAQ,KAG9CA,EAAE,cAAc,eAAe,cAAc,OAAO,GAAG,MAAA;AAAA,MACzD;AAAA,MACC,GAAGP;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,MAAMQ,IAA2BJ;AAAA,EAC/B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,WACE;AAAA,QACF,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAEA,SAASK,EAAiB;AAAA,EACxB,WAAAV;AAAA,EACA,MAAAW,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,GAAGZ;AACL,GACiD;AAC/C,SACE,gBAAAC;AAAA,IAACY;AAAA,IAAA;AAAA,MACC,MAAAH;AAAA,MACA,aAAWE;AAAA,MACX,SAAAD;AAAA,MACA,WAAWT,EAAGM,EAAyB,EAAE,MAAAI,EAAA,CAAM,GAAGb,CAAS;AAAA,MAC1D,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASc,EAAe,EAAE,WAAAf,GAAW,GAAGC,KAAuC;AAC7E,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASe,EAAgB;AAAA,EACvB,WAAAhB;AAAA,EACA,GAAGC;AACL,GAAkC;AAChC,SACE,gBAAAC;AAAA,IAACe;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWd;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASiB,EAAmB;AAAA,EAC1B,WAAAlB;AAAA,EACA,GAAGC;AACL,GAAqC;AACnC,SACE,gBAAAC;AAAA,IAACiB;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWhB;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;"}
1
+ {"version":3,"file":"input-group.js","sources":["../../src/ui/input-group.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva } from \"class-variance-authority\";\n\nimport { cn } from \"../lib/utils\";\nimport { Button } from \"./button\";\nimport { Input } from \"./input\";\nimport { Textarea } from \"./textarea\";\nimport type {VariantProps} from \"class-variance-authority\";\n\nfunction InputGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n \"group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none\",\n \"h-9 min-w-0 has-[>textarea]:h-auto\",\n\n // Variants based on alignment.\n \"has-[>[data-align=inline-start]]:[&>input]:pl-2\",\n \"has-[>[data-align=inline-end]]:[&>input]:pr-2\",\n \"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3\",\n \"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3\",\n\n // Focus state.\n \"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]\",\n\n // Error state.\n \"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40\",\n\n className\n )}\n {...props}\n />\n );\n}\n\nconst inputGroupAddonVariants = cva(\n \"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n \"inline-end\":\n \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n \"block-start\":\n \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n \"block-end\":\n \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n }\n);\n\nfunction InputGroupAddon({\n className,\n align = \"inline-start\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest(\"button\")) {\n return;\n }\n e.currentTarget.parentElement?.querySelector(\"input\")?.focus();\n }}\n {...props}\n />\n );\n}\n\nconst inputGroupButtonVariants = cva(\n \"text-sm shadow-none flex gap-2 items-center\",\n {\n variants: {\n size: {\n xs: \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n sm: \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n \"icon-xs\":\n \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n },\n },\n defaultVariants: {\n size: \"xs\",\n },\n }\n);\n\nfunction InputGroupButton({\n className,\n type = \"button\",\n variant = \"ghost\",\n size = \"xs\",\n ...props\n}: Omit<React.ComponentProps<typeof Button>, \"size\"> &\n VariantProps<typeof inputGroupButtonVariants>) {\n return (\n <Button\n type={type}\n data-size={size}\n variant={variant}\n className={cn(inputGroupButtonVariants({ size }), className)}\n {...props}\n />\n );\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n className={cn(\n \"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupInput({\n className,\n ...props\n}: React.ComponentProps<\"input\">) {\n return (\n <Input\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupTextarea({\n className,\n ...props\n}: React.ComponentProps<\"textarea\">) {\n return (\n <Textarea\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupText,\n InputGroupInput,\n InputGroupTextarea,\n};\n"],"names":["InputGroup","className","props","jsx","cn","inputGroupAddonVariants","cva","InputGroupAddon","align","e","inputGroupButtonVariants","InputGroupButton","type","variant","size","Button","InputGroupText","InputGroupInput","Input","InputGroupTextarea","Textarea"],"mappings":";;;;;;;AASA,SAASA,EAAW,EAAE,WAAAC,GAAW,GAAGC,KAAsC;AACxE,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,WAAWC;AAAA,QACT;AAAA,QACA;AAAA;AAAA,QAGA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,QAGA;AAAA;AAAA,QAGA;AAAA,QAEAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,MAAMG,IAA0BC;AAAA,EAC9B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,OAAO;AAAA,QACL,gBACE;AAAA,QACF,cACE;AAAA,QACF,eACE;AAAA,QACF,aACE;AAAA,MAAA;AAAA,IACJ;AAAA,IAEF,iBAAiB;AAAA,MACf,OAAO;AAAA,IAAA;AAAA,EACT;AAEJ;AAEA,SAASC,EAAgB;AAAA,EACvB,WAAAN;AAAA,EACA,OAAAO,IAAQ;AAAA,EACR,GAAGN;AACL,GAA+E;AAC7E,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,cAAYK;AAAA,MACZ,WAAWJ,EAAGC,EAAwB,EAAE,OAAAG,EAAA,CAAO,GAAGP,CAAS;AAAA,MAC3D,SAAS,CAACQ,MAAM;AACd,QAAKA,EAAE,OAAuB,QAAQ,QAAQ,KAG9CA,EAAE,cAAc,eAAe,cAAc,OAAO,GAAG,MAAA;AAAA,MACzD;AAAA,MACC,GAAGP;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,MAAMQ,IAA2BJ;AAAA,EAC/B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,WACE;AAAA,QACF,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAEA,SAASK,EAAiB;AAAA,EACxB,WAAAV;AAAA,EACA,MAAAW,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,GAAGZ;AACL,GACiD;AAC/C,SACE,gBAAAC;AAAA,IAACY;AAAA,IAAA;AAAA,MACC,MAAAH;AAAA,MACA,aAAWE;AAAA,MACX,SAAAD;AAAA,MACA,WAAWT,EAAGM,EAAyB,EAAE,MAAAI,EAAA,CAAM,GAAGb,CAAS;AAAA,MAC1D,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASc,EAAe,EAAE,WAAAf,GAAW,GAAGC,KAAuC;AAC7E,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASe,EAAgB;AAAA,EACvB,WAAAhB;AAAA,EACA,GAAGC;AACL,GAAkC;AAChC,SACE,gBAAAC;AAAA,IAACe;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWd;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;AAEA,SAASiB,EAAmB;AAAA,EAC1B,WAAAlB;AAAA,EACA,GAAGC;AACL,GAAqC;AACnC,SACE,gBAAAC;AAAA,IAACiB;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAWhB;AAAA,QACT;AAAA,QACAH;AAAA,MAAA;AAAA,MAED,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;"}
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryPicker.js","sources":["../../../src/ui/lightbox/GalleryPicker.tsx"],"sourcesContent":["import { ChevronDown, ChevronUp } from \"lucide-react\";\nimport { useState } from \"react\";\nimport type { Gallery } from \"../../types/gallery\";\nimport { useImageDialog } from \"../../context/ImageDialogContext\";\n\ninterface GalleryPickerProps {\n currentGalleryId?: string;\n onGalleryChange: (galleryId: string) => void;\n}\n\nexport const GalleryPicker = ({\n currentGalleryId,\n onGalleryChange,\n}: GalleryPickerProps) => {\n const [isOpen, setIsOpen] = useState(false);\n const { galleries } = useImageDialog();\n\n const currentGallery = galleries.find((g) => g.id === currentGalleryId);\n\n return (\n <div className=\"relative w-full\">\n {/* Toggle Button */}\n <div\n onClick={() => setIsOpen(!isOpen)}\n className=\"cursor-pointer w-full flex items-center justify-between px-4 py-3 bg-background/40 border-b border-border hover:bg-secondary/20 transition-colors select-none\"\n >\n <div className=\"flex items-center gap-3\">\n {currentGallery && (\n <>\n <img\n src={currentGallery.thumbnail}\n alt={currentGallery.name}\n className=\"w-8 h-8 object-cover rounded\"\n />\n <div className=\"text-left\">\n <div className=\"font-medium text-sm\">{currentGallery.name}</div>\n {currentGallery.description && (\n <div className=\"text-xs text-muted-foreground\">\n {currentGallery.description}\n </div>\n )}\n </div>\n </>\n )}\n </div>\n {isOpen ? (\n <ChevronUp className=\"w-4 h-4 text-muted-foreground\" />\n ) : (\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n )}\n </div>\n\n {/* Gallery Grid */}\n {isOpen && (\n <div className=\"overflow-hidden bg-background/95 backdrop-blur-sm border-b border-border\">\n <div className=\"flex flex-wrap gap-2 p-4 max-h-64 overflow-y-auto\">\n {galleries.map((gallery: Gallery) => (\n <button\n key={gallery.id}\n onClick={() => {\n onGalleryChange(gallery.id);\n setIsOpen(false);\n }}\n className={`cursor-pointer relative w-20 h-20 rounded-lg overflow-hidden border-2 transition-all hover:scale-105 shrink-0 ${\n gallery.id === currentGalleryId\n ? \"border-primary ring-2 ring-primary/50\"\n : \"border-border hover:border-primary/50\"\n }`}\n >\n <img\n src={gallery.thumbnail}\n alt={gallery.name}\n className=\"w-full h-full object-cover\"\n />\n <div className=\"absolute inset-0 bg-linear-to-t from-background via-background/60 to-transparent flex items-end p-1\">\n <span className=\"text-xs font-medium truncate w-full text-center leading-tight\">\n {gallery.name}\n </span>\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"names":["GalleryPicker","currentGalleryId","onGalleryChange","isOpen","setIsOpen","useState","galleries","useImageDialog","currentGallery","g","jsxs","jsx","Fragment","ChevronUp","ChevronDown","gallery"],"mappings":";;;;;AAUO,MAAMA,IAAgB,CAAC;AAAA,EAC5B,kBAAAC;AAAA,EACA,iBAAAC;AACF,MAA0B;AACxB,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAAS,EAAK,GACpC,EAAE,WAAAC,EAAA,IAAcC,EAAA,GAEhBC,IAAiBF,EAAU,KAAK,CAACG,MAAMA,EAAE,OAAOR,CAAgB;AAEtE,SACE,gBAAAS,EAAC,OAAA,EAAI,WAAU,mBAEb,UAAA;AAAA,IAAA,gBAAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS,MAAMN,EAAU,CAACD,CAAM;AAAA,QAChC,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,2BACZ,UAAAH,KACC,gBAAAE,EAAAE,GAAA,EACE,UAAA;AAAA,YAAA,gBAAAD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAKH,EAAe;AAAA,gBACpB,KAAKA,EAAe;AAAA,gBACpB,WAAU;AAAA,cAAA;AAAA,YAAA;AAAA,YAEZ,gBAAAE,EAAC,OAAA,EAAI,WAAU,aACb,UAAA;AAAA,cAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,uBAAuB,UAAAH,EAAe,MAAK;AAAA,cACzDA,EAAe,eACd,gBAAAG,EAAC,SAAI,WAAU,iCACZ,YAAe,YAAA,CAClB;AAAA,YAAA,EAAA,CAEJ;AAAA,UAAA,EAAA,CACF,EAAA,CAEJ;AAAA,UACCR,sBACEU,GAAA,EAAU,WAAU,iCAAgC,IAErD,gBAAAF,EAACG,GAAA,EAAY,WAAU,gCAAA,CAAgC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAK1DX,KACC,gBAAAQ,EAAC,OAAA,EAAI,WAAU,4EACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,qDACZ,UAAAL,EAAU,IAAI,CAACS,MACd,gBAAAL;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,SAAS,MAAM;AACb,UAAAR,EAAgBa,EAAQ,EAAE,GAC1BX,EAAU,EAAK;AAAA,QACjB;AAAA,QACA,WAAW,iHACTW,EAAQ,OAAOd,IACX,0CACA,uCACN;AAAA,QAEA,UAAA;AAAA,UAAA,gBAAAU;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAKI,EAAQ;AAAA,cACb,KAAKA,EAAQ;AAAA,cACb,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ,gBAAAJ,EAAC,OAAA,EAAI,WAAU,uGACb,UAAA,gBAAAA,EAAC,UAAK,WAAU,iEACb,UAAAI,EAAQ,KAAA,CACX,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,MApBKA,EAAQ;AAAA,IAAA,CAsBhB,GACH,EAAA,CACF;AAAA,EAAA,GAEJ;AAEJ;"}
1
+ {"version":3,"file":"GalleryPicker.js","sources":["../../../src/ui/lightbox/GalleryPicker.tsx"],"sourcesContent":["import { ChevronDown, ChevronUp } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { useImageDialog } from \"../../context/ImageDialogContext\";\nimport type { Gallery } from \"../../types/gallery\";\n\ninterface GalleryPickerProps {\n currentGalleryId?: string;\n onGalleryChange: (galleryId: string) => void;\n}\n\nexport const GalleryPicker = ({\n currentGalleryId,\n onGalleryChange,\n}: GalleryPickerProps) => {\n const [isOpen, setIsOpen] = useState(false);\n const { galleries } = useImageDialog();\n\n const currentGallery = galleries.find((g) => g.id === currentGalleryId);\n\n return (\n <div className=\"relative w-full\">\n {/* Toggle Button */}\n <div\n onClick={() => setIsOpen(!isOpen)}\n className=\"cursor-pointer w-full flex items-center justify-between px-4 py-3 bg-background/40 border-b border-border hover:bg-secondary/20 transition-colors select-none\"\n >\n <div className=\"flex items-center gap-3\">\n {currentGallery && (\n <>\n <img\n src={currentGallery.thumbnail}\n alt={currentGallery.name}\n className=\"w-8 h-8 object-cover rounded\"\n />\n <div className=\"text-left\">\n <div className=\"font-medium text-sm\">{currentGallery.name}</div>\n {currentGallery.description && (\n <div className=\"text-xs text-muted-foreground\">\n {currentGallery.description}\n </div>\n )}\n </div>\n </>\n )}\n </div>\n {isOpen ? (\n <ChevronUp className=\"w-4 h-4 text-muted-foreground\" />\n ) : (\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n )}\n </div>\n\n {/* Gallery Grid */}\n {isOpen && (\n <div className=\"overflow-hidden bg-background/95 backdrop-blur-sm border-b border-border\">\n <div className=\"flex flex-wrap gap-2 p-4 max-h-64 overflow-y-auto\">\n {galleries.map((gallery: Gallery) => (\n <button\n key={gallery.id}\n onClick={() => {\n onGalleryChange(gallery.id);\n setIsOpen(false);\n }}\n className={`cursor-pointer relative w-20 h-20 rounded-lg overflow-hidden border-2 transition-all hover:scale-105 shrink-0 ${\n gallery.id === currentGalleryId\n ? \"border-primary ring-2 ring-primary/50\"\n : \"border-border hover:border-primary/50\"\n }`}\n >\n <img\n src={gallery.thumbnail}\n alt={gallery.name}\n className=\"w-full h-full object-cover\"\n />\n <div className=\"absolute inset-0 bg-linear-to-t from-background via-background/60 to-transparent flex items-end p-1\">\n <span className=\"text-xs font-medium truncate w-full text-center leading-tight\">\n {gallery.name}\n </span>\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"names":["GalleryPicker","currentGalleryId","onGalleryChange","isOpen","setIsOpen","useState","galleries","useImageDialog","currentGallery","g","jsxs","jsx","Fragment","ChevronUp","ChevronDown","gallery"],"mappings":";;;;;AAUO,MAAMA,IAAgB,CAAC;AAAA,EAC5B,kBAAAC;AAAA,EACA,iBAAAC;AACF,MAA0B;AACxB,QAAM,CAACC,GAAQC,CAAS,IAAIC,EAAS,EAAK,GACpC,EAAE,WAAAC,EAAA,IAAcC,EAAA,GAEhBC,IAAiBF,EAAU,KAAK,CAACG,MAAMA,EAAE,OAAOR,CAAgB;AAEtE,SACE,gBAAAS,EAAC,OAAA,EAAI,WAAU,mBAEb,UAAA;AAAA,IAAA,gBAAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAS,MAAMN,EAAU,CAACD,CAAM;AAAA,QAChC,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,2BACZ,UAAAH,KACC,gBAAAE,EAAAE,GAAA,EACE,UAAA;AAAA,YAAA,gBAAAD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAKH,EAAe;AAAA,gBACpB,KAAKA,EAAe;AAAA,gBACpB,WAAU;AAAA,cAAA;AAAA,YAAA;AAAA,YAEZ,gBAAAE,EAAC,OAAA,EAAI,WAAU,aACb,UAAA;AAAA,cAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,uBAAuB,UAAAH,EAAe,MAAK;AAAA,cACzDA,EAAe,eACd,gBAAAG,EAAC,SAAI,WAAU,iCACZ,YAAe,YAAA,CAClB;AAAA,YAAA,EAAA,CAEJ;AAAA,UAAA,EAAA,CACF,EAAA,CAEJ;AAAA,UACCR,sBACEU,GAAA,EAAU,WAAU,iCAAgC,IAErD,gBAAAF,EAACG,GAAA,EAAY,WAAU,gCAAA,CAAgC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAK1DX,KACC,gBAAAQ,EAAC,OAAA,EAAI,WAAU,4EACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,qDACZ,UAAAL,EAAU,IAAI,CAACS,MACd,gBAAAL;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,SAAS,MAAM;AACb,UAAAR,EAAgBa,EAAQ,EAAE,GAC1BX,EAAU,EAAK;AAAA,QACjB;AAAA,QACA,WAAW,iHACTW,EAAQ,OAAOd,IACX,0CACA,uCACN;AAAA,QAEA,UAAA;AAAA,UAAA,gBAAAU;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAKI,EAAQ;AAAA,cACb,KAAKA,EAAQ;AAAA,cACb,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ,gBAAAJ,EAAC,OAAA,EAAI,WAAU,uGACb,UAAA,gBAAAA,EAAC,UAAK,WAAU,iEACb,UAAAI,EAAQ,KAAA,CACX,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,MApBKA,EAAQ;AAAA,IAAA,CAsBhB,GACH,EAAA,CACF;AAAA,EAAA,GAEJ;AAEJ;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ImageThumbnailStrip.js","sources":["../../../src/ui/lightbox/ImageThumbnailStrip.tsx"],"sourcesContent":["import { ChevronUp, ChevronDown, Info } from \"lucide-react\";\nimport { useState, useRef, useEffect } from \"react\";\nimport type { Gallery } from \"../../types/gallery\";\n\ninterface ImageThumbnailStripProps {\n gallery: Gallery;\n currentIndex: number;\n onImageChange: (index: number) => void;\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const ImageThumbnailStrip = ({\n gallery,\n currentIndex,\n onImageChange,\n isOpen,\n onToggle,\n}: ImageThumbnailStripProps) => {\n const [showInfo, setShowInfo] = useState(false);\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const currentImage = gallery.images[currentIndex];\n\n // Auto-scroll to current image\n useEffect(() => {\n if (isOpen && scrollContainerRef.current) {\n const thumbnail = scrollContainerRef.current.children[\n currentIndex\n ] as HTMLElement;\n if (thumbnail) {\n thumbnail.scrollIntoView({\n behavior: \"smooth\",\n block: \"nearest\",\n inline: \"center\",\n });\n }\n }\n }, [currentIndex, isOpen]);\n\n return (\n <div className=\"relative w-full flex flex-col-reverse\">\n {/* Toggle Button - stays at bottom */}\n <div\n onClick={onToggle}\n className=\"cursor-pointer w-full flex items-center justify-between px-4 py-3 hover:bg-background/40 backdrop-blur-sm border-t border-border bg-secondary/20 transition-colors select-none focus:outline-none focus:ring-0\"\n >\n <div className=\"flex items-center gap-3\">\n {currentImage && (\n <>\n <img\n src={currentImage.thumbnail || currentImage.src}\n alt={currentImage.title || `Image ${currentIndex + 1}`}\n className=\"w-10 h-10 object-cover rounded\"\n />\n <div className=\"text-left\">\n <div className=\"font-medium text-sm\">\n {currentImage.title || `Image ${currentIndex + 1}`}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {currentIndex + 1} / {gallery.images.length}\n </div>\n </div>\n </>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {currentImage?.description && (\n <div\n onClick={(e) => {\n e.stopPropagation();\n setShowInfo(!showInfo);\n }}\n className=\"p-1 hover:bg-primary/20 rounded transition-colors cursor-pointer\"\n >\n <Info className=\"w-4 h-4\" />\n </div>\n )}\n {isOpen ? (\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n ) : (\n <ChevronUp className=\"w-4 h-4 text-muted-foreground\" />\n )}\n </div>\n </div>\n\n {/* Thumbnail Strip */}\n {isOpen && (\n <div className=\"w-full bg-background/80 backdrop-blur-md border-t border-border p-2 animate-in slide-in-from-bottom-10 fade-in duration-200\">\n <div\n ref={scrollContainerRef}\n className=\"flex gap-2 overflow-x-auto pb-2 scrollbar-thin scrollbar-thumb-secondary scrollbar-track-transparent px-2\"\n >\n {gallery.images.map((img, idx) => (\n <div\n key={idx}\n onClick={() => onImageChange(idx)}\n className={`relative flex-shrink-0 cursor-pointer transition-all duration-200 ${\n idx === currentIndex\n ? \"ring-2 ring-primary scale-105 z-10\"\n : \"opacity-70 hover:opacity-100 hover:scale-105\"\n }`}\n >\n <img\n src={img.thumbnail || img.src}\n alt={img.title || `Thumbnail ${idx + 1}`}\n className=\"h-20 w-auto object-cover rounded-sm\"\n loading=\"lazy\"\n />\n </div>\n ))}\n </div>\n\n {/* Info Panel */}\n {showInfo && currentImage?.description && (\n <div className=\"p-4 text-sm text-muted-foreground border-t border-border mt-2\">\n {currentImage.description}\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageThumbnailStrip","gallery","currentIndex","onImageChange","isOpen","onToggle","showInfo","setShowInfo","useState","scrollContainerRef","useRef","currentImage","useEffect","thumbnail","jsxs","jsx","Fragment","e","Info","ChevronDown","ChevronUp","img","idx"],"mappings":"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"}
1
+ {"version":3,"file":"ImageThumbnailStrip.js","sources":["../../../src/ui/lightbox/ImageThumbnailStrip.tsx"],"sourcesContent":["import { ChevronDown, ChevronUp, Info } from \"lucide-react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Gallery } from \"../../types/gallery\";\n\ninterface ImageThumbnailStripProps {\n gallery: Gallery;\n currentIndex: number;\n onImageChange: (index: number) => void;\n isOpen: boolean;\n onToggle: () => void;\n}\n\nexport const ImageThumbnailStrip = ({\n gallery,\n currentIndex,\n onImageChange,\n isOpen,\n onToggle,\n}: ImageThumbnailStripProps) => {\n const [showInfo, setShowInfo] = useState(false);\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const currentImage = gallery.images[currentIndex];\n\n // Auto-scroll to current image\n useEffect(() => {\n if (isOpen && scrollContainerRef.current) {\n const thumbnail = scrollContainerRef.current.children[\n currentIndex\n ] as HTMLElement;\n if (thumbnail) {\n thumbnail.scrollIntoView({\n behavior: \"smooth\",\n block: \"nearest\",\n inline: \"center\",\n });\n }\n }\n }, [currentIndex, isOpen]);\n\n return (\n <div className=\"relative w-full flex flex-col-reverse\">\n {/* Toggle Button - stays at bottom */}\n <div\n onClick={onToggle}\n className=\"cursor-pointer w-full flex items-center justify-between px-4 py-3 hover:bg-background/40 backdrop-blur-sm border-t border-border bg-secondary/20 transition-colors select-none focus:outline-none focus:ring-0\"\n >\n <div className=\"flex items-center gap-3\">\n {currentImage && (\n <>\n <img\n src={currentImage.thumbnail || currentImage.src}\n alt={currentImage.title || `Image ${currentIndex + 1}`}\n className=\"w-10 h-10 object-cover rounded\"\n />\n <div className=\"text-left\">\n <div className=\"font-medium text-sm\">\n {currentImage.title || `Image ${currentIndex + 1}`}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {currentIndex + 1} / {gallery.images.length}\n </div>\n </div>\n </>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {currentImage?.description && (\n <div\n onClick={(e) => {\n e.stopPropagation();\n setShowInfo(!showInfo);\n }}\n className=\"p-1 hover:bg-primary/20 rounded transition-colors cursor-pointer\"\n >\n <Info className=\"w-4 h-4\" />\n </div>\n )}\n {isOpen ? (\n <ChevronDown className=\"w-4 h-4 text-muted-foreground\" />\n ) : (\n <ChevronUp className=\"w-4 h-4 text-muted-foreground\" />\n )}\n </div>\n </div>\n\n {/* Thumbnail Strip */}\n {isOpen && (\n <div className=\"w-full bg-background/80 backdrop-blur-md border-t border-border p-2 animate-in slide-in-from-bottom-10 fade-in duration-200\">\n <div\n ref={scrollContainerRef}\n className=\"flex gap-2 overflow-x-auto pb-2 scrollbar-thin scrollbar-thumb-secondary scrollbar-track-transparent px-2\"\n >\n {gallery.images.map((img, idx) => (\n <div\n key={idx}\n onClick={() => onImageChange(idx)}\n className={`relative flex-shrink-0 cursor-pointer transition-all duration-200 ${\n idx === currentIndex\n ? \"ring-2 ring-primary scale-105 z-10\"\n : \"opacity-70 hover:opacity-100 hover:scale-105\"\n }`}\n >\n <img\n src={img.thumbnail || img.src}\n alt={img.title || `Thumbnail ${idx + 1}`}\n className=\"h-20 w-auto object-cover rounded-sm\"\n loading=\"lazy\"\n />\n </div>\n ))}\n </div>\n\n {/* Info Panel */}\n {showInfo && currentImage?.description && (\n <div className=\"p-4 text-sm text-muted-foreground border-t border-border mt-2\">\n {currentImage.description}\n </div>\n )}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageThumbnailStrip","gallery","currentIndex","onImageChange","isOpen","onToggle","showInfo","setShowInfo","useState","scrollContainerRef","useRef","currentImage","useEffect","thumbnail","jsxs","jsx","Fragment","e","Info","ChevronDown","ChevronUp","img","idx"],"mappings":"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"}
@@ -6,7 +6,7 @@ interface LightboxViewerProps {
6
6
  onGalleryChange: (galleryId: string) => void;
7
7
  onImageChange: (index: number) => void;
8
8
  isOpen?: boolean;
9
- actions?: ImageAction[];
9
+ actions?: Array<ImageAction>;
10
10
  isLoading?: boolean;
11
11
  onClose?: () => void;
12
12
  showGalleryPicker?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"LightboxViewer.d.ts","sourceRoot":"","sources":["../../../src/ui/lightbox/LightboxViewer.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEhE,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,GAAI,gJAY5B,mBAAmB,4CAmIrB,CAAC"}
1
+ {"version":3,"file":"LightboxViewer.d.ts","sourceRoot":"","sources":["../../../src/ui/lightbox/LightboxViewer.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEhE,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,GAAI,gJAY5B,mBAAmB,4CAmIrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"LightboxViewer.js","sources":["../../../src/ui/lightbox/LightboxViewer.tsx"],"sourcesContent":["import { useState, useEffect, useRef } from \"react\";\nimport { Play, Pause, Loader2, X } from \"lucide-react\";\nimport { Button } from \"../button\";\nimport { PannableImage } from \"./PannableImage\";\nimport { ImageThumbnailStrip } from \"./ImageThumbnailStrip\";\nimport { GalleryPicker } from \"./GalleryPicker\";\nimport type { Gallery, ImageAction } from \"../../types/gallery\";\n\ninterface LightboxViewerProps {\n imageSrc?: string | null;\n gallery: Gallery | null;\n imageIndex: number;\n onGalleryChange: (galleryId: string) => void;\n onImageChange: (index: number) => void;\n isOpen?: boolean;\n actions?: ImageAction[];\n isLoading?: boolean;\n onClose?: () => void;\n showGalleryPicker?: boolean;\n showThumbnailStrip?: boolean;\n}\n\nexport const LightboxViewer = ({\n imageSrc,\n gallery,\n imageIndex,\n onGalleryChange,\n onImageChange,\n isOpen,\n actions = [],\n isLoading,\n onClose,\n showGalleryPicker = false,\n showThumbnailStrip = false,\n}: LightboxViewerProps) => {\n const [isPlaying, setIsPlaying] = useState(false);\n const [isStripOpen, setIsStripOpen] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (isPlaying) {\n timerRef.current = setInterval(() => {\n onImageChange(imageIndex + 1);\n }, 2500);\n }\n return () => {\n if (timerRef.current) clearInterval(timerRef.current);\n };\n }, [isPlaying, imageIndex, onImageChange]);\n\n // Stop playing if dialog closes\n useEffect(() => {\n if (!isOpen) setIsPlaying(false);\n }, [isOpen]);\n\n const handleImageChange = async (index: number) => {\n if (!gallery) return;\n await onImageChange(index);\n };\n\n // Prepare actions for PannableImage\n const currentImage = gallery?.images[imageIndex];\n const pannableActions = currentImage\n ? actions\n .filter((action) => !action.isVisible || action.isVisible(currentImage))\n .map((action) => ({\n icon: action.icon,\n label: action.label,\n onClick: () => action.onClick(currentImage),\n }))\n : [];\n\n // Calculate bottom offset for controls based on strip state\n const controlsBottomOffset = showThumbnailStrip\n ? isStripOpen\n ? 180 // Strip open height + padding\n : 80 // Strip closed height + padding\n : 16; // Default padding\n\n return (\n <div className=\"flex flex-col w-full h-full relative min-h-max flex-1 focus:outline-none\">\n {/* Top Gallery Picker */}\n {showGalleryPicker && (\n <div className=\"absolute top-0 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"pointer-events-auto\">\n <GalleryPicker\n currentGalleryId={gallery?.id}\n onGalleryChange={onGalleryChange}\n />\n </div>\n </div>\n )}\n\n <div className=\"absolute top-2 right-10 z-30 pointer-events-auto flex gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n className=\"px-4 flex items-center justify-center text-sm font-medium text-muted-foreground backdrop-blur-sm\"\n >\n {imageIndex + 1} /{\" \"}\n {gallery?.totalImages || gallery?.images.length || 0}\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => setIsPlaying(!isPlaying)}\n className=\" rounded-none bg-background/90 hover:bg-secondary/20 text-muted-foreground hover:text-foreground border-b border-l border-border backdrop-blur-sm\"\n title={isPlaying ? \"Pause slideshow\" : \"Start slideshow\"}\n >\n {isPlaying ? (\n <Pause className=\"h-4 w-4\" />\n ) : (\n <Play className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n\n {/* Main Image - Pannable Canvas */}\n <div className=\"flex-1 flex items-center justify-center relative w-full h-full min-h-full\">\n {isLoading && (\n <div className=\"absolute inset-0 z-50 flex items-center justify-center bg-black/20 backdrop-blur-[1px]\">\n <Loader2 className=\"w-10 h-10 text-white animate-spin\" />\n </div>\n )}\n {imageSrc && (\n <PannableImage\n src={imageSrc}\n className=\"w-full h-full\"\n isOpen={isOpen}\n actions={pannableActions}\n controlsBottomOffset={controlsBottomOffset}\n />\n )}\n </div>\n\n {/* Close Button - positioned over content */}\n {onClose && (\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={onClose}\n className=\"cursor-pointer hover:bg-secondary/20 fixed top-2 right-1.5 z-50 flex items-center justify-center group\"\n aria-label=\"Close dialog\"\n >\n <X className=\" text-muted-foreground group-hover:text-foreground transition-colors\" />\n </Button>\n )}\n\n {/* Bottom Image Strip */}\n {showThumbnailStrip && (\n <div className=\"absolute bottom-0 left-0 right-0 z-20 select-none focus-visible:outline-none focus:ring-0 focus:ring-transparent\">\n {gallery && (\n <ImageThumbnailStrip\n gallery={gallery}\n currentIndex={imageIndex}\n onImageChange={handleImageChange}\n isOpen={isStripOpen}\n onToggle={() => setIsStripOpen(!isStripOpen)}\n />\n )}\n </div>\n )}\n </div>\n );\n};\n"],"names":["LightboxViewer","imageSrc","gallery","imageIndex","onGalleryChange","onImageChange","isOpen","actions","isLoading","onClose","showGalleryPicker","showThumbnailStrip","isPlaying","setIsPlaying","useState","isStripOpen","setIsStripOpen","timerRef","useRef","useEffect","handleImageChange","index","currentImage","pannableActions","action","controlsBottomOffset","jsxs","jsx","GalleryPicker","Button","Pause","Play","Loader2","PannableImage","X","ImageThumbnailStrip"],"mappings":"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"}
1
+ {"version":3,"file":"LightboxViewer.js","sources":["../../../src/ui/lightbox/LightboxViewer.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Loader2, Pause, Play, X } from \"lucide-react\";\nimport { Button } from \"../button\";\nimport { PannableImage } from \"./PannableImage\";\nimport { ImageThumbnailStrip } from \"./ImageThumbnailStrip\";\nimport { GalleryPicker } from \"./GalleryPicker\";\nimport type { Gallery, ImageAction } from \"../../types/gallery\";\n\ninterface LightboxViewerProps {\n imageSrc?: string | null;\n gallery: Gallery | null;\n imageIndex: number;\n onGalleryChange: (galleryId: string) => void;\n onImageChange: (index: number) => void;\n isOpen?: boolean;\n actions?: Array<ImageAction>;\n isLoading?: boolean;\n onClose?: () => void;\n showGalleryPicker?: boolean;\n showThumbnailStrip?: boolean;\n}\n\nexport const LightboxViewer = ({\n imageSrc,\n gallery,\n imageIndex,\n onGalleryChange,\n onImageChange,\n isOpen,\n actions = [],\n isLoading,\n onClose,\n showGalleryPicker = false,\n showThumbnailStrip = false,\n}: LightboxViewerProps) => {\n const [isPlaying, setIsPlaying] = useState(false);\n const [isStripOpen, setIsStripOpen] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (isPlaying) {\n timerRef.current = setInterval(() => {\n onImageChange(imageIndex + 1);\n }, 2500);\n }\n return () => {\n if (timerRef.current) clearInterval(timerRef.current);\n };\n }, [isPlaying, imageIndex, onImageChange]);\n\n // Stop playing if dialog closes\n useEffect(() => {\n if (!isOpen) setIsPlaying(false);\n }, [isOpen]);\n\n const handleImageChange = async (index: number) => {\n if (!gallery) return;\n await onImageChange(index);\n };\n\n // Prepare actions for PannableImage\n const currentImage = gallery?.images[imageIndex];\n const pannableActions = currentImage\n ? actions\n .filter((action) => !action.isVisible || action.isVisible(currentImage))\n .map((action) => ({\n icon: action.icon,\n label: action.label,\n onClick: () => action.onClick(currentImage),\n }))\n : [];\n\n // Calculate bottom offset for controls based on strip state\n const controlsBottomOffset = showThumbnailStrip\n ? isStripOpen\n ? 180 // Strip open height + padding\n : 80 // Strip closed height + padding\n : 16; // Default padding\n\n return (\n <div className=\"flex flex-col w-full h-full relative min-h-max flex-1 focus:outline-none\">\n {/* Top Gallery Picker */}\n {showGalleryPicker && (\n <div className=\"absolute top-0 left-0 right-0 z-20 pointer-events-none\">\n <div className=\"pointer-events-auto\">\n <GalleryPicker\n currentGalleryId={gallery?.id}\n onGalleryChange={onGalleryChange}\n />\n </div>\n </div>\n )}\n\n <div className=\"absolute top-2 right-10 z-30 pointer-events-auto flex gap-2\">\n <Button\n size=\"sm\"\n variant=\"outline\"\n disabled\n className=\"px-4 flex items-center justify-center text-sm font-medium text-muted-foreground backdrop-blur-sm\"\n >\n {imageIndex + 1} /{\" \"}\n {gallery?.totalImages || gallery?.images.length || 0}\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={() => setIsPlaying(!isPlaying)}\n className=\" rounded-none bg-background/90 hover:bg-secondary/20 text-muted-foreground hover:text-foreground border-b border-l border-border backdrop-blur-sm\"\n title={isPlaying ? \"Pause slideshow\" : \"Start slideshow\"}\n >\n {isPlaying ? (\n <Pause className=\"h-4 w-4\" />\n ) : (\n <Play className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n\n {/* Main Image - Pannable Canvas */}\n <div className=\"flex-1 flex items-center justify-center relative w-full h-full min-h-full\">\n {isLoading && (\n <div className=\"absolute inset-0 z-50 flex items-center justify-center bg-black/20 backdrop-blur-[1px]\">\n <Loader2 className=\"w-10 h-10 text-white animate-spin\" />\n </div>\n )}\n {imageSrc && (\n <PannableImage\n src={imageSrc}\n className=\"w-full h-full\"\n isOpen={isOpen}\n actions={pannableActions}\n controlsBottomOffset={controlsBottomOffset}\n />\n )}\n </div>\n\n {/* Close Button - positioned over content */}\n {onClose && (\n <Button\n variant=\"outline\"\n size=\"icon-sm\"\n onClick={onClose}\n className=\"cursor-pointer hover:bg-secondary/20 fixed top-2 right-1.5 z-50 flex items-center justify-center group\"\n aria-label=\"Close dialog\"\n >\n <X className=\" text-muted-foreground group-hover:text-foreground transition-colors\" />\n </Button>\n )}\n\n {/* Bottom Image Strip */}\n {showThumbnailStrip && (\n <div className=\"absolute bottom-0 left-0 right-0 z-20 select-none focus-visible:outline-none focus:ring-0 focus:ring-transparent\">\n {gallery && (\n <ImageThumbnailStrip\n gallery={gallery}\n currentIndex={imageIndex}\n onImageChange={handleImageChange}\n isOpen={isStripOpen}\n onToggle={() => setIsStripOpen(!isStripOpen)}\n />\n )}\n </div>\n )}\n </div>\n );\n};\n"],"names":["LightboxViewer","imageSrc","gallery","imageIndex","onGalleryChange","onImageChange","isOpen","actions","isLoading","onClose","showGalleryPicker","showThumbnailStrip","isPlaying","setIsPlaying","useState","isStripOpen","setIsStripOpen","timerRef","useRef","useEffect","handleImageChange","index","currentImage","pannableActions","action","controlsBottomOffset","jsxs","jsx","GalleryPicker","Button","Pause","Play","Loader2","PannableImage","X","ImageThumbnailStrip"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from "react";
1
+ import type { ReactNode } from "react";
2
2
  interface PannableImageAction {
3
3
  icon: ReactNode;
4
4
  label: string;
@@ -8,7 +8,7 @@ interface PannableImageProps {
8
8
  src: string;
9
9
  className?: string;
10
10
  isOpen?: boolean;
11
- actions?: PannableImageAction[];
11
+ actions?: Array<PannableImageAction>;
12
12
  controlsBottomOffset?: number;
13
13
  }
14
14
  export declare const PannableImage: ({ src, className, isOpen, actions, controlsBottomOffset, }: PannableImageProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"PannableImage.d.ts","sourceRoot":"","sources":["../../../src/ui/lightbox/PannableImage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,UAAU,mBAAmB;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,kBAAkB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,aAAa,GAAI,4DAM3B,kBAAkB,4CAuZpB,CAAC"}
1
+ {"version":3,"file":"PannableImage.d.ts","sourceRoot":"","sources":["../../../src/ui/lightbox/PannableImage.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,UAAU,mBAAmB;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,kBAAkB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACrC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,aAAa,GAAI,4DAM3B,kBAAkB,4CAuZpB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"PannableImage.js","sources":["../../../src/ui/lightbox/PannableImage.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { RotateCcw, RotateCw } from \"lucide-react\";\nimport { Button } from \"../button\";\n\ninterface PannableImageAction {\n icon: ReactNode;\n label: string;\n onClick: () => void;\n}\n\ninterface PannableImageProps {\n src: string;\n className?: string;\n isOpen?: boolean;\n actions?: PannableImageAction[];\n controlsBottomOffset?: number;\n}\n\nexport const PannableImage = ({\n src,\n className,\n isOpen,\n actions = [],\n controlsBottomOffset = 16,\n}: PannableImageProps) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const imageRef = useRef<HTMLImageElement | null>(null);\n\n const [isDragging, setIsDragging] = useState(false);\n const [zoom, setZoom] = useState(1);\n const zoomRef = useRef(1);\n const [pan, setPan] = useState({ x: 0, y: 0 });\n const panRef = useRef({ x: 0, y: 0 });\n const [rotation, setRotation] = useState(0);\n const rotationRef = useRef(0);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [isImageLoaded, setIsImageLoaded] = useState(false);\n const [showHelp, setShowHelp] = useState(false);\n\n // Draw image on canvas\n const drawImage = useCallback(() => {\n if (!canvasRef.current || !imageRef.current) return;\n\n const canvas = canvasRef.current;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || canvas.width === 0 || canvas.height === 0) return;\n\n const dpr = window.devicePixelRatio || 1;\n const img = imageRef.current;\n\n // Clear canvas\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n // Calculate fit dimensions\n const r = rotationRef.current;\n const isRotated = (r / 90) % 2 !== 0;\n const canvasAspect = canvas.width / canvas.height;\n const imageAspect = isRotated\n ? img.height / img.width\n : img.width / img.height;\n\n let fitWidth = canvas.width;\n let fitHeight = canvas.height;\n\n if (imageAspect > canvasAspect) {\n // Image is wider than canvas (relative to aspect)\n fitHeight = canvas.width / imageAspect;\n } else {\n // Image is taller than canvas\n fitWidth = canvas.height * imageAspect;\n }\n\n // Apply zoom\n const z = zoomRef.current;\n const p = panRef.current;\n\n // The dimensions of the image as it will be drawn (unrotated)\n const drawWidth = (isRotated ? fitHeight : fitWidth) * z;\n const drawHeight = (isRotated ? fitWidth : fitHeight) * z;\n\n ctx.save();\n // Move to center of canvas + pan\n ctx.translate(canvas.width / 2 + p.x * dpr, canvas.height / 2 + p.y * dpr);\n ctx.rotate((r * Math.PI) / 180);\n\n // Draw image centered at 0,0\n ctx.drawImage(img, -drawWidth / 2, -drawHeight / 2, drawWidth, drawHeight);\n ctx.restore();\n }, []);\n\n // Ensure canvas gets sized correctly once layout stabilizes.\n const ensureCanvasSize = useCallback(() => {\n if (!containerRef.current || !canvasRef.current) return;\n\n const dpr = window.devicePixelRatio || 1;\n let attempts = 0;\n const maxAttempts = 60;\n\n const trySet = () => {\n if (!containerRef.current || !canvasRef.current) return;\n const rect = containerRef.current.getBoundingClientRect();\n\n if (rect.width > 0 && rect.height > 0) {\n canvasRef.current.width = rect.width * dpr;\n canvasRef.current.height = rect.height * dpr;\n canvasRef.current.style.width = `${rect.width}px`;\n canvasRef.current.style.height = `${rect.height}px`;\n drawImage();\n } else if (attempts < maxAttempts) {\n attempts++;\n requestAnimationFrame(trySet);\n }\n };\n\n requestAnimationFrame(trySet);\n }, [drawImage]);\n\n // Resize handler\n const handleResize = useCallback(() => {\n ensureCanvasSize();\n }, [ensureCanvasSize]);\n\n // Trigger ensureCanvasSize when dialog is opened\n useEffect(() => {\n if (isOpen) {\n // Small delay to allow dialog animation/layout to settle\n setTimeout(ensureCanvasSize, 50);\n setTimeout(ensureCanvasSize, 200);\n }\n }, [isOpen, ensureCanvasSize]);\n\n // Load image\n useEffect(() => {\n setIsImageLoaded(false);\n const img = new Image();\n img.src = src;\n img.onload = () => {\n imageRef.current = img;\n setIsImageLoaded(true);\n // Reset zoom/pan on new image\n zoomRef.current = 1;\n setZoom(1);\n panRef.current = { x: 0, y: 0 };\n setPan({ x: 0, y: 0 });\n rotationRef.current = 0;\n setRotation(0);\n handleResize();\n };\n }, [src, handleResize]);\n\n // Setup resize observer and window listener\n useEffect(() => {\n window.addEventListener(\"resize\", handleResize);\n const resizeObserver = new ResizeObserver(() => handleResize());\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver.disconnect();\n };\n }, [handleResize]);\n\n // Redraw when zoom or pan changes\n useEffect(() => {\n zoomRef.current = zoom;\n panRef.current = pan;\n rotationRef.current = rotation;\n requestAnimationFrame(drawImage);\n }, [zoom, pan, rotation, drawImage]);\n\n // Mouse wheel zoom (with pivot at cursor)\n const handleWheel = useCallback((e: WheelEvent) => {\n e.preventDefault();\n const dpr = window.devicePixelRatio || 1;\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const mouseX = (e.clientX - rect.left) * dpr;\n const mouseY = (e.clientY - rect.top) * dpr;\n\n // Center of canvas\n const cx = canvas.width / 2;\n const cy = canvas.height / 2;\n\n // Mouse position relative to center (before zoom)\n const rx = mouseX - cx - panRef.current.x * dpr;\n const ry = mouseY - cy - panRef.current.y * dpr;\n\n const delta = -Math.sign(e.deltaY) * 0.1;\n const newZoom = Math.max(0.1, Math.min(10, zoomRef.current + delta));\n const zoomFactor = newZoom / zoomRef.current;\n\n // Adjust pan to keep mouse over same point\n // newRx = rx * zoomFactor\n // newRx = mouseX - cx - newPanX\n // => newPanX = mouseX - cx - rx * zoomFactor\n const newPanX = (mouseX - cx - rx * zoomFactor) / dpr;\n const newPanY = (mouseY - cy - ry * zoomFactor) / dpr;\n\n setZoom(newZoom);\n setPan({ x: newPanX, y: newPanY });\n }, []);\n\n // Touch handling\n const [touchState, setTouchState] = useState<{\n isPinching: boolean;\n initialDistance: number;\n initialZoom: number;\n initialPan: { x: number; y: number };\n midPoint: { x: number; y: number };\n } | null>(null);\n\n const handleTouchStart = useCallback((e: TouchEvent) => {\n if (e.touches.length === 2) {\n e.preventDefault();\n const t1 = e.touches[0];\n const t2 = e.touches[1];\n const dist = Math.hypot(t1.clientX - t2.clientX, t1.clientY - t2.clientY);\n const midX = (t1.clientX + t2.clientX) / 2;\n const midY = (t1.clientY + t2.clientY) / 2;\n\n setTouchState({\n isPinching: true,\n initialDistance: dist,\n initialZoom: zoomRef.current,\n initialPan: { ...panRef.current },\n midPoint: { x: midX, y: midY },\n });\n } else if (e.touches.length === 1) {\n const t = e.touches[0];\n setDragStart({ x: t.clientX, y: t.clientY });\n setIsDragging(true);\n }\n }, []);\n\n const handleTouchMove = useCallback(\n (e: TouchEvent) => {\n if (e.touches.length === 2 && touchState?.isPinching) {\n e.preventDefault();\n const t1 = e.touches[0];\n const t2 = e.touches[1];\n const dist = Math.hypot(\n t1.clientX - t2.clientX,\n t1.clientY - t2.clientY\n );\n\n const scale = dist / touchState.initialDistance;\n setZoom(Math.max(0.1, Math.min(10, touchState.initialZoom * scale)));\n\n // Optional: Handle pan during pinch (using midpoint delta)\n // const midX = (t1.clientX + t2.clientX) / 2;\n // const midY = (t1.clientY + t2.clientY) / 2;\n // const dx = midX - touchState.midPoint.x;\n // const dy = midY - touchState.midPoint.y;\n // setPan({\n // x: touchState.initialPan.x + dx,\n // y: touchState.initialPan.y + dy\n // });\n } else if (e.touches.length === 1 && isDragging) {\n e.preventDefault(); // Prevent scrolling\n const t = e.touches[0];\n const dx = t.clientX - dragStart.x;\n const dy = t.clientY - dragStart.y;\n setPan((p) => ({ x: p.x + dx, y: p.y + dy }));\n setDragStart({ x: t.clientX, y: t.clientY });\n }\n },\n [touchState, isDragging, dragStart]\n );\n\n const handleTouchEnd = useCallback(() => {\n setTouchState(null);\n setIsDragging(false);\n }, []);\n\n // Mouse drag\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n setDragStart({ x: e.clientX, y: e.clientY });\n setIsDragging(true);\n }, []);\n\n const handleMouseMove = useCallback(\n (e: React.MouseEvent) => {\n if (isDragging) {\n const dx = e.clientX - dragStart.x;\n const dy = e.clientY - dragStart.y;\n setPan((p) => ({ x: p.x + dx, y: p.y + dy }));\n setDragStart({ x: e.clientX, y: e.clientY });\n }\n },\n [isDragging, dragStart]\n );\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n // Reset view on double click\n const handleDoubleClick = useCallback(() => {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n setRotation(0);\n }, []);\n\n // Attach event listeners\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n // Passive: false is important for preventing default scroll on touch\n canvas.addEventListener(\"wheel\", handleWheel, { passive: false });\n canvas.addEventListener(\"touchstart\", handleTouchStart, { passive: false });\n canvas.addEventListener(\"touchmove\", handleTouchMove, { passive: false });\n canvas.addEventListener(\"touchend\", handleTouchEnd);\n\n return () => {\n canvas.removeEventListener(\"wheel\", handleWheel);\n canvas.removeEventListener(\"touchstart\", handleTouchStart);\n canvas.removeEventListener(\"touchmove\", handleTouchMove);\n canvas.removeEventListener(\"touchend\", handleTouchEnd);\n };\n }, [handleWheel, handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n return (\n <div\n ref={containerRef}\n className={`${className} relative h-full w-full overflow-hidden`}\n >\n <canvas\n ref={canvasRef}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onDoubleClick={handleDoubleClick}\n className={`w-[100dvw] h-[100dvh] transition-opacity duration-200 ${\n isImageLoaded ? \"opacity-100\" : \"opacity-0\"\n } ${isDragging ? \"cursor-grabbing\" : \"cursor-grab\"} touch-none`}\n />\n\n {/* Rotation Controls */}\n <div\n className=\"absolute left-2 flex items-center gap-2 opacity-0 hover:opacity-100 transition-opacity duration-200 transition-all duration-300 ease-in-out\"\n style={{ bottom: `${controlsBottomOffset}px` }}\n >\n <Button\n onClick={(e) => {\n e.stopPropagation();\n setRotation((prev) => (prev - 90) % 360);\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title=\"Rotate Counter-clockwise\"\n >\n <RotateCcw className=\"w-4 h-4 text-muted-foreground\" />\n </Button>\n <Button\n onClick={(e) => {\n e.stopPropagation();\n setRotation((prev) => (prev + 90) % 360);\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title=\"Rotate Clockwise\"\n >\n <RotateCw className=\"w-4 h-4 text-muted-foreground\" />\n </Button>\n </div>\n\n {/* Zoom indicator and Help */}\n <div\n className=\"absolute right-2 flex items-center gap-2 transition-all duration-300 ease-in-out\"\n style={{ bottom: `${controlsBottomOffset}px` }}\n >\n {/* Action Buttons */}\n {actions.map((action, idx) => (\n <Button\n key={idx}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick();\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title={action.label}\n >\n {action.icon}\n </Button>\n ))}\n\n <div className=\"h-8 ring-1 ring-foreground/10 bg-background/90 backdrop-blur-sm px-3 py-1.5 text-xs text-muted-foreground pointer-events-none border border-border/50 transition-opacity duration-0 items-center justify-center flex\">\n {Math.round(zoom * 100)}%\n </div>\n\n {/* Help icon */}\n <div className=\"relative\">\n <div\n onMouseEnter={() => setShowHelp(true)}\n onMouseLeave={() => setShowHelp(false)}\n className=\"w-8 h-8 ring-1 ring-foreground/10 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center cursor-help transition-all duration-0 hover:bg-primary/20\"\n >\n <span className=\"text-xs text-muted-foreground font-medium\">?</span>\n </div>\n\n {/* Help tooltip */}\n {showHelp && (\n <div className=\"absolute bottom-full right-0 mb-2 w-64 bg-background/95 backdrop-blur-sm border border-border p-3 text-xs text-muted-foreground shadow-lg\">\n <div className=\"space-y-1\">\n <div>\n <span className=\"text-foreground\">Scroll/Pinch:</span> Zoom\n in/out\n </div>\n <div>\n <span className=\"text-foreground\">Drag:</span> Pan around\n image\n </div>\n <div>\n <span className=\"text-foreground\">Double-click:</span> Reset\n view\n </div>\n <div>\n <span className=\"text-foreground\">Escape:</span> Close dialog\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"names":["PannableImage","src","className","isOpen","actions","controlsBottomOffset","canvasRef","useRef","containerRef","imageRef","isDragging","setIsDragging","useState","zoom","setZoom","zoomRef","pan","setPan","panRef","rotation","setRotation","rotationRef","dragStart","setDragStart","isImageLoaded","setIsImageLoaded","showHelp","setShowHelp","drawImage","useCallback","canvas","ctx","dpr","img","r","isRotated","canvasAspect","imageAspect","fitWidth","fitHeight","p","drawWidth","drawHeight","ensureCanvasSize","attempts","maxAttempts","trySet","rect","handleResize","useEffect","resizeObserver","handleWheel","mouseX","mouseY","cx","cy","rx","ry","delta","newZoom","zoomFactor","newPanX","newPanY","touchState","setTouchState","handleTouchStart","t1","t2","dist","midX","midY","handleTouchMove","scale","dx","dy","handleTouchEnd","handleMouseDown","handleMouseMove","handleMouseUp","handleDoubleClick","jsxs","jsx","Button","prev","RotateCcw","RotateCw","action","idx","e"],"mappings":"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"}
1
+ {"version":3,"file":"PannableImage.js","sources":["../../../src/ui/lightbox/PannableImage.tsx"],"sourcesContent":["import {\n \n useCallback,\n useEffect,\n useRef,\n useState\n} from \"react\";\nimport { RotateCcw, RotateCw } from \"lucide-react\";\nimport { Button } from \"../button\";\nimport type {ReactNode} from \"react\";\n\ninterface PannableImageAction {\n icon: ReactNode;\n label: string;\n onClick: () => void;\n}\n\ninterface PannableImageProps {\n src: string;\n className?: string;\n isOpen?: boolean;\n actions?: Array<PannableImageAction>;\n controlsBottomOffset?: number;\n}\n\nexport const PannableImage = ({\n src,\n className,\n isOpen,\n actions = [],\n controlsBottomOffset = 16,\n}: PannableImageProps) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const imageRef = useRef<HTMLImageElement | null>(null);\n\n const [isDragging, setIsDragging] = useState(false);\n const [zoom, setZoom] = useState(1);\n const zoomRef = useRef(1);\n const [pan, setPan] = useState({ x: 0, y: 0 });\n const panRef = useRef({ x: 0, y: 0 });\n const [rotation, setRotation] = useState(0);\n const rotationRef = useRef(0);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [isImageLoaded, setIsImageLoaded] = useState(false);\n const [showHelp, setShowHelp] = useState(false);\n\n // Draw image on canvas\n const drawImage = useCallback(() => {\n if (!canvasRef.current || !imageRef.current) return;\n\n const canvas = canvasRef.current;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || canvas.width === 0 || canvas.height === 0) return;\n\n const dpr = window.devicePixelRatio || 1;\n const img = imageRef.current;\n\n // Clear canvas\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n // Calculate fit dimensions\n const r = rotationRef.current;\n const isRotated = (r / 90) % 2 !== 0;\n const canvasAspect = canvas.width / canvas.height;\n const imageAspect = isRotated\n ? img.height / img.width\n : img.width / img.height;\n\n let fitWidth = canvas.width;\n let fitHeight = canvas.height;\n\n if (imageAspect > canvasAspect) {\n // Image is wider than canvas (relative to aspect)\n fitHeight = canvas.width / imageAspect;\n } else {\n // Image is taller than canvas\n fitWidth = canvas.height * imageAspect;\n }\n\n // Apply zoom\n const z = zoomRef.current;\n const p = panRef.current;\n\n // The dimensions of the image as it will be drawn (unrotated)\n const drawWidth = (isRotated ? fitHeight : fitWidth) * z;\n const drawHeight = (isRotated ? fitWidth : fitHeight) * z;\n\n ctx.save();\n // Move to center of canvas + pan\n ctx.translate(canvas.width / 2 + p.x * dpr, canvas.height / 2 + p.y * dpr);\n ctx.rotate((r * Math.PI) / 180);\n\n // Draw image centered at 0,0\n ctx.drawImage(img, -drawWidth / 2, -drawHeight / 2, drawWidth, drawHeight);\n ctx.restore();\n }, []);\n\n // Ensure canvas gets sized correctly once layout stabilizes.\n const ensureCanvasSize = useCallback(() => {\n if (!containerRef.current || !canvasRef.current) return;\n\n const dpr = window.devicePixelRatio || 1;\n let attempts = 0;\n const maxAttempts = 60;\n\n const trySet = () => {\n if (!containerRef.current || !canvasRef.current) return;\n const rect = containerRef.current.getBoundingClientRect();\n\n if (rect.width > 0 && rect.height > 0) {\n canvasRef.current.width = rect.width * dpr;\n canvasRef.current.height = rect.height * dpr;\n canvasRef.current.style.width = `${rect.width}px`;\n canvasRef.current.style.height = `${rect.height}px`;\n drawImage();\n } else if (attempts < maxAttempts) {\n attempts++;\n requestAnimationFrame(trySet);\n }\n };\n\n requestAnimationFrame(trySet);\n }, [drawImage]);\n\n // Resize handler\n const handleResize = useCallback(() => {\n ensureCanvasSize();\n }, [ensureCanvasSize]);\n\n // Trigger ensureCanvasSize when dialog is opened\n useEffect(() => {\n if (isOpen) {\n // Small delay to allow dialog animation/layout to settle\n setTimeout(ensureCanvasSize, 50);\n setTimeout(ensureCanvasSize, 200);\n }\n }, [isOpen, ensureCanvasSize]);\n\n // Load image\n useEffect(() => {\n setIsImageLoaded(false);\n const img = new Image();\n img.src = src;\n img.onload = () => {\n imageRef.current = img;\n setIsImageLoaded(true);\n // Reset zoom/pan on new image\n zoomRef.current = 1;\n setZoom(1);\n panRef.current = { x: 0, y: 0 };\n setPan({ x: 0, y: 0 });\n rotationRef.current = 0;\n setRotation(0);\n handleResize();\n };\n }, [src, handleResize]);\n\n // Setup resize observer and window listener\n useEffect(() => {\n window.addEventListener(\"resize\", handleResize);\n const resizeObserver = new ResizeObserver(() => handleResize());\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n resizeObserver.disconnect();\n };\n }, [handleResize]);\n\n // Redraw when zoom or pan changes\n useEffect(() => {\n zoomRef.current = zoom;\n panRef.current = pan;\n rotationRef.current = rotation;\n requestAnimationFrame(drawImage);\n }, [zoom, pan, rotation, drawImage]);\n\n // Mouse wheel zoom (with pivot at cursor)\n const handleWheel = useCallback((e: WheelEvent) => {\n e.preventDefault();\n const dpr = window.devicePixelRatio || 1;\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const mouseX = (e.clientX - rect.left) * dpr;\n const mouseY = (e.clientY - rect.top) * dpr;\n\n // Center of canvas\n const cx = canvas.width / 2;\n const cy = canvas.height / 2;\n\n // Mouse position relative to center (before zoom)\n const rx = mouseX - cx - panRef.current.x * dpr;\n const ry = mouseY - cy - panRef.current.y * dpr;\n\n const delta = -Math.sign(e.deltaY) * 0.1;\n const newZoom = Math.max(0.1, Math.min(10, zoomRef.current + delta));\n const zoomFactor = newZoom / zoomRef.current;\n\n // Adjust pan to keep mouse over same point\n // newRx = rx * zoomFactor\n // newRx = mouseX - cx - newPanX\n // => newPanX = mouseX - cx - rx * zoomFactor\n const newPanX = (mouseX - cx - rx * zoomFactor) / dpr;\n const newPanY = (mouseY - cy - ry * zoomFactor) / dpr;\n\n setZoom(newZoom);\n setPan({ x: newPanX, y: newPanY });\n }, []);\n\n // Touch handling\n const [touchState, setTouchState] = useState<{\n isPinching: boolean;\n initialDistance: number;\n initialZoom: number;\n initialPan: { x: number; y: number };\n midPoint: { x: number; y: number };\n } | null>(null);\n\n const handleTouchStart = useCallback((e: TouchEvent) => {\n if (e.touches.length === 2) {\n e.preventDefault();\n const t1 = e.touches[0];\n const t2 = e.touches[1];\n const dist = Math.hypot(t1.clientX - t2.clientX, t1.clientY - t2.clientY);\n const midX = (t1.clientX + t2.clientX) / 2;\n const midY = (t1.clientY + t2.clientY) / 2;\n\n setTouchState({\n isPinching: true,\n initialDistance: dist,\n initialZoom: zoomRef.current,\n initialPan: { ...panRef.current },\n midPoint: { x: midX, y: midY },\n });\n } else if (e.touches.length === 1) {\n const t = e.touches[0];\n setDragStart({ x: t.clientX, y: t.clientY });\n setIsDragging(true);\n }\n }, []);\n\n const handleTouchMove = useCallback(\n (e: TouchEvent) => {\n if (e.touches.length === 2 && touchState?.isPinching) {\n e.preventDefault();\n const t1 = e.touches[0];\n const t2 = e.touches[1];\n const dist = Math.hypot(\n t1.clientX - t2.clientX,\n t1.clientY - t2.clientY\n );\n\n const scale = dist / touchState.initialDistance;\n setZoom(Math.max(0.1, Math.min(10, touchState.initialZoom * scale)));\n\n // Optional: Handle pan during pinch (using midpoint delta)\n // const midX = (t1.clientX + t2.clientX) / 2;\n // const midY = (t1.clientY + t2.clientY) / 2;\n // const dx = midX - touchState.midPoint.x;\n // const dy = midY - touchState.midPoint.y;\n // setPan({\n // x: touchState.initialPan.x + dx,\n // y: touchState.initialPan.y + dy\n // });\n } else if (e.touches.length === 1 && isDragging) {\n e.preventDefault(); // Prevent scrolling\n const t = e.touches[0];\n const dx = t.clientX - dragStart.x;\n const dy = t.clientY - dragStart.y;\n setPan((p) => ({ x: p.x + dx, y: p.y + dy }));\n setDragStart({ x: t.clientX, y: t.clientY });\n }\n },\n [touchState, isDragging, dragStart]\n );\n\n const handleTouchEnd = useCallback(() => {\n setTouchState(null);\n setIsDragging(false);\n }, []);\n\n // Mouse drag\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n setDragStart({ x: e.clientX, y: e.clientY });\n setIsDragging(true);\n }, []);\n\n const handleMouseMove = useCallback(\n (e: React.MouseEvent) => {\n if (isDragging) {\n const dx = e.clientX - dragStart.x;\n const dy = e.clientY - dragStart.y;\n setPan((p) => ({ x: p.x + dx, y: p.y + dy }));\n setDragStart({ x: e.clientX, y: e.clientY });\n }\n },\n [isDragging, dragStart]\n );\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n // Reset view on double click\n const handleDoubleClick = useCallback(() => {\n setZoom(1);\n setPan({ x: 0, y: 0 });\n setRotation(0);\n }, []);\n\n // Attach event listeners\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n // Passive: false is important for preventing default scroll on touch\n canvas.addEventListener(\"wheel\", handleWheel, { passive: false });\n canvas.addEventListener(\"touchstart\", handleTouchStart, { passive: false });\n canvas.addEventListener(\"touchmove\", handleTouchMove, { passive: false });\n canvas.addEventListener(\"touchend\", handleTouchEnd);\n\n return () => {\n canvas.removeEventListener(\"wheel\", handleWheel);\n canvas.removeEventListener(\"touchstart\", handleTouchStart);\n canvas.removeEventListener(\"touchmove\", handleTouchMove);\n canvas.removeEventListener(\"touchend\", handleTouchEnd);\n };\n }, [handleWheel, handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n return (\n <div\n ref={containerRef}\n className={`${className} relative h-full w-full overflow-hidden`}\n >\n <canvas\n ref={canvasRef}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n onDoubleClick={handleDoubleClick}\n className={`w-[100dvw] h-[100dvh] transition-opacity duration-200 ${\n isImageLoaded ? \"opacity-100\" : \"opacity-0\"\n } ${isDragging ? \"cursor-grabbing\" : \"cursor-grab\"} touch-none`}\n />\n\n {/* Rotation Controls */}\n <div\n className=\"absolute left-2 flex items-center gap-2 opacity-0 hover:opacity-100 transition-opacity duration-200 transition-all duration-300 ease-in-out\"\n style={{ bottom: `${controlsBottomOffset}px` }}\n >\n <Button\n onClick={(e) => {\n e.stopPropagation();\n setRotation((prev) => (prev - 90) % 360);\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title=\"Rotate Counter-clockwise\"\n >\n <RotateCcw className=\"w-4 h-4 text-muted-foreground\" />\n </Button>\n <Button\n onClick={(e) => {\n e.stopPropagation();\n setRotation((prev) => (prev + 90) % 360);\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title=\"Rotate Clockwise\"\n >\n <RotateCw className=\"w-4 h-4 text-muted-foreground\" />\n </Button>\n </div>\n\n {/* Zoom indicator and Help */}\n <div\n className=\"absolute right-2 flex items-center gap-2 transition-all duration-300 ease-in-out\"\n style={{ bottom: `${controlsBottomOffset}px` }}\n >\n {/* Action Buttons */}\n {actions.map((action, idx) => (\n <Button\n key={idx}\n onClick={(e) => {\n e.stopPropagation();\n action.onClick();\n }}\n className=\"h-8 w-8 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center hover:bg-primary/20 transition-all duration-200\"\n title={action.label}\n >\n {action.icon}\n </Button>\n ))}\n\n <div className=\"h-8 ring-1 ring-foreground/10 bg-background/90 backdrop-blur-sm px-3 py-1.5 text-xs text-muted-foreground pointer-events-none border border-border/50 transition-opacity duration-0 items-center justify-center flex\">\n {Math.round(zoom * 100)}%\n </div>\n\n {/* Help icon */}\n <div className=\"relative\">\n <div\n onMouseEnter={() => setShowHelp(true)}\n onMouseLeave={() => setShowHelp(false)}\n className=\"w-8 h-8 ring-1 ring-foreground/10 bg-background/90 backdrop-blur-sm border border-border/50 flex items-center justify-center cursor-help transition-all duration-0 hover:bg-primary/20\"\n >\n <span className=\"text-xs text-muted-foreground font-medium\">?</span>\n </div>\n\n {/* Help tooltip */}\n {showHelp && (\n <div className=\"absolute bottom-full right-0 mb-2 w-64 bg-background/95 backdrop-blur-sm border border-border p-3 text-xs text-muted-foreground shadow-lg\">\n <div className=\"space-y-1\">\n <div>\n <span className=\"text-foreground\">Scroll/Pinch:</span> Zoom\n in/out\n </div>\n <div>\n <span className=\"text-foreground\">Drag:</span> Pan around\n image\n </div>\n <div>\n <span className=\"text-foreground\">Double-click:</span> Reset\n view\n </div>\n <div>\n <span className=\"text-foreground\">Escape:</span> Close dialog\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"names":["PannableImage","src","className","isOpen","actions","controlsBottomOffset","canvasRef","useRef","containerRef","imageRef","isDragging","setIsDragging","useState","zoom","setZoom","zoomRef","pan","setPan","panRef","rotation","setRotation","rotationRef","dragStart","setDragStart","isImageLoaded","setIsImageLoaded","showHelp","setShowHelp","drawImage","useCallback","canvas","ctx","dpr","img","r","isRotated","canvasAspect","imageAspect","fitWidth","fitHeight","p","drawWidth","drawHeight","ensureCanvasSize","attempts","maxAttempts","trySet","rect","handleResize","useEffect","resizeObserver","handleWheel","mouseX","mouseY","cx","cy","rx","ry","delta","newZoom","zoomFactor","newPanX","newPanY","touchState","setTouchState","handleTouchStart","t1","t2","dist","midX","midY","handleTouchMove","scale","dx","dy","handleTouchEnd","handleMouseDown","handleMouseMove","handleMouseUp","handleDoubleClick","jsxs","jsx","Button","prev","RotateCcw","RotateCw","action","idx","e"],"mappings":"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"}