@giddaa-housing/ui 0.1.0 → 1.0.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.
- package/README.md +18 -6
- package/css/base.css +37 -0
- package/css/components.css +135 -0
- package/css/generated/shared.css +1 -0
- package/css/giddaa.css +402 -0
- package/css/preset.css +77 -0
- package/css/styles.css +2 -0
- package/css/theme.css +255 -0
- package/dist/accordion.js +5 -35
- package/dist/accordion.js.map +1 -1
- package/dist/activity-timeline.d.ts +33 -0
- package/dist/activity-timeline.js +212 -0
- package/dist/activity-timeline.js.map +1 -0
- package/dist/alert.js +5 -35
- package/dist/alert.js.map +1 -1
- package/dist/auth-layout.d.ts +23 -0
- package/dist/auth-layout.js +304 -0
- package/dist/auth-layout.js.map +1 -0
- package/dist/avatar.js +10 -142
- package/dist/avatar.js.map +1 -1
- package/dist/badge.d.ts +3 -2
- package/dist/badge.js +6 -114
- package/dist/badge.js.map +1 -1
- package/dist/bar-chart.d.ts +101 -77
- package/dist/bar-chart.js +142 -220
- package/dist/bar-chart.js.map +1 -1
- package/dist/breadcrumb.js +5 -35
- package/dist/breadcrumb.js.map +1 -1
- package/dist/bullet-chart.js +15 -48
- package/dist/bullet-chart.js.map +1 -1
- package/dist/button-group.js +14 -90
- package/dist/button-group.js.map +1 -1
- package/dist/button.d.ts +5 -5
- package/dist/button.js +7 -140
- package/dist/button.js.map +1 -1
- package/dist/calendar.js +12 -287
- package/dist/calendar.js.map +1 -1
- package/dist/card.js +5 -35
- package/dist/card.js.map +1 -1
- package/dist/carousel.js +12 -386
- package/dist/carousel.js.map +1 -1
- package/dist/chart.js +16 -480
- package/dist/chart.js.map +1 -1
- package/dist/checkbox.d.ts +1 -1
- package/dist/checkbox.js +13 -48
- package/dist/checkbox.js.map +1 -1
- package/dist/chunk-322YCNVL.js +278 -0
- package/dist/chunk-322YCNVL.js.map +1 -0
- package/dist/chunk-3ACQVT7A.js +25 -0
- package/dist/chunk-3ACQVT7A.js.map +1 -0
- package/dist/chunk-3T65TLJX.js +334 -0
- package/dist/chunk-3T65TLJX.js.map +1 -0
- package/dist/chunk-6ZSGQHH2.js +192 -0
- package/dist/chunk-6ZSGQHH2.js.map +1 -0
- package/dist/chunk-7TBMLFGW.js +41 -0
- package/dist/chunk-7TBMLFGW.js.map +1 -0
- package/dist/chunk-B4H6RNDH.js +135 -0
- package/dist/chunk-B4H6RNDH.js.map +1 -0
- package/dist/chunk-BUXCGZ6X.js +219 -0
- package/dist/chunk-BUXCGZ6X.js.map +1 -0
- package/dist/chunk-CHII2QHH.js +58 -0
- package/dist/chunk-CHII2QHH.js.map +1 -0
- package/dist/chunk-DMNOXRRW.js +147 -0
- package/dist/chunk-DMNOXRRW.js.map +1 -0
- package/dist/chunk-EFSOSSIC.js +130 -0
- package/dist/chunk-EFSOSSIC.js.map +1 -0
- package/dist/chunk-FZDSVMKY.js +363 -0
- package/dist/chunk-FZDSVMKY.js.map +1 -0
- package/dist/chunk-GJOFIJS3.js +246 -0
- package/dist/chunk-GJOFIJS3.js.map +1 -0
- package/dist/chunk-HL3ZSYES.js +23 -0
- package/dist/chunk-HL3ZSYES.js.map +1 -0
- package/dist/chunk-JVLUBAPB.js +129 -0
- package/dist/chunk-JVLUBAPB.js.map +1 -0
- package/dist/chunk-KDPYSOYZ.js +64 -0
- package/dist/chunk-KDPYSOYZ.js.map +1 -0
- package/dist/chunk-KSMDANKI.js +43 -0
- package/dist/chunk-KSMDANKI.js.map +1 -0
- package/dist/chunk-MEKCCOP5.js +46 -0
- package/dist/chunk-MEKCCOP5.js.map +1 -0
- package/dist/chunk-NOFXVRWL.js +451 -0
- package/dist/chunk-NOFXVRWL.js.map +1 -0
- package/dist/chunk-PC5MHNVA.js +171 -0
- package/dist/chunk-PC5MHNVA.js.map +1 -0
- package/dist/chunk-QKAQZ2GU.js +122 -0
- package/dist/chunk-QKAQZ2GU.js.map +1 -0
- package/dist/chunk-QZHSHSVV.js +26 -0
- package/dist/chunk-QZHSHSVV.js.map +1 -0
- package/dist/chunk-RBMK26XD.js +19 -0
- package/dist/chunk-RBMK26XD.js.map +1 -0
- package/dist/chunk-SFNJGF6M.js +262 -0
- package/dist/chunk-SFNJGF6M.js.map +1 -0
- package/dist/chunk-UJJNLGTM.js +112 -0
- package/dist/chunk-UJJNLGTM.js.map +1 -0
- package/dist/chunk-VGR4ZWJ3.js +418 -0
- package/dist/chunk-VGR4ZWJ3.js.map +1 -0
- package/dist/chunk-XG47P6D4.js +99 -0
- package/dist/chunk-XG47P6D4.js.map +1 -0
- package/dist/chunk-XZZAHNVM.js +21 -0
- package/dist/chunk-XZZAHNVM.js.map +1 -0
- package/dist/chunk-Y4TTYVNE.js +36 -0
- package/dist/chunk-Y4TTYVNE.js.map +1 -0
- package/dist/chunk-YDWIHW6Q.js +69 -0
- package/dist/chunk-YDWIHW6Q.js.map +1 -0
- package/dist/collapsible.js +6 -35
- package/dist/collapsible.js.map +1 -1
- package/dist/combobox.js +26 -694
- package/dist/combobox.js.map +1 -1
- package/dist/cta.d.ts +66 -0
- package/dist/cta.js +358 -0
- package/dist/cta.js.map +1 -0
- package/dist/currency-selector.d.ts +42 -0
- package/dist/currency-selector.js +192 -0
- package/dist/currency-selector.js.map +1 -0
- package/dist/date-picker.d.ts +18 -10
- package/dist/date-picker.js +105 -430
- package/dist/date-picker.js.map +1 -1
- package/dist/details-card.d.ts +19 -0
- package/dist/details-card.js +267 -0
- package/dist/details-card.js.map +1 -0
- package/dist/dialog.js +36 -146
- package/dist/dialog.js.map +1 -1
- package/dist/dropdown-menu.d.ts +1 -1
- package/dist/dropdown-menu.js +20 -358
- package/dist/dropdown-menu.js.map +1 -1
- package/dist/dropzone.js +13 -40
- package/dist/dropzone.js.map +1 -1
- package/dist/editorial-card.d.ts +29 -0
- package/dist/editorial-card.js +311 -0
- package/dist/editorial-card.js.map +1 -0
- package/dist/empty-state.js +5 -35
- package/dist/empty-state.js.map +1 -1
- package/dist/field.js +30 -135
- package/dist/field.js.map +1 -1
- package/dist/footer.d.ts +47 -0
- package/dist/footer.js +430 -0
- package/dist/footer.js.map +1 -0
- package/dist/funnel-chart.js +42 -415
- package/dist/funnel-chart.js.map +1 -1
- package/dist/gallery-indicator.d.ts +18 -0
- package/dist/gallery-indicator.js +12 -0
- package/dist/gallery-indicator.js.map +1 -0
- package/dist/heatmap-chart.d.ts +98 -0
- package/dist/heatmap-chart.js +248 -0
- package/dist/heatmap-chart.js.map +1 -0
- package/dist/infotip.d.ts +11 -0
- package/dist/infotip.js +66 -0
- package/dist/infotip.js.map +1 -0
- package/dist/input-group.d.ts +2 -1
- package/dist/input-group.js +15 -371
- package/dist/input-group.js.map +1 -1
- package/dist/input-size-context.js +5 -19
- package/dist/input-size-context.js.map +1 -1
- package/dist/input.js +6 -78
- package/dist/input.js.map +1 -1
- package/dist/item.js +5 -35
- package/dist/item.js.map +1 -1
- package/dist/kpi-card.js +12 -52
- package/dist/kpi-card.js.map +1 -1
- package/dist/label.js +5 -64
- package/dist/label.js.map +1 -1
- package/dist/line-chart.js +9 -166
- package/dist/line-chart.js.map +1 -1
- package/dist/logo.js +4 -141
- package/dist/logo.js.map +1 -1
- package/dist/map-indicator.d.ts +13 -0
- package/dist/map-indicator.js +109 -0
- package/dist/map-indicator.js.map +1 -0
- package/dist/match.d.ts +16 -0
- package/dist/match.js +113 -0
- package/dist/match.js.map +1 -0
- package/dist/media-gallery-hero.d.ts +60 -0
- package/dist/media-gallery-hero.js +362 -0
- package/dist/media-gallery-hero.js.map +1 -0
- package/dist/media-player.d.ts +60 -0
- package/dist/media-player.js +1394 -0
- package/dist/media-player.js.map +1 -0
- package/dist/number-input.js +30 -325
- package/dist/number-input.js.map +1 -1
- package/dist/page-header.js +4 -32
- package/dist/page-header.js.map +1 -1
- package/dist/pagination.d.ts +1 -0
- package/dist/pagination.js +27 -161
- package/dist/pagination.js.map +1 -1
- package/dist/password-input.d.ts +1 -0
- package/dist/password-input.js +21 -319
- package/dist/password-input.js.map +1 -1
- package/dist/phone-input.d.ts +2 -1
- package/dist/phone-input.js +148 -359
- package/dist/phone-input.js.map +1 -1
- package/dist/photo-gallery.d.ts +1 -1
- package/dist/photo-gallery.js +97 -393
- package/dist/photo-gallery.js.map +1 -1
- package/dist/pie-chart.js +17 -52
- package/dist/pie-chart.js.map +1 -1
- package/dist/popover.js +13 -158
- package/dist/popover.js.map +1 -1
- package/dist/price-tag.d.ts +35 -0
- package/dist/price-tag.js +178 -0
- package/dist/price-tag.js.map +1 -0
- package/dist/progress.d.ts +5 -2
- package/dist/progress.js +14 -303
- package/dist/progress.js.map +1 -1
- package/dist/property-listing-card.d.ts +32 -0
- package/dist/property-listing-card.js +235 -0
- package/dist/property-listing-card.js.map +1 -0
- package/dist/radar-chart.d.ts +110 -0
- package/dist/radar-chart.js +147 -0
- package/dist/radar-chart.js.map +1 -0
- package/dist/radio-group.js +15 -50
- package/dist/radio-group.js.map +1 -1
- package/dist/review-block.d.ts +20 -0
- package/dist/review-block.js +10 -0
- package/dist/review-block.js.map +1 -0
- package/dist/rich-text-editor.js +172 -433
- package/dist/rich-text-editor.js.map +1 -1
- package/dist/scatter-chart.d.ts +142 -0
- package/dist/scatter-chart.js +252 -0
- package/dist/scatter-chart.js.map +1 -0
- package/dist/search-input.d.ts +1 -0
- package/dist/search-input.js +22 -320
- package/dist/search-input.js.map +1 -1
- package/dist/select.js +15 -292
- package/dist/select.js.map +1 -1
- package/dist/separator.js +5 -68
- package/dist/separator.js.map +1 -1
- package/dist/sheet.js +14 -271
- package/dist/sheet.js.map +1 -1
- package/dist/sidebar.d.ts +1 -1
- package/dist/sidebar.js +89 -494
- package/dist/sidebar.js.map +1 -1
- package/dist/size-context.js +5 -17
- package/dist/size-context.js.map +1 -1
- package/dist/skeleton.js +4 -44
- package/dist/skeleton.js.map +1 -1
- package/dist/slider.d.ts +28 -0
- package/dist/slider.js +152 -0
- package/dist/slider.js.map +1 -0
- package/dist/sparkline.js +33 -341
- package/dist/sparkline.js.map +1 -1
- package/dist/stepper.js +5 -35
- package/dist/stepper.js.map +1 -1
- package/dist/styles.css +9593 -2
- package/dist/switch.js +13 -48
- package/dist/switch.js.map +1 -1
- package/dist/tab-list.js +35 -306
- package/dist/tab-list.js.map +1 -1
- package/dist/table.js +5 -32
- package/dist/table.js.map +1 -1
- package/dist/tabs.js +10 -150
- package/dist/tabs.js.map +1 -1
- package/dist/tag.d.ts +7 -6
- package/dist/tag.js +101 -97
- package/dist/tag.js.map +1 -1
- package/dist/testimonial-block.d.ts +34 -0
- package/dist/testimonial-block.js +377 -0
- package/dist/testimonial-block.js.map +1 -0
- package/dist/textarea.js +6 -73
- package/dist/textarea.js.map +1 -1
- package/dist/time-picker.js +119 -279
- package/dist/time-picker.js.map +1 -1
- package/dist/toast.js +27 -132
- package/dist/toast.js.map +1 -1
- package/dist/tooltip.d.ts +5 -5
- package/dist/tooltip.js +7 -90
- package/dist/tooltip.js.map +1 -1
- package/dist/tree-map.js +41 -414
- package/dist/tree-map.js.map +1 -1
- package/dist/waterfall-chart.d.ts +129 -0
- package/dist/waterfall-chart.js +577 -0
- package/dist/waterfall-chart.js.map +1 -0
- package/package.json +98 -28
- package/dist/base.css +0 -32
- package/dist/files/red-hat-display-latin-300-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-300-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-300-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-300-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-400-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-400-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-400-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-400-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-500-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-500-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-500-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-500-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-600-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-600-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-600-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-600-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-700-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-700-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-700-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-700-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-800-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-800-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-800-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-800-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-900-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-900-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-900-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-900-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-300-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-300-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-300-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-300-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-400-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-400-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-400-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-400-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-500-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-500-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-500-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-500-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-600-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-600-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-600-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-600-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-700-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-700-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-700-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-700-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-800-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-800-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-800-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-800-normal.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-900-italic.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-900-italic.woff2 +0 -0
- package/dist/files/red-hat-display-latin-ext-900-normal.woff +0 -0
- package/dist/files/red-hat-display-latin-ext-900-normal.woff2 +0 -0
- package/dist/index.d.ts +0 -87
- package/dist/index.js +0 -10448
- package/dist/index.js.map +0 -1
- package/dist/red-hat-display.css +0 -2
- package/dist/theme/giddaa.css +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ui/photo-gallery.tsx","../src/lib/cn.ts","../src/components/ui/button.tsx","../src/components/ui/size-context.tsx","../src/components/ui/carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport {\n\tChevronLeftIcon,\n\tChevronRightIcon,\n\tFullscreen,\n\tXIcon,\n} from \"lucide-react\";\nimport type { SVGProps } from \"react\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { Button } from \"./button\";\nimport {\n\tCarousel,\n\ttype CarouselApi,\n\tCarouselContent,\n\tCarouselItem,\n} from \"./carousel\";\n\n/**\n * A single property photo. `src` is optional so the gallery can render a\n * \"Property Image\" placeholder in previews / while imagery is still loading.\n */\ntype PhotoGalleryImage = {\n\tsrc?: string;\n\talt?: string;\n};\n\n/**\n * Wires an Embla carousel to a controlled/uncontrolled active index. Returns\n * the `setApi` to hand to {@link Carousel} plus the live index and navigation\n * helpers. Both surfaces share this so the inline carousel and the fullscreen\n * viewer can stand alone — or stay in sync by sharing `index`/`onIndexChange`.\n */\nfunction useGalleryCarousel(\n\tindex: number | undefined,\n\tonIndexChange: ((index: number) => void) | undefined,\n) {\n\tconst [api, setApi] = React.useState<CarouselApi>();\n\tconst [selectedIndex, setSelectedIndex] = React.useState(index ?? 0);\n\tconst initialIndexRef = React.useRef(index ?? 0);\n\n\t// Keep the change callback in a ref so subscribing doesn't depend on a\n\t// caller passing a stable function identity.\n\tconst onIndexChangeRef = React.useRef(onIndexChange);\n\tReact.useEffect(() => {\n\t\tonIndexChangeRef.current = onIndexChange;\n\t});\n\n\tReact.useEffect(() => {\n\t\tif (!api) return;\n\t\tconst onSelect = () => {\n\t\t\tconst next = api.selectedScrollSnap();\n\t\t\tsetSelectedIndex(next);\n\t\t\tonIndexChangeRef.current?.(next);\n\t\t};\n\t\tonSelect();\n\t\tapi.on(\"select\", onSelect).on(\"reInit\", onSelect);\n\t\treturn () => {\n\t\t\tapi.off(\"select\", onSelect).off(\"reInit\", onSelect);\n\t\t};\n\t}, [api]);\n\n\t// Controlled mode: follow the index the parent hands down.\n\tReact.useEffect(() => {\n\t\tif (api && index !== undefined && index !== api.selectedScrollSnap()) {\n\t\t\tapi.scrollTo(index, false);\n\t\t}\n\t}, [api, index]);\n\n\tconst scrollTo = React.useCallback(\n\t\t(i: number) => api?.scrollTo(i, false),\n\t\t[api],\n\t);\n\tconst scrollPrev = React.useCallback(() => api?.scrollPrev(false), [api]);\n\tconst scrollNext = React.useCallback(() => api?.scrollNext(false), [api]);\n\n\treturn {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex: initialIndexRef.current,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t};\n}\n\n/* -------------------------------------------------------------------------- */\n/* Shared chrome */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The image surface. Fills its slide; falls back to a centred placeholder\n * label when `src` is missing. `cover` for the listing crop, `contain` for the\n * fullscreen viewer so the whole photo stays visible.\n */\nfunction GalleryFrame({\n\timage,\n\tfit = \"cover\",\n\tclassName,\n}: {\n\timage: PhotoGalleryImage | undefined;\n\tfit?: \"cover\" | \"contain\";\n\tclassName?: string;\n}) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery-frame\"\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex size-full items-center justify-center overflow-hidden\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{image?.src ? (\n\t\t\t\t<img\n\t\t\t\t\tsrc={image.src}\n\t\t\t\t\talt={image.alt ?? \"Property image\"}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"size-full\",\n\t\t\t\t\t\tfit === \"contain\" ? \"object-contain\" : \"object-cover\",\n\t\t\t\t\t)}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<span className=\"text-gdt-sm font-medium text-fg-caption-placeholder\">\n\t\t\t\t\tProperty Image\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nconst Images = (props: SVGProps<SVGSVGElement>) => (\n\t<svg\n\t\taria-hidden=\"true\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\twidth={15}\n\t\theight={16}\n\t\tviewBox=\"0 0 15 16\"\n\t\tfill=\"none\"\n\t\t{...props}\n\t>\n\t\t<path\n\t\t\tfill=\"currentColor\"\n\t\t\td=\"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\"\n\t\t/>\n\t\t<path\n\t\t\tfill=\"currentColor\"\n\t\t\td=\"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\"\n\t\t/>\n\t</svg>\n);\n\n/** Pill overlay showing `current / total`. Hidden when there is one image. */\nfunction GalleryCounter({\n\tcurrent,\n\ttotal,\n\tclassName,\n}: {\n\tcurrent: number;\n\ttotal: number;\n\tclassName?: string;\n}) {\n\tif (total <= 1) return null;\n\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery-counter\"\n\t\t\tclassName={cn(\n\t\t\t\t\"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\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<Images aria-hidden=\"true\" className=\"size-3.5\" />\n\t\t\t<span>\n\t\t\t\t{current} / {total}\n\t\t\t</span>\n\t\t</div>\n\t);\n}\n\nfunction GalleryButton({\n\tclassName,\n\tvariant = \"ghost\",\n\t...rest\n}: React.ComponentProps<typeof Button>) {\n\treturn (\n\t\t<Button\n\t\t\tsize=\"icon\"\n\t\t\tclassName={cn(\n\t\t\t\t\"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\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tvariant={variant}\n\t\t\t{...rest}\n\t\t/>\n\t);\n}\n\n/** Circular floating navigation button. Always present; the track loops. */\nfunction GalleryArrow({\n\tside,\n\tonClick,\n\tclassName,\n}: {\n\tside: \"prev\" | \"next\";\n\tonClick: () => void;\n\tclassName?: string;\n}) {\n\tconst Icon = side === \"prev\" ? ChevronLeftIcon : ChevronRightIcon;\n\treturn (\n\t\t<GalleryButton\n\t\t\ttype=\"button\"\n\t\t\tdata-slot={`photo-gallery-${side}`}\n\t\t\taria-label={side === \"prev\" ? \"Previous photo\" : \"Next photo\"}\n\t\t\tonClick={(event) => {\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tonClick();\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center active:not-aria-[haspopup]:-translate-y-1/2\",\n\t\t\t\tside === \"prev\" ? \"left-2 sm:left-4\" : \"right-2 sm:right-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<Icon className=\"cn-rtl-flip size-4 sm:size-5\" />\n\t\t</GalleryButton>\n\t);\n}\n\n/**\n * Equal-sized thumbnail strip. `cols` are sized via CSS vars so exactly N fill\n * the width (5 on mobile, more on web); extras overflow and scroll. The active\n * thumb gets a 2px focus stroke and is kept in view as the index changes.\n */\nfunction GalleryThumbnails({\n\timages,\n\tselectedIndex,\n\tonSelect,\n\tcolsClassName,\n\tclassName,\n\tactiveVariant = \"focus\",\n}: {\n\timages: PhotoGalleryImage[];\n\tselectedIndex: number;\n\tonSelect: (index: number) => void;\n\tcolsClassName: string;\n\tclassName?: string;\n\tactiveVariant?: \"focus\" | \"subtle\";\n}) {\n\tconst containerRef = React.useRef<HTMLDivElement>(null);\n\n\tReact.useEffect(() => {\n\t\tconst active = containerRef.current?.children[selectedIndex];\n\t\tactive?.scrollIntoView({\n\t\t\tbehavior: \"smooth\",\n\t\t\tinline: \"center\",\n\t\t\tblock: \"nearest\",\n\t\t});\n\t}, [selectedIndex]);\n\n\tif (images.length <= 1) return null;\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tdata-slot=\"photo-gallery-thumbnails\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex gap-2 overflow-x-auto [--gallery-gap:0.5rem] scrollbar-none [&::-webkit-scrollbar]:hidden\",\n\t\t\t\tcolsClassName,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{images.map((image, index) => {\n\t\t\t\tconst isActive = index === selectedIndex;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label={`View photo ${index + 1}`}\n\t\t\t\t\t\taria-current={isActive}\n\t\t\t\t\t\tonClick={() => onSelect(index)}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\twidth:\n\t\t\t\t\t\t\t\t\"calc((100% - (var(--gallery-cols) - 1) * var(--gallery-gap)) / var(--gallery-cols))\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"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)]\",\n\t\t\t\t\t\t\tactiveVariant === \"subtle\" &&\n\t\t\t\t\t\t\t\t\"focus-visible:border-line-subtle focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-subtle)]\",\n\t\t\t\t\t\t\tisActive\n\t\t\t\t\t\t\t\t? activeVariant === \"subtle\"\n\t\t\t\t\t\t\t\t\t? \"border-line-subtle\"\n\t\t\t\t\t\t\t\t\t: \"border-line-focus\"\n\t\t\t\t\t\t\t\t: \"border-transparent opacity-80 hover:opacity-100\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{image.src ? (\n\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\tsrc={image.src}\n\t\t\t\t\t\t\t\talt={image.alt ?? `Property image ${index + 1}`}\n\t\t\t\t\t\t\t\tclassName=\"size-full object-cover\"\n\t\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Inline carousel */\n/* -------------------------------------------------------------------------- */\n\ntype PhotoGalleryProps = Omit<React.ComponentProps<\"div\">, \"onClick\"> & {\n\timages: PhotoGalleryImage[];\n\t/** Controlled active index. Omit to let the gallery manage it internally. */\n\tindex?: number;\n\tonIndexChange?: (index: number) => void;\n\t/** Called when the hero image is activated — wire this to open fullscreen. */\n\tonImageClick?: (index: number) => void;\n};\n\n/**\n * Inline property gallery: a swipeable hero image (drag / touch / ← →) with a\n * counter pill, navigation arrows, and a thumbnail strip below. Built on\n * {@link Carousel}. Standalone — pass `onImageClick` to open it into a\n * {@link PhotoGalleryFullscreen} viewer, but neither surface needs the other.\n */\nfunction PhotoGallery({\n\timages,\n\tindex,\n\tonIndexChange,\n\tonImageClick,\n\tclassName,\n\t...props\n}: PhotoGalleryProps) {\n\tconst {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t} = useGalleryCarousel(index, onIndexChange);\n\tconst hasMany = images.length > 1;\n\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex w-full flex-col gap-3 rounded-2xl border border-line bg-surface p-3\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Carousel\n\t\t\t\timageSize=\"full\"\n\t\t\t\tsetApi={setApi}\n\t\t\t\topts={{ loop: true, startIndex: initialIndex, watchDrag: hasMany }}\n\t\t\t\tclassName=\"aspect-video rounded-xl bg-surface-raised\"\n\t\t\t>\n\t\t\t\t<CarouselContent>\n\t\t\t\t\t{images.map((image, i) => (\n\t\t\t\t\t\t<CarouselItem\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<GalleryFrame image={image} />\n\t\t\t\t\t\t</CarouselItem>\n\t\t\t\t\t))}\n\t\t\t\t</CarouselContent>\n\t\t\t\t{onImageClick && (\n\t\t\t\t\t<GalleryButton\n\t\t\t\t\t\tclassName=\"absolute bottom-2 right-2 sm:bottom-4 sm:right-4\"\n\t\t\t\t\t\tonClick={() => onImageClick(selectedIndex)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Fullscreen className=\"size-4 md:size-5\" />\n\t\t\t\t\t</GalleryButton>\n\t\t\t\t)}\n\n\t\t\t\t<GalleryCounter\n\t\t\t\t\tcurrent={selectedIndex + 1}\n\t\t\t\t\ttotal={images.length}\n\t\t\t\t\tclassName=\"top-2 right-2 sm:top-4 md:right-4\"\n\t\t\t\t/>\n\t\t\t\t{hasMany && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<GalleryArrow side=\"prev\" onClick={scrollPrev} />\n\t\t\t\t\t\t<GalleryArrow side=\"next\" onClick={scrollNext} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Carousel>\n\n\t\t\t<GalleryThumbnails\n\t\t\t\timages={images}\n\t\t\t\tselectedIndex={selectedIndex}\n\t\t\t\tonSelect={scrollTo}\n\t\t\t\tcolsClassName=\"[--gallery-cols:5] sm:[--gallery-cols:8]\"\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Fullscreen viewer */\n/* -------------------------------------------------------------------------- */\n\ntype PhotoGalleryFullscreenProps = {\n\timages: PhotoGalleryImage[];\n\topen: boolean;\n\tonOpenChange: (open: boolean) => void;\n\t/** Controlled active index. Omit to let the viewer manage it internally. */\n\tindex?: number;\n\tonIndexChange?: (index: number) => void;\n};\n\n/**\n * Fullscreen lightbox: takes over the viewport over a `bg-canvas` surface for\n * distraction-free browsing. Swipeable (drag / touch) with ← → key navigation\n * and ESC to close. Built on {@link Carousel}; controlled via `open` /\n * `onOpenChange` and usable without the inline gallery.\n */\nfunction PhotoGalleryFullscreen({\n\timages,\n\topen,\n\tonOpenChange,\n\tindex,\n\tonIndexChange,\n}: PhotoGalleryFullscreenProps) {\n\tconst {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t} = useGalleryCarousel(index, onIndexChange);\n\tconst hasMany = images.length > 1;\n\n\tconst handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n\t\t// The carousel handles arrows in the capture phase when it holds focus;\n\t\t// skip so focus inside the track doesn't navigate twice.\n\t\tif (event.defaultPrevented) return;\n\t\tif (event.key === \"ArrowLeft\") {\n\t\t\tevent.preventDefault();\n\t\t\tscrollPrev();\n\t\t} else if (event.key === \"ArrowRight\") {\n\t\t\tevent.preventDefault();\n\t\t\tscrollNext();\n\t\t}\n\t};\n\n\treturn (\n\t\t<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogPrimitive.Portal>\n\t\t\t\t<DialogPrimitive.Backdrop\n\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen-backdrop\"\n\t\t\t\t\tclassName=\"fixed inset-0 z-50 bg-black/50 transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100\"\n\t\t\t\t/>\n\t\t\t\t<DialogPrimitive.Popup\n\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen\"\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tclassName=\"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\"\n\t\t\t\t>\n\t\t\t\t\t<DialogPrimitive.Title className=\"sr-only\">\n\t\t\t\t\t\tPhoto Gallery\n\t\t\t\t\t</DialogPrimitive.Title>\n\n\t\t\t\t\t<div className=\"w-full flex items-center justify-between\">\n\t\t\t\t\t\t<GalleryCounter\n\t\t\t\t\t\t\tcurrent={selectedIndex + 1}\n\t\t\t\t\t\t\ttotal={images.length}\n\t\t\t\t\t\t\tclassName=\"static\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<DialogPrimitive.Close\n\t\t\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen-close\"\n\t\t\t\t\t\t\taria-label=\"Close gallery\"\n\t\t\t\t\t\t\trender={<GalleryButton />}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<XIcon className=\"size-4 sm:size-5\" />\n\t\t\t\t\t\t</DialogPrimitive.Close>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<Carousel\n\t\t\t\t\t\timageSize=\"full\"\n\t\t\t\t\t\tsetApi={setApi}\n\t\t\t\t\t\topts={{ loop: true, startIndex: initialIndex, watchDrag: hasMany }}\n\t\t\t\t\t\tclassName=\"flex-1 w-full rounded-xl bg-transparent\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<CarouselContent className=\"items-center\">\n\t\t\t\t\t\t\t{images.map((image, i) => (\n\t\t\t\t\t\t\t\t<CarouselItem\n\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\tclassName=\"h-full\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<GalleryFrame image={image} fit=\"contain\" />\n\t\t\t\t\t\t\t\t</CarouselItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</CarouselContent>\n\t\t\t\t\t\t{hasMany && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<GalleryArrow\n\t\t\t\t\t\t\t\t\tside=\"prev\"\n\t\t\t\t\t\t\t\t\tonClick={scrollPrev}\n\t\t\t\t\t\t\t\t\tclassName=\"left-0!\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<GalleryArrow\n\t\t\t\t\t\t\t\t\tside=\"next\"\n\t\t\t\t\t\t\t\t\tonClick={scrollNext}\n\t\t\t\t\t\t\t\t\tclassName=\"right-0!\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Carousel>\n\n\t\t\t\t\t{hasMany && (\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<p className=\"hidden text-center text-gdt-xs text-fg-secondary sm:block\">\n\t\t\t\t\t\t\t\t← → to navigate · ESC to close\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<GalleryThumbnails\n\t\t\t\t\t\t\t\timages={images}\n\t\t\t\t\t\t\t\tselectedIndex={selectedIndex}\n\t\t\t\t\t\t\t\tonSelect={scrollTo}\n\t\t\t\t\t\t\t\tcolsClassName=\"[--gallery-cols:5] sm:[--gallery-cols:10]\"\n\t\t\t\t\t\t\t\tclassName=\"mx-auto w-full max-w-3xl\"\n\t\t\t\t\t\t\t\tactiveVariant=\"subtle\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</DialogPrimitive.Popup>\n\t\t\t</DialogPrimitive.Portal>\n\t\t</DialogPrimitive.Root>\n\t);\n}\n\nexport {\n\ttype PhotoGalleryImage,\n\ttype PhotoGalleryProps,\n\ttype PhotoGalleryFullscreenProps,\n\tPhotoGallery,\n\tPhotoGalleryFullscreen,\n};\n","import { type ClassValue, clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n\textend: {\n\t\tclassGroups: {\n\t\t\t\"font-size\": [\n\t\t\t\t{\n\t\t\t\t\ttext: [\n\t\t\t\t\t\t\"gdt-display\",\n\t\t\t\t\t\t\"gdt-h1\",\n\t\t\t\t\t\t\"gdt-h2\",\n\t\t\t\t\t\t\"gdt-h3\",\n\t\t\t\t\t\t\"gdt-h4\",\n\t\t\t\t\t\t\"gdt-h5\",\n\t\t\t\t\t\t\"gdt-xl\",\n\t\t\t\t\t\t\"gdt-lg\",\n\t\t\t\t\t\t\"gdt-md\",\n\t\t\t\t\t\t\"gdt-sm\",\n\t\t\t\t\t\t\"gdt-xs\",\n\t\t\t\t\t\t\"gdt-subtext\",\n\t\t\t\t\t\t\"gdt-capitalized\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n});\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Loader } from \"lucide-react\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { useComponentSize } from \"./size-context\";\n\nconst buttonVariants = cva(\n\t\"group/button inline-flex shrink-0 items-center justify-center rounded-full bg-clip-padding whitespace-nowrap font-bold transition-[background-color,color,border-color,box-shadow,transform] outline-none select-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n\t{\n\t\tvariants: {\n\t\t\tvariant: {\n\t\t\t\tprimary:\n\t\t\t\t\t\"bg-action-primary text-fg-on-brand hover:bg-action-primary-hover active:bg-action-primary-pressed\",\n\t\t\t\t\"primary-outline\":\n\t\t\t\t\t\"border-2 border-action-primary bg-transparent text-fg-brand hover:bg-surface-brand-subtle active:bg-surface-brand-subtle data-focused:bg-surface-brand-subtle data-pressed:bg-surface-brand-subtle\",\n\t\t\t\tsecondary:\n\t\t\t\t\t\"bg-surface-brand-subtle text-fg-brand hover:bg-action-primary-hover hover:text-fg-on-brand active:bg-action-primary-pressed active:text-fg-on-brand data-focused:bg-action-primary-hover data-pressed:bg-action-primary-pressed data-focused:text-fg-on-brand data-pressed:text-fg-on-brand\",\n\t\t\t\t\"secondary-outline\":\n\t\t\t\t\t\"border-2 border-action-secondary bg-transparent text-fg-brand hover:bg-surface-brand-subtle active:bg-surface-brand-subtle data-focused:bg-surface-brand-subtle data-pressed:bg-surface-brand-subtle\",\n\t\t\t\ttertiary:\n\t\t\t\t\t\"bg-action-tertiary text-fg-primary hover:bg-action-tertiary-hover active:bg-action-tertiary-pressed data-focused:bg-action-tertiary-hover data-pressed:bg-action-tertiary-pressed\",\n\t\t\t\t\"tertiary-outline\":\n\t\t\t\t\t\"border border-line-strong bg-transparent text-fg-primary hover:bg-surface active:bg-surface-raised data-focused:bg-surface data-pressed:bg-surface-raised\",\n\t\t\t\tghost:\n\t\t\t\t\t\"bg-transparent text-fg-primary hover:bg-surface active:bg-surface-raised data-focused:bg-surface data-pressed:bg-surface-raised\",\n\t\t\t\tdanger:\n\t\t\t\t\t\"bg-action-danger text-fg-on-brand hover:bg-action-danger-hover active:bg-action-danger-pressed data-focused:bg-action-danger-hover data-pressed:bg-action-danger-pressed\",\n\t\t\t\t\"glass-overlay\": \"bg-surface-glass-overlay-button text-fg-on-brand\",\n\t\t\t\t\"link-brand\":\n\t\t\t\t\t\"border-transparent bg-transparent px-0 text-fg-brand hover:underline active:underline active:opacity-70\",\n\t\t\t\t\"link-neutral\":\n\t\t\t\t\t\"border-transparent bg-transparent px-0 text-fg-secondary hover:underline active:underline active:opacity-70\",\n\t\t\t},\n\t\t\tsize: {\n\t\t\t\tsm: \"h-8 gap-2 px-3.5 text-gdt-xs has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3 [&_svg:not([class*='size-'])]:size-3.5\",\n\t\t\t\tmd: \"h-10 gap-2 px-4.5 text-gdt-sm has-data-[icon=inline-end]:pr-4 has-data-[icon=inline-start]:pl-4\",\n\t\t\t\tlg: \"h-12.5 gap-2.5 px-5.5 text-gdt-md has-data-[icon=inline-end]:pr-5 has-data-[icon=inline-start]:pl-5 [&_svg:not([class*='size-'])]:size-4.5\",\n\t\t\t\txl: \"h-14 gap-3 px-6.5 text-gdt-lg has-data-[icon=inline-end]:pr-6 has-data-[icon=inline-start]:pl-6 [&_svg:not([class*='size-'])]:size-5\",\n\t\t\t\ticon: \"size-10\",\n\t\t\t\t\"icon-xs\": \"size-6 text-gdt-xs [&_svg:not([class*='size-'])]:size-3\",\n\t\t\t\t\"icon-sm\": \"size-8 text-gdt-sm [&_svg:not([class*='size-'])]:size-3.5\",\n\t\t\t\t\"icon-lg\":\n\t\t\t\t\t\"size-12.5 text-gdt-md [&_svg:not([class*='size-'])]:size-4.5\",\n\t\t\t\t\"icon-xl\": \"size-14 text-gdt-lg [&_svg:not([class*='size-'])]:size-5\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\tvariant: \"primary\",\n\t\t\tsize: \"md\",\n\t\t},\n\t},\n);\n\ntype ButtonSize = NonNullable<VariantProps<typeof buttonVariants>[\"size\"]>;\n\nfunction Button({\n\tclassName,\n\tvariant = \"primary\",\n\tsize,\n\tisLoading = false,\n\tchildren,\n\tdisabled = false,\n\t...props\n}: ButtonPrimitive.Props &\n\tVariantProps<typeof buttonVariants> & { isLoading?: boolean }) {\n\tconst inheritedSize = useComponentSize();\n\tconst resolvedSize = size ?? inheritedSize;\n\tconst _disabled = disabled || isLoading;\n\treturn (\n\t\t<ButtonPrimitive\n\t\t\tdata-slot=\"button\"\n\t\t\tclassName={cn(buttonVariants({ variant, size: resolvedSize, className }))}\n\t\t\tdisabled={_disabled}\n\t\t\t{...props}\n\t\t>\n\t\t\t{isLoading && <Loader className=\"size-4 animate-spin\" />} {children}\n\t\t</ButtonPrimitive>\n\t);\n}\n\ntype ButtonLinkProps = Omit<React.ComponentProps<\"a\">, \"href\"> &\n\tVariantProps<typeof buttonVariants> & {\n\t\tdisabled?: boolean;\n\t\thref: string;\n\t};\n\nfunction ButtonLink({\n\tclassName,\n\thref,\n\tvariant = \"primary\",\n\tsize,\n\tdisabled = false,\n\tonClick,\n\t...props\n}: ButtonLinkProps) {\n\tconst inheritedSize = useComponentSize();\n\tconst resolvedSize: ButtonSize = size ?? inheritedSize;\n\n\treturn (\n\t\t<a\n\t\t\tdata-slot=\"button-link\"\n\t\t\thref={href}\n\t\t\taria-disabled={disabled}\n\t\t\ttabIndex={disabled ? -1 : props.tabIndex}\n\t\t\tclassName={cn(buttonVariants({ variant, size: resolvedSize, className }))}\n\t\t\tonClick={(event) => {\n\t\t\t\tif (disabled) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tonClick?.(event);\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport { Button, ButtonLink, buttonVariants };\n","\"use client\";\n\nimport { createContext, type ReactNode, useContext } from \"react\";\n\ntype ComponentSize = \"sm\" | \"md\" | \"lg\";\n\nconst SizeContext = createContext<ComponentSize | undefined>(undefined);\n\nfunction SizeProvider({\n\tchildren,\n\tsize,\n}: {\n\tchildren: ReactNode;\n\tsize?: ComponentSize | null;\n}) {\n\tif (!size) {\n\t\treturn <>{children}</>;\n\t}\n\n\treturn <SizeContext.Provider value={size}>{children}</SizeContext.Provider>;\n}\n\nfunction useComponentSize(\n\tsize?: ComponentSize | null,\n\tfallback: ComponentSize = \"md\",\n) {\n\tconst inheritedSize = useContext(SizeContext);\n\treturn size ?? inheritedSize ?? fallback;\n}\n\nexport { SizeProvider, useComponentSize, type ComponentSize };\n","\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport useEmblaCarousel, {\n\ttype UseEmblaCarouselType,\n} from \"embla-carousel-react\";\nimport { ChevronLeftIcon, ChevronRightIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { type ComponentSize, useComponentSize } from \"./size-context\";\n\ntype CarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>;\ntype CarouselOptions = UseCarouselParameters[0];\ntype CarouselPlugin = UseCarouselParameters[1];\n\n/**\n * Shared glassmorphic treatment for every overlay surface in the carousel\n * (navigation arrows + indicator). Dark glass at 35% over a 16px backdrop\n * blur with a near-invisible 18% light border that lifts the chrome off the\n * imagery. Always dark, in both themes — see `--color-surface-glass-overlay-button`.\n */\nconst glassChrome =\n\t\"border border-fg-on-brand/[0.18] bg-surface-glass-overlay-button backdrop-blur-[16px]\";\n\nconst carouselVariants = cva(\n\t\"relative overflow-hidden rounded-2xl bg-surface-brand-subtle\",\n\t{\n\t\tvariants: {\n\t\t\timageSize: {\n\t\t\t\tsm: \"w-[320px] max-w-full aspect-[320/220]\",\n\t\t\t\tmd: \"w-[520px] max-w-full aspect-[520/340]\",\n\t\t\t\tlg: \"w-[800px] max-w-full aspect-[800/500]\",\n\t\t\t\tfull: \"w-full\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\timageSize: \"md\",\n\t\t},\n\t},\n);\n\ntype CarouselContextProps = {\n\tcarouselRef: ReturnType<typeof useEmblaCarousel>[0];\n\tapi: CarouselApi;\n\torientation: \"horizontal\" | \"vertical\";\n\tsize: ComponentSize;\n\tscrollPrev: () => void;\n\tscrollNext: () => void;\n\tscrollTo: (index: number) => void;\n\tcanScrollPrev: boolean;\n\tcanScrollNext: boolean;\n\tselectedIndex: number;\n\tscrollSnaps: number[];\n};\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null);\n\nfunction useCarousel() {\n\tconst context = React.useContext(CarouselContext);\n\n\tif (!context) {\n\t\tthrow new Error(\"useCarousel must be used within a <Carousel />\");\n\t}\n\n\treturn context;\n}\n\ntype CarouselProps = {\n\topts?: CarouselOptions;\n\tplugins?: CarouselPlugin;\n\torientation?: \"horizontal\" | \"vertical\";\n\t/** Scales the chrome (arrows + indicator) without touching the image. */\n\tsize?: ComponentSize;\n\tsetApi?: (api: CarouselApi) => void;\n};\n\nfunction Carousel({\n\torientation = \"horizontal\",\n\topts,\n\tsetApi,\n\tplugins,\n\tsize,\n\timageSize,\n\tclassName,\n\tchildren,\n\t...props\n}: React.ComponentProps<\"div\"> &\n\tCarouselProps &\n\tVariantProps<typeof carouselVariants>) {\n\tconst resolvedSize = useComponentSize(size);\n\tconst [carouselRef, api] = useEmblaCarousel(\n\t\t{\n\t\t\t...opts,\n\t\t\taxis: orientation === \"horizontal\" ? \"x\" : \"y\",\n\t\t},\n\t\tplugins,\n\t);\n\tconst [canScrollPrev, setCanScrollPrev] = React.useState(false);\n\tconst [canScrollNext, setCanScrollNext] = React.useState(false);\n\tconst [selectedIndex, setSelectedIndex] = React.useState(0);\n\tconst [scrollSnaps, setScrollSnaps] = React.useState<number[]>([]);\n\n\tconst onSelect = React.useCallback((api: CarouselApi) => {\n\t\tif (!api) return;\n\t\tsetCanScrollPrev(api.canScrollPrev());\n\t\tsetCanScrollNext(api.canScrollNext());\n\t\tsetSelectedIndex(api.selectedScrollSnap());\n\t}, []);\n\n\tconst onReInit = React.useCallback(\n\t\t(api: CarouselApi) => {\n\t\t\tif (!api) return;\n\t\t\tsetScrollSnaps(api.scrollSnapList());\n\t\t\tonSelect(api);\n\t\t},\n\t\t[onSelect],\n\t);\n\n\tconst scrollPrev = React.useCallback(() => {\n\t\tapi?.scrollPrev();\n\t}, [api]);\n\n\tconst scrollNext = React.useCallback(() => {\n\t\tapi?.scrollNext();\n\t}, [api]);\n\n\tconst scrollTo = React.useCallback(\n\t\t(index: number) => {\n\t\t\tapi?.scrollTo(index);\n\t\t},\n\t\t[api],\n\t);\n\n\tconst handleKeyDown = React.useCallback(\n\t\t(event: React.KeyboardEvent<HTMLDivElement>) => {\n\t\t\tif (event.key === \"ArrowLeft\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tscrollPrev();\n\t\t\t} else if (event.key === \"ArrowRight\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tscrollNext();\n\t\t\t}\n\t\t},\n\t\t[scrollPrev, scrollNext],\n\t);\n\n\tReact.useEffect(() => {\n\t\tif (!api || !setApi) return;\n\t\tsetApi(api);\n\t}, [api, setApi]);\n\n\tReact.useEffect(() => {\n\t\tif (!api) return;\n\t\tonReInit(api);\n\t\tapi.on(\"reInit\", onReInit);\n\t\tapi.on(\"select\", onSelect);\n\n\t\treturn () => {\n\t\t\tapi?.off(\"reInit\", onReInit);\n\t\t\tapi?.off(\"select\", onSelect);\n\t\t};\n\t}, [api, onReInit, onSelect]);\n\n\treturn (\n\t\t<CarouselContext.Provider\n\t\t\tvalue={{\n\t\t\t\tcarouselRef,\n\t\t\t\tapi,\n\t\t\t\torientation,\n\t\t\t\tsize: resolvedSize,\n\t\t\t\tscrollPrev,\n\t\t\t\tscrollNext,\n\t\t\t\tscrollTo,\n\t\t\t\tcanScrollPrev,\n\t\t\t\tcanScrollNext,\n\t\t\t\tselectedIndex,\n\t\t\t\tscrollSnaps,\n\t\t\t}}\n\t\t>\n\t\t\t{/* biome-ignore lint/a11y/useSemanticElements: the W3C carousel pattern is a region with aria-roledescription, not a generic landmark element. */}\n\t\t\t<div\n\t\t\t\tonKeyDownCapture={handleKeyDown}\n\t\t\t\tclassName={cn(carouselVariants({ imageSize }), className)}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-roledescription=\"carousel\"\n\t\t\t\tdata-slot=\"carousel\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</CarouselContext.Provider>\n\t);\n}\n\nfunction CarouselContent({ className, ...props }: React.ComponentProps<\"div\">) {\n\tconst { carouselRef, orientation } = useCarousel();\n\n\treturn (\n\t\t<div\n\t\t\tref={carouselRef}\n\t\t\tclassName=\"h-full overflow-hidden\"\n\t\t\tdata-slot=\"carousel-content\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex h-full\",\n\t\t\t\t\torientation === \"horizontal\" ? \"\" : \"flex-col\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nfunction CarouselItem({ className, ...props }: React.ComponentProps<\"div\">) {\n\treturn (\n\t\t// biome-ignore lint/a11y/useSemanticElements: a carousel slide is a role=\"group\" with aria-roledescription per the W3C pattern, not a fieldset.\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-roledescription=\"slide\"\n\t\t\tdata-slot=\"carousel-item\"\n\t\t\tclassName={cn(\"min-w-0 shrink-0 grow-0 basis-full\", className)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nconst arrowVariants = cva(\n\tcn(\n\t\t\"absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center rounded-full text-fg-on-brand/95 shadow-1 transition-[transform,opacity] outline-none\",\n\t\tglassChrome,\n\t\t\"hover:scale-105 focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:scale-95 disabled:pointer-events-none disabled:opacity-40\",\n\t),\n\t{\n\t\tvariants: {\n\t\t\tsize: {\n\t\t\t\tsm: \"size-8 [&_svg]:size-4\",\n\t\t\t\tmd: \"size-10 [&_svg]:size-[18px]\",\n\t\t\t\tlg: \"size-12 [&_svg]:size-5\",\n\t\t\t},\n\t\t\tside: {\n\t\t\t\tprev: \"\",\n\t\t\t\tnext: \"\",\n\t\t\t},\n\t\t},\n\t\tcompoundVariants: [\n\t\t\t{ size: \"sm\", side: \"prev\", className: \"left-3\" },\n\t\t\t{ size: \"sm\", side: \"next\", className: \"right-3\" },\n\t\t\t{ size: \"md\", side: \"prev\", className: \"left-4\" },\n\t\t\t{ size: \"md\", side: \"next\", className: \"right-4\" },\n\t\t\t{ size: \"lg\", side: \"prev\", className: \"left-5\" },\n\t\t\t{ size: \"lg\", side: \"next\", className: \"right-5\" },\n\t\t],\n\t\tdefaultVariants: {\n\t\t\tsize: \"md\",\n\t\t\tside: \"prev\",\n\t\t},\n\t},\n);\n\nfunction CarouselPrevious({\n\tclassName,\n\t...props\n}: React.ComponentProps<\"button\">) {\n\tconst { size, scrollPrev, canScrollPrev } = useCarousel();\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdata-slot=\"carousel-previous\"\n\t\t\tclassName={cn(arrowVariants({ size, side: \"prev\" }), className)}\n\t\t\tdisabled={!canScrollPrev}\n\t\t\tonClick={scrollPrev}\n\t\t\t{...props}\n\t\t>\n\t\t\t<ChevronLeftIcon className=\"cn-rtl-flip\" />\n\t\t\t<span className=\"sr-only\">Previous slide</span>\n\t\t</button>\n\t);\n}\n\nfunction CarouselNext({ className, ...props }: React.ComponentProps<\"button\">) {\n\tconst { size, scrollNext, canScrollNext } = useCarousel();\n\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tdata-slot=\"carousel-next\"\n\t\t\tclassName={cn(arrowVariants({ size, side: \"next\" }), className)}\n\t\t\tdisabled={!canScrollNext}\n\t\t\tonClick={scrollNext}\n\t\t\t{...props}\n\t\t>\n\t\t\t<ChevronRightIcon className=\"cn-rtl-flip\" />\n\t\t\t<span className=\"sr-only\">Next slide</span>\n\t\t</button>\n\t);\n}\n\n/**\n * Past this many items the indicator switches from \"show every dot\" to the\n * Airbnb-style windowed mode: at most `MANY_WINDOW` dots, the active one kept\n * near the centre, and dots at a clipped edge faded down to imply more beyond.\n */\nconst MANY_THRESHOLD = 5;\nconst MANY_WINDOW = 5;\n\ntype IndicatorDot = {\n\t/** Index into the full list of slides. */\n\tindex: number;\n\t/** True for the outermost dot on a side that has hidden slides beyond it. */\n\tfaded: boolean;\n};\n\n/**\n * Returns the dots to render plus the window start, so the determinate and\n * windowed (\"many\") cases share one render path. The dot strip is always the\n * full list; `start` drives the translate that slides it under the viewport.\n */\nfunction getIndicatorWindow(count: number, selected: number) {\n\tif (count < MANY_THRESHOLD) {\n\t\tconst dots: IndicatorDot[] = Array.from({ length: count }, (_, index) => ({\n\t\t\tindex,\n\t\t\tfaded: false,\n\t\t}));\n\t\treturn { dots, start: 0, visible: count };\n\t}\n\n\tconst half = Math.floor(MANY_WINDOW / 2);\n\tconst start = Math.max(0, Math.min(selected - half, count - MANY_WINDOW));\n\tconst end = start + MANY_WINDOW - 1;\n\tconst overflowLeft = start > 0;\n\tconst overflowRight = end < count - 1;\n\n\tconst dots: IndicatorDot[] = Array.from({ length: count }, (_, index) => ({\n\t\tindex,\n\t\tfaded:\n\t\t\t(overflowLeft && index === start) || (overflowRight && index === end),\n\t}));\n\n\treturn { dots, start, visible: MANY_WINDOW };\n}\n\n/** Dot diameter, gap, and pill padding per size — in px to keep them crisp. */\nconst INDICATOR_SIZES: Record<\n\tComponentSize,\n\t{ dot: number; gap: number; padX: number; padY: number }\n> = {\n\tsm: { dot: 5, gap: 4, padX: 8, padY: 4 },\n\tmd: { dot: 7, gap: 5, padX: 10, padY: 5 },\n\tlg: { dot: 9, gap: 6, padX: 12, padY: 6 },\n};\n\n/** Distance of the indicator from the bottom edge, per size (12/18/24px). */\nconst INDICATOR_OFFSET: Record<ComponentSize, string> = {\n\tsm: \"bottom-3\",\n\tmd: \"bottom-[18px]\",\n\tlg: \"bottom-6\",\n};\n\ntype CarouselIndicatorProps = Omit<\n\tReact.ComponentProps<\"div\">,\n\t\"children\" | \"onSelect\"\n> & {\n\t/** Override the live count (e.g. for static design previews). */\n\tcount?: number;\n\t/** Override the live selected index. */\n\tselected?: number;\n\t/** Override the inherited carousel size. */\n\tsize?: ComponentSize;\n\t/** Jump to a slide when a dot is activated. Defaults to the carousel API. */\n\tonSelect?: (index: number) => void;\n};\n\nfunction CarouselIndicator({\n\tclassName,\n\tcount: countProp,\n\tselected: selectedProp,\n\tsize: sizeProp,\n\tonSelect,\n\t...props\n}: CarouselIndicatorProps) {\n\t// Read context loosely so the indicator can also stand alone (previews,\n\t// docs) by passing `count`/`selected` directly.\n\tconst ctx = React.useContext(CarouselContext);\n\tconst inheritedSize = useComponentSize(sizeProp);\n\n\tconst size = sizeProp ?? ctx?.size ?? inheritedSize;\n\tconst count = countProp ?? ctx?.scrollSnaps.length ?? 0;\n\tconst selected = selectedProp ?? ctx?.selectedIndex ?? 0;\n\tconst handleSelect = onSelect ?? ctx?.scrollTo;\n\n\tif (count <= 1) return null;\n\n\tconst { dot, gap, padX, padY } = INDICATOR_SIZES[size];\n\tconst { dots, start, visible } = getIndicatorWindow(count, selected);\n\tconst step = dot + gap;\n\t// Viewport width clips the strip to exactly `visible` dots; the strip then\n\t// translates by `start` steps so the windowed dots line up under it.\n\tconst viewportWidth = visible * step - gap;\n\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"carousel-indicator\"\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute left-1/2 z-10 flex -translate-x-1/2 items-center justify-center rounded-full\",\n\t\t\t\tINDICATOR_OFFSET[size],\n\t\t\t\tglassChrome,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={{ padding: `${padY}px ${padX}px` }}\n\t\t\trole=\"tablist\"\n\t\t\taria-label=\"Slide indicators\"\n\t\t\t{...props}\n\t\t>\n\t\t\t<div className=\"overflow-hidden\" style={{ width: viewportWidth }}>\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"flex items-center transition-transform duration-300 ease-out\"\n\t\t\t\t\tstyle={{ gap, transform: `translateX(${-start * step}px)` }}\n\t\t\t\t>\n\t\t\t\t\t{dots.map(({ index, faded }) => {\n\t\t\t\t\t\tconst isActive = index === selected;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\taria-selected={isActive}\n\t\t\t\t\t\t\t\taria-label={`Go to slide ${index + 1}`}\n\t\t\t\t\t\t\t\tonClick={() => handleSelect?.(index)}\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"shrink-0 rounded-full bg-fg-on-brand transition-[transform,opacity] duration-300 ease-out\",\n\t\t\t\t\t\t\t\t\thandleSelect ? \"cursor-pointer\" : \"cursor-default\",\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\twidth: dot,\n\t\t\t\t\t\t\t\t\theight: dot,\n\t\t\t\t\t\t\t\t\topacity: faded ? 0.3 : isActive ? 1 : 0.55,\n\t\t\t\t\t\t\t\t\ttransform: faded ? \"scale(0.6)\" : \"scale(1)\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nexport {\n\ttype CarouselApi,\n\tCarousel,\n\tCarouselContent,\n\tCarouselItem,\n\tCarouselPrevious,\n\tCarouselNext,\n\tCarouselIndicator,\n\tuseCarousel,\n};\n"],"mappings":"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","names":["ChevronLeftIcon","ChevronRightIcon","React","jsx","cva","jsx","jsxs","cva","api","Fragment","jsx","jsxs","ChevronLeftIcon","ChevronRightIcon"]}
|
|
1
|
+
{"version":3,"sources":["../src/photo-gallery.tsx"],"sourcesContent":["\"use client\";\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport {\n\tChevronLeftIcon,\n\tChevronRightIcon,\n\tFullscreen,\n\tXIcon,\n} from \"lucide-react\";\nimport type { SVGProps } from \"react\";\nimport * as React from \"react\";\nimport { Button } from \"./button\";\nimport {\n\tCarousel,\n\ttype CarouselApi,\n\tCarouselContent,\n\tCarouselItem,\n} from \"./carousel\";\nimport { cn } from \"./lib/cn\";\n\n/**\n * A single property photo. `src` is optional so the gallery can render a\n * \"Property Image\" placeholder in previews / while imagery is still loading.\n */\ntype PhotoGalleryImage = {\n\tsrc?: string;\n\talt?: string;\n};\n\n/**\n * Wires an Embla carousel to a controlled/uncontrolled active index. Returns\n * the `setApi` to hand to {@link Carousel} plus the live index and navigation\n * helpers. Both surfaces share this so the inline carousel and the fullscreen\n * viewer can stand alone — or stay in sync by sharing `index`/`onIndexChange`.\n */\nfunction useGalleryCarousel(\n\tindex: number | undefined,\n\tonIndexChange: ((index: number) => void) | undefined,\n) {\n\tconst [api, setApi] = React.useState<CarouselApi>();\n\tconst [selectedIndex, setSelectedIndex] = React.useState(index ?? 0);\n\tconst initialIndexRef = React.useRef(index ?? 0);\n\n\t// Keep the change callback in a ref so subscribing doesn't depend on a\n\t// caller passing a stable function identity.\n\tconst onIndexChangeRef = React.useRef(onIndexChange);\n\tReact.useEffect(() => {\n\t\tonIndexChangeRef.current = onIndexChange;\n\t});\n\n\tReact.useEffect(() => {\n\t\tif (!api) return;\n\t\tconst onSelect = () => {\n\t\t\tconst next = api.selectedScrollSnap();\n\t\t\tsetSelectedIndex(next);\n\t\t\tonIndexChangeRef.current?.(next);\n\t\t};\n\t\tonSelect();\n\t\tapi.on(\"select\", onSelect).on(\"reInit\", onSelect);\n\t\treturn () => {\n\t\t\tapi.off(\"select\", onSelect).off(\"reInit\", onSelect);\n\t\t};\n\t}, [api]);\n\n\t// Controlled mode: follow the index the parent hands down.\n\tReact.useEffect(() => {\n\t\tif (api && index !== undefined && index !== api.selectedScrollSnap()) {\n\t\t\tapi.scrollTo(index, false);\n\t\t}\n\t}, [api, index]);\n\n\tconst scrollTo = React.useCallback(\n\t\t(i: number) => api?.scrollTo(i, false),\n\t\t[api],\n\t);\n\tconst scrollPrev = React.useCallback(() => api?.scrollPrev(false), [api]);\n\tconst scrollNext = React.useCallback(() => api?.scrollNext(false), [api]);\n\n\treturn {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex: initialIndexRef.current,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t};\n}\n\n/* -------------------------------------------------------------------------- */\n/* Shared chrome */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The image surface. Centres its image within the slide; falls back to a\n * \"Property Image\" label when `src` is missing. `cover` fills and crops the\n * frame for the listing hero; `contain` clamps the photo to the frame's bounds\n * (`max-w`/`max-h`) so the whole image stays visible — never overflowing the\n * fullscreen viewer's chrome and never stretched out of its aspect ratio.\n */\nfunction GalleryFrame({\n\timage,\n\tfit = \"cover\",\n\tclassName,\n}: {\n\timage: PhotoGalleryImage | undefined;\n\tfit?: \"cover\" | \"contain\";\n\tclassName?: string;\n}) {\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery-frame\"\n\t\t\tclassName={cn(\n\t\t\t\t\"relative flex size-full items-center justify-center overflow-hidden\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{image?.src ? (\n\t\t\t\t<img\n\t\t\t\t\tsrc={image.src}\n\t\t\t\t\talt={image.alt ?? \"Property image\"}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\tfit === \"contain\"\n\t\t\t\t\t\t\t? \"max-h-full max-w-full rounded-lg object-contain\"\n\t\t\t\t\t\t\t: \"size-full object-cover\",\n\t\t\t\t\t)}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<span className=\"text-gdt-sm font-medium text-fg-caption-placeholder\">\n\t\t\t\t\tProperty Image\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nconst Images = (props: SVGProps<SVGSVGElement>) => (\n\t<svg\n\t\taria-hidden=\"true\"\n\t\txmlns=\"http://www.w3.org/2000/svg\"\n\t\twidth={15}\n\t\theight={16}\n\t\tviewBox=\"0 0 15 16\"\n\t\tfill=\"none\"\n\t\t{...props}\n\t>\n\t\t<path\n\t\t\tfill=\"currentColor\"\n\t\t\td=\"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\"\n\t\t/>\n\t\t<path\n\t\t\tfill=\"currentColor\"\n\t\t\td=\"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\"\n\t\t/>\n\t</svg>\n);\n\n/** Pill overlay showing `current / total`. Hidden when there is one image. */\nfunction GalleryCounter({\n\tcurrent,\n\ttotal,\n\tclassName,\n}: {\n\tcurrent: number;\n\ttotal: number;\n\tclassName?: string;\n}) {\n\tif (total <= 1) return null;\n\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery-counter\"\n\t\t\tclassName={cn(\n\t\t\t\t\"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\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<Images aria-hidden=\"true\" className=\"size-3.5\" />\n\t\t\t<span>\n\t\t\t\t{current} / {total}\n\t\t\t</span>\n\t\t</div>\n\t);\n}\n\nfunction GalleryButton({\n\tclassName,\n\tvariant = \"ghost\",\n\t...rest\n}: React.ComponentProps<typeof Button>) {\n\treturn (\n\t\t<Button\n\t\t\tsize=\"icon\"\n\t\t\tclassName={cn(\n\t\t\t\t\"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\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tvariant={variant}\n\t\t\t{...rest}\n\t\t/>\n\t);\n}\n\n/** Circular floating navigation button. Always present; the track loops. */\nfunction GalleryArrow({\n\tside,\n\tonClick,\n\tclassName,\n}: {\n\tside: \"prev\" | \"next\";\n\tonClick: () => void;\n\tclassName?: string;\n}) {\n\tconst Icon = side === \"prev\" ? ChevronLeftIcon : ChevronRightIcon;\n\treturn (\n\t\t<GalleryButton\n\t\t\ttype=\"button\"\n\t\t\tdata-slot={`photo-gallery-${side}`}\n\t\t\taria-label={side === \"prev\" ? \"Previous photo\" : \"Next photo\"}\n\t\t\tonClick={(event) => {\n\t\t\t\tevent.stopPropagation();\n\t\t\t\tonClick();\n\t\t\t}}\n\t\t\tclassName={cn(\n\t\t\t\t\"absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center active:not-aria-[haspopup]:-translate-y-1/2\",\n\t\t\t\tside === \"prev\" ? \"left-2 sm:left-4\" : \"right-2 sm:right-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t<Icon className=\"cn-rtl-flip size-4 sm:size-5\" />\n\t\t</GalleryButton>\n\t);\n}\n\n/**\n * Equal-sized thumbnail strip. `cols` are sized via CSS vars so exactly N fill\n * the width (5 on mobile, more on web); extras overflow and scroll. The active\n * thumb gets a 2px focus stroke and is kept in view as the index changes.\n */\nfunction GalleryThumbnails({\n\timages,\n\tselectedIndex,\n\tonSelect,\n\tcolsClassName,\n\tclassName,\n}: {\n\timages: PhotoGalleryImage[];\n\tselectedIndex: number;\n\tonSelect: (index: number) => void;\n\tcolsClassName: string;\n\tclassName?: string;\n}) {\n\tconst containerRef = React.useRef<HTMLDivElement>(null);\n\tconst hasPositionedRef = React.useRef(false);\n\tconst [overflowing, setOverflowing] = React.useState(false);\n\n\t// Track whether the strip is wider than its container so it can be centred\n\t// while every thumb fits, and only switch to a scrollable, start-aligned\n\t// strip once they overflow (centring an overflowing scroller clips the\n\t// leading thumbs out of reach).\n\tReact.useEffect(() => {\n\t\tconst el = containerRef.current;\n\t\tif (!el) return;\n\t\tconst update = () => setOverflowing(el.scrollWidth > el.clientWidth + 1);\n\t\tupdate();\n\t\tconst observer = new ResizeObserver(update);\n\t\tobserver.observe(el);\n\t\treturn () => observer.disconnect();\n\t}, []);\n\n\tReact.useEffect(() => {\n\t\tconst active = containerRef.current?.children[selectedIndex];\n\t\tif (!active) return;\n\t\t// Jump instantly the first time (e.g. when the viewer opens on a non-zero\n\t\t// index) so the current thumb is already in view without a visible scroll;\n\t\t// animate on subsequent navigation.\n\t\tactive.scrollIntoView({\n\t\t\tbehavior: hasPositionedRef.current ? \"smooth\" : \"auto\",\n\t\t\tinline: \"center\",\n\t\t\tblock: \"nearest\",\n\t\t});\n\t\thasPositionedRef.current = true;\n\t}, [selectedIndex]);\n\n\tif (images.length <= 1) return null;\n\n\treturn (\n\t\t<div\n\t\t\tref={containerRef}\n\t\t\tdata-slot=\"photo-gallery-thumbnails\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex gap-2 overflow-x-auto [--gallery-gap:0.5rem] scrollbar-none [&::-webkit-scrollbar]:hidden\",\n\t\t\t\toverflowing ? \"justify-start\" : \"justify-center\",\n\t\t\t\tcolsClassName,\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t>\n\t\t\t{images.map((image, index) => {\n\t\t\t\tconst isActive = index === selectedIndex;\n\t\t\t\treturn (\n\t\t\t\t\t<button\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\taria-label={`View photo ${index + 1}`}\n\t\t\t\t\t\taria-current={isActive}\n\t\t\t\t\t\tonClick={() => onSelect(index)}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\twidth:\n\t\t\t\t\t\t\t\t\"calc((100% - (var(--gallery-cols) - 1) * var(--gallery-gap)) / var(--gallery-cols))\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"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)]\",\n\t\t\t\t\t\t\tisActive\n\t\t\t\t\t\t\t\t? \"border-line-focus\"\n\t\t\t\t\t\t\t\t: \"border-transparent opacity-80 hover:opacity-100\",\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{image.src ? (\n\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\tsrc={image.src}\n\t\t\t\t\t\t\t\talt={image.alt ?? `Property image ${index + 1}`}\n\t\t\t\t\t\t\t\tclassName=\"size-full object-cover\"\n\t\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</button>\n\t\t\t\t);\n\t\t\t})}\n\t\t</div>\n\t);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Inline carousel */\n/* -------------------------------------------------------------------------- */\n\ntype PhotoGalleryProps = Omit<React.ComponentProps<\"div\">, \"onClick\"> & {\n\timages: PhotoGalleryImage[];\n\t/** Controlled active index. Omit to let the gallery manage it internally. */\n\tindex?: number;\n\tonIndexChange?: (index: number) => void;\n\t/** Called when the hero image is activated — wire this to open fullscreen. */\n\tonImageClick?: (index: number) => void;\n};\n\n/**\n * Inline property gallery: a swipeable hero image (drag / touch / ← →) with a\n * counter pill, navigation arrows, and a thumbnail strip below. Built on\n * {@link Carousel}. Standalone — pass `onImageClick` to open it into a\n * {@link PhotoGalleryFullscreen} viewer, but neither surface needs the other.\n */\nfunction PhotoGallery({\n\timages,\n\tindex,\n\tonIndexChange,\n\tonImageClick,\n\tclassName,\n\t...props\n}: PhotoGalleryProps) {\n\tconst {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t} = useGalleryCarousel(index, onIndexChange);\n\tconst hasMany = images.length > 1;\n\n\treturn (\n\t\t<div\n\t\t\tdata-slot=\"photo-gallery\"\n\t\t\tclassName={cn(\n\t\t\t\t\"flex w-full flex-col gap-3 rounded-2xl border border-line bg-surface p-3\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Carousel\n\t\t\t\timageSize=\"full\"\n\t\t\t\tsetApi={setApi}\n\t\t\t\topts={{ loop: true, startIndex: initialIndex, watchDrag: hasMany }}\n\t\t\t\tclassName=\"aspect-video rounded-xl bg-surface-raised\"\n\t\t\t>\n\t\t\t\t<CarouselContent>\n\t\t\t\t\t{images.map((image, i) => (\n\t\t\t\t\t\t<CarouselItem\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<GalleryFrame image={image} />\n\t\t\t\t\t\t</CarouselItem>\n\t\t\t\t\t))}\n\t\t\t\t</CarouselContent>\n\t\t\t\t{onImageClick && (\n\t\t\t\t\t<GalleryButton\n\t\t\t\t\t\tclassName=\"absolute bottom-2 right-2 sm:bottom-4 sm:right-4\"\n\t\t\t\t\t\tonClick={() => onImageClick(selectedIndex)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Fullscreen className=\"size-4 md:size-5\" />\n\t\t\t\t\t</GalleryButton>\n\t\t\t\t)}\n\n\t\t\t\t<GalleryCounter\n\t\t\t\t\tcurrent={selectedIndex + 1}\n\t\t\t\t\ttotal={images.length}\n\t\t\t\t\tclassName=\"top-2 right-2 sm:top-4 md:right-4\"\n\t\t\t\t/>\n\t\t\t\t{hasMany && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<GalleryArrow side=\"prev\" onClick={scrollPrev} />\n\t\t\t\t\t\t<GalleryArrow side=\"next\" onClick={scrollNext} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Carousel>\n\n\t\t\t<GalleryThumbnails\n\t\t\t\timages={images}\n\t\t\t\tselectedIndex={selectedIndex}\n\t\t\t\tonSelect={scrollTo}\n\t\t\t\tcolsClassName=\"[--gallery-cols:5] sm:[--gallery-cols:8]\"\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Fullscreen viewer */\n/* -------------------------------------------------------------------------- */\n\ntype PhotoGalleryFullscreenProps = {\n\timages: PhotoGalleryImage[];\n\topen: boolean;\n\tonOpenChange: (open: boolean) => void;\n\t/** Controlled active index. Omit to let the viewer manage it internally. */\n\tindex?: number;\n\tonIndexChange?: (index: number) => void;\n};\n\n/**\n * Fullscreen lightbox: takes over the viewport over a dimmed backdrop for\n * distraction-free browsing. Swipeable (drag / touch) with ← → key navigation\n * and ESC to close. Built on {@link Carousel}; controlled via `open` /\n * `onOpenChange` and usable without the inline gallery.\n */\nfunction PhotoGalleryFullscreen({\n\timages,\n\topen,\n\tonOpenChange,\n\tindex,\n\tonIndexChange,\n}: PhotoGalleryFullscreenProps) {\n\tconst {\n\t\tsetApi,\n\t\tselectedIndex,\n\t\tinitialIndex,\n\t\tscrollTo,\n\t\tscrollPrev,\n\t\tscrollNext,\n\t} = useGalleryCarousel(index, onIndexChange);\n\tconst hasMany = images.length > 1;\n\n\tconst handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n\t\t// The carousel handles arrows in the capture phase when it holds focus;\n\t\t// skip so focus inside the track doesn't navigate twice.\n\t\tif (event.defaultPrevented) return;\n\t\tif (event.key === \"ArrowLeft\") {\n\t\t\tevent.preventDefault();\n\t\t\tscrollPrev();\n\t\t} else if (event.key === \"ArrowRight\") {\n\t\t\tevent.preventDefault();\n\t\t\tscrollNext();\n\t\t}\n\t};\n\n\treturn (\n\t\t<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogPrimitive.Portal>\n\t\t\t\t<DialogPrimitive.Backdrop\n\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen-backdrop\"\n\t\t\t\t\tclassName=\"fixed inset-0 z-50 bg-black/90 transition-opacity duration-150 data-closed:opacity-0 data-open:opacity-100\"\n\t\t\t\t/>\n\t\t\t\t<DialogPrimitive.Popup\n\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen\"\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tclassName=\"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\"\n\t\t\t\t>\n\t\t\t\t\t<DialogPrimitive.Title className=\"sr-only\">\n\t\t\t\t\t\tPhoto Gallery\n\t\t\t\t\t</DialogPrimitive.Title>\n\n\t\t\t\t\t<div className=\"w-full flex items-center justify-between\">\n\t\t\t\t\t\t<GalleryCounter\n\t\t\t\t\t\t\tcurrent={selectedIndex + 1}\n\t\t\t\t\t\t\ttotal={images.length}\n\t\t\t\t\t\t\tclassName=\"static\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<DialogPrimitive.Close\n\t\t\t\t\t\t\tdata-slot=\"photo-gallery-fullscreen-close\"\n\t\t\t\t\t\t\taria-label=\"Close gallery\"\n\t\t\t\t\t\t\trender={<GalleryButton />}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<XIcon className=\"size-4 sm:size-5\" />\n\t\t\t\t\t\t</DialogPrimitive.Close>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<Carousel\n\t\t\t\t\t\timageSize=\"full\"\n\t\t\t\t\t\tsetApi={setApi}\n\t\t\t\t\t\topts={{ loop: true, startIndex: initialIndex, watchDrag: hasMany }}\n\t\t\t\t\t\tclassName=\"min-h-0 flex-1 w-full rounded-xl bg-transparent\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<CarouselContent className=\"items-center\">\n\t\t\t\t\t\t\t{images.map((image, i) => (\n\t\t\t\t\t\t\t\t<CarouselItem\n\t\t\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: photos are a fixed, ordered list that never reorders, so the index is the stable identity.\n\t\t\t\t\t\t\t\t\tkey={i}\n\t\t\t\t\t\t\t\t\tclassName=\"h-full\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<GalleryFrame image={image} fit=\"contain\" />\n\t\t\t\t\t\t\t\t</CarouselItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</CarouselContent>\n\t\t\t\t\t\t{hasMany && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<GalleryArrow\n\t\t\t\t\t\t\t\t\tside=\"prev\"\n\t\t\t\t\t\t\t\t\tonClick={scrollPrev}\n\t\t\t\t\t\t\t\t\tclassName=\"left-0!\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<GalleryArrow\n\t\t\t\t\t\t\t\t\tside=\"next\"\n\t\t\t\t\t\t\t\t\tonClick={scrollNext}\n\t\t\t\t\t\t\t\t\tclassName=\"right-0!\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Carousel>\n\n\t\t\t\t\t{hasMany && (\n\t\t\t\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t\t\t\t<p className=\"hidden text-center text-gdt-xs text-fg-secondary sm:block\">\n\t\t\t\t\t\t\t\t← → to navigate · ESC to close\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<GalleryThumbnails\n\t\t\t\t\t\t\t\timages={images}\n\t\t\t\t\t\t\t\tselectedIndex={selectedIndex}\n\t\t\t\t\t\t\t\tonSelect={scrollTo}\n\t\t\t\t\t\t\t\tcolsClassName=\"[--gallery-cols:5] sm:[--gallery-cols:10]\"\n\t\t\t\t\t\t\t\tclassName=\"mx-auto w-full max-w-3xl\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</DialogPrimitive.Popup>\n\t\t\t</DialogPrimitive.Portal>\n\t\t</DialogPrimitive.Root>\n\t);\n}\n\nexport {\n\ttype PhotoGalleryImage,\n\ttype PhotoGalleryProps,\n\ttype PhotoGalleryFullscreenProps,\n\tPhotoGallery,\n\tPhotoGalleryFullscreen,\n};\n"],"mappings":"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","names":[]}
|
package/dist/pie-chart.js
CHANGED
|
@@ -1,49 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useComponentSize
|
|
4
|
+
} from "./chunk-HL3ZSYES.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-Y4TTYVNE.js";
|
|
3
8
|
|
|
4
|
-
// src/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
var twMerge = extendTailwindMerge({
|
|
8
|
-
extend: {
|
|
9
|
-
classGroups: {
|
|
10
|
-
"font-size": [
|
|
11
|
-
{
|
|
12
|
-
text: [
|
|
13
|
-
"gdt-display",
|
|
14
|
-
"gdt-h1",
|
|
15
|
-
"gdt-h2",
|
|
16
|
-
"gdt-h3",
|
|
17
|
-
"gdt-h4",
|
|
18
|
-
"gdt-h5",
|
|
19
|
-
"gdt-xl",
|
|
20
|
-
"gdt-lg",
|
|
21
|
-
"gdt-md",
|
|
22
|
-
"gdt-sm",
|
|
23
|
-
"gdt-xs",
|
|
24
|
-
"gdt-subtext",
|
|
25
|
-
"gdt-capitalized"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
function cn(...inputs) {
|
|
33
|
-
return twMerge(clsx(inputs));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/components/ui/size-context.tsx
|
|
37
|
-
import { createContext, useContext } from "react";
|
|
38
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
39
|
-
var SizeContext = createContext(void 0);
|
|
40
|
-
function useComponentSize(size, fallback = "md") {
|
|
41
|
-
const inheritedSize = useContext(SizeContext);
|
|
42
|
-
return size ?? inheritedSize ?? fallback;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// src/components/ui/pie-chart.tsx
|
|
46
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
9
|
+
// src/pie-chart.tsx
|
|
10
|
+
import { cva } from "class-variance-authority";
|
|
11
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
47
12
|
var PIE_CHART_LAYOUT = {
|
|
48
13
|
sm: {
|
|
49
14
|
size: 132,
|
|
@@ -116,7 +81,7 @@ function PieCenterLabel({
|
|
|
116
81
|
const { cx, cy } = viewBox;
|
|
117
82
|
const captionY = cy + label.totalFontSize * 0.72;
|
|
118
83
|
return /* @__PURE__ */ jsxs("text", { x: cx, y: cy, textAnchor: "middle", dominantBaseline: "central", children: [
|
|
119
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ jsx(
|
|
120
85
|
"tspan",
|
|
121
86
|
{
|
|
122
87
|
x: cx,
|
|
@@ -126,7 +91,7 @@ function PieCenterLabel({
|
|
|
126
91
|
children: total
|
|
127
92
|
}
|
|
128
93
|
),
|
|
129
|
-
caption != null && /* @__PURE__ */
|
|
94
|
+
caption != null && /* @__PURE__ */ jsx(
|
|
130
95
|
"tspan",
|
|
131
96
|
{
|
|
132
97
|
x: cx,
|
|
@@ -161,13 +126,13 @@ function PieChartLegend({
|
|
|
161
126
|
...props
|
|
162
127
|
}) {
|
|
163
128
|
const resolvedSize = useComponentSize(size);
|
|
164
|
-
return /* @__PURE__ */
|
|
129
|
+
return /* @__PURE__ */ jsx(
|
|
165
130
|
"ul",
|
|
166
131
|
{
|
|
167
132
|
className: cn(pieLegendVariants({ size: resolvedSize }), className),
|
|
168
133
|
...props,
|
|
169
134
|
children: items.map((item) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
170
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ jsx(
|
|
171
136
|
"span",
|
|
172
137
|
{
|
|
173
138
|
"aria-hidden": "true",
|
|
@@ -175,9 +140,9 @@ function PieChartLegend({
|
|
|
175
140
|
style: { backgroundColor: item.color }
|
|
176
141
|
}
|
|
177
142
|
),
|
|
178
|
-
/* @__PURE__ */
|
|
179
|
-
/* @__PURE__ */
|
|
180
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-fg-primary", children: item.label }),
|
|
144
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-fg-secondary", children: item.value }),
|
|
145
|
+
/* @__PURE__ */ jsx("span", { className: "w-9 shrink-0 text-right font-bold tabular-nums text-fg-primary", children: item.percentage })
|
|
181
146
|
] }, item.label))
|
|
182
147
|
}
|
|
183
148
|
);
|
package/dist/pie-chart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ui/pie-chart.tsx","../src/lib/cn.ts","../src/components/ui/size-context.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cn } from \"../../lib/cn\";\nimport { type ComponentSize, useComponentSize } from \"./size-context\";\n\n/**\n * Pie / donut charts are composed from recharts plot primitives directly —\n * recharts identifies `PieChart`, `Pie`, and `Cell` by component identity, so\n * they cannot be wrapped. This module supplies the giddaa-specific pieces that\n * would otherwise be copy-pasted: per-size layout numbers, a categorical\n * palette, the donut center label, and the rich legend (dot · name · value ·\n * percentage). Pair them with the shared frame from `./chart`.\n *\n * A donut keeps an open center for a total label (`innerRadius` > 0); a pie\n * fills the circle (`innerRadius={0}`). Both read the same layout.\n *\n * @example\n * const chart = usePieChartLayout({ size: \"md\", type: \"donut\" });\n * <ChartCard size=\"md\">\n * <div className=\"flex items-center gap-4\">\n * <ChartContainer config={config} {...chart.container}>\n * <PieChart>\n * <Pie data={data} dataKey=\"value\" nameKey=\"label\" {...chart.pie}>\n * {data.map((d) => <Cell key={d.label} fill={d.color} />)}\n * <Label content={<PieCenterLabel total=\"₦1.1M\" caption=\"Total spend\" />} />\n * </Pie>\n * </PieChart>\n * </ChartContainer>\n * <PieChartLegend items={legendItems} />\n * </div>\n * </ChartCard>\n */\n\n/** Pie sizes line up with the three shared `ComponentSize` values. */\ntype PieChartSize = ComponentSize;\n\ntype PieChartLayout = {\n\t/** Square plot box in px (width = height); width is NOT parent-driven here. */\n\tsize: number;\n\t/** Donut hole radius in px. Pass `0` to the `Pie` for a filled pie. */\n\tinnerRadius: number;\n\t/** Outer ring radius in px. */\n\touterRadius: number;\n\t/** Gap between segments, in degrees. */\n\tpaddingAngle: number;\n\t/** Corner radius of each segment. */\n\tcornerRadius: number;\n\t/** Center total font size. */\n\ttotalFontSize: number;\n\t/** Center caption font size. */\n\tcaptionFontSize: number;\n};\n\nconst PIE_CHART_LAYOUT: Record<PieChartSize, PieChartLayout> = {\n\tsm: {\n\t\tsize: 132,\n\t\tinnerRadius: 42,\n\t\touterRadius: 64,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 18,\n\t\tcaptionFontSize: 9,\n\t},\n\tmd: {\n\t\tsize: 176,\n\t\tinnerRadius: 56,\n\t\touterRadius: 84,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 24,\n\t\tcaptionFontSize: 11,\n\t},\n\tlg: {\n\t\tsize: 224,\n\t\tinnerRadius: 72,\n\t\touterRadius: 108,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 30,\n\t\tcaptionFontSize: 12,\n\t},\n};\n\n/**\n * Categorical palette for pie/donut segments, ordered by share. Giddaa has no\n * `chart-1`…`chart-N` tokens yet, so these map to the brand scales: forest →\n * brass → moss → clay → stone. Assign by index, or override per `Cell`.\n */\nconst PIE_CHART_PALETTE = [\n\t\"var(--color-forest-700)\",\n\t\"var(--color-brass-500)\",\n\t\"var(--color-moss-600)\",\n\t\"var(--color-clay-500)\",\n\t\"var(--color-stone-500)\",\n] as const;\n\n/**\n * Resolve the pie-chart layout for an explicit or inherited component size and\n * chart `type`. The returned object groups the giddaa defaults by the recharts\n * component they belong to — spread `container` onto `ChartContainer` and `pie`\n * onto `Pie`, then pass the data-specific props (`data`, `dataKey`, `nameKey`)\n * directly afterwards. `type=\"pie\"` collapses the donut hole (`innerRadius` 0).\n */\nfunction usePieChartLayout({\n\tsize,\n\ttype = \"donut\",\n}: {\n\tsize?: PieChartSize;\n\ttype?: \"donut\" | \"pie\";\n} = {}) {\n\tconst layout = PIE_CHART_LAYOUT[useComponentSize(size)];\n\n\treturn {\n\t\tcontainer: {\n\t\t\tclassName: \"aspect-square shrink-0\",\n\t\t\tstyle: { width: layout.size, height: layout.size },\n\t\t},\n\t\tpie: {\n\t\t\tinnerRadius: type === \"pie\" ? 0 : layout.innerRadius,\n\t\t\touterRadius: layout.outerRadius,\n\t\t\tpaddingAngle: type === \"pie\" ? 0 : layout.paddingAngle,\n\t\t\tcornerRadius: layout.cornerRadius,\n\t\t\tstrokeWidth: 0,\n\t\t},\n\t\tlabel: {\n\t\t\ttotalFontSize: layout.totalFontSize,\n\t\t\tcaptionFontSize: layout.captionFontSize,\n\t\t},\n\t};\n}\n\n/**\n * Center label for a donut — the hero total over a short caption. Pass it to\n * recharts as `<Label content={<PieCenterLabel total=… caption=… />} />` inside\n * the `Pie`; recharts injects the `viewBox` carrying the polar center (cx/cy).\n */\ntype PieCenterLabelProps = {\n\t/** Hero figure — pre-formatted, e.g. \"₦1.1M\". */\n\ttotal: React.ReactNode;\n\t/** Short label describing what the total represents, e.g. \"Total spend\". */\n\tcaption?: React.ReactNode;\n\t/** Explicit size; otherwise inherited from the nearest `SizeProvider`. */\n\tsize?: PieChartSize;\n\t// Injected by recharts at render time.\n\tviewBox?: { cx?: number; cy?: number };\n};\n\nfunction PieCenterLabel({\n\ttotal,\n\tcaption,\n\tsize,\n\tviewBox,\n}: PieCenterLabelProps) {\n\tconst { label } = usePieChartLayout({ size });\n\n\tif (!viewBox || viewBox.cx == null || viewBox.cy == null) {\n\t\treturn null;\n\t}\n\n\tconst { cx, cy } = viewBox;\n\tconst captionY = cy + label.totalFontSize * 0.72;\n\n\treturn (\n\t\t<text x={cx} y={cy} textAnchor=\"middle\" dominantBaseline=\"central\">\n\t\t\t<tspan\n\t\t\t\tx={cx}\n\t\t\t\ty={caption == null ? cy : cy - label.captionFontSize * 0.5}\n\t\t\t\tclassName=\"fill-fg-primary font-extrabold tabular-nums\"\n\t\t\t\tstyle={{ fontSize: label.totalFontSize }}\n\t\t\t>\n\t\t\t\t{total}\n\t\t\t</tspan>\n\t\t\t{caption != null && (\n\t\t\t\t<tspan\n\t\t\t\t\tx={cx}\n\t\t\t\t\ty={captionY}\n\t\t\t\t\tclassName=\"fill-fg-secondary font-medium\"\n\t\t\t\t\tstyle={{ fontSize: label.captionFontSize }}\n\t\t\t\t>\n\t\t\t\t\t{caption}\n\t\t\t\t</tspan>\n\t\t\t)}\n\t\t</text>\n\t);\n}\n\n/**\n * Rich legend for pie/donut charts. Unlike the shared `ChartLegendContent`\n * (marker + label only), each row pairs a colour dot with the category name, its\n * value, and its share — laid out as aligned columns so the figures read like a\n * mini table. Values and percentages are pre-formatted by the caller.\n */\ntype PieLegendItem = {\n\t/** Category name, e.g. \"Housing\". */\n\tlabel: string;\n\t/** Segment colour — should match the matching `Cell` fill. */\n\tcolor: string;\n\t/** Pre-formatted value, e.g. \"₦420k\". */\n\tvalue: React.ReactNode;\n\t/** Pre-formatted share, e.g. \"38%\". */\n\tpercentage: React.ReactNode;\n};\n\nconst pieLegendVariants = cva(\"flex min-w-0 flex-col\", {\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"gap-1.5 text-gdt-xs\",\n\t\t\tmd: \"gap-2 text-gdt-sm\",\n\t\t\tlg: \"gap-2.5 text-gdt-sm\",\n\t\t},\n\t},\n\tdefaultVariants: { size: \"md\" },\n});\n\nconst pieLegendDotVariants = cva(\"shrink-0 rounded-full\", {\n\tvariants: {\n\t\tsize: { sm: \"size-2\", md: \"size-2.5\", lg: \"size-3\" },\n\t},\n\tdefaultVariants: { size: \"md\" },\n});\n\nfunction PieChartLegend({\n\titems,\n\tsize,\n\tclassName,\n\t...props\n}: React.ComponentProps<\"ul\"> & {\n\titems: PieLegendItem[];\n\tsize?: PieChartSize;\n}) {\n\tconst resolvedSize = useComponentSize(size);\n\n\treturn (\n\t\t<ul\n\t\t\tclassName={cn(pieLegendVariants({ size: resolvedSize }), className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{items.map((item) => (\n\t\t\t\t<li key={item.label} className=\"flex items-center gap-2.5\">\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName={cn(pieLegendDotVariants({ size: resolvedSize }))}\n\t\t\t\t\t\tstyle={{ backgroundColor: item.color }}\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"min-w-0 flex-1 truncate text-fg-primary\">\n\t\t\t\t\t\t{item.label}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"shrink-0 tabular-nums text-fg-secondary\">\n\t\t\t\t\t\t{item.value}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"w-9 shrink-0 text-right font-bold tabular-nums text-fg-primary\">\n\t\t\t\t\t\t{item.percentage}\n\t\t\t\t\t</span>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n\nexport {\n\tPIE_CHART_LAYOUT,\n\tPIE_CHART_PALETTE,\n\tPieCenterLabel,\n\tPieChartLegend,\n\tusePieChartLayout,\n};\nexport type {\n\tPieChartLayout,\n\tPieChartSize,\n\tPieCenterLabelProps,\n\tPieLegendItem,\n};\n","import { type ClassValue, clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst twMerge = extendTailwindMerge({\n\textend: {\n\t\tclassGroups: {\n\t\t\t\"font-size\": [\n\t\t\t\t{\n\t\t\t\t\ttext: [\n\t\t\t\t\t\t\"gdt-display\",\n\t\t\t\t\t\t\"gdt-h1\",\n\t\t\t\t\t\t\"gdt-h2\",\n\t\t\t\t\t\t\"gdt-h3\",\n\t\t\t\t\t\t\"gdt-h4\",\n\t\t\t\t\t\t\"gdt-h5\",\n\t\t\t\t\t\t\"gdt-xl\",\n\t\t\t\t\t\t\"gdt-lg\",\n\t\t\t\t\t\t\"gdt-md\",\n\t\t\t\t\t\t\"gdt-sm\",\n\t\t\t\t\t\t\"gdt-xs\",\n\t\t\t\t\t\t\"gdt-subtext\",\n\t\t\t\t\t\t\"gdt-capitalized\",\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n});\n\nexport function cn(...inputs: ClassValue[]) {\n\treturn twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport { createContext, type ReactNode, useContext } from \"react\";\n\ntype ComponentSize = \"sm\" | \"md\" | \"lg\";\n\nconst SizeContext = createContext<ComponentSize | undefined>(undefined);\n\nfunction SizeProvider({\n\tchildren,\n\tsize,\n}: {\n\tchildren: ReactNode;\n\tsize?: ComponentSize | null;\n}) {\n\tif (!size) {\n\t\treturn <>{children}</>;\n\t}\n\n\treturn <SizeContext.Provider value={size}>{children}</SizeContext.Provider>;\n}\n\nfunction useComponentSize(\n\tsize?: ComponentSize | null,\n\tfallback: ComponentSize = \"md\",\n) {\n\tconst inheritedSize = useContext(SizeContext);\n\treturn size ?? inheritedSize ?? fallback;\n}\n\nexport { SizeProvider, useComponentSize, type ComponentSize };\n"],"mappings":"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","names":["jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/pie-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { cn } from \"./lib/cn\";\nimport { type ComponentSize, useComponentSize } from \"./size-context\";\n\n/**\n * Pie / donut charts are composed from recharts plot primitives directly —\n * recharts identifies `PieChart`, `Pie`, and `Cell` by component identity, so\n * they cannot be wrapped. This module supplies the giddaa-specific pieces that\n * would otherwise be copy-pasted: per-size layout numbers, a categorical\n * palette, the donut center label, and the rich legend (dot · name · value ·\n * percentage). Pair them with the shared frame from `./chart`.\n *\n * A donut keeps an open center for a total label (`innerRadius` > 0); a pie\n * fills the circle (`innerRadius={0}`). Both read the same layout.\n *\n * @example\n * const chart = usePieChartLayout({ size: \"md\", type: \"donut\" });\n * <ChartCard size=\"md\">\n * <div className=\"flex items-center gap-4\">\n * <ChartContainer config={config} {...chart.container}>\n * <PieChart>\n * <Pie data={data} dataKey=\"value\" nameKey=\"label\" {...chart.pie}>\n * {data.map((d) => <Cell key={d.label} fill={d.color} />)}\n * <Label content={<PieCenterLabel total=\"₦1.1M\" caption=\"Total spend\" />} />\n * </Pie>\n * </PieChart>\n * </ChartContainer>\n * <PieChartLegend items={legendItems} />\n * </div>\n * </ChartCard>\n */\n\n/** Pie sizes line up with the three shared `ComponentSize` values. */\ntype PieChartSize = ComponentSize;\n\ntype PieChartLayout = {\n\t/** Square plot box in px (width = height); width is NOT parent-driven here. */\n\tsize: number;\n\t/** Donut hole radius in px. Pass `0` to the `Pie` for a filled pie. */\n\tinnerRadius: number;\n\t/** Outer ring radius in px. */\n\touterRadius: number;\n\t/** Gap between segments, in degrees. */\n\tpaddingAngle: number;\n\t/** Corner radius of each segment. */\n\tcornerRadius: number;\n\t/** Center total font size. */\n\ttotalFontSize: number;\n\t/** Center caption font size. */\n\tcaptionFontSize: number;\n};\n\nconst PIE_CHART_LAYOUT: Record<PieChartSize, PieChartLayout> = {\n\tsm: {\n\t\tsize: 132,\n\t\tinnerRadius: 42,\n\t\touterRadius: 64,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 18,\n\t\tcaptionFontSize: 9,\n\t},\n\tmd: {\n\t\tsize: 176,\n\t\tinnerRadius: 56,\n\t\touterRadius: 84,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 24,\n\t\tcaptionFontSize: 11,\n\t},\n\tlg: {\n\t\tsize: 224,\n\t\tinnerRadius: 72,\n\t\touterRadius: 108,\n\t\tpaddingAngle: 2,\n\t\tcornerRadius: 0,\n\t\ttotalFontSize: 30,\n\t\tcaptionFontSize: 12,\n\t},\n};\n\n/**\n * Categorical palette for pie/donut segments, ordered by share. Giddaa has no\n * `chart-1`…`chart-N` tokens yet, so these map to the brand scales: forest →\n * brass → moss → clay → stone. Assign by index, or override per `Cell`.\n */\nconst PIE_CHART_PALETTE = [\n\t\"var(--color-forest-700)\",\n\t\"var(--color-brass-500)\",\n\t\"var(--color-moss-600)\",\n\t\"var(--color-clay-500)\",\n\t\"var(--color-stone-500)\",\n] as const;\n\n/**\n * Resolve the pie-chart layout for an explicit or inherited component size and\n * chart `type`. The returned object groups the giddaa defaults by the recharts\n * component they belong to — spread `container` onto `ChartContainer` and `pie`\n * onto `Pie`, then pass the data-specific props (`data`, `dataKey`, `nameKey`)\n * directly afterwards. `type=\"pie\"` collapses the donut hole (`innerRadius` 0).\n */\nfunction usePieChartLayout({\n\tsize,\n\ttype = \"donut\",\n}: {\n\tsize?: PieChartSize;\n\ttype?: \"donut\" | \"pie\";\n} = {}) {\n\tconst layout = PIE_CHART_LAYOUT[useComponentSize(size)];\n\n\treturn {\n\t\tcontainer: {\n\t\t\tclassName: \"aspect-square shrink-0\",\n\t\t\tstyle: { width: layout.size, height: layout.size },\n\t\t},\n\t\tpie: {\n\t\t\tinnerRadius: type === \"pie\" ? 0 : layout.innerRadius,\n\t\t\touterRadius: layout.outerRadius,\n\t\t\tpaddingAngle: type === \"pie\" ? 0 : layout.paddingAngle,\n\t\t\tcornerRadius: layout.cornerRadius,\n\t\t\tstrokeWidth: 0,\n\t\t},\n\t\tlabel: {\n\t\t\ttotalFontSize: layout.totalFontSize,\n\t\t\tcaptionFontSize: layout.captionFontSize,\n\t\t},\n\t};\n}\n\n/**\n * Center label for a donut — the hero total over a short caption. Pass it to\n * recharts as `<Label content={<PieCenterLabel total=… caption=… />} />` inside\n * the `Pie`; recharts injects the `viewBox` carrying the polar center (cx/cy).\n */\ntype PieCenterLabelProps = {\n\t/** Hero figure — pre-formatted, e.g. \"₦1.1M\". */\n\ttotal: React.ReactNode;\n\t/** Short label describing what the total represents, e.g. \"Total spend\". */\n\tcaption?: React.ReactNode;\n\t/** Explicit size; otherwise inherited from the nearest `SizeProvider`. */\n\tsize?: PieChartSize;\n\t// Injected by recharts at render time.\n\tviewBox?: { cx?: number; cy?: number };\n};\n\nfunction PieCenterLabel({\n\ttotal,\n\tcaption,\n\tsize,\n\tviewBox,\n}: PieCenterLabelProps) {\n\tconst { label } = usePieChartLayout({ size });\n\n\tif (!viewBox || viewBox.cx == null || viewBox.cy == null) {\n\t\treturn null;\n\t}\n\n\tconst { cx, cy } = viewBox;\n\tconst captionY = cy + label.totalFontSize * 0.72;\n\n\treturn (\n\t\t<text x={cx} y={cy} textAnchor=\"middle\" dominantBaseline=\"central\">\n\t\t\t<tspan\n\t\t\t\tx={cx}\n\t\t\t\ty={caption == null ? cy : cy - label.captionFontSize * 0.5}\n\t\t\t\tclassName=\"fill-fg-primary font-extrabold tabular-nums\"\n\t\t\t\tstyle={{ fontSize: label.totalFontSize }}\n\t\t\t>\n\t\t\t\t{total}\n\t\t\t</tspan>\n\t\t\t{caption != null && (\n\t\t\t\t<tspan\n\t\t\t\t\tx={cx}\n\t\t\t\t\ty={captionY}\n\t\t\t\t\tclassName=\"fill-fg-secondary font-medium\"\n\t\t\t\t\tstyle={{ fontSize: label.captionFontSize }}\n\t\t\t\t>\n\t\t\t\t\t{caption}\n\t\t\t\t</tspan>\n\t\t\t)}\n\t\t</text>\n\t);\n}\n\n/**\n * Rich legend for pie/donut charts. Unlike the shared `ChartLegendContent`\n * (marker + label only), each row pairs a colour dot with the category name, its\n * value, and its share — laid out as aligned columns so the figures read like a\n * mini table. Values and percentages are pre-formatted by the caller.\n */\ntype PieLegendItem = {\n\t/** Category name, e.g. \"Housing\". */\n\tlabel: string;\n\t/** Segment colour — should match the matching `Cell` fill. */\n\tcolor: string;\n\t/** Pre-formatted value, e.g. \"₦420k\". */\n\tvalue: React.ReactNode;\n\t/** Pre-formatted share, e.g. \"38%\". */\n\tpercentage: React.ReactNode;\n};\n\nconst pieLegendVariants = cva(\"flex min-w-0 flex-col\", {\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"gap-1.5 text-gdt-xs\",\n\t\t\tmd: \"gap-2 text-gdt-sm\",\n\t\t\tlg: \"gap-2.5 text-gdt-sm\",\n\t\t},\n\t},\n\tdefaultVariants: { size: \"md\" },\n});\n\nconst pieLegendDotVariants = cva(\"shrink-0 rounded-full\", {\n\tvariants: {\n\t\tsize: { sm: \"size-2\", md: \"size-2.5\", lg: \"size-3\" },\n\t},\n\tdefaultVariants: { size: \"md\" },\n});\n\nfunction PieChartLegend({\n\titems,\n\tsize,\n\tclassName,\n\t...props\n}: React.ComponentProps<\"ul\"> & {\n\titems: PieLegendItem[];\n\tsize?: PieChartSize;\n}) {\n\tconst resolvedSize = useComponentSize(size);\n\n\treturn (\n\t\t<ul\n\t\t\tclassName={cn(pieLegendVariants({ size: resolvedSize }), className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{items.map((item) => (\n\t\t\t\t<li key={item.label} className=\"flex items-center gap-2.5\">\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclassName={cn(pieLegendDotVariants({ size: resolvedSize }))}\n\t\t\t\t\t\tstyle={{ backgroundColor: item.color }}\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"min-w-0 flex-1 truncate text-fg-primary\">\n\t\t\t\t\t\t{item.label}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"shrink-0 tabular-nums text-fg-secondary\">\n\t\t\t\t\t\t{item.value}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"w-9 shrink-0 text-right font-bold tabular-nums text-fg-primary\">\n\t\t\t\t\t\t{item.percentage}\n\t\t\t\t\t</span>\n\t\t\t\t</li>\n\t\t\t))}\n\t\t</ul>\n\t);\n}\n\nexport {\n\tPIE_CHART_LAYOUT,\n\tPIE_CHART_PALETTE,\n\tPieCenterLabel,\n\tPieChartLegend,\n\tusePieChartLayout,\n};\nexport type {\n\tPieChartLayout,\n\tPieChartSize,\n\tPieCenterLabelProps,\n\tPieLegendItem,\n};\n"],"mappings":"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","names":[]}
|
package/dist/popover.js
CHANGED
|
@@ -1,161 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"gdt-h1",
|
|
15
|
-
"gdt-h2",
|
|
16
|
-
"gdt-h3",
|
|
17
|
-
"gdt-h4",
|
|
18
|
-
"gdt-h5",
|
|
19
|
-
"gdt-xl",
|
|
20
|
-
"gdt-lg",
|
|
21
|
-
"gdt-md",
|
|
22
|
-
"gdt-sm",
|
|
23
|
-
"gdt-xs",
|
|
24
|
-
"gdt-subtext",
|
|
25
|
-
"gdt-capitalized"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
function cn(...inputs) {
|
|
33
|
-
return twMerge(clsx(inputs));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/components/ui/size-context.tsx
|
|
37
|
-
import { createContext, useContext } from "react";
|
|
38
|
-
import { Fragment, jsx } from "react/jsx-runtime";
|
|
39
|
-
var SizeContext = createContext(void 0);
|
|
40
|
-
function SizeProvider({
|
|
41
|
-
children,
|
|
42
|
-
size
|
|
43
|
-
}) {
|
|
44
|
-
if (!size) {
|
|
45
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
46
|
-
}
|
|
47
|
-
return /* @__PURE__ */ jsx(SizeContext.Provider, { value: size, children });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// src/components/ui/popover.tsx
|
|
51
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
52
|
-
function Popover({ ...props }) {
|
|
53
|
-
return /* @__PURE__ */ jsx2(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
|
|
54
|
-
}
|
|
55
|
-
function PopoverTrigger({ ...props }) {
|
|
56
|
-
return /* @__PURE__ */ jsx2(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
57
|
-
}
|
|
58
|
-
function PopoverContent({
|
|
59
|
-
className,
|
|
60
|
-
align = "center",
|
|
61
|
-
alignOffset = 0,
|
|
62
|
-
side = "bottom",
|
|
63
|
-
sideOffset = 6,
|
|
64
|
-
showArrow = true,
|
|
65
|
-
size = "md",
|
|
66
|
-
children,
|
|
67
|
-
...props
|
|
68
|
-
}) {
|
|
69
|
-
return /* @__PURE__ */ jsx2(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx2(
|
|
70
|
-
PopoverPrimitive.Positioner,
|
|
71
|
-
{
|
|
72
|
-
align,
|
|
73
|
-
alignOffset,
|
|
74
|
-
side,
|
|
75
|
-
sideOffset,
|
|
76
|
-
className: "isolate z-50",
|
|
77
|
-
children: /* @__PURE__ */ jsxs(
|
|
78
|
-
PopoverPrimitive.Popup,
|
|
79
|
-
{
|
|
80
|
-
"data-slot": "popover-content",
|
|
81
|
-
className: cn(
|
|
82
|
-
"z-50 relative flex w-72 max-w-[calc(100vw-2rem)] origin-(--transform-origin) flex-col rounded-lg border-0 bg-surface-overlay py-4 text-gdt-sm text-fg-primary shadow-2 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 has-[&_[data-slot=popover-footer]]:pb-0",
|
|
83
|
-
className
|
|
84
|
-
),
|
|
85
|
-
...props,
|
|
86
|
-
children: [
|
|
87
|
-
/* @__PURE__ */ jsx2(SizeProvider, { size, children }),
|
|
88
|
-
showArrow ? /* @__PURE__ */ jsx2(PopoverPrimitive.Arrow, { className: "relative block w-3 h-1.5 overflow-clip data-[side=bottom]:top-[-6px] data-[side=left]:right-[-9px] data-[side=left]:rotate-90 data-[side=right]:left-[-9px] data-[side=right]:-rotate-90 data-[side=top]:bottom-[-6px] data-[side=top]:rotate-180 before:content-[''] before:absolute before:bottom-0 before:left-1/2 before:w-[calc(6px*sqrt(2))] before:h-[calc(6px*sqrt(2))] before:bg-surface-overlay before:border before:border-line before:[transform:translate(-50%,50%)_rotate(45deg)]" }) : null
|
|
89
|
-
]
|
|
90
|
-
}
|
|
91
|
-
)
|
|
92
|
-
}
|
|
93
|
-
) });
|
|
94
|
-
}
|
|
95
|
-
function PopoverHeader({
|
|
96
|
-
className,
|
|
97
|
-
border,
|
|
98
|
-
...props
|
|
99
|
-
}) {
|
|
100
|
-
return /* @__PURE__ */ jsx2(
|
|
101
|
-
"div",
|
|
102
|
-
{
|
|
103
|
-
"data-slot": "popover-header",
|
|
104
|
-
className: cn(
|
|
105
|
-
"flex flex-col gap-0.5 px-4",
|
|
106
|
-
border && "border-b border-line-subtle pb-3",
|
|
107
|
-
className
|
|
108
|
-
),
|
|
109
|
-
...props
|
|
110
|
-
}
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
function PopoverBody({ className, ...props }) {
|
|
114
|
-
return /* @__PURE__ */ jsx2(
|
|
115
|
-
"div",
|
|
116
|
-
{
|
|
117
|
-
"data-slot": "popover-body",
|
|
118
|
-
className: cn("px-4 py-2", className),
|
|
119
|
-
...props
|
|
120
|
-
}
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
function PopoverFooter({ className, ...props }) {
|
|
124
|
-
return /* @__PURE__ */ jsx2(
|
|
125
|
-
"div",
|
|
126
|
-
{
|
|
127
|
-
"data-slot": "popover-footer",
|
|
128
|
-
className: cn(
|
|
129
|
-
"flex flex-row items-center gap-2 px-4 border-t border-line-subtle pt-3",
|
|
130
|
-
className
|
|
131
|
-
),
|
|
132
|
-
...props
|
|
133
|
-
}
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
function PopoverTitle({ className, ...props }) {
|
|
137
|
-
return /* @__PURE__ */ jsx2(
|
|
138
|
-
PopoverPrimitive.Title,
|
|
139
|
-
{
|
|
140
|
-
"data-slot": "popover-title",
|
|
141
|
-
className: cn("text-gdt-sm font-semibold text-fg-primary", className),
|
|
142
|
-
...props
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
function PopoverDescription({
|
|
147
|
-
className,
|
|
148
|
-
...props
|
|
149
|
-
}) {
|
|
150
|
-
return /* @__PURE__ */ jsx2(
|
|
151
|
-
PopoverPrimitive.Description,
|
|
152
|
-
{
|
|
153
|
-
"data-slot": "popover-description",
|
|
154
|
-
className: cn("text-gdt-xs font-normal text-fg-secondary", className),
|
|
155
|
-
...props
|
|
156
|
-
}
|
|
157
|
-
);
|
|
158
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Popover,
|
|
4
|
+
PopoverBody,
|
|
5
|
+
PopoverContent,
|
|
6
|
+
PopoverDescription,
|
|
7
|
+
PopoverFooter,
|
|
8
|
+
PopoverHeader,
|
|
9
|
+
PopoverTitle,
|
|
10
|
+
PopoverTrigger
|
|
11
|
+
} from "./chunk-JVLUBAPB.js";
|
|
12
|
+
import "./chunk-HL3ZSYES.js";
|
|
13
|
+
import "./chunk-Y4TTYVNE.js";
|
|
159
14
|
export {
|
|
160
15
|
Popover,
|
|
161
16
|
PopoverBody,
|
package/dist/popover.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
declare const priceTagVariants: (props?: ({
|
|
6
|
+
size?: "sm" | "md" | "lg" | "xs" | "xxs" | null | undefined;
|
|
7
|
+
hasMonthlyPayment?: boolean | null | undefined;
|
|
8
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
|
+
type PriceTagSize = NonNullable<VariantProps<typeof priceTagVariants>["size"]>;
|
|
10
|
+
type PriceTagCurrencyOption = {
|
|
11
|
+
code: string;
|
|
12
|
+
amount: string;
|
|
13
|
+
shortAmount?: string;
|
|
14
|
+
monthlyPayment?: string;
|
|
15
|
+
monthlyPaymentLabel?: string;
|
|
16
|
+
};
|
|
17
|
+
type PriceTagFormat = "full" | "shortened";
|
|
18
|
+
type PriceTagProps = Omit<React.ComponentProps<"button">, "children"> & {
|
|
19
|
+
amount: string;
|
|
20
|
+
shortAmount?: string;
|
|
21
|
+
format?: PriceTagFormat;
|
|
22
|
+
size?: PriceTagSize;
|
|
23
|
+
monthlyPayment?: string;
|
|
24
|
+
monthlyPaymentLabel?: string;
|
|
25
|
+
currencies?: PriceTagCurrencyOption[];
|
|
26
|
+
selectedCurrency?: string;
|
|
27
|
+
onCurrencyChange?: (currency: PriceTagCurrencyOption) => void;
|
|
28
|
+
open?: boolean;
|
|
29
|
+
defaultOpen?: boolean;
|
|
30
|
+
onOpenChange?: (open: boolean) => void;
|
|
31
|
+
popoverClassName?: string;
|
|
32
|
+
};
|
|
33
|
+
declare function PriceTag({ amount, shortAmount, format, size, monthlyPayment, monthlyPaymentLabel, currencies, selectedCurrency, onCurrencyChange, open, defaultOpen, onOpenChange, className, popoverClassName, type, ...props }: PriceTagProps): React.JSX.Element;
|
|
34
|
+
|
|
35
|
+
export { PriceTag, type PriceTagCurrencyOption, type PriceTagFormat, type PriceTagProps, type PriceTagSize, priceTagVariants };
|