@giddaa-housing/ui 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/dist/accordion.d.ts +9 -10
  3. package/dist/accordion.js +41 -87
  4. package/dist/activity-timeline.d.ts +12 -16
  5. package/dist/activity-timeline.js +83 -198
  6. package/dist/alert.d.ts +8 -9
  7. package/dist/alert.js +53 -111
  8. package/dist/auth-layout.d.ts +4 -4
  9. package/dist/auth-layout.js +143 -294
  10. package/dist/avatar.d.ts +6 -6
  11. package/dist/avatar.js +49 -19
  12. package/dist/badge.d.ts +12 -14
  13. package/dist/badge.js +71 -11
  14. package/dist/bar-chart.d.ts +65 -67
  15. package/dist/bar-chart.js +232 -207
  16. package/dist/breadcrumb.d.ts +5 -5
  17. package/dist/breadcrumb.js +56 -118
  18. package/dist/bullet-chart.d.ts +33 -33
  19. package/dist/bullet-chart.js +121 -148
  20. package/dist/button-BZIeyUw6.d.ts +17 -0
  21. package/dist/button-group.d.ts +13 -16
  22. package/dist/button-group.js +39 -88
  23. package/dist/button.d.ts +2 -19
  24. package/dist/button.js +94 -13
  25. package/dist/calendar.d.ts +6 -6
  26. package/dist/calendar.js +138 -17
  27. package/dist/card.d.ts +14 -16
  28. package/dist/card.js +59 -145
  29. package/dist/carousel.d.ts +34 -35
  30. package/dist/carousel.js +335 -20
  31. package/dist/chart.d.ts +58 -59
  32. package/dist/chart.js +376 -28
  33. package/dist/checkbox.d.ts +10 -12
  34. package/dist/checkbox.js +82 -47
  35. package/dist/cn-BI_4DMBf.js +23 -0
  36. package/dist/collapsible.d.ts +7 -8
  37. package/dist/collapsible.js +22 -47
  38. package/dist/combobox.d.ts +10 -10
  39. package/dist/combobox.js +236 -44
  40. package/dist/cta.d.ts +12 -14
  41. package/dist/cta.js +175 -341
  42. package/dist/currency-selector.d.ts +31 -32
  43. package/dist/currency-selector.js +106 -184
  44. package/dist/data-table.d.ts +164 -0
  45. package/dist/data-table.js +673 -0
  46. package/dist/date-picker.d.ts +22 -23
  47. package/dist/date-picker.js +119 -192
  48. package/dist/details-card.d.ts +7 -7
  49. package/dist/details-card.js +104 -253
  50. package/dist/dialog.d.ts +13 -14
  51. package/dist/dialog.js +116 -209
  52. package/dist/dropdown-menu.d.ts +13 -13
  53. package/dist/dropdown-menu.js +180 -37
  54. package/dist/dropzone.d.ts +55 -55
  55. package/dist/dropzone.js +327 -439
  56. package/dist/editorial-card.d.ts +23 -25
  57. package/dist/editorial-card.js +129 -296
  58. package/dist/empty-state.d.ts +8 -9
  59. package/dist/empty-state.js +48 -105
  60. package/dist/field.d.ts +23 -25
  61. package/dist/field.js +110 -221
  62. package/dist/filter.d.ts +118 -0
  63. package/dist/filter.js +775 -0
  64. package/dist/footer.d.ts +8 -15
  65. package/dist/footer.js +197 -400
  66. package/dist/funnel-chart.d.ts +38 -41
  67. package/dist/funnel-chart.js +167 -189
  68. package/dist/gallery-indicator.d.ts +11 -12
  69. package/dist/gallery-indicator.js +75 -12
  70. package/dist/heatmap-chart.d.ts +47 -50
  71. package/dist/heatmap-chart.js +186 -237
  72. package/dist/infotip.d.ts +8 -9
  73. package/dist/infotip.js +33 -59
  74. package/dist/input-CfoEJ8A6.d.ts +12 -0
  75. package/dist/input-group.d.ts +16 -20
  76. package/dist/input-group.js +99 -23
  77. package/dist/input-size-context-C-SFx9sx.d.ts +10 -0
  78. package/dist/input-size-context.d.ts +2 -11
  79. package/dist/input-size-context.js +17 -9
  80. package/dist/input.d.ts +2 -13
  81. package/dist/input.js +27 -11
  82. package/dist/item.d.ts +7 -8
  83. package/dist/item.js +22 -59
  84. package/dist/kpi-card.d.ts +18 -20
  85. package/dist/kpi-card.js +84 -192
  86. package/dist/label.d.ts +6 -6
  87. package/dist/label.js +40 -8
  88. package/dist/line-chart.d.ts +88 -89
  89. package/dist/line-chart.js +142 -104
  90. package/dist/logo.d.ts +4 -4
  91. package/dist/logo.js +92 -9
  92. package/dist/map-indicator.d.ts +7 -7
  93. package/dist/map-indicator.js +80 -106
  94. package/dist/match.d.ts +10 -11
  95. package/dist/match.js +62 -107
  96. package/dist/media-gallery-hero.d.ts +40 -42
  97. package/dist/media-gallery-hero.js +182 -343
  98. package/dist/media-player.d.ts +17 -17
  99. package/dist/media-player.js +873 -1348
  100. package/dist/multi-step-form.d.ts +56 -0
  101. package/dist/multi-step-form.js +342 -0
  102. package/dist/number-input.d.ts +34 -34
  103. package/dist/number-input.js +61 -117
  104. package/dist/page-header.d.ts +10 -11
  105. package/dist/page-header.js +34 -79
  106. package/dist/pagination.d.ts +17 -21
  107. package/dist/pagination.js +132 -207
  108. package/dist/password-input.d.ts +5 -13
  109. package/dist/password-input.js +31 -55
  110. package/dist/phone-input.d.ts +19 -20
  111. package/dist/phone-input.js +226 -344
  112. package/dist/photo-gallery.d.ts +19 -19
  113. package/dist/photo-gallery.js +313 -449
  114. package/dist/picker-lzgmsNfG.js +32 -0
  115. package/dist/pie-chart.d.ts +60 -60
  116. package/dist/pie-chart.js +140 -148
  117. package/dist/popover.d.ts +9 -9
  118. package/dist/popover.js +72 -23
  119. package/dist/price-tag.d.ts +26 -27
  120. package/dist/price-tag.js +113 -173
  121. package/dist/progress.d.ts +16 -17
  122. package/dist/progress.js +169 -24
  123. package/dist/property-listing-card.d.ts +14 -17
  124. package/dist/property-listing-card.js +102 -220
  125. package/dist/radar-chart.d.ts +29 -31
  126. package/dist/radar-chart.js +162 -137
  127. package/dist/radio-group.d.ts +11 -13
  128. package/dist/radio-group.js +46 -60
  129. package/dist/review-block.d.ts +14 -16
  130. package/dist/review-block.js +154 -10
  131. package/dist/rich-text-editor.d.ts +30 -14
  132. package/dist/rich-text-editor.js +592 -716
  133. package/dist/scatter-chart.d.ts +45 -47
  134. package/dist/scatter-chart.js +236 -240
  135. package/dist/search-input.d.ts +8 -16
  136. package/dist/search-input.js +57 -109
  137. package/dist/select.d.ts +8 -8
  138. package/dist/select.js +144 -27
  139. package/dist/separator.d.ts +8 -9
  140. package/dist/separator.js +32 -8
  141. package/dist/sheet.d.ts +11 -11
  142. package/dist/sheet.js +103 -24
  143. package/dist/sidebar.d.ts +32 -37
  144. package/dist/sidebar.js +364 -634
  145. package/dist/size-context-D4mYvcg8.d.ts +10 -0
  146. package/dist/size-context.d.ts +2 -11
  147. package/dist/size-context.js +17 -9
  148. package/dist/skeleton.d.ts +4 -5
  149. package/dist/skeleton.js +12 -8
  150. package/dist/slider.d.ts +8 -9
  151. package/dist/slider.js +64 -135
  152. package/dist/sparkline.d.ts +43 -46
  153. package/dist/sparkline.js +221 -251
  154. package/dist/stepper.d.ts +23 -24
  155. package/dist/stepper.js +149 -246
  156. package/dist/styles.css +510 -108
  157. package/dist/switch.d.ts +10 -12
  158. package/dist/switch.js +48 -70
  159. package/dist/table-card.d.ts +35 -0
  160. package/dist/table-card.js +125 -0
  161. package/dist/table.d.ts +18 -14
  162. package/dist/table.js +113 -154
  163. package/dist/tabs.d.ts +23 -15
  164. package/dist/tabs.js +71 -18
  165. package/dist/tag.d.ts +21 -23
  166. package/dist/tag.js +103 -159
  167. package/dist/testimonial-block.d.ts +18 -19
  168. package/dist/testimonial-block.js +189 -358
  169. package/dist/textarea-IS_D8pXf.d.ts +11 -0
  170. package/dist/textarea.d.ts +2 -12
  171. package/dist/textarea.js +24 -11
  172. package/dist/time-picker.d.ts +11 -11
  173. package/dist/time-picker.js +245 -302
  174. package/dist/toast.d.ts +16 -18
  175. package/dist/toast.js +154 -205
  176. package/dist/tooltip.d.ts +8 -9
  177. package/dist/tooltip.js +37 -12
  178. package/dist/tree-map.d.ts +54 -57
  179. package/dist/tree-map.js +227 -269
  180. package/dist/use-uncontrolled-CLfM1XbB.js +21 -0
  181. package/dist/waterfall-chart.d.ts +94 -97
  182. package/dist/waterfall-chart.js +455 -552
  183. package/package.json +28 -9
  184. package/dist/accordion.js.map +0 -1
  185. package/dist/activity-timeline.js.map +0 -1
  186. package/dist/alert.js.map +0 -1
  187. package/dist/auth-layout.js.map +0 -1
  188. package/dist/avatar.js.map +0 -1
  189. package/dist/badge.js.map +0 -1
  190. package/dist/bar-chart.js.map +0 -1
  191. package/dist/breadcrumb.js.map +0 -1
  192. package/dist/bullet-chart.js.map +0 -1
  193. package/dist/button-group.js.map +0 -1
  194. package/dist/button.js.map +0 -1
  195. package/dist/calendar.js.map +0 -1
  196. package/dist/card.js.map +0 -1
  197. package/dist/carousel.js.map +0 -1
  198. package/dist/chart.js.map +0 -1
  199. package/dist/checkbox.js.map +0 -1
  200. package/dist/chunk-322YCNVL.js +0 -278
  201. package/dist/chunk-322YCNVL.js.map +0 -1
  202. package/dist/chunk-3ACQVT7A.js +0 -25
  203. package/dist/chunk-3ACQVT7A.js.map +0 -1
  204. package/dist/chunk-3T65TLJX.js +0 -334
  205. package/dist/chunk-3T65TLJX.js.map +0 -1
  206. package/dist/chunk-6ZSGQHH2.js +0 -192
  207. package/dist/chunk-6ZSGQHH2.js.map +0 -1
  208. package/dist/chunk-7TBMLFGW.js +0 -41
  209. package/dist/chunk-7TBMLFGW.js.map +0 -1
  210. package/dist/chunk-B4H6RNDH.js +0 -135
  211. package/dist/chunk-B4H6RNDH.js.map +0 -1
  212. package/dist/chunk-BUXCGZ6X.js +0 -219
  213. package/dist/chunk-BUXCGZ6X.js.map +0 -1
  214. package/dist/chunk-CHII2QHH.js +0 -58
  215. package/dist/chunk-CHII2QHH.js.map +0 -1
  216. package/dist/chunk-DMNOXRRW.js +0 -147
  217. package/dist/chunk-DMNOXRRW.js.map +0 -1
  218. package/dist/chunk-EFSOSSIC.js +0 -130
  219. package/dist/chunk-EFSOSSIC.js.map +0 -1
  220. package/dist/chunk-FZDSVMKY.js +0 -363
  221. package/dist/chunk-FZDSVMKY.js.map +0 -1
  222. package/dist/chunk-GJOFIJS3.js +0 -246
  223. package/dist/chunk-GJOFIJS3.js.map +0 -1
  224. package/dist/chunk-HL3ZSYES.js +0 -23
  225. package/dist/chunk-HL3ZSYES.js.map +0 -1
  226. package/dist/chunk-JVLUBAPB.js +0 -129
  227. package/dist/chunk-JVLUBAPB.js.map +0 -1
  228. package/dist/chunk-KDPYSOYZ.js +0 -64
  229. package/dist/chunk-KDPYSOYZ.js.map +0 -1
  230. package/dist/chunk-KSMDANKI.js +0 -43
  231. package/dist/chunk-KSMDANKI.js.map +0 -1
  232. package/dist/chunk-MEKCCOP5.js +0 -46
  233. package/dist/chunk-MEKCCOP5.js.map +0 -1
  234. package/dist/chunk-NOFXVRWL.js +0 -451
  235. package/dist/chunk-NOFXVRWL.js.map +0 -1
  236. package/dist/chunk-PC5MHNVA.js +0 -171
  237. package/dist/chunk-PC5MHNVA.js.map +0 -1
  238. package/dist/chunk-QKAQZ2GU.js +0 -122
  239. package/dist/chunk-QKAQZ2GU.js.map +0 -1
  240. package/dist/chunk-QZHSHSVV.js +0 -26
  241. package/dist/chunk-QZHSHSVV.js.map +0 -1
  242. package/dist/chunk-RBMK26XD.js +0 -19
  243. package/dist/chunk-RBMK26XD.js.map +0 -1
  244. package/dist/chunk-SFNJGF6M.js +0 -262
  245. package/dist/chunk-SFNJGF6M.js.map +0 -1
  246. package/dist/chunk-UJJNLGTM.js +0 -112
  247. package/dist/chunk-UJJNLGTM.js.map +0 -1
  248. package/dist/chunk-VGR4ZWJ3.js +0 -418
  249. package/dist/chunk-VGR4ZWJ3.js.map +0 -1
  250. package/dist/chunk-XG47P6D4.js +0 -99
  251. package/dist/chunk-XG47P6D4.js.map +0 -1
  252. package/dist/chunk-XZZAHNVM.js +0 -21
  253. package/dist/chunk-XZZAHNVM.js.map +0 -1
  254. package/dist/chunk-Y4TTYVNE.js +0 -36
  255. package/dist/chunk-Y4TTYVNE.js.map +0 -1
  256. package/dist/chunk-YDWIHW6Q.js +0 -69
  257. package/dist/chunk-YDWIHW6Q.js.map +0 -1
  258. package/dist/collapsible.js.map +0 -1
  259. package/dist/combobox.js.map +0 -1
  260. package/dist/cta.js.map +0 -1
  261. package/dist/currency-selector.js.map +0 -1
  262. package/dist/date-picker.js.map +0 -1
  263. package/dist/details-card.js.map +0 -1
  264. package/dist/dialog.js.map +0 -1
  265. package/dist/dropdown-menu.js.map +0 -1
  266. package/dist/dropzone.js.map +0 -1
  267. package/dist/editorial-card.js.map +0 -1
  268. package/dist/empty-state.js.map +0 -1
  269. package/dist/field.js.map +0 -1
  270. package/dist/footer.js.map +0 -1
  271. package/dist/funnel-chart.js.map +0 -1
  272. package/dist/gallery-indicator.js.map +0 -1
  273. package/dist/heatmap-chart.js.map +0 -1
  274. package/dist/infotip.js.map +0 -1
  275. package/dist/input-group.js.map +0 -1
  276. package/dist/input-size-context.js.map +0 -1
  277. package/dist/input.js.map +0 -1
  278. package/dist/item.js.map +0 -1
  279. package/dist/kpi-card.js.map +0 -1
  280. package/dist/label.js.map +0 -1
  281. package/dist/line-chart.js.map +0 -1
  282. package/dist/logo.js.map +0 -1
  283. package/dist/map-indicator.js.map +0 -1
  284. package/dist/match.js.map +0 -1
  285. package/dist/media-gallery-hero.js.map +0 -1
  286. package/dist/media-player.js.map +0 -1
  287. package/dist/number-input.js.map +0 -1
  288. package/dist/page-header.js.map +0 -1
  289. package/dist/pagination.js.map +0 -1
  290. package/dist/password-input.js.map +0 -1
  291. package/dist/phone-input.js.map +0 -1
  292. package/dist/photo-gallery.js.map +0 -1
  293. package/dist/pie-chart.js.map +0 -1
  294. package/dist/popover.js.map +0 -1
  295. package/dist/price-tag.js.map +0 -1
  296. package/dist/progress.js.map +0 -1
  297. package/dist/property-listing-card.js.map +0 -1
  298. package/dist/radar-chart.js.map +0 -1
  299. package/dist/radio-group.js.map +0 -1
  300. package/dist/review-block.js.map +0 -1
  301. package/dist/rich-text-editor.js.map +0 -1
  302. package/dist/scatter-chart.js.map +0 -1
  303. package/dist/search-input.js.map +0 -1
  304. package/dist/select.js.map +0 -1
  305. package/dist/separator.js.map +0 -1
  306. package/dist/sheet.js.map +0 -1
  307. package/dist/sidebar.js.map +0 -1
  308. package/dist/size-context.js.map +0 -1
  309. package/dist/skeleton.js.map +0 -1
  310. package/dist/slider.js.map +0 -1
  311. package/dist/sparkline.js.map +0 -1
  312. package/dist/stepper.js.map +0 -1
  313. package/dist/switch.js.map +0 -1
  314. package/dist/tab-list.d.ts +0 -38
  315. package/dist/tab-list.js +0 -123
  316. package/dist/tab-list.js.map +0 -1
  317. package/dist/table.js.map +0 -1
  318. package/dist/tabs.js.map +0 -1
  319. package/dist/tag.js.map +0 -1
  320. package/dist/testimonial-block.js.map +0 -1
  321. package/dist/textarea.js.map +0 -1
  322. package/dist/time-picker.js.map +0 -1
  323. package/dist/toast.js.map +0 -1
  324. package/dist/tooltip.js.map +0 -1
  325. package/dist/tree-map.js.map +0 -1
  326. 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 };