@krizaka/ui 3.3.0 → 3.4.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 (352) hide show
  1. package/dist/activity-feed.d.ts +199 -0
  2. package/dist/activity-feed.js +155 -0
  3. package/dist/activity-feed.js.map +1 -0
  4. package/dist/argument-card.js +3 -3
  5. package/dist/chunk-7Z4KHPFC.js +42 -0
  6. package/dist/chunk-7Z4KHPFC.js.map +1 -0
  7. package/dist/data-table.js +98 -131
  8. package/dist/data-table.js.map +1 -1
  9. package/dist/description-list.d.ts +105 -0
  10. package/dist/description-list.js +49 -0
  11. package/dist/description-list.js.map +1 -0
  12. package/dist/index.js +13 -66
  13. package/dist/index.js.map +1 -1
  14. package/dist/kanban.d.ts +132 -0
  15. package/dist/kanban.js +187 -0
  16. package/dist/kanban.js.map +1 -0
  17. package/dist/list.d.ts +153 -0
  18. package/dist/list.js +130 -0
  19. package/dist/list.js.map +1 -0
  20. package/dist/map.d.ts +463 -0
  21. package/dist/map.js +952 -0
  22. package/dist/map.js.map +1 -0
  23. package/dist/motion.css +12 -1
  24. package/dist/native/map.d.ts +200 -0
  25. package/dist/native/map.js +673 -0
  26. package/dist/native/map.js.map +1 -0
  27. package/dist/native/media-picker.d.ts +58 -0
  28. package/dist/native/media-picker.js +63 -0
  29. package/dist/native/media-picker.js.map +1 -0
  30. package/dist/native.d.ts +568 -6
  31. package/dist/native.js +1989 -868
  32. package/dist/native.js.map +1 -1
  33. package/dist/page-hero.js +3 -3
  34. package/dist/stat.d.ts +31 -2
  35. package/dist/stat.js +21 -4
  36. package/dist/stat.js.map +1 -1
  37. package/dist/tree-view.d.ts +111 -0
  38. package/dist/tree-view.js +154 -0
  39. package/dist/tree-view.js.map +1 -0
  40. package/package.json +147 -10
  41. package/registry/achievement.json +1 -1
  42. package/registry/action-bar.json +1 -1
  43. package/registry/action-sheet.json +121 -0
  44. package/registry/activity-feed.json +468 -0
  45. package/registry/alert.json +1 -1
  46. package/registry/app-shell.json +1 -1
  47. package/registry/argument-card.json +1 -1
  48. package/registry/audio-player.json +1 -1
  49. package/registry/auth-layout.json +1 -1
  50. package/registry/avatar.json +58 -3
  51. package/registry/badge.json +1 -1
  52. package/registry/button.json +1 -1
  53. package/registry/card-grid.json +1 -1
  54. package/registry/card.json +1 -1
  55. package/registry/catalogue-page.json +1 -1
  56. package/registry/changelog-page.json +1 -1
  57. package/registry/checkbox.json +1 -1
  58. package/registry/chip-link.json +1 -1
  59. package/registry/chip.json +1 -1
  60. package/registry/choice-grid.json +1 -1
  61. package/registry/code-block.json +1 -1
  62. package/registry/combobox.json +1 -1
  63. package/registry/command.json +1 -1
  64. package/registry/component-page.json +1 -1
  65. package/registry/confirm-button.json +1 -1
  66. package/registry/contact-page.json +1 -1
  67. package/registry/continue-prompt.json +1 -1
  68. package/registry/countdown.json +1 -1
  69. package/registry/cta-panel.json +1 -1
  70. package/registry/dashboard-layout.json +1 -1
  71. package/registry/data-table.json +1 -1
  72. package/registry/date-picker.json +2 -2
  73. package/registry/decision-list.json +1 -1
  74. package/registry/description-list.json +232 -0
  75. package/registry/detail-layout.json +1 -1
  76. package/registry/dialog.json +1 -1
  77. package/registry/docs-article-page.json +1 -1
  78. package/registry/docs-hub-page.json +1 -1
  79. package/registry/docs-layout.json +1 -1
  80. package/registry/dropdown-menu.json +1 -1
  81. package/registry/empty-state.json +1 -1
  82. package/registry/error-page.json +1 -1
  83. package/registry/examples/action-sheet/native/video-actions.d.ts +4 -0
  84. package/registry/examples/action-sheet/native/video-actions.dark.png +0 -0
  85. package/registry/examples/action-sheet/native/video-actions.js +30 -0
  86. package/registry/examples/action-sheet/native/video-actions.light.png +0 -0
  87. package/registry/examples/action-sheet/native/video-actions.tsx +24 -0
  88. package/registry/examples/activity-feed/job-activity.d.ts +4 -0
  89. package/registry/examples/activity-feed/job-activity.js +21 -0
  90. package/registry/examples/activity-feed/job-activity.tsx +17 -0
  91. package/registry/examples/activity-feed/live.d.ts +4 -0
  92. package/registry/examples/activity-feed/live.js +23 -0
  93. package/registry/examples/activity-feed/live.tsx +24 -0
  94. package/registry/examples/activity-feed/native/notifications.d.ts +4 -0
  95. package/registry/examples/activity-feed/native/notifications.dark.png +0 -0
  96. package/registry/examples/activity-feed/native/notifications.js +18 -0
  97. package/registry/examples/activity-feed/native/notifications.light.png +0 -0
  98. package/registry/examples/activity-feed/native/notifications.tsx +18 -0
  99. package/registry/examples/activity-feed/timeline.d.ts +4 -0
  100. package/registry/examples/activity-feed/timeline.js +25 -0
  101. package/registry/examples/activity-feed/timeline.tsx +19 -0
  102. package/registry/examples/avatar/native/presence.d.ts +4 -0
  103. package/registry/examples/avatar/native/presence.dark.png +0 -0
  104. package/registry/examples/avatar/native/presence.js +18 -0
  105. package/registry/examples/avatar/native/presence.light.png +0 -0
  106. package/registry/examples/avatar/native/presence.tsx +15 -0
  107. package/registry/examples/description-list/job-details.d.ts +4 -0
  108. package/registry/examples/description-list/job-details.js +23 -0
  109. package/registry/examples/description-list/job-details.tsx +17 -0
  110. package/registry/examples/description-list/key-value-grid.d.ts +4 -0
  111. package/registry/examples/description-list/key-value-grid.js +22 -0
  112. package/registry/examples/description-list/key-value-grid.tsx +16 -0
  113. package/registry/examples/description-list/native/job-details.d.ts +4 -0
  114. package/registry/examples/description-list/native/job-details.dark.png +0 -0
  115. package/registry/examples/description-list/native/job-details.js +33 -0
  116. package/registry/examples/description-list/native/job-details.light.png +0 -0
  117. package/registry/examples/description-list/native/job-details.tsx +24 -0
  118. package/registry/examples/description-list/receipt.d.ts +4 -0
  119. package/registry/examples/description-list/receipt.js +23 -0
  120. package/registry/examples/description-list/receipt.tsx +17 -0
  121. package/registry/examples/fab/native/extended.d.ts +4 -0
  122. package/registry/examples/fab/native/extended.dark.png +0 -0
  123. package/registry/examples/fab/native/extended.js +18 -0
  124. package/registry/examples/fab/native/extended.light.png +0 -0
  125. package/registry/examples/fab/native/extended.tsx +23 -0
  126. package/registry/examples/header/native/large-title.d.ts +4 -0
  127. package/registry/examples/header/native/large-title.dark.png +0 -0
  128. package/registry/examples/header/native/large-title.js +23 -0
  129. package/registry/examples/header/native/large-title.light.png +0 -0
  130. package/registry/examples/header/native/large-title.tsx +31 -0
  131. package/registry/examples/image-viewer/native/gallery.d.ts +4 -0
  132. package/registry/examples/image-viewer/native/gallery.dark.png +0 -0
  133. package/registry/examples/image-viewer/native/gallery.js +22 -0
  134. package/registry/examples/image-viewer/native/gallery.light.png +0 -0
  135. package/registry/examples/image-viewer/native/gallery.tsx +21 -0
  136. package/registry/examples/kanban/moderation.d.ts +4 -0
  137. package/registry/examples/kanban/moderation.js +35 -0
  138. package/registry/examples/kanban/moderation.tsx +37 -0
  139. package/registry/examples/list/jobs.d.ts +4 -0
  140. package/registry/examples/list/jobs.js +35 -0
  141. package/registry/examples/list/jobs.tsx +33 -0
  142. package/registry/examples/list/selectable.d.ts +4 -0
  143. package/registry/examples/list/selectable.js +33 -0
  144. package/registry/examples/list/selectable.tsx +30 -0
  145. package/registry/examples/list/virtualized.d.ts +4 -0
  146. package/registry/examples/list/virtualized.js +22 -0
  147. package/registry/examples/list/virtualized.tsx +17 -0
  148. package/registry/examples/loader/native/block.d.ts +4 -0
  149. package/registry/examples/loader/native/block.dark.png +0 -0
  150. package/registry/examples/loader/native/block.js +12 -0
  151. package/registry/examples/loader/native/block.light.png +0 -0
  152. package/registry/examples/loader/native/block.tsx +11 -0
  153. package/registry/examples/loader/native/job-wait.d.ts +4 -0
  154. package/registry/examples/loader/native/job-wait.dark.png +0 -0
  155. package/registry/examples/loader/native/job-wait.js +17 -0
  156. package/registry/examples/loader/native/job-wait.light.png +0 -0
  157. package/registry/examples/loader/native/job-wait.tsx +14 -0
  158. package/registry/examples/map/cluster.d.ts +4 -0
  159. package/registry/examples/map/cluster.js +16 -0
  160. package/registry/examples/map/cluster.tsx +18 -0
  161. package/registry/examples/map/location-picker.d.ts +4 -0
  162. package/registry/examples/map/location-picker.js +24 -0
  163. package/registry/examples/map/location-picker.tsx +22 -0
  164. package/registry/examples/map/native/location-picker.d.ts +4 -0
  165. package/registry/examples/map/native/location-picker.dark.png +0 -0
  166. package/registry/examples/map/native/location-picker.js +14 -0
  167. package/registry/examples/map/native/location-picker.light.png +0 -0
  168. package/registry/examples/map/native/location-picker.tsx +13 -0
  169. package/registry/examples/map/native/places.d.ts +4 -0
  170. package/registry/examples/map/native/places.dark.png +0 -0
  171. package/registry/examples/map/native/places.js +25 -0
  172. package/registry/examples/map/native/places.light.png +0 -0
  173. package/registry/examples/map/native/places.tsx +27 -0
  174. package/registry/examples/map/places.d.ts +4 -0
  175. package/registry/examples/map/places.js +28 -0
  176. package/registry/examples/map/places.tsx +28 -0
  177. package/registry/examples/map/static.d.ts +4 -0
  178. package/registry/examples/map/static.js +22 -0
  179. package/registry/examples/map/static.tsx +18 -0
  180. package/registry/examples/media-picker/native/story.d.ts +4 -0
  181. package/registry/examples/media-picker/native/story.dark.png +0 -0
  182. package/registry/examples/media-picker/native/story.js +30 -0
  183. package/registry/examples/media-picker/native/story.light.png +0 -0
  184. package/registry/examples/media-picker/native/story.tsx +26 -0
  185. package/registry/examples/meter/native/credits.d.ts +4 -0
  186. package/registry/examples/meter/native/credits.dark.png +0 -0
  187. package/registry/examples/meter/native/credits.js +15 -0
  188. package/registry/examples/meter/native/credits.light.png +0 -0
  189. package/registry/examples/meter/native/credits.tsx +12 -0
  190. package/registry/examples/meter/native/split-ring.d.ts +4 -0
  191. package/registry/examples/meter/native/split-ring.dark.png +0 -0
  192. package/registry/examples/meter/native/split-ring.js +24 -0
  193. package/registry/examples/meter/native/split-ring.light.png +0 -0
  194. package/registry/examples/meter/native/split-ring.tsx +19 -0
  195. package/registry/examples/number-ticker/native/balance.d.ts +4 -0
  196. package/registry/examples/number-ticker/native/balance.dark.png +0 -0
  197. package/registry/examples/number-ticker/native/balance.js +18 -0
  198. package/registry/examples/number-ticker/native/balance.light.png +0 -0
  199. package/registry/examples/number-ticker/native/balance.tsx +17 -0
  200. package/registry/examples/onboarding/native/first-launch.d.ts +4 -0
  201. package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
  202. package/registry/examples/onboarding/native/first-launch.js +23 -0
  203. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  204. package/registry/examples/onboarding/native/first-launch.tsx +19 -0
  205. package/registry/examples/otp-input/native/invalid.d.ts +4 -0
  206. package/registry/examples/otp-input/native/invalid.dark.png +0 -0
  207. package/registry/examples/otp-input/native/invalid.js +15 -0
  208. package/registry/examples/otp-input/native/invalid.light.png +0 -0
  209. package/registry/examples/otp-input/native/invalid.tsx +14 -0
  210. package/registry/examples/otp-input/native/verify.d.ts +4 -0
  211. package/registry/examples/otp-input/native/verify.dark.png +0 -0
  212. package/registry/examples/otp-input/native/verify.js +17 -0
  213. package/registry/examples/otp-input/native/verify.light.png +0 -0
  214. package/registry/examples/otp-input/native/verify.tsx +14 -0
  215. package/registry/examples/permission-prompt/native/blocked.d.ts +4 -0
  216. package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
  217. package/registry/examples/permission-prompt/native/blocked.js +25 -0
  218. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  219. package/registry/examples/permission-prompt/native/blocked.tsx +21 -0
  220. package/registry/examples/permission-prompt/native/camera.d.ts +4 -0
  221. package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
  222. package/registry/examples/permission-prompt/native/camera.js +25 -0
  223. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  224. package/registry/examples/permission-prompt/native/camera.tsx +21 -0
  225. package/registry/examples/pull-to-refresh/native/feed.d.ts +4 -0
  226. package/registry/examples/pull-to-refresh/native/feed.dark.png +0 -0
  227. package/registry/examples/pull-to-refresh/native/feed.js +14 -0
  228. package/registry/examples/pull-to-refresh/native/feed.light.png +0 -0
  229. package/registry/examples/pull-to-refresh/native/feed.tsx +19 -0
  230. package/registry/examples/search-field/native/cancel.d.ts +4 -0
  231. package/registry/examples/search-field/native/cancel.dark.png +0 -0
  232. package/registry/examples/search-field/native/cancel.js +14 -0
  233. package/registry/examples/search-field/native/cancel.light.png +0 -0
  234. package/registry/examples/search-field/native/cancel.tsx +13 -0
  235. package/registry/examples/stat/grid.d.ts +4 -0
  236. package/registry/examples/stat/grid.js +17 -0
  237. package/registry/examples/stat/grid.tsx +14 -0
  238. package/registry/examples/stepper/native/run.d.ts +4 -0
  239. package/registry/examples/stepper/native/run.dark.png +0 -0
  240. package/registry/examples/stepper/native/run.js +24 -0
  241. package/registry/examples/stepper/native/run.light.png +0 -0
  242. package/registry/examples/stepper/native/run.tsx +20 -0
  243. package/registry/examples/swipeable-row/native/conversation.d.ts +4 -0
  244. package/registry/examples/swipeable-row/native/conversation.dark.png +0 -0
  245. package/registry/examples/swipeable-row/native/conversation.js +30 -0
  246. package/registry/examples/swipeable-row/native/conversation.light.png +0 -0
  247. package/registry/examples/swipeable-row/native/conversation.tsx +27 -0
  248. package/registry/examples/tab-bar/native/main-sections.d.ts +4 -0
  249. package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
  250. package/registry/examples/tab-bar/native/main-sections.js +29 -0
  251. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  252. package/registry/examples/tab-bar/native/main-sections.tsx +30 -0
  253. package/registry/examples/tabs/native/sections.d.ts +4 -0
  254. package/registry/examples/tabs/native/sections.dark.png +0 -0
  255. package/registry/examples/tabs/native/sections.js +23 -0
  256. package/registry/examples/tabs/native/sections.light.png +0 -0
  257. package/registry/examples/tabs/native/sections.tsx +19 -0
  258. package/registry/examples/tabs/native/segmented.d.ts +4 -0
  259. package/registry/examples/tabs/native/segmented.dark.png +0 -0
  260. package/registry/examples/tabs/native/segmented.js +22 -0
  261. package/registry/examples/tabs/native/segmented.light.png +0 -0
  262. package/registry/examples/tabs/native/segmented.tsx +18 -0
  263. package/registry/examples/toast/native/snackbar.d.ts +4 -0
  264. package/registry/examples/toast/native/snackbar.dark.png +0 -0
  265. package/registry/examples/toast/native/snackbar.js +23 -0
  266. package/registry/examples/toast/native/snackbar.light.png +0 -0
  267. package/registry/examples/toast/native/snackbar.tsx +21 -0
  268. package/registry/examples/tree-view/docs.d.ts +4 -0
  269. package/registry/examples/tree-view/docs.js +24 -0
  270. package/registry/examples/tree-view/docs.tsx +22 -0
  271. package/registry/examples/tree-view/lazy.d.ts +4 -0
  272. package/registry/examples/tree-view/lazy.js +21 -0
  273. package/registry/examples/tree-view/lazy.tsx +19 -0
  274. package/registry/fab.json +122 -0
  275. package/registry/field.json +1 -1
  276. package/registry/file-upload.json +2 -2
  277. package/registry/filter-bar.json +1 -1
  278. package/registry/form.json +2 -2
  279. package/registry/gallery-page.json +1 -1
  280. package/registry/glow-card.json +1 -1
  281. package/registry/goal-gauge.json +1 -1
  282. package/registry/header.json +137 -0
  283. package/registry/how-it-works-page.json +1 -1
  284. package/registry/image-cropper.json +1 -1
  285. package/registry/image-viewer.json +107 -0
  286. package/registry/index.json +299 -25
  287. package/registry/iso.json +1 -1
  288. package/registry/kanban.json +253 -0
  289. package/registry/kbd.json +1 -1
  290. package/registry/landing-page.json +1 -1
  291. package/registry/landscape.json +1 -1
  292. package/registry/legal-page.json +1 -1
  293. package/registry/link-card.json +1 -1
  294. package/registry/list.json +367 -30
  295. package/registry/loader.json +157 -4
  296. package/registry/longform-page.json +1 -1
  297. package/registry/map.json +1368 -0
  298. package/registry/marketing-layout.json +1 -1
  299. package/registry/marquee.json +1 -1
  300. package/registry/mascot-quote.json +1 -1
  301. package/registry/mascot-state.json +1 -1
  302. package/registry/mascots.json +1 -1
  303. package/registry/media-capture.json +1 -1
  304. package/registry/media-picker.json +129 -0
  305. package/registry/meter.json +136 -4
  306. package/registry/nav-bar.json +1 -1
  307. package/registry/number-ticker.json +96 -4
  308. package/registry/onboarding.json +95 -0
  309. package/registry/otp-input.json +150 -0
  310. package/registry/page-header.json +1 -1
  311. package/registry/page-hero.json +1 -1
  312. package/registry/page.json +1 -1
  313. package/registry/pagination.json +1 -1
  314. package/registry/permission-prompt.json +172 -0
  315. package/registry/pointer-light.json +1 -1
  316. package/registry/popover.json +1 -1
  317. package/registry/pricing-page.json +1 -1
  318. package/registry/product-page.json +1 -1
  319. package/registry/profile-card.json +1 -1
  320. package/registry/progress.json +2 -2
  321. package/registry/promise-card.json +1 -1
  322. package/registry/pull-to-refresh.json +74 -0
  323. package/registry/radio-group.json +1 -1
  324. package/registry/scroll-stage.json +1 -1
  325. package/registry/search-field.json +30 -3
  326. package/registry/section-backdrop.json +1 -1
  327. package/registry/separator.json +1 -1
  328. package/registry/settings-layout.json +1 -1
  329. package/registry/skeleton.json +1 -1
  330. package/registry/slider.json +1 -1
  331. package/registry/slot.json +1 -1
  332. package/registry/spinner.json +1 -1
  333. package/registry/split-view.json +1 -1
  334. package/registry/stage-banner.json +1 -1
  335. package/registry/stat.json +68 -5
  336. package/registry/status-page.json +1 -1
  337. package/registry/stepper.json +75 -4
  338. package/registry/swipeable-row.json +124 -0
  339. package/registry/switch.json +1 -1
  340. package/registry/tab-bar.json +115 -0
  341. package/registry/tabs.json +94 -4
  342. package/registry/tag-input.json +1 -1
  343. package/registry/terminal-replay.json +1 -1
  344. package/registry/theme.json +8 -1
  345. package/registry/toast.json +17 -3
  346. package/registry/toc.json +1 -1
  347. package/registry/tooltip.json +1 -1
  348. package/registry/tree-view.json +291 -0
  349. package/registry/video-player.json +1 -1
  350. package/registry/video-trimmer.json +1 -1
  351. package/registry/virtual.json +1 -1
  352. package/skills/map/SKILL.md +35 -0
package/dist/map.js ADDED
@@ -0,0 +1,952 @@
1
+ "use client";
2
+
3
+ // src/map/assets.ts
4
+ var CDN = "https://krizaka-assets.b-cdn.net/maps/v1";
5
+ var MAP_TILES = {
6
+ world: `${CDN}/tiles/world-20261012.pmtiles`,
7
+ quebec: `${CDN}/tiles/quebec-20261012.pmtiles`
8
+ };
9
+ var MAP_GLYPHS = `${CDN}/fonts/{fontstack}/{range}.pbf`;
10
+ var MAP_ATTRIBUTION = { osm: "\xA9 OpenStreetMap contributors", osmUrl: "https://www.openstreetmap.org/copyright", protomaps: "Protomaps", protomapsUrl: "https://protomaps.com" };
11
+ var base = null;
12
+ function setMapAssetsBase(url) {
13
+ base = url ? url.replace(/\/+$/, "") : null;
14
+ }
15
+ function mapAssets() {
16
+ const at = (u) => base ? u.replace(CDN, base) : u;
17
+ return { tiles: { world: at(MAP_TILES.world), quebec: at(MAP_TILES.quebec) }, glyphs: at(MAP_GLYPHS) };
18
+ }
19
+
20
+ // src/map/geo.ts
21
+ var R = 63710088e-1;
22
+ var rad = (d) => d * Math.PI / 180;
23
+ function distanceMeters(a, b) {
24
+ const dLat = rad(b[1] - a[1]);
25
+ const dLng = rad(b[0] - a[0]);
26
+ const h = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a[1])) * Math.cos(rad(b[1])) * Math.sin(dLng / 2) ** 2;
27
+ return 2 * R * Math.asin(Math.min(1, Math.sqrt(h)));
28
+ }
29
+ function circlePolygon(center, radius, steps = 64) {
30
+ const [lng, lat] = center;
31
+ const d = radius / R;
32
+ const ring = [];
33
+ for (let i = 0; i <= steps; i++) {
34
+ const brg = 2 * Math.PI * i / steps;
35
+ const lat2 = Math.asin(Math.sin(rad(lat)) * Math.cos(d) + Math.cos(rad(lat)) * Math.sin(d) * Math.cos(brg));
36
+ const lng2 = rad(lng) + Math.atan2(Math.sin(brg) * Math.sin(d) * Math.cos(rad(lat)), Math.cos(d) - Math.sin(rad(lat)) * Math.sin(lat2));
37
+ ring.push([lng2 * 180 / Math.PI, lat2 * 180 / Math.PI]);
38
+ }
39
+ return { type: "Feature", properties: {}, geometry: { type: "Polygon", coordinates: [ring] } };
40
+ }
41
+ function project([lng, lat], zoom) {
42
+ const scale = 256 * 2 ** zoom;
43
+ const s = Math.sin(rad(Math.max(-85.0511, Math.min(85.0511, lat))));
44
+ return [(lng + 180) / 360 * scale, (0.5 - Math.log((1 + s) / (1 - s)) / (4 * Math.PI)) * scale];
45
+ }
46
+ function formatDistance(meters, locale) {
47
+ if (meters < 1e3) return new Intl.NumberFormat(locale, { style: "unit", unit: "meter", maximumFractionDigits: 0 }).format(Math.round(meters / 10) * 10);
48
+ return new Intl.NumberFormat(locale, { style: "unit", unit: "kilometer", maximumFractionDigits: meters < 1e4 ? 1 : 0 }).format(meters / 1e3);
49
+ }
50
+
51
+ // src/map/location-picker.tsx
52
+ import * as React3 from "react";
53
+
54
+ // src/tv.ts
55
+ import { createTV } from "tailwind-variants";
56
+
57
+ // src/cn.ts
58
+ import { clsx } from "clsx";
59
+ import { cnMerge } from "tailwind-variants";
60
+ var twMergeConfig = {
61
+ extend: {
62
+ classGroups: {
63
+ "bg-image": ["bg-sheen", "bg-fill-shade", "bg-halo"],
64
+ shadow: ["shadow-raised", "shadow-floating", "shadow-overlay", "shadow-glow", "shadow-glow-lg"],
65
+ "inset-shadow": ["inset-shadow-edge", "inset-shadow-edge-fill", "inset-shadow-well"]
66
+ }
67
+ }
68
+ };
69
+
70
+ // src/tv.ts
71
+ var tv = createTV({ twMergeConfig });
72
+
73
+ // src/map/map.tsx
74
+ import * as React2 from "react";
75
+ import { createPortal } from "react-dom";
76
+
77
+ // src/media.ts
78
+ import * as React from "react";
79
+ var REDUCE = "(prefers-reduced-motion: reduce)";
80
+ var subscribeReduce = (notify) => {
81
+ if (typeof window === "undefined" || !window.matchMedia) return () => void 0;
82
+ const query = window.matchMedia(REDUCE);
83
+ query.addEventListener?.("change", notify);
84
+ return () => query.removeEventListener?.("change", notify);
85
+ };
86
+ function usePrefersReducedMotion() {
87
+ return React.useSyncExternalStore(
88
+ subscribeReduce,
89
+ () => typeof window !== "undefined" && window.matchMedia ? window.matchMedia(REDUCE).matches : false,
90
+ () => false
91
+ );
92
+ }
93
+
94
+ // ../tokens/dist/native.js
95
+ var themes = /* @__PURE__ */ Object.freeze({ dark: /* @__PURE__ */ Object.freeze({
96
+ "surface0": "#0c0c0e",
97
+ "surface1": "#161618",
98
+ "surface2": "#1f1f23",
99
+ "surface3": "#2a2a2d",
100
+ "media": "#1b1b1d",
101
+ "borderSubtle": "rgba(255,255,255,0.06)",
102
+ "borderDefault": "rgba(255,255,255,0.1)",
103
+ "borderStrong": "rgba(255,255,255,0.16)",
104
+ "textPrimary": "#f5f5f5",
105
+ "textSecondary": "#a0a0a7",
106
+ "textMuted": "#73737d",
107
+ "textOnMedia": "#ffffff",
108
+ "accent": "#196df5",
109
+ "accentHover": "#0e5bd8",
110
+ "accentSoft": "rgba(25,109,245,0.1)",
111
+ "accentText": "#629cf8",
112
+ "accent2": "#196df5",
113
+ "onAccent": "#ffffff",
114
+ "ring": "#196df5",
115
+ "brandGradientFrom": "#0e1525",
116
+ "brandGradientVia": "#0e0f16",
117
+ "brandGradientTo": "#0c0c0e",
118
+ "success": "#10b77f",
119
+ "successText": "#36d399",
120
+ "successSoft": "rgba(16,183,127,0.14)",
121
+ "warning": "#f59f0a",
122
+ "warningText": "#f6a823",
123
+ "warningSoft": "rgba(245,159,10,0.14)",
124
+ "danger": "#ef4343",
125
+ "dangerText": "#f87272",
126
+ "dangerSoft": "rgba(239,67,67,0.14)",
127
+ "info": "#196df5",
128
+ "infoText": "#629cf8",
129
+ "scrim": "rgba(0,0,0,0.6)",
130
+ "scrimStrong": "rgba(0,0,0,0.8)",
131
+ "overlay": "rgba(0,0,0,0.7)",
132
+ "surfaceSheen": "rgba(255,255,255,0.045)",
133
+ "fillShade": "rgba(0,0,0,0.12)",
134
+ "edgeLight": "rgba(255,255,255,0.07)",
135
+ "edgeOnFill": "rgba(255,255,255,0.22)",
136
+ "edgeWell": "rgba(4,4,7,0.5)",
137
+ "glassBg": "rgba(29,29,32,0.88)",
138
+ "glassBorder": "rgba(255,255,255,0.1)"
139
+ }), light: /* @__PURE__ */ Object.freeze({
140
+ "surface0": "#fafafa",
141
+ "surface1": "#ffffff",
142
+ "surface2": "#f1f1f3",
143
+ "surface3": "#e4e4e7",
144
+ "media": "#e9e9ec",
145
+ "borderSubtle": "rgba(0,0,0,0.06)",
146
+ "borderDefault": "rgba(0,0,0,0.1)",
147
+ "borderStrong": "rgba(0,0,0,0.16)",
148
+ "textPrimary": "#18181b",
149
+ "textSecondary": "#64646d",
150
+ "textMuted": "#808089",
151
+ "textOnMedia": "#ffffff",
152
+ "accent": "#0a64f5",
153
+ "accentHover": "#0d55c9",
154
+ "accentSoft": "rgba(10,100,245,0.08)",
155
+ "accentText": "#0954ce",
156
+ "accent2": "#0a64f5",
157
+ "onAccent": "#ffffff",
158
+ "ring": "#0a64f5",
159
+ "brandGradientFrom": "#dcebfe",
160
+ "brandGradientVia": "#f3f6fc",
161
+ "brandGradientTo": "#fafafa",
162
+ "success": "#10b77f",
163
+ "successText": "#0a714e",
164
+ "successSoft": "rgba(16,183,127,0.1)",
165
+ "warning": "#f59f0a",
166
+ "warningText": "#955104",
167
+ "warningSoft": "rgba(245,159,10,0.12)",
168
+ "danger": "#ef4343",
169
+ "dangerText": "#af1d1d",
170
+ "dangerSoft": "rgba(239,67,67,0.1)",
171
+ "info": "#0a64f5",
172
+ "infoText": "#0954ce",
173
+ "scrim": "rgba(0,0,0,0.6)",
174
+ "scrimStrong": "rgba(0,0,0,0.8)",
175
+ "overlay": "rgba(0,0,0,0.7)",
176
+ "surfaceSheen": "rgba(255,255,255,0.7)",
177
+ "fillShade": "rgba(0,0,0,0.12)",
178
+ "edgeLight": "rgba(255,255,255,0.9)",
179
+ "edgeOnFill": "rgba(255,255,255,0.22)",
180
+ "edgeWell": "rgba(48,52,80,0.08)",
181
+ "glassBg": "rgba(255,255,255,0.88)",
182
+ "glassBorder": "rgba(0,0,0,0.08)"
183
+ }) });
184
+ var brands = /* @__PURE__ */ Object.freeze({
185
+ "krizaka": {
186
+ "dark": {
187
+ "accent": "#196df5",
188
+ "accentHover": "#0e5bd8",
189
+ "accentSoft": "rgba(25,109,245,0.1)",
190
+ "accentText": "#629cf8",
191
+ "accent2": "#196df5",
192
+ "onAccent": "#ffffff",
193
+ "ring": "#196df5",
194
+ "info": "#196df5",
195
+ "infoText": "#629cf8",
196
+ "brandGradientFrom": "#0e1525",
197
+ "brandGradientVia": "#0e0f16",
198
+ "brandGradientTo": "#0c0c0e"
199
+ },
200
+ "light": {
201
+ "accent": "#0a64f5",
202
+ "accentHover": "#0d55c9",
203
+ "accentSoft": "rgba(10,100,245,0.08)",
204
+ "accentText": "#0954ce",
205
+ "accent2": "#0a64f5",
206
+ "onAccent": "#ffffff",
207
+ "ring": "#0a64f5",
208
+ "info": "#0a64f5",
209
+ "infoText": "#0954ce",
210
+ "brandGradientFrom": "#dcebfe",
211
+ "brandGradientVia": "#f3f6fc",
212
+ "brandGradientTo": "#fafafa"
213
+ }
214
+ },
215
+ "orazaka": {
216
+ "dark": {
217
+ "accent": "#f67e23",
218
+ "accentHover": "#f79245",
219
+ "accentSoft": "rgba(246,126,35,0.12)",
220
+ "accentText": "#f78c3b",
221
+ "accent2": "#f59e0b",
222
+ "onAccent": "#0c0c0e",
223
+ "ring": "#f67e23",
224
+ "info": "#3b83f7",
225
+ "infoText": "#629cf8",
226
+ "brandGradientFrom": "#28170b",
227
+ "brandGradientVia": "#17130c",
228
+ "brandGradientTo": "#0c0c0e"
229
+ },
230
+ "light": {
231
+ "accent": "#b45309",
232
+ "accentHover": "#964608",
233
+ "accentSoft": "rgba(180,83,9,0.08)",
234
+ "accentText": "#9b4808",
235
+ "accent2": "#a45904",
236
+ "onAccent": "#ffffff",
237
+ "ring": "#b45309",
238
+ "info": "#0a64f5",
239
+ "infoText": "#0954ce",
240
+ "brandGradientFrom": "#ffebd6",
241
+ "brandGradientVia": "#fdf7ed",
242
+ "brandGradientTo": "#fafafa"
243
+ }
244
+ },
245
+ "orochia": {
246
+ "dark": {
247
+ "accent": "#7c3aed",
248
+ "accentHover": "#6d28d9",
249
+ "accentSoft": "rgba(139,92,246,0.12)",
250
+ "accentText": "#a78bfa",
251
+ "accent2": "#db2777",
252
+ "onAccent": "#ffffff",
253
+ "ring": "#a78bfa",
254
+ "info": "#7c3aed",
255
+ "infoText": "#a78bfa",
256
+ "brandGradientFrom": "#1a0e2a",
257
+ "brandGradientVia": "#1c0d17",
258
+ "brandGradientTo": "#0c0c0e"
259
+ },
260
+ "light": {
261
+ "accent": "#7c3aed",
262
+ "accentHover": "#6d28d9",
263
+ "accentSoft": "rgba(124,58,237,0.08)",
264
+ "accentText": "#6d28d9",
265
+ "accent2": "#db2777",
266
+ "onAccent": "#ffffff",
267
+ "ring": "#7c3aed",
268
+ "info": "#7c3aed",
269
+ "infoText": "#6d28d9",
270
+ "brandGradientFrom": "#efe7fe",
271
+ "brandGradientVia": "#fdedf5",
272
+ "brandGradientTo": "#fafafa"
273
+ }
274
+ },
275
+ "yazakia": {
276
+ "dark": {
277
+ "accent": "#24dbc9",
278
+ "accentHover": "#47e1d2",
279
+ "accentSoft": "rgba(36,219,201,0.12)",
280
+ "accentText": "#3ee0cf",
281
+ "accent2": "#22c378",
282
+ "onAccent": "#0c0c0e",
283
+ "ring": "#24dbc9",
284
+ "info": "#3b83f7",
285
+ "infoText": "#629cf8",
286
+ "brandGradientFrom": "#0a241e",
287
+ "brandGradientVia": "#0c1818",
288
+ "brandGradientTo": "#0c0c0e"
289
+ },
290
+ "light": {
291
+ "accent": "#097169",
292
+ "accentHover": "#085e57",
293
+ "accentSoft": "rgba(9,113,105,0.08)",
294
+ "accentText": "#096d64",
295
+ "accent2": "#107546",
296
+ "onAccent": "#ffffff",
297
+ "ring": "#097169",
298
+ "info": "#0a64f5",
299
+ "infoText": "#0954ce",
300
+ "brandGradientFrom": "#e1faf1",
301
+ "brandGradientVia": "#e9fbfa",
302
+ "brandGradientTo": "#fafafa"
303
+ }
304
+ },
305
+ "yororis": {
306
+ "dark": {
307
+ "accent": "#98b587",
308
+ "accentHover": "#adc69f",
309
+ "accentSoft": "rgba(152,181,135,0.12)",
310
+ "accentText": "#a7c497",
311
+ "accent2": "#c3a579",
312
+ "onAccent": "#0c0c0e",
313
+ "ring": "#98b587",
314
+ "info": "#3b83f7",
315
+ "infoText": "#629cf8",
316
+ "brandGradientFrom": "#1c1812",
317
+ "brandGradientVia": "#11140f",
318
+ "brandGradientTo": "#0c0c0e"
319
+ },
320
+ "light": {
321
+ "accent": "#456237",
322
+ "accentHover": "#39532d",
323
+ "accentSoft": "rgba(69,98,55,0.08)",
324
+ "accentText": "#415b33",
325
+ "accent2": "#745834",
326
+ "onAccent": "#ffffff",
327
+ "ring": "#456237",
328
+ "info": "#0a64f5",
329
+ "infoText": "#0954ce",
330
+ "brandGradientFrom": "#f5efe5",
331
+ "brandGradientVia": "#f1f6ee",
332
+ "brandGradientTo": "#fafafa"
333
+ }
334
+ }
335
+ });
336
+
337
+ // src/map/style.ts
338
+ import { layers, namedFlavor } from "@protomaps/basemaps";
339
+ function mix(a, b, t) {
340
+ const p = (h) => [1, 3, 5].map((i) => parseInt(h.slice(i, i + 2), 16));
341
+ const [x, y] = [p(a), p(b)];
342
+ return `#${x.map((v, i) => Math.round(v + (y[i] - v) * t).toString(16).padStart(2, "0")).join("")}`;
343
+ }
344
+ function mapPalette(scheme, brand = "krizaka") {
345
+ const t = { ...themes[scheme], ...brands[brand]?.[scheme] };
346
+ const dark = scheme === "dark";
347
+ const land = dark ? t.surface1 : t.surface0;
348
+ return {
349
+ land,
350
+ background: dark ? t.surface0 : t.surface2,
351
+ water: mix(land, t.accent, dark ? 0.18 : 0.14),
352
+ park: mix(land, t.success, dark ? 0.1 : 0.12),
353
+ road: dark ? mix(land, t.textPrimary, 0.12) : "#ffffff",
354
+ roadMajor: dark ? mix(land, t.textPrimary, 0.2) : mix(land, t.textPrimary, 0.06),
355
+ casing: mix(land, t.textPrimary, dark ? 0.05 : 0.12),
356
+ building: mix(land, t.textPrimary, dark ? 0.06 : 0.07),
357
+ boundary: mix(land, t.textPrimary, 0.3),
358
+ label: t.textSecondary,
359
+ labelStrong: t.textPrimary,
360
+ halo: land,
361
+ accent: t.accent,
362
+ onAccent: t.onAccent
363
+ };
364
+ }
365
+ function mapFlavor(scheme, brand) {
366
+ const c = mapPalette(scheme, brand);
367
+ const base2 = namedFlavor(scheme);
368
+ return {
369
+ ...base2,
370
+ background: c.background,
371
+ earth: c.land,
372
+ park_a: c.park,
373
+ park_b: c.park,
374
+ wood_a: c.park,
375
+ wood_b: c.park,
376
+ scrub_a: c.park,
377
+ scrub_b: c.park,
378
+ glacier: c.land,
379
+ sand: c.land,
380
+ beach: c.land,
381
+ zoo: c.park,
382
+ hospital: c.land,
383
+ industrial: c.land,
384
+ school: c.land,
385
+ military: c.land,
386
+ aerodrome: c.land,
387
+ pedestrian: c.land,
388
+ runway: c.building,
389
+ water: c.water,
390
+ buildings: c.building,
391
+ pier: c.building,
392
+ boundaries: c.boundary,
393
+ railway: c.casing,
394
+ other: c.road,
395
+ minor_service: c.road,
396
+ minor_a: c.road,
397
+ minor_b: c.road,
398
+ link: c.road,
399
+ major: c.roadMajor,
400
+ highway: c.roadMajor,
401
+ bridges_other: c.road,
402
+ bridges_minor: c.road,
403
+ bridges_link: c.road,
404
+ bridges_major: c.roadMajor,
405
+ bridges_highway: c.roadMajor,
406
+ tunnel_other: c.road,
407
+ tunnel_minor: c.road,
408
+ tunnel_link: c.road,
409
+ tunnel_major: c.roadMajor,
410
+ tunnel_highway: c.roadMajor,
411
+ minor_service_casing: c.casing,
412
+ minor_casing: c.casing,
413
+ link_casing: c.casing,
414
+ major_casing_late: c.casing,
415
+ major_casing_early: c.casing,
416
+ highway_casing_late: c.casing,
417
+ highway_casing_early: c.casing,
418
+ bridges_other_casing: c.casing,
419
+ bridges_minor_casing: c.casing,
420
+ bridges_link_casing: c.casing,
421
+ bridges_major_casing: c.casing,
422
+ bridges_highway_casing: c.casing,
423
+ tunnel_other_casing: c.casing,
424
+ tunnel_minor_casing: c.casing,
425
+ tunnel_link_casing: c.casing,
426
+ tunnel_major_casing: c.casing,
427
+ tunnel_highway_casing: c.casing,
428
+ roads_label_minor: c.label,
429
+ roads_label_minor_halo: c.halo,
430
+ roads_label_major: c.label,
431
+ roads_label_major_halo: c.halo,
432
+ ocean_label: c.label,
433
+ subplace_label: c.label,
434
+ subplace_label_halo: c.halo,
435
+ city_label: c.labelStrong,
436
+ city_label_halo: c.halo,
437
+ state_label: c.label,
438
+ state_label_halo: c.halo,
439
+ country_label: c.label,
440
+ address_label: c.label,
441
+ address_label_halo: c.halo,
442
+ regular: "Noto Sans Regular",
443
+ bold: "Noto Sans Medium",
444
+ italic: "Noto Sans Italic",
445
+ // No point-of-interest icons (no sprite to host): the app's own markers carry the places that matter.
446
+ pois: void 0,
447
+ landcover: void 0
448
+ };
449
+ }
450
+ var REGION_FROM_ZOOM = 6.5;
451
+ function mapStyle({ scheme, brand, lang = "en", world = { url: mapAssets().tiles.world, maxzoom: 6 }, region = { url: mapAssets().tiles.quebec, maxzoom: 14 }, glyphs = mapAssets().glyphs }) {
452
+ const flavor = mapFlavor(scheme, brand);
453
+ const attribution = `<a href="${MAP_ATTRIBUTION.protomapsUrl}">${MAP_ATTRIBUTION.protomaps}</a> \xB7 <a href="${MAP_ATTRIBUTION.osmUrl}">${MAP_ATTRIBUTION.osm}</a>`;
454
+ const sources = {};
455
+ const all = [];
456
+ if (world) {
457
+ sources.world = { type: "vector", url: `pmtiles://${world.url}`, attribution };
458
+ for (const l of layers("world", flavor, { lang })) {
459
+ if (l.id === "background") all.push(l);
460
+ else all.push({ ...l, id: `world-${l.id}`, maxzoom: region ? Math.min(l.maxzoom ?? 24, REGION_FROM_ZOOM) : l.maxzoom });
461
+ }
462
+ }
463
+ if (region) {
464
+ sources.region = { type: "vector", url: `pmtiles://${region.url}`, attribution };
465
+ for (const l of layers("region", flavor, { lang })) {
466
+ if (l.id === "background") {
467
+ if (!world) all.push(l);
468
+ continue;
469
+ }
470
+ all.push({ ...l, id: `region-${l.id}`, minzoom: world ? Math.max(l.minzoom ?? 0, REGION_FROM_ZOOM) : l.minzoom });
471
+ }
472
+ }
473
+ const drawn = all.filter((l) => !l.layout?.["icon-image"]);
474
+ return { version: 8, glyphs, sources, layers: drawn.map((l) => l.maxzoom === void 0 ? withoutKey(l, "maxzoom") : l) };
475
+ }
476
+ var withoutKey = (o, key) => Object.fromEntries(Object.entries(o).filter(([k]) => k !== key));
477
+
478
+ // src/map/map.tsx
479
+ import { jsx, jsxs } from "react/jsx-runtime";
480
+ var map = tv({
481
+ slots: {
482
+ root: "relative isolate overflow-hidden rounded-2xl border border-border-default bg-surface-2 shadow-raised",
483
+ canvas: "absolute inset-0 [&_.maplibregl-canvas]:outline-hidden",
484
+ fallback: "absolute inset-0",
485
+ controls: "absolute right-3 top-3 z-10 flex flex-col overflow-hidden rounded-xl border border-border-default bg-surface-1 shadow-floating",
486
+ control: "inline-flex h-10 w-10 items-center justify-center text-lg font-semibold text-fg-secondary transition-colors hover:bg-surface-3 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset disabled:opacity-40 [&+&]:border-t [&+&]:border-border-subtle",
487
+ attribution: "absolute bottom-1.5 right-1.5 z-10 rounded-md bg-surface-1/85 px-1.5 py-0.5 text-[10px] text-fg-secondary backdrop-blur-sm [&_a]:underline-offset-2 hover:[&_a]:underline",
488
+ places: "sr-only",
489
+ marker: "group relative flex -translate-y-1/2 cursor-pointer items-center justify-center rounded-full border-2 border-on-accent bg-accent shadow-floating outline-hidden transition-transform hover:scale-110 focus-visible:focus-ring motion-reduce:transition-none motion-reduce:hover:scale-100 data-[selected]:scale-125",
490
+ markerLabel: "pointer-events-none absolute bottom-full mb-2 whitespace-nowrap rounded-lg border border-border-default bg-surface-1 px-2 py-1 text-xs font-semibold text-fg shadow-floating"
491
+ }
492
+ });
493
+ var MapContext = React2.createContext(null);
494
+ function useMap() {
495
+ const ctx = React2.useContext(MapContext);
496
+ if (!ctx) throw new Error("useMap: inside a <Map> only");
497
+ return ctx;
498
+ }
499
+ function usePageScheme() {
500
+ const read = () => typeof document !== "undefined" && document.documentElement.classList.contains("light") ? "light" : "dark";
501
+ const [scheme, setScheme] = React2.useState(read);
502
+ React2.useEffect(() => {
503
+ const observer = new MutationObserver(() => setScheme(read()));
504
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
505
+ return () => observer.disconnect();
506
+ }, []);
507
+ return scheme;
508
+ }
509
+ var protocolAdded = false;
510
+ var workerUrl = null;
511
+ function configureMaps(options) {
512
+ if (options.workerUrl) workerUrl = options.workerUrl;
513
+ if (options.assetsBase) setMapAssetsBase(options.assetsBase);
514
+ }
515
+ async function loadEngine() {
516
+ const [lib, pmtiles] = await Promise.all([import("maplibre-gl"), import("pmtiles")]);
517
+ const ml = lib.default ?? lib;
518
+ if (!protocolAdded) {
519
+ protocolAdded = true;
520
+ const remote = `https://cdn.jsdelivr.net/npm/maplibre-gl@${ml.getVersion()}/dist/maplibre-gl-worker.mjs`;
521
+ ml.setWorkerUrl(workerUrl ?? URL.createObjectURL(new Blob([`import ${JSON.stringify(remote)};`], { type: "text/javascript" })));
522
+ ml.addProtocol("pmtiles", new pmtiles.Protocol().tile);
523
+ }
524
+ return ml;
525
+ }
526
+ var hasWebGL = () => {
527
+ try {
528
+ const canvas = document.createElement("canvas");
529
+ return Boolean(canvas.getContext("webgl2") ?? canvas.getContext("webgl"));
530
+ } catch {
531
+ return false;
532
+ }
533
+ };
534
+ var mapLabels = { zoomIn: "Zoom in", zoomOut: "Zoom out", places: "Places on the map" };
535
+ function Map({
536
+ label,
537
+ center,
538
+ zoom = 12,
539
+ controlled,
540
+ scheme: schemeProp,
541
+ brand,
542
+ lang,
543
+ region,
544
+ world,
545
+ controls = true,
546
+ interactive = true,
547
+ fallback,
548
+ onMoveEnd,
549
+ onPress,
550
+ children,
551
+ labels: given,
552
+ className
553
+ }) {
554
+ const labels = { ...mapLabels, ...given };
555
+ const s = map();
556
+ const pageScheme = usePageScheme();
557
+ const scheme = schemeProp ?? pageScheme;
558
+ const reduce = usePrefersReducedMotion();
559
+ const host = React2.useRef(null);
560
+ const [instance, setInstance] = React2.useState(null);
561
+ const [lib, setLib] = React2.useState(null);
562
+ const [ready, setReady] = React2.useState(false);
563
+ const [failed, setFailed] = React2.useState(false);
564
+ const [places, setPlaces] = React2.useState({});
565
+ const registry = React2.useMemo(
566
+ () => ({
567
+ add: (id, text) => setPlaces((p) => p[id] === text ? p : { ...p, [id]: text }),
568
+ remove: (id) => setPlaces((p) => {
569
+ const { [id]: _gone, ...rest } = p;
570
+ return rest;
571
+ })
572
+ }),
573
+ []
574
+ );
575
+ const latest = React2.useRef({ onMoveEnd, onPress });
576
+ React2.useEffect(() => {
577
+ latest.current = { onMoveEnd, onPress };
578
+ });
579
+ const styleOf = React2.useCallback((sc) => mapStyle({ scheme: sc, brand, lang, ...region !== void 0 ? { region } : {}, ...world !== void 0 ? { world } : {} }), [brand, lang, region, world]);
580
+ React2.useEffect(() => {
581
+ if (!host.current) return;
582
+ let alive = true;
583
+ let created = null;
584
+ (hasWebGL() ? loadEngine() : Promise.reject(new Error("no WebGL"))).then((ml) => {
585
+ if (!alive || !host.current) return;
586
+ created = new ml.Map({
587
+ container: host.current,
588
+ style: styleOf(scheme),
589
+ center: [...center],
590
+ zoom,
591
+ interactive,
592
+ attributionControl: false,
593
+ fadeDuration: reduce ? 0 : 300,
594
+ cooperativeGestures: false
595
+ });
596
+ created.getCanvas().setAttribute("aria-hidden", "true");
597
+ created.getCanvas().setAttribute("tabindex", "-1");
598
+ created.on("load", () => alive && setReady(true));
599
+ created.on("error", (e) => {
600
+ const source = e.sourceId;
601
+ if (alive && (source === "world" || source === "region")) setFailed(true);
602
+ });
603
+ created.on("moveend", () => {
604
+ const c = created.getCenter();
605
+ latest.current.onMoveEnd?.({ center: [c.lng, c.lat], zoom: created.getZoom() });
606
+ });
607
+ created.on("click", (e) => {
608
+ if (e.originalEvent.target?.closest?.("[data-kz-marker]")) return;
609
+ latest.current.onPress?.([e.lngLat.lng, e.lngLat.lat]);
610
+ });
611
+ setLib(ml);
612
+ setInstance(created);
613
+ }).catch(() => alive && setFailed(true));
614
+ return () => {
615
+ alive = false;
616
+ created?.remove();
617
+ };
618
+ }, []);
619
+ const first = React2.useRef(true);
620
+ React2.useEffect(() => {
621
+ if (!instance) return;
622
+ if (first.current) {
623
+ first.current = false;
624
+ return;
625
+ }
626
+ instance.setStyle(styleOf(scheme));
627
+ }, [instance, scheme, styleOf]);
628
+ React2.useEffect(() => {
629
+ if (!instance || !controlled) return;
630
+ const view = { center: [...center], zoom };
631
+ if (reduce) instance.jumpTo(view);
632
+ else instance.flyTo({ ...view, speed: 1.4 });
633
+ }, [instance, controlled, center[0], center[1], zoom, reduce]);
634
+ const zoomBy = (by) => instance && (reduce ? instance.setZoom(instance.getZoom() + by) : instance.zoomTo(instance.getZoom() + by, { duration: 250 }));
635
+ const ctx = React2.useMemo(() => ({ map: instance, lib, ready, reduce, places: registry }), [instance, lib, ready, reduce, registry]);
636
+ const listed = Object.entries(places);
637
+ return /* @__PURE__ */ jsx(MapContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxs(
638
+ "section",
639
+ {
640
+ "aria-label": label,
641
+ className: s.root({ className }),
642
+ "data-ready": ready ? "" : void 0,
643
+ tabIndex: interactive ? 0 : void 0,
644
+ onKeyDown: (e) => {
645
+ if (e.target !== e.currentTarget || !instance) return;
646
+ if (e.key === "+" || e.key === "=") zoomBy(1);
647
+ else if (e.key === "-") zoomBy(-1);
648
+ else if (e.key.startsWith("Arrow")) {
649
+ e.preventDefault();
650
+ const step = 80;
651
+ const by = { ArrowUp: [0, -step], ArrowDown: [0, step], ArrowLeft: [-step, 0], ArrowRight: [step, 0] };
652
+ instance.panBy(by[e.key], { duration: reduce ? 0 : 200 });
653
+ }
654
+ },
655
+ children: [
656
+ !ready || failed ? /* @__PURE__ */ jsx("div", { className: s.fallback(), children: fallback }) : null,
657
+ /* @__PURE__ */ jsx("div", { ref: host, className: s.canvas(), style: { position: "absolute", inset: 0, visibility: failed ? "hidden" : void 0 } }),
658
+ controls && interactive && !failed ? /* @__PURE__ */ jsxs("div", { className: s.controls(), children: [
659
+ /* @__PURE__ */ jsx("button", { type: "button", className: s.control(), "aria-label": labels.zoomIn, disabled: !instance, onClick: () => zoomBy(1), children: "+" }),
660
+ /* @__PURE__ */ jsx("button", { type: "button", className: s.control(), "aria-label": labels.zoomOut, disabled: !instance, onClick: () => zoomBy(-1), children: "\u2212" })
661
+ ] }) : null,
662
+ /* @__PURE__ */ jsxs("p", { className: s.attribution(), children: [
663
+ /* @__PURE__ */ jsx("a", { href: MAP_ATTRIBUTION.protomapsUrl, target: "_blank", rel: "noreferrer", children: MAP_ATTRIBUTION.protomaps }),
664
+ " \xB7 ",
665
+ /* @__PURE__ */ jsx("a", { href: MAP_ATTRIBUTION.osmUrl, target: "_blank", rel: "noreferrer", children: MAP_ATTRIBUTION.osm })
666
+ ] }),
667
+ listed.length ? /* @__PURE__ */ jsxs("div", { className: s.places(), children: [
668
+ /* @__PURE__ */ jsx("p", { children: labels.places }),
669
+ /* @__PURE__ */ jsx("ul", { children: listed.map(([id, text]) => /* @__PURE__ */ jsx("li", { children: text }, id)) })
670
+ ] }) : null,
671
+ children
672
+ ]
673
+ }
674
+ ) });
675
+ }
676
+ function Marker({ position, label, onPress, selected, size = 18, children }) {
677
+ const { map: m, lib, places } = useMap();
678
+ const s = map();
679
+ const id = React2.useId();
680
+ const [el] = React2.useState(() => typeof document === "undefined" ? null : document.createElement("div"));
681
+ React2.useEffect(() => {
682
+ places.add(id, label);
683
+ return () => places.remove(id);
684
+ }, [id, label, places]);
685
+ React2.useEffect(() => {
686
+ if (!m || !lib || !el) return;
687
+ el.setAttribute("data-kz-marker", "");
688
+ const marker = new lib.Marker({ element: el, anchor: "center" }).setLngLat([...position]).addTo(m);
689
+ return () => void marker.remove();
690
+ }, [m, lib, el, position[0], position[1]]);
691
+ if (!el) return null;
692
+ const Tag = onPress ? "button" : "span";
693
+ return createPortal(
694
+ /* @__PURE__ */ jsxs(
695
+ Tag,
696
+ {
697
+ type: onPress ? "button" : void 0,
698
+ "aria-label": onPress ? label : void 0,
699
+ "aria-hidden": onPress ? void 0 : true,
700
+ "aria-pressed": onPress && selected !== void 0 ? selected : void 0,
701
+ "data-selected": selected ? "" : void 0,
702
+ className: s.marker(),
703
+ style: children ? void 0 : { width: size, height: size },
704
+ onClick: onPress,
705
+ children: [
706
+ children,
707
+ selected ? /* @__PURE__ */ jsx("span", { className: s.markerLabel(), children: label }) : null
708
+ ]
709
+ }
710
+ ),
711
+ el
712
+ );
713
+ }
714
+ function UserPosition({ position, label, accuracy }) {
715
+ const { map: m, lib, places } = useMap();
716
+ const id = React2.useId();
717
+ React2.useEffect(() => {
718
+ places.add(id, label);
719
+ return () => places.remove(id);
720
+ }, [id, label, places]);
721
+ React2.useEffect(() => {
722
+ if (!m || !lib) return;
723
+ const el = document.createElement("div");
724
+ el.className = "kz-map-user";
725
+ el.setAttribute("aria-hidden", "true");
726
+ const marker = new lib.Marker({ element: el, anchor: "center" }).setLngLat([...position]).addTo(m);
727
+ return () => void marker.remove();
728
+ }, [m, lib, position[0], position[1]]);
729
+ return accuracy ? /* @__PURE__ */ jsx(RadiusCircle, { center: position, radius: accuracy, tone: "soft" }) : null;
730
+ }
731
+ function useGeoLayer(id, data, layers2, source = {}) {
732
+ const { map: m, ready } = useMap();
733
+ const dataRef = React2.useRef(data);
734
+ React2.useEffect(() => {
735
+ dataRef.current = data;
736
+ const src = m?.getSource(id);
737
+ src?.setData?.(data);
738
+ }, [m, id, data]);
739
+ React2.useEffect(() => {
740
+ if (!m || !ready) return;
741
+ const add = () => {
742
+ if (m.getSource(id)) return;
743
+ const scheme = document.documentElement.classList.contains("light") ? "light" : "dark";
744
+ m.addSource(id, { type: "geojson", data: dataRef.current, ...source });
745
+ for (const layer of layers2(mapPalette(scheme))) m.addLayer(layer);
746
+ };
747
+ add();
748
+ m.on("styledata", add);
749
+ return () => {
750
+ m.off("styledata", add);
751
+ if (!m.getStyle()) return;
752
+ for (const layer of m.getStyle().layers.filter((l) => "source" in l && l.source === id)) m.removeLayer(layer.id);
753
+ if (m.getSource(id)) m.removeSource(id);
754
+ };
755
+ }, [m, ready, id]);
756
+ }
757
+ function RadiusCircle({ center, radius, tone = "accent" }) {
758
+ const id = `kz-circle-${React2.useId().replace(/[^a-zA-Z0-9]/g, "")}`;
759
+ const data = React2.useMemo(() => circlePolygon(center, radius), [center[0], center[1], radius]);
760
+ useGeoLayer(id, data, (c) => [
761
+ { id: `${id}-fill`, type: "fill", source: id, paint: { "fill-color": c.accent, "fill-opacity": tone === "soft" ? 0.1 : 0.14 } },
762
+ { id: `${id}-line`, type: "line", source: id, paint: { "line-color": c.accent, "line-width": tone === "soft" ? 1 : 2, "line-opacity": tone === "soft" ? 0.4 : 0.9, ...tone === "accent" ? { "line-dasharray": [2, 1.5] } : {} } }
763
+ ]);
764
+ return null;
765
+ }
766
+ function Cluster({ points, onPointPress, radius = 48 }) {
767
+ const { map: m, ready, reduce, places } = useMap();
768
+ const id = `kz-cluster-${React2.useId().replace(/[^a-zA-Z0-9]/g, "")}`;
769
+ const data = React2.useMemo(
770
+ () => ({ type: "FeatureCollection", features: points.map((p) => ({ type: "Feature", properties: { id: p.id, label: p.label }, geometry: { type: "Point", coordinates: [...p.position] } })) }),
771
+ [points]
772
+ );
773
+ React2.useEffect(() => {
774
+ for (const p of points) places.add(`${id}-${p.id}`, p.label);
775
+ return () => points.forEach((p) => places.remove(`${id}-${p.id}`));
776
+ }, [points, places, id]);
777
+ useGeoLayer(
778
+ id,
779
+ data,
780
+ (c) => [
781
+ { id: `${id}-groups`, type: "circle", source: id, filter: ["has", "point_count"], paint: { "circle-color": c.accent, "circle-opacity": 0.92, "circle-radius": ["step", ["get", "point_count"], 16, 10, 20, 50, 26], "circle-stroke-width": 3, "circle-stroke-color": c.halo } },
782
+ { id: `${id}-count`, type: "symbol", source: id, filter: ["has", "point_count"], layout: { "text-field": ["get", "point_count_abbreviated"], "text-font": ["Noto Sans Medium"], "text-size": 13 }, paint: { "text-color": c.onAccent } },
783
+ { id: `${id}-points`, type: "circle", source: id, filter: ["!", ["has", "point_count"]], paint: { "circle-color": c.accent, "circle-radius": 7, "circle-stroke-width": 2.5, "circle-stroke-color": c.halo } }
784
+ ],
785
+ { cluster: true, clusterRadius: radius, clusterMaxZoom: 15 }
786
+ );
787
+ React2.useEffect(() => {
788
+ if (!m || !ready) return;
789
+ const openGroup = async (e) => {
790
+ const f = e.features?.[0];
791
+ if (!f) return;
792
+ const src = m.getSource(id);
793
+ const z = await src.getClusterExpansionZoom(f.properties.cluster_id);
794
+ const center = f.geometry.coordinates;
795
+ if (reduce) m.jumpTo({ center, zoom: z });
796
+ else m.easeTo({ center, zoom: z });
797
+ };
798
+ const pressPoint = (e) => {
799
+ const pid = e.features?.[0]?.properties.id;
800
+ const point = points.find((p) => p.id === pid);
801
+ if (point) onPointPress?.(point);
802
+ };
803
+ m.on("click", `${id}-groups`, openGroup);
804
+ m.on("click", `${id}-points`, pressPoint);
805
+ return () => {
806
+ m.off("click", `${id}-groups`, openGroup);
807
+ m.off("click", `${id}-points`, pressPoint);
808
+ };
809
+ }, [m, ready, id, points, onPointPress, reduce]);
810
+ return null;
811
+ }
812
+
813
+ // src/map/location-picker.tsx
814
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
815
+ var locationPicker = tv({
816
+ slots: {
817
+ root: "flex flex-col gap-2",
818
+ frame: "relative",
819
+ pin: "pointer-events-none absolute left-1/2 top-1/2 z-10 -translate-x-1/2 -translate-y-full text-accent drop-shadow-md",
820
+ bar: "absolute inset-x-3 bottom-8 z-10 flex flex-wrap items-center justify-between gap-2",
821
+ chip: "rounded-full border border-border-default bg-surface-1 px-3 py-1.5 text-xs font-semibold tabular-nums text-fg shadow-floating",
822
+ near: "inline-flex h-10 items-center gap-2 rounded-full border border-border-default bg-surface-1 bg-sheen px-4 text-sm font-semibold text-fg shadow-floating inset-shadow-edge transition-colors hover:border-border-strong focus-visible:outline-hidden focus-visible:focus-ring disabled:opacity-60",
823
+ status: "text-xs text-fg-secondary data-[tone=danger]:text-fg-danger"
824
+ }
825
+ });
826
+ var locationPickerLabels = {
827
+ nearMe: "Near me",
828
+ locating: "Finding you\u2026",
829
+ denied: "Location is off for this site. Move the map instead.",
830
+ unavailable: "We could not find you. Move the map instead.",
831
+ you: "You are here",
832
+ distance: (d) => `${d} from you`
833
+ };
834
+ function LocationPicker({ label, value, onValueChange, locale, zoom = 14, radius, origin: originProp = null, labels: given, className, ...map2 }) {
835
+ const labels = { ...locationPickerLabels, ...given };
836
+ const s = locationPicker();
837
+ const [origin, setOrigin] = React3.useState(originProp);
838
+ const [camera, setCamera] = React3.useState(value);
839
+ const [status, setStatus] = React3.useState("idle");
840
+ const statusId = React3.useId();
841
+ const nearMe = () => {
842
+ if (typeof navigator === "undefined" || !navigator.geolocation) return setStatus("unavailable");
843
+ setStatus("locating");
844
+ navigator.geolocation.getCurrentPosition(
845
+ (p) => {
846
+ const here = [p.coords.longitude, p.coords.latitude];
847
+ setOrigin(here);
848
+ setCamera(here);
849
+ onValueChange(here);
850
+ setStatus("idle");
851
+ },
852
+ (e) => setStatus(e.code === 1 ? "denied" : "unavailable"),
853
+ { enableHighAccuracy: false, timeout: 1e4, maximumAge: 6e4 }
854
+ );
855
+ };
856
+ const distance = origin ? formatDistance(distanceMeters(origin, value), locale) : null;
857
+ const message = status === "locating" ? labels.locating : status === "denied" ? labels.denied : status === "unavailable" ? labels.unavailable : "";
858
+ return /* @__PURE__ */ jsxs2("div", { className: s.root({ className }), role: "group", "aria-label": label, children: [
859
+ /* @__PURE__ */ jsxs2("div", { className: s.frame(), children: [
860
+ /* @__PURE__ */ jsxs2(Map, { ...map2, label, center: camera, zoom, controlled: true, onMoveEnd: (v) => onValueChange(v.center), className: "h-80", children: [
861
+ radius ? /* @__PURE__ */ jsx2(RadiusCircle, { center: value, radius }) : null,
862
+ origin ? /* @__PURE__ */ jsx2(UserPosition, { position: origin, label: labels.you }) : null
863
+ ] }),
864
+ /* @__PURE__ */ jsxs2("svg", { "aria-hidden": true, viewBox: "0 0 24 32", className: s.pin(), width: "30", height: "40", children: [
865
+ /* @__PURE__ */ jsx2("path", { d: "M12 0C5.4 0 0 5.2 0 11.7 0 20.4 12 32 12 32s12-11.6 12-20.3C24 5.2 18.6 0 12 0Z", fill: "currentColor" }),
866
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "11.5", r: "4.5", fill: "var(--kz-on-accent)" })
867
+ ] }),
868
+ /* @__PURE__ */ jsxs2("div", { className: s.bar(), children: [
869
+ distance ? /* @__PURE__ */ jsx2("span", { className: s.chip(), "aria-live": "polite", children: labels.distance(distance) }) : /* @__PURE__ */ jsx2("span", {}),
870
+ /* @__PURE__ */ jsxs2("button", { type: "button", className: s.near(), onClick: nearMe, disabled: status === "locating", "aria-describedby": message ? statusId : void 0, children: [
871
+ /* @__PURE__ */ jsxs2("svg", { "aria-hidden": true, viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: [
872
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "3.5" }),
873
+ /* @__PURE__ */ jsx2("path", { d: "M12 2v3M12 19v3M2 12h3M19 12h3" })
874
+ ] }),
875
+ status === "locating" ? labels.locating : labels.nearMe
876
+ ] })
877
+ ] })
878
+ ] }),
879
+ /* @__PURE__ */ jsx2("p", { id: statusId, className: s.status(), "data-tone": status === "denied" || status === "unavailable" ? "danger" : void 0, "aria-live": "polite", children: message })
880
+ ] });
881
+ }
882
+
883
+ // src/map/static-map.tsx
884
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
885
+ var staticMap = tv({
886
+ slots: {
887
+ root: "relative block h-full w-full overflow-hidden bg-surface-2",
888
+ svg: "absolute inset-0 h-full w-full",
889
+ attribution: "absolute bottom-1.5 right-1.5 rounded-md bg-surface-1/85 px-1.5 py-0.5 text-[10px] text-fg-secondary"
890
+ }
891
+ });
892
+ var W = 640;
893
+ var H = 400;
894
+ function StaticMap({ label, center, zoom = 12, places = [], image, className }) {
895
+ const s = staticMap();
896
+ const [cx, cy] = project(center, zoom);
897
+ const at = (p) => {
898
+ const [x, y] = project(p, zoom);
899
+ return [W / 2 + x - cx, H / 2 + y - cy];
900
+ };
901
+ const name = places.length ? `${label}: ${places.map((p) => p.label).join(", ")}` : label;
902
+ return /* @__PURE__ */ jsxs3("span", { role: "img", "aria-label": name, className: s.root({ className }), children: [
903
+ /* @__PURE__ */ jsxs3("svg", { viewBox: `0 0 ${W} ${H}`, preserveAspectRatio: "xMidYMid slice", className: s.svg(), "aria-hidden": true, children: [
904
+ /* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsx3("pattern", { id: "kz-map-paper", width: "48", height: "48", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx3("path", { d: "M48 0H0V48", fill: "none", stroke: "var(--kz-border-subtle)", strokeWidth: "1" }) }) }),
905
+ /* @__PURE__ */ jsx3("rect", { width: W, height: H, fill: "var(--kz-surface-2)" }),
906
+ image ? /* @__PURE__ */ jsx3("image", { href: image, x: "0", y: "0", width: W, height: H, preserveAspectRatio: "xMidYMid slice" }) : /* @__PURE__ */ jsx3("rect", { width: W, height: H, fill: "url(#kz-map-paper)" }),
907
+ places.map((p) => {
908
+ const [x, y] = at(p.position);
909
+ return /* @__PURE__ */ jsxs3("g", { children: [
910
+ /* @__PURE__ */ jsx3("circle", { cx: x, cy: y, r: "12", fill: "var(--kz-accent)", opacity: "0.18" }),
911
+ /* @__PURE__ */ jsx3("circle", { cx: x, cy: y, r: "7", fill: "var(--kz-accent)", stroke: "var(--kz-on-accent)", strokeWidth: "2.5" })
912
+ ] }, `${p.position[0]},${p.position[1]}`);
913
+ })
914
+ ] }),
915
+ image ? /* @__PURE__ */ jsxs3("span", { "aria-hidden": true, className: s.attribution(), children: [
916
+ MAP_ATTRIBUTION.protomaps,
917
+ " \xB7 ",
918
+ MAP_ATTRIBUTION.osm
919
+ ] }) : null
920
+ ] });
921
+ }
922
+ export {
923
+ Cluster,
924
+ LocationPicker,
925
+ MAP_ATTRIBUTION,
926
+ MAP_GLYPHS,
927
+ MAP_TILES,
928
+ Map,
929
+ Marker,
930
+ REGION_FROM_ZOOM,
931
+ RadiusCircle,
932
+ StaticMap,
933
+ UserPosition,
934
+ circlePolygon,
935
+ configureMaps,
936
+ distanceMeters,
937
+ formatDistance,
938
+ locationPicker,
939
+ locationPickerLabels,
940
+ map,
941
+ mapAssets,
942
+ mapFlavor,
943
+ mapLabels,
944
+ mapPalette,
945
+ mapStyle,
946
+ mix,
947
+ project,
948
+ setMapAssetsBase,
949
+ staticMap,
950
+ useMap
951
+ };
952
+ //# sourceMappingURL=map.js.map