@giddaa-housing/ui 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/giddaa.css +12 -2
  3. package/dist/accordion.d.ts +9 -10
  4. package/dist/accordion.js +41 -87
  5. package/dist/activity-timeline.d.ts +12 -16
  6. package/dist/activity-timeline.js +83 -198
  7. package/dist/alert.d.ts +8 -9
  8. package/dist/alert.js +53 -111
  9. package/dist/auth-layout.d.ts +4 -4
  10. package/dist/auth-layout.js +143 -294
  11. package/dist/avatar.d.ts +6 -6
  12. package/dist/avatar.js +49 -19
  13. package/dist/badge.d.ts +12 -14
  14. package/dist/badge.js +71 -11
  15. package/dist/bar-chart.d.ts +65 -67
  16. package/dist/bar-chart.js +232 -207
  17. package/dist/breadcrumb.d.ts +5 -5
  18. package/dist/breadcrumb.js +56 -118
  19. package/dist/bullet-chart.d.ts +41 -37
  20. package/dist/bullet-chart.js +125 -148
  21. package/dist/button-BZIeyUw6.d.ts +17 -0
  22. package/dist/button-group.d.ts +13 -16
  23. package/dist/button-group.js +39 -88
  24. package/dist/button.d.ts +2 -19
  25. package/dist/button.js +94 -13
  26. package/dist/calendar.d.ts +6 -6
  27. package/dist/calendar.js +138 -17
  28. package/dist/card.d.ts +14 -16
  29. package/dist/card.js +59 -145
  30. package/dist/carousel.d.ts +34 -35
  31. package/dist/carousel.js +335 -20
  32. package/dist/chart.d.ts +90 -63
  33. package/dist/chart.js +573 -28
  34. package/dist/checkbox.d.ts +10 -12
  35. package/dist/checkbox.js +82 -47
  36. package/dist/cn-BI_4DMBf.js +23 -0
  37. package/dist/collapsible.d.ts +7 -8
  38. package/dist/collapsible.js +22 -47
  39. package/dist/combobox.d.ts +10 -10
  40. package/dist/combobox.js +236 -44
  41. package/dist/cta.d.ts +12 -14
  42. package/dist/cta.js +175 -341
  43. package/dist/currency-selector.d.ts +31 -32
  44. package/dist/currency-selector.js +106 -184
  45. package/dist/data-table.d.ts +168 -0
  46. package/dist/data-table.js +676 -0
  47. package/dist/date-picker.d.ts +22 -23
  48. package/dist/date-picker.js +119 -192
  49. package/dist/details-card.d.ts +7 -7
  50. package/dist/details-card.js +104 -253
  51. package/dist/dialog.d.ts +13 -14
  52. package/dist/dialog.js +116 -209
  53. package/dist/dropdown-menu.d.ts +13 -13
  54. package/dist/dropdown-menu.js +180 -37
  55. package/dist/dropzone.d.ts +55 -55
  56. package/dist/dropzone.js +327 -439
  57. package/dist/editorial-card.d.ts +23 -25
  58. package/dist/editorial-card.js +129 -296
  59. package/dist/empty-state.d.ts +8 -9
  60. package/dist/empty-state.js +48 -105
  61. package/dist/field.d.ts +23 -25
  62. package/dist/field.js +110 -221
  63. package/dist/filter.d.ts +118 -0
  64. package/dist/filter.js +775 -0
  65. package/dist/footer.d.ts +8 -15
  66. package/dist/footer.js +197 -400
  67. package/dist/funnel-chart.d.ts +49 -48
  68. package/dist/funnel-chart.js +170 -189
  69. package/dist/gallery-indicator.d.ts +11 -12
  70. package/dist/gallery-indicator.js +75 -12
  71. package/dist/heatmap-chart.d.ts +47 -50
  72. package/dist/heatmap-chart.js +186 -237
  73. package/dist/infotip.d.ts +8 -9
  74. package/dist/infotip.js +33 -59
  75. package/dist/input-CfoEJ8A6.d.ts +12 -0
  76. package/dist/input-group.d.ts +16 -20
  77. package/dist/input-group.js +99 -23
  78. package/dist/input-size-context-C-SFx9sx.d.ts +10 -0
  79. package/dist/input-size-context.d.ts +2 -11
  80. package/dist/input-size-context.js +17 -9
  81. package/dist/input.d.ts +2 -13
  82. package/dist/input.js +27 -11
  83. package/dist/item.d.ts +7 -8
  84. package/dist/item.js +22 -59
  85. package/dist/kpi-card.d.ts +18 -20
  86. package/dist/kpi-card.js +84 -192
  87. package/dist/label.d.ts +6 -6
  88. package/dist/label.js +40 -8
  89. package/dist/line-chart.d.ts +200 -129
  90. package/dist/line-chart.js +330 -105
  91. package/dist/list-item.d.ts +22 -0
  92. package/dist/list-item.js +84 -0
  93. package/dist/logo.d.ts +4 -4
  94. package/dist/logo.js +92 -9
  95. package/dist/map-indicator.d.ts +7 -7
  96. package/dist/map-indicator.js +80 -106
  97. package/dist/match.d.ts +10 -11
  98. package/dist/match.js +62 -107
  99. package/dist/media-gallery-hero.d.ts +40 -42
  100. package/dist/media-gallery-hero.js +182 -343
  101. package/dist/media-player.d.ts +17 -17
  102. package/dist/media-player.js +873 -1348
  103. package/dist/multi-step-form.d.ts +56 -0
  104. package/dist/multi-step-form.js +342 -0
  105. package/dist/number-input.d.ts +34 -34
  106. package/dist/number-input.js +64 -117
  107. package/dist/page-header.d.ts +10 -11
  108. package/dist/page-header.js +34 -79
  109. package/dist/pagination.d.ts +17 -21
  110. package/dist/pagination.js +132 -207
  111. package/dist/password-input.d.ts +5 -13
  112. package/dist/password-input.js +31 -55
  113. package/dist/phone-input.d.ts +19 -20
  114. package/dist/phone-input.js +226 -344
  115. package/dist/photo-gallery.d.ts +19 -19
  116. package/dist/photo-gallery.js +313 -449
  117. package/dist/picker-lzgmsNfG.js +32 -0
  118. package/dist/pie-chart.d.ts +121 -90
  119. package/dist/pie-chart.js +183 -149
  120. package/dist/popover.d.ts +9 -9
  121. package/dist/popover.js +72 -23
  122. package/dist/price-tag.d.ts +26 -27
  123. package/dist/price-tag.js +113 -173
  124. package/dist/progress.d.ts +16 -17
  125. package/dist/progress.js +169 -24
  126. package/dist/property-listing-card.d.ts +14 -17
  127. package/dist/property-listing-card.js +102 -220
  128. package/dist/purchase-option-card.d.ts +79 -0
  129. package/dist/purchase-option-card.js +176 -0
  130. package/dist/radar-chart.d.ts +29 -31
  131. package/dist/radar-chart.js +162 -137
  132. package/dist/radio-group.d.ts +11 -13
  133. package/dist/radio-group.js +46 -60
  134. package/dist/review-block.d.ts +14 -16
  135. package/dist/review-block.js +154 -10
  136. package/dist/rich-text-editor.d.ts +30 -14
  137. package/dist/rich-text-editor.js +592 -716
  138. package/dist/scatter-chart.d.ts +45 -47
  139. package/dist/scatter-chart.js +236 -240
  140. package/dist/search-input.d.ts +8 -16
  141. package/dist/search-input.js +57 -109
  142. package/dist/select.d.ts +8 -8
  143. package/dist/select.js +144 -27
  144. package/dist/separator.d.ts +8 -9
  145. package/dist/separator.js +32 -8
  146. package/dist/sheet.d.ts +11 -11
  147. package/dist/sheet.js +103 -24
  148. package/dist/sidebar.d.ts +32 -37
  149. package/dist/sidebar.js +364 -634
  150. package/dist/size-context-D4mYvcg8.d.ts +10 -0
  151. package/dist/size-context.d.ts +2 -11
  152. package/dist/size-context.js +17 -9
  153. package/dist/skeleton.d.ts +4 -5
  154. package/dist/skeleton.js +12 -8
  155. package/dist/slider.d.ts +8 -9
  156. package/dist/slider.js +64 -135
  157. package/dist/sparkline.d.ts +68 -58
  158. package/dist/sparkline.js +315 -251
  159. package/dist/stepper.d.ts +23 -24
  160. package/dist/stepper.js +149 -246
  161. package/dist/styles.css +1004 -116
  162. package/dist/switch.d.ts +10 -12
  163. package/dist/switch.js +48 -70
  164. package/dist/table-card.d.ts +35 -0
  165. package/dist/table-card.js +125 -0
  166. package/dist/table.d.ts +18 -14
  167. package/dist/table.js +117 -154
  168. package/dist/tabs.d.ts +33 -15
  169. package/dist/tabs.js +110 -18
  170. package/dist/tag.d.ts +21 -23
  171. package/dist/tag.js +103 -159
  172. package/dist/testimonial-block.d.ts +18 -19
  173. package/dist/testimonial-block.js +189 -358
  174. package/dist/textarea-IS_D8pXf.d.ts +11 -0
  175. package/dist/textarea.d.ts +2 -12
  176. package/dist/textarea.js +24 -11
  177. package/dist/time-picker.d.ts +11 -11
  178. package/dist/time-picker.js +245 -302
  179. package/dist/toast.d.ts +16 -18
  180. package/dist/toast.js +154 -205
  181. package/dist/tooltip.d.ts +8 -9
  182. package/dist/tooltip.js +37 -12
  183. package/dist/tree-map.d.ts +59 -62
  184. package/dist/tree-map.js +226 -269
  185. package/dist/use-uncontrolled-CLfM1XbB.js +21 -0
  186. package/dist/waterfall-chart.d.ts +94 -97
  187. package/dist/waterfall-chart.js +455 -552
  188. package/package.json +36 -9
  189. package/dist/accordion.js.map +0 -1
  190. package/dist/activity-timeline.js.map +0 -1
  191. package/dist/alert.js.map +0 -1
  192. package/dist/auth-layout.js.map +0 -1
  193. package/dist/avatar.js.map +0 -1
  194. package/dist/badge.js.map +0 -1
  195. package/dist/bar-chart.js.map +0 -1
  196. package/dist/breadcrumb.js.map +0 -1
  197. package/dist/bullet-chart.js.map +0 -1
  198. package/dist/button-group.js.map +0 -1
  199. package/dist/button.js.map +0 -1
  200. package/dist/calendar.js.map +0 -1
  201. package/dist/card.js.map +0 -1
  202. package/dist/carousel.js.map +0 -1
  203. package/dist/chart.js.map +0 -1
  204. package/dist/checkbox.js.map +0 -1
  205. package/dist/chunk-322YCNVL.js +0 -278
  206. package/dist/chunk-322YCNVL.js.map +0 -1
  207. package/dist/chunk-3ACQVT7A.js +0 -25
  208. package/dist/chunk-3ACQVT7A.js.map +0 -1
  209. package/dist/chunk-3T65TLJX.js +0 -334
  210. package/dist/chunk-3T65TLJX.js.map +0 -1
  211. package/dist/chunk-6ZSGQHH2.js +0 -192
  212. package/dist/chunk-6ZSGQHH2.js.map +0 -1
  213. package/dist/chunk-7TBMLFGW.js +0 -41
  214. package/dist/chunk-7TBMLFGW.js.map +0 -1
  215. package/dist/chunk-B4H6RNDH.js +0 -135
  216. package/dist/chunk-B4H6RNDH.js.map +0 -1
  217. package/dist/chunk-BUXCGZ6X.js +0 -219
  218. package/dist/chunk-BUXCGZ6X.js.map +0 -1
  219. package/dist/chunk-CHII2QHH.js +0 -58
  220. package/dist/chunk-CHII2QHH.js.map +0 -1
  221. package/dist/chunk-DMNOXRRW.js +0 -147
  222. package/dist/chunk-DMNOXRRW.js.map +0 -1
  223. package/dist/chunk-EFSOSSIC.js +0 -130
  224. package/dist/chunk-EFSOSSIC.js.map +0 -1
  225. package/dist/chunk-FZDSVMKY.js +0 -363
  226. package/dist/chunk-FZDSVMKY.js.map +0 -1
  227. package/dist/chunk-GJOFIJS3.js +0 -246
  228. package/dist/chunk-GJOFIJS3.js.map +0 -1
  229. package/dist/chunk-HL3ZSYES.js +0 -23
  230. package/dist/chunk-HL3ZSYES.js.map +0 -1
  231. package/dist/chunk-JVLUBAPB.js +0 -129
  232. package/dist/chunk-JVLUBAPB.js.map +0 -1
  233. package/dist/chunk-KDPYSOYZ.js +0 -64
  234. package/dist/chunk-KDPYSOYZ.js.map +0 -1
  235. package/dist/chunk-KSMDANKI.js +0 -43
  236. package/dist/chunk-KSMDANKI.js.map +0 -1
  237. package/dist/chunk-MEKCCOP5.js +0 -46
  238. package/dist/chunk-MEKCCOP5.js.map +0 -1
  239. package/dist/chunk-NOFXVRWL.js +0 -451
  240. package/dist/chunk-NOFXVRWL.js.map +0 -1
  241. package/dist/chunk-PC5MHNVA.js +0 -171
  242. package/dist/chunk-PC5MHNVA.js.map +0 -1
  243. package/dist/chunk-QKAQZ2GU.js +0 -122
  244. package/dist/chunk-QKAQZ2GU.js.map +0 -1
  245. package/dist/chunk-QZHSHSVV.js +0 -26
  246. package/dist/chunk-QZHSHSVV.js.map +0 -1
  247. package/dist/chunk-RBMK26XD.js +0 -19
  248. package/dist/chunk-RBMK26XD.js.map +0 -1
  249. package/dist/chunk-SFNJGF6M.js +0 -262
  250. package/dist/chunk-SFNJGF6M.js.map +0 -1
  251. package/dist/chunk-UJJNLGTM.js +0 -112
  252. package/dist/chunk-UJJNLGTM.js.map +0 -1
  253. package/dist/chunk-VGR4ZWJ3.js +0 -418
  254. package/dist/chunk-VGR4ZWJ3.js.map +0 -1
  255. package/dist/chunk-XG47P6D4.js +0 -99
  256. package/dist/chunk-XG47P6D4.js.map +0 -1
  257. package/dist/chunk-XZZAHNVM.js +0 -21
  258. package/dist/chunk-XZZAHNVM.js.map +0 -1
  259. package/dist/chunk-Y4TTYVNE.js +0 -36
  260. package/dist/chunk-Y4TTYVNE.js.map +0 -1
  261. package/dist/chunk-YDWIHW6Q.js +0 -69
  262. package/dist/chunk-YDWIHW6Q.js.map +0 -1
  263. package/dist/collapsible.js.map +0 -1
  264. package/dist/combobox.js.map +0 -1
  265. package/dist/cta.js.map +0 -1
  266. package/dist/currency-selector.js.map +0 -1
  267. package/dist/date-picker.js.map +0 -1
  268. package/dist/details-card.js.map +0 -1
  269. package/dist/dialog.js.map +0 -1
  270. package/dist/dropdown-menu.js.map +0 -1
  271. package/dist/dropzone.js.map +0 -1
  272. package/dist/editorial-card.js.map +0 -1
  273. package/dist/empty-state.js.map +0 -1
  274. package/dist/field.js.map +0 -1
  275. package/dist/footer.js.map +0 -1
  276. package/dist/funnel-chart.js.map +0 -1
  277. package/dist/gallery-indicator.js.map +0 -1
  278. package/dist/heatmap-chart.js.map +0 -1
  279. package/dist/infotip.js.map +0 -1
  280. package/dist/input-group.js.map +0 -1
  281. package/dist/input-size-context.js.map +0 -1
  282. package/dist/input.js.map +0 -1
  283. package/dist/item.js.map +0 -1
  284. package/dist/kpi-card.js.map +0 -1
  285. package/dist/label.js.map +0 -1
  286. package/dist/line-chart.js.map +0 -1
  287. package/dist/logo.js.map +0 -1
  288. package/dist/map-indicator.js.map +0 -1
  289. package/dist/match.js.map +0 -1
  290. package/dist/media-gallery-hero.js.map +0 -1
  291. package/dist/media-player.js.map +0 -1
  292. package/dist/number-input.js.map +0 -1
  293. package/dist/page-header.js.map +0 -1
  294. package/dist/pagination.js.map +0 -1
  295. package/dist/password-input.js.map +0 -1
  296. package/dist/phone-input.js.map +0 -1
  297. package/dist/photo-gallery.js.map +0 -1
  298. package/dist/pie-chart.js.map +0 -1
  299. package/dist/popover.js.map +0 -1
  300. package/dist/price-tag.js.map +0 -1
  301. package/dist/progress.js.map +0 -1
  302. package/dist/property-listing-card.js.map +0 -1
  303. package/dist/radar-chart.js.map +0 -1
  304. package/dist/radio-group.js.map +0 -1
  305. package/dist/review-block.js.map +0 -1
  306. package/dist/rich-text-editor.js.map +0 -1
  307. package/dist/scatter-chart.js.map +0 -1
  308. package/dist/search-input.js.map +0 -1
  309. package/dist/select.js.map +0 -1
  310. package/dist/separator.js.map +0 -1
  311. package/dist/sheet.js.map +0 -1
  312. package/dist/sidebar.js.map +0 -1
  313. package/dist/size-context.js.map +0 -1
  314. package/dist/skeleton.js.map +0 -1
  315. package/dist/slider.js.map +0 -1
  316. package/dist/sparkline.js.map +0 -1
  317. package/dist/stepper.js.map +0 -1
  318. package/dist/switch.js.map +0 -1
  319. package/dist/tab-list.d.ts +0 -38
  320. package/dist/tab-list.js +0 -123
  321. package/dist/tab-list.js.map +0 -1
  322. package/dist/table.js.map +0 -1
  323. package/dist/tabs.js.map +0 -1
  324. package/dist/tag.js.map +0 -1
  325. package/dist/testimonial-block.js.map +0 -1
  326. package/dist/textarea.js.map +0 -1
  327. package/dist/time-picker.js.map +0 -1
  328. package/dist/toast.js.map +0 -1
  329. package/dist/tooltip.js.map +0 -1
  330. package/dist/tree-map.js.map +0 -1
  331. package/dist/waterfall-chart.js.map +0 -1
@@ -1,460 +1,324 @@
1
1
  "use client";
2
- import {
3
- Button
4
- } from "./chunk-B4H6RNDH.js";
5
- import {
6
- Carousel,
7
- CarouselContent,
8
- CarouselItem
9
- } from "./chunk-FZDSVMKY.js";
10
- import "./chunk-HL3ZSYES.js";
11
- import {
12
- cn
13
- } from "./chunk-Y4TTYVNE.js";
14
-
15
- // src/photo-gallery.tsx
16
- import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
17
- import {
18
- ChevronLeftIcon,
19
- ChevronRightIcon,
20
- Fullscreen,
21
- XIcon
22
- } from "lucide-react";
23
- import * as React from "react";
2
+ import { t as cn } from "./cn-BI_4DMBf.js";
3
+ import { Button } from "./button.js";
4
+ import { Carousel, CarouselContent, CarouselItem } from "./carousel.js";
5
+ import { ChevronLeftIcon, ChevronRightIcon, Fullscreen, XIcon } from "lucide-react";
24
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import * as React from "react";
8
+ import { Dialog } from "@base-ui/react/dialog";
9
+ //#region src/photo-gallery.tsx
10
+ /**
11
+ * Wires an Embla carousel to a controlled/uncontrolled active index. Returns
12
+ * the `setApi` to hand to {@link Carousel} plus the live index and navigation
13
+ * helpers. Both surfaces share this so the inline carousel and the fullscreen
14
+ * viewer can stand alone — or stay in sync by sharing `index`/`onIndexChange`.
15
+ */
25
16
  function useGalleryCarousel(index, onIndexChange) {
26
- const [api, setApi] = React.useState();
27
- const [selectedIndex, setSelectedIndex] = React.useState(index ?? 0);
28
- const initialIndexRef = React.useRef(index ?? 0);
29
- const onIndexChangeRef = React.useRef(onIndexChange);
30
- React.useEffect(() => {
31
- onIndexChangeRef.current = onIndexChange;
32
- });
33
- React.useEffect(() => {
34
- if (!api) return;
35
- const onSelect = () => {
36
- const next = api.selectedScrollSnap();
37
- setSelectedIndex(next);
38
- onIndexChangeRef.current?.(next);
39
- };
40
- onSelect();
41
- api.on("select", onSelect).on("reInit", onSelect);
42
- return () => {
43
- api.off("select", onSelect).off("reInit", onSelect);
44
- };
45
- }, [api]);
46
- React.useEffect(() => {
47
- if (api && index !== void 0 && index !== api.selectedScrollSnap()) {
48
- api.scrollTo(index, false);
49
- }
50
- }, [api, index]);
51
- const scrollTo = React.useCallback(
52
- (i) => api?.scrollTo(i, false),
53
- [api]
54
- );
55
- const scrollPrev = React.useCallback(() => api?.scrollPrev(false), [api]);
56
- const scrollNext = React.useCallback(() => api?.scrollNext(false), [api]);
57
- return {
58
- setApi,
59
- selectedIndex,
60
- initialIndex: initialIndexRef.current,
61
- scrollTo,
62
- scrollPrev,
63
- scrollNext
64
- };
17
+ const [api, setApi] = React.useState();
18
+ const [selectedIndex, setSelectedIndex] = React.useState(index ?? 0);
19
+ const initialIndexRef = React.useRef(index ?? 0);
20
+ const onIndexChangeRef = React.useRef(onIndexChange);
21
+ React.useEffect(() => {
22
+ onIndexChangeRef.current = onIndexChange;
23
+ });
24
+ React.useEffect(() => {
25
+ if (!api) return;
26
+ const onSelect = () => {
27
+ const next = api.selectedScrollSnap();
28
+ setSelectedIndex(next);
29
+ onIndexChangeRef.current?.(next);
30
+ };
31
+ onSelect();
32
+ api.on("select", onSelect).on("reInit", onSelect);
33
+ return () => {
34
+ api.off("select", onSelect).off("reInit", onSelect);
35
+ };
36
+ }, [api]);
37
+ React.useEffect(() => {
38
+ if (api && index !== void 0 && index !== api.selectedScrollSnap()) api.scrollTo(index, false);
39
+ }, [api, index]);
40
+ const scrollTo = React.useCallback((i) => api?.scrollTo(i, false), [api]);
41
+ const scrollPrev = React.useCallback(() => api?.scrollPrev(false), [api]);
42
+ const scrollNext = React.useCallback(() => api?.scrollNext(false), [api]);
43
+ return {
44
+ setApi,
45
+ selectedIndex,
46
+ initialIndex: initialIndexRef.current,
47
+ scrollTo,
48
+ scrollPrev,
49
+ scrollNext
50
+ };
65
51
  }
66
- function GalleryFrame({
67
- image,
68
- fit = "cover",
69
- className
70
- }) {
71
- return /* @__PURE__ */ jsx(
72
- "div",
73
- {
74
- "data-slot": "photo-gallery-frame",
75
- className: cn(
76
- "relative flex size-full items-center justify-center overflow-hidden",
77
- className
78
- ),
79
- children: image?.src ? /* @__PURE__ */ jsx(
80
- "img",
81
- {
82
- src: image.src,
83
- alt: image.alt ?? "Property image",
84
- className: cn(
85
- fit === "contain" ? "max-h-full max-w-full rounded-lg object-contain" : "size-full object-cover"
86
- ),
87
- draggable: false
88
- }
89
- ) : /* @__PURE__ */ jsx("span", { className: "text-gdt-sm font-medium text-fg-caption-placeholder", children: "Property Image" })
90
- }
91
- );
52
+ /**
53
+ * The image surface. Centres its image within the slide; falls back to a
54
+ * "Property Image" label when `src` is missing. `cover` fills and crops the
55
+ * frame for the listing hero; `contain` clamps the photo to the frame's bounds
56
+ * (`max-w`/`max-h`) so the whole image stays visible — never overflowing the
57
+ * fullscreen viewer's chrome and never stretched out of its aspect ratio.
58
+ */
59
+ function GalleryFrame({ image, fit = "cover", className }) {
60
+ return /* @__PURE__ */ jsx("div", {
61
+ "data-slot": "photo-gallery-frame",
62
+ className: cn("relative flex size-full items-center justify-center overflow-hidden", className),
63
+ children: image?.src ? /* @__PURE__ */ jsx("img", {
64
+ src: image.src,
65
+ alt: image.alt ?? "Property image",
66
+ className: cn(fit === "contain" ? "max-h-full max-w-full rounded-lg object-contain" : "size-full object-cover"),
67
+ draggable: false
68
+ }) : /* @__PURE__ */ jsx("span", {
69
+ className: "text-gdt-sm font-medium text-fg-caption-placeholder",
70
+ children: "Property Image"
71
+ })
72
+ });
92
73
  }
93
- var Images = (props) => /* @__PURE__ */ jsxs(
94
- "svg",
95
- {
96
- "aria-hidden": "true",
97
- xmlns: "http://www.w3.org/2000/svg",
98
- width: 15,
99
- height: 16,
100
- viewBox: "0 0 15 16",
101
- fill: "none",
102
- ...props,
103
- children: [
104
- /* @__PURE__ */ jsx(
105
- "path",
106
- {
107
- fill: "currentColor",
108
- d: "M6.72 14.332c-.705 0-1.38-.3-1.878-.83a2.935 2.935 0 0 1-.779-2.003V2.012l-3.02.738c-.36.102-.667.353-.853.697a1.587 1.587 0 0 0-.143 1.136l2.589 10.309c.083.318.261.598.507.798.246.2.546.309.856.31.115 0 .233-.015.349-.048l6.3-1.62H6.72ZM8.125 6c.69 0 1.25-.597 1.25-1.333 0-.735-.56-1.333-1.25-1.333s-1.25.598-1.25 1.333c0 .736.56 1.333 1.25 1.333Z"
109
- }
110
- ),
111
- /* @__PURE__ */ jsx(
112
- "path",
113
- {
114
- fill: "currentColor",
115
- d: "M15 2a2.07 2.07 0 0 0-.55-1.414A1.818 1.818 0 0 0 13.126 0h-6.25C6.376 0 5.9.21 5.547.586A2.07 2.07 0 0 0 4.998 2v9.332c0 .53.198 1.04.55 1.414.352.375.829.586 1.326.586h6.25c.498 0 .975-.21 1.327-.586.351-.375.549-.883.549-1.414V2Zm-8.126-.667h6.25c.166 0 .325.07.443.195A.69.69 0 0 1 13.75 2v4.292l-.475-.507a1.094 1.094 0 0 0-.356-.253 1.037 1.037 0 0 0-.839 0 1.094 1.094 0 0 0-.355.253L8.749 8.96l-.787-.84a1.094 1.094 0 0 0-.356-.254 1.037 1.037 0 0 0-.839 0 1.094 1.094 0 0 0-.355.254l-.163.173V2a.69.69 0 0 1 .183-.472.606.606 0 0 1 .442-.195Z"
116
- }
117
- )
118
- ]
119
- }
120
- );
121
- function GalleryCounter({
122
- current,
123
- total,
124
- className
125
- }) {
126
- if (total <= 1) return null;
127
- return /* @__PURE__ */ jsxs(
128
- "div",
129
- {
130
- "data-slot": "photo-gallery-counter",
131
- className: cn(
132
- "pointer-events-none absolute z-10 inline-flex items-center gap-1.5 rounded-full border border-line bg-surface-overlay px-2.5 py-1 text-gdt-xs font-bold text-fg-primary shadow-2",
133
- className
134
- ),
135
- children: [
136
- /* @__PURE__ */ jsx(Images, { "aria-hidden": "true", className: "size-3.5" }),
137
- /* @__PURE__ */ jsxs("span", { children: [
138
- current,
139
- " / ",
140
- total
141
- ] })
142
- ]
143
- }
144
- );
74
+ const Images = (props) => /* @__PURE__ */ jsxs("svg", {
75
+ "aria-hidden": "true",
76
+ xmlns: "http://www.w3.org/2000/svg",
77
+ width: 15,
78
+ height: 16,
79
+ viewBox: "0 0 15 16",
80
+ fill: "none",
81
+ ...props,
82
+ children: [/* @__PURE__ */ jsx("path", {
83
+ fill: "currentColor",
84
+ d: "M6.72 14.332c-.705 0-1.38-.3-1.878-.83a2.935 2.935 0 0 1-.779-2.003V2.012l-3.02.738c-.36.102-.667.353-.853.697a1.587 1.587 0 0 0-.143 1.136l2.589 10.309c.083.318.261.598.507.798.246.2.546.309.856.31.115 0 .233-.015.349-.048l6.3-1.62H6.72ZM8.125 6c.69 0 1.25-.597 1.25-1.333 0-.735-.56-1.333-1.25-1.333s-1.25.598-1.25 1.333c0 .736.56 1.333 1.25 1.333Z"
85
+ }), /* @__PURE__ */ jsx("path", {
86
+ fill: "currentColor",
87
+ d: "M15 2a2.07 2.07 0 0 0-.55-1.414A1.818 1.818 0 0 0 13.126 0h-6.25C6.376 0 5.9.21 5.547.586A2.07 2.07 0 0 0 4.998 2v9.332c0 .53.198 1.04.55 1.414.352.375.829.586 1.326.586h6.25c.498 0 .975-.21 1.327-.586.351-.375.549-.883.549-1.414V2Zm-8.126-.667h6.25c.166 0 .325.07.443.195A.69.69 0 0 1 13.75 2v4.292l-.475-.507a1.094 1.094 0 0 0-.356-.253 1.037 1.037 0 0 0-.839 0 1.094 1.094 0 0 0-.355.253L8.749 8.96l-.787-.84a1.094 1.094 0 0 0-.356-.254 1.037 1.037 0 0 0-.839 0 1.094 1.094 0 0 0-.355.254l-.163.173V2a.69.69 0 0 1 .183-.472.606.606 0 0 1 .442-.195Z"
88
+ })]
89
+ });
90
+ /** Pill overlay showing `current / total`. Hidden when there is one image. */
91
+ function GalleryCounter({ current, total, className }) {
92
+ if (total <= 1) return null;
93
+ return /* @__PURE__ */ jsxs("div", {
94
+ "data-slot": "photo-gallery-counter",
95
+ className: cn("pointer-events-none absolute z-10 inline-flex items-center gap-1.5 rounded-full border border-line bg-surface-overlay px-2.5 py-1 text-gdt-xs font-bold text-fg-primary shadow-2", className),
96
+ children: [/* @__PURE__ */ jsx(Images, {
97
+ "aria-hidden": "true",
98
+ className: "size-3.5"
99
+ }), /* @__PURE__ */ jsxs("span", { children: [
100
+ current,
101
+ " / ",
102
+ total
103
+ ] })]
104
+ });
145
105
  }
146
- function GalleryButton({
147
- className,
148
- variant = "ghost",
149
- ...rest
150
- }) {
151
- return /* @__PURE__ */ jsx(
152
- Button,
153
- {
154
- size: "icon",
155
- className: cn(
156
- "border border-line bg-surface-overlay text-fg-primary shadow-2 transition-[background-color] outline-none hover:bg-surface-raised focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] size-9 sm:size-11",
157
- className
158
- ),
159
- variant,
160
- ...rest
161
- }
162
- );
106
+ function GalleryButton({ className, variant = "ghost", ...rest }) {
107
+ return /* @__PURE__ */ jsx(Button, {
108
+ size: "icon",
109
+ className: cn("border border-line bg-surface-overlay text-fg-primary shadow-2 transition-[background-color] outline-none hover:bg-surface-raised focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] size-9 sm:size-11", className),
110
+ variant,
111
+ ...rest
112
+ });
163
113
  }
164
- function GalleryArrow({
165
- side,
166
- onClick,
167
- className
168
- }) {
169
- const Icon = side === "prev" ? ChevronLeftIcon : ChevronRightIcon;
170
- return /* @__PURE__ */ jsx(
171
- GalleryButton,
172
- {
173
- type: "button",
174
- "data-slot": `photo-gallery-${side}`,
175
- "aria-label": side === "prev" ? "Previous photo" : "Next photo",
176
- onClick: (event) => {
177
- event.stopPropagation();
178
- onClick();
179
- },
180
- className: cn(
181
- "absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center active:not-aria-[haspopup]:-translate-y-1/2",
182
- side === "prev" ? "left-2 sm:left-4" : "right-2 sm:right-4",
183
- className
184
- ),
185
- children: /* @__PURE__ */ jsx(Icon, { className: "cn-rtl-flip size-4 sm:size-5" })
186
- }
187
- );
114
+ /** Circular floating navigation button. Always present; the track loops. */
115
+ function GalleryArrow({ side, onClick, className }) {
116
+ const Icon = side === "prev" ? ChevronLeftIcon : ChevronRightIcon;
117
+ return /* @__PURE__ */ jsx(GalleryButton, {
118
+ type: "button",
119
+ "data-slot": `photo-gallery-${side}`,
120
+ "aria-label": side === "prev" ? "Previous photo" : "Next photo",
121
+ onClick: (event) => {
122
+ event.stopPropagation();
123
+ onClick();
124
+ },
125
+ className: cn("absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center active:not-aria-[haspopup]:-translate-y-1/2", side === "prev" ? "left-2 sm:left-4" : "right-2 sm:right-4", className),
126
+ children: /* @__PURE__ */ jsx(Icon, { className: "cn-rtl-flip size-4 sm:size-5" })
127
+ });
188
128
  }
189
- function GalleryThumbnails({
190
- images,
191
- selectedIndex,
192
- onSelect,
193
- colsClassName,
194
- className
195
- }) {
196
- const containerRef = React.useRef(null);
197
- const hasPositionedRef = React.useRef(false);
198
- const [overflowing, setOverflowing] = React.useState(false);
199
- React.useEffect(() => {
200
- const el = containerRef.current;
201
- if (!el) return;
202
- const update = () => setOverflowing(el.scrollWidth > el.clientWidth + 1);
203
- update();
204
- const observer = new ResizeObserver(update);
205
- observer.observe(el);
206
- return () => observer.disconnect();
207
- }, []);
208
- React.useEffect(() => {
209
- const active = containerRef.current?.children[selectedIndex];
210
- if (!active) return;
211
- active.scrollIntoView({
212
- behavior: hasPositionedRef.current ? "smooth" : "auto",
213
- inline: "center",
214
- block: "nearest"
215
- });
216
- hasPositionedRef.current = true;
217
- }, [selectedIndex]);
218
- if (images.length <= 1) return null;
219
- return /* @__PURE__ */ jsx(
220
- "div",
221
- {
222
- ref: containerRef,
223
- "data-slot": "photo-gallery-thumbnails",
224
- className: cn(
225
- "flex gap-2 overflow-x-auto [--gallery-gap:0.5rem] scrollbar-none [&::-webkit-scrollbar]:hidden",
226
- overflowing ? "justify-start" : "justify-center",
227
- colsClassName,
228
- className
229
- ),
230
- children: images.map((image, index) => {
231
- const isActive = index === selectedIndex;
232
- return /* @__PURE__ */ jsx(
233
- "button",
234
- {
235
- type: "button",
236
- "aria-label": `View photo ${index + 1}`,
237
- "aria-current": isActive,
238
- onClick: () => onSelect(index),
239
- style: {
240
- width: "calc((100% - (var(--gallery-cols) - 1) * var(--gallery-gap)) / var(--gallery-cols))"
241
- },
242
- className: cn(
243
- "relative aspect-4/3 shrink-0 overflow-hidden rounded-lg border-2 bg-surface-raised transition-[border-color,opacity] outline-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)]",
244
- isActive ? "border-line-focus" : "border-transparent opacity-80 hover:opacity-100"
245
- ),
246
- children: image.src ? /* @__PURE__ */ jsx(
247
- "img",
248
- {
249
- src: image.src,
250
- alt: image.alt ?? `Property image ${index + 1}`,
251
- className: "size-full object-cover",
252
- draggable: false
253
- }
254
- ) : null
255
- },
256
- index
257
- );
258
- })
259
- }
260
- );
129
+ /**
130
+ * Equal-sized thumbnail strip. `cols` are sized via CSS vars so exactly N fill
131
+ * the width (5 on mobile, more on web); extras overflow and scroll. The active
132
+ * thumb gets a 2px focus stroke and is kept in view as the index changes.
133
+ */
134
+ function GalleryThumbnails({ images, selectedIndex, onSelect, colsClassName, className }) {
135
+ const containerRef = React.useRef(null);
136
+ const hasPositionedRef = React.useRef(false);
137
+ const [overflowing, setOverflowing] = React.useState(false);
138
+ React.useEffect(() => {
139
+ const el = containerRef.current;
140
+ if (!el) return;
141
+ const update = () => setOverflowing(el.scrollWidth > el.clientWidth + 1);
142
+ update();
143
+ const observer = new ResizeObserver(update);
144
+ observer.observe(el);
145
+ return () => observer.disconnect();
146
+ }, []);
147
+ React.useEffect(() => {
148
+ const active = containerRef.current?.children[selectedIndex];
149
+ if (!active) return;
150
+ active.scrollIntoView({
151
+ behavior: hasPositionedRef.current ? "smooth" : "auto",
152
+ inline: "center",
153
+ block: "nearest"
154
+ });
155
+ hasPositionedRef.current = true;
156
+ }, [selectedIndex]);
157
+ if (images.length <= 1) return null;
158
+ return /* @__PURE__ */ jsx("div", {
159
+ ref: containerRef,
160
+ "data-slot": "photo-gallery-thumbnails",
161
+ className: cn("flex gap-2 overflow-x-auto [--gallery-gap:0.5rem] scrollbar-none [&::-webkit-scrollbar]:hidden", overflowing ? "justify-start" : "justify-center", colsClassName, className),
162
+ children: images.map((image, index) => {
163
+ const isActive = index === selectedIndex;
164
+ return /* @__PURE__ */ jsx("button", {
165
+ type: "button",
166
+ "aria-label": `View photo ${index + 1}`,
167
+ "aria-current": isActive,
168
+ onClick: () => onSelect(index),
169
+ style: { width: "calc((100% - (var(--gallery-cols) - 1) * var(--gallery-gap)) / var(--gallery-cols))" },
170
+ className: cn("relative aspect-4/3 shrink-0 overflow-hidden rounded-lg border-2 bg-surface-raised transition-[border-color,opacity] outline-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)]", isActive ? "border-line-focus" : "border-transparent opacity-80 hover:opacity-100"),
171
+ children: image.src ? /* @__PURE__ */ jsx("img", {
172
+ src: image.src,
173
+ alt: image.alt ?? `Property image ${index + 1}`,
174
+ className: "size-full object-cover",
175
+ draggable: false
176
+ }) : null
177
+ }, index);
178
+ })
179
+ });
261
180
  }
262
- function PhotoGallery({
263
- images,
264
- index,
265
- onIndexChange,
266
- onImageClick,
267
- className,
268
- ...props
269
- }) {
270
- const {
271
- setApi,
272
- selectedIndex,
273
- initialIndex,
274
- scrollTo,
275
- scrollPrev,
276
- scrollNext
277
- } = useGalleryCarousel(index, onIndexChange);
278
- const hasMany = images.length > 1;
279
- return /* @__PURE__ */ jsxs(
280
- "div",
281
- {
282
- "data-slot": "photo-gallery",
283
- className: cn(
284
- "flex w-full flex-col gap-3 rounded-2xl border border-line bg-surface p-3",
285
- className
286
- ),
287
- ...props,
288
- children: [
289
- /* @__PURE__ */ jsxs(
290
- Carousel,
291
- {
292
- imageSize: "full",
293
- setApi,
294
- opts: { loop: true, startIndex: initialIndex, watchDrag: hasMany },
295
- className: "aspect-video rounded-xl bg-surface-raised",
296
- children: [
297
- /* @__PURE__ */ jsx(CarouselContent, { children: images.map((image, i) => /* @__PURE__ */ jsx(
298
- CarouselItem,
299
- {
300
- children: /* @__PURE__ */ jsx(GalleryFrame, { image })
301
- },
302
- i
303
- )) }),
304
- onImageClick && /* @__PURE__ */ jsx(
305
- GalleryButton,
306
- {
307
- className: "absolute bottom-2 right-2 sm:bottom-4 sm:right-4",
308
- onClick: () => onImageClick(selectedIndex),
309
- children: /* @__PURE__ */ jsx(Fullscreen, { className: "size-4 md:size-5" })
310
- }
311
- ),
312
- /* @__PURE__ */ jsx(
313
- GalleryCounter,
314
- {
315
- current: selectedIndex + 1,
316
- total: images.length,
317
- className: "top-2 right-2 sm:top-4 md:right-4"
318
- }
319
- ),
320
- hasMany && /* @__PURE__ */ jsxs(Fragment, { children: [
321
- /* @__PURE__ */ jsx(GalleryArrow, { side: "prev", onClick: scrollPrev }),
322
- /* @__PURE__ */ jsx(GalleryArrow, { side: "next", onClick: scrollNext })
323
- ] })
324
- ]
325
- }
326
- ),
327
- /* @__PURE__ */ jsx(
328
- GalleryThumbnails,
329
- {
330
- images,
331
- selectedIndex,
332
- onSelect: scrollTo,
333
- colsClassName: "[--gallery-cols:5] sm:[--gallery-cols:8]"
334
- }
335
- )
336
- ]
337
- }
338
- );
181
+ /**
182
+ * Inline property gallery: a swipeable hero image (drag / touch / ← →) with a
183
+ * counter pill, navigation arrows, and a thumbnail strip below. Built on
184
+ * {@link Carousel}. Standalone — pass `onImageClick` to open it into a
185
+ * {@link PhotoGalleryFullscreen} viewer, but neither surface needs the other.
186
+ */
187
+ function PhotoGallery({ images, index, onIndexChange, onImageClick, className, ...props }) {
188
+ const { setApi, selectedIndex, initialIndex, scrollTo, scrollPrev, scrollNext } = useGalleryCarousel(index, onIndexChange);
189
+ const hasMany = images.length > 1;
190
+ return /* @__PURE__ */ jsxs("div", {
191
+ "data-slot": "photo-gallery",
192
+ className: cn("flex w-full flex-col gap-3 rounded-2xl border border-line bg-surface p-3", className),
193
+ ...props,
194
+ children: [/* @__PURE__ */ jsxs(Carousel, {
195
+ imageSize: "full",
196
+ setApi,
197
+ opts: {
198
+ loop: true,
199
+ startIndex: initialIndex,
200
+ watchDrag: hasMany
201
+ },
202
+ className: "aspect-video rounded-xl bg-surface-raised",
203
+ children: [
204
+ /* @__PURE__ */ jsx(CarouselContent, { children: images.map((image, i) => /* @__PURE__ */ jsx(CarouselItem, { children: /* @__PURE__ */ jsx(GalleryFrame, { image }) }, i)) }),
205
+ onImageClick && /* @__PURE__ */ jsx(GalleryButton, {
206
+ className: "absolute bottom-2 right-2 sm:bottom-4 sm:right-4",
207
+ onClick: () => onImageClick(selectedIndex),
208
+ children: /* @__PURE__ */ jsx(Fullscreen, { className: "size-4 md:size-5" })
209
+ }),
210
+ /* @__PURE__ */ jsx(GalleryCounter, {
211
+ current: selectedIndex + 1,
212
+ total: images.length,
213
+ className: "top-2 right-2 sm:top-4 md:right-4"
214
+ }),
215
+ hasMany && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(GalleryArrow, {
216
+ side: "prev",
217
+ onClick: scrollPrev
218
+ }), /* @__PURE__ */ jsx(GalleryArrow, {
219
+ side: "next",
220
+ onClick: scrollNext
221
+ })] })
222
+ ]
223
+ }), /* @__PURE__ */ jsx(GalleryThumbnails, {
224
+ images,
225
+ selectedIndex,
226
+ onSelect: scrollTo,
227
+ colsClassName: "[--gallery-cols:5] sm:[--gallery-cols:8]"
228
+ })]
229
+ });
339
230
  }
340
- function PhotoGalleryFullscreen({
341
- images,
342
- open,
343
- onOpenChange,
344
- index,
345
- onIndexChange
346
- }) {
347
- const {
348
- setApi,
349
- selectedIndex,
350
- initialIndex,
351
- scrollTo,
352
- scrollPrev,
353
- scrollNext
354
- } = useGalleryCarousel(index, onIndexChange);
355
- const hasMany = images.length > 1;
356
- const handleKeyDown = (event) => {
357
- if (event.defaultPrevented) return;
358
- if (event.key === "ArrowLeft") {
359
- event.preventDefault();
360
- scrollPrev();
361
- } else if (event.key === "ArrowRight") {
362
- event.preventDefault();
363
- scrollNext();
364
- }
365
- };
366
- return /* @__PURE__ */ jsx(DialogPrimitive.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
367
- /* @__PURE__ */ jsx(
368
- DialogPrimitive.Backdrop,
369
- {
370
- "data-slot": "photo-gallery-fullscreen-backdrop",
371
- className: "fixed inset-0 z-50 bg-black/90 transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100"
372
- }
373
- ),
374
- /* @__PURE__ */ jsxs(
375
- DialogPrimitive.Popup,
376
- {
377
- "data-slot": "photo-gallery-fullscreen",
378
- onKeyDown: handleKeyDown,
379
- className: "fixed inset-0 z-50 flex flex-col gap-4 p-4 sm:p-6 xl:p-8 outline-none transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100",
380
- children: [
381
- /* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "sr-only", children: "Photo Gallery" }),
382
- /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center justify-between", children: [
383
- /* @__PURE__ */ jsx(
384
- GalleryCounter,
385
- {
386
- current: selectedIndex + 1,
387
- total: images.length,
388
- className: "static"
389
- }
390
- ),
391
- /* @__PURE__ */ jsx(
392
- DialogPrimitive.Close,
393
- {
394
- "data-slot": "photo-gallery-fullscreen-close",
395
- "aria-label": "Close gallery",
396
- render: /* @__PURE__ */ jsx(GalleryButton, {}),
397
- children: /* @__PURE__ */ jsx(XIcon, { className: "size-4 sm:size-5" })
398
- }
399
- )
400
- ] }),
401
- /* @__PURE__ */ jsxs(
402
- Carousel,
403
- {
404
- imageSize: "full",
405
- setApi,
406
- opts: { loop: true, startIndex: initialIndex, watchDrag: hasMany },
407
- className: "min-h-0 flex-1 w-full rounded-xl bg-transparent",
408
- children: [
409
- /* @__PURE__ */ jsx(CarouselContent, { className: "items-center", children: images.map((image, i) => /* @__PURE__ */ jsx(
410
- CarouselItem,
411
- {
412
- className: "h-full",
413
- children: /* @__PURE__ */ jsx(GalleryFrame, { image, fit: "contain" })
414
- },
415
- i
416
- )) }),
417
- hasMany && /* @__PURE__ */ jsxs(Fragment, { children: [
418
- /* @__PURE__ */ jsx(
419
- GalleryArrow,
420
- {
421
- side: "prev",
422
- onClick: scrollPrev,
423
- className: "left-0!"
424
- }
425
- ),
426
- /* @__PURE__ */ jsx(
427
- GalleryArrow,
428
- {
429
- side: "next",
430
- onClick: scrollNext,
431
- className: "right-0!"
432
- }
433
- )
434
- ] })
435
- ]
436
- }
437
- ),
438
- hasMany && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
439
- /* @__PURE__ */ jsx("p", { className: "hidden text-center text-gdt-xs text-fg-secondary sm:block", children: "\u2190 \u2192 to navigate \xB7 ESC to close" }),
440
- /* @__PURE__ */ jsx(
441
- GalleryThumbnails,
442
- {
443
- images,
444
- selectedIndex,
445
- onSelect: scrollTo,
446
- colsClassName: "[--gallery-cols:5] sm:[--gallery-cols:10]",
447
- className: "mx-auto w-full max-w-3xl"
448
- }
449
- )
450
- ] })
451
- ]
452
- }
453
- )
454
- ] }) });
231
+ /**
232
+ * Fullscreen lightbox: takes over the viewport over a dimmed backdrop for
233
+ * distraction-free browsing. Swipeable (drag / touch) with ← → key navigation
234
+ * and ESC to close. Built on {@link Carousel}; controlled via `open` /
235
+ * `onOpenChange` and usable without the inline gallery.
236
+ */
237
+ function PhotoGalleryFullscreen({ images, open, onOpenChange, index, onIndexChange }) {
238
+ const { setApi, selectedIndex, initialIndex, scrollTo, scrollPrev, scrollNext } = useGalleryCarousel(index, onIndexChange);
239
+ const hasMany = images.length > 1;
240
+ const handleKeyDown = (event) => {
241
+ if (event.defaultPrevented) return;
242
+ if (event.key === "ArrowLeft") {
243
+ event.preventDefault();
244
+ scrollPrev();
245
+ } else if (event.key === "ArrowRight") {
246
+ event.preventDefault();
247
+ scrollNext();
248
+ }
249
+ };
250
+ return /* @__PURE__ */ jsx(Dialog.Root, {
251
+ open,
252
+ onOpenChange,
253
+ children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {
254
+ "data-slot": "photo-gallery-fullscreen-backdrop",
255
+ className: "fixed inset-0 z-50 bg-black/90 transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100"
256
+ }), /* @__PURE__ */ jsxs(Dialog.Popup, {
257
+ "data-slot": "photo-gallery-fullscreen",
258
+ onKeyDown: handleKeyDown,
259
+ className: "fixed inset-0 z-50 flex flex-col gap-4 p-4 sm:p-6 xl:p-8 outline-none transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100",
260
+ children: [
261
+ /* @__PURE__ */ jsx(Dialog.Title, {
262
+ className: "sr-only",
263
+ children: "Photo Gallery"
264
+ }),
265
+ /* @__PURE__ */ jsxs("div", {
266
+ className: "w-full flex items-center justify-between",
267
+ children: [/* @__PURE__ */ jsx(GalleryCounter, {
268
+ current: selectedIndex + 1,
269
+ total: images.length,
270
+ className: "static"
271
+ }), /* @__PURE__ */ jsx(Dialog.Close, {
272
+ "data-slot": "photo-gallery-fullscreen-close",
273
+ "aria-label": "Close gallery",
274
+ render: /* @__PURE__ */ jsx(GalleryButton, {}),
275
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-4 sm:size-5" })
276
+ })]
277
+ }),
278
+ /* @__PURE__ */ jsxs(Carousel, {
279
+ imageSize: "full",
280
+ setApi,
281
+ opts: {
282
+ loop: true,
283
+ startIndex: initialIndex,
284
+ watchDrag: hasMany
285
+ },
286
+ className: "min-h-0 flex-1 w-full rounded-xl bg-transparent",
287
+ children: [/* @__PURE__ */ jsx(CarouselContent, {
288
+ className: "items-center",
289
+ children: images.map((image, i) => /* @__PURE__ */ jsx(CarouselItem, {
290
+ className: "h-full",
291
+ children: /* @__PURE__ */ jsx(GalleryFrame, {
292
+ image,
293
+ fit: "contain"
294
+ })
295
+ }, i))
296
+ }), hasMany && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(GalleryArrow, {
297
+ side: "prev",
298
+ onClick: scrollPrev,
299
+ className: "left-0!"
300
+ }), /* @__PURE__ */ jsx(GalleryArrow, {
301
+ side: "next",
302
+ onClick: scrollNext,
303
+ className: "right-0!"
304
+ })] })]
305
+ }),
306
+ hasMany && /* @__PURE__ */ jsxs("div", {
307
+ className: "flex flex-col gap-3",
308
+ children: [/* @__PURE__ */ jsx("p", {
309
+ className: "hidden text-center text-gdt-xs text-fg-secondary sm:block",
310
+ children: "← → to navigate · ESC to close"
311
+ }), /* @__PURE__ */ jsx(GalleryThumbnails, {
312
+ images,
313
+ selectedIndex,
314
+ onSelect: scrollTo,
315
+ colsClassName: "[--gallery-cols:5] sm:[--gallery-cols:10]",
316
+ className: "mx-auto w-full max-w-3xl"
317
+ })]
318
+ })
319
+ ]
320
+ })] })
321
+ });
455
322
  }
456
- export {
457
- PhotoGallery,
458
- PhotoGalleryFullscreen
459
- };
460
- //# sourceMappingURL=photo-gallery.js.map
323
+ //#endregion
324
+ export { PhotoGallery, PhotoGalleryFullscreen };