@datum-cloud/datum-ui 0.2.0-alpha.3 → 0.2.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +46 -21
  2. package/dist/alert/index.mjs +3 -0
  3. package/dist/alert-BC2Mccfo.mjs +95 -0
  4. package/dist/autocomplete/index.mjs +7 -0
  5. package/dist/autocomplete-DZtI97HP.mjs +295 -0
  6. package/dist/avatar-stack/index.mjs +5 -0
  7. package/dist/avatar-stack-JCfBlPB9.mjs +80 -0
  8. package/dist/badge/index.mjs +3 -0
  9. package/dist/badge-bFgeYceE.mjs +185 -0
  10. package/dist/breadcrumb/index.mjs +4 -0
  11. package/dist/breadcrumb-BGYJgom_.mjs +71 -0
  12. package/dist/button/index.mjs +4 -0
  13. package/dist/button-AzpnV-WB.mjs +49 -0
  14. package/dist/button-C1wRfGtT.mjs +230 -0
  15. package/dist/button-group/index.mjs +5 -0
  16. package/dist/button-group-C1IB2K5s.mjs +40 -0
  17. package/dist/calendar/index.mjs +5 -0
  18. package/dist/calendar-DlIHeWb0.mjs +113 -0
  19. package/dist/card/index.mjs +4 -0
  20. package/dist/card-3Kd0VdNf.mjs +63 -0
  21. package/dist/chart/index.mjs +4 -0
  22. package/dist/chart-BZqUKpkh.mjs +143 -0
  23. package/dist/checkbox/index.mjs +4 -0
  24. package/dist/checkbox-LG1OKTpG.mjs +34 -0
  25. package/dist/col-lrLMZaTJ.mjs +184 -0
  26. package/dist/collapsible/index.mjs +3 -0
  27. package/dist/collapsible-Bt9UYfv3.mjs +9 -0
  28. package/dist/command/index.mjs +5 -0
  29. package/dist/command-s0Yv3abE.mjs +86 -0
  30. package/dist/components/features/date-picker/index.d.ts +3 -0
  31. package/dist/components/features/date-picker/index.d.ts.map +1 -0
  32. package/dist/components/features/dropzone/index.d.ts +1 -0
  33. package/dist/components/features/dropzone/index.d.ts.map +1 -1
  34. package/dist/date-picker/index.mjs +9 -0
  35. package/dist/{datum.provider-D6VMjSV0.mjs → datum.provider-B77goJgl.mjs} +1 -1
  36. package/dist/dialog/index.mjs +5 -0
  37. package/dist/dialog-DXBaT9gA.mjs +86 -0
  38. package/dist/dialog-bnMMf9GD.mjs +73 -0
  39. package/dist/dropdown/index.mjs +3 -0
  40. package/dist/dropdown-DtSa_lqc.mjs +112 -0
  41. package/dist/dropzone/index.mjs +5 -0
  42. package/dist/dropzone-BkOnwrS4.mjs +221 -0
  43. package/dist/empty-content/index.mjs +3 -0
  44. package/dist/empty-content-BM9rzI13.mjs +196 -0
  45. package/dist/exports/map.d.ts +3 -0
  46. package/dist/exports/map.d.ts.map +1 -0
  47. package/dist/form/index.mjs +146 -0
  48. package/dist/grid/index.mjs +3 -0
  49. package/dist/hooks/index.mjs +2 -3
  50. package/dist/hover-card/index.mjs +4 -0
  51. package/dist/hover-card-CUPfFUqE.mjs +33 -0
  52. package/dist/icon-wrapper-9ticVbRL.mjs +14 -0
  53. package/dist/icons/index.mjs +3 -3
  54. package/dist/index.mjs +66 -8
  55. package/dist/input/index.mjs +5 -0
  56. package/dist/input-DuyjEKEW.mjs +17 -0
  57. package/dist/input-fzXBheCN.mjs +17 -0
  58. package/dist/input-group/index.mjs +7 -0
  59. package/dist/input-group-CPaFSTEV.mjs +80 -0
  60. package/dist/input-number/index.mjs +6 -0
  61. package/dist/input-number-9o62JHRl.mjs +106 -0
  62. package/dist/input-with-addons/index.mjs +3 -0
  63. package/dist/input-with-addons-BQn7KCTU.mjs +30 -0
  64. package/dist/label/index.mjs +4 -0
  65. package/dist/label-_ste_Re3.mjs +44 -0
  66. package/dist/link-button-TIF2Zdrk.mjs +36 -0
  67. package/dist/loader-overlay/index.mjs +3 -0
  68. package/dist/loader-overlay-DUaQSZQP.mjs +17 -0
  69. package/dist/map/index.mjs +13 -0
  70. package/dist/map-Df8QMcX0.mjs +1094 -0
  71. package/dist/more-actions/index.mjs +5 -0
  72. package/dist/more-actions-Ch1f6Mh3.mjs +54 -0
  73. package/dist/nprogress/index.mjs +32 -0
  74. package/dist/page-title/index.mjs +3 -0
  75. package/dist/page-title-BJuo81rT.mjs +26 -0
  76. package/dist/popover/index.mjs +4 -0
  77. package/dist/popover-SQlKSz6L.mjs +36 -0
  78. package/dist/provider/index.mjs +4 -0
  79. package/dist/radio-group/index.mjs +4 -0
  80. package/dist/radio-group-Oshv0b-U.mjs +49 -0
  81. package/dist/select/index.mjs +4 -0
  82. package/dist/select-DVlEzD2W.mjs +166 -0
  83. package/dist/separator/index.mjs +4 -0
  84. package/dist/separator-T2ppyD-8.mjs +18 -0
  85. package/dist/sheet/index.mjs +5 -0
  86. package/dist/sheet-BKiCwtNO.mjs +45 -0
  87. package/dist/sheet-CtnP6gTD.mjs +77 -0
  88. package/dist/sidebar/index.mjs +11 -0
  89. package/dist/sidebar-DfqezV8t.mjs +945 -0
  90. package/dist/skeleton/index.mjs +4 -0
  91. package/dist/skeleton-vzbxA-DQ.mjs +13 -0
  92. package/dist/spinner/index.mjs +4 -0
  93. package/dist/spinner-BE7k2bAD.mjs +16 -0
  94. package/dist/{icon-wrapper-BgPkifId.mjs → spinner.icon-Bg8zgGh0.mjs} +1 -12
  95. package/dist/stepper/index.mjs +5 -0
  96. package/dist/stepper-SWB-u_nM.mjs +323 -0
  97. package/dist/switch/index.mjs +4 -0
  98. package/dist/switch-Calk7Gyw.mjs +32 -0
  99. package/dist/table/index.mjs +4 -0
  100. package/dist/table-CsXBcQLI.mjs +68 -0
  101. package/dist/tabs/index.mjs +3 -0
  102. package/dist/tabs-D8n-dqnw.mjs +52 -0
  103. package/dist/tag-input/index.mjs +5 -0
  104. package/dist/tag-input-Di7SDNbK.mjs +284 -0
  105. package/dist/task-queue/index.mjs +7 -0
  106. package/dist/task-queue-dropdown-DW72ikDH.mjs +1356 -0
  107. package/dist/textarea/index.mjs +5 -0
  108. package/dist/textarea-CxE3YbC7.mjs +17 -0
  109. package/dist/textarea-QYRcDEpK.mjs +15 -0
  110. package/dist/theme/index.mjs +4 -0
  111. package/dist/theme-script-XBouzsNR.mjs +66 -0
  112. package/dist/to-api-format-C2xjQUcI.mjs +1506 -0
  113. package/dist/toast/index.mjs +3 -0
  114. package/dist/tooltip/index.mjs +4 -0
  115. package/dist/tooltip-Dd3ActSS.mjs +74 -0
  116. package/dist/typography/index.mjs +3 -0
  117. package/dist/typography-UA7ZZvgJ.mjs +200 -0
  118. package/dist/use-copy-to-clipboard-ki-WoTml.mjs +31 -0
  119. package/dist/use-stepper-BaToCYMs.mjs +2017 -0
  120. package/dist/{use-copy-to-clipboard-BfrpD6G8.mjs → use-toast-mdn_CqRY.mjs} +34 -27
  121. package/dist/utils/index.mjs +0 -1
  122. package/dist/utils-Bfgoe-Gm.mjs +20 -0
  123. package/dist/visually-hidden/index.mjs +3 -0
  124. package/dist/visuallyhidden-aaTUk4Yo.mjs +7 -0
  125. package/package.json +208 -8
  126. package/dist/components/index.mjs +0 -8
  127. package/dist/providers/index.mjs +0 -4
  128. package/dist/theme-script-DHyLk25i.mjs +0 -11128
  129. /package/dist/{close.icon-chkXPAUC.mjs → close.icon-CMNMoXM_.mjs} +0 -0
  130. /package/dist/{map-leaflet-imports-OKaoesjZ.mjs → map-leaflet-imports-CdzvEnzY.mjs} +0 -0
  131. /package/dist/{theme.provider-DpFLwtHe.mjs → theme.provider-DgGshapa.mjs} +0 -0
  132. /package/dist/{use-debounce-BYB-jPeX.mjs → use-debounce-DQ1tmxOL.mjs} +0 -0
@@ -0,0 +1,1094 @@
1
+ import { t as cn } from "./utils-Bfgoe-Gm.mjs";
2
+ import { t as ButtonGroup } from "./button-group-C1IB2K5s.mjs";
3
+ import { t as Button } from "./button-AzpnV-WB.mjs";
4
+ import { i as CommandGroup, o as CommandItem, r as CommandEmpty, s as CommandList, t as Command } from "./command-s0Yv3abE.mjs";
5
+ import { i as InputGroupInput, n as InputGroupAddon, t as InputGroup } from "./input-group-CPaFSTEV.mjs";
6
+ import { t as Spinner } from "./spinner-BE7k2bAD.mjs";
7
+ import { CheckIcon, ChevronRightIcon, CircleIcon, LayersIcon, LoaderCircleIcon, MapPinIcon, MaximizeIcon, MinimizeIcon, MinusIcon, NavigationIcon, PenLineIcon, PentagonIcon, PlusIcon, SearchIcon, SquareIcon, Trash2Icon, Undo2Icon, WaypointsIcon } from "lucide-react";
8
+ import * as React$1 from "react";
9
+ import React, { Suspense, createContext, lazy, useContext, useEffect, useRef, useState } from "react";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
12
+ import { renderToString } from "react-dom/server.browser";
13
+
14
+ //#region ../shadcn/hooks/use-theme.ts
15
+ /**
16
+ * Lightweight theme detection hook for shadcn components.
17
+ * Detects dark mode via the `dark` class on <html> (Tailwind convention)
18
+ * or falls back to prefers-color-scheme media query.
19
+ */
20
+ function useTheme() {
21
+ const [resolvedTheme, setResolvedTheme] = React$1.useState("light");
22
+ React$1.useEffect(() => {
23
+ const detect = () => {
24
+ if (document.documentElement.classList.contains("dark")) return "dark";
25
+ if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark";
26
+ return "light";
27
+ };
28
+ setResolvedTheme(detect());
29
+ const observer = new MutationObserver(() => setResolvedTheme(detect()));
30
+ observer.observe(document.documentElement, {
31
+ attributes: true,
32
+ attributeFilter: ["class"]
33
+ });
34
+ const mql = window.matchMedia("(prefers-color-scheme: dark)");
35
+ const onChange = () => setResolvedTheme(detect());
36
+ mql.addEventListener("change", onChange);
37
+ return () => {
38
+ observer.disconnect();
39
+ mql.removeEventListener("change", onChange);
40
+ };
41
+ }, []);
42
+ return { resolvedTheme };
43
+ }
44
+
45
+ //#endregion
46
+ //#region ../shadcn/ui/dropdown-menu.tsx
47
+ /**
48
+ * Vanilla shadcn/ui DropdownMenu Component
49
+ * Pure shadcn dropdown without Datum customizations
50
+ * For Datum-specific features (destructive MenuItem), import from @/modules/datum-ui
51
+ */
52
+ const DropdownMenu = DropdownMenuPrimitive.Root;
53
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
54
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
55
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
56
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
57
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
58
+ const DropdownMenuSubTrigger = React$1.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.SubTrigger, {
59
+ ref,
60
+ className: cn("focus:bg-accent data-[state=open]:bg-accent flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", inset && "pl-8", className),
61
+ ...props,
62
+ children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto" })]
63
+ }));
64
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
65
+ const DropdownMenuSubContent = React$1.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.SubContent, {
66
+ ref,
67
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-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 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg", className),
68
+ ...props
69
+ }));
70
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
71
+ const DropdownMenuContent = React$1.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.Content, {
72
+ ref,
73
+ sideOffset,
74
+ className: cn("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-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 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md", className),
75
+ ...props
76
+ }) }));
77
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
78
+ const DropdownMenuItem = React$1.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Item, {
79
+ ref,
80
+ className: cn("focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", inset && "pl-8", className),
81
+ ...props
82
+ }));
83
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
84
+ const DropdownMenuCheckboxItem = React$1.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.CheckboxItem, {
85
+ ref,
86
+ className: cn("focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
87
+ checked,
88
+ ...props,
89
+ children: [/* @__PURE__ */ jsx("span", {
90
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
91
+ children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4" }) })
92
+ }), children]
93
+ }));
94
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
95
+ const DropdownMenuRadioItem = React$1.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DropdownMenuPrimitive.RadioItem, {
96
+ ref,
97
+ className: cn("focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
98
+ ...props,
99
+ children: [/* @__PURE__ */ jsx("span", {
100
+ className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center",
101
+ children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(CircleIcon, { className: "h-2 w-2 fill-current" }) })
102
+ }), children]
103
+ }));
104
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
105
+ const DropdownMenuLabel = React$1.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Label, {
106
+ ref,
107
+ className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
108
+ ...props
109
+ }));
110
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
111
+ const DropdownMenuSeparator = React$1.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Separator, {
112
+ ref,
113
+ className: cn("bg-muted -mx-1 my-1 h-px", className),
114
+ ...props
115
+ }));
116
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
117
+ const DropdownMenuShortcut = ({ className, ...props }) => {
118
+ return /* @__PURE__ */ jsx("span", {
119
+ className: cn("ml-auto text-xs tracking-widest opacity-60", className),
120
+ ...props
121
+ });
122
+ };
123
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
124
+
125
+ //#endregion
126
+ //#region ../shadcn/ui/place-autocomplete.tsx
127
+ function formatAddress(properties) {
128
+ const parts = [];
129
+ if (properties.name) parts.push(properties.name);
130
+ if (properties.housenumber && properties.street) parts.push(`${properties.housenumber} ${properties.street}`);
131
+ else if (properties.street) parts.push(properties.street);
132
+ if (properties.city) parts.push(properties.city);
133
+ else if (properties.locality) parts.push(properties.locality);
134
+ if (properties.state && properties.state !== properties.city) parts.push(properties.state);
135
+ if (properties.country) parts.push(properties.country);
136
+ return [...new Set(parts)].join(", ");
137
+ }
138
+ function buildSearchUrl({ query, bbox, lang, lat, limit, locationBiasScale, lon, zoom }) {
139
+ const url = new URL("https://photon.komoot.io/api");
140
+ url.searchParams.set("q", query);
141
+ if (lang) url.searchParams.set("lang", lang);
142
+ if (limit) url.searchParams.set("limit", String(limit));
143
+ if (bbox) url.searchParams.set("bbox", bbox.join(","));
144
+ if (lat !== void 0 && lon !== void 0) {
145
+ url.searchParams.set("lat", String(lat));
146
+ url.searchParams.set("lon", String(lon));
147
+ }
148
+ if (zoom !== void 0) url.searchParams.set("zoom", String(zoom));
149
+ if (locationBiasScale !== void 0) url.searchParams.set("location_bias_scale", String(locationBiasScale));
150
+ return String(url);
151
+ }
152
+ function useDebounce(value, delay = 300) {
153
+ const [debouncedValue, setDebouncedValue] = React$1.useState(value);
154
+ React$1.useEffect(() => {
155
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
156
+ return () => clearTimeout(timer);
157
+ }, [value, delay]);
158
+ return debouncedValue;
159
+ }
160
+ function usePlaceSearch({ debounceMs, query, ...props }) {
161
+ const [results, setResults] = React$1.useState([]);
162
+ const [isLoading, setIsLoading] = React$1.useState(false);
163
+ const [error, setError] = React$1.useState(null);
164
+ const [hasSearched, setHasSearched] = React$1.useState(false);
165
+ const debouncedQuery = useDebounce(query, debounceMs);
166
+ React$1.useEffect(() => {
167
+ if (!debouncedQuery.trim()) {
168
+ setResults([]);
169
+ setIsLoading(false);
170
+ setHasSearched(false);
171
+ return;
172
+ }
173
+ const abortController = new AbortController();
174
+ async function fetchResults() {
175
+ setIsLoading(true);
176
+ setError(null);
177
+ setHasSearched(true);
178
+ try {
179
+ const url = buildSearchUrl({
180
+ query: debouncedQuery,
181
+ ...props
182
+ });
183
+ const response = await fetch(url, { signal: abortController.signal });
184
+ if (!response.ok) throw new Error(`Photon API error: ${response.status} ${response.statusText}`);
185
+ const data = await response.json();
186
+ const addressOsmIds = /* @__PURE__ */ new Set();
187
+ setResults(data.features.filter((feature) => {
188
+ const id = feature.properties.osm_id;
189
+ if (addressOsmIds.has(id)) return false;
190
+ addressOsmIds.add(id);
191
+ return true;
192
+ }));
193
+ } catch (err) {
194
+ if (err instanceof Error && err.name !== "AbortError") {
195
+ setError(err);
196
+ setResults([]);
197
+ }
198
+ } finally {
199
+ setIsLoading(false);
200
+ }
201
+ }
202
+ fetchResults();
203
+ return () => abortController.abort();
204
+ }, [
205
+ debouncedQuery,
206
+ props.lang,
207
+ props.limit,
208
+ props.bbox,
209
+ props.lat,
210
+ props.lon,
211
+ props.zoom,
212
+ props.locationBiasScale
213
+ ]);
214
+ return {
215
+ results,
216
+ isLoading,
217
+ error,
218
+ hasSearched
219
+ };
220
+ }
221
+ function PlaceAutocomplete({ debounceMs = 300, lang, limit = 5, bbox, lat, lon, zoom, locationBiasScale, className, value: controlledValue, defaultValue = "", onChange: controlledOnChange, onPlaceSelect, onResultsChange, ...props }) {
222
+ const [internalValue, setInternalValue] = React$1.useState(defaultValue);
223
+ const [searchQuery, setSearchQuery] = React$1.useState("");
224
+ const isControlled = controlledValue !== void 0;
225
+ const displayValue = isControlled ? controlledValue : internalValue;
226
+ const { results, isLoading, error, hasSearched } = usePlaceSearch({
227
+ query: searchQuery,
228
+ debounceMs,
229
+ lang,
230
+ limit,
231
+ bbox,
232
+ lat,
233
+ lon,
234
+ zoom,
235
+ locationBiasScale
236
+ });
237
+ React$1.useEffect(() => {
238
+ onResultsChange?.(results);
239
+ }, [results, onResultsChange]);
240
+ const hasNoResults = hasSearched && !isLoading && !error && results.length === 0;
241
+ const showCommandList = error || hasNoResults || results.length > 0;
242
+ return /* @__PURE__ */ jsx(Command, {
243
+ className: cn("h-fit overflow-visible", className),
244
+ shouldFilter: false,
245
+ loop: true,
246
+ children: /* @__PURE__ */ jsxs("div", {
247
+ className: "relative",
248
+ children: [/* @__PURE__ */ jsxs(InputGroup, {
249
+ className: cn("border-input! bg-popover! ring-0!", showCommandList && "rounded-b-none"),
250
+ children: [
251
+ /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, {}) }),
252
+ /* @__PURE__ */ jsx(InputGroupInput, {
253
+ placeholder: "Search",
254
+ value: displayValue,
255
+ onChange: (event) => {
256
+ const newValue = event.target.value;
257
+ if (!isControlled) setInternalValue(newValue);
258
+ setSearchQuery(newValue);
259
+ controlledOnChange?.(newValue);
260
+ },
261
+ ...props
262
+ }),
263
+ isLoading && /* @__PURE__ */ jsx(InputGroupAddon, {
264
+ align: "inline-end",
265
+ children: /* @__PURE__ */ jsx(Spinner, {})
266
+ })
267
+ ]
268
+ }), showCommandList && /* @__PURE__ */ jsxs(CommandList, {
269
+ "data-state": showCommandList ? "open" : "closed",
270
+ className: cn("bg-popover border-input absolute top-full right-0 left-0 rounded-b-md border border-t-0 shadow-md", "data-[state=open]:animate-in data-[state=closed]:animate-out", "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95", "data-[state=open]:slide-in-from-top-2 data-[state=closed]:slide-out-to-top-2"),
271
+ children: [
272
+ error && /* @__PURE__ */ jsxs(CommandEmpty, { children: ["Error: ", error.message] }),
273
+ hasNoResults && /* @__PURE__ */ jsxs(CommandEmpty, { children: [
274
+ "Can't find ",
275
+ displayValue,
276
+ "."
277
+ ] }),
278
+ results.length > 0 && /* @__PURE__ */ jsx(CommandGroup, { children: results.map((feature) => {
279
+ const formattedAddress = formatAddress(feature.properties);
280
+ return /* @__PURE__ */ jsxs(CommandItem, {
281
+ value: String(feature.properties.osm_id),
282
+ onSelect: () => {
283
+ const formattedAddress = formatAddress(feature.properties);
284
+ if (!isControlled) setInternalValue(formattedAddress);
285
+ setSearchQuery("");
286
+ controlledOnChange?.(formattedAddress);
287
+ onPlaceSelect?.(feature);
288
+ },
289
+ children: [/* @__PURE__ */ jsx(MapPinIcon, {}), /* @__PURE__ */ jsxs("div", {
290
+ className: "flex flex-col items-start text-start",
291
+ children: [/* @__PURE__ */ jsx("span", {
292
+ className: "font-medium",
293
+ children: feature.properties.name || feature.properties.street || "Unknown"
294
+ }), /* @__PURE__ */ jsx("span", {
295
+ className: "text-muted-foreground text-xs",
296
+ children: formattedAddress
297
+ })]
298
+ })]
299
+ }, feature.properties.osm_id);
300
+ }) })
301
+ ]
302
+ })]
303
+ })
304
+ });
305
+ }
306
+
307
+ //#endregion
308
+ //#region ../shadcn/ui/map.tsx
309
+ let _useMap;
310
+ let _useMapEvents;
311
+ if (typeof window !== "undefined") import("./map-leaflet-imports-CdzvEnzY.mjs").then((mod) => {
312
+ _useMap = mod.useMap;
313
+ _useMapEvents = mod.useMapEvents;
314
+ });
315
+ function createLazyComponent(factory) {
316
+ const LazyComponent = lazy(factory);
317
+ return (props) => {
318
+ const [isMounted, setIsMounted] = useState(false);
319
+ useEffect(() => {
320
+ setIsMounted(true);
321
+ }, []);
322
+ if (!isMounted) return null;
323
+ return /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(LazyComponent, { ...props }) });
324
+ };
325
+ }
326
+ const LeafletMapContainer = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.MapContainer })));
327
+ const LeafletTileLayer = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.TileLayer })));
328
+ const LeafletMarker = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Marker })));
329
+ const LeafletPopup = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Popup })));
330
+ const LeafletTooltip = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Tooltip })));
331
+ const LeafletCircle = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Circle })));
332
+ const LeafletCircleMarker = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.CircleMarker })));
333
+ const LeafletPolyline = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Polyline })));
334
+ const LeafletPolygon = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Polygon })));
335
+ const LeafletRectangle = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.Rectangle })));
336
+ const LeafletLayerGroup = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.LayerGroup })));
337
+ const LeafletFeatureGroup = createLazyComponent(() => import("react-leaflet").then((mod) => ({ default: mod.FeatureGroup })));
338
+ const LeafletMarkerClusterGroup = createLazyComponent(async () => import("react-leaflet-markercluster").then((mod) => ({ default: mod.default })));
339
+ function Map({ zoom = 15, maxZoom = 18, className, ...props }) {
340
+ return /* @__PURE__ */ jsx(LeafletMapContainer, {
341
+ zoom,
342
+ maxZoom,
343
+ attributionControl: false,
344
+ zoomControl: false,
345
+ className: cn("z-50 size-full min-h-96 flex-1 rounded-md", className),
346
+ ...props
347
+ });
348
+ }
349
+ const MapLayersContext = createContext(null);
350
+ function useMapLayersContext() {
351
+ return useContext(MapLayersContext);
352
+ }
353
+ function MapTileLayer({ name = "Default", url, attribution, darkUrl, darkAttribution, ...props }) {
354
+ const map = _useMap();
355
+ if (map.attributionControl) map.attributionControl.setPrefix("");
356
+ const context = useContext(MapLayersContext);
357
+ const DEFAULT_URL = "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png";
358
+ const DEFAULT_DARK_URL = "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png";
359
+ const { resolvedTheme } = useTheme();
360
+ const resolvedUrl = resolvedTheme === "dark" ? darkUrl ?? url ?? DEFAULT_DARK_URL : url ?? DEFAULT_URL;
361
+ const resolvedAttribution = resolvedTheme === "dark" && darkAttribution ? darkAttribution : attribution ?? "&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>, &copy; <a href=\"https://carto.com/attributions\">CARTO</a>";
362
+ useEffect(() => {
363
+ if (context) context.registerTileLayer({
364
+ name,
365
+ url: resolvedUrl,
366
+ attribution: resolvedAttribution
367
+ });
368
+ }, [
369
+ context,
370
+ name,
371
+ url,
372
+ attribution
373
+ ]);
374
+ if (context && context.selectedTileLayer !== name) return null;
375
+ return /* @__PURE__ */ jsx(LeafletTileLayer, {
376
+ url: resolvedUrl,
377
+ attribution: resolvedAttribution,
378
+ ...props
379
+ });
380
+ }
381
+ function MapLayerGroup({ name, disabled, ...props }) {
382
+ const context = useMapLayersContext();
383
+ useEffect(() => {
384
+ if (context) context.registerLayerGroup({
385
+ name,
386
+ disabled
387
+ });
388
+ }, [
389
+ context,
390
+ name,
391
+ disabled
392
+ ]);
393
+ if (context && !context.activeLayerGroups.includes(name)) return null;
394
+ return /* @__PURE__ */ jsx(LeafletLayerGroup, { ...props });
395
+ }
396
+ function MapFeatureGroup({ name, disabled, ...props }) {
397
+ const context = useMapLayersContext();
398
+ useEffect(() => {
399
+ if (context) context.registerLayerGroup({
400
+ name,
401
+ disabled
402
+ });
403
+ }, [
404
+ context,
405
+ name,
406
+ disabled
407
+ ]);
408
+ if (context && !context.activeLayerGroups.includes(name)) return null;
409
+ return /* @__PURE__ */ jsx(LeafletFeatureGroup, { ...props });
410
+ }
411
+ function MapLayers({ defaultTileLayer, defaultLayerGroups = [], ...props }) {
412
+ const [tileLayers, setTileLayers] = useState([]);
413
+ const [selectedTileLayer, setSelectedTileLayer] = useState(defaultTileLayer || "");
414
+ const [layerGroups, setLayerGroups] = useState([]);
415
+ const [activeLayerGroups, setActiveLayerGroups] = useState(defaultLayerGroups);
416
+ function registerTileLayer(tileLayer) {
417
+ setTileLayers((prevTileLayers) => {
418
+ if (prevTileLayers.some((layer) => layer.name === tileLayer.name)) return prevTileLayers;
419
+ return [...prevTileLayers, tileLayer];
420
+ });
421
+ }
422
+ function registerLayerGroup(layerGroup) {
423
+ setLayerGroups((prevLayerGroups) => {
424
+ if (prevLayerGroups.some((group) => group.name === layerGroup.name)) return prevLayerGroups;
425
+ return [...prevLayerGroups, layerGroup];
426
+ });
427
+ }
428
+ useEffect(() => {
429
+ if (defaultTileLayer && tileLayers.length > 0 && !tileLayers.some((tileLayer) => tileLayer.name === defaultTileLayer)) throw new Error(`Invalid defaultTileLayer "${defaultTileLayer}" provided to MapLayers. It must match a MapTileLayer's name prop.`);
430
+ if (tileLayers.length > 0 && !selectedTileLayer) setSelectedTileLayer(defaultTileLayer && tileLayers.some((layer) => layer.name === defaultTileLayer) ? defaultTileLayer : tileLayers[0].name);
431
+ if (defaultLayerGroups.length > 0 && layerGroups.length > 0 && defaultLayerGroups.some((name) => !layerGroups.some((group) => group.name === name))) throw new Error(`Invalid defaultLayerGroups value provided to MapLayers. All names must match a MapLayerGroup's name prop.`);
432
+ }, [
433
+ tileLayers,
434
+ defaultTileLayer,
435
+ selectedTileLayer,
436
+ layerGroups,
437
+ defaultLayerGroups
438
+ ]);
439
+ return /* @__PURE__ */ jsx(MapLayersContext.Provider, {
440
+ value: {
441
+ registerTileLayer,
442
+ tileLayers,
443
+ selectedTileLayer,
444
+ setSelectedTileLayer,
445
+ registerLayerGroup,
446
+ layerGroups,
447
+ activeLayerGroups,
448
+ setActiveLayerGroups
449
+ },
450
+ ...props
451
+ });
452
+ }
453
+ function MapLayersControl({ tileLayersLabel = "Map Type", layerGroupsLabel = "Layers", position = "top-1 right-1", className, ...props }) {
454
+ const layersContext = useMapLayersContext();
455
+ if (!layersContext) throw new Error("MapLayersControl must be used within MapLayers");
456
+ const { tileLayers, selectedTileLayer, setSelectedTileLayer, layerGroups, activeLayerGroups, setActiveLayerGroups } = layersContext;
457
+ if (tileLayers.length === 0 && layerGroups.length === 0) return null;
458
+ function handleLayerGroupToggle(name, checked) {
459
+ setActiveLayerGroups(checked ? [...activeLayerGroups, name] : activeLayerGroups.filter((groupName) => groupName !== name));
460
+ }
461
+ const showTileLayersDropdown = tileLayers.length > 1;
462
+ const showLayerGroupsDropdown = layerGroups.length > 0;
463
+ if (!showTileLayersDropdown && !showLayerGroupsDropdown) return null;
464
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
465
+ asChild: true,
466
+ children: /* @__PURE__ */ jsx(Button, {
467
+ type: "button",
468
+ variant: "secondary",
469
+ size: "sm",
470
+ "aria-label": "Select layers",
471
+ title: "Select layers",
472
+ className: cn("absolute z-1000 border", position, className),
473
+ ...props,
474
+ children: /* @__PURE__ */ jsx(LayersIcon, {})
475
+ })
476
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
477
+ align: "end",
478
+ className: "z-1000",
479
+ children: [
480
+ showTileLayersDropdown && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DropdownMenuLabel, { children: tileLayersLabel }), /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
481
+ value: selectedTileLayer,
482
+ onValueChange: setSelectedTileLayer,
483
+ children: tileLayers.map((tileLayer) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
484
+ value: tileLayer.name,
485
+ children: tileLayer.name
486
+ }, tileLayer.name))
487
+ })] }),
488
+ showTileLayersDropdown && showLayerGroupsDropdown && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
489
+ showLayerGroupsDropdown && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DropdownMenuLabel, { children: layerGroupsLabel }), layerGroups.map((layerGroup) => /* @__PURE__ */ jsx(DropdownMenuCheckboxItem, {
490
+ checked: activeLayerGroups.includes(layerGroup.name),
491
+ disabled: layerGroup.disabled,
492
+ onCheckedChange: (checked) => handleLayerGroupToggle(layerGroup.name, checked),
493
+ children: layerGroup.name
494
+ }, layerGroup.name))] })
495
+ ]
496
+ })] });
497
+ }
498
+ function MapMarker({ icon = /* @__PURE__ */ jsx(MapPinIcon, { className: "size-6" }), iconAnchor = [12, 12], bgPos, popupAnchor, tooltipAnchor, ...props }) {
499
+ const { L } = useLeaflet();
500
+ if (!L) return null;
501
+ return /* @__PURE__ */ jsx(LeafletMarker, {
502
+ icon: L.divIcon({
503
+ html: renderToString(icon),
504
+ iconAnchor,
505
+ ...bgPos ? { bgPos } : {},
506
+ ...popupAnchor ? { popupAnchor } : {},
507
+ ...tooltipAnchor ? { tooltipAnchor } : {}
508
+ }),
509
+ riseOnHover: true,
510
+ ...props
511
+ });
512
+ }
513
+ function MapMarkerClusterGroup({ polygonOptions = { className: "fill-foreground stroke-foreground stroke-2" }, spiderLegPolylineOptions = { className: "fill-foreground stroke-foreground stroke-2" }, icon, ...props }) {
514
+ const { L } = useLeaflet();
515
+ if (!L) return null;
516
+ return /* @__PURE__ */ jsx(LeafletMarkerClusterGroup, {
517
+ polygonOptions,
518
+ spiderLegPolylineOptions,
519
+ iconCreateFunction: icon ? (cluster) => {
520
+ const iconNode = icon(cluster.getChildCount());
521
+ return L.divIcon({ html: renderToString(iconNode) });
522
+ } : void 0,
523
+ ...props
524
+ });
525
+ }
526
+ function MapCircle({ className, ...props }) {
527
+ return /* @__PURE__ */ jsx(LeafletCircle, {
528
+ className: cn("fill-foreground stroke-foreground stroke-2", className),
529
+ ...props
530
+ });
531
+ }
532
+ function MapCircleMarker({ className, ...props }) {
533
+ return /* @__PURE__ */ jsx(LeafletCircleMarker, {
534
+ className: cn("fill-foreground stroke-foreground stroke-2", className),
535
+ ...props
536
+ });
537
+ }
538
+ function MapPolyline({ className, ...props }) {
539
+ return /* @__PURE__ */ jsx(LeafletPolyline, {
540
+ className: cn("fill-foreground stroke-foreground stroke-2", className),
541
+ ...props
542
+ });
543
+ }
544
+ function MapPolygon({ className, ...props }) {
545
+ return /* @__PURE__ */ jsx(LeafletPolygon, {
546
+ className: cn("fill-foreground stroke-foreground stroke-2", className),
547
+ ...props
548
+ });
549
+ }
550
+ function MapRectangle({ className, ...props }) {
551
+ return /* @__PURE__ */ jsx(LeafletRectangle, {
552
+ className: cn("fill-foreground stroke-foreground stroke-2", className),
553
+ ...props
554
+ });
555
+ }
556
+ function MapPopup({ className, ...props }) {
557
+ return /* @__PURE__ */ jsx(LeafletPopup, {
558
+ className: cn("bg-popover text-popover-foreground animate-in fade-out-0 fade-in-0 zoom-out-95 zoom-in-95 slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 font-sans shadow-md outline-hidden", className),
559
+ ...props
560
+ });
561
+ }
562
+ function MapTooltip({ className, children, side = "top", sideOffset = 15, ...props }) {
563
+ const ARROW_POSITION_CLASSES = {
564
+ top: "bottom-0.5 left-1/2 -translate-x-1/2 translate-y-1/2",
565
+ bottom: "top-0.5 left-1/2 -translate-x-1/2 -translate-y-1/2",
566
+ left: "right-0.5 top-1/2 translate-x-1/2 -translate-y-1/2",
567
+ right: "left-0.5 top-1/2 -translate-x-1/2 -translate-y-1/2"
568
+ };
569
+ const DEFAULT_OFFSET = {
570
+ top: [0, -sideOffset],
571
+ bottom: [0, sideOffset],
572
+ left: [-sideOffset, 0],
573
+ right: [sideOffset, 0]
574
+ };
575
+ return /* @__PURE__ */ jsxs(LeafletTooltip, {
576
+ className: cn("animate-in fade-in-0 zoom-in-95 fade-out-0 zoom-out-95 data-[side=bottom]:slide-in-from-top-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 relative z-50 w-fit text-xs text-balance transition-opacity", className),
577
+ "data-side": side,
578
+ direction: side,
579
+ offset: DEFAULT_OFFSET[side],
580
+ opacity: 1,
581
+ ...props,
582
+ children: [children, /* @__PURE__ */ jsx("div", { className: cn("bg-foreground fill-foreground absolute z-50 size-2.5 rotate-45 rounded-[2px]", ARROW_POSITION_CLASSES[side]) })]
583
+ });
584
+ }
585
+ function MapZoomControl({ position = "top-1 left-1", className, ...props }) {
586
+ const map = _useMap();
587
+ const [zoomLevel, setZoomLevel] = useState(map.getZoom());
588
+ _useMapEvents({ zoomend: () => {
589
+ setZoomLevel(map.getZoom());
590
+ } });
591
+ return /* @__PURE__ */ jsx(MapControlContainer, {
592
+ className: cn(position, className),
593
+ children: /* @__PURE__ */ jsxs(ButtonGroup, {
594
+ orientation: "vertical",
595
+ "aria-label": "Zoom controls",
596
+ ...props,
597
+ children: [/* @__PURE__ */ jsx(Button, {
598
+ type: "button",
599
+ size: "icon",
600
+ variant: "outline",
601
+ "aria-label": "Zoom in",
602
+ title: "Zoom in",
603
+ className: "border",
604
+ disabled: zoomLevel >= map.getMaxZoom(),
605
+ onClick: () => map.zoomIn(),
606
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
607
+ }), /* @__PURE__ */ jsx(Button, {
608
+ type: "button",
609
+ size: "icon",
610
+ variant: "outline",
611
+ "aria-label": "Zoom out",
612
+ title: "Zoom out",
613
+ className: "border",
614
+ disabled: zoomLevel <= map.getMinZoom(),
615
+ onClick: () => map.zoomOut(),
616
+ children: /* @__PURE__ */ jsx(MinusIcon, {})
617
+ })]
618
+ })
619
+ });
620
+ }
621
+ function MapFullscreenControl({ position = "top-1 right-1", className, ...props }) {
622
+ const map = _useMap();
623
+ const [isFullscreen, setIsFullscreen] = useState(false);
624
+ const { L } = useLeaflet();
625
+ useEffect(() => {
626
+ if (!L) return;
627
+ const fullscreenControl = new L.Control.FullScreen();
628
+ fullscreenControl.addTo(map);
629
+ const container = fullscreenControl.getContainer();
630
+ if (container) container.style.display = "none";
631
+ const handleEnter = () => setIsFullscreen(true);
632
+ const handleExit = () => setIsFullscreen(false);
633
+ map.on("enterFullscreen", handleEnter);
634
+ map.on("exitFullscreen", handleExit);
635
+ return () => {
636
+ fullscreenControl.remove();
637
+ map.off("enterFullscreen", handleEnter);
638
+ map.off("exitFullscreen", handleExit);
639
+ };
640
+ }, [L, map]);
641
+ return /* @__PURE__ */ jsx(MapControlContainer, {
642
+ className: cn(position, className),
643
+ children: /* @__PURE__ */ jsx(Button, {
644
+ type: "button",
645
+ size: "icon",
646
+ variant: "outline",
647
+ onClick: () => map.toggleFullscreen(),
648
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
649
+ title: isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
650
+ className: "border",
651
+ ...props,
652
+ children: isFullscreen ? /* @__PURE__ */ jsx(MinimizeIcon, {}) : /* @__PURE__ */ jsx(MaximizeIcon, {})
653
+ })
654
+ });
655
+ }
656
+ function MapLocatePulseIcon() {
657
+ return /* @__PURE__ */ jsxs("div", {
658
+ className: "absolute -top-1 -right-1 flex size-3 rounded-full",
659
+ children: [/* @__PURE__ */ jsx("div", { className: "bg-primary absolute inline-flex size-full animate-ping rounded-full opacity-75" }), /* @__PURE__ */ jsx("div", { className: "bg-primary relative inline-flex size-3 rounded-full" })]
660
+ });
661
+ }
662
+ function MapLocateControl({ watch = false, onLocationFound, onLocationError, position = "right-1 bottom-1", className, ...props }) {
663
+ const map = _useMap();
664
+ const [isLocating, setIsLocating] = useDebounceLoadingState(200);
665
+ const [location, setLocation] = useState(null);
666
+ function startLocating() {
667
+ setIsLocating(true);
668
+ map.locate({
669
+ setView: true,
670
+ maxZoom: map.getMaxZoom(),
671
+ watch
672
+ });
673
+ map.on("locationfound", (location) => {
674
+ setLocation(location.latlng);
675
+ setIsLocating(false);
676
+ onLocationFound?.(location);
677
+ });
678
+ map.on("locationerror", (error) => {
679
+ setLocation(null);
680
+ setIsLocating(false);
681
+ onLocationError?.(error);
682
+ });
683
+ }
684
+ function stopLocating() {
685
+ map.stopLocate();
686
+ map.off("locationfound");
687
+ map.off("locationerror");
688
+ setLocation(null);
689
+ setIsLocating(false);
690
+ }
691
+ useEffect(() => () => stopLocating(), []);
692
+ return /* @__PURE__ */ jsxs(MapControlContainer, {
693
+ className: cn(position, className),
694
+ children: [/* @__PURE__ */ jsx(Button, {
695
+ type: "button",
696
+ size: "sm",
697
+ variant: location ? "default" : "secondary",
698
+ onClick: location ? stopLocating : startLocating,
699
+ disabled: isLocating,
700
+ title: isLocating ? "Locating..." : location ? "Stop tracking" : "Track location",
701
+ "aria-label": isLocating ? "Locating..." : location ? "Stop location tracking" : "Start location tracking",
702
+ className: "border",
703
+ ...props,
704
+ children: isLocating ? /* @__PURE__ */ jsx(LoaderCircleIcon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(NavigationIcon, {})
705
+ }), location && /* @__PURE__ */ jsx(MapMarker, {
706
+ position: location,
707
+ icon: /* @__PURE__ */ jsx(MapLocatePulseIcon, {})
708
+ })]
709
+ });
710
+ }
711
+ function MapSearchControl({ position = "top-1 left-1", className, ...props }) {
712
+ return /* @__PURE__ */ jsx(MapControlContainer, {
713
+ className: cn("z-1001 w-60", position, className),
714
+ children: /* @__PURE__ */ jsx(PlaceAutocomplete, { ...props })
715
+ });
716
+ }
717
+ const MapDrawContext = createContext(null);
718
+ function useMapDrawContext() {
719
+ return useContext(MapDrawContext);
720
+ }
721
+ function MapDrawControl({ onLayersChange, position = "bottom-1 left-1", className, ...props }) {
722
+ const { L, LeafletDraw } = useLeaflet();
723
+ const map = _useMap();
724
+ const featureGroupRef = useRef(null);
725
+ const editControlRef = useRef(null);
726
+ const deleteControlRef = useRef(null);
727
+ const [activeMode, setActiveMode] = useState(null);
728
+ const [layersCount, setLayersCount] = useState(0);
729
+ function updateLayersCount() {
730
+ if (featureGroupRef.current) setLayersCount(featureGroupRef.current.getLayers().length);
731
+ }
732
+ function handleDrawCreated(event) {
733
+ if (!featureGroupRef.current) return;
734
+ const { layer } = event;
735
+ featureGroupRef.current.addLayer(layer);
736
+ onLayersChange?.(featureGroupRef.current);
737
+ updateLayersCount();
738
+ setActiveMode(null);
739
+ }
740
+ function handleDrawEditedOrDeleted() {
741
+ if (!featureGroupRef.current) return;
742
+ onLayersChange?.(featureGroupRef.current);
743
+ updateLayersCount();
744
+ setActiveMode(null);
745
+ }
746
+ useEffect(() => {
747
+ if (!L || !LeafletDraw || !map) return;
748
+ map.on(L.Draw.Event.CREATED, handleDrawCreated);
749
+ map.on(L.Draw.Event.EDITED, handleDrawEditedOrDeleted);
750
+ map.on(L.Draw.Event.DELETED, handleDrawEditedOrDeleted);
751
+ return () => {
752
+ map.off(L.Draw.Event.CREATED, handleDrawCreated);
753
+ map.off(L.Draw.Event.EDITED, handleDrawEditedOrDeleted);
754
+ map.off(L.Draw.Event.DELETED, handleDrawEditedOrDeleted);
755
+ };
756
+ }, [
757
+ L,
758
+ LeafletDraw,
759
+ map,
760
+ onLayersChange
761
+ ]);
762
+ return /* @__PURE__ */ jsxs(MapDrawContext.Provider, {
763
+ value: {
764
+ featureGroup: featureGroupRef.current,
765
+ activeMode,
766
+ setActiveMode,
767
+ editControlRef,
768
+ deleteControlRef,
769
+ layersCount
770
+ },
771
+ children: [/* @__PURE__ */ jsx(LeafletFeatureGroup, { ref: featureGroupRef }), /* @__PURE__ */ jsx(MapControlContainer, {
772
+ className: cn(position, className),
773
+ children: /* @__PURE__ */ jsx(ButtonGroup, {
774
+ orientation: "vertical",
775
+ ...props
776
+ })
777
+ })]
778
+ });
779
+ }
780
+ function MapDrawShapeButton({ drawMode, createDrawTool, className, ...props }) {
781
+ const drawContext = useMapDrawContext();
782
+ if (!drawContext) throw new Error("MapDrawShapeButton must be used within MapDrawControl");
783
+ const { L } = useLeaflet();
784
+ const map = _useMap();
785
+ const controlRef = useRef(null);
786
+ const { activeMode, setActiveMode } = drawContext;
787
+ const isActive = activeMode === drawMode;
788
+ useEffect(() => {
789
+ if (!L || !isActive) {
790
+ controlRef.current?.disable();
791
+ controlRef.current = null;
792
+ return;
793
+ }
794
+ const control = createDrawTool(L, map);
795
+ control.enable();
796
+ controlRef.current = control;
797
+ return () => {
798
+ control.disable();
799
+ controlRef.current = null;
800
+ };
801
+ }, [
802
+ L,
803
+ map,
804
+ isActive,
805
+ createDrawTool
806
+ ]);
807
+ function handleClick() {
808
+ setActiveMode(isActive ? null : drawMode);
809
+ }
810
+ return /* @__PURE__ */ jsx(Button, {
811
+ type: "button",
812
+ size: "sm",
813
+ "aria-label": `Draw ${drawMode}`,
814
+ title: `Draw ${drawMode}`,
815
+ className: cn("border", className),
816
+ variant: isActive ? "default" : "secondary",
817
+ disabled: activeMode === "edit" || activeMode === "delete",
818
+ onClick: handleClick,
819
+ ...props
820
+ });
821
+ }
822
+ function MapDrawMarker({ ...props }) {
823
+ return /* @__PURE__ */ jsx(MapDrawShapeButton, {
824
+ drawMode: "marker",
825
+ createDrawTool: (L, map) => new L.Draw.Marker(map, {
826
+ icon: L.divIcon({
827
+ className: "",
828
+ iconAnchor: [12, 12],
829
+ html: renderToString(/* @__PURE__ */ jsx(MapPinIcon, { className: "size-6" }))
830
+ }),
831
+ ...props
832
+ }),
833
+ children: /* @__PURE__ */ jsx(MapPinIcon, {})
834
+ });
835
+ }
836
+ function MapDrawPolyline({ showLength = false, drawError = { color: "var(--color-destructive)" }, shapeOptions = {
837
+ color: "var(--color-primary)",
838
+ opacity: 1,
839
+ weight: 2
840
+ }, ...props }) {
841
+ const mapDrawHandleIcon = useMapDrawHandleIcon();
842
+ return /* @__PURE__ */ jsx(MapDrawShapeButton, {
843
+ drawMode: "polyline",
844
+ createDrawTool: (L, map) => new L.Draw.Polyline(map, {
845
+ ...mapDrawHandleIcon ? {
846
+ icon: mapDrawHandleIcon,
847
+ touchIcon: mapDrawHandleIcon
848
+ } : {},
849
+ showLength,
850
+ drawError,
851
+ shapeOptions,
852
+ ...props
853
+ }),
854
+ children: /* @__PURE__ */ jsx(WaypointsIcon, {})
855
+ });
856
+ }
857
+ function MapDrawCircle({ showRadius = false, shapeOptions = {
858
+ color: "var(--color-primary)",
859
+ opacity: 1,
860
+ weight: 2
861
+ }, ...props }) {
862
+ return /* @__PURE__ */ jsx(MapDrawShapeButton, {
863
+ drawMode: "circle",
864
+ createDrawTool: (L, map) => new L.Draw.Circle(map, {
865
+ showRadius,
866
+ shapeOptions,
867
+ ...props
868
+ }),
869
+ children: /* @__PURE__ */ jsx(CircleIcon, {})
870
+ });
871
+ }
872
+ function MapDrawRectangle({ showArea = false, shapeOptions = {
873
+ color: "var(--color-primary)",
874
+ opacity: 1,
875
+ weight: 2
876
+ }, ...props }) {
877
+ return /* @__PURE__ */ jsx(MapDrawShapeButton, {
878
+ drawMode: "rectangle",
879
+ createDrawTool: (L, map) => new L.Draw.Rectangle(map, {
880
+ showArea,
881
+ shapeOptions,
882
+ ...props
883
+ }),
884
+ children: /* @__PURE__ */ jsx(SquareIcon, {})
885
+ });
886
+ }
887
+ function MapDrawPolygon({ drawError = { color: "var(--color-destructive)" }, shapeOptions = {
888
+ color: "var(--color-primary)",
889
+ opacity: 1,
890
+ weight: 2
891
+ }, ...props }) {
892
+ const mapDrawHandleIcon = useMapDrawHandleIcon();
893
+ return /* @__PURE__ */ jsx(MapDrawShapeButton, {
894
+ drawMode: "polygon",
895
+ createDrawTool: (L, map) => new L.Draw.Polygon(map, {
896
+ ...mapDrawHandleIcon ? {
897
+ icon: mapDrawHandleIcon,
898
+ touchIcon: mapDrawHandleIcon
899
+ } : {},
900
+ drawError,
901
+ shapeOptions,
902
+ ...props
903
+ }),
904
+ children: /* @__PURE__ */ jsx(PentagonIcon, {})
905
+ });
906
+ }
907
+ function MapDrawActionButton({ drawAction, createDrawTool, controlRef, className, ...props }) {
908
+ const drawContext = useMapDrawContext();
909
+ if (!drawContext) throw new Error("MapDrawActionButton must be used within MapDrawControl");
910
+ const { L } = useLeaflet();
911
+ const map = _useMap();
912
+ const { featureGroup, activeMode, setActiveMode, layersCount } = drawContext;
913
+ const isActive = activeMode === drawAction;
914
+ const hasFeatures = layersCount > 0;
915
+ useEffect(() => {
916
+ if (!L || !featureGroup || !isActive) {
917
+ controlRef.current?.disable?.();
918
+ controlRef.current = null;
919
+ return;
920
+ }
921
+ const control = createDrawTool(L, map, featureGroup);
922
+ control.enable?.();
923
+ controlRef.current = control;
924
+ return () => {
925
+ control.disable?.();
926
+ controlRef.current = null;
927
+ };
928
+ }, [
929
+ L,
930
+ map,
931
+ isActive,
932
+ featureGroup,
933
+ createDrawTool
934
+ ]);
935
+ function handleClick() {
936
+ controlRef.current?.save();
937
+ setActiveMode(isActive ? null : drawAction);
938
+ }
939
+ return /* @__PURE__ */ jsx(Button, {
940
+ type: "button",
941
+ size: "sm",
942
+ "aria-label": `${drawAction === "edit" ? "Edit" : "Remove"} shapes`,
943
+ title: `${drawAction === "edit" ? "Edit" : "Remove"} shapes`,
944
+ variant: isActive ? "default" : "secondary",
945
+ disabled: !hasFeatures,
946
+ onClick: handleClick,
947
+ className: cn("border", className),
948
+ ...props
949
+ });
950
+ }
951
+ function MapDrawEdit({ selectedPathOptions = {
952
+ color: "var(--color-primary)",
953
+ fillColor: "var(--color-primary)",
954
+ weight: 2
955
+ }, ...props }) {
956
+ const { L } = useLeaflet();
957
+ const mapDrawHandleIcon = useMapDrawHandleIcon();
958
+ const drawContext = useMapDrawContext();
959
+ if (!drawContext) throw new Error("MapDrawEdit must be used within MapDrawControl");
960
+ useEffect(() => {
961
+ if (!L || !mapDrawHandleIcon) return;
962
+ L.Edit.PolyVerticesEdit.mergeOptions({
963
+ icon: mapDrawHandleIcon,
964
+ touchIcon: mapDrawHandleIcon,
965
+ drawError: { color: "var(--color-destructive)" }
966
+ });
967
+ L.Edit.SimpleShape.mergeOptions({
968
+ moveIcon: mapDrawHandleIcon,
969
+ resizeIcon: mapDrawHandleIcon,
970
+ touchMoveIcon: mapDrawHandleIcon,
971
+ touchResizeIcon: mapDrawHandleIcon
972
+ });
973
+ L.drawLocal.edit.handlers.edit.tooltip = {
974
+ text: "Drag handles or markers to edit.",
975
+ subtext: ""
976
+ };
977
+ L.drawLocal.edit.handlers.remove.tooltip = { text: "Click on a shape to remove." };
978
+ }, [mapDrawHandleIcon]);
979
+ return /* @__PURE__ */ jsx(MapDrawActionButton, {
980
+ drawAction: "edit",
981
+ controlRef: drawContext.editControlRef,
982
+ createDrawTool: (L, map, featureGroup) => new L.EditToolbar.Edit(map, {
983
+ featureGroup,
984
+ selectedPathOptions,
985
+ ...props
986
+ }),
987
+ children: /* @__PURE__ */ jsx(PenLineIcon, {})
988
+ });
989
+ }
990
+ function MapDrawDelete() {
991
+ const drawContext = useMapDrawContext();
992
+ if (!drawContext) throw new Error("MapDrawDelete must be used within MapDrawControl");
993
+ return /* @__PURE__ */ jsx(MapDrawActionButton, {
994
+ drawAction: "delete",
995
+ controlRef: drawContext.deleteControlRef,
996
+ createDrawTool: (L, map, featureGroup) => new L.EditToolbar.Delete(map, { featureGroup }),
997
+ children: /* @__PURE__ */ jsx(Trash2Icon, {})
998
+ });
999
+ }
1000
+ function MapDrawUndo({ className, ...props }) {
1001
+ const drawContext = useMapDrawContext();
1002
+ if (!drawContext) throw new Error("MapDrawUndo must be used within MapDrawControl");
1003
+ const { activeMode, setActiveMode, editControlRef, deleteControlRef, layersCount } = drawContext;
1004
+ const isInEditMode = activeMode === "edit";
1005
+ const isInDeleteMode = activeMode === "delete";
1006
+ const isActive = (isInEditMode || isInDeleteMode) && layersCount > 0;
1007
+ function handleUndo() {
1008
+ if (isInEditMode) editControlRef.current?.revertLayers();
1009
+ else if (isInDeleteMode) deleteControlRef.current?.revertLayers();
1010
+ setActiveMode(null);
1011
+ }
1012
+ return /* @__PURE__ */ jsx(Button, {
1013
+ type: "button",
1014
+ size: "sm",
1015
+ variant: "secondary",
1016
+ "aria-label": `Undo ${activeMode}`,
1017
+ title: `Undo ${activeMode}`,
1018
+ onClick: handleUndo,
1019
+ disabled: !isActive,
1020
+ className: cn("border", className),
1021
+ ...props,
1022
+ children: /* @__PURE__ */ jsx(Undo2Icon, {})
1023
+ });
1024
+ }
1025
+ function MapControlContainer({ className, ...props }) {
1026
+ const { L } = useLeaflet();
1027
+ const containerRef = useRef(null);
1028
+ useEffect(() => {
1029
+ if (!L) return;
1030
+ const element = containerRef.current;
1031
+ if (!element) return;
1032
+ L.DomEvent.disableClickPropagation(element);
1033
+ L.DomEvent.disableScrollPropagation(element);
1034
+ }, [L]);
1035
+ return /* @__PURE__ */ jsx("div", {
1036
+ ref: containerRef,
1037
+ className: cn("absolute z-1000 size-fit cursor-default", className),
1038
+ ...props
1039
+ });
1040
+ }
1041
+ function useMapDrawHandleIcon() {
1042
+ const { L } = useLeaflet();
1043
+ if (!L) return null;
1044
+ return L.divIcon({
1045
+ iconAnchor: [8, 8],
1046
+ html: renderToString(/* @__PURE__ */ jsx(CircleIcon, { className: "fill-primary stroke-primary size-4 transition-transform hover:scale-110" }))
1047
+ });
1048
+ }
1049
+ function useLeaflet() {
1050
+ const [L, setL] = useState(null);
1051
+ const [LeafletDraw, setLeafletDraw] = useState(null);
1052
+ useEffect(() => {
1053
+ async function loadLeaflet() {
1054
+ const leaflet = await import("leaflet");
1055
+ const leafletFullscreen = await import("leaflet.fullscreen");
1056
+ const leafletDraw = await import("leaflet-draw");
1057
+ const L_object = leaflet.default;
1058
+ if (L_object.Control && !L_object.Control.FullScreen) L_object.Control.FullScreen = leafletFullscreen.default || leafletFullscreen;
1059
+ setLeafletDraw(leafletDraw);
1060
+ setL(L_object);
1061
+ }
1062
+ if (L && LeafletDraw) return;
1063
+ if (typeof window === "undefined") return;
1064
+ loadLeaflet();
1065
+ }, [L, LeafletDraw]);
1066
+ return {
1067
+ L,
1068
+ LeafletDraw
1069
+ };
1070
+ }
1071
+ function useDebounceLoadingState(delay = 200) {
1072
+ const [isLoading, setIsLoading] = useState(false);
1073
+ const [showLoading, setShowLoading] = useState(false);
1074
+ const timeoutRef = useRef(null);
1075
+ useEffect(() => {
1076
+ if (isLoading) timeoutRef.current = setTimeout(() => {
1077
+ setShowLoading(true);
1078
+ }, delay);
1079
+ else {
1080
+ if (timeoutRef.current) {
1081
+ clearTimeout(timeoutRef.current);
1082
+ timeoutRef.current = null;
1083
+ }
1084
+ setShowLoading(false);
1085
+ }
1086
+ return () => {
1087
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
1088
+ };
1089
+ }, [isLoading, delay]);
1090
+ return [showLoading, setIsLoading];
1091
+ }
1092
+
1093
+ //#endregion
1094
+ export { useLeaflet as A, MapPolyline as C, MapTileLayer as D, MapSearchControl as E, MapTooltip as O, MapPolygon as S, MapRectangle as T, MapLayers as _, MapDrawCircle as a, MapMarker as b, MapDrawEdit as c, MapDrawPolyline as d, MapDrawRectangle as f, MapLayerGroup as g, MapFullscreenControl as h, MapControlContainer as i, PlaceAutocomplete as j, MapZoomControl as k, MapDrawMarker as l, MapFeatureGroup as m, MapCircle as n, MapDrawControl as o, MapDrawUndo as p, MapCircleMarker as r, MapDrawDelete as s, Map as t, MapDrawPolygon as u, MapLayersControl as v, MapPopup as w, MapMarkerClusterGroup as x, MapLocateControl as y };