@konce-pt/react 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/accordion/accordion.d.ts +45 -0
  4. package/dist/accordion/accordion.js +69 -0
  5. package/dist/alert/alert.d.ts +25 -0
  6. package/dist/alert/alert.js +31 -0
  7. package/dist/app-shell/app-shell.d.ts +94 -0
  8. package/dist/app-shell/app-shell.js +105 -0
  9. package/dist/auth/auth-types.d.ts +44 -0
  10. package/dist/auth/auth-types.js +2 -0
  11. package/dist/auth/auth.d.ts +76 -0
  12. package/dist/auth/auth.js +184 -0
  13. package/dist/autocomplete/autocomplete.d.ts +18 -0
  14. package/dist/autocomplete/autocomplete.js +72 -0
  15. package/dist/avatar/avatar.d.ts +33 -0
  16. package/dist/avatar/avatar.js +30 -0
  17. package/dist/avatar-group/avatar-group.d.ts +21 -0
  18. package/dist/avatar-group/avatar-group.js +15 -0
  19. package/dist/badge/badge.d.ts +25 -0
  20. package/dist/badge/badge.js +14 -0
  21. package/dist/bottom-sheet/bottom-sheet.d.ts +21 -0
  22. package/dist/bottom-sheet/bottom-sheet.js +22 -0
  23. package/dist/breadcrumb/breadcrumb.d.ts +19 -0
  24. package/dist/breadcrumb/breadcrumb.js +20 -0
  25. package/dist/button/button.d.ts +27 -0
  26. package/dist/button/button.js +49 -0
  27. package/dist/button-group/button-group.d.ts +25 -0
  28. package/dist/button-group/button-group.js +30 -0
  29. package/dist/card/card.d.ts +66 -0
  30. package/dist/card/card.js +96 -0
  31. package/dist/carousel/carousel.d.ts +20 -0
  32. package/dist/carousel/carousel.js +24 -0
  33. package/dist/charts/chart-legend.d.ts +23 -0
  34. package/dist/charts/chart-legend.js +9 -0
  35. package/dist/charts/chart-tooltip.d.ts +21 -0
  36. package/dist/charts/chart-tooltip.js +13 -0
  37. package/dist/charts/chart.d.ts +18 -0
  38. package/dist/charts/chart.js +231 -0
  39. package/dist/charts-entry/public-api.d.ts +4 -0
  40. package/dist/charts-entry/public-api.js +7 -0
  41. package/dist/checkbox/checkbox.d.ts +33 -0
  42. package/dist/checkbox/checkbox.js +29 -0
  43. package/dist/chip/chip.d.ts +22 -0
  44. package/dist/chip/chip.js +16 -0
  45. package/dist/chips-input/chips-input.d.ts +25 -0
  46. package/dist/chips-input/chips-input.js +54 -0
  47. package/dist/clock/clock.d.ts +17 -0
  48. package/dist/clock/clock.js +57 -0
  49. package/dist/color-picker/color-picker.d.ts +23 -0
  50. package/dist/color-picker/color-picker.js +28 -0
  51. package/dist/confirm/confirm-container.d.ts +13 -0
  52. package/dist/confirm/confirm-container.js +26 -0
  53. package/dist/confirm/confirm-store.d.ts +29 -0
  54. package/dist/confirm/confirm-store.js +52 -0
  55. package/dist/context-menu/context-menu.d.ts +21 -0
  56. package/dist/context-menu/context-menu.js +36 -0
  57. package/dist/data-table/data-table-types.d.ts +67 -0
  58. package/dist/data-table/data-table-types.js +1 -0
  59. package/dist/data-table/data-table.d.ts +62 -0
  60. package/dist/data-table/data-table.js +453 -0
  61. package/dist/data-table/export-csv.d.ts +7 -0
  62. package/dist/data-table/export-csv.js +19 -0
  63. package/dist/data-view/data-view.d.ts +21 -0
  64. package/dist/data-view/data-view.js +25 -0
  65. package/dist/date-range/date-range.d.ts +30 -0
  66. package/dist/date-range/date-range.js +155 -0
  67. package/dist/datepicker/datepicker.d.ts +39 -0
  68. package/dist/datepicker/datepicker.js +202 -0
  69. package/dist/dialog/dialog.d.ts +35 -0
  70. package/dist/dialog/dialog.js +59 -0
  71. package/dist/divider/divider.d.ts +16 -0
  72. package/dist/divider/divider.js +13 -0
  73. package/dist/drawer/drawer.d.ts +25 -0
  74. package/dist/drawer/drawer.js +25 -0
  75. package/dist/empty/empty.d.ts +18 -0
  76. package/dist/empty/empty.js +14 -0
  77. package/dist/fab/fab.d.ts +22 -0
  78. package/dist/fab/fab.js +17 -0
  79. package/dist/fieldset/fieldset.d.ts +22 -0
  80. package/dist/fieldset/fieldset.js +24 -0
  81. package/dist/file-upload/file-upload.d.ts +22 -0
  82. package/dist/file-upload/file-upload.js +50 -0
  83. package/dist/form-field/form-field-context.d.ts +23 -0
  84. package/dist/form-field/form-field-context.js +17 -0
  85. package/dist/form-field/form-field.d.ts +39 -0
  86. package/dist/form-field/form-field.js +41 -0
  87. package/dist/galleria/galleria.d.ts +22 -0
  88. package/dist/galleria/galleria.js +21 -0
  89. package/dist/grid/col.d.ts +39 -0
  90. package/dist/grid/col.js +32 -0
  91. package/dist/grid/flex.d.ts +45 -0
  92. package/dist/grid/flex.js +35 -0
  93. package/dist/grid/grid.d.ts +47 -0
  94. package/dist/grid/grid.js +38 -0
  95. package/dist/grid/layout.d.ts +18 -0
  96. package/dist/grid/layout.js +32 -0
  97. package/dist/grid-entry/public-api.d.ts +6 -0
  98. package/dist/grid-entry/public-api.js +8 -0
  99. package/dist/i18n/i18n-context.d.ts +45 -0
  100. package/dist/i18n/i18n-context.js +65 -0
  101. package/dist/icon/icon-registry.d.ts +16 -0
  102. package/dist/icon/icon-registry.js +43 -0
  103. package/dist/icon/icon.d.ts +17 -0
  104. package/dist/icon/icon.js +23 -0
  105. package/dist/icon-button/icon-button.d.ts +23 -0
  106. package/dist/icon-button/icon-button.js +14 -0
  107. package/dist/icons-entry/public-api.d.ts +12 -0
  108. package/dist/icons-entry/public-api.js +20 -0
  109. package/dist/image/image.d.ts +17 -0
  110. package/dist/image/image.js +16 -0
  111. package/dist/input/input.d.ts +41 -0
  112. package/dist/input/input.js +36 -0
  113. package/dist/input-mask/input-mask.d.ts +19 -0
  114. package/dist/input-mask/input-mask.js +65 -0
  115. package/dist/input-number/input-number.d.ts +28 -0
  116. package/dist/input-number/input-number.js +52 -0
  117. package/dist/input-otp/input-otp.d.ts +21 -0
  118. package/dist/input-otp/input-otp.js +59 -0
  119. package/dist/internal/cn.d.ts +9 -0
  120. package/dist/internal/cn.js +19 -0
  121. package/dist/internal/compose-refs.d.ts +6 -0
  122. package/dist/internal/compose-refs.js +16 -0
  123. package/dist/internal/overlay-container.d.ts +3 -0
  124. package/dist/internal/overlay-container.js +19 -0
  125. package/dist/internal/overlay.d.ts +26 -0
  126. package/dist/internal/overlay.js +64 -0
  127. package/dist/internal/slot.d.ts +23 -0
  128. package/dist/internal/slot.js +49 -0
  129. package/dist/internal/types.d.ts +25 -0
  130. package/dist/internal/types.js +1 -0
  131. package/dist/internal/use-breakpoint.d.ts +18 -0
  132. package/dist/internal/use-breakpoint.js +52 -0
  133. package/dist/internal/use-controllable-state.d.ts +11 -0
  134. package/dist/internal/use-controllable-state.js +18 -0
  135. package/dist/internal/use-id.d.ts +9 -0
  136. package/dist/internal/use-id.js +13 -0
  137. package/dist/knob/knob.d.ts +27 -0
  138. package/dist/knob/knob.js +86 -0
  139. package/dist/listbox/listbox.d.ts +28 -0
  140. package/dist/listbox/listbox.js +43 -0
  141. package/dist/map/map-create-dialog.d.ts +21 -0
  142. package/dist/map/map-create-dialog.js +196 -0
  143. package/dist/map/map-hours-field.d.ts +22 -0
  144. package/dist/map/map-hours-field.js +90 -0
  145. package/dist/map/map-image-field.d.ts +24 -0
  146. package/dist/map/map-image-field.js +61 -0
  147. package/dist/map/map-legend.d.ts +29 -0
  148. package/dist/map/map-legend.js +41 -0
  149. package/dist/map/map-poi-card.d.ts +42 -0
  150. package/dist/map/map-poi-card.js +152 -0
  151. package/dist/map/map-search.d.ts +37 -0
  152. package/dist/map/map-search.js +201 -0
  153. package/dist/map/map.d.ts +113 -0
  154. package/dist/map/map.js +425 -0
  155. package/dist/map/ports.d.ts +76 -0
  156. package/dist/map/ports.js +174 -0
  157. package/dist/map-entry/public-api.d.ts +20 -0
  158. package/dist/map-entry/public-api.js +19 -0
  159. package/dist/megamenu/megamenu.d.ts +17 -0
  160. package/dist/megamenu/megamenu.js +28 -0
  161. package/dist/menu/menu-item.d.ts +33 -0
  162. package/dist/menu/menu-item.js +1 -0
  163. package/dist/menu/menu-rows.d.ts +9 -0
  164. package/dist/menu/menu-rows.js +15 -0
  165. package/dist/menu/menu.d.ts +22 -0
  166. package/dist/menu/menu.js +31 -0
  167. package/dist/menubar/menubar.d.ts +16 -0
  168. package/dist/menubar/menubar.js +39 -0
  169. package/dist/meter-group/meter-group.d.ts +20 -0
  170. package/dist/meter-group/meter-group.js +24 -0
  171. package/dist/order-list/order-list.d.ts +18 -0
  172. package/dist/order-list/order-list.js +37 -0
  173. package/dist/paginator/paginator.d.ts +29 -0
  174. package/dist/paginator/paginator.js +45 -0
  175. package/dist/panel/panel.d.ts +31 -0
  176. package/dist/panel/panel.js +36 -0
  177. package/dist/password/password.d.ts +28 -0
  178. package/dist/password/password.js +37 -0
  179. package/dist/pick-list/pick-list.d.ts +28 -0
  180. package/dist/pick-list/pick-list.js +65 -0
  181. package/dist/popover/popover.d.ts +23 -0
  182. package/dist/popover/popover.js +27 -0
  183. package/dist/progress/progress.d.ts +19 -0
  184. package/dist/progress/progress.js +21 -0
  185. package/dist/public-api.d.ts +181 -0
  186. package/dist/public-api.js +105 -0
  187. package/dist/radio-group/radio-group.d.ts +24 -0
  188. package/dist/radio-group/radio-group.js +23 -0
  189. package/dist/rating/rating.d.ts +22 -0
  190. package/dist/rating/rating.js +30 -0
  191. package/dist/rich-text/lists.d.ts +17 -0
  192. package/dist/rich-text/lists.js +144 -0
  193. package/dist/rich-text/rich-text.d.ts +28 -0
  194. package/dist/rich-text/rich-text.js +654 -0
  195. package/dist/rich-text/sanitize.d.ts +10 -0
  196. package/dist/rich-text/sanitize.js +85 -0
  197. package/dist/rich-text/tables.d.ts +44 -0
  198. package/dist/rich-text/tables.js +268 -0
  199. package/dist/roadmap/roadmap.d.ts +37 -0
  200. package/dist/roadmap/roadmap.js +271 -0
  201. package/dist/roadmap-entry/public-api.d.ts +4 -0
  202. package/dist/roadmap-entry/public-api.js +7 -0
  203. package/dist/scroll-top/scroll-top.d.ts +16 -0
  204. package/dist/scroll-top/scroll-top.js +38 -0
  205. package/dist/select/select.d.ts +37 -0
  206. package/dist/select/select.js +117 -0
  207. package/dist/shared/types.d.ts +8 -0
  208. package/dist/shared/types.js +1 -0
  209. package/dist/sidenav/sidenav.d.ts +26 -0
  210. package/dist/sidenav/sidenav.js +41 -0
  211. package/dist/skeleton/skeleton.d.ts +20 -0
  212. package/dist/skeleton/skeleton.js +15 -0
  213. package/dist/slider/slider.d.ts +28 -0
  214. package/dist/slider/slider.js +30 -0
  215. package/dist/speed-dial/speed-dial.d.ts +20 -0
  216. package/dist/speed-dial/speed-dial.js +23 -0
  217. package/dist/spinner/spinner.d.ts +15 -0
  218. package/dist/spinner/spinner.js +14 -0
  219. package/dist/split-button/split-button.d.ts +28 -0
  220. package/dist/split-button/split-button.js +34 -0
  221. package/dist/splitter/splitter.d.ts +39 -0
  222. package/dist/splitter/splitter.js +80 -0
  223. package/dist/stepper/stepper.d.ts +51 -0
  224. package/dist/stepper/stepper.js +71 -0
  225. package/dist/switch/switch.d.ts +39 -0
  226. package/dist/switch/switch.js +30 -0
  227. package/dist/switch-group/switch-group.d.ts +29 -0
  228. package/dist/switch-group/switch-group.js +47 -0
  229. package/dist/tabs/tabs.d.ts +38 -0
  230. package/dist/tabs/tabs.js +74 -0
  231. package/dist/textarea/textarea.d.ts +28 -0
  232. package/dist/textarea/textarea.js +44 -0
  233. package/dist/timeline/timeline.d.ts +19 -0
  234. package/dist/timeline/timeline.js +12 -0
  235. package/dist/toast/toast-container.d.ts +12 -0
  236. package/dist/toast/toast-container.js +23 -0
  237. package/dist/toast/toast-store.d.ts +26 -0
  238. package/dist/toast/toast-store.js +51 -0
  239. package/dist/toolbar/toolbar.d.ts +29 -0
  240. package/dist/toolbar/toolbar.js +24 -0
  241. package/dist/tooltip/tooltip.d.ts +26 -0
  242. package/dist/tooltip/tooltip.js +113 -0
  243. package/dist/tree/tree.d.ts +31 -0
  244. package/dist/tree/tree.js +62 -0
  245. package/package.json +91 -0
@@ -0,0 +1,152 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { foregroundVarOf, formatDistance, formatLatLng, groupWeek, isAlwaysOpen, isOpenAt, nextChange, normalizeUrl, prettyUrl, } from '@konce-pt/map';
3
+ import { useId, useRef, useState } from 'react';
4
+ import { cn } from "../internal/cn.js";
5
+ import { useControllableState } from "../internal/use-controllable-state.js";
6
+ import { useKptMessages } from "../i18n/i18n-context.js";
7
+ import { KptButton } from "../button/button.js";
8
+ import { KptIcon } from "../icon/icon.js";
9
+ import { KptIconButton } from "../icon-button/icon-button.js";
10
+ /**
11
+ * Karta miejsca do popupu mapy — dystans, zdjęcie, akcje, kategoria, rozwijane godziny
12
+ * otwarcia i wiersze kontaktowe z kopiowaniem.
13
+ *
14
+ * Komponent jest sterowany danymi: bierze `KptMapPoi`, a nie model domenowy aplikacji.
15
+ * Mapowanie `KptMapLocation.data` → `KptMapPoi` robi aplikacja, dzięki czemu karta nie wie,
16
+ * czy pokazuje ładowarkę, restaurację, czy punkt serwisowy.
17
+ *
18
+ * Sam popup trzeba przełączyć na `popupLayout="card"` — inaczej karta dostanie szerokość
19
+ * i padding przeznaczone dla treści tekstowej.
20
+ *
21
+ * @example
22
+ * <KptMap popupLayout="card" renderPopup={({ location, data, distance, close }) => (
23
+ * <KptMapPoiCard poi={poiOf(location, data)} distance={distance} onClose={close} />
24
+ * )} />
25
+ */
26
+ export function KptMapPoiCard({ poi, distance = null, category = null, primaryLabel = '', showShare = true, showFavourite = true, favourite, defaultFavourite = false, onFavouriteChange, closable = true, hoursExpanded, defaultHoursExpanded = false, onHoursExpandedChange, onPrimaryAction, onClose, onShare, locale: localeOverride, dictionary, className, ...rest }) {
27
+ const { t, locale } = useKptMessages({ locale: localeOverride, dictionary });
28
+ /** Identyfikator regionu godzin; kart na stronie bywa więcej niż jedna. */
29
+ const hoursId = useId();
30
+ const [isFavourite, setFavourite] = useControllableState({
31
+ value: favourite,
32
+ defaultValue: defaultFavourite,
33
+ onChange: onFavouriteChange,
34
+ });
35
+ const [expanded, setExpanded] = useControllableState({
36
+ value: hoursExpanded,
37
+ defaultValue: defaultHoursExpanded,
38
+ onChange: onHoursExpandedChange,
39
+ });
40
+ /** Rośnie przy każdym rozwinięciu godzin — karta bywa otwarta dłużej niż minutę. */
41
+ const [now, setNow] = useState(() => Date.now());
42
+ /** Klucz wiersza, którego wartość właśnie skopiowano — przełącza ikonę na „check". */
43
+ const [justCopied, setJustCopied] = useState(null);
44
+ const copyTimer = useRef(null);
45
+ /** Bez API schowka przycisk kopiowania w ogóle się nie renderuje. */
46
+ const canCopy = typeof navigator !== 'undefined' && !!navigator.clipboard;
47
+ const canShare = typeof navigator !== 'undefined' && 'share' in navigator;
48
+ const hasHours = (poi.hours?.length ?? 0) > 0;
49
+ const alwaysOpen = isAlwaysOpen(poi.hours);
50
+ const open = isOpenAt(poi.hours, new Date(now));
51
+ const hoursGroups = groupWeek(poi.hours, locale);
52
+ const statusLabel = alwaysOpen ? t('map.poi.alwaysOpen') : t(open ? 'map.poi.openNow' : 'map.poi.closedNow');
53
+ /** Dopisek „otwarcie o 11:00" — nie ma go dla 24/7 ani gdy zmiana jest dalej niż doba. */
54
+ const statusHint = (() => {
55
+ if (alwaysOpen || !hasHours)
56
+ return null;
57
+ const at = new Date(now);
58
+ const change = nextChange(poi.hours, at);
59
+ if (!change)
60
+ return null;
61
+ if (change.at.getTime() - at.getTime() > 24 * 60 * 60 * 1000)
62
+ return null;
63
+ const time = new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(change.at);
64
+ return t(change.open ? 'map.poi.opensAt' : 'map.poi.closesAt', { time });
65
+ })();
66
+ const rows = [];
67
+ if (poi.phone) {
68
+ rows.push({
69
+ kind: 'phone',
70
+ icon: 'phone',
71
+ text: poi.phone,
72
+ copyValue: poi.phone,
73
+ href: `tel:${poi.phone.replace(/\s+/g, '')}`,
74
+ external: false,
75
+ actionIcon: 'phone',
76
+ actionLabel: t('map.poi.call'),
77
+ });
78
+ }
79
+ if (poi.website) {
80
+ const url = normalizeUrl(poi.website);
81
+ rows.push({
82
+ kind: 'website',
83
+ icon: 'world',
84
+ text: prettyUrl(poi.website),
85
+ copyValue: url,
86
+ href: url,
87
+ external: true,
88
+ actionIcon: 'external-link',
89
+ actionLabel: t('map.poi.openWebsite'),
90
+ });
91
+ }
92
+ if (poi.email) {
93
+ rows.push({
94
+ kind: 'email',
95
+ icon: 'mail',
96
+ text: poi.email,
97
+ copyValue: poi.email,
98
+ href: `mailto:${poi.email}`,
99
+ external: false,
100
+ actionIcon: 'mail',
101
+ actionLabel: t('map.poi.sendEmail'),
102
+ });
103
+ }
104
+ if (poi.at) {
105
+ const text = formatLatLng(poi.at);
106
+ rows.push({ kind: 'coords', icon: 'crosshair', text, copyValue: text, href: null, external: false, actionIcon: '', actionLabel: '' });
107
+ }
108
+ const copy = async (row) => {
109
+ try {
110
+ await navigator.clipboard.writeText(row.copyValue);
111
+ }
112
+ catch {
113
+ // Odmowa zgody albo brak bezpiecznego kontekstu — nie ma czego zgłaszać użytkownikowi.
114
+ return;
115
+ }
116
+ setJustCopied(row.kind);
117
+ if (copyTimer.current)
118
+ clearTimeout(copyTimer.current);
119
+ copyTimer.current = setTimeout(() => setJustCopied(null), 2000);
120
+ };
121
+ /**
122
+ * Udostępnianie: natywny arkusz systemowy, gdy przeglądarka go ma, inaczej schowek.
123
+ * W obu przypadkach leci `onShare`, więc aplikacja może dołożyć własną telemetrię.
124
+ */
125
+ const share = async () => {
126
+ const url = poi.website ? normalizeUrl(poi.website) : undefined;
127
+ if (canShare) {
128
+ try {
129
+ await navigator.share({ title: poi.title, text: poi.address, url });
130
+ }
131
+ catch {
132
+ // Anulowanie arkusza przez użytkownika nie jest błędem.
133
+ return;
134
+ }
135
+ }
136
+ else if (canCopy) {
137
+ try {
138
+ await navigator.clipboard.writeText(url ?? poi.title);
139
+ }
140
+ catch {
141
+ return;
142
+ }
143
+ }
144
+ onShare?.(poi);
145
+ };
146
+ const distanceLabel = formatDistance(distance, locale);
147
+ return (_jsxs("div", { className: cn('kpt-map-poi', className), ...rest, children: [_jsxs("header", { className: "kpt-map-poi__head", children: [_jsx("p", { className: "kpt-map-poi__title", role: "heading", "aria-level": 3, children: poi.title }), closable ? (_jsx(KptIconButton, { hostProps: { className: 'kpt-map-poi__close' }, variant: "text", size: "sm", "aria-label": t('common.close'), onClick: onClose, children: _jsx(KptIcon, { name: "x" }) })) : null] }), _jsxs("p", { className: "kpt-map-poi__meta", children: [distanceLabel ? _jsx("strong", { className: "kpt-map-poi__distance", children: distanceLabel }) : null, poi.address ? _jsx("span", { className: "kpt-map-poi__address", children: poi.address }) : null] }), _jsxs("div", { className: "kpt-map-poi__scroll", children: [_jsx("div", { className: "kpt-map-poi__media", children: poi.photo ? (_jsx("img", { className: "kpt-map-poi__photo", src: poi.photo, alt: poi.photoAlt ?? poi.title, loading: "lazy", decoding: "async" })) : (_jsx("div", { className: "kpt-map-poi__photo-empty", "aria-label": t('map.poi.noPhoto'), role: "img", children: _jsx(KptIcon, { name: "photo", size: "1.75rem" }) })) }), _jsxs("div", { className: "kpt-map-poi__actions", children: [primaryLabel ? (_jsx(KptButton, { hostProps: { className: 'kpt-map-poi__cta' }, size: "sm", fullWidth: true, onClick: () => onPrimaryAction?.(poi), children: primaryLabel })) : null, showShare ? (_jsx(KptIconButton, { variant: "outline", size: "sm", "aria-label": t('map.poi.share'), onClick: share, children: _jsx(KptIcon, { name: "share" }) })) : null, showFavourite ? (_jsx(KptIconButton, { hostProps: { className: 'kpt-map-poi__fav', 'data-on': isFavourite ? '' : undefined }, variant: "outline", size: "sm", "aria-pressed": isFavourite, "aria-label": t(isFavourite ? 'map.poi.removeFavourite' : 'map.poi.addFavourite'), onClick: () => setFavourite(!isFavourite), children: _jsx(KptIcon, { name: "star" }) })) : null] }), category ? (_jsxs("p", { className: "kpt-map-poi__category", style: { '--_kpt-poi-color': foregroundVarOf(category.color) }, children: [category.icon ? _jsx(KptIcon, { className: "kpt-map-poi__category-icon", name: category.icon }) : null, category.label] })) : null, hasHours ? (_jsxs("div", { className: "kpt-map-poi__hours", children: [_jsxs("button", { className: "kpt-map-poi__hours-toggle", type: "button", "aria-expanded": expanded, "aria-controls": hoursId, onClick: () => {
148
+ // Odświeżamy zegar przy rozwinięciu — karta bywa otwarta dłużej niż minutę.
149
+ setNow(Date.now());
150
+ setExpanded(!expanded);
151
+ }, children: [_jsx(KptIcon, { className: "kpt-map-poi__row-icon", name: "clock" }), _jsx("span", { className: "kpt-map-poi__status", "data-open": open || alwaysOpen, children: statusLabel }), statusHint ? _jsxs("span", { className: "kpt-map-poi__status-hint", children: ["\u00B7 ", statusHint] }) : null, _jsx(KptIcon, { className: "kpt-map-poi__chevron", name: "chevron-down" })] }), expanded ? (_jsx("dl", { className: "kpt-map-poi__week", id: hoursId, children: hoursGroups.map((group) => (_jsxs("div", { style: { display: 'contents' }, children: [_jsx("dt", { className: "kpt-map-poi__week-day", children: group.label }), _jsx("dd", { className: "kpt-map-poi__week-hours", children: group.closed ? (_jsx("span", { className: "kpt-map-poi__week-closed", children: t('map.poi.closedDay') })) : (group.ranges.map((range) => (_jsx("span", { className: "kpt-map-poi__week-range", children: range }, range)))) })] }, group.label))) })) : null] })) : null, rows.length || poi.facts?.length ? (_jsxs("ul", { className: "kpt-map-poi__rows", children: [rows.map((row) => (_jsxs("li", { className: "kpt-map-poi__row", children: [_jsx(KptIcon, { className: "kpt-map-poi__row-icon", name: row.icon }), row.href ? (_jsx("a", { className: "kpt-map-poi__row-value kpt-map-poi__row-link", href: row.href, target: row.external ? '_blank' : undefined, rel: row.external ? 'noopener' : undefined, children: row.text })) : (_jsx("span", { className: "kpt-map-poi__row-value", children: row.text })), _jsxs("span", { className: "kpt-map-poi__row-actions", children: [row.href ? (_jsx("a", { className: "kpt-map-poi__row-action", href: row.href, target: row.external ? '_blank' : undefined, rel: row.external ? 'noopener' : undefined, "aria-label": row.actionLabel, title: row.actionLabel, children: _jsx(KptIcon, { name: row.actionIcon }) })) : null, canCopy ? (_jsx("button", { className: "kpt-map-poi__row-action", type: "button", "aria-label": t('map.poi.copy'), title: t('map.poi.copy'), onClick: () => void copy(row), children: _jsx(KptIcon, { name: justCopied === row.kind ? 'check' : 'copy' }) })) : null] })] }, row.kind))), (poi.facts ?? []).map((fact) => (_jsxs("li", { className: "kpt-map-poi__row kpt-map-poi__row--fact", children: [fact.icon ? (_jsx(KptIcon, { className: "kpt-map-poi__row-icon", name: fact.icon })) : (_jsx("span", { className: "kpt-map-poi__row-icon", "aria-hidden": "true" })), _jsxs("span", { className: "kpt-map-poi__row-value", children: [_jsx("span", { className: "kpt-map-poi__fact-label", children: fact.label }), " ", fact.value] })] }, fact.label)))] })) : null, _jsx("p", { className: "kpt-map-poi__live", "aria-live": "polite", children: justCopied ? t('map.poi.copied') : '' })] })] }));
152
+ }
@@ -0,0 +1,37 @@
1
+ import type { KptMapBounds, KptMapSearchResult } from '@konce-pt/map';
2
+ import { type ComponentPropsWithRef } from 'react';
3
+ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
4
+ import type { KptMapGeocoderPort } from './ports.ts';
5
+ export interface KptMapSearchProps extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'>, KptI18nOverrides {
6
+ /** Geokoder tego pola. Bez metody `search()` pole renderuje się wyłączone. */
7
+ geocoder?: KptMapGeocoderPort | null;
8
+ /** Podpowiedź w pustym polu. Pusta oddaje głos słownikowi `map.search.placeholder`. */
9
+ placeholder?: string;
10
+ /** Od ilu znaków pytać geokoder. Krótsze frazy zwracają pół świata. */
11
+ minLength?: number;
12
+ /** Ile milisekund ciszy przed zapytaniem. */
13
+ debounce?: number;
14
+ /** Ile podpowiedzi najwyżej. */
15
+ limit?: number;
16
+ /** Zawężenie twarde do krajów (ISO 3166-1 alpha-2) — wyniki spoza nich nie wrócą. */
17
+ countryCodes?: readonly string[] | null;
18
+ /** Preferowany prostokąt wyników. Nie odcina reszty świata, tylko przesuwa ją niżej. */
19
+ viewbox?: KptMapBounds | null;
20
+ disabled?: boolean;
21
+ /** Wybrano miejsce — **zawsze ze współrzędnymi**. */
22
+ onSelect?: (result: KptMapSearchResult) => void;
23
+ /** Pole wyczyszczone — rodzic sprząta po sobie (np. chowa tymczasową pinezkę). */
24
+ onClear?: () => void;
25
+ }
26
+ /**
27
+ * Wyszukiwarka adresów: pole z podpowiedziami z geokodera. Wynik wyboru leci w `onSelect`,
28
+ * a co z nim zrobić — decyduje rodzic (`KptMap` przenosi na niego widok).
29
+ *
30
+ * Świadomie **nie** stoi na `KptAutocomplete`: tamten filtruje opcje po stronie klienta (wyniki
31
+ * geokodera, tolerancyjne na literówki, wypadałyby z listy), a jego wartością jest sam `string`
32
+ * — nie ma czym przewieźć współrzędnych.
33
+ *
34
+ * @example
35
+ * <KptMapSearch geocoder={geocoder} viewbox={bounds} onSelect={goTo} />
36
+ */
37
+ export declare function KptMapSearch({ geocoder, placeholder, minLength, debounce, limit, countryCodes, viewbox, disabled, onSelect, onClear, locale: localeOverride, dictionary, className, ...rest }: Readonly<KptMapSearchProps>): import("react").JSX.Element;
@@ -0,0 +1,201 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useId, useRef, useState } from 'react';
3
+ import { cn } from "../internal/cn.js";
4
+ import { useKptMessages } from "../i18n/i18n-context.js";
5
+ import { KptIcon } from "../icon/icon.js";
6
+ /**
7
+ * Wyszukiwarka adresów: pole z podpowiedziami z geokodera. Wynik wyboru leci w `onSelect`,
8
+ * a co z nim zrobić — decyduje rodzic (`KptMap` przenosi na niego widok).
9
+ *
10
+ * Świadomie **nie** stoi na `KptAutocomplete`: tamten filtruje opcje po stronie klienta (wyniki
11
+ * geokodera, tolerancyjne na literówki, wypadałyby z listy), a jego wartością jest sam `string`
12
+ * — nie ma czym przewieźć współrzędnych.
13
+ *
14
+ * @example
15
+ * <KptMapSearch geocoder={geocoder} viewbox={bounds} onSelect={goTo} />
16
+ */
17
+ export function KptMapSearch({ geocoder = null, placeholder = '', minLength = 3, debounce = 300, limit = 5, countryCodes = null, viewbox = null, disabled = false, onSelect, onClear, locale: localeOverride, dictionary, className, ...rest }) {
18
+ const { t, locale } = useKptMessages({ locale: localeOverride, dictionary });
19
+ const uid = useId();
20
+ /** Tekst widoczny w polu. Wybór podpowiedzi wpisuje tu jego etykietę. */
21
+ const [query, setQuery] = useState('');
22
+ /**
23
+ * Fraza do odpytania geokodera. Osobna od `query`, bo wybór podpowiedzi zmienia treść pola
24
+ * — a to nie może wywołać kolejnego zapytania o coś, co już znaleźliśmy.
25
+ */
26
+ const [term, setTerm] = useState('');
27
+ const [results, setResults] = useState([]);
28
+ const [loading, setLoading] = useState(false);
29
+ /** Trwa dociąganie współrzędnych wybranej podpowiedzi — inny moment niż czekanie na listę. */
30
+ const [resolving, setResolving] = useState(false);
31
+ /** Czy jakieś zapytanie już wróciło — bez tego „brak wyników" mignąłby przed pierwszym. */
32
+ const [searched, setSearched] = useState(false);
33
+ const [open, setOpen] = useState(false);
34
+ const [activeIndex, setActiveIndex] = useState(-1);
35
+ /** Nie udało się ustalić miejsca wybranej podpowiedzi — komunikat zamiast cichej ciszy. */
36
+ const [unresolved, setUnresolved] = useState(false);
37
+ /** Przerywacz dociągania w locie — kolejny wybór i czyszczenie pola go używają. */
38
+ const pending = useRef(null);
39
+ const canSearch = !!geocoder?.search;
40
+ const busy = loading || resolving;
41
+ const tooShort = query.trim().length > 0 && query.trim().length < minLength;
42
+ const hasPanel = open && (tooShort || busy || results.length > 0 || searched);
43
+ const applyResults = useCallback((found) => {
44
+ // Podpowiedź bez współrzędnych ma sens tylko wtedy, gdy port umie ją uzupełnić —
45
+ // pozycja, która nie ma dokąd polecieć, jest gorsza od jej braku.
46
+ setResults(geocoder?.resolve ? found : found.filter((suggestion) => suggestion.at));
47
+ setLoading(false);
48
+ setSearched(true);
49
+ setActiveIndex(-1);
50
+ setOpen(true);
51
+ }, [geocoder]);
52
+ // Odpytanie geokodera po odczekaniu `debounce` od ostatniego znaku. Sprzątanie kasuje
53
+ // zarówno niewystrzelony timer, jak i zapytanie w locie — adapter przerywa wtedy `fetch`.
54
+ useEffect(() => {
55
+ const needle = term.trim();
56
+ if (!geocoder?.search || needle.length < minLength) {
57
+ setResults([]);
58
+ setLoading(false);
59
+ setSearched(false);
60
+ setActiveIndex(-1);
61
+ return;
62
+ }
63
+ setLoading(true);
64
+ const controller = new AbortController();
65
+ const timer = setTimeout(() => {
66
+ geocoder
67
+ .search(needle, {
68
+ language: locale,
69
+ limit,
70
+ viewbox: viewbox ?? undefined,
71
+ countryCodes: countryCodes ?? undefined,
72
+ signal: controller.signal,
73
+ })
74
+ .then((found) => {
75
+ if (!controller.signal.aborted)
76
+ applyResults(found);
77
+ })
78
+ // Nieudane zapytanie to pusta lista, a nie wywrotka pola.
79
+ .catch(() => {
80
+ if (!controller.signal.aborted)
81
+ applyResults([]);
82
+ });
83
+ }, debounce);
84
+ return () => {
85
+ clearTimeout(timer);
86
+ controller.abort();
87
+ };
88
+ }, [term, geocoder, minLength, debounce, limit, viewbox, countryCodes, locale, applyResults]);
89
+ useEffect(() => () => pending.current?.abort(), []);
90
+ const status = (() => {
91
+ if (tooShort)
92
+ return t('map.search.minLength', { count: minLength });
93
+ if (busy)
94
+ return t('map.search.searching');
95
+ if (unresolved)
96
+ return t('map.search.noResults');
97
+ if (!searched)
98
+ return '';
99
+ return results.length === 0
100
+ ? t('map.search.noResults')
101
+ : t('map.search.found', { count: results.length });
102
+ })();
103
+ /**
104
+ * Wybór podpowiedzi. Dostawca, który podał współrzędne na liście, emituje natychmiast;
105
+ * podpowiedź bez `at` trzeba najpierw uzupełnić — jedno wywołanie `resolve()` na *wybór*,
106
+ * nigdy w trakcie pisania.
107
+ */
108
+ const pick = (suggestion) => {
109
+ // Etykieta wraca do pola, ale `term` zostaje — inaczej wybór odpaliłby kolejne zapytanie.
110
+ setQuery(suggestion.label);
111
+ setActiveIndex(-1);
112
+ setUnresolved(false);
113
+ pending.current?.abort();
114
+ pending.current = null;
115
+ if (suggestion.at) {
116
+ setOpen(false);
117
+ setResolving(false);
118
+ onSelect?.(suggestion);
119
+ return;
120
+ }
121
+ // Do listy trafiają tylko pozycje możliwe do obsłużenia, więc tu nie ma czego ratować.
122
+ if (!geocoder?.resolve)
123
+ return;
124
+ const controller = new AbortController();
125
+ pending.current = controller;
126
+ setResolving(true);
127
+ geocoder
128
+ .resolve(suggestion, { language: locale, signal: controller.signal })
129
+ .then((result) => applyResolved(result, controller))
130
+ // Nieudane dociągnięcie to komunikat, a nie wywrotka pola.
131
+ .catch(() => applyResolved(null, controller));
132
+ };
133
+ const applyResolved = (result, controller) => {
134
+ if (controller.signal.aborted)
135
+ return;
136
+ setResolving(false);
137
+ pending.current = null;
138
+ if (!result) {
139
+ // Etykieta zostaje w polu, żeby dało się poprawić frazę zamiast pisać ją od zera.
140
+ setUnresolved(true);
141
+ setOpen(true);
142
+ return;
143
+ }
144
+ setOpen(false);
145
+ onSelect?.(result);
146
+ };
147
+ const clear = () => {
148
+ pending.current?.abort();
149
+ pending.current = null;
150
+ setResolving(false);
151
+ setUnresolved(false);
152
+ setQuery('');
153
+ setTerm('');
154
+ setResults([]);
155
+ setSearched(false);
156
+ setActiveIndex(-1);
157
+ setOpen(false);
158
+ onClear?.();
159
+ };
160
+ const onKeyDown = (event) => {
161
+ switch (event.key) {
162
+ case 'ArrowDown':
163
+ event.preventDefault();
164
+ setOpen(true);
165
+ setActiveIndex((index) => Math.min(index + 1, results.length - 1));
166
+ break;
167
+ case 'ArrowUp':
168
+ event.preventDefault();
169
+ setActiveIndex((index) => Math.max(index - 1, 0));
170
+ break;
171
+ case 'Enter': {
172
+ const result = results[activeIndex];
173
+ if (result) {
174
+ // Pole bywa w formularzu aplikacji — Enter nie ma go wysyłać.
175
+ event.preventDefault();
176
+ pick(result);
177
+ }
178
+ break;
179
+ }
180
+ case 'Escape':
181
+ // Pierwszy Esc zamyka listę, drugi czyści pole — jak w polu wyszukiwania przeglądarki.
182
+ if (open)
183
+ setOpen(false);
184
+ else if (query)
185
+ clear();
186
+ break;
187
+ default:
188
+ break;
189
+ }
190
+ };
191
+ const optionId = (index) => `${uid}-opt-${index}`;
192
+ return (_jsxs("div", { className: cn('kpt-map-search', className), ...rest, children: [_jsxs("div", { className: "kpt-map-search__field", children: [_jsx("span", { className: "kpt-map-search__icon", "aria-hidden": "true", children: _jsx(KptIcon, { name: "search" }) }), _jsx("input", { className: "kpt-map-search__input", type: "text", autoComplete: "off", autoCapitalize: "off", spellCheck: false, role: "combobox", "aria-autocomplete": "list", id: uid, value: query, placeholder: placeholder || t('map.search.placeholder'), disabled: disabled || !canSearch, "aria-label": t('map.search.label'), "aria-expanded": hasPanel, "aria-busy": busy || undefined, "aria-controls": hasPanel ? `${uid}-panel` : undefined, "aria-activedescendant": activeIndex >= 0 ? optionId(activeIndex) : undefined, onChange: (event) => {
193
+ setQuery(event.target.value);
194
+ setTerm(event.target.value);
195
+ setOpen(true);
196
+ setUnresolved(false);
197
+ }, onFocus: () => setOpen(true), onBlur: () => setOpen(false), onKeyDown: onKeyDown }), query ? (_jsx("button", { className: "kpt-map-search__clear", type: "button", "aria-label": t('map.search.clear'), title: t('map.search.clear'), onClick: clear, children: _jsx(KptIcon, { name: "x" }) })) : null] }), hasPanel ? (_jsx("div", { className: "kpt-map-search__panel", id: `${uid}-panel`, children: tooShort ? (_jsx("p", { className: "kpt-map-search__note", children: t('map.search.minLength', { count: minLength }) })) : busy ? (_jsx("p", { className: "kpt-map-search__note", children: t('map.search.searching') })) : results.length ? (_jsx("ul", { className: "kpt-map-search__list", role: "listbox", "aria-label": t('map.search.results'), children: results.map((result, index) => (_jsxs("li", { className: cn('kpt-map-search__option', index === activeIndex && 'is-active'), role: "option", id: optionId(index), "aria-selected": index === activeIndex, onMouseDown: (event) => {
198
+ event.preventDefault();
199
+ pick(result);
200
+ }, onMouseEnter: () => setActiveIndex(index), children: [_jsx("span", { className: "kpt-map-search__pin", "aria-hidden": "true", children: _jsx(KptIcon, { name: "map-pin" }) }), _jsx("span", { className: "kpt-map-search__label", children: result.label })] }, result.id))) })) : (_jsx("p", { className: "kpt-map-search__note", children: t('map.search.noResults') })) })) : null, _jsx("p", { className: "kpt-map-search__status", "aria-live": "polite", children: status })] }));
201
+ }
@@ -0,0 +1,113 @@
1
+ import type { KptClusterOptions, KptLatLng, KptMapBounds, KptMapCategory, KptMapCluster, KptMapCreateEvent, KptMapEngineFactory, KptMapGeolocationError, KptMapLocation, KptMapSearchResult, KptMapUserPosition, KptMapView } from '@konce-pt/map';
2
+ import { type ComponentPropsWithRef, type ReactNode } from 'react';
3
+ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
4
+ import type { KptMapGeocoderPort, KptMapGeolocationPort } from './ports.ts';
5
+ /** Kontekst treści popupu — odpowiednik kontekstu szablonu `kptMapPopup` z portu Angulara. */
6
+ export interface KptMapPopupContext<T> {
7
+ location: KptMapLocation<T>;
8
+ data: T | undefined;
9
+ category: KptMapCategory | undefined;
10
+ /** Odległość od `distanceFrom` (albo od użytkownika) w metrach; `null` bez punktu odniesienia. */
11
+ distance: number | null;
12
+ close: () => void;
13
+ }
14
+ /** Kontekst własnego formularza „dodaj lokalizację". */
15
+ export interface KptMapCreateFormApi {
16
+ at: KptLatLng;
17
+ category: KptMapCategory;
18
+ close: () => void;
19
+ submit: (value: Record<string, unknown>) => void;
20
+ }
21
+ export interface KptMapProps<T = unknown> extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'onSelect'>, KptI18nOverrides {
22
+ locations: readonly KptMapLocation<T>[];
23
+ categories: readonly KptMapCategory[];
24
+ /** Kod kraju z presetów (`PL`, `DE`, `EU`…). Nieznany kod cofa się do Polski. */
25
+ country?: string;
26
+ /** Jawny widok startowy; nadpisuje `country`. */
27
+ view?: KptMapView | null;
28
+ /** Jawny zasięg startowy; nadpisuje `country` i `view`. */
29
+ bounds?: KptMapBounds | null;
30
+ /** Blokuje przesuwanie poza zasięg kraju (albo `bounds`, gdy podane). */
31
+ restrictToCountry?: boolean;
32
+ cluster?: boolean;
33
+ clusterOptions?: Partial<Omit<KptClusterOptions, 'zoom'>>;
34
+ /** `dominant` barwi grupę kolorem najliczniejszej kategorii. */
35
+ clusterColorBy?: 'dominant' | 'none';
36
+ /** Renderuje legendę pod mapą. */
37
+ legend?: boolean;
38
+ legendCounts?: boolean;
39
+ /** Identyfikatory ukrytych kategorii — kontrolowane albo niekontrolowane. */
40
+ hiddenCategories?: string[];
41
+ defaultHiddenCategories?: string[];
42
+ onHiddenCategoriesChange?: (hidden: string[]) => void;
43
+ showUserLocation?: boolean;
44
+ /** Przy każdej nowej pozycji centruje mapę na użytkowniku. */
45
+ followUser?: boolean;
46
+ /** Źródło pozycji użytkownika. Bez niego kontrolka „moje położenie" nie ma czego pokazać. */
47
+ geolocation?: KptMapGeolocationPort | null;
48
+ /** Włącza menu „Dodaj lokalizację" pod prawym przyciskiem myszy. */
49
+ allowCreate?: boolean;
50
+ /** Pokazuje wyszukiwarkę adresów. Wymaga geokodera **z metodą `search()`**. */
51
+ search?: boolean;
52
+ searchPlaceholder?: string;
53
+ searchOptions?: {
54
+ minLength?: number;
55
+ debounce?: number;
56
+ limit?: number;
57
+ countryCodes?: readonly string[];
58
+ };
59
+ /** Zoom dla wyniku bez własnego zasięgu (pojedynczy adres). */
60
+ searchZoom?: number;
61
+ /** Zostawia tymczasową pinezkę w znalezionym punkcie. */
62
+ searchMarker?: boolean;
63
+ /** Geokoder tej mapy — obsługuje i wyszukiwarkę, i podpowiedzi adresu w formularzu. */
64
+ geocoder?: KptMapGeocoderPort | null;
65
+ /** `card` oddaje popup w całości treści: bez paddingu, szerszy, z przewijaniem. */
66
+ popupLayout?: 'plain' | 'card';
67
+ /** Punkt odniesienia dystansu w popupie; `null` = pozycja użytkownika. */
68
+ distanceFrom?: KptLatLng | null;
69
+ height?: string;
70
+ /** Bez znaczenia dla silnika Google — kafle i atrybucję dostarcza tam Google. */
71
+ tileUrl?: string | null;
72
+ attribution?: string | null;
73
+ /**
74
+ * Fabryka silnika tej mapy. W Reakcie nie ma DI, więc to jedyna droga — i dobrze:
75
+ * dwie mapy o różnych silnikach mieszczą się na stronie bez żadnych opakowań.
76
+ * Czytana raz, przy inicjalizacji.
77
+ */
78
+ engine: KptMapEngineFactory;
79
+ /** Treść popupu. Bez niej popup pokazuje tytuł i nazwę kategorii. */
80
+ renderPopup?: (context: KptMapPopupContext<T>) => ReactNode;
81
+ /** Własny formularz „dodaj lokalizację"; jego obecność wyłącza formularz ze schemy. */
82
+ renderCreateForm?: (api: KptMapCreateFormApi) => ReactNode;
83
+ onLocationClick?: (location: KptMapLocation<T>) => void;
84
+ onClusterClick?: (cluster: KptMapCluster<T>) => void;
85
+ /** Komponent **nie dopisuje** nic do `locations` — źródłem prawdy jest aplikacja. */
86
+ onLocationCreate?: (event: KptMapCreateEvent) => void;
87
+ /** Wybrano podpowiedź wyszukiwarki; mapa już przeniosła widok. */
88
+ onSearchSelect?: (result: KptMapSearchResult) => void;
89
+ onViewChange?: (view: {
90
+ center: KptLatLng;
91
+ zoom: number;
92
+ bounds: KptMapBounds;
93
+ }) => void;
94
+ onUserPositionChange?: (position: KptMapUserPosition | null) => void;
95
+ onUserLocationError?: (error: KptMapGeolocationError) => void;
96
+ }
97
+ /**
98
+ * Mapa z konfigurowalnymi znacznikami: kategorie z kolorem i ikoną, grupowanie z licznikiem,
99
+ * popup szczegółów, legenda, wyszukiwarka adresów i dodawanie lokalizacji prawym przyciskiem.
100
+ *
101
+ * Silnik (Leaflet albo Google) przychodzi propem `engine` z `@konce-pt/map` — ta sama warstwa,
102
+ * na której stoi port Angulara. Leaflet ładuje się dynamicznym `import()`, więc aplikacja bez
103
+ * mapy go nie pobiera; wymaga też arkusza `leaflet/dist/leaflet.css`.
104
+ *
105
+ * @example
106
+ * <KptMap
107
+ * engine={() => createLeafletEngine()}
108
+ * locations={locations}
109
+ * categories={categories}
110
+ * renderPopup={({ location, data }) => <strong>{location.title}</strong>}
111
+ * />
112
+ */
113
+ export declare function KptMap<T = unknown>({ locations, categories, country, view, bounds, restrictToCountry, cluster, clusterOptions, clusterColorBy, legend, legendCounts, hiddenCategories, defaultHiddenCategories, onHiddenCategoriesChange, showUserLocation, followUser, geolocation, allowCreate, search, searchPlaceholder, searchOptions, searchZoom, searchMarker, geocoder, popupLayout, distanceFrom, height, tileUrl, attribution, engine, renderPopup, renderCreateForm, onLocationClick, onClusterClick, onLocationCreate, onSearchSelect, onViewChange, onUserPositionChange, onUserLocationError, locale: localeOverride, dictionary, className, style, ...rest }: Readonly<KptMapProps<T>>): import("react").JSX.Element;