@krizaka/ui 3.35.0 → 3.37.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 (620) hide show
  1. package/dist/account-menu.js +1 -1
  2. package/dist/account-menu.js.map +1 -1
  3. package/dist/activity-feed.js +2 -2
  4. package/dist/activity-feed.js.map +1 -1
  5. package/dist/anatomy-plate.d.ts +26 -0
  6. package/dist/anatomy-plate.js +32 -0
  7. package/dist/anatomy-plate.js.map +1 -0
  8. package/dist/app-header.js +1 -1
  9. package/dist/app-header.js.map +1 -1
  10. package/dist/app-shell.js +6 -6
  11. package/dist/app-shell.js.map +1 -1
  12. package/dist/argument-card.js +1 -1
  13. package/dist/badge.d.ts +1 -1
  14. package/dist/badge.js +1 -1
  15. package/dist/badge.js.map +1 -1
  16. package/dist/bird-plate.d.ts +38 -0
  17. package/dist/bird-plate.js +39 -0
  18. package/dist/bird-plate.js.map +1 -0
  19. package/dist/blocks.css +243 -46
  20. package/dist/card.d.ts +6 -6
  21. package/dist/card.js +2 -2
  22. package/dist/card.js.map +1 -1
  23. package/dist/checkbox.js +1 -1
  24. package/dist/checkbox.js.map +1 -1
  25. package/dist/chip-row.js +1 -1
  26. package/dist/chip-row.js.map +1 -1
  27. package/dist/chip.js +1 -1
  28. package/dist/chip.js.map +1 -1
  29. package/dist/{chunk-QDXV544C.js → chunk-4QH6CP2Y.js} +2 -2
  30. package/dist/chunk-4QH6CP2Y.js.map +1 -0
  31. package/dist/{chunk-NJFCSVPT.js → chunk-6EAHUURY.js} +2 -2
  32. package/dist/chunk-6EAHUURY.js.map +1 -0
  33. package/dist/{chunk-REPTKUJ6.js → chunk-7NRSPHAF.js} +2 -2
  34. package/dist/chunk-7NRSPHAF.js.map +1 -0
  35. package/dist/{chunk-CKSHLSDH.js → chunk-AAP3U66V.js} +2 -2
  36. package/dist/{chunk-7UCPGXKN.js → chunk-C3NF7V5Y.js} +2 -2
  37. package/dist/{chunk-7UCPGXKN.js.map → chunk-C3NF7V5Y.js.map} +1 -1
  38. package/dist/chunk-JFJECOZ2.js +338 -0
  39. package/dist/chunk-JFJECOZ2.js.map +1 -0
  40. package/dist/{chunk-KIBICUZK.js → chunk-S5LP7KKW.js} +4 -4
  41. package/dist/{chunk-3S4GHSPZ.js → chunk-VPO27AFS.js} +5 -5
  42. package/dist/chunk-VPO27AFS.js.map +1 -0
  43. package/dist/{chunk-2PNLHZLT.js → chunk-WYQ277F2.js} +3 -3
  44. package/dist/chunk-WYQ277F2.js.map +1 -0
  45. package/dist/{chunk-7Z4KHPFC.js → chunk-YGIN2YIY.js} +2 -2
  46. package/dist/{chunk-7Z4KHPFC.js.map → chunk-YGIN2YIY.js.map} +1 -1
  47. package/dist/{chunk-LZNZLCOE.js → chunk-YKEIOYJ5.js} +20 -6
  48. package/dist/chunk-YKEIOYJ5.js.map +1 -0
  49. package/dist/{chunk-2DGLWTPS.js → chunk-YKOLME7R.js} +3 -3
  50. package/dist/{chunk-2DGLWTPS.js.map → chunk-YKOLME7R.js.map} +1 -1
  51. package/dist/code-block.js +4 -4
  52. package/dist/code-block.js.map +1 -1
  53. package/dist/combobox.js +2 -2
  54. package/dist/command.js +3 -3
  55. package/dist/command.js.map +1 -1
  56. package/dist/comparison-table.js +2 -2
  57. package/dist/comparison-table.js.map +1 -1
  58. package/dist/countdown.js +1 -1
  59. package/dist/countdown.js.map +1 -1
  60. package/dist/cover-hero.js +15 -6
  61. package/dist/cover-hero.js.map +1 -1
  62. package/dist/dashboard-layout.js +1 -1
  63. package/dist/dashboard-layout.js.map +1 -1
  64. package/dist/data-table.js +5 -5
  65. package/dist/date-picker.js +3 -3
  66. package/dist/date-picker.js.map +1 -1
  67. package/dist/description-list.js +1 -1
  68. package/dist/description-list.js.map +1 -1
  69. package/dist/detail-layout.js +1 -1
  70. package/dist/detail-layout.js.map +1 -1
  71. package/dist/dialog.js +1 -1
  72. package/dist/docs-nav.js +1 -1
  73. package/dist/docs-nav.js.map +1 -1
  74. package/dist/dropdown-menu.js +1 -1
  75. package/dist/dropdown-menu.js.map +1 -1
  76. package/dist/file-upload.js +3 -3
  77. package/dist/file-upload.js.map +1 -1
  78. package/dist/filter-bar.js +2 -2
  79. package/dist/footnote.d.ts +32 -0
  80. package/dist/footnote.js +29 -0
  81. package/dist/footnote.js.map +1 -0
  82. package/dist/genui.js +6 -6
  83. package/dist/geometry-DncHaYP8.d.ts +22 -0
  84. package/dist/language-switch.js +1 -1
  85. package/dist/list.js +1 -1
  86. package/dist/loader.js +2 -2
  87. package/dist/loader.js.map +1 -1
  88. package/dist/map.js +95 -83
  89. package/dist/map.js.map +1 -1
  90. package/dist/marketing-layout.js +1 -1
  91. package/dist/marketing-layout.js.map +1 -1
  92. package/dist/mascot-quote.d.ts +2 -21
  93. package/dist/mascot-quote.js +9 -338
  94. package/dist/mascot-quote.js.map +1 -1
  95. package/dist/match-dialog.js +1 -1
  96. package/dist/match-dialog.js.map +1 -1
  97. package/dist/media-grid.js +1 -1
  98. package/dist/meter.js +3 -3
  99. package/dist/meter.js.map +1 -1
  100. package/dist/motion.css +28 -41
  101. package/dist/native/map.js +94 -82
  102. package/dist/native/map.js.map +1 -1
  103. package/dist/native.d.ts +8 -1
  104. package/dist/native.js +57 -45
  105. package/dist/native.js.map +1 -1
  106. package/dist/nav-bar.js +12 -12
  107. package/dist/nav-bar.js.map +1 -1
  108. package/dist/page-hero.js +1 -1
  109. package/dist/page-index.d.ts +30 -0
  110. package/dist/page-index.js +23 -0
  111. package/dist/page-index.js.map +1 -0
  112. package/dist/page.d.ts +19 -7
  113. package/dist/page.js +1 -1
  114. package/dist/photo-grid.js +2 -2
  115. package/dist/photo-grid.js.map +1 -1
  116. package/dist/progress.js +3 -3
  117. package/dist/progress.js.map +1 -1
  118. package/dist/radio-group.js +1 -1
  119. package/dist/radio-group.js.map +1 -1
  120. package/dist/rail-nav.js +2 -2
  121. package/dist/rail-nav.js.map +1 -1
  122. package/dist/search-field.js +1 -1
  123. package/dist/service-card.js +3 -3
  124. package/dist/service-card.js.map +1 -1
  125. package/dist/settings-layout.js +1 -1
  126. package/dist/settings-layout.js.map +1 -1
  127. package/dist/site-footer.js +3 -3
  128. package/dist/site-footer.js.map +1 -1
  129. package/dist/skip-link.js +1 -1
  130. package/dist/slot-picker.js +1 -1
  131. package/dist/slot-picker.js.map +1 -1
  132. package/dist/specimen-tag.d.ts +52 -0
  133. package/dist/specimen-tag.js +33 -0
  134. package/dist/specimen-tag.js.map +1 -0
  135. package/dist/stat.js +1 -1
  136. package/dist/stat.js.map +1 -1
  137. package/dist/step-progress.js +1 -1
  138. package/dist/step-progress.js.map +1 -1
  139. package/dist/sticky-action.d.ts +1 -1
  140. package/dist/sticky-action.js +1 -1
  141. package/dist/sticky-action.js.map +1 -1
  142. package/dist/swipe-deck.js +1 -1
  143. package/dist/swipe-deck.js.map +1 -1
  144. package/dist/tabs.js +4 -4
  145. package/dist/tabs.js.map +1 -1
  146. package/dist/tag-input.js +2 -2
  147. package/dist/tag-selector.js +1 -1
  148. package/dist/toast.js +1 -1
  149. package/dist/toast.js.map +1 -1
  150. package/package.json +74 -4
  151. package/registry/account-menu.json +1 -1
  152. package/registry/achievement.json +1 -1
  153. package/registry/action-bar.json +1 -1
  154. package/registry/activity-feed.json +2 -2
  155. package/registry/alert.json +1 -1
  156. package/registry/anatomy-plate.json +168 -0
  157. package/registry/app-header.json +2 -2
  158. package/registry/app-shell.json +2 -2
  159. package/registry/argument-card.json +1 -1
  160. package/registry/audio-player.json +1 -1
  161. package/registry/auth-layout.json +1 -1
  162. package/registry/avatar.json +1 -1
  163. package/registry/badge.json +2 -2
  164. package/registry/bird-plate.json +221 -0
  165. package/registry/button.json +1 -1
  166. package/registry/captcha.json +1 -1
  167. package/registry/card-grid.json +1 -1
  168. package/registry/card.json +2 -2
  169. package/registry/catalogue-page.json +1 -1
  170. package/registry/changelog-page.json +1 -1
  171. package/registry/chat.json +3 -3
  172. package/registry/checkbox.json +2 -2
  173. package/registry/chip-link.json +1 -1
  174. package/registry/chip-row.json +2 -2
  175. package/registry/chip.json +2 -2
  176. package/registry/choice-grid.json +1 -1
  177. package/registry/code-block.json +1 -1
  178. package/registry/combobox.json +1 -1
  179. package/registry/command.json +2 -2
  180. package/registry/comparison-table.json +2 -2
  181. package/registry/component-page.json +1 -1
  182. package/registry/confirm-button.json +1 -1
  183. package/registry/contact-page.json +1 -1
  184. package/registry/continue-prompt.json +1 -1
  185. package/registry/countdown.json +2 -2
  186. package/registry/cover-hero.json +2 -2
  187. package/registry/cta-panel.json +1 -1
  188. package/registry/dashboard-layout.json +2 -2
  189. package/registry/data-table.json +1 -1
  190. package/registry/date-picker.json +4 -4
  191. package/registry/decision-list.json +1 -1
  192. package/registry/description-list.json +2 -2
  193. package/registry/detail-layout.json +2 -2
  194. package/registry/dialog.json +2 -2
  195. package/registry/docs-article-page.json +1 -1
  196. package/registry/docs-hub-page.json +1 -1
  197. package/registry/docs-layout.json +1 -1
  198. package/registry/docs-nav.json +2 -2
  199. package/registry/document-viewer.json +1 -1
  200. package/registry/dropdown-menu.json +2 -2
  201. package/registry/empty-state.json +1 -1
  202. package/registry/engine-flow.json +1 -1
  203. package/registry/error-page.json +1 -1
  204. package/registry/examples/action-sheet/native/video-actions.dark.png +0 -0
  205. package/registry/examples/action-sheet/native/video-actions.light.png +0 -0
  206. package/registry/examples/activity-feed/native/notifications.dark.png +0 -0
  207. package/registry/examples/activity-feed/native/notifications.light.png +0 -0
  208. package/registry/examples/anatomy-plate/button.d.ts +4 -0
  209. package/registry/examples/anatomy-plate/button.js +25 -0
  210. package/registry/examples/anatomy-plate/button.tsx +20 -0
  211. package/registry/examples/avatar/native/group.dark.png +0 -0
  212. package/registry/examples/avatar/native/group.light.png +0 -0
  213. package/registry/examples/avatar/native/presence.dark.png +0 -0
  214. package/registry/examples/avatar/native/presence.light.png +0 -0
  215. package/registry/examples/avatar/native/sizes.dark.png +0 -0
  216. package/registry/examples/avatar/native/sizes.light.png +0 -0
  217. package/registry/examples/badge/native/dot.dark.png +0 -0
  218. package/registry/examples/badge/native/dot.light.png +0 -0
  219. package/registry/examples/badge/native/scrim.dark.png +0 -0
  220. package/registry/examples/badge/native/scrim.light.png +0 -0
  221. package/registry/examples/badge/native/tones.dark.png +0 -0
  222. package/registry/examples/badge/native/tones.light.png +0 -0
  223. package/registry/examples/bird-plate/flock.d.ts +4 -0
  224. package/registry/examples/bird-plate/flock.js +24 -0
  225. package/registry/examples/bird-plate/flock.tsx +18 -0
  226. package/registry/examples/bird-plate/single.d.ts +4 -0
  227. package/registry/examples/bird-plate/single.js +19 -0
  228. package/registry/examples/bird-plate/single.tsx +13 -0
  229. package/registry/examples/button/native/danger.dark.png +0 -0
  230. package/registry/examples/button/native/danger.light.png +0 -0
  231. package/registry/examples/button/native/disabled.dark.png +0 -0
  232. package/registry/examples/button/native/disabled.light.png +0 -0
  233. package/registry/examples/button/native/ghost.dark.png +0 -0
  234. package/registry/examples/button/native/ghost.light.png +0 -0
  235. package/registry/examples/button/native/gradient.dark.png +0 -0
  236. package/registry/examples/button/native/gradient.light.png +0 -0
  237. package/registry/examples/button/native/icon-only.dark.png +0 -0
  238. package/registry/examples/button/native/icon-only.light.png +0 -0
  239. package/registry/examples/button/native/icon.dark.png +0 -0
  240. package/registry/examples/button/native/icon.light.png +0 -0
  241. package/registry/examples/button/native/loading.dark.png +0 -0
  242. package/registry/examples/button/native/loading.light.png +0 -0
  243. package/registry/examples/button/native/outline.dark.png +0 -0
  244. package/registry/examples/button/native/outline.light.png +0 -0
  245. package/registry/examples/button/native/primary.dark.png +0 -0
  246. package/registry/examples/button/native/primary.light.png +0 -0
  247. package/registry/examples/button/native/secondary.dark.png +0 -0
  248. package/registry/examples/button/native/secondary.light.png +0 -0
  249. package/registry/examples/button/native/sizes.dark.png +0 -0
  250. package/registry/examples/button/native/sizes.light.png +0 -0
  251. package/registry/examples/card/native/body.dark.png +0 -0
  252. package/registry/examples/card/native/body.light.png +0 -0
  253. package/registry/examples/card/native/default.dark.png +0 -0
  254. package/registry/examples/card/native/default.light.png +0 -0
  255. package/registry/examples/card/native/elevated.dark.png +0 -0
  256. package/registry/examples/card/native/elevated.light.png +0 -0
  257. package/registry/examples/card/native/pressable.dark.png +0 -0
  258. package/registry/examples/card/native/pressable.light.png +0 -0
  259. package/registry/examples/chat/native/assistant.dark.png +0 -0
  260. package/registry/examples/chat/native/assistant.light.png +0 -0
  261. package/registry/examples/chat/native/conversation.dark.png +0 -0
  262. package/registry/examples/chat/native/conversation.light.png +0 -0
  263. package/registry/examples/chat/native/inbox.dark.png +0 -0
  264. package/registry/examples/chat/native/inbox.light.png +0 -0
  265. package/registry/examples/checkbox/native/terms.dark.png +0 -0
  266. package/registry/examples/checkbox/native/terms.light.png +0 -0
  267. package/registry/examples/chip/native/multiple.dark.png +0 -0
  268. package/registry/examples/chip/native/multiple.light.png +0 -0
  269. package/registry/examples/chip/native/removable.dark.png +0 -0
  270. package/registry/examples/chip/native/removable.light.png +0 -0
  271. package/registry/examples/chip/native/single.dark.png +0 -0
  272. package/registry/examples/chip/native/single.light.png +0 -0
  273. package/registry/examples/chip/native/toggle.dark.png +0 -0
  274. package/registry/examples/chip/native/toggle.light.png +0 -0
  275. package/registry/examples/combobox/native/multiple.dark.png +0 -0
  276. package/registry/examples/combobox/native/multiple.light.png +0 -0
  277. package/registry/examples/combobox/native/search.dark.png +0 -0
  278. package/registry/examples/combobox/native/search.light.png +0 -0
  279. package/registry/examples/countdown/native/days.dark.png +0 -0
  280. package/registry/examples/countdown/native/days.light.png +0 -0
  281. package/registry/examples/countdown/native/hours.dark.png +0 -0
  282. package/registry/examples/countdown/native/hours.light.png +0 -0
  283. package/registry/examples/countdown/native/sizes.dark.png +0 -0
  284. package/registry/examples/countdown/native/sizes.light.png +0 -0
  285. package/registry/examples/countdown/native/urgent.dark.png +0 -0
  286. package/registry/examples/countdown/native/urgent.light.png +0 -0
  287. package/registry/examples/countdown/native/with-label.dark.png +0 -0
  288. package/registry/examples/countdown/native/with-label.light.png +0 -0
  289. package/registry/examples/date-picker/native/birth-date-wheel.dark.png +0 -0
  290. package/registry/examples/date-picker/native/birth-date-wheel.light.png +0 -0
  291. package/registry/examples/date-picker/native/birth-date.dark.png +0 -0
  292. package/registry/examples/date-picker/native/birth-date.light.png +0 -0
  293. package/registry/examples/date-picker/native/calendar.dark.png +0 -0
  294. package/registry/examples/date-picker/native/calendar.light.png +0 -0
  295. package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
  296. package/registry/examples/date-picker/native/day-strip.light.png +0 -0
  297. package/registry/examples/date-picker/native/month-year.dark.png +0 -0
  298. package/registry/examples/date-picker/native/month-year.light.png +0 -0
  299. package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
  300. package/registry/examples/date-picker/native/time-slots.light.png +0 -0
  301. package/registry/examples/date-picker/native/time-wheel.dark.png +0 -0
  302. package/registry/examples/date-picker/native/time-wheel.light.png +0 -0
  303. package/registry/examples/description-list/native/job-details.dark.png +0 -0
  304. package/registry/examples/description-list/native/job-details.light.png +0 -0
  305. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  306. package/registry/examples/dialog/native/sheet.light.png +0 -0
  307. package/registry/examples/empty-state/native/default.dark.png +0 -0
  308. package/registry/examples/empty-state/native/default.light.png +0 -0
  309. package/registry/examples/fab/native/extended.dark.png +0 -0
  310. package/registry/examples/fab/native/extended.light.png +0 -0
  311. package/registry/examples/field/native/default.dark.png +0 -0
  312. package/registry/examples/field/native/default.light.png +0 -0
  313. package/registry/examples/field/native/select.dark.png +0 -0
  314. package/registry/examples/field/native/select.light.png +0 -0
  315. package/registry/examples/footnote/notes.d.ts +4 -0
  316. package/registry/examples/footnote/notes.js +24 -0
  317. package/registry/examples/footnote/notes.tsx +19 -0
  318. package/registry/examples/force-update-screen/native/default.dark.png +0 -0
  319. package/registry/examples/force-update-screen/native/default.light.png +0 -0
  320. package/registry/examples/form/native/amount.dark.png +0 -0
  321. package/registry/examples/form/native/amount.light.png +0 -0
  322. package/registry/examples/form/native/audience.dark.png +0 -0
  323. package/registry/examples/form/native/audience.light.png +0 -0
  324. package/registry/examples/form/native/profile.dark.png +0 -0
  325. package/registry/examples/form/native/profile.light.png +0 -0
  326. package/registry/examples/form/native/settings.dark.png +0 -0
  327. package/registry/examples/form/native/settings.light.png +0 -0
  328. package/registry/examples/form/native/sign-up.dark.png +0 -0
  329. package/registry/examples/form/native/sign-up.light.png +0 -0
  330. package/registry/examples/form/native/upload.dark.png +0 -0
  331. package/registry/examples/form/native/upload.light.png +0 -0
  332. package/registry/examples/goal-gauge/native/default.dark.png +0 -0
  333. package/registry/examples/goal-gauge/native/default.light.png +0 -0
  334. package/registry/examples/header/native/large-title.dark.png +0 -0
  335. package/registry/examples/header/native/large-title.light.png +0 -0
  336. package/registry/examples/image-viewer/native/gallery.dark.png +0 -0
  337. package/registry/examples/image-viewer/native/gallery.light.png +0 -0
  338. package/registry/examples/list/native/default.dark.png +0 -0
  339. package/registry/examples/list/native/default.light.png +0 -0
  340. package/registry/examples/list/native/infinite.dark.png +0 -0
  341. package/registry/examples/list/native/infinite.light.png +0 -0
  342. package/registry/examples/list/native/states.dark.png +0 -0
  343. package/registry/examples/list/native/states.light.png +0 -0
  344. package/registry/examples/loader/native/block.dark.png +0 -0
  345. package/registry/examples/loader/native/block.light.png +0 -0
  346. package/registry/examples/loader/native/branded.dark.png +0 -0
  347. package/registry/examples/loader/native/branded.light.png +0 -0
  348. package/registry/examples/loader/native/job-wait.dark.png +0 -0
  349. package/registry/examples/loader/native/job-wait.light.png +0 -0
  350. package/registry/examples/maintenance-screen/native/default.dark.png +0 -0
  351. package/registry/examples/maintenance-screen/native/default.light.png +0 -0
  352. package/registry/examples/map/native/location-picker.dark.png +0 -0
  353. package/registry/examples/map/native/location-picker.light.png +0 -0
  354. package/registry/examples/map/native/places.dark.png +0 -0
  355. package/registry/examples/map/native/places.light.png +0 -0
  356. package/registry/examples/markdown/native/ai-stream.dark.png +0 -0
  357. package/registry/examples/markdown/native/ai-stream.light.png +0 -0
  358. package/registry/examples/markdown/native/basic.dark.png +0 -0
  359. package/registry/examples/markdown/native/basic.light.png +0 -0
  360. package/registry/examples/mascot-state/native/default.dark.png +0 -0
  361. package/registry/examples/mascot-state/native/default.light.png +0 -0
  362. package/registry/examples/mascots/native/crane.dark.png +0 -0
  363. package/registry/examples/mascots/native/crane.light.png +0 -0
  364. package/registry/examples/mascots/native/default.dark.png +0 -0
  365. package/registry/examples/mascots/native/default.light.png +0 -0
  366. package/registry/examples/mascots/native/lovebird.dark.png +0 -0
  367. package/registry/examples/mascots/native/lovebird.light.png +0 -0
  368. package/registry/examples/mascots/native/phoenix.dark.png +0 -0
  369. package/registry/examples/mascots/native/phoenix.light.png +0 -0
  370. package/registry/examples/match-dialog/native/its-a-match.dark.png +0 -0
  371. package/registry/examples/match-dialog/native/its-a-match.light.png +0 -0
  372. package/registry/examples/media-capture/native/photo.dark.png +0 -0
  373. package/registry/examples/media-capture/native/photo.light.png +0 -0
  374. package/registry/examples/media-picker/native/story.dark.png +0 -0
  375. package/registry/examples/media-picker/native/story.light.png +0 -0
  376. package/registry/examples/meta-row/native/video.dark.png +0 -0
  377. package/registry/examples/meta-row/native/video.light.png +0 -0
  378. package/registry/examples/meter/native/credits.dark.png +0 -0
  379. package/registry/examples/meter/native/credits.light.png +0 -0
  380. package/registry/examples/meter/native/split-ring.dark.png +0 -0
  381. package/registry/examples/meter/native/split-ring.light.png +0 -0
  382. package/registry/examples/number-ticker/native/balance.dark.png +0 -0
  383. package/registry/examples/number-ticker/native/balance.light.png +0 -0
  384. package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
  385. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  386. package/registry/examples/otp-input/native/invalid.dark.png +0 -0
  387. package/registry/examples/otp-input/native/invalid.light.png +0 -0
  388. package/registry/examples/otp-input/native/verify.dark.png +0 -0
  389. package/registry/examples/otp-input/native/verify.light.png +0 -0
  390. package/registry/examples/page-index/docs.d.ts +4 -0
  391. package/registry/examples/page-index/docs.js +33 -0
  392. package/registry/examples/page-index/docs.tsx +27 -0
  393. package/registry/examples/pagination/native/cursor.dark.png +0 -0
  394. package/registry/examples/pagination/native/cursor.light.png +0 -0
  395. package/registry/examples/pagination/native/pages.dark.png +0 -0
  396. package/registry/examples/pagination/native/pages.light.png +0 -0
  397. package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
  398. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  399. package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
  400. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  401. package/registry/examples/photo-grid/native/profile-photos.dark.png +0 -0
  402. package/registry/examples/photo-grid/native/profile-photos.light.png +0 -0
  403. package/registry/examples/profile-card/native/default.dark.png +0 -0
  404. package/registry/examples/profile-card/native/default.light.png +0 -0
  405. package/registry/examples/progress/native/bar.dark.png +0 -0
  406. package/registry/examples/progress/native/bar.light.png +0 -0
  407. package/registry/examples/progress/native/indeterminate.dark.png +0 -0
  408. package/registry/examples/progress/native/indeterminate.light.png +0 -0
  409. package/registry/examples/progress/native/ring.dark.png +0 -0
  410. package/registry/examples/progress/native/ring.light.png +0 -0
  411. package/registry/examples/pull-to-refresh/native/branded.dark.png +0 -0
  412. package/registry/examples/pull-to-refresh/native/branded.light.png +0 -0
  413. package/registry/examples/pull-to-refresh/native/feed.dark.png +0 -0
  414. package/registry/examples/pull-to-refresh/native/feed.light.png +0 -0
  415. package/registry/examples/radio-group/native/buttons.dark.png +0 -0
  416. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  417. package/registry/examples/radio-group/native/cards.dark.png +0 -0
  418. package/registry/examples/radio-group/native/cards.light.png +0 -0
  419. package/registry/examples/radio-group/native/list.dark.png +0 -0
  420. package/registry/examples/radio-group/native/list.light.png +0 -0
  421. package/registry/examples/radio-group/native/segmented.dark.png +0 -0
  422. package/registry/examples/radio-group/native/segmented.light.png +0 -0
  423. package/registry/examples/screen/native/app-shell.dark.png +0 -0
  424. package/registry/examples/screen/native/app-shell.light.png +0 -0
  425. package/registry/examples/screen/native/auth.dark.png +0 -0
  426. package/registry/examples/screen/native/auth.light.png +0 -0
  427. package/registry/examples/screen/native/chat.dark.png +0 -0
  428. package/registry/examples/screen/native/chat.light.png +0 -0
  429. package/registry/examples/screen/native/feed.dark.png +0 -0
  430. package/registry/examples/screen/native/feed.light.png +0 -0
  431. package/registry/examples/screen/native/map.dark.png +0 -0
  432. package/registry/examples/screen/native/map.light.png +0 -0
  433. package/registry/examples/screen/native/notifications.dark.png +0 -0
  434. package/registry/examples/screen/native/notifications.light.png +0 -0
  435. package/registry/examples/screen/native/profile.dark.png +0 -0
  436. package/registry/examples/screen/native/profile.light.png +0 -0
  437. package/registry/examples/screen/native/settings.dark.png +0 -0
  438. package/registry/examples/screen/native/settings.light.png +0 -0
  439. package/registry/examples/search-field/native/cancel.dark.png +0 -0
  440. package/registry/examples/search-field/native/cancel.light.png +0 -0
  441. package/registry/examples/search-field/native/default.dark.png +0 -0
  442. package/registry/examples/search-field/native/default.light.png +0 -0
  443. package/registry/examples/segmented/native/default.dark.png +0 -0
  444. package/registry/examples/segmented/native/default.light.png +0 -0
  445. package/registry/examples/segmented/native/small.dark.png +0 -0
  446. package/registry/examples/segmented/native/small.light.png +0 -0
  447. package/registry/examples/settings-layout/native/account.dark.png +0 -0
  448. package/registry/examples/settings-layout/native/account.light.png +0 -0
  449. package/registry/examples/showcase/native/slides.dark.png +0 -0
  450. package/registry/examples/showcase/native/slides.light.png +0 -0
  451. package/registry/examples/skeleton/native/shapes.dark.png +0 -0
  452. package/registry/examples/skeleton/native/shapes.light.png +0 -0
  453. package/registry/examples/slider/native/default.dark.png +0 -0
  454. package/registry/examples/slider/native/default.light.png +0 -0
  455. package/registry/examples/slider/native/range.dark.png +0 -0
  456. package/registry/examples/slider/native/range.light.png +0 -0
  457. package/registry/examples/slider/native/stepped.dark.png +0 -0
  458. package/registry/examples/slider/native/stepped.light.png +0 -0
  459. package/registry/examples/slider/native/vertical.dark.png +0 -0
  460. package/registry/examples/slider/native/vertical.light.png +0 -0
  461. package/registry/examples/specimen-tag/product.d.ts +4 -0
  462. package/registry/examples/specimen-tag/product.js +28 -0
  463. package/registry/examples/specimen-tag/product.tsx +25 -0
  464. package/registry/examples/specimen-tag/stamps.d.ts +4 -0
  465. package/registry/examples/specimen-tag/stamps.js +16 -0
  466. package/registry/examples/specimen-tag/stamps.tsx +13 -0
  467. package/registry/examples/specimen-tag/wire.d.ts +4 -0
  468. package/registry/examples/specimen-tag/wire.js +16 -0
  469. package/registry/examples/specimen-tag/wire.tsx +20 -0
  470. package/registry/examples/spinner/native/sizes.dark.png +0 -0
  471. package/registry/examples/spinner/native/sizes.light.png +0 -0
  472. package/registry/examples/splash-handoff/native/default.dark.png +0 -0
  473. package/registry/examples/splash-handoff/native/default.light.png +0 -0
  474. package/registry/examples/step-progress/native/sign-up.dark.png +0 -0
  475. package/registry/examples/step-progress/native/sign-up.light.png +0 -0
  476. package/registry/examples/stepper/native/run.dark.png +0 -0
  477. package/registry/examples/stepper/native/run.light.png +0 -0
  478. package/registry/examples/swipe-deck/native/discover.dark.png +0 -0
  479. package/registry/examples/swipe-deck/native/discover.light.png +0 -0
  480. package/registry/examples/swipeable-row/native/conversation.dark.png +0 -0
  481. package/registry/examples/swipeable-row/native/conversation.light.png +0 -0
  482. package/registry/examples/switch/native/default.dark.png +0 -0
  483. package/registry/examples/switch/native/default.light.png +0 -0
  484. package/registry/examples/switch/native/settings.dark.png +0 -0
  485. package/registry/examples/switch/native/settings.light.png +0 -0
  486. package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
  487. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  488. package/registry/examples/tabs/native/sections.dark.png +0 -0
  489. package/registry/examples/tabs/native/sections.light.png +0 -0
  490. package/registry/examples/tabs/native/segmented.dark.png +0 -0
  491. package/registry/examples/tabs/native/segmented.light.png +0 -0
  492. package/registry/examples/tag-selector/native/interests.dark.png +0 -0
  493. package/registry/examples/tag-selector/native/interests.light.png +0 -0
  494. package/registry/examples/toast/native/notification.dark.png +0 -0
  495. package/registry/examples/toast/native/notification.light.png +0 -0
  496. package/registry/examples/toast/native/snackbar.dark.png +0 -0
  497. package/registry/examples/toast/native/snackbar.light.png +0 -0
  498. package/registry/examples/toast/native/tones.dark.png +0 -0
  499. package/registry/examples/toast/native/tones.light.png +0 -0
  500. package/registry/examples/txt/native/tones.dark.png +0 -0
  501. package/registry/examples/txt/native/tones.light.png +0 -0
  502. package/registry/examples/txt/native/variants.dark.png +0 -0
  503. package/registry/examples/txt/native/variants.light.png +0 -0
  504. package/registry/examples/update-prompt/native/default.dark.png +0 -0
  505. package/registry/examples/update-prompt/native/default.light.png +0 -0
  506. package/registry/examples/verified-badge/native/verified.dark.png +0 -0
  507. package/registry/examples/verified-badge/native/verified.light.png +0 -0
  508. package/registry/examples/vertical-video/native/rail.dark.png +0 -0
  509. package/registry/examples/vertical-video/native/rail.light.png +0 -0
  510. package/registry/examples/video-player/native/default.dark.png +0 -0
  511. package/registry/examples/video-player/native/default.light.png +0 -0
  512. package/registry/examples/waveform/native/card.dark.png +0 -0
  513. package/registry/examples/waveform/native/card.light.png +0 -0
  514. package/registry/field.json +1 -1
  515. package/registry/file-upload.json +1 -1
  516. package/registry/filter-bar.json +1 -1
  517. package/registry/footnote.json +220 -0
  518. package/registry/force-update-screen.json +1 -1
  519. package/registry/form.json +3 -3
  520. package/registry/gallery-page.json +1 -1
  521. package/registry/genui.json +1 -1
  522. package/registry/glow-card.json +1 -1
  523. package/registry/goal-gauge.json +1 -1
  524. package/registry/how-it-works-page.json +1 -1
  525. package/registry/image-cropper.json +1 -1
  526. package/registry/index.json +160 -5
  527. package/registry/iso.json +1 -1
  528. package/registry/kanban.json +1 -1
  529. package/registry/kbd.json +1 -1
  530. package/registry/landing-page.json +1 -1
  531. package/registry/landscape.json +1 -1
  532. package/registry/language-switch.json +2 -2
  533. package/registry/legal-page.json +1 -1
  534. package/registry/link-card.json +1 -1
  535. package/registry/list.json +1 -1
  536. package/registry/loader.json +2 -2
  537. package/registry/longform-page.json +1 -1
  538. package/registry/maintenance-screen.json +1 -1
  539. package/registry/map.json +3 -3
  540. package/registry/markdown.json +1 -1
  541. package/registry/marketing-layout.json +1 -1
  542. package/registry/marquee.json +1 -1
  543. package/registry/mascot-quote.json +1 -1
  544. package/registry/mascot-state.json +1 -1
  545. package/registry/mascots.json +1 -1
  546. package/registry/match-dialog.json +1 -1
  547. package/registry/media-capture.json +1 -1
  548. package/registry/media-gallery.json +1 -1
  549. package/registry/media-grid.json +1 -1
  550. package/registry/meta-row.json +1 -1
  551. package/registry/meter.json +2 -2
  552. package/registry/nav-bar.json +3 -3
  553. package/registry/number-ticker.json +1 -1
  554. package/registry/opening-hours.json +1 -1
  555. package/registry/page-header.json +1 -1
  556. package/registry/page-hero.json +1 -1
  557. package/registry/page-index.json +168 -0
  558. package/registry/page.json +89 -5
  559. package/registry/pagination.json +1 -1
  560. package/registry/photo-grid.json +2 -2
  561. package/registry/pointer-light.json +1 -1
  562. package/registry/popover.json +1 -1
  563. package/registry/pricing-page.json +1 -1
  564. package/registry/product-page.json +1 -1
  565. package/registry/profile-card.json +1 -1
  566. package/registry/progress.json +2 -2
  567. package/registry/promise-card.json +1 -1
  568. package/registry/radio-group.json +2 -2
  569. package/registry/rail-nav.json +3 -3
  570. package/registry/recipes.json +1 -1
  571. package/registry/scroll-stage.json +1 -1
  572. package/registry/search-field.json +2 -2
  573. package/registry/section-backdrop.json +1 -1
  574. package/registry/separator.json +1 -1
  575. package/registry/service-card.json +2 -2
  576. package/registry/settings-layout.json +2 -2
  577. package/registry/showcase.json +1 -1
  578. package/registry/site-footer.json +3 -3
  579. package/registry/sites.json +1 -1
  580. package/registry/skeleton.json +1 -1
  581. package/registry/skip-link.json +2 -2
  582. package/registry/slider.json +1 -1
  583. package/registry/slot-picker.json +2 -2
  584. package/registry/slot.json +1 -1
  585. package/registry/specimen-tag.json +269 -0
  586. package/registry/spinner.json +1 -1
  587. package/registry/split-view.json +1 -1
  588. package/registry/stage-banner.json +1 -1
  589. package/registry/stat.json +2 -2
  590. package/registry/status-page.json +1 -1
  591. package/registry/step-progress.json +2 -2
  592. package/registry/step-showcase.json +1 -1
  593. package/registry/stepper.json +1 -1
  594. package/registry/sticky-action.json +2 -2
  595. package/registry/swipe-deck.json +2 -2
  596. package/registry/switch.json +1 -1
  597. package/registry/tabs.json +2 -2
  598. package/registry/tag-input.json +1 -1
  599. package/registry/tag-selector.json +1 -1
  600. package/registry/terminal-replay.json +1 -1
  601. package/registry/theme.json +1 -1
  602. package/registry/toast.json +2 -2
  603. package/registry/toc.json +1 -1
  604. package/registry/tooltip.json +1 -1
  605. package/registry/tree-view.json +1 -1
  606. package/registry/update-prompt.json +1 -1
  607. package/registry/verified-badge.json +1 -1
  608. package/registry/vertical-video.json +1 -1
  609. package/registry/video-player.json +1 -1
  610. package/registry/video-trimmer.json +1 -1
  611. package/registry/virtual.json +1 -1
  612. package/registry/waveform.json +1 -1
  613. package/dist/chunk-2PNLHZLT.js.map +0 -1
  614. package/dist/chunk-3S4GHSPZ.js.map +0 -1
  615. package/dist/chunk-LZNZLCOE.js.map +0 -1
  616. package/dist/chunk-NJFCSVPT.js.map +0 -1
  617. package/dist/chunk-QDXV544C.js.map +0 -1
  618. package/dist/chunk-REPTKUJ6.js.map +0 -1
  619. /package/dist/{chunk-CKSHLSDH.js.map → chunk-AAP3U66V.js.map} +0 -0
  620. /package/dist/{chunk-KIBICUZK.js.map → chunk-S5LP7KKW.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/progress/progress.tsx"],"sourcesContent":["// Server-safe: no hook, no context. role=\"progressbar\" with aria-valuenow / aria-valuemax (none when indeterminate),\n// named by `label`. A bar or a ring; the ring can hold content in its centre (an amount, a percentage).\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const progress = tv({\n slots: {\n root: \"relative\",\n track: \"\",\n indicator: \"\",\n center: \"absolute inset-0 flex flex-col items-center justify-center text-center\",\n buffer: \"absolute inset-y-0 left-0 -z-10 rounded-full bg-accent/25 transition-[width] duration-500 motion-reduce:transition-none\",\n frame: \"flex w-full flex-col gap-1.5\",\n header: \"flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs\",\n caption: \"max-w-full shrink-0 grow truncate font-medium text-fg\",\n figure: \"shrink-0 tabular-nums text-fg-secondary\",\n },\n variants: {\n variant: {\n bar: {\n root: \"relative isolate w-full overflow-hidden rounded-full bg-surface-3\",\n indicator:\n \"kz-progress h-full rounded-full bg-linear-to-r from-accent to-accent-2 transition-[width] duration-500 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:w-2/5\",\n },\n ring: {\n root: \"inline-flex shrink-0 items-center justify-center\",\n track: \"stroke-border-default\",\n indicator:\n \"stroke-accent transition-[stroke-dashoffset] duration-1000 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:origin-center data-[state=indeterminate]:animate-spin motion-reduce:data-[state=indeterminate]:animate-none\",\n },\n },\n size: { sm: {}, md: {}, lg: {} },\n status: {\n active: {},\n // Paused: the fill rests, striped — the task is waiting for someone, not broken.\n paused: { indicator: \"kz-progress-paused opacity-70\" },\n // Failed: the fill turns to the danger colour where it stopped.\n error: { indicator: \"from-danger to-danger stroke-danger\" },\n },\n },\n compoundVariants: [\n { variant: \"bar\", size: \"sm\", class: { root: \"h-1\" } },\n { variant: \"bar\", size: \"md\", class: { root: \"h-2\" } },\n { variant: \"bar\", size: \"lg\", class: { root: \"h-3\" } },\n { variant: \"ring\", size: \"sm\", class: { root: \"h-10 w-10\" } },\n { variant: \"ring\", size: \"md\", class: { root: \"h-20 w-20\" } },\n { variant: \"ring\", size: \"lg\", class: { root: \"h-36 w-36\" } },\n ],\n defaultVariants: { variant: \"bar\", size: \"md\", status: \"active\" },\n});\n\nexport type ProgressVariants = VariantProps<typeof progress>;\n\nexport type ProgressProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n ProgressVariants & {\n /** bar · ring (a ring holds its `children` in the centre). */\n variant?: ProgressVariants[\"variant\"];\n /** sm · md · lg: the bar's thickness, the ring's diameter. */\n size?: ProgressVariants[\"size\"];\n /** How far, between 0 and `max`. `null` or absent: indeterminate (a wait of unknown length). */\n value?: number | null;\n /** The value that means complete. */\n max?: number;\n /** The accessible name — passed translated (\"Upload\", \"Raised towards the goal\"). */\n label: string;\n /** The value in words for assistive technology (\"$420 of $1,000\") — default: the percentage. */\n valueText?: string;\n /** A ring's centre: an amount, a percentage, an icon. */\n children?: React.ReactNode;\n /** How far is already available beyond the value (a video buffered ahead), between 0 and `max` — bar only. */\n buffer?: number;\n /** Splits the bar or the ring into this many segments: the steps of a task, the parts of a goal. */\n segments?: number;\n /**\n * active · paused (the fill rests, striped: waiting for someone) · error (the fill turns to the danger colour where it stopped).\n * @default \"active\"\n */\n status?: ProgressVariants[\"status\"];\n /** Shows the label above the bar, with the percentage (or `valueText`) and `eta` — bar only. */\n showLabel?: boolean;\n /** The time left, in words (“About 2 min left”), shown with `showLabel` and read with the value — passed translated. */\n eta?: string;\n };\n\nconst STROKE = { sm: 12, md: 9, lg: 7 } as const;\n\n/** A progress bar or ring: `value` / `max`, indeterminate without a value. State: `data-state` (loading · complete · indeterminate). */\nexport function Progress({\n variant = \"bar\",\n size = \"md\",\n value,\n max = 100,\n label,\n valueText,\n className,\n children,\n buffer,\n segments,\n status = \"active\",\n showLabel,\n eta,\n ...props\n}: ProgressProps) {\n const s = progress({ variant, size, status });\n const maskId = `kz-seg-${React.useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const known = typeof value === \"number\" && Number.isFinite(value);\n const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;\n const percent = Math.round(ratio * 100);\n const state = !known ? \"indeterminate\" : ratio >= 1 ? \"complete\" : \"loading\";\n const aria = {\n role: \"progressbar\" as const,\n \"aria-label\": label,\n \"aria-valuemin\": known ? 0 : undefined,\n \"aria-valuemax\": known ? max : undefined,\n \"aria-valuenow\": known ? Math.min(max, Math.max(0, value)) : undefined,\n \"aria-valuetext\": [known ? (valueText ?? `${percent}%`) : valueText, eta].filter(Boolean).join(\", \") || undefined,\n \"data-state\": state,\n \"data-status\": status === \"active\" ? undefined : status,\n \"data-value\": known ? value : undefined,\n \"data-variant\": variant,\n };\n if (variant === \"ring\") {\n const stroke = STROKE[size];\n const r = 50 - stroke / 2;\n return (\n <div {...aria} className={s.root({ className })} {...props}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full w-full -rotate-90\" aria-hidden>\n {segments && segments > 1 && (\n <mask id={maskId}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" stroke=\"white\" strokeWidth={stroke + 2} pathLength={100} strokeDasharray={`${100 / segments - 2} 2`} />\n </mask>\n )}\n <g mask={segments && segments > 1 ? `url(#${maskId})` : undefined}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" strokeWidth={stroke} className={s.track()} />\n <circle\n cx=\"50\"\n cy=\"50\"\n r={r}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n pathLength={100}\n strokeDasharray={100}\n strokeDashoffset={known ? 100 - percent : 75}\n data-state={state}\n className={s.indicator()}\n />\n </g>\n </svg>\n {children !== undefined && <div className={s.center()}>{children}</div>}\n </div>\n );\n }\n const segmented = segments && segments > 1 ? ({ \"--kz-segments\": segments } as React.CSSProperties) : undefined;\n const bufferRatio = typeof buffer === \"number\" && Number.isFinite(buffer) ? Math.min(1, Math.max(0, buffer / (max || 1))) : null;\n const bar = (\n <div {...aria} className={s.root({ className: [segmented && \"kz-progress-segmented\", className].filter(Boolean).join(\" \") || undefined })} style={segmented} {...props}>\n <div data-state={state} className={s.indicator()} style={known ? { width: `${ratio * 100}%` } : undefined} />\n {bufferRatio !== null && <div aria-hidden className={s.buffer()} style={{ width: `${bufferRatio * 100}%` }} />}\n </div>\n );\n if (!showLabel) return bar;\n const figure = [known ? (valueText ?? `${percent} %`) : valueText, eta].filter(Boolean).join(\" · \");\n return (\n <div className={s.frame()}>\n <div aria-hidden className={s.header()}>\n <span className={s.caption()}>{label}</span>\n {figure && <span className={s.figure()}>{figure}</span>}\n </div>\n {bar}\n </div>\n );\n}\n"],"mappings":";AAEA,YAAY,WAAW;AACvB,SAAS,UAA6B;AAgIxB,cAGJ,YAHI;AA9HP,IAAM,WAAW,GAAG;AAAA,EACzB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,MACP,KAAK;AAAA,QACH,MAAM;AAAA,QACN,WACE;AAAA,MAEJ;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,OAAO;AAAA,QACP,WACE;AAAA,MAEJ;AAAA,IACF;AAAA,IACA,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE;AAAA,IAC/B,QAAQ;AAAA,MACN,QAAQ,CAAC;AAAA;AAAA,MAET,QAAQ,EAAE,WAAW,gCAAgC;AAAA;AAAA,MAErD,OAAO,EAAE,WAAW,sCAAsC;AAAA,IAC5D;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB,EAAE,SAAS,OAAO,MAAM,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,IACrD,EAAE,SAAS,OAAO,MAAM,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,IACrD,EAAE,SAAS,OAAO,MAAM,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,IACrD,EAAE,SAAS,QAAQ,MAAM,MAAM,OAAO,EAAE,MAAM,YAAY,EAAE;AAAA,IAC5D,EAAE,SAAS,QAAQ,MAAM,MAAM,OAAO,EAAE,MAAM,YAAY,EAAE;AAAA,IAC5D,EAAE,SAAS,QAAQ,MAAM,MAAM,OAAO,EAAE,MAAM,YAAY,EAAE;AAAA,EAC9D;AAAA,EACA,iBAAiB,EAAE,SAAS,OAAO,MAAM,MAAM,QAAQ,SAAS;AAClE,CAAC;AAmCD,IAAM,SAAS,EAAE,IAAI,IAAI,IAAI,GAAG,IAAI,EAAE;AAG/B,SAAS,SAAS;AAAA,EACvB,UAAU;AAAA,EACV,OAAO;AAAA,EACP;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkB;AAChB,QAAM,IAAI,SAAS,EAAE,SAAS,MAAM,OAAO,CAAC;AAC5C,QAAM,SAAS,UAAgB,YAAM,EAAE,QAAQ,mBAAmB,EAAE,CAAC;AACrE,QAAM,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AAChE,QAAM,QAAQ,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,SAAS,OAAO,EAAE,CAAC,IAAI;AACrE,QAAM,UAAU,KAAK,MAAM,QAAQ,GAAG;AACtC,QAAM,QAAQ,CAAC,QAAQ,kBAAkB,SAAS,IAAI,aAAa;AACnE,QAAM,OAAO;AAAA,IACX,MAAM;AAAA,IACN,cAAc;AAAA,IACd,iBAAiB,QAAQ,IAAI;AAAA,IAC7B,iBAAiB,QAAQ,MAAM;AAAA,IAC/B,iBAAiB,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI;AAAA,IAC7D,kBAAkB,CAAC,QAAS,aAAa,GAAG,OAAO,MAAO,WAAW,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,KAAK;AAAA,IACxG,cAAc;AAAA,IACd,eAAe,WAAW,WAAW,SAAY;AAAA,IACjD,cAAc,QAAQ,QAAQ;AAAA,IAC9B,gBAAgB;AAAA,EAClB;AACA,MAAI,YAAY,QAAQ;AACtB,UAAM,SAAS,OAAO,IAAI;AAC1B,UAAM,IAAI,KAAK,SAAS;AACxB,WACE,qBAAC,SAAK,GAAG,MAAM,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACnD;AAAA,2BAAC,SAAI,SAAQ,eAAc,WAAU,4BAA2B,eAAW,MACxE;AAAA,oBAAY,WAAW,KACtB,oBAAC,UAAK,IAAI,QACR,8BAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAM,MAAK,QAAO,QAAO,SAAQ,aAAa,SAAS,GAAG,YAAY,KAAK,iBAAiB,GAAG,MAAM,WAAW,CAAC,MAAM,GACjJ;AAAA,QAEF,qBAAC,OAAE,MAAM,YAAY,WAAW,IAAI,QAAQ,MAAM,MAAM,QACxD;AAAA,8BAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAM,MAAK,QAAO,aAAa,QAAQ,WAAW,EAAE,MAAM,GAAG;AAAA,UACrF;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,IAAG;AAAA,cACH;AAAA,cACA,MAAK;AAAA,cACL,aAAa;AAAA,cACb,eAAc;AAAA,cACd,YAAY;AAAA,cACZ,iBAAiB;AAAA,cACjB,kBAAkB,QAAQ,MAAM,UAAU;AAAA,cAC1C,cAAY;AAAA,cACZ,WAAW,EAAE,UAAU;AAAA;AAAA,UACzB;AAAA,WACA;AAAA,SACF;AAAA,MACC,aAAa,UAAa,oBAAC,SAAI,WAAW,EAAE,OAAO,GAAI,UAAS;AAAA,OACnE;AAAA,EAEJ;AACA,QAAM,YAAY,YAAY,WAAW,IAAK,EAAE,iBAAiB,SAAS,IAA4B;AACtG,QAAM,cAAc,OAAO,WAAW,YAAY,OAAO,SAAS,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,UAAU,OAAO,EAAE,CAAC,IAAI;AAC5H,QAAM,MACJ,qBAAC,SAAK,GAAG,MAAM,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,aAAa,yBAAyB,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK,OAAU,CAAC,GAAG,OAAO,WAAY,GAAG,OAC/J;AAAA,wBAAC,SAAI,cAAY,OAAO,WAAW,EAAE,UAAU,GAAG,OAAO,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,IAAI,QAAW;AAAA,IAC1G,gBAAgB,QAAQ,oBAAC,SAAI,eAAW,MAAC,WAAW,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,GAAG;AAAA,KAC9G;AAEF,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,SAAS,CAAC,QAAS,aAAa,GAAG,OAAO,OAAQ,WAAW,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK;AAClG,SACE,qBAAC,SAAI,WAAW,EAAE,MAAM,GACtB;AAAA,yBAAC,SAAI,eAAW,MAAC,WAAW,EAAE,OAAO,GACnC;AAAA,0BAAC,UAAK,WAAW,EAAE,QAAQ,GAAI,iBAAM;AAAA,MACpC,UAAU,oBAAC,UAAK,WAAW,EAAE,OAAO,GAAI,kBAAO;AAAA,OAClD;AAAA,IACC;AAAA,KACH;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/progress/progress.tsx"],"sourcesContent":["// Server-safe: no hook, no context. role=\"progressbar\" with aria-valuenow / aria-valuemax (none when indeterminate),\n// named by `label`. A bar or a ring; the ring can hold content in its centre (an amount, a percentage).\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nexport const progress = tv({\n slots: {\n root: \"relative\",\n track: \"\",\n indicator: \"\",\n center: \"absolute inset-0 flex flex-col items-center justify-center text-center\",\n buffer: \"absolute inset-y-0 left-0 -z-10 rounded-sm bg-accent/25 transition-[width] duration-500 motion-reduce:transition-none\",\n frame: \"flex w-full flex-col gap-1.5\",\n header: \"flex flex-wrap items-baseline gap-x-2 gap-y-0.5 text-xs\",\n caption: \"max-w-full shrink-0 grow truncate font-medium text-fg\",\n figure: \"shrink-0 tabular-nums text-fg-secondary\",\n },\n variants: {\n variant: {\n bar: {\n root: \"relative isolate w-full overflow-hidden rounded-sm bg-surface-3\",\n indicator:\n \"kz-progress h-full rounded-sm bg-linear-to-r from-accent to-accent-2 transition-[width] duration-500 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:w-2/5\",\n },\n ring: {\n root: \"inline-flex shrink-0 items-center justify-center\",\n track: \"stroke-border-default\",\n indicator:\n \"stroke-accent transition-[stroke-dashoffset] duration-1000 motion-reduce:transition-none \" +\n \"data-[state=indeterminate]:origin-center data-[state=indeterminate]:animate-spin motion-reduce:data-[state=indeterminate]:animate-none\",\n },\n },\n size: { sm: {}, md: {}, lg: {} },\n status: {\n active: {},\n // Paused: the fill rests, striped — the task is waiting for someone, not broken.\n paused: { indicator: \"kz-progress-paused opacity-70\" },\n // Failed: the fill turns to the danger colour where it stopped.\n error: { indicator: \"from-danger to-danger stroke-danger\" },\n },\n },\n compoundVariants: [\n { variant: \"bar\", size: \"sm\", class: { root: \"h-1\" } },\n { variant: \"bar\", size: \"md\", class: { root: \"h-2\" } },\n { variant: \"bar\", size: \"lg\", class: { root: \"h-3\" } },\n { variant: \"ring\", size: \"sm\", class: { root: \"h-10 w-10\" } },\n { variant: \"ring\", size: \"md\", class: { root: \"h-20 w-20\" } },\n { variant: \"ring\", size: \"lg\", class: { root: \"h-36 w-36\" } },\n ],\n defaultVariants: { variant: \"bar\", size: \"md\", status: \"active\" },\n});\n\nexport type ProgressVariants = VariantProps<typeof progress>;\n\nexport type ProgressProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n ProgressVariants & {\n /** bar · ring (a ring holds its `children` in the centre). */\n variant?: ProgressVariants[\"variant\"];\n /** sm · md · lg: the bar's thickness, the ring's diameter. */\n size?: ProgressVariants[\"size\"];\n /** How far, between 0 and `max`. `null` or absent: indeterminate (a wait of unknown length). */\n value?: number | null;\n /** The value that means complete. */\n max?: number;\n /** The accessible name — passed translated (\"Upload\", \"Raised towards the goal\"). */\n label: string;\n /** The value in words for assistive technology (\"$420 of $1,000\") — default: the percentage. */\n valueText?: string;\n /** A ring's centre: an amount, a percentage, an icon. */\n children?: React.ReactNode;\n /** How far is already available beyond the value (a video buffered ahead), between 0 and `max` — bar only. */\n buffer?: number;\n /** Splits the bar or the ring into this many segments: the steps of a task, the parts of a goal. */\n segments?: number;\n /**\n * active · paused (the fill rests, striped: waiting for someone) · error (the fill turns to the danger colour where it stopped).\n * @default \"active\"\n */\n status?: ProgressVariants[\"status\"];\n /** Shows the label above the bar, with the percentage (or `valueText`) and `eta` — bar only. */\n showLabel?: boolean;\n /** The time left, in words (“About 2 min left”), shown with `showLabel` and read with the value — passed translated. */\n eta?: string;\n };\n\nconst STROKE = { sm: 12, md: 9, lg: 7 } as const;\n\n/** A progress bar or ring: `value` / `max`, indeterminate without a value. State: `data-state` (loading · complete · indeterminate). */\nexport function Progress({\n variant = \"bar\",\n size = \"md\",\n value,\n max = 100,\n label,\n valueText,\n className,\n children,\n buffer,\n segments,\n status = \"active\",\n showLabel,\n eta,\n ...props\n}: ProgressProps) {\n const s = progress({ variant, size, status });\n const maskId = `kz-seg-${React.useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n const known = typeof value === \"number\" && Number.isFinite(value);\n const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;\n const percent = Math.round(ratio * 100);\n const state = !known ? \"indeterminate\" : ratio >= 1 ? \"complete\" : \"loading\";\n const aria = {\n role: \"progressbar\" as const,\n \"aria-label\": label,\n \"aria-valuemin\": known ? 0 : undefined,\n \"aria-valuemax\": known ? max : undefined,\n \"aria-valuenow\": known ? Math.min(max, Math.max(0, value)) : undefined,\n \"aria-valuetext\": [known ? (valueText ?? `${percent}%`) : valueText, eta].filter(Boolean).join(\", \") || undefined,\n \"data-state\": state,\n \"data-status\": status === \"active\" ? undefined : status,\n \"data-value\": known ? value : undefined,\n \"data-variant\": variant,\n };\n if (variant === \"ring\") {\n const stroke = STROKE[size];\n const r = 50 - stroke / 2;\n return (\n <div {...aria} className={s.root({ className })} {...props}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full w-full -rotate-90\" aria-hidden>\n {segments && segments > 1 && (\n <mask id={maskId}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" stroke=\"white\" strokeWidth={stroke + 2} pathLength={100} strokeDasharray={`${100 / segments - 2} 2`} />\n </mask>\n )}\n <g mask={segments && segments > 1 ? `url(#${maskId})` : undefined}>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" strokeWidth={stroke} className={s.track()} />\n <circle\n cx=\"50\"\n cy=\"50\"\n r={r}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n pathLength={100}\n strokeDasharray={100}\n strokeDashoffset={known ? 100 - percent : 75}\n data-state={state}\n className={s.indicator()}\n />\n </g>\n </svg>\n {children !== undefined && <div className={s.center()}>{children}</div>}\n </div>\n );\n }\n const segmented = segments && segments > 1 ? ({ \"--kz-segments\": segments } as React.CSSProperties) : undefined;\n const bufferRatio = typeof buffer === \"number\" && Number.isFinite(buffer) ? Math.min(1, Math.max(0, buffer / (max || 1))) : null;\n const bar = (\n <div {...aria} className={s.root({ className: [segmented && \"kz-progress-segmented\", className].filter(Boolean).join(\" \") || undefined })} style={segmented} {...props}>\n <div data-state={state} className={s.indicator()} style={known ? { width: `${ratio * 100}%` } : undefined} />\n {bufferRatio !== null && <div aria-hidden className={s.buffer()} style={{ width: `${bufferRatio * 100}%` }} />}\n </div>\n );\n if (!showLabel) return bar;\n const figure = [known ? (valueText ?? `${percent} %`) : valueText, eta].filter(Boolean).join(\" · \");\n return (\n <div className={s.frame()}>\n <div aria-hidden className={s.header()}>\n <span className={s.caption()}>{label}</span>\n {figure && <span className={s.figure()}>{figure}</span>}\n </div>\n {bar}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -18,7 +18,7 @@ var radioGroup = tv({
18
18
  root: "grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap",
19
19
  item: "peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-strong bg-surface-1 inset-shadow-well transition-colors focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger",
20
20
  dot: "h-2 w-2 rounded-full bg-on-accent",
21
- label: "flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-60",
21
+ label: "flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70",
22
22
  card: "group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow",
23
23
  // The card's check: an empty ring at rest, the accent filled with its check once chosen.
24
24
  cardCheck: "absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-strong bg-surface-1 text-on-accent transition-colors group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/radio-group/radio-group.tsx"],"sourcesContent":["// Client (a context). Radix RadioGroup: role=\"radiogroup\" / \"radio\", one tab stop, the arrows move and select, a\n// hidden input inside a form. Four looks, one behaviour:\n// - `RadioGroup.Item`: a dot and its words (a settings list);\n// - `RadioGroup.Card`: a whole card is the radio — an amount, a pack, a plan — its check lit when chosen;\n// - `RadioGroup.Button`: a tactile key that presses in — raised on a ledge, sunk when chosen (a size, a tip, a level);\n// - `RadioGroup.Segment` in `<RadioGroup.Root variant=\"segmented\">`: a segmented control, one light gliding to the choice.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { CheckGlyph } from \"../glyphs\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { tv } from \"../tv\";\n\nexport const radioGroup = tv({\n slots: {\n root: \"grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap\",\n item:\n \"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-strong bg-surface-1 inset-shadow-well transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger\",\n dot: \"h-2 w-2 rounded-full bg-on-accent\",\n label: \"flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-60\",\n card:\n \"group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge \" +\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow\",\n // The card's check: an empty ring at rest, the accent filled with its check once chosen.\n cardCheck:\n \"absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-strong bg-surface-1 text-on-accent transition-colors \" +\n \"group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent\",\n // The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.\n button:\n \"relative inline-flex min-h-12 min-w-12 select-none flex-col items-center justify-center gap-0.5 rounded-xl border border-border-default bg-surface-2 bg-sheen px-4 py-2 \" +\n \"text-sm font-semibold text-fg inset-shadow-edge shadow-[0_4px_0_0_var(--kz-border-strong)] \" +\n \"transition-[transform,box-shadow,background-color,border-color,color] duration-100 ease-out motion-reduce:transition-none \" +\n \"hover:border-border-strong \" +\n \"active:translate-y-[3px] active:shadow-[0_1px_0_0_var(--kz-border-strong)] \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:translate-y-[3px] data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:bg-fill-shade \" +\n \"data-[state=checked]:text-on-accent data-[state=checked]:inset-shadow-edge-fill data-[state=checked]:shadow-[0_1px_0_0_var(--kz-accent-hover)]\",\n buttonHint: \"text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent\",\n segmented:\n \"relative isolate inline-grid auto-cols-fr grid-flow-col gap-1 rounded-xl border border-border-default bg-surface-2 p-1 inset-shadow-well \" +\n \"before:pointer-events-none before:absolute before:left-0 before:top-0 before:-z-10 before:h-(--kz-ind-h) before:w-(--kz-ind-w) \" +\n \"before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:border before:border-border-default before:bg-surface-0 before:bg-sheen \" +\n \"before:opacity-0 before:shadow-raised before:transition-[translate,width,height,opacity] before:duration-300 motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n segment:\n \"inline-flex min-h-9 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3.5 text-sm font-semibold text-fg-secondary transition-colors \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border data-[state=checked]:border-border-default data-[state=checked]:bg-surface-0 data-[state=checked]:text-fg data-[state=checked]:shadow-raised \" +\n \"group-data-[indicator=on]/seg:data-[state=checked]:border-transparent group-data-[indicator=on]/seg:data-[state=checked]:bg-transparent group-data-[indicator=on]/seg:data-[state=checked]:shadow-none\",\n },\n variants: {\n variant: {\n list: {},\n cards: { root: \"grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-3\" },\n buttons: { root: \"flex flex-wrap gap-2.5 pb-1\" },\n segmented: {},\n },\n },\n defaultVariants: { variant: \"list\" },\n});\nconst s = radioGroup();\n\nexport type RadioGroupRootProps = React.ComponentProps<typeof RadioGroupPrimitive.Root> & {\n /** The group's accessible name — passed translated (or `aria-labelledby` a visible heading). */\n label?: string;\n /** Marks every radio invalid: aria-invalid (pair it with a `Field.Error`). */\n invalid?: boolean;\n /**\n * The layout of the radios: `list` (dots), `cards` (a grid of `Card`s), `buttons` (a row of tactile `Button`s), or\n * `segmented` (a track of `Segment`s, one light gliding to the choice).\n * @default \"list\"\n */\n variant?: \"list\" | \"cards\" | \"buttons\" | \"segmented\";\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation`, `required`, `name` for a form, `variant` for the layout. */\nexport function RadioGroupRoot({ label, invalid, variant = \"list\", className, ...props }: RadioGroupRootProps) {\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=radio]\", active: \"[role=radio][data-state=checked]\" });\n const segmented = variant === \"segmented\";\n return (\n <RadioGroupPrimitive.Root\n ref={segmented ? ref : undefined}\n aria-label={label}\n aria-invalid={invalid || undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-variant={variant}\n orientation={segmented ? \"horizontal\" : props.orientation}\n className={segmented ? s.segmented({ className: [\"group/seg\", className].filter(Boolean).join(\" \") }) : radioGroup({ variant }).root({ className })}\n {...props}\n />\n );\n}\n\nexport type RadioGroupItemProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Item>, \"children\"> & {\n /** The words next to the dot, clickable. Otherwise name it with `Field.Label htmlFor` or `aria-label`. */\n children?: React.ReactNode;\n};\n\n/** A radio: a dot, and its words when given. */\nexport function RadioGroupItem({ className, children, ...props }: RadioGroupItemProps) {\n const item = (\n <RadioGroupPrimitive.Item className={s.item({ className: children ? \"mt-0.5\" : className })} {...props}>\n <RadioGroupPrimitive.Indicator className={s.dot()} />\n </RadioGroupPrimitive.Item>\n );\n if (!children) return item;\n return (\n <label className={s.label({ className })}>\n {item}\n <span className=\"min-w-0\">{children}</span>\n </label>\n );\n}\n\n/** A whole card as the radio: its content is the radio's name; its check lights up when chosen. */\nexport function RadioGroupCard({ className, children, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item className={s.card({ className })} {...props}>\n {children}\n <span aria-hidden className={s.cardCheck()}>\n <RadioGroupPrimitive.Indicator forceMount className=\"inline-flex data-[state=unchecked]:hidden\">\n <CheckGlyph className=\"h-3 w-3\" />\n </RadioGroupPrimitive.Indicator>\n </span>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport type RadioGroupButtonProps = React.ComponentProps<typeof RadioGroupPrimitive.Item> & {\n /** A second line under the words (\"+15 %\"), part of the radio's name. */\n hint?: React.ReactNode;\n};\n\n/** A tactile key: raised on its ledge, pressed in while held and once chosen — sizes, a tip, a level. */\nexport function RadioGroupButton({ className, children, hint, ...props }: RadioGroupButtonProps) {\n return (\n <RadioGroupPrimitive.Item className={s.button({ className: [\"group\", className].filter(Boolean).join(\" \") })} {...props}>\n <span>{children}</span>\n {hint ? <span className={s.buttonHint()}>{hint}</span> : null}\n </RadioGroupPrimitive.Item>\n );\n}\n\n/** A segment of a `variant=\"segmented\"` group: equal widths, one light gliding to the choice. */\nexport function RadioGroupSegment({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return <RadioGroupPrimitive.Item className={s.segment({ className })} {...props} />;\n}\n\n/** `RadioGroup.Root/Item/Card/Button/Segment`. */\nexport const RadioGroup = { Root: RadioGroupRoot, Item: RadioGroupItem, Card: RadioGroupCard, Button: RadioGroupButton, Segment: RadioGroupSegment };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/radio-group/radio-group.tsx"],"sourcesContent":["// Client (a context). Radix RadioGroup: role=\"radiogroup\" / \"radio\", one tab stop, the arrows move and select, a\n// hidden input inside a form. Four looks, one behaviour:\n// - `RadioGroup.Item`: a dot and its words (a settings list);\n// - `RadioGroup.Card`: a whole card is the radio — an amount, a pack, a plan — its check lit when chosen;\n// - `RadioGroup.Button`: a tactile key that presses in — raised on a ledge, sunk when chosen (a size, a tip, a level);\n// - `RadioGroup.Segment` in `<RadioGroup.Root variant=\"segmented\">`: a segmented control, one light gliding to the choice.\nimport { RadioGroup as RadioGroupPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { CheckGlyph } from \"../glyphs\";\nimport { useSlidingIndicator } from \"../sliding-indicator\";\nimport { tv } from \"../tv\";\n\nexport const radioGroup = tv({\n slots: {\n root: \"grid gap-2 data-[orientation=horizontal]:flex data-[orientation=horizontal]:flex-wrap\",\n item:\n \"peer inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-border-strong bg-surface-1 inset-shadow-well transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring hover:border-accent disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:shadow-glow aria-invalid:border-danger\",\n dot: \"h-2 w-2 rounded-full bg-on-accent\",\n label: \"flex cursor-pointer items-start gap-3 text-sm text-fg has-disabled:cursor-not-allowed has-disabled:opacity-70\",\n card:\n \"group relative flex min-w-0 flex-col items-start gap-1 rounded-2xl border border-border-default bg-surface-1 bg-sheen p-4 pr-10 text-left text-sm text-fg inset-shadow-edge \" +\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 hover:border-border-strong active:scale-[0.99] motion-reduce:transition-none motion-reduce:active:scale-100 \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:border-accent data-[state=checked]:bg-accent-soft data-[state=checked]:shadow-glow\",\n // The card's check: an empty ring at rest, the accent filled with its check once chosen.\n cardCheck:\n \"absolute right-3.5 top-3.5 inline-flex h-5 w-5 items-center justify-center rounded-full border border-border-strong bg-surface-1 text-on-accent transition-colors \" +\n \"group-data-[state=checked]:border-accent group-data-[state=checked]:bg-accent\",\n // The tactile key: on a ledge (its lower edge), its hairline stronger on hover, pressed in while held and once chosen.\n button:\n \"relative inline-flex min-h-12 min-w-12 select-none flex-col items-center justify-center gap-0.5 rounded-xl border border-border-default bg-surface-2 bg-sheen px-4 py-2 \" +\n \"text-sm font-semibold text-fg inset-shadow-edge shadow-[0_4px_0_0_var(--kz-border-strong)] \" +\n \"transition-[transform,box-shadow,background-color,border-color,color] duration-100 ease-out motion-reduce:transition-none \" +\n \"hover:border-border-strong \" +\n \"active:translate-y-[3px] active:shadow-[0_1px_0_0_var(--kz-border-strong)] \" +\n \"focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 aria-invalid:border-danger \" +\n \"data-[state=checked]:translate-y-[3px] data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=checked]:bg-fill-shade \" +\n \"data-[state=checked]:text-on-accent data-[state=checked]:inset-shadow-edge-fill data-[state=checked]:shadow-[0_1px_0_0_var(--kz-accent-hover)]\",\n buttonHint: \"text-[11px] font-medium text-fg-secondary group-data-[state=checked]:text-on-accent\",\n segmented:\n \"relative isolate inline-grid auto-cols-fr grid-flow-col gap-1 rounded-xl border border-border-default bg-surface-2 p-1 inset-shadow-well \" +\n \"before:pointer-events-none before:absolute before:left-0 before:top-0 before:-z-10 before:h-(--kz-ind-h) before:w-(--kz-ind-w) \" +\n \"before:translate-x-(--kz-ind-x) before:translate-y-(--kz-ind-y) before:rounded-lg before:border before:border-border-default before:bg-surface-0 before:bg-sheen \" +\n \"before:opacity-0 before:shadow-raised before:transition-[translate,width,height,opacity] before:duration-300 motion-reduce:before:transition-none data-[indicator=on]:before:opacity-100\",\n segment:\n \"inline-flex min-h-9 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3.5 text-sm font-semibold text-fg-secondary transition-colors \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring disabled:cursor-not-allowed disabled:opacity-40 \" +\n \"data-[state=checked]:border data-[state=checked]:border-border-default data-[state=checked]:bg-surface-0 data-[state=checked]:text-fg data-[state=checked]:shadow-raised \" +\n \"group-data-[indicator=on]/seg:data-[state=checked]:border-transparent group-data-[indicator=on]/seg:data-[state=checked]:bg-transparent group-data-[indicator=on]/seg:data-[state=checked]:shadow-none\",\n },\n variants: {\n variant: {\n list: {},\n cards: { root: \"grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-3\" },\n buttons: { root: \"flex flex-wrap gap-2.5 pb-1\" },\n segmented: {},\n },\n },\n defaultVariants: { variant: \"list\" },\n});\nconst s = radioGroup();\n\nexport type RadioGroupRootProps = React.ComponentProps<typeof RadioGroupPrimitive.Root> & {\n /** The group's accessible name — passed translated (or `aria-labelledby` a visible heading). */\n label?: string;\n /** Marks every radio invalid: aria-invalid (pair it with a `Field.Error`). */\n invalid?: boolean;\n /**\n * The layout of the radios: `list` (dots), `cards` (a grid of `Card`s), `buttons` (a row of tactile `Button`s), or\n * `segmented` (a track of `Segment`s, one light gliding to the choice).\n * @default \"list\"\n */\n variant?: \"list\" | \"cards\" | \"buttons\" | \"segmented\";\n};\n\n/** `value`/`defaultValue` + `onValueChange`, `orientation`, `required`, `name` for a form, `variant` for the layout. */\nexport function RadioGroupRoot({ label, invalid, variant = \"list\", className, ...props }: RadioGroupRootProps) {\n const { ref } = useSlidingIndicator<HTMLDivElement>({ item: \"[role=radio]\", active: \"[role=radio][data-state=checked]\" });\n const segmented = variant === \"segmented\";\n return (\n <RadioGroupPrimitive.Root\n ref={segmented ? ref : undefined}\n aria-label={label}\n aria-invalid={invalid || undefined}\n data-invalid={invalid ? \"\" : undefined}\n data-variant={variant}\n orientation={segmented ? \"horizontal\" : props.orientation}\n className={segmented ? s.segmented({ className: [\"group/seg\", className].filter(Boolean).join(\" \") }) : radioGroup({ variant }).root({ className })}\n {...props}\n />\n );\n}\n\nexport type RadioGroupItemProps = Omit<React.ComponentProps<typeof RadioGroupPrimitive.Item>, \"children\"> & {\n /** The words next to the dot, clickable. Otherwise name it with `Field.Label htmlFor` or `aria-label`. */\n children?: React.ReactNode;\n};\n\n/** A radio: a dot, and its words when given. */\nexport function RadioGroupItem({ className, children, ...props }: RadioGroupItemProps) {\n const item = (\n <RadioGroupPrimitive.Item className={s.item({ className: children ? \"mt-0.5\" : className })} {...props}>\n <RadioGroupPrimitive.Indicator className={s.dot()} />\n </RadioGroupPrimitive.Item>\n );\n if (!children) return item;\n return (\n <label className={s.label({ className })}>\n {item}\n <span className=\"min-w-0\">{children}</span>\n </label>\n );\n}\n\n/** A whole card as the radio: its content is the radio's name; its check lights up when chosen. */\nexport function RadioGroupCard({ className, children, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item className={s.card({ className })} {...props}>\n {children}\n <span aria-hidden className={s.cardCheck()}>\n <RadioGroupPrimitive.Indicator forceMount className=\"inline-flex data-[state=unchecked]:hidden\">\n <CheckGlyph className=\"h-3 w-3\" />\n </RadioGroupPrimitive.Indicator>\n </span>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport type RadioGroupButtonProps = React.ComponentProps<typeof RadioGroupPrimitive.Item> & {\n /** A second line under the words (\"+15 %\"), part of the radio's name. */\n hint?: React.ReactNode;\n};\n\n/** A tactile key: raised on its ledge, pressed in while held and once chosen — sizes, a tip, a level. */\nexport function RadioGroupButton({ className, children, hint, ...props }: RadioGroupButtonProps) {\n return (\n <RadioGroupPrimitive.Item className={s.button({ className: [\"group\", className].filter(Boolean).join(\" \") })} {...props}>\n <span>{children}</span>\n {hint ? <span className={s.buttonHint()}>{hint}</span> : null}\n </RadioGroupPrimitive.Item>\n );\n}\n\n/** A segment of a `variant=\"segmented\"` group: equal widths, one light gliding to the choice. */\nexport function RadioGroupSegment({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return <RadioGroupPrimitive.Item className={s.segment({ className })} {...props} />;\n}\n\n/** `RadioGroup.Root/Item/Card/Button/Segment`. */\nexport const RadioGroup = { Root: RadioGroupRoot, Item: RadioGroupItem, Card: RadioGroupCard, Button: RadioGroupButton, Segment: RadioGroupSegment };\n"],"mappings":"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","names":[]}
package/dist/rail-nav.js CHANGED
@@ -53,7 +53,7 @@ var railNav = tv({
53
53
  shell: "flex min-h-dvh w-full bg-surface-0 text-fg",
54
54
  root: (
55
55
  // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.
56
- "fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1/95 pb-[env(safe-area-inset-bottom)] backdrop-blur-xl md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 md:backdrop-blur-none md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56"
56
+ "fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56"
57
57
  ),
58
58
  // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).
59
59
  mark: "hidden h-14 w-full shrink-0 items-center justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4",
@@ -63,7 +63,7 @@ var railNav = tv({
63
63
  item: "group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0",
64
64
  icon: "relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5",
65
65
  label: "max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only",
66
- badge: "absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-full bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]",
66
+ badge: "absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]",
67
67
  toggle: "hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5",
68
68
  body: "flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]"
69
69
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1/95 pb-[env(safe-area-inset-bottom)] backdrop-blur-xl \" +\n \"md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 md:backdrop-blur-none \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-full bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded = false, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState(defaultExpanded);\n const expanded = expandable ? (controlled ?? own) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/tooltip/tooltip.tsx","../src/floating.ts","../src/rail-nav/rail-nav.tsx"],"sourcesContent":["// Client (a portal). A short label for a control, on hover after `delayDuration` and on keyboard focus at once;\n// Escape dismisses it. It names nothing: the control keeps its own accessible name (an IconButton's `label`).\nimport { Tooltip as TooltipPrimitive } from \"radix-ui\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { floating } from \"../floating\";\n\n/** Optional, once near the root: shares `delayDuration` and the skip delay between tooltips. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\nexport type TooltipProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Content>, \"content\" | \"children\"> & {\n /** What the tooltip says — passed translated. */\n content: React.ReactNode;\n /** The trigger, rendered as is (`asChild`): a focusable element. */\n children: React.ReactNode;\n /** Open or closed (controlled), with `onOpenChange`. */\n open?: boolean;\n /** Open at first, uncontrolled. */\n defaultOpen?: boolean;\n /** Called when it opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Hover delay in ms before it opens (300 by default). */\n delayDuration?: number;\n /** The element the portal renders into (default: document.body). */\n container?: HTMLElement | null;\n};\n\nexport function Tooltip({\n content,\n children,\n open,\n defaultOpen,\n onOpenChange,\n delayDuration = 300,\n container,\n sideOffset = 6,\n collisionPadding = 8,\n className,\n ...props\n}: TooltipProps) {\n return (\n <TooltipPrimitive.Provider delayDuration={delayDuration}>\n <TooltipPrimitive.Root open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n sideOffset={sideOffset}\n collisionPadding={collisionPadding}\n className={cn(floating, \"max-w-xs px-2.5 py-1.5 text-xs font-medium origin-(--radix-tooltip-content-transform-origin)\", className)}\n {...props}\n >\n {content}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n","// The one surface of everything that floats next to its trigger (popover, menu, tooltip): a raised surface, a border,\n// the large shadow and the `kz-pop` entrance from the side Radix measured (`--radix-*-transform-origin`).\nexport const floating =\n \"kz-pop z-50 rounded-lg border border-border-default bg-surface-2 text-fg shadow-lg outline-hidden\";\n","// Client (the expand state, the arrow keys, the tooltip). The compact navigation of an application, read from Orazaka's\n// web client: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, the current one\n// marked by an accent bar on its left edge, a footer for settings and the account — that becomes a bottom tab bar on a\n// phone. The same nodes in both: only the layout changes, so the items, their order and their words are written once.\n// The mark lives in the rail on a desktop; on a phone, where the rail has no room for it, `AppHeader` shows it (the rule\n// « one mark visible at every width »). Brand-aware through the tokens: `accent` scopes `.brand-<id>`.\nimport { Tooltip } from \"@krizaka/ui/tooltip\";\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { ChevronGlyph } from \"../glyphs\";\nimport type { BrandId } from \"../marks/ProductLogo\";\n\nexport const railNav = tv({\n slots: {\n shell: \"flex min-h-dvh w-full bg-surface-0 text-fg\",\n root:\n // Phone: a bottom tab bar, clear of the home indicator. Desktop: a sticky column that is only as wide as its icons.\n \"fixed inset-x-0 bottom-0 z-40 flex h-[calc(3.5rem+env(safe-area-inset-bottom))] flex-row border-t border-border-subtle bg-surface-1 pb-[env(safe-area-inset-bottom)] \" +\n \"md:sticky md:inset-auto md:top-0 md:bottom-auto md:z-auto md:h-dvh md:w-14 md:shrink-0 md:flex-col md:border-t-0 md:border-r md:bg-surface-1 md:pb-0 \" +\n \"md:transition-[width] md:duration-300 motion-reduce:md:transition-none md:data-expanded:w-56\",\n // The mark is the rail's on a desktop; hidden on a phone (the header carries it there).\n mark: \"hidden h-14 w-full shrink-0 items-center justify-center md:flex md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-4\",\n group: \"flex min-w-0 flex-row items-stretch md:flex-col md:items-center md:gap-1 md:px-1.5 md:group-data-expanded/rail:items-stretch\",\n main: \"max-md:grow-(--rail-n) md:flex-1 md:py-2\",\n foot: \"max-md:grow-(--rail-n) md:border-t md:border-border-subtle md:py-2\",\n item:\n \"group/item relative flex min-w-0 flex-1 flex-col items-center justify-center gap-0.5 px-1 text-[11px] font-medium text-fg-secondary no-underline transition-colors \" +\n \"hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset \" +\n \"aria-[current=page]:bg-accent-soft aria-[current=page]:text-fg-accent \" +\n // The accent bar: on the top edge of a tab, on the left edge of a rail item.\n \"before:absolute before:inset-x-3 before:top-0 before:h-[3px] before:rounded-b-full before:bg-accent before:opacity-0 before:transition-opacity aria-[current=page]:before:opacity-100 \" +\n \"md:h-10 md:w-full md:flex-none md:flex-row md:justify-center md:gap-3 md:rounded-none md:px-0 md:text-sm \" +\n \"md:before:inset-x-auto md:before:inset-y-2 md:before:left-0 md:before:top-2 md:before:h-auto md:before:w-[3px] md:before:rounded-r-full md:before:rounded-b-none \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5 [&>svg]:h-5 [&>svg]:w-5 [&>svg]:shrink-0\",\n icon: \"relative inline-flex shrink-0 items-center justify-center [&>svg]:h-5 [&>svg]:w-5\",\n label: \"max-w-full truncate leading-none md:sr-only md:text-sm md:leading-normal md:group-data-expanded/rail:not-sr-only\",\n badge:\n \"absolute -right-2 -top-1.5 inline-flex min-w-4 items-center justify-center rounded-sm bg-accent px-1 text-[10px] font-bold leading-4 text-on-accent after:content-[attr(data-count)]\",\n toggle:\n \"hidden h-10 w-full items-center justify-center gap-3 text-xs font-medium text-fg-secondary hover:bg-surface-2 hover:text-fg focus-visible:outline-hidden focus-visible:focus-ring-inset md:flex \" +\n \"md:group-data-expanded/rail:justify-start md:group-data-expanded/rail:px-3.5\",\n body: \"flex min-w-0 flex-1 flex-col max-md:pb-[calc(3.5rem+env(safe-area-inset-bottom))]\",\n },\n});\nconst s = railNav();\n\ninterface RailState {\n expanded: boolean;\n}\nconst RailContext = React.createContext<RailState | null>(null);\nconst useRail = () => {\n const ctx = React.useContext(RailContext);\n if (!ctx) throw new Error(\"RailNav parts must be inside <RailNav.Root>\");\n return ctx;\n};\n\n/** The frame of the page: the rail, then `RailNav.Body` (the header and the content). A row on a desktop. */\nexport function RailNavShell({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.shell({ className })} {...props} />;\n}\n\n/** The column beside the rail: the `AppHeader`, then the content. On a phone it keeps clear of the tab bar. */\nexport function RailNavBody({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={s.body({ className })} {...props} />;\n}\n\nexport type RailNavRootProps = Omit<React.ComponentProps<\"nav\">, \"children\"> & {\n /** The navigation's accessible name (`Orazaka`, `Studio`). */\n label: string;\n /** The product's mark on top of the rail, as a link home (`<Link href=\"/\"><ProductLogo id=\"orazaka\" /></Link>`); named by the app (its `aria-label`). Hidden on a phone: `AppHeader` shows it there. */\n mark?: React.ReactNode;\n /** The product's brand: scopes its colours (`brand-orazaka`…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. */\n accent?: BrandId;\n /** The main destinations: `RailNav.Item`, the ones you work in. Five at most so that they fit a phone's tab bar. */\n children: React.ReactNode;\n /** At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. `RailNav.Item`s or a control with `data-rail-item`. */\n footer?: React.ReactNode;\n /** Adds a button that widens the rail to show the words (desktop only). Needs `expandLabels`. */\n expandable?: boolean;\n /** Controlled width (pair with `onExpandedChange` to keep the choice). */\n expanded?: boolean;\n /** The starting width when uncontrolled. */\n defaultExpanded?: boolean;\n /** Called when the toggle widens or narrows the rail. */\n onExpandedChange?: (expanded: boolean) => void;\n /** The toggle's words, `[expand, collapse]`. */\n expandLabels?: readonly [string, string];\n};\n\nconst count = (node: React.ReactNode) => React.Children.toArray(node).length;\n\n/** Moves the focus along the rail's items with the arrows (↑ ↓ on the rail, ← → on the tab bar; both always work), Home and End. */\nfunction moveFocus(event: React.KeyboardEvent<HTMLElement>) {\n const keys: Record<string, number> = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 };\n const step = keys[event.key];\n if (step === undefined && event.key !== \"Home\" && event.key !== \"End\") return;\n const items = [...event.currentTarget.querySelectorAll<HTMLElement>(\"[data-rail-item]\")];\n if (items.length === 0) return;\n const here = items.findIndex((el) => el === document.activeElement || el.contains(document.activeElement));\n let next: number;\n if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (here < 0) next = step > 0 ? 0 : items.length - 1;\n else next = (here + step + items.length) % items.length;\n event.preventDefault();\n items[next]?.focus();\n}\n\n/** The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone. */\nexport function RailNavRoot({\n label, mark, accent, children, footer, expandable, expanded: controlled, defaultExpanded = false, onExpandedChange, expandLabels, className, onKeyDown, ...props\n}: RailNavRootProps) {\n const [own, setOwn] = React.useState(defaultExpanded);\n const expanded = expandable ? (controlled ?? own) : false;\n const toggle = () => {\n if (controlled === undefined) setOwn(!expanded);\n onExpandedChange?.(!expanded);\n };\n const value = React.useMemo(() => ({ expanded }), [expanded]);\n return (\n <RailContext.Provider value={value}>\n <nav\n aria-label={label}\n data-expanded={expanded ? \"\" : undefined}\n className={cn(\"group/rail\", accent && \"brand-\" + accent, s.root({ className }))}\n onKeyDown={(e) => {\n onKeyDown?.(e);\n if (!e.defaultPrevented) moveFocus(e);\n }}\n {...props}\n >\n {mark && (\n <div data-brand-mark className={s.mark()}>\n {mark}\n </div>\n )}\n <div className={s.group({ className: s.main() })} style={{ [\"--rail-n\" as string]: Math.max(count(children), 1) }}>\n {children}\n </div>\n {(footer || expandable) && (\n <div className={s.group({ className: s.foot() })} style={{ [\"--rail-n\" as string]: Math.max(count(footer), 1) }}>\n {footer}\n {expandable && expandLabels && (\n <button type=\"button\" data-rail-item className={s.toggle()} aria-expanded={expanded} onClick={toggle}>\n <ChevronGlyph direction={expanded ? \"left\" : \"right\"} className=\"h-4 w-4 shrink-0\" />\n <span className={expanded ? undefined : \"sr-only\"}>{expanded ? expandLabels[1] : expandLabels[0]}</span>\n </button>\n )}\n </div>\n )}\n </nav>\n </RailContext.Provider>\n );\n}\n\nexport type RailNavItemProps = Omit<React.ComponentProps<\"a\">, \"children\"> & {\n /** The item's icon (a signature icon of `@krizaka/icons`): all that shows on a desktop rail. */\n icon: React.ReactNode;\n /** Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. */\n label: string;\n /** This is the section the user is in: `aria-current=\"page\"`, the accent bar and the accent colour. */\n current?: boolean;\n /** A count (unread, pending) on the icon. Say it in words with `badgeLabel`. */\n badge?: React.ReactNode;\n /** The count in words (« 3 unread »), appended to the accessible name. */\n badgeLabel?: string;\n /** Renders your router's link with the item's look: pass it as the only child. */\n asChild?: boolean;\n children?: React.ReactElement;\n};\n\n/** A destination of the rail. */\nexport function RailNavItem({ icon, label, current, badge, badgeLabel, asChild, children, className, ...props }: RailNavItemProps) {\n const { expanded } = useRail();\n const Comp = asChild ? Slot.Root : \"a\";\n const inner = (\n <>\n <span className={s.icon()}>\n {icon}\n {badge != null && (typeof badge === \"string\" || typeof badge === \"number\") ? (\n // Drawn by CSS, so the count is no text of the link: the visible text stays the label, which the name `Chat, 2 unread` contains.\n <span className={s.badge()} data-count={badge} aria-hidden />\n ) : (\n badge != null && <span className={s.badge()} aria-hidden>{badge}</span>\n )}\n </span>\n <span className={s.label()}>{label}</span>\n </>\n );\n const link = (\n <Comp data-rail-item aria-label={badgeLabel ? `${label}, ${badgeLabel}` : label} aria-current={current ? \"page\" : undefined} className={s.item({ className })} {...props}>\n {asChild && children ? React.cloneElement(children, undefined, inner) : inner}\n </Comp>\n );\n // Expanded, the words are on the row; collapsed, the tooltip says them (Escape dismisses it, the keyboard focus shows it).\n return expanded ? link : <Tooltip content={label} side=\"right\">{link}</Tooltip>;\n}\n\nexport const RailNav = {\n Shell: RailNavShell,\n Root: RailNavRoot,\n Item: RailNavItem,\n Body: RailNavBody,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  SearchField,
4
4
  searchField
5
- } from "./chunk-REPTKUJ6.js";
5
+ } from "./chunk-7NRSPHAF.js";
6
6
  import "./chunk-ZIXB33X7.js";
7
7
  import "./chunk-FZBWEDQI.js";
8
8
  import "./chunk-CPA5CF35.js";
@@ -19,15 +19,15 @@ var serviceCard = tv({
19
19
  titles: "flex min-w-0 flex-1 flex-col gap-1",
20
20
  name: "m-0 font-display text-lg font-bold leading-tight tracking-tight text-fg",
21
21
  facts: "m-0 flex list-none flex-wrap gap-x-2 gap-y-0.5 p-0 text-xs text-fg-secondary",
22
- tag: "shrink-0 rounded-full bg-accent px-2 py-0.5 text-[10px] font-extrabold uppercase tracking-wide text-on-accent",
22
+ tag: "shrink-0 rounded-sm bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent",
23
23
  description: "m-0 text-sm leading-relaxed text-fg-secondary",
24
24
  included: "m-0 flex list-none flex-col gap-1.5 p-0 text-sm text-fg-secondary",
25
25
  includedItem: "flex items-start gap-2 [&>svg]:mt-0.5 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 [&>svg]:text-fg-accent",
26
26
  foot: "mt-auto flex items-end justify-between gap-3 border-t border-border-subtle pt-3",
27
27
  priceBlock: "flex flex-col leading-none",
28
- from: "mb-1 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary",
28
+ from: "mb-1 text-[11px] font-semibold text-fg-secondary",
29
29
  price: "font-display text-2xl font-black tabular-nums text-fg",
30
- action: "inline-flex min-h-9 items-center gap-1 rounded-full text-sm font-bold text-fg-accent no-underline after:absolute after:inset-0 after:content-[''] focus-visible:outline-hidden group-data-[selected]:text-fg"
30
+ action: "inline-flex min-h-9 items-center gap-1 rounded-sm text-sm font-bold text-fg-accent no-underline after:absolute after:inset-0 after:content-[''] focus-visible:outline-hidden group-data-[selected]:text-fg"
31
31
  }
32
32
  });
33
33
  var s = serviceCard();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/service-card/service-card.tsx"],"sourcesContent":["// Server-safe: no hook, no context. A service a shop sells, as a card that argues: icon or photo, name, duration, price\n// (« from » when it varies), what is included, the capacity, a « Popular » tag — and one way in: a link (the booking page\n// with this service chosen) or a button (`onSelect`, from a client parent). The whole card takes the press.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { CheckGlyph } from \"../glyphs\";\n\nexport const serviceCard = tv({\n slots: {\n root:\n \"group relative flex h-full min-w-0 flex-col overflow-hidden rounded-xl border border-border-default bg-surface-1 text-fg transition-colors duration-150 hover:border-border-strong hover:bg-surface-2 \" +\n \"hover:border-accent/50 focus-within:ring-2 focus-within:ring-ring data-[selected]:border-accent data-[selected]:bg-accent-soft\",\n media: \"relative aspect-[16/9] w-full overflow-hidden bg-media [&>img]:h-full [&>img]:w-full [&>img]:object-cover\",\n body: \"flex flex-1 flex-col gap-3 p-4 sm:p-5\",\n head: \"flex items-start gap-3\",\n icon: \"inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-accent-soft text-fg-accent [&>svg]:h-5 [&>svg]:w-5\",\n titles: \"flex min-w-0 flex-1 flex-col gap-1\",\n name: \"m-0 font-display text-lg font-bold leading-tight tracking-tight text-fg\",\n facts: \"m-0 flex list-none flex-wrap gap-x-2 gap-y-0.5 p-0 text-xs text-fg-secondary\",\n tag: \"shrink-0 rounded-full bg-accent px-2 py-0.5 text-[10px] font-extrabold uppercase tracking-wide text-on-accent\",\n description: \"m-0 text-sm leading-relaxed text-fg-secondary\",\n included: \"m-0 flex list-none flex-col gap-1.5 p-0 text-sm text-fg-secondary\",\n includedItem: \"flex items-start gap-2 [&>svg]:mt-0.5 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 [&>svg]:text-fg-accent\",\n foot: \"mt-auto flex items-end justify-between gap-3 border-t border-border-subtle pt-3\",\n priceBlock: \"flex flex-col leading-none\",\n from: \"mb-1 text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n price: \"font-display text-2xl font-black tabular-nums text-fg\",\n action:\n \"inline-flex min-h-9 items-center gap-1 rounded-full text-sm font-bold text-fg-accent no-underline \" +\n \"after:absolute after:inset-0 after:content-[''] focus-visible:outline-hidden group-data-[selected]:text-fg\",\n },\n});\nconst s = serviceCard();\n\nexport type ServiceCardProps = Omit<React.ComponentProps<\"article\">, \"title\" | \"children\"> & {\n /** The service's name (the heading). */\n name: string;\n /** Its price, formatted by the app (`22,00 $`): the card never formats money. */\n price: string;\n /** The words before the price when it varies (`From`, `À partir de`), passed translated. */\n priceFrom?: string;\n /** How long it takes (`30 min`) — the first fact. */\n duration?: string;\n /** How many it takes (`Up to 5 dogs`, `1 person`) — the second fact. */\n capacity?: string;\n /** One or two sentences: what it is. */\n description?: string;\n /** What is included, one short line each (a check precedes it). */\n included?: readonly string[];\n /** A tag on the top right (`Popular`): only from real data, never decoration. */\n tag?: string;\n /** An icon tile before the name (a signature icon): decorative. */\n icon?: React.ReactNode;\n /** A photo or a loop above the card (an `img`, a `video`): fills a 16:9 band. */\n media?: React.ReactNode;\n /** This service is the chosen one (the accent, `data-selected`). */\n selected?: boolean;\n /** The words of the way in (`Book`, `Choose`): the accessible name of the press. */\n actionLabel: string;\n /** The way in, as an address (the booking page with this service preselected). */\n href?: string;\n /** The app's link component for internal addresses (Next's `Link`). */\n linkAs?: LinkComponent;\n /** The way in, as a press (a client parent). Ignored when `href` is set. */\n onSelect?: () => void;\n /**\n * The heading level of the name.\n * @default \"h3\"\n */\n titleAs?: \"h2\" | \"h3\" | \"h4\";\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay. */\n reveal?: number;\n};\n\n/** A service as a card: icon or photo, duration, price, what is included, the capacity, a tag — one way in. */\nexport function ServiceCard({\n name, price, priceFrom, duration, capacity, description, included, tag, icon, media, selected, actionLabel, href, linkAs, onSelect, titleAs: Title = \"h3\", reveal, className, style, ...props\n}: ServiceCardProps) {\n const id = React.useId();\n const facts = [duration, capacity].filter(Boolean);\n const arrow = <span aria-hidden>→</span>;\n const revealStyle = reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <article\n aria-labelledby={id}\n data-selected={selected ? \"\" : undefined}\n data-reveal={reveal === undefined ? undefined : \"\"}\n style={revealStyle}\n className={s.root({ className })}\n {...props}\n >\n {media && <div className={s.media()}>{media}</div>}\n <div className={s.body()}>\n <div className={s.head()}>\n {icon && <span aria-hidden className={s.icon()}>{icon}</span>}\n <div className={s.titles()}>\n <Title id={id} className={s.name()}>{name}</Title>\n {facts.length > 0 && (\n <ul className={s.facts()}>\n {facts.map((fact, i) => (\n <li key={i}>{i > 0 && <span aria-hidden>· </span>}{fact}</li>\n ))}\n </ul>\n )}\n </div>\n {tag && <span className={s.tag()}>{tag}</span>}\n </div>\n {description && <p className={s.description()}>{description}</p>}\n {included && included.length > 0 && (\n <ul className={s.included()}>\n {included.map((line) => (\n <li key={line} className={s.includedItem()}>\n <CheckGlyph />\n <span>{line}</span>\n </li>\n ))}\n </ul>\n )}\n <div className={s.foot()}>\n <p className={s.priceBlock()}>\n {priceFrom && <span className={s.from()}>{priceFrom}</span>}\n <span className={s.price()}>{price}</span>\n </p>\n {href ? (\n <BlockLink href={href} linkAs={linkAs} className={s.action()} aria-describedby={id}>\n {actionLabel} {arrow}\n </BlockLink>\n ) : onSelect ? (\n <button type=\"button\" onClick={onSelect} aria-pressed={selected ?? false} aria-describedby={id} className={s.action()}>\n {actionLabel} {arrow}\n </button>\n ) : null}\n </div>\n </div>\n </article>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/service-card/service-card.tsx"],"sourcesContent":["// Server-safe: no hook, no context. A service a shop sells, as a card that argues: icon or photo, name, duration, price\n// (« from » when it varies), what is included, the capacity, a « Popular » tag — and one way in: a link (the booking page\n// with this service chosen) or a button (`onSelect`, from a client parent). The whole card takes the press.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { CheckGlyph } from \"../glyphs\";\n\nexport const serviceCard = tv({\n slots: {\n root:\n \"group relative flex h-full min-w-0 flex-col overflow-hidden rounded-xl border border-border-default bg-surface-1 text-fg transition-colors duration-150 hover:border-border-strong hover:bg-surface-2 \" +\n \"hover:border-accent/50 focus-within:ring-2 focus-within:ring-ring data-[selected]:border-accent data-[selected]:bg-accent-soft\",\n media: \"relative aspect-[16/9] w-full overflow-hidden bg-media [&>img]:h-full [&>img]:w-full [&>img]:object-cover\",\n body: \"flex flex-1 flex-col gap-3 p-4 sm:p-5\",\n head: \"flex items-start gap-3\",\n icon: \"inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-accent-soft text-fg-accent [&>svg]:h-5 [&>svg]:w-5\",\n titles: \"flex min-w-0 flex-1 flex-col gap-1\",\n name: \"m-0 font-display text-lg font-bold leading-tight tracking-tight text-fg\",\n facts: \"m-0 flex list-none flex-wrap gap-x-2 gap-y-0.5 p-0 text-xs text-fg-secondary\",\n tag: \"shrink-0 rounded-sm bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent\",\n description: \"m-0 text-sm leading-relaxed text-fg-secondary\",\n included: \"m-0 flex list-none flex-col gap-1.5 p-0 text-sm text-fg-secondary\",\n includedItem: \"flex items-start gap-2 [&>svg]:mt-0.5 [&>svg]:h-4 [&>svg]:w-4 [&>svg]:shrink-0 [&>svg]:text-fg-accent\",\n foot: \"mt-auto flex items-end justify-between gap-3 border-t border-border-subtle pt-3\",\n priceBlock: \"flex flex-col leading-none\",\n from: \"mb-1 text-[11px] font-semibold text-fg-secondary\",\n price: \"font-display text-2xl font-black tabular-nums text-fg\",\n action:\n \"inline-flex min-h-9 items-center gap-1 rounded-sm text-sm font-bold text-fg-accent no-underline \" +\n \"after:absolute after:inset-0 after:content-[''] focus-visible:outline-hidden group-data-[selected]:text-fg\",\n },\n});\nconst s = serviceCard();\n\nexport type ServiceCardProps = Omit<React.ComponentProps<\"article\">, \"title\" | \"children\"> & {\n /** The service's name (the heading). */\n name: string;\n /** Its price, formatted by the app (`22,00 $`): the card never formats money. */\n price: string;\n /** The words before the price when it varies (`From`, `À partir de`), passed translated. */\n priceFrom?: string;\n /** How long it takes (`30 min`) — the first fact. */\n duration?: string;\n /** How many it takes (`Up to 5 dogs`, `1 person`) — the second fact. */\n capacity?: string;\n /** One or two sentences: what it is. */\n description?: string;\n /** What is included, one short line each (a check precedes it). */\n included?: readonly string[];\n /** A tag on the top right (`Popular`): only from real data, never decoration. */\n tag?: string;\n /** An icon tile before the name (a signature icon): decorative. */\n icon?: React.ReactNode;\n /** A photo or a loop above the card (an `img`, a `video`): fills a 16:9 band. */\n media?: React.ReactNode;\n /** This service is the chosen one (the accent, `data-selected`). */\n selected?: boolean;\n /** The words of the way in (`Book`, `Choose`): the accessible name of the press. */\n actionLabel: string;\n /** The way in, as an address (the booking page with this service preselected). */\n href?: string;\n /** The app's link component for internal addresses (Next's `Link`). */\n linkAs?: LinkComponent;\n /** The way in, as a press (a client parent). Ignored when `href` is set. */\n onSelect?: () => void;\n /**\n * The heading level of the name.\n * @default \"h3\"\n */\n titleAs?: \"h2\" | \"h3\" | \"h4\";\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay. */\n reveal?: number;\n};\n\n/** A service as a card: icon or photo, duration, price, what is included, the capacity, a tag — one way in. */\nexport function ServiceCard({\n name, price, priceFrom, duration, capacity, description, included, tag, icon, media, selected, actionLabel, href, linkAs, onSelect, titleAs: Title = \"h3\", reveal, className, style, ...props\n}: ServiceCardProps) {\n const id = React.useId();\n const facts = [duration, capacity].filter(Boolean);\n const arrow = <span aria-hidden>→</span>;\n const revealStyle = reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <article\n aria-labelledby={id}\n data-selected={selected ? \"\" : undefined}\n data-reveal={reveal === undefined ? undefined : \"\"}\n style={revealStyle}\n className={s.root({ className })}\n {...props}\n >\n {media && <div className={s.media()}>{media}</div>}\n <div className={s.body()}>\n <div className={s.head()}>\n {icon && <span aria-hidden className={s.icon()}>{icon}</span>}\n <div className={s.titles()}>\n <Title id={id} className={s.name()}>{name}</Title>\n {facts.length > 0 && (\n <ul className={s.facts()}>\n {facts.map((fact, i) => (\n <li key={i}>{i > 0 && <span aria-hidden>· </span>}{fact}</li>\n ))}\n </ul>\n )}\n </div>\n {tag && <span className={s.tag()}>{tag}</span>}\n </div>\n {description && <p className={s.description()}>{description}</p>}\n {included && included.length > 0 && (\n <ul className={s.included()}>\n {included.map((line) => (\n <li key={line} className={s.includedItem()}>\n <CheckGlyph />\n <span>{line}</span>\n </li>\n ))}\n </ul>\n )}\n <div className={s.foot()}>\n <p className={s.priceBlock()}>\n {priceFrom && <span className={s.from()}>{priceFrom}</span>}\n <span className={s.price()}>{price}</span>\n </p>\n {href ? (\n <BlockLink href={href} linkAs={linkAs} className={s.action()} aria-describedby={id}>\n {actionLabel} {arrow}\n </BlockLink>\n ) : onSelect ? (\n <button type=\"button\" onClick={onSelect} aria-pressed={selected ?? false} aria-describedby={id} className={s.action()}>\n {actionLabel} {arrow}\n </button>\n ) : null}\n </div>\n </div>\n </article>\n );\n}\n"],"mappings":"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","names":[]}
@@ -11,7 +11,7 @@ var settingsLayout = tv({
11
11
  columns: "grid grid-cols-1 gap-6 lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-10",
12
12
  nav: "-mx-4 overflow-x-auto overflow-y-hidden px-4 py-1 -my-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden lg:mx-0 lg:overflow-visible lg:px-0 lg:py-0 lg:my-0",
13
13
  navList: "flex w-max gap-2 lg:sticky lg:top-20 lg:w-auto lg:flex-col lg:gap-0.5",
14
- navLink: "flex h-9 items-center gap-2.5 whitespace-nowrap rounded-full border border-border-default bg-surface-1 px-3.5 text-sm font-medium text-fg-secondary no-underline hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current]:border-accent aria-[current]:text-fg lg:rounded-lg lg:border-transparent lg:bg-transparent lg:px-3 lg:hover:bg-surface-2 lg:aria-[current]:bg-accent-soft [&>svg]:h-4 [&>svg]:w-4",
14
+ navLink: "flex h-9 items-center gap-2.5 whitespace-nowrap rounded-sm border border-border-default bg-surface-1 px-3.5 text-sm font-medium text-fg-secondary no-underline hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current]:border-accent aria-[current]:text-fg lg:rounded-lg lg:border-transparent lg:bg-transparent lg:px-3 lg:hover:bg-surface-2 lg:aria-[current]:bg-accent-soft [&>svg]:h-4 [&>svg]:w-4",
15
15
  content: "flex min-w-0 flex-col gap-6",
16
16
  section: "rounded-xl border border-border-default bg-surface-1",
17
17
  sectionHead: "flex flex-col gap-1 px-5 pt-5",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/settings-layout/settings-layout.tsx"],"sourcesContent":["// Server-safe. Settings, read from the products' account and administration screens: a list of sections on the left\n// (a row of chips that scrolls on a phone), the current section's forms on the right, each form a titled card with its\n// own save at the foot. The sections are links (one page each) or anchors (one long page).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const settingsLayout = tv({\n slots: {\n root: \"flex w-full flex-col gap-6\",\n head: \"flex flex-col gap-1\",\n title: \"font-display text-2xl font-extrabold tracking-tight text-fg\",\n description: \"max-w-2xl text-sm text-fg-secondary\",\n columns: \"grid grid-cols-1 gap-6 lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-10\",\n nav: \"-mx-4 overflow-x-auto overflow-y-hidden px-4 py-1 -my-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden lg:mx-0 lg:overflow-visible lg:px-0 lg:py-0 lg:my-0\",\n navList: \"flex w-max gap-2 lg:sticky lg:top-20 lg:w-auto lg:flex-col lg:gap-0.5\",\n navLink:\n \"flex h-9 items-center gap-2.5 whitespace-nowrap rounded-full border border-border-default bg-surface-1 px-3.5 text-sm font-medium text-fg-secondary no-underline \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current]:border-accent aria-[current]:text-fg \" +\n \"lg:rounded-lg lg:border-transparent lg:bg-transparent lg:px-3 lg:hover:bg-surface-2 lg:aria-[current]:bg-accent-soft [&>svg]:h-4 [&>svg]:w-4\",\n content: \"flex min-w-0 flex-col gap-6\",\n section: \"rounded-xl border border-border-default bg-surface-1\",\n sectionHead: \"flex flex-col gap-1 px-5 pt-5\",\n sectionTitle: \"text-base font-bold text-fg\",\n sectionDescription: \"text-sm text-fg-secondary\",\n sectionBody: \"flex flex-col gap-4 px-5 py-5\",\n sectionFooter: \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle bg-surface-2/40 px-5 py-3 rounded-b-xl\",\n // The flat look: no card, hairline-divided rows (Linear / Vercel / GitHub settings).\n rows: \"flex flex-col divide-y divide-border-subtle border-y border-border-subtle\",\n row: \"flex flex-col gap-2 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6\",\n rowText: \"flex min-w-0 flex-col gap-0.5\",\n rowLabel: \"text-sm font-medium text-fg\",\n rowDescription: \"text-sm text-fg-secondary\",\n rowControl: \"flex min-w-0 shrink-0 items-center gap-2 text-sm text-fg sm:max-w-[60%] sm:justify-end\",\n },\n variants: {\n variant: {\n card: {},\n flat: {\n content: \"max-w-[45rem] gap-10\",\n section: \"rounded-none border-0 bg-transparent\",\n sectionHead: \"gap-0.5 px-0 pb-3 pt-0\",\n sectionBody: \"gap-0 px-0 py-0\",\n sectionFooter: \"justify-start border-t-0 bg-transparent px-0 pb-0 pt-4\",\n },\n },\n },\n defaultVariants: { variant: \"card\" },\n});\n\nexport interface SettingsNavItem {\n /** Its id (the anchor of a section on one long page). */\n id: string;\n /** Its words. */\n label: string;\n /** Where it leads: a page (`/settings/billing`) or an anchor (`#billing`). */\n href: string;\n /** Its icon (a signature icon). */\n icon?: React.ReactNode;\n /** The section shown now: `aria-current`. */\n current?: boolean;\n}\n\nexport type SettingsLayoutProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The screen's title (`Settings`). */\n title?: React.ReactNode;\n /** One sentence under it. */\n description?: React.ReactNode;\n /** The sections. */\n nav: readonly SettingsNavItem[];\n /** The navigation's accessible name (`Settings sections`). */\n navLabel: string;\n /** The app's link component for the sections (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /**\n * `card` (each form a titled card) or `flat` (one calm column of at most 45rem, rows divided by hairlines).\n * @default \"card\"\n */\n variant?: \"card\" | \"flat\";\n /** The current section's forms (`SettingsSection`). */\n children: React.ReactNode;\n};\n\n/** A settings screen: sections on the left (chips on a phone), forms on the right. */\nexport function SettingsLayout({ title, description, nav, navLabel, linkAs: Link = \"a\", variant = \"card\", className, children, ...props }: SettingsLayoutProps) {\n const s = settingsLayout({ variant });\n return (\n <div className={s.root({ className })} {...props}>\n {(title || description) && (\n <div className={s.head()}>\n {title && <h1 className={s.title()}>{title}</h1>}\n {description && <p className={s.description()}>{description}</p>}\n </div>\n )}\n <div className={s.columns()}>\n <nav aria-label={navLabel} className={s.nav()}>\n <ul className={s.navList()}>\n {nav.map((item) => (\n <li key={item.id}>\n <Link href={item.href} className={s.navLink()} aria-current={item.current ? (item.href.startsWith(\"#\") ? \"location\" : \"page\") : undefined}>\n {item.icon}\n {item.label}\n </Link>\n </li>\n ))}\n </ul>\n </nav>\n <div className={s.content()}>{children}</div>\n </div>\n </div>\n );\n}\n\nexport type SettingsSectionProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n /** The section's title: it names the region (and is its anchor's target when `id` is set). */\n title: React.ReactNode;\n /** What these settings change, in one sentence. */\n description?: React.ReactNode;\n /** At the foot: the section's own save (a Button), a note. */\n footer?: React.ReactNode;\n /**\n * `card` (a titled card) or `flat` (no card: a title, then hairline-divided `SettingsRow`s).\n * @default \"card\"\n */\n variant?: \"card\" | \"flat\";\n /** The fields (or, flat, the `SettingsRow`s). */\n children: React.ReactNode;\n};\n\n/** A group of settings: a titled card with its fields and its own save, or flat rows under a title. */\nexport function SettingsSection({ title, description, footer, variant = \"card\", id, className, children, ...props }: SettingsSectionProps) {\n const s = settingsLayout({ variant });\n const auto = React.useId();\n const titleId = `${id ?? auto}-title`;\n return (\n <section id={id} aria-labelledby={titleId} className={s.section({ className })} {...props}>\n <div className={s.sectionHead()}>\n <h2 id={titleId} className={s.sectionTitle()}>\n {title}\n </h2>\n {description && <p className={s.sectionDescription()}>{description}</p>}\n </div>\n <div className={variant === \"flat\" ? s.rows() : s.sectionBody()} data-settings-rows={variant === \"flat\" ? \"\" : undefined}>\n {children}\n </div>\n {footer && <div className={s.sectionFooter()}>{footer}</div>}\n </section>\n );\n}\n\nexport type SettingsRowProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** What the setting is (`Username`). */\n label: React.ReactNode;\n /** The help text under it, one sentence. */\n description?: React.ReactNode;\n /** The id of the control, so the label names it (a `<label htmlFor>`). Leave out for a plain value. */\n htmlFor?: string;\n /** The control or the value, on the right (stacked under the label on a phone). */\n children?: React.ReactNode;\n};\n\n/** One setting: its label and help on the left, its control or value on the right. Put rows in a flat `SettingsSection`. */\nexport function SettingsRow({ label, description, htmlFor, className, children, ...props }: SettingsRowProps) {\n const s = settingsLayout();\n const Label = htmlFor ? \"label\" : \"span\";\n return (\n <div className={s.row({ className })} {...props}>\n <div className={s.rowText()}>\n <Label className={s.rowLabel()} {...(htmlFor ? { htmlFor } : {})}>\n {label}\n </Label>\n {description && <span className={s.rowDescription()}>{description}</span>}\n </div>\n {children !== undefined && <div className={s.rowControl()}>{children}</div>}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/settings-layout/settings-layout.tsx"],"sourcesContent":["// Server-safe. Settings, read from the products' account and administration screens: a list of sections on the left\n// (a row of chips that scrolls on a phone), the current section's forms on the right, each form a titled card with its\n// own save at the foot. The sections are links (one page each) or anchors (one long page).\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const settingsLayout = tv({\n slots: {\n root: \"flex w-full flex-col gap-6\",\n head: \"flex flex-col gap-1\",\n title: \"font-display text-2xl font-extrabold tracking-tight text-fg\",\n description: \"max-w-2xl text-sm text-fg-secondary\",\n columns: \"grid grid-cols-1 gap-6 lg:grid-cols-[13rem_minmax(0,1fr)] lg:gap-10\",\n nav: \"-mx-4 overflow-x-auto overflow-y-hidden px-4 py-1 -my-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden lg:mx-0 lg:overflow-visible lg:px-0 lg:py-0 lg:my-0\",\n navList: \"flex w-max gap-2 lg:sticky lg:top-20 lg:w-auto lg:flex-col lg:gap-0.5\",\n navLink:\n \"flex h-9 items-center gap-2.5 whitespace-nowrap rounded-sm border border-border-default bg-surface-1 px-3.5 text-sm font-medium text-fg-secondary no-underline \" +\n \"hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current]:border-accent aria-[current]:text-fg \" +\n \"lg:rounded-lg lg:border-transparent lg:bg-transparent lg:px-3 lg:hover:bg-surface-2 lg:aria-[current]:bg-accent-soft [&>svg]:h-4 [&>svg]:w-4\",\n content: \"flex min-w-0 flex-col gap-6\",\n section: \"rounded-xl border border-border-default bg-surface-1\",\n sectionHead: \"flex flex-col gap-1 px-5 pt-5\",\n sectionTitle: \"text-base font-bold text-fg\",\n sectionDescription: \"text-sm text-fg-secondary\",\n sectionBody: \"flex flex-col gap-4 px-5 py-5\",\n sectionFooter: \"flex flex-wrap items-center justify-end gap-2 border-t border-border-subtle bg-surface-2/40 px-5 py-3 rounded-b-xl\",\n // The flat look: no card, hairline-divided rows (Linear / Vercel / GitHub settings).\n rows: \"flex flex-col divide-y divide-border-subtle border-y border-border-subtle\",\n row: \"flex flex-col gap-2 py-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6\",\n rowText: \"flex min-w-0 flex-col gap-0.5\",\n rowLabel: \"text-sm font-medium text-fg\",\n rowDescription: \"text-sm text-fg-secondary\",\n rowControl: \"flex min-w-0 shrink-0 items-center gap-2 text-sm text-fg sm:max-w-[60%] sm:justify-end\",\n },\n variants: {\n variant: {\n card: {},\n flat: {\n content: \"max-w-[45rem] gap-10\",\n section: \"rounded-none border-0 bg-transparent\",\n sectionHead: \"gap-0.5 px-0 pb-3 pt-0\",\n sectionBody: \"gap-0 px-0 py-0\",\n sectionFooter: \"justify-start border-t-0 bg-transparent px-0 pb-0 pt-4\",\n },\n },\n },\n defaultVariants: { variant: \"card\" },\n});\n\nexport interface SettingsNavItem {\n /** Its id (the anchor of a section on one long page). */\n id: string;\n /** Its words. */\n label: string;\n /** Where it leads: a page (`/settings/billing`) or an anchor (`#billing`). */\n href: string;\n /** Its icon (a signature icon). */\n icon?: React.ReactNode;\n /** The section shown now: `aria-current`. */\n current?: boolean;\n}\n\nexport type SettingsLayoutProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The screen's title (`Settings`). */\n title?: React.ReactNode;\n /** One sentence under it. */\n description?: React.ReactNode;\n /** The sections. */\n nav: readonly SettingsNavItem[];\n /** The navigation's accessible name (`Settings sections`). */\n navLabel: string;\n /** The app's link component for the sections (Next's `Link`); an `<a>` otherwise. */\n linkAs?: React.ElementType;\n /**\n * `card` (each form a titled card) or `flat` (one calm column of at most 45rem, rows divided by hairlines).\n * @default \"card\"\n */\n variant?: \"card\" | \"flat\";\n /** The current section's forms (`SettingsSection`). */\n children: React.ReactNode;\n};\n\n/** A settings screen: sections on the left (chips on a phone), forms on the right. */\nexport function SettingsLayout({ title, description, nav, navLabel, linkAs: Link = \"a\", variant = \"card\", className, children, ...props }: SettingsLayoutProps) {\n const s = settingsLayout({ variant });\n return (\n <div className={s.root({ className })} {...props}>\n {(title || description) && (\n <div className={s.head()}>\n {title && <h1 className={s.title()}>{title}</h1>}\n {description && <p className={s.description()}>{description}</p>}\n </div>\n )}\n <div className={s.columns()}>\n <nav aria-label={navLabel} className={s.nav()}>\n <ul className={s.navList()}>\n {nav.map((item) => (\n <li key={item.id}>\n <Link href={item.href} className={s.navLink()} aria-current={item.current ? (item.href.startsWith(\"#\") ? \"location\" : \"page\") : undefined}>\n {item.icon}\n {item.label}\n </Link>\n </li>\n ))}\n </ul>\n </nav>\n <div className={s.content()}>{children}</div>\n </div>\n </div>\n );\n}\n\nexport type SettingsSectionProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n /** The section's title: it names the region (and is its anchor's target when `id` is set). */\n title: React.ReactNode;\n /** What these settings change, in one sentence. */\n description?: React.ReactNode;\n /** At the foot: the section's own save (a Button), a note. */\n footer?: React.ReactNode;\n /**\n * `card` (a titled card) or `flat` (no card: a title, then hairline-divided `SettingsRow`s).\n * @default \"card\"\n */\n variant?: \"card\" | \"flat\";\n /** The fields (or, flat, the `SettingsRow`s). */\n children: React.ReactNode;\n};\n\n/** A group of settings: a titled card with its fields and its own save, or flat rows under a title. */\nexport function SettingsSection({ title, description, footer, variant = \"card\", id, className, children, ...props }: SettingsSectionProps) {\n const s = settingsLayout({ variant });\n const auto = React.useId();\n const titleId = `${id ?? auto}-title`;\n return (\n <section id={id} aria-labelledby={titleId} className={s.section({ className })} {...props}>\n <div className={s.sectionHead()}>\n <h2 id={titleId} className={s.sectionTitle()}>\n {title}\n </h2>\n {description && <p className={s.sectionDescription()}>{description}</p>}\n </div>\n <div className={variant === \"flat\" ? s.rows() : s.sectionBody()} data-settings-rows={variant === \"flat\" ? \"\" : undefined}>\n {children}\n </div>\n {footer && <div className={s.sectionFooter()}>{footer}</div>}\n </section>\n );\n}\n\nexport type SettingsRowProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** What the setting is (`Username`). */\n label: React.ReactNode;\n /** The help text under it, one sentence. */\n description?: React.ReactNode;\n /** The id of the control, so the label names it (a `<label htmlFor>`). Leave out for a plain value. */\n htmlFor?: string;\n /** The control or the value, on the right (stacked under the label on a phone). */\n children?: React.ReactNode;\n};\n\n/** One setting: its label and help on the left, its control or value on the right. Put rows in a flat `SettingsSection`. */\nexport function SettingsRow({ label, description, htmlFor, className, children, ...props }: SettingsRowProps) {\n const s = settingsLayout();\n const Label = htmlFor ? \"label\" : \"span\";\n return (\n <div className={s.row({ className })} {...props}>\n <div className={s.rowText()}>\n <Label className={s.rowLabel()} {...(htmlFor ? { htmlFor } : {})}>\n {label}\n </Label>\n {description && <span className={s.rowDescription()}>{description}</span>}\n </div>\n {children !== undefined && <div className={s.rowControl()}>{children}</div>}\n </div>\n );\n}\n"],"mappings":";AAGA,YAAY,WAAW;AACvB,SAAS,UAAU;AAoFX,SACY,KADZ;AAlFD,IAAM,iBAAiB,GAAG;AAAA,EAC/B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,IACT,KAAK;AAAA,IACL,SAAS;AAAA,IACT,SACE;AAAA,IAGF,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA,IACb,eAAe;AAAA;AAAA,IAEf,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,YAAY;AAAA,EACd;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,MACP,MAAM,CAAC;AAAA,MACP,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,QACb,aAAa;AAAA,QACb,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,OAAO;AACrC,CAAC;AAoCM,SAAS,eAAe,EAAE,OAAO,aAAa,KAAK,UAAU,QAAQ,OAAO,KAAK,UAAU,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAwB;AAC9J,QAAM,IAAI,eAAe,EAAE,QAAQ,CAAC;AACpC,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACvC;AAAA,cAAS,gBACT,qBAAC,SAAI,WAAW,EAAE,KAAK,GACpB;AAAA,eAAS,oBAAC,QAAG,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,MAC1C,eAAe,oBAAC,OAAE,WAAW,EAAE,YAAY,GAAI,uBAAY;AAAA,OAC9D;AAAA,IAEF,qBAAC,SAAI,WAAW,EAAE,QAAQ,GACxB;AAAA,0BAAC,SAAI,cAAY,UAAU,WAAW,EAAE,IAAI,GAC1C,8BAAC,QAAG,WAAW,EAAE,QAAQ,GACtB,cAAI,IAAI,CAAC,SACR,oBAAC,QACC,+BAAC,QAAK,MAAM,KAAK,MAAM,WAAW,EAAE,QAAQ,GAAG,gBAAc,KAAK,UAAW,KAAK,KAAK,WAAW,GAAG,IAAI,aAAa,SAAU,QAC7H;AAAA,aAAK;AAAA,QACL,KAAK;AAAA,SACR,KAJO,KAAK,EAKd,CACD,GACH,GACF;AAAA,MACA,oBAAC,SAAI,WAAW,EAAE,QAAQ,GAAI,UAAS;AAAA,OACzC;AAAA,KACF;AAEJ;AAmBO,SAAS,gBAAgB,EAAE,OAAO,aAAa,QAAQ,UAAU,QAAQ,IAAI,WAAW,UAAU,GAAG,MAAM,GAAyB;AACzI,QAAM,IAAI,eAAe,EAAE,QAAQ,CAAC;AACpC,QAAM,OAAa,YAAM;AACzB,QAAM,UAAU,GAAG,MAAM,IAAI;AAC7B,SACE,qBAAC,aAAQ,IAAQ,mBAAiB,SAAS,WAAW,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAI,GAAG,OAClF;AAAA,yBAAC,SAAI,WAAW,EAAE,YAAY,GAC5B;AAAA,0BAAC,QAAG,IAAI,SAAS,WAAW,EAAE,aAAa,GACxC,iBACH;AAAA,MACC,eAAe,oBAAC,OAAE,WAAW,EAAE,mBAAmB,GAAI,uBAAY;AAAA,OACrE;AAAA,IACA,oBAAC,SAAI,WAAW,YAAY,SAAS,EAAE,KAAK,IAAI,EAAE,YAAY,GAAG,sBAAoB,YAAY,SAAS,KAAK,QAC5G,UACH;AAAA,IACC,UAAU,oBAAC,SAAI,WAAW,EAAE,cAAc,GAAI,kBAAO;AAAA,KACxD;AAEJ;AAcO,SAAS,YAAY,EAAE,OAAO,aAAa,SAAS,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC5G,QAAM,IAAI,eAAe;AACzB,QAAM,QAAQ,UAAU,UAAU;AAClC,SACE,qBAAC,SAAI,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,GAAI,GAAG,OACxC;AAAA,yBAAC,SAAI,WAAW,EAAE,QAAQ,GACxB;AAAA,0BAAC,SAAM,WAAW,EAAE,SAAS,GAAI,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC,GAC3D,iBACH;AAAA,MACC,eAAe,oBAAC,UAAK,WAAW,EAAE,eAAe,GAAI,uBAAY;AAAA,OACpE;AAAA,IACC,aAAa,UAAa,oBAAC,SAAI,WAAW,EAAE,WAAW,GAAI,UAAS;AAAA,KACvE;AAEJ;","names":[]}
@@ -25,14 +25,14 @@ var siteFooter = tv({
25
25
  own: "grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8",
26
26
  family: "grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4",
27
27
  column: "grid min-w-0 content-start gap-3",
28
- title: "text-[11px] font-semibold uppercase tracking-wider text-fg-secondary",
28
+ title: "text-[11px] font-semibold text-fg-secondary",
29
29
  list: "grid min-w-0 gap-2",
30
30
  link: "inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold",
31
31
  mark: "flex h-4 w-4 shrink-0 items-center justify-center text-fg",
32
- tag: "rounded-full bg-surface-3 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-fg-secondary",
32
+ tag: "rounded-sm bg-surface-3 px-1.5 py-px text-[10px] font-semibold text-fg-secondary",
33
33
  bottom: "flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary",
34
34
  signature: "inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
35
- version: "rounded-full border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary",
35
+ version: "rounded-sm border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary",
36
36
  legal: "flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto"
37
37
  },
38
38
  variants: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family: the site's own columns, then the\n// family in columns from `@krizaka/ui/sites` (the same groups as the bar's switcher), then the signature line — “A\n// Krizaka product” by the kind of the current site — the version and the place.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12\",\n top: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]\",\n site: \"grid content-start gap-3\",\n siteName: \"inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg\",\n siteText: \"max-w-xs text-sm leading-relaxed text-fg-secondary\",\n own: \"grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8\",\n family: \"grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold uppercase tracking-wider text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-full bg-surface-3 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-full border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n variants: {\n // `site`: the full footer. `docs`: no site block, the columns in one row, on the documentation's width. `app`: one\n // slim line inside a signed-in product — signature, version, legal links.\n variant: {\n site: {},\n docs: {\n inner: \"max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8\",\n top: \"lg:grid-cols-[minmax(0,1fr)]\",\n own: \"sm:grid-cols-4\",\n },\n app: {\n root: \"bg-transparent\",\n inner: \"gap-0 py-3\",\n bottom: \"border-t-0 pt-0\",\n },\n },\n },\n defaultVariants: { variant: \"site\" },\n});\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n /**\n * `site` — the full footer of a marketing or company site. `docs` — a compact one for documentation pages (no site\n * block, the columns in a row, the documentation's width; never the family). `app` — one slim line inside a signed-in\n * product: the publisher line, the version and the legal links (no columns, no family); render it once, in the\n * layout, and not at all where the app shell has a sidebar that holds them.\n * @default \"site\"\n */\n variant?: \"site\" | \"docs\" | \"app\";\n};\n\n/** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family: familyProp = true,\n variant = \"site\",\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const s = siteFooter({ variant });\n const family = variant === \"site\" && familyProp;\n const slim = variant === \"app\";\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n {!slim && (\n <div className={s.top()}>\n {variant === \"site\" && (\n <div className={s.site()}>\n <a href={site.url} className={s.siteName()}>\n <FamilyMark mark={site.mark} size={24} />\n {site.name}\n </a>\n <p className={s.siteText()}>{labels.descriptions[site.id]}</p>\n </div>\n )}\n {React.Children.toArray(children).length > 0 && <div className={s.own()}>{children}</div>}\n </div>\n )}\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {sitesByGroup().map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n {!slim && <span>{labels.place}</span>}\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n // A group with no link is not a column: only a heading over nothing.\n if (React.Children.toArray(children).length === 0) return null;\n const s = siteFooter();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.toArray(children).map((child, i) => <li key={i}>{child}</li>)}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const s = siteFooter();\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family: the site's own columns, then the\n// family in columns from `@krizaka/ui/sites` (the same groups as the bar's switcher), then the signature line — “A\n// Krizaka product” by the kind of the current site — the version and the place.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12\",\n top: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]\",\n site: \"grid content-start gap-3\",\n siteName: \"inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg\",\n siteText: \"max-w-xs text-sm leading-relaxed text-fg-secondary\",\n own: \"grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8\",\n family: \"grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-sm bg-surface-3 px-1.5 py-px text-[10px] font-semibold text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-sm border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n variants: {\n // `site`: the full footer. `docs`: no site block, the columns in one row, on the documentation's width. `app`: one\n // slim line inside a signed-in product — signature, version, legal links.\n variant: {\n site: {},\n docs: {\n inner: \"max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8\",\n top: \"lg:grid-cols-[minmax(0,1fr)]\",\n own: \"sm:grid-cols-4\",\n },\n app: {\n root: \"bg-transparent\",\n inner: \"gap-0 py-3\",\n bottom: \"border-t-0 pt-0\",\n },\n },\n },\n defaultVariants: { variant: \"site\" },\n});\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n /**\n * `site` — the full footer of a marketing or company site. `docs` — a compact one for documentation pages (no site\n * block, the columns in a row, the documentation's width; never the family). `app` — one slim line inside a signed-in\n * product: the publisher line, the version and the legal links (no columns, no family); render it once, in the\n * layout, and not at all where the app shell has a sidebar that holds them.\n * @default \"site\"\n */\n variant?: \"site\" | \"docs\" | \"app\";\n};\n\n/** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family: familyProp = true,\n variant = \"site\",\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const s = siteFooter({ variant });\n const family = variant === \"site\" && familyProp;\n const slim = variant === \"app\";\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n {!slim && (\n <div className={s.top()}>\n {variant === \"site\" && (\n <div className={s.site()}>\n <a href={site.url} className={s.siteName()}>\n <FamilyMark mark={site.mark} size={24} />\n {site.name}\n </a>\n <p className={s.siteText()}>{labels.descriptions[site.id]}</p>\n </div>\n )}\n {React.Children.toArray(children).length > 0 && <div className={s.own()}>{children}</div>}\n </div>\n )}\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {sitesByGroup().map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n {!slim && <span>{labels.place}</span>}\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n // A group with no link is not a column: only a heading over nothing.\n if (React.Children.toArray(children).length === 0) return null;\n const s = siteFooter();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.toArray(children).map((child, i) => <li key={i}>{child}</li>)}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const s = siteFooter();\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":"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","names":[]}
package/dist/skip-link.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  SkipLink,
4
4
  skipLink
5
- } from "./chunk-QDXV544C.js";
5
+ } from "./chunk-4QH6CP2Y.js";
6
6
  export {
7
7
  SkipLink,
8
8
  skipLink
@@ -15,7 +15,7 @@ var slotPicker = tv({
15
15
  dayName: "text-xs font-bold",
16
16
  daySub: "text-[11px] tabular-nums text-fg-muted",
17
17
  times: "m-0 flex list-none flex-wrap gap-2 p-0",
18
- time: "inline-flex min-h-11 min-w-[4.75rem] items-center justify-center gap-1.5 rounded-full border border-border-default bg-surface-1 px-4 text-sm font-semibold tabular-nums text-fg no-underline transition-colors hover:border-accent/60 hover:bg-accent-soft focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-pressed:border-accent aria-pressed:bg-accent aria-pressed:text-on-accent disabled:cursor-not-allowed disabled:opacity-50",
18
+ time: "inline-flex min-h-11 min-w-[4.75rem] items-center justify-center gap-1.5 rounded-sm border border-border-default bg-surface-1 px-4 text-sm font-semibold tabular-nums text-fg no-underline transition-colors hover:border-accent/60 hover:bg-accent-soft focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-pressed:border-accent aria-pressed:bg-accent aria-pressed:text-on-accent disabled:cursor-not-allowed disabled:opacity-50",
19
19
  note: "text-[11px] font-medium text-fg-secondary group-aria-pressed:text-on-accent",
20
20
  empty: "m-0 rounded-xl border border-dashed border-border-default px-4 py-6 text-center text-sm text-fg-secondary"
21
21
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/slot-picker/slot-picker.tsx"],"sourcesContent":["// Client (the chosen day). The next free times of a service as tappable chips: a strip of days, then the day's times.\n// A time is a link (`href`: the booking page with the time chosen) or a toggle the reader presses (`value`,\n// `onValueChange`). The app computes the slots (its availability is the truth) and formats the labels.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\n\nexport const slotPicker = tv({\n slots: {\n root: \"flex min-w-0 flex-col gap-3\",\n days: \"flex gap-2 overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\",\n day:\n \"flex min-h-12 min-w-[4.5rem] shrink-0 cursor-pointer flex-col items-center justify-center rounded-xl border border-border-default bg-surface-1 px-3 py-1.5 text-center leading-tight text-fg-secondary \" +\n \"transition-colors hover:border-border-strong hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-pressed:border-accent aria-pressed:bg-accent-soft aria-pressed:text-fg\",\n dayName: \"text-xs font-bold\",\n daySub: \"text-[11px] tabular-nums text-fg-muted\",\n times: \"m-0 flex list-none flex-wrap gap-2 p-0\",\n time:\n \"inline-flex min-h-11 min-w-[4.75rem] items-center justify-center gap-1.5 rounded-full border border-border-default bg-surface-1 px-4 text-sm font-semibold tabular-nums text-fg no-underline \" +\n \"transition-colors hover:border-accent/60 hover:bg-accent-soft focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-pressed:border-accent aria-pressed:bg-accent aria-pressed:text-on-accent disabled:cursor-not-allowed disabled:opacity-50\",\n note: \"text-[11px] font-medium text-fg-secondary group-aria-pressed:text-on-accent\",\n empty: \"m-0 rounded-xl border border-dashed border-border-default px-4 py-6 text-center text-sm text-fg-secondary\",\n },\n});\nconst s = slotPicker();\n\nexport type PickerSlot = {\n /** A stable id (the slot's start as an ISO string). */\n id: string;\n /** The time in words, formatted by the app (`9 h 30`). */\n label: string;\n /** What to know about it (`2 places left`), shown beside the time and read with it. */\n note?: string;\n /** Not offered any more: shown, disabled. */\n disabled?: boolean;\n /** Makes the time a link to this address (the booking page with the slot chosen). */\n href?: string;\n};\n\nexport type PickerDay = {\n /** A stable id (`2026-10-19`). */\n id: string;\n /** The day's name, translated (`Today`, `Mon`). */\n label: string;\n /** Under it (`19 Oct`). */\n sub?: string;\n /** Its free times, in order. */\n slots: readonly PickerSlot[];\n};\n\nexport type SlotPickerProps = Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> & {\n /** The days that have free times, in order. */\n days: readonly PickerDay[];\n /** The name of the group (`Available times`), passed translated. */\n label: string;\n /** Said when no day has a free time. */\n emptyLabel: string;\n /** The chosen slot's id (controlled). */\n value?: string | null;\n /** Called with the chosen slot's id. */\n onValueChange?: (id: string) => void;\n /** The first day shown. Default: the first of `days`. */\n defaultDay?: string;\n /** The app's link component for the times that have an `href`. */\n linkAs?: LinkComponent;\n};\n\n/** Tappable free times by day: the day strip, then the day's chips — links or toggles. */\nexport function SlotPicker({ days, label, emptyLabel, value, onValueChange, defaultDay, linkAs, className, ...props }: SlotPickerProps) {\n const [dayId, setDayId] = React.useState(defaultDay ?? days[0]?.id);\n const active = days.find((d) => d.id === dayId) ?? days[0];\n if (!active) return <p className={s.empty({ className })}>{emptyLabel}</p>;\n return (\n <div className={s.root({ className })} {...props}>\n <div className={s.days()} role=\"group\" aria-label={label}>\n {days.map((day) => (\n <button key={day.id} type=\"button\" aria-pressed={day.id === active.id} onClick={() => setDayId(day.id)} className={s.day()}>\n <span className={s.dayName()}>{day.label}</span>\n {day.sub && <span className={s.daySub()}>{day.sub}</span>}\n </button>\n ))}\n </div>\n <ul className={s.times()} aria-label={`${active.label}${active.sub ? ` ${active.sub}` : \"\"}`}>\n {active.slots.map((slot) => (\n <li key={slot.id}>\n {slot.href ? (\n <BlockLink href={slot.href} linkAs={linkAs} className={s.time()}>\n {slot.label}\n {slot.note && <span className={s.note()}>{slot.note}</span>}\n </BlockLink>\n ) : (\n <button type=\"button\" aria-pressed={value === slot.id} disabled={slot.disabled} onClick={() => onValueChange?.(slot.id)} className={s.time({ className: \"group\" })}>\n {slot.label}\n {slot.note && <span className={s.note()}>{slot.note}</span>}\n </button>\n )}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":";;;;;;AAGA,YAAY,WAAW;AACvB,SAAS,UAAU;AAsEG,cAKZ,YALY;AAlEf,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,KACE;AAAA,IAGF,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MACE;AAAA,IAGF,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AA4Cd,SAAS,WAAW,EAAE,MAAM,OAAO,YAAY,OAAO,eAAe,YAAY,QAAQ,WAAW,GAAG,MAAM,GAAoB;AACtI,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAS,cAAc,KAAK,CAAC,GAAG,EAAE;AAClE,QAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,KAAK,KAAK,CAAC;AACzD,MAAI,CAAC,OAAQ,QAAO,oBAAC,OAAE,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,sBAAW;AACtE,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACzC;AAAA,wBAAC,SAAI,WAAW,EAAE,KAAK,GAAG,MAAK,SAAQ,cAAY,OAChD,eAAK,IAAI,CAAC,QACT,qBAAC,YAAoB,MAAK,UAAS,gBAAc,IAAI,OAAO,OAAO,IAAI,SAAS,MAAM,SAAS,IAAI,EAAE,GAAG,WAAW,EAAE,IAAI,GACvH;AAAA,0BAAC,UAAK,WAAW,EAAE,QAAQ,GAAI,cAAI,OAAM;AAAA,MACxC,IAAI,OAAO,oBAAC,UAAK,WAAW,EAAE,OAAO,GAAI,cAAI,KAAI;AAAA,SAFvC,IAAI,EAGjB,CACD,GACH;AAAA,IACA,oBAAC,QAAG,WAAW,EAAE,MAAM,GAAG,cAAY,GAAG,OAAO,KAAK,GAAG,OAAO,MAAM,IAAI,OAAO,GAAG,KAAK,EAAE,IACvF,iBAAO,MAAM,IAAI,CAAC,SACjB,oBAAC,QACE,eAAK,OACJ,qBAAC,aAAU,MAAM,KAAK,MAAM,QAAgB,WAAW,EAAE,KAAK,GAC3D;AAAA,WAAK;AAAA,MACL,KAAK,QAAQ,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,eAAK,MAAK;AAAA,OACtD,IAEA,qBAAC,YAAO,MAAK,UAAS,gBAAc,UAAU,KAAK,IAAI,UAAU,KAAK,UAAU,SAAS,MAAM,gBAAgB,KAAK,EAAE,GAAG,WAAW,EAAE,KAAK,EAAE,WAAW,QAAQ,CAAC,GAC9J;AAAA,WAAK;AAAA,MACL,KAAK,QAAQ,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,eAAK,MAAK;AAAA,OACtD,KAVK,KAAK,EAYd,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/slot-picker/slot-picker.tsx"],"sourcesContent":["// Client (the chosen day). The next free times of a service as tappable chips: a strip of days, then the day's times.\n// A time is a link (`href`: the booking page with the time chosen) or a toggle the reader presses (`value`,\n// `onValueChange`). The app computes the slots (its availability is the truth) and formats the labels.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\n\nexport const slotPicker = tv({\n slots: {\n root: \"flex min-w-0 flex-col gap-3\",\n days: \"flex gap-2 overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\",\n day:\n \"flex min-h-12 min-w-[4.5rem] shrink-0 cursor-pointer flex-col items-center justify-center rounded-xl border border-border-default bg-surface-1 px-3 py-1.5 text-center leading-tight text-fg-secondary \" +\n \"transition-colors hover:border-border-strong hover:text-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-pressed:border-accent aria-pressed:bg-accent-soft aria-pressed:text-fg\",\n dayName: \"text-xs font-bold\",\n daySub: \"text-[11px] tabular-nums text-fg-muted\",\n times: \"m-0 flex list-none flex-wrap gap-2 p-0\",\n time:\n \"inline-flex min-h-11 min-w-[4.75rem] items-center justify-center gap-1.5 rounded-sm border border-border-default bg-surface-1 px-4 text-sm font-semibold tabular-nums text-fg no-underline \" +\n \"transition-colors hover:border-accent/60 hover:bg-accent-soft focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring \" +\n \"aria-pressed:border-accent aria-pressed:bg-accent aria-pressed:text-on-accent disabled:cursor-not-allowed disabled:opacity-50\",\n note: \"text-[11px] font-medium text-fg-secondary group-aria-pressed:text-on-accent\",\n empty: \"m-0 rounded-xl border border-dashed border-border-default px-4 py-6 text-center text-sm text-fg-secondary\",\n },\n});\nconst s = slotPicker();\n\nexport type PickerSlot = {\n /** A stable id (the slot's start as an ISO string). */\n id: string;\n /** The time in words, formatted by the app (`9 h 30`). */\n label: string;\n /** What to know about it (`2 places left`), shown beside the time and read with it. */\n note?: string;\n /** Not offered any more: shown, disabled. */\n disabled?: boolean;\n /** Makes the time a link to this address (the booking page with the slot chosen). */\n href?: string;\n};\n\nexport type PickerDay = {\n /** A stable id (`2026-10-19`). */\n id: string;\n /** The day's name, translated (`Today`, `Mon`). */\n label: string;\n /** Under it (`19 Oct`). */\n sub?: string;\n /** Its free times, in order. */\n slots: readonly PickerSlot[];\n};\n\nexport type SlotPickerProps = Omit<React.ComponentProps<\"div\">, \"onChange\" | \"defaultValue\"> & {\n /** The days that have free times, in order. */\n days: readonly PickerDay[];\n /** The name of the group (`Available times`), passed translated. */\n label: string;\n /** Said when no day has a free time. */\n emptyLabel: string;\n /** The chosen slot's id (controlled). */\n value?: string | null;\n /** Called with the chosen slot's id. */\n onValueChange?: (id: string) => void;\n /** The first day shown. Default: the first of `days`. */\n defaultDay?: string;\n /** The app's link component for the times that have an `href`. */\n linkAs?: LinkComponent;\n};\n\n/** Tappable free times by day: the day strip, then the day's chips — links or toggles. */\nexport function SlotPicker({ days, label, emptyLabel, value, onValueChange, defaultDay, linkAs, className, ...props }: SlotPickerProps) {\n const [dayId, setDayId] = React.useState(defaultDay ?? days[0]?.id);\n const active = days.find((d) => d.id === dayId) ?? days[0];\n if (!active) return <p className={s.empty({ className })}>{emptyLabel}</p>;\n return (\n <div className={s.root({ className })} {...props}>\n <div className={s.days()} role=\"group\" aria-label={label}>\n {days.map((day) => (\n <button key={day.id} type=\"button\" aria-pressed={day.id === active.id} onClick={() => setDayId(day.id)} className={s.day()}>\n <span className={s.dayName()}>{day.label}</span>\n {day.sub && <span className={s.daySub()}>{day.sub}</span>}\n </button>\n ))}\n </div>\n <ul className={s.times()} aria-label={`${active.label}${active.sub ? ` ${active.sub}` : \"\"}`}>\n {active.slots.map((slot) => (\n <li key={slot.id}>\n {slot.href ? (\n <BlockLink href={slot.href} linkAs={linkAs} className={s.time()}>\n {slot.label}\n {slot.note && <span className={s.note()}>{slot.note}</span>}\n </BlockLink>\n ) : (\n <button type=\"button\" aria-pressed={value === slot.id} disabled={slot.disabled} onClick={() => onValueChange?.(slot.id)} className={s.time({ className: \"group\" })}>\n {slot.label}\n {slot.note && <span className={s.note()}>{slot.note}</span>}\n </button>\n )}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":";;;;;;AAGA,YAAY,WAAW;AACvB,SAAS,UAAU;AAsEG,cAKZ,YALY;AAlEf,IAAM,aAAa,GAAG;AAAA,EAC3B,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,KACE;AAAA,IAGF,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MACE;AAAA,IAGF,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AACF,CAAC;AACD,IAAM,IAAI,WAAW;AA4Cd,SAAS,WAAW,EAAE,MAAM,OAAO,YAAY,OAAO,eAAe,YAAY,QAAQ,WAAW,GAAG,MAAM,GAAoB;AACtI,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAS,cAAc,KAAK,CAAC,GAAG,EAAE;AAClE,QAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,KAAK,KAAK,CAAC;AACzD,MAAI,CAAC,OAAQ,QAAO,oBAAC,OAAE,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,GAAI,sBAAW;AACtE,SACE,qBAAC,SAAI,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACzC;AAAA,wBAAC,SAAI,WAAW,EAAE,KAAK,GAAG,MAAK,SAAQ,cAAY,OAChD,eAAK,IAAI,CAAC,QACT,qBAAC,YAAoB,MAAK,UAAS,gBAAc,IAAI,OAAO,OAAO,IAAI,SAAS,MAAM,SAAS,IAAI,EAAE,GAAG,WAAW,EAAE,IAAI,GACvH;AAAA,0BAAC,UAAK,WAAW,EAAE,QAAQ,GAAI,cAAI,OAAM;AAAA,MACxC,IAAI,OAAO,oBAAC,UAAK,WAAW,EAAE,OAAO,GAAI,cAAI,KAAI;AAAA,SAFvC,IAAI,EAGjB,CACD,GACH;AAAA,IACA,oBAAC,QAAG,WAAW,EAAE,MAAM,GAAG,cAAY,GAAG,OAAO,KAAK,GAAG,OAAO,MAAM,IAAI,OAAO,GAAG,KAAK,EAAE,IACvF,iBAAO,MAAM,IAAI,CAAC,SACjB,oBAAC,QACE,eAAK,OACJ,qBAAC,aAAU,MAAM,KAAK,MAAM,QAAgB,WAAW,EAAE,KAAK,GAC3D;AAAA,WAAK;AAAA,MACL,KAAK,QAAQ,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,eAAK,MAAK;AAAA,OACtD,IAEA,qBAAC,YAAO,MAAK,UAAS,gBAAc,UAAU,KAAK,IAAI,UAAU,KAAK,UAAU,SAAS,MAAM,gBAAgB,KAAK,EAAE,GAAG,WAAW,EAAE,KAAK,EAAE,WAAW,QAAQ,CAAC,GAC9J;AAAA,WAAK;AAAA,MACL,KAAK,QAAQ,oBAAC,UAAK,WAAW,EAAE,KAAK,GAAI,eAAK,MAAK;AAAA,OACtD,KAVK,KAAK,EAYd,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}