@krizaka/ui 3.29.0 → 3.31.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 (403) hide show
  1. package/README.md +4 -8
  2. package/dist/action-bar.js +3 -3
  3. package/dist/action-bar.js.map +1 -1
  4. package/dist/argument-card.d.ts +1 -1
  5. package/dist/argument-card.js +2 -2
  6. package/dist/argument-card.js.map +1 -1
  7. package/dist/blocks.css +19 -60
  8. package/dist/{button-BmCrLCq7.d.ts → button-Cm9pFH3P.d.ts} +10 -9
  9. package/dist/button.d.ts +11 -10
  10. package/dist/button.js +1 -1
  11. package/dist/captcha.js +1 -1
  12. package/dist/card-grid.d.ts +5 -12
  13. package/dist/card-grid.js +4 -12
  14. package/dist/card-grid.js.map +1 -1
  15. package/dist/card.d.ts +7 -7
  16. package/dist/card.js +2 -2
  17. package/dist/card.js.map +1 -1
  18. package/dist/{chunk-OUWPBSSL.js → chunk-2AJ4NJUF.js} +8 -9
  19. package/dist/chunk-2AJ4NJUF.js.map +1 -0
  20. package/dist/{chunk-MQPC3P4T.js → chunk-2DGLWTPS.js} +3 -3
  21. package/dist/chunk-2DGLWTPS.js.map +1 -0
  22. package/dist/{chunk-DZU6RMYD.js → chunk-3DHNN5V7.js} +15 -9
  23. package/dist/chunk-3DHNN5V7.js.map +1 -0
  24. package/dist/{chunk-TFJDIOFK.js → chunk-4E5IUZHR.js} +3 -3
  25. package/dist/chunk-4E5IUZHR.js.map +1 -0
  26. package/dist/{chunk-HAQWKORZ.js → chunk-4JO5GSSD.js} +1 -37
  27. package/dist/chunk-4JO5GSSD.js.map +1 -0
  28. package/dist/{chunk-APNIVNIX.js → chunk-IBDTAMPF.js} +3 -4
  29. package/dist/chunk-IBDTAMPF.js.map +1 -0
  30. package/dist/{chunk-LYOPPBMC.js → chunk-KIBICUZK.js} +2 -2
  31. package/dist/{chunk-HBZPJ3EP.js → chunk-NJFCSVPT.js} +2 -2
  32. package/dist/{chunk-KM6VAKIE.js → chunk-RE5WJ4QP.js} +2 -2
  33. package/dist/chunk-RE5WJ4QP.js.map +1 -0
  34. package/dist/{chunk-CHOJUCVE.js → chunk-SJS6RJIT.js} +15 -9
  35. package/dist/chunk-SJS6RJIT.js.map +1 -0
  36. package/dist/{chunk-6ZYRUOTA.js → chunk-UV4HBVH7.js} +15 -9
  37. package/dist/chunk-UV4HBVH7.js.map +1 -0
  38. package/dist/command.js +2 -2
  39. package/dist/confirm-button.d.ts +1 -1
  40. package/dist/confirm-button.js +1 -1
  41. package/dist/continue-prompt.js +14 -8
  42. package/dist/continue-prompt.js.map +1 -1
  43. package/dist/data-table.js +2 -2
  44. package/dist/dialog.js +2 -2
  45. package/dist/engine-flow.d.ts +25 -2
  46. package/dist/engine-flow.js +27 -6
  47. package/dist/engine-flow.js.map +1 -1
  48. package/dist/force-update-screen.js +2 -2
  49. package/dist/force-update-screen.js.map +1 -1
  50. package/dist/genui.js +3 -3
  51. package/dist/glow-card.d.ts +5 -4
  52. package/dist/glow-card.js +2 -8
  53. package/dist/glow-card.js.map +1 -1
  54. package/dist/image-cropper.js +1 -1
  55. package/dist/index.js +4 -4
  56. package/dist/index.js.map +1 -1
  57. package/dist/iso.d.ts +1 -1
  58. package/dist/iso.js.map +1 -1
  59. package/dist/landscape.js +4 -4
  60. package/dist/landscape.js.map +1 -1
  61. package/dist/link-card.d.ts +3 -6
  62. package/dist/link-card.js +1 -1
  63. package/dist/maintenance-screen.js +1 -1
  64. package/dist/map.d.ts +50 -5
  65. package/dist/map.js +202 -66
  66. package/dist/map.js.map +1 -1
  67. package/dist/match-dialog.js +1 -1
  68. package/dist/media-gallery.js +1 -1
  69. package/dist/media-gallery.js.map +1 -1
  70. package/dist/media-grid.js +2 -2
  71. package/dist/motion.css +52 -122
  72. package/dist/motion.d.ts +2 -2
  73. package/dist/motion.js +1 -1
  74. package/dist/native/map.js +64 -64
  75. package/dist/native/map.js.map +1 -1
  76. package/dist/native.js +30 -30
  77. package/dist/native.js.map +1 -1
  78. package/dist/nav-bar.d.ts +12 -3
  79. package/dist/nav-bar.js +19 -12
  80. package/dist/nav-bar.js.map +1 -1
  81. package/dist/pointer-light.d.ts +6 -9
  82. package/dist/pointer-light.js +9 -5
  83. package/dist/pointer-light.js.map +1 -1
  84. package/dist/radio-group.js +2 -2
  85. package/dist/radio-group.js.map +1 -1
  86. package/dist/service-card.js +1 -1
  87. package/dist/service-card.js.map +1 -1
  88. package/dist/site-footer.d.ts +1 -1
  89. package/dist/site-footer.js +2 -2
  90. package/dist/{sites-CHp_vELn.d.ts → sites-B4prB793.d.ts} +2 -2
  91. package/dist/sites.d.ts +2 -2
  92. package/dist/sites.js +6 -7
  93. package/dist/sites.js.map +1 -1
  94. package/dist/slider.js +1 -1
  95. package/dist/slider.js.map +1 -1
  96. package/dist/story.css +5 -12
  97. package/dist/theme.d.ts +1 -1
  98. package/dist/theme.js +1 -1
  99. package/dist/update-prompt.js +2 -2
  100. package/dist/update-prompt.js.map +1 -1
  101. package/dist/vertical-video.js +1 -1
  102. package/dist/video-player.js +2 -2
  103. package/dist/video-player.js.map +1 -1
  104. package/package.json +5 -5
  105. package/registry/action-bar.json +1 -1
  106. package/registry/app-shell.json +4 -4
  107. package/registry/argument-card.json +7 -16
  108. package/registry/auth-layout.json +4 -4
  109. package/registry/button.json +20 -20
  110. package/registry/card-grid.json +21 -24
  111. package/registry/card.json +7 -7
  112. package/registry/component-page.json +2 -2
  113. package/registry/confirm-button.json +6 -6
  114. package/registry/contact-page.json +2 -2
  115. package/registry/cover-hero.json +3 -3
  116. package/registry/dashboard-layout.json +2 -2
  117. package/registry/detail-layout.json +4 -4
  118. package/registry/docs-hub-page.json +2 -2
  119. package/registry/empty-state.json +1 -1
  120. package/registry/engine-flow.json +74 -3
  121. package/registry/examples/app-shell/admin-console.js +1 -1
  122. package/registry/examples/app-shell/admin-console.tsx +1 -1
  123. package/registry/examples/app-shell/basic.js +1 -1
  124. package/registry/examples/app-shell/basic.tsx +1 -1
  125. package/registry/examples/app-shell/desktop.js +1 -1
  126. package/registry/examples/app-shell/desktop.tsx +1 -1
  127. package/registry/examples/app-shell/orochia-studio.js +1 -1
  128. package/registry/examples/app-shell/orochia-studio.tsx +1 -1
  129. package/registry/examples/argument-card/hover-quiet.js +1 -1
  130. package/registry/examples/argument-card/hover-quiet.tsx +1 -1
  131. package/registry/examples/auth-layout/onboarding.js +2 -2
  132. package/registry/examples/auth-layout/onboarding.tsx +2 -2
  133. package/registry/examples/auth-layout/sign-in.js +2 -2
  134. package/registry/examples/auth-layout/sign-in.tsx +2 -2
  135. package/registry/examples/auth-layout/verify.js +1 -1
  136. package/registry/examples/auth-layout/verify.tsx +1 -1
  137. package/registry/examples/avatar/native/presence.dark.png +0 -0
  138. package/registry/examples/avatar/native/presence.light.png +0 -0
  139. package/registry/examples/badge/native/tones.dark.png +0 -0
  140. package/registry/examples/badge/native/tones.light.png +0 -0
  141. package/registry/examples/button/native/disabled.dark.png +0 -0
  142. package/registry/examples/button/native/disabled.light.png +0 -0
  143. package/registry/examples/button/native/gradient.dark.png +0 -0
  144. package/registry/examples/button/native/gradient.light.png +0 -0
  145. package/registry/examples/button/native/icon-only.dark.png +0 -0
  146. package/registry/examples/button/native/icon-only.light.png +0 -0
  147. package/registry/examples/button/native/icon.dark.png +0 -0
  148. package/registry/examples/button/native/icon.light.png +0 -0
  149. package/registry/examples/button/native/loading.dark.png +0 -0
  150. package/registry/examples/button/native/loading.light.png +0 -0
  151. package/registry/examples/button/native/primary.dark.png +0 -0
  152. package/registry/examples/button/native/primary.light.png +0 -0
  153. package/registry/examples/button/native/sizes.dark.png +0 -0
  154. package/registry/examples/button/native/sizes.light.png +0 -0
  155. package/registry/examples/button/signature.js +2 -2
  156. package/registry/examples/button/signature.tsx +4 -4
  157. package/registry/examples/card/interactive-link.tsx +1 -1
  158. package/registry/examples/card/native/body.dark.png +0 -0
  159. package/registry/examples/card/native/body.light.png +0 -0
  160. package/registry/examples/card/native/default.dark.png +0 -0
  161. package/registry/examples/card/native/default.light.png +0 -0
  162. package/registry/examples/card/native/elevated.dark.png +0 -0
  163. package/registry/examples/card/native/elevated.light.png +0 -0
  164. package/registry/examples/card-grid/hover-quiet.js +1 -1
  165. package/registry/examples/card-grid/hover-quiet.tsx +1 -1
  166. package/registry/examples/chat/native/assistant.dark.png +0 -0
  167. package/registry/examples/chat/native/assistant.light.png +0 -0
  168. package/registry/examples/chat/native/conversation.dark.png +0 -0
  169. package/registry/examples/chat/native/conversation.light.png +0 -0
  170. package/registry/examples/chat/native/inbox.dark.png +0 -0
  171. package/registry/examples/chat/native/inbox.light.png +0 -0
  172. package/registry/examples/checkbox/native/terms.dark.png +0 -0
  173. package/registry/examples/checkbox/native/terms.light.png +0 -0
  174. package/registry/examples/chip/native/multiple.dark.png +0 -0
  175. package/registry/examples/chip/native/multiple.light.png +0 -0
  176. package/registry/examples/chip/native/single.dark.png +0 -0
  177. package/registry/examples/chip/native/single.light.png +0 -0
  178. package/registry/examples/chip/native/toggle.dark.png +0 -0
  179. package/registry/examples/chip/native/toggle.light.png +0 -0
  180. package/registry/examples/component-page/button.js +2 -2
  181. package/registry/examples/component-page/button.tsx +2 -2
  182. package/registry/examples/contact-page/team.js +1 -1
  183. package/registry/examples/contact-page/team.tsx +1 -1
  184. package/registry/examples/cover-hero/plain.js +1 -1
  185. package/registry/examples/cover-hero/plain.tsx +1 -1
  186. package/registry/examples/cover-hero/shop.js +1 -1
  187. package/registry/examples/cover-hero/shop.tsx +1 -1
  188. package/registry/examples/dashboard-layout/orazaka-eric.js +2 -2
  189. package/registry/examples/dashboard-layout/orazaka-eric.tsx +2 -2
  190. package/registry/examples/date-picker/native/calendar.dark.png +0 -0
  191. package/registry/examples/date-picker/native/calendar.light.png +0 -0
  192. package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
  193. package/registry/examples/date-picker/native/day-strip.light.png +0 -0
  194. package/registry/examples/date-picker/native/month-year.dark.png +0 -0
  195. package/registry/examples/date-picker/native/month-year.light.png +0 -0
  196. package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
  197. package/registry/examples/date-picker/native/time-slots.light.png +0 -0
  198. package/registry/examples/description-list/native/job-details.dark.png +0 -0
  199. package/registry/examples/description-list/native/job-details.light.png +0 -0
  200. package/registry/examples/detail-layout/checkout.js +1 -1
  201. package/registry/examples/detail-layout/checkout.tsx +1 -1
  202. package/registry/examples/detail-layout/job.js +1 -1
  203. package/registry/examples/detail-layout/job.tsx +1 -1
  204. package/registry/examples/detail-layout/video.js +2 -2
  205. package/registry/examples/detail-layout/video.tsx +2 -2
  206. package/registry/examples/dialog/native/sheet.dark.png +0 -0
  207. package/registry/examples/dialog/native/sheet.light.png +0 -0
  208. package/registry/examples/docs-hub-page/krizaka.js +1 -1
  209. package/registry/examples/docs-hub-page/krizaka.tsx +1 -1
  210. package/registry/examples/empty-state/library.js +1 -1
  211. package/registry/examples/empty-state/library.tsx +1 -1
  212. package/registry/examples/empty-state/native/default.dark.png +0 -0
  213. package/registry/examples/empty-state/native/default.light.png +0 -0
  214. package/registry/examples/fab/native/extended.dark.png +0 -0
  215. package/registry/examples/fab/native/extended.light.png +0 -0
  216. package/registry/examples/force-update-screen/native/default.dark.png +0 -0
  217. package/registry/examples/force-update-screen/native/default.light.png +0 -0
  218. package/registry/examples/form/native/amount.dark.png +0 -0
  219. package/registry/examples/form/native/amount.light.png +0 -0
  220. package/registry/examples/form/native/audience.dark.png +0 -0
  221. package/registry/examples/form/native/audience.light.png +0 -0
  222. package/registry/examples/form/native/profile.dark.png +0 -0
  223. package/registry/examples/form/native/profile.light.png +0 -0
  224. package/registry/examples/form/native/settings.dark.png +0 -0
  225. package/registry/examples/form/native/settings.light.png +0 -0
  226. package/registry/examples/form/native/sign-up.dark.png +0 -0
  227. package/registry/examples/form/native/sign-up.light.png +0 -0
  228. package/registry/examples/form/native/upload.dark.png +0 -0
  229. package/registry/examples/form/native/upload.light.png +0 -0
  230. package/registry/examples/glow-card/spotlight.tsx +1 -1
  231. package/registry/examples/goal-gauge/native/default.dark.png +0 -0
  232. package/registry/examples/goal-gauge/native/default.light.png +0 -0
  233. package/registry/examples/landing-page/krizaka.js +3 -3
  234. package/registry/examples/landing-page/krizaka.tsx +3 -3
  235. package/registry/examples/link-card/hover-quiet.js +1 -1
  236. package/registry/examples/link-card/hover-quiet.tsx +1 -1
  237. package/registry/examples/loader/native/block.dark.png +0 -0
  238. package/registry/examples/loader/native/block.light.png +0 -0
  239. package/registry/examples/map/native/location-picker.dark.png +0 -0
  240. package/registry/examples/map/native/location-picker.light.png +0 -0
  241. package/registry/examples/map/route.js +36 -0
  242. package/registry/examples/map/route.tsx +35 -0
  243. package/registry/examples/marketing-layout/pricing.js +1 -1
  244. package/registry/examples/marketing-layout/pricing.tsx +1 -1
  245. package/registry/examples/marketing-layout/product-page.js +1 -1
  246. package/registry/examples/marketing-layout/product-page.tsx +2 -2
  247. package/registry/examples/mascot-state/native/default.dark.png +0 -0
  248. package/registry/examples/mascot-state/native/default.light.png +0 -0
  249. package/registry/examples/mascots/native/crane.dark.png +0 -0
  250. package/registry/examples/mascots/native/crane.light.png +0 -0
  251. package/registry/examples/mascots/native/default.dark.png +0 -0
  252. package/registry/examples/mascots/native/default.light.png +0 -0
  253. package/registry/examples/mascots/native/lovebird.dark.png +0 -0
  254. package/registry/examples/mascots/native/lovebird.light.png +0 -0
  255. package/registry/examples/mascots/native/phoenix.dark.png +0 -0
  256. package/registry/examples/mascots/native/phoenix.light.png +0 -0
  257. package/registry/examples/match-dialog/native/its-a-match.dark.png +0 -0
  258. package/registry/examples/match-dialog/native/its-a-match.light.png +0 -0
  259. package/registry/examples/media-capture/native/photo.dark.png +0 -0
  260. package/registry/examples/media-capture/native/photo.light.png +0 -0
  261. package/registry/examples/meta-row/native/video.dark.png +0 -0
  262. package/registry/examples/meta-row/native/video.light.png +0 -0
  263. package/registry/examples/meter/native/credits.dark.png +0 -0
  264. package/registry/examples/meter/native/credits.light.png +0 -0
  265. package/registry/examples/meter/native/split-ring.dark.png +0 -0
  266. package/registry/examples/meter/native/split-ring.light.png +0 -0
  267. package/registry/examples/nav-bar/family-product.js +1 -1
  268. package/registry/examples/nav-bar/family-product.tsx +1 -1
  269. package/registry/examples/onboarding/native/first-launch.dark.png +0 -0
  270. package/registry/examples/onboarding/native/first-launch.light.png +0 -0
  271. package/registry/examples/permission-prompt/native/blocked.dark.png +0 -0
  272. package/registry/examples/permission-prompt/native/blocked.light.png +0 -0
  273. package/registry/examples/permission-prompt/native/camera.dark.png +0 -0
  274. package/registry/examples/permission-prompt/native/camera.light.png +0 -0
  275. package/registry/examples/photo-grid/native/profile-photos.dark.png +0 -0
  276. package/registry/examples/photo-grid/native/profile-photos.light.png +0 -0
  277. package/registry/examples/pricing-page/credits.js +3 -3
  278. package/registry/examples/pricing-page/credits.tsx +3 -3
  279. package/registry/examples/product-page/orazaka.js +2 -2
  280. package/registry/examples/product-page/orazaka.tsx +2 -2
  281. package/registry/examples/profile-card/native/default.dark.png +0 -0
  282. package/registry/examples/profile-card/native/default.light.png +0 -0
  283. package/registry/examples/progress/native/bar.dark.png +0 -0
  284. package/registry/examples/progress/native/bar.light.png +0 -0
  285. package/registry/examples/progress/native/indeterminate.dark.png +0 -0
  286. package/registry/examples/progress/native/indeterminate.light.png +0 -0
  287. package/registry/examples/progress/native/ring.dark.png +0 -0
  288. package/registry/examples/progress/native/ring.light.png +0 -0
  289. package/registry/examples/radio-group/native/buttons.dark.png +0 -0
  290. package/registry/examples/radio-group/native/buttons.light.png +0 -0
  291. package/registry/examples/radio-group/native/cards.dark.png +0 -0
  292. package/registry/examples/radio-group/native/cards.light.png +0 -0
  293. package/registry/examples/radio-group/native/list.dark.png +0 -0
  294. package/registry/examples/radio-group/native/list.light.png +0 -0
  295. package/registry/examples/screen/native/auth.dark.png +0 -0
  296. package/registry/examples/screen/native/auth.light.png +0 -0
  297. package/registry/examples/screen/native/chat.dark.png +0 -0
  298. package/registry/examples/screen/native/chat.light.png +0 -0
  299. package/registry/examples/screen/native/profile.dark.png +0 -0
  300. package/registry/examples/screen/native/profile.light.png +0 -0
  301. package/registry/examples/screen/native/settings.dark.png +0 -0
  302. package/registry/examples/screen/native/settings.light.png +0 -0
  303. package/registry/examples/search-field/native/cancel.dark.png +0 -0
  304. package/registry/examples/search-field/native/cancel.light.png +0 -0
  305. package/registry/examples/settings-layout/account.js +1 -1
  306. package/registry/examples/settings-layout/account.tsx +1 -1
  307. package/registry/examples/settings-layout/native/account.dark.png +0 -0
  308. package/registry/examples/settings-layout/native/account.light.png +0 -0
  309. package/registry/examples/settings-layout/sections.js +1 -1
  310. package/registry/examples/settings-layout/sections.tsx +1 -1
  311. package/registry/examples/showcase/native/slides.dark.png +0 -0
  312. package/registry/examples/showcase/native/slides.light.png +0 -0
  313. package/registry/examples/slider/native/default.dark.png +0 -0
  314. package/registry/examples/slider/native/default.light.png +0 -0
  315. package/registry/examples/slider/native/range.dark.png +0 -0
  316. package/registry/examples/slider/native/range.light.png +0 -0
  317. package/registry/examples/slider/native/stepped.dark.png +0 -0
  318. package/registry/examples/slider/native/stepped.light.png +0 -0
  319. package/registry/examples/slider/native/vertical.dark.png +0 -0
  320. package/registry/examples/slider/native/vertical.light.png +0 -0
  321. package/registry/examples/spinner/native/sizes.dark.png +0 -0
  322. package/registry/examples/spinner/native/sizes.light.png +0 -0
  323. package/registry/examples/split-view/messages.js +1 -1
  324. package/registry/examples/split-view/messages.tsx +1 -1
  325. package/registry/examples/status-page/building.js +1 -1
  326. package/registry/examples/status-page/building.tsx +1 -1
  327. package/registry/examples/step-progress/native/sign-up.dark.png +0 -0
  328. package/registry/examples/step-progress/native/sign-up.light.png +0 -0
  329. package/registry/examples/stepper/native/run.dark.png +0 -0
  330. package/registry/examples/stepper/native/run.light.png +0 -0
  331. package/registry/examples/sticky-action/phone.js +1 -1
  332. package/registry/examples/sticky-action/phone.tsx +1 -1
  333. package/registry/examples/switch/native/default.dark.png +0 -0
  334. package/registry/examples/switch/native/default.light.png +0 -0
  335. package/registry/examples/switch/native/settings.dark.png +0 -0
  336. package/registry/examples/switch/native/settings.light.png +0 -0
  337. package/registry/examples/tab-bar/native/main-sections.dark.png +0 -0
  338. package/registry/examples/tab-bar/native/main-sections.light.png +0 -0
  339. package/registry/examples/tabs/native/sections.dark.png +0 -0
  340. package/registry/examples/tabs/native/sections.light.png +0 -0
  341. package/registry/examples/tag-selector/native/interests.dark.png +0 -0
  342. package/registry/examples/tag-selector/native/interests.light.png +0 -0
  343. package/registry/examples/toast/native/snackbar.dark.png +0 -0
  344. package/registry/examples/toast/native/snackbar.light.png +0 -0
  345. package/registry/examples/toast/native/tones.dark.png +0 -0
  346. package/registry/examples/toast/native/tones.light.png +0 -0
  347. package/registry/examples/txt/native/tones.dark.png +0 -0
  348. package/registry/examples/txt/native/tones.light.png +0 -0
  349. package/registry/examples/update-prompt/native/default.dark.png +0 -0
  350. package/registry/examples/update-prompt/native/default.light.png +0 -0
  351. package/registry/examples/verified-badge/native/verified.dark.png +0 -0
  352. package/registry/examples/verified-badge/native/verified.light.png +0 -0
  353. package/registry/examples/vertical-video/native/rail.dark.png +0 -0
  354. package/registry/examples/vertical-video/native/rail.light.png +0 -0
  355. package/registry/examples/waveform/native/card.dark.png +0 -0
  356. package/registry/examples/waveform/native/card.light.png +0 -0
  357. package/registry/force-update-screen.json +1 -1
  358. package/registry/form.json +6 -6
  359. package/registry/glow-card.json +19 -19
  360. package/registry/index.json +20 -21
  361. package/registry/iso.json +7 -7
  362. package/registry/landing-page.json +2 -2
  363. package/registry/landscape.json +1 -1
  364. package/registry/link-card.json +15 -24
  365. package/registry/map.json +235 -6
  366. package/registry/marketing-layout.json +3 -3
  367. package/registry/media-gallery.json +1 -1
  368. package/registry/nav-bar.json +32 -4
  369. package/registry/pointer-light.json +17 -22
  370. package/registry/pricing-page.json +2 -2
  371. package/registry/product-page.json +2 -2
  372. package/registry/progress.json +2 -2
  373. package/registry/radio-group.json +1 -1
  374. package/registry/rail-nav.json +2 -2
  375. package/registry/service-card.json +1 -1
  376. package/registry/settings-layout.json +3 -3
  377. package/registry/site-footer.json +2 -2
  378. package/registry/sites.json +1 -1
  379. package/registry/slider.json +1 -1
  380. package/registry/split-view.json +2 -2
  381. package/registry/status-page.json +1 -1
  382. package/registry/sticky-action.json +2 -2
  383. package/registry/update-prompt.json +1 -1
  384. package/registry/video-player.json +1 -1
  385. package/dist/chunk-6ZYRUOTA.js.map +0 -1
  386. package/dist/chunk-AB5D3KBG.js +0 -37
  387. package/dist/chunk-AB5D3KBG.js.map +0 -1
  388. package/dist/chunk-APNIVNIX.js.map +0 -1
  389. package/dist/chunk-CHOJUCVE.js.map +0 -1
  390. package/dist/chunk-DZU6RMYD.js.map +0 -1
  391. package/dist/chunk-HAQWKORZ.js.map +0 -1
  392. package/dist/chunk-KM6VAKIE.js.map +0 -1
  393. package/dist/chunk-MQPC3P4T.js.map +0 -1
  394. package/dist/chunk-OUWPBSSL.js.map +0 -1
  395. package/dist/chunk-TFJDIOFK.js.map +0 -1
  396. package/registry/examples/argument-card/hover-light.js +0 -17
  397. package/registry/examples/argument-card/hover-light.tsx +0 -19
  398. package/registry/examples/link-card/hover-light.d.ts +0 -4
  399. package/registry/examples/link-card/hover-light.js +0 -18
  400. package/registry/examples/link-card/hover-light.tsx +0 -20
  401. /package/dist/{chunk-LYOPPBMC.js.map → chunk-KIBICUZK.js.map} +0 -0
  402. /package/dist/{chunk-HBZPJ3EP.js.map → chunk-NJFCSVPT.js.map} +0 -0
  403. /package/registry/examples/{argument-card/hover-light.d.ts → map/route.d.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  Button
4
- } from "./chunk-CHOJUCVE.js";
4
+ } from "./chunk-SJS6RJIT.js";
5
5
  import "./chunk-D3T54RSL.js";
6
6
  import "./chunk-WEVYKZIF.js";
7
7
  import {
@@ -42,7 +42,7 @@ function defineRecipe(config) {
42
42
 
43
43
  // src/button/recipe.ts
44
44
  var buttonRecipe = defineRecipe({
45
- base: "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] [&[data-loading]]:opacity-100",
45
+ base: "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition duration-150 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] [&[data-loading]]:opacity-100",
46
46
  variants: {
47
47
  variant: {
48
48
  primary: "bg-accent text-on-accent shadow-sm hover:bg-accent-hover",
@@ -56,9 +56,9 @@ var buttonRecipe = defineRecipe({
56
56
  danger: "border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20"
57
57
  },
58
58
  size: { sm: "h-8 px-3 text-xs", md: "h-10 px-4 text-sm", lg: "h-12 px-6 text-sm", icon: "h-10 w-10" },
59
- // `cut`: the Krizaka chamfer — 45° corners (CSS corner-shape, where supported; rounded elsewhere). The border, the
60
- // focus ring and the hover follow the cut, unlike a clip-path.
61
- shape: { rounded: "rounded-lg", pill: "rounded-full", cut: "rounded-[10px] [corner-shape:bevel]" }
59
+ // One clean shape (krizaka-ui#393): an 8 px radius (`--kz-radius-sm`, the radius of a field — a button beside an
60
+ // input lines up with it), the pill on demand. `cut` (the retired chamfer) is a deprecated alias of `rounded`.
61
+ shape: { rounded: "rounded-sm", pill: "rounded-full", cut: "rounded-sm" }
62
62
  },
63
63
  defaultVariants: { variant: "secondary", size: "md", shape: "rounded" }
64
64
  });
@@ -67,6 +67,12 @@ var buttonRecipe = defineRecipe({
67
67
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
68
68
  var buttonVariants = tv(buttonRecipe);
69
69
  var STATUS_TEXT = { success: "text-fg-success", error: "text-fg-danger" };
70
+ var warnedCut = false;
71
+ function warnCut() {
72
+ if (warnedCut || typeof process === "undefined" || process.env.NODE_ENV === "production") return;
73
+ warnedCut = true;
74
+ console.warn('@krizaka/ui/button: shape="cut" is deprecated (krizaka-ui#393) and now draws the default rounded shape. Remove the prop.');
75
+ }
70
76
  function Button({
71
77
  asChild,
72
78
  loading,
@@ -74,8 +80,8 @@ function Button({
74
80
  status,
75
81
  announce,
76
82
  indicator = true,
77
- shimmer,
78
- magnetic,
83
+ shimmer: _shimmer,
84
+ magnetic: _magnetic,
79
85
  variant,
80
86
  size,
81
87
  shape,
@@ -85,6 +91,7 @@ function Button({
85
91
  ...props
86
92
  }) {
87
93
  const Comp = asChild ? Slot.Root : "button";
94
+ if (shape === "cut") warnCut();
88
95
  const known = loading && typeof progress === "number" && Number.isFinite(progress);
89
96
  const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;
90
97
  const glyph = indicator && !asChild && (loading || status) ? status ?? "loading" : null;
@@ -97,14 +104,13 @@ function Button({
97
104
  "data-loading": loading ? "" : void 0,
98
105
  "data-variant": variant ?? "secondary",
99
106
  "data-kz-status": status ?? void 0,
100
- "data-kz-magnetic": magnetic ? "" : void 0,
101
107
  disabled: asChild ? void 0 : disabled || loading,
102
108
  "aria-disabled": asChild && (disabled || loading) ? true : void 0,
103
109
  className: buttonVariants({
104
110
  variant,
105
111
  size,
106
112
  shape,
107
- className: cn(known && "relative isolate overflow-hidden", shimmer && "kz-sheen", className)
113
+ className: cn(known && "relative isolate overflow-hidden", className)
108
114
  }),
109
115
  ...props,
110
116
  children: asChild ? children : /* @__PURE__ */ jsxs2(Fragment, { children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/button/button.tsx","../src/spinner/glyph.tsx","../src/recipes/define.ts","../src/button/recipe.ts","../src/continue-prompt/continue-prompt.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { LoaderGlyph } from \"../spinner/glyph\";\nimport { buttonRecipe } from \"./recipe\";\n\nexport const buttonVariants = tv(buttonRecipe);\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n * `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * rounded · pill · cut (45° corners, the Krizaka chamfer).\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /**\n * Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\n * button keeps its colour.\n */\n loading?: boolean;\n /**\n * Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\n * upload, an export).\n */\n progress?: number | null;\n /**\n * How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\n * the status colour opens around it. Clear it to return to rest.\n */\n status?: \"success\" | \"error\" | null;\n /** A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated. */\n announce?: string;\n /**\n * Shows the glyph while `loading` / with a `status`. `false`: you draw your own.\n * @default true\n */\n indicator?: boolean;\n /** A sheen of light crosses the button on hover — for the one action a page is about. */\n shimmer?: boolean;\n /** The button leans a few pixels toward a fine pointer (driven by `MotionObserver`; never under reduced motion or on touch). */\n magnetic?: boolean;\n };\n\nconst STATUS_TEXT = { success: \"text-fg-success\", error: \"text-fg-danger\" } as const;\n\nexport function Button({\n asChild,\n loading,\n progress,\n status,\n announce,\n indicator = true,\n shimmer,\n magnetic,\n variant,\n size,\n shape,\n className,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n const known = loading && typeof progress === \"number\" && Number.isFinite(progress);\n const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;\n const glyph = indicator && !asChild && (loading || status) ? (status ?? \"loading\") : null;\n // On a filled variant the glyph stays in the label's colour; on the others it takes the status colour.\n const filled = variant === \"primary\" || variant === \"gradient\";\n const button = (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n data-kz-status={status ?? undefined}\n data-kz-magnetic={magnetic ? \"\" : undefined}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({\n variant,\n size,\n shape,\n className: cn(known && \"relative isolate overflow-hidden\", shimmer && \"kz-sheen\", className),\n })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {known && (\n <span aria-hidden className=\"absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500\" style={{ width: `${ratio * 100}%` }} />\n )}\n {glyph && (\n <span\n aria-hidden\n data-slot=\"indicator\"\n className=\"-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0\"\n >\n <span className=\"overflow-hidden\">\n <LoaderGlyph state={glyph} value={known ? ratio : null} className={cn(\"h-4 w-4\", glyph !== \"loading\" && !filled && STATUS_TEXT[glyph])} />\n </span>\n </span>\n )}\n {children}\n </>\n )}\n </Comp>\n );\n if (announce === undefined || asChild) return button;\n return (\n <>\n {button}\n <span role=\"status\" className=\"sr-only\">\n {announce}\n </span>\n </>\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. Loading or with a status, the glyph takes the icon's place. */\nexport function IconButton({ label, size = \"icon\", children, ...props }: IconButtonProps) {\n const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);\n return (\n <Button aria-label={label} title={label} size={size} {...props}>\n {swap ? null : children}\n </Button>\n );\n}\n","// The Krizaka loader glyph, server-safe: a hexagon (the marks' shape) traced by a segment of light around a node that\n// breathes; determinate, it fills to its value; done, the trace closes and a check (or a cross) draws itself. Animated by\n// motion.css (`kz-loader-*`); still under prefers-reduced-motion — a segment at rest and the node lit, never blank.\nimport type * as React from \"react\";\n\n/** The hexagon, pointy top, radius 9 around (12, 12). */\nconst HEX = \"M12 3 19.79 7.5 19.79 16.5 12 21 4.21 16.5 4.21 7.5Z\";\n\n/** What the glyph shows: a wait (with an optional value), or how it ended. */\nexport type LoaderGlyphState = \"loading\" | \"success\" | \"error\";\n\nexport interface LoaderGlyphProps extends Omit<React.ComponentProps<\"svg\">, \"children\"> {\n /** loading · success · error. */\n state?: LoaderGlyphState;\n /** Between 0 and 1: a determinate wait, the trace grows to it. Absent: indeterminate. */\n value?: number | null;\n}\n\n/** The glyph alone (decorative): the Spinner, the Loader and the Button's `loading` draw it. */\nexport function LoaderGlyph({ state = \"loading\", value, ...props }: LoaderGlyphProps) {\n const known = typeof value === \"number\" && Number.isFinite(value);\n const fill = state !== \"loading\" ? 100 : known ? Math.round(Math.min(1, Math.max(0, value)) * 100) : null;\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden data-state={state} data-progress={fill === null ? undefined : fill} {...props}>\n <path d={HEX} stroke=\"currentColor\" strokeOpacity=\"0.22\" strokeWidth=\"2.2\" strokeLinejoin=\"round\" />\n <path\n d={HEX}\n pathLength={100}\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n className=\"kz-loader-trace\"\n strokeDasharray={fill === null ? undefined : `${fill} ${100 - fill}`}\n />\n {state === \"loading\" && <circle cx=\"12\" cy=\"12\" r=\"2.6\" fill=\"currentColor\" className=\"kz-loader-node\" />}\n {state === \"success\" && <path d=\"M8.3 12.3l2.6 2.6 4.9-5.3\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"kz-loader-mark\" />}\n {state === \"error\" && <path d=\"M9.4 9.4l5.2 5.2M14.6 9.4l-5.2 5.2\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" className=\"kz-loader-mark\" />}\n </svg>\n );\n}\n","import type { TV } from \"tailwind-variants\";\n\n/** What a recipe is made of: the `tv()` options — `base`, `slots`, `variants`, `defaultVariants`, `compoundVariants`. */\nexport type RecipeConfig = Parameters<TV>[0];\n\n/**\n * A recipe is data: the variants of a component (a `variant`, a `size`, a `tone`…) as classes of the Krizaka tokens.\n * `defineRecipe` only keeps the literal types, so `tv(recipe)` is typed exactly as `tv({ … })` would be (the web side) and\n * `nativeRecipe(recipe)` reads the same classes into styles on the theme's roles (the native side, `./native`).\n *\n * Sizes are a variant dimension (`size: { sm: \"h-8 px-3 text-xs\" }`); states are the prefixes (`hover:`, `disabled:`,\n * `data-[state=on]:`). Write colours as roles (`bg-accent`, `text-fg-secondary`, `border-border-default`, `ring-accent/40`),\n * spacing as Tailwind units (`h-10`, `px-4`), type as `text-sm` / `text-[11px]` / `font-semibold`.\n */\nexport function defineRecipe<const C extends RecipeConfig>(config: C): C {\n return config;\n}\n","// The button's variants, written once as classes of the Krizaka tokens: the web wears them with `tv(buttonRecipe)`\n// (button.tsx), React Native reads the same classes into styles (native/button.tsx, `nativeRecipe`).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const buttonRecipe = defineRecipe({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition-all \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] \" +\n // Busy is not unavailable: a loading button keeps its colour (it is disabled only so it is not pressed twice).\n \"[&[data-loading]]:opacity-100\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).\n gradient: \"bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest\n // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n // `cut`: the Krizaka chamfer — 45° corners (CSS corner-shape, where supported; rounded elsewhere). The border, the\n // focus ring and the hover follow the cut, unlike a clip-path.\n shape: { rounded: \"rounded-lg\", pill: \"rounded-full\", cut: \"rounded-[10px] [corner-shape:bevel]\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n","// Server-safe. The last call of a page or a flow (story.css): a short question, a figure that counts (days, seats,\n// seconds), what to say before leaving, and the one action that continues — “Keep your studio? · 3 days left”.\nimport type * as React from \"react\";\n\nimport { Button } from \"../button/button\";\nimport { cn } from \"../cn\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport type ContinuePromptProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> & {\n /** The question (“Keep your studio?”, arcade “Continue?”). */\n title: React.ReactNode;\n /** What counts, beside the question: a figure, or a live `Countdown` for a real deadline. Decorative: say it in words too. */\n count?: React.ReactNode;\n /**\n * A count that ticks down once when its scene plays (`{ from: 9, to: 7 }`), then waits; still under reduced motion.\n * Use `count` for anything else.\n */\n countdown?: { readonly from: number; readonly to: number };\n /** Inside the screen, under the question: a heading, a line, links — the closing call itself. */\n children?: React.ReactNode;\n /** The action's words. */\n actionLabel: React.ReactNode;\n /** Runs the action (a client handler). Without `href`, the action is a `button`. */\n onAction?: React.MouseEventHandler<HTMLButtonElement>;\n /** Makes the action a link. */\n href?: string;\n /** A key-cap before the action's words (“Enter”, arcade “1P Start”). Decorative. */\n actionKey?: React.ReactNode;\n /** The action's glyph after its words; default an arrow. Decorative. */\n actionIcon?: React.ReactNode;\n /** A small line at the top of the card (where it comes from). */\n caption?: React.ReactNode;\n /** In the deck, in the accent: the call (“Last places”, arcade “Insert coin”). */\n highlight?: React.ReactNode;\n /** Beside the highlight: how (“One click, no card”). */\n hint?: React.ReactNode;\n /** A status with a green dot (“All features on”, “Credit 01”). */\n status?: React.ReactNode;\n /**\n * `default`: a calm card. `arcade`: the cabinet — screws, a dark CRT that switches on, a coin deck.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope (`krizaka` → `.brand-krizaka`). */\n brand?: string;\n};\n\nconst Arrow = () => (\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M5 12h14M13 6l6 6-6 6\" />\n </svg>\n);\n\n/** One countdown's keyframes, named by its range: the digit steps from `from` to `to`, once. */\nfunction countdownCss(from: number, to: number) {\n const steps = Math.max(1, Math.abs(from - to));\n const frames = Array.from({ length: steps + 1 }, (_, i) => {\n const n = from > to ? from - i : from + i;\n return `${Math.round((i / steps) * 100)}% { content: \"${n}\"; }`;\n }).join(\" \");\n return `@keyframes kzs-count-${from}-${to} { ${frames} }\n@media (prefers-reduced-motion: no-preference) {\n [data-in] .kzs-prompt-count[data-from=\"${from}\"][data-to=\"${to}\"] { color: transparent; }\n [data-in] .kzs-prompt-count[data-from=\"${from}\"][data-to=\"${to}\"]::after { content: \"${to}\"; animation: kzs-count-${from}-${to} ${steps}s steps(1) 1s both; }\n}`;\n}\n\n/** A last call: a question, what counts, the closing words, the one action that continues — a `button`, or a link. */\nexport function ContinuePrompt({\n title,\n count,\n countdown,\n children,\n actionLabel,\n onAction,\n href,\n actionKey,\n actionIcon,\n caption,\n highlight,\n hint,\n status,\n variant,\n brand,\n className,\n ...props\n}: ContinuePromptProps) {\n const arcade = variant === \"arcade\";\n const inner = (\n <>\n {actionKey && (\n <span className=\"kzs-prompt-key\" aria-hidden>\n {actionKey}\n </span>\n )}\n {actionLabel}\n <span className=\"kzs-prompt-icon\" aria-hidden>\n {actionIcon ?? <Arrow />}\n </span>\n </>\n );\n const button = { variant: arcade ? (\"secondary\" as const) : (\"primary\" as const), size: \"md\" as const, shape: arcade ? (\"cut\" as const) : undefined, className: \"kzs-prompt-action\" };\n return (\n <div data-kzs-scene=\"\" className={cn(\"kzs-prompt\", storyVariantClass(variant), brandClass(brand), className)} {...props}>\n {countdown && <style>{countdownCss(countdown.from, countdown.to)}</style>}\n {(caption || arcade) && (\n <div className=\"kzs-prompt-top\">\n <span className=\"kzs-prompt-screw\" aria-hidden />\n {caption && <span>{caption}</span>}\n <span className=\"kzs-prompt-screw\" aria-hidden />\n </div>\n )}\n <div className={cn(\"kzs-prompt-screen\", arcade && \"theme-dark\", brandClass(brand))}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n <span className=\"kzs-prompt-glass\" aria-hidden />\n <div className=\"kzs-prompt-content\">\n <div className=\"kzs-prompt-head\">\n <span className=\"kzs-prompt-title\">{title}</span>\n {countdown ? (\n <span className=\"kzs-prompt-count\" data-from={countdown.from} data-to={countdown.to} aria-hidden>\n {countdown.from}\n </span>\n ) : (\n count !== undefined && (\n <span className=\"kzs-prompt-count\" aria-hidden>\n {count}\n </span>\n )\n )}\n </div>\n {children}\n </div>\n </div>\n <div className=\"kzs-prompt-deck\">\n {(highlight || hint || status) && (\n <div className=\"kzs-prompt-coin\">\n {highlight && <span className=\"kzs-prompt-highlight\">{highlight}</span>}\n {hint && <span className=\"kzs-prompt-hint\">{hint}</span>}\n {status && (\n <span className=\"kzs-prompt-status\">\n <span className=\"kzs-prompt-led\" aria-hidden />\n {status}\n </span>\n )}\n </div>\n )}\n {href ? (\n <Button asChild {...button}>\n <a href={href}>{inner}</a>\n </Button>\n ) : (\n <Button type=\"button\" onClick={onAction} {...button}>\n {inner}\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","Fragment","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/button/button.tsx","../src/spinner/glyph.tsx","../src/recipes/define.ts","../src/button/recipe.ts","../src/continue-prompt/continue-prompt.tsx"],"sourcesContent":["// Server-safe: no hook, no context. `buttonVariants` styles a <Link> or a Server Component without the component.\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { LoaderGlyph } from \"../spinner/glyph\";\nimport { buttonRecipe } from \"./recipe\";\n\nexport const buttonVariants = tv(buttonRecipe);\n\nexport type ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonProps = React.ComponentProps<\"button\"> &\n ButtonVariants & {\n /**\n * The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n * `ghost`, `danger`.\n * @default \"secondary\"\n */\n variant?: ButtonVariants[\"variant\"];\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"md\"\n */\n size?: ButtonVariants[\"size\"];\n /**\n * `rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\n * retired) — it draws `rounded` and warns in development; it will be removed in 4.0.\n * @default \"rounded\"\n */\n shape?: ButtonVariants[\"shape\"];\n /** Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. */\n asChild?: boolean;\n /**\n * Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\n * button keeps its colour.\n */\n loading?: boolean;\n /**\n * Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\n * upload, an export).\n */\n progress?: number | null;\n /**\n * How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\n * the status colour opens around it. Clear it to return to rest.\n */\n status?: \"success\" | \"error\" | null;\n /** A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated. */\n announce?: string;\n /**\n * Shows the glyph while `loading` / with a `status`. `false`: you draw your own.\n * @default true\n */\n indicator?: boolean;\n /** @deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0. */\n shimmer?: boolean;\n /** @deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0. */\n magnetic?: boolean;\n };\n\nconst STATUS_TEXT = { success: \"text-fg-success\", error: \"text-fg-danger\" } as const;\n\nlet warnedCut = false;\n/** `shape=\"cut\"` (the chamfer) is retired: one warning per page in development, never in production. */\nfunction warnCut() {\n if (warnedCut || typeof process === \"undefined\" || process.env.NODE_ENV === \"production\") return;\n warnedCut = true;\n console.warn('@krizaka/ui/button: shape=\"cut\" is deprecated (krizaka-ui#393) and now draws the default rounded shape. Remove the prop.');\n}\n\nexport function Button({\n asChild,\n loading,\n progress,\n status,\n announce,\n indicator = true,\n shimmer: _shimmer,\n magnetic: _magnetic,\n variant,\n size,\n shape,\n className,\n disabled,\n children,\n ...props\n}: ButtonProps) {\n const Comp = asChild ? Slot.Root : \"button\";\n if (shape === \"cut\") warnCut();\n const known = loading && typeof progress === \"number\" && Number.isFinite(progress);\n const ratio = known ? Math.min(1, Math.max(0, progress)) : 0;\n const glyph = indicator && !asChild && (loading || status) ? (status ?? \"loading\") : null;\n // On a filled variant the glyph stays in the label's colour; on the others it takes the status colour.\n const filled = variant === \"primary\" || variant === \"gradient\";\n const button = (\n <Comp\n type={asChild ? undefined : \"button\"}\n aria-busy={loading || undefined}\n data-loading={loading ? \"\" : undefined}\n data-variant={variant ?? \"secondary\"}\n data-kz-status={status ?? undefined}\n disabled={asChild ? undefined : disabled || loading}\n aria-disabled={asChild && (disabled || loading) ? true : undefined}\n className={buttonVariants({\n variant,\n size,\n shape,\n className: cn(known && \"relative isolate overflow-hidden\", className),\n })}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n {known && (\n <span aria-hidden className=\"absolute inset-y-0 left-0 -z-10 bg-current opacity-15 transition-[width] duration-500\" style={{ width: `${ratio * 100}%` }} />\n )}\n {glyph && (\n <span\n aria-hidden\n data-slot=\"indicator\"\n className=\"-my-1 grid grid-cols-[1fr] transition-[grid-template-columns,margin,opacity] duration-300 starting:-mr-2 starting:grid-cols-[0fr] starting:opacity-0\"\n >\n <span className=\"overflow-hidden\">\n <LoaderGlyph state={glyph} value={known ? ratio : null} className={cn(\"h-4 w-4\", glyph !== \"loading\" && !filled && STATUS_TEXT[glyph])} />\n </span>\n </span>\n )}\n {children}\n </>\n )}\n </Comp>\n );\n if (announce === undefined || asChild) return button;\n return (\n <>\n {button}\n <span role=\"status\" className=\"sr-only\">\n {announce}\n </span>\n </>\n );\n}\n\nexport type IconButtonProps = Omit<ButtonProps, \"size\"> & {\n /** The accessible name (and tooltip) of the button — required, passed translated. */\n label: string;\n /**\n * sm · md · lg, or `icon` (a square).\n * @default \"icon\"\n */\n size?: ButtonProps[\"size\"];\n};\n\n/** An icon-only button: `label` is required, it is its accessible name. Loading or with a status, the glyph takes the icon's place. */\nexport function IconButton({ label, size = \"icon\", children, ...props }: IconButtonProps) {\n const swap = props.indicator !== false && !props.asChild && (props.loading || props.status);\n return (\n <Button aria-label={label} title={label} size={size} {...props}>\n {swap ? null : children}\n </Button>\n );\n}\n","// The Krizaka loader glyph, server-safe: a hexagon (the marks' shape) traced by a segment of light around a node that\n// breathes; determinate, it fills to its value; done, the trace closes and a check (or a cross) draws itself. Animated by\n// motion.css (`kz-loader-*`); still under prefers-reduced-motion — a segment at rest and the node lit, never blank.\nimport type * as React from \"react\";\n\n/** The hexagon, pointy top, radius 9 around (12, 12). */\nconst HEX = \"M12 3 19.79 7.5 19.79 16.5 12 21 4.21 16.5 4.21 7.5Z\";\n\n/** What the glyph shows: a wait (with an optional value), or how it ended. */\nexport type LoaderGlyphState = \"loading\" | \"success\" | \"error\";\n\nexport interface LoaderGlyphProps extends Omit<React.ComponentProps<\"svg\">, \"children\"> {\n /** loading · success · error. */\n state?: LoaderGlyphState;\n /** Between 0 and 1: a determinate wait, the trace grows to it. Absent: indeterminate. */\n value?: number | null;\n}\n\n/** The glyph alone (decorative): the Spinner, the Loader and the Button's `loading` draw it. */\nexport function LoaderGlyph({ state = \"loading\", value, ...props }: LoaderGlyphProps) {\n const known = typeof value === \"number\" && Number.isFinite(value);\n const fill = state !== \"loading\" ? 100 : known ? Math.round(Math.min(1, Math.max(0, value)) * 100) : null;\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden data-state={state} data-progress={fill === null ? undefined : fill} {...props}>\n <path d={HEX} stroke=\"currentColor\" strokeOpacity=\"0.22\" strokeWidth=\"2.2\" strokeLinejoin=\"round\" />\n <path\n d={HEX}\n pathLength={100}\n stroke=\"currentColor\"\n strokeWidth=\"2.2\"\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n className=\"kz-loader-trace\"\n strokeDasharray={fill === null ? undefined : `${fill} ${100 - fill}`}\n />\n {state === \"loading\" && <circle cx=\"12\" cy=\"12\" r=\"2.6\" fill=\"currentColor\" className=\"kz-loader-node\" />}\n {state === \"success\" && <path d=\"M8.3 12.3l2.6 2.6 4.9-5.3\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"kz-loader-mark\" />}\n {state === \"error\" && <path d=\"M9.4 9.4l5.2 5.2M14.6 9.4l-5.2 5.2\" pathLength={20} stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" className=\"kz-loader-mark\" />}\n </svg>\n );\n}\n","import type { TV } from \"tailwind-variants\";\n\n/** What a recipe is made of: the `tv()` options — `base`, `slots`, `variants`, `defaultVariants`, `compoundVariants`. */\nexport type RecipeConfig = Parameters<TV>[0];\n\n/**\n * A recipe is data: the variants of a component (a `variant`, a `size`, a `tone`…) as classes of the Krizaka tokens.\n * `defineRecipe` only keeps the literal types, so `tv(recipe)` is typed exactly as `tv({ … })` would be (the web side) and\n * `nativeRecipe(recipe)` reads the same classes into styles on the theme's roles (the native side, `./native`).\n *\n * Sizes are a variant dimension (`size: { sm: \"h-8 px-3 text-xs\" }`); states are the prefixes (`hover:`, `disabled:`,\n * `data-[state=on]:`). Write colours as roles (`bg-accent`, `text-fg-secondary`, `border-border-default`, `ring-accent/40`),\n * spacing as Tailwind units (`h-10`, `px-4`), type as `text-sm` / `text-[11px]` / `font-semibold`.\n */\nexport function defineRecipe<const C extends RecipeConfig>(config: C): C {\n return config;\n}\n","// The button's variants, written once as classes of the Krizaka tokens: the web wears them with `tv(buttonRecipe)`\n// (button.tsx), React Native reads the same classes into styles (native/button.tsx, `nativeRecipe`).\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const buttonRecipe = defineRecipe({\n base:\n \"inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap font-semibold transition duration-150 \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 \" +\n \"disabled:pointer-events-none disabled:opacity-40 data-loading:cursor-progress active:scale-[0.98] \" +\n // Busy is not unavailable: a loading button keeps its colour (it is disabled only so it is not pressed twice).\n \"[&[data-loading]]:opacity-100\",\n variants: {\n variant: {\n primary: \"bg-accent text-on-accent shadow-sm hover:bg-accent-hover\",\n // The brand's signature: accent → accent-2 (on-accent reads on both stops, tested in @krizaka/tokens).\n gradient: \"bg-linear-to-r from-accent to-accent-2 text-on-accent shadow-sm hover:brightness-110\",\n secondary: \"border border-border-default bg-surface-2 text-fg hover:border-border-strong hover:bg-surface-3\",\n outline: \"border border-border-default bg-transparent text-fg hover:border-accent hover:text-fg-accent\",\n ghost: \"text-fg-secondary hover:bg-surface-2 hover:text-fg\",\n // The border and the tint carry the danger; the label stays the primary text role, legible on the tint at rest\n // and hovered over every surface (`text-fg-danger` is for text set directly on a surface).\n danger: \"border border-danger/50 bg-danger/10 text-fg hover:border-danger hover:bg-danger/20\",\n },\n size: { sm: \"h-8 px-3 text-xs\", md: \"h-10 px-4 text-sm\", lg: \"h-12 px-6 text-sm\", icon: \"h-10 w-10\" },\n // One clean shape (krizaka-ui#393): an 8 px radius (`--kz-radius-sm`, the radius of a field — a button beside an\n // input lines up with it), the pill on demand. `cut` (the retired chamfer) is a deprecated alias of `rounded`.\n shape: { rounded: \"rounded-sm\", pill: \"rounded-full\", cut: \"rounded-sm\" },\n },\n defaultVariants: { variant: \"secondary\", size: \"md\", shape: \"rounded\" },\n});\n","// Server-safe. The last call of a page or a flow (story.css): a short question, a figure that counts (days, seats,\n// seconds), what to say before leaving, and the one action that continues — “Keep your studio? · 3 days left”.\nimport type * as React from \"react\";\n\nimport { Button } from \"../button/button\";\nimport { cn } from \"../cn\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport type ContinuePromptProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> & {\n /** The question (“Keep your studio?”, arcade “Continue?”). */\n title: React.ReactNode;\n /** What counts, beside the question: a figure, or a live `Countdown` for a real deadline. Decorative: say it in words too. */\n count?: React.ReactNode;\n /**\n * A count that ticks down once when its scene plays (`{ from: 9, to: 7 }`), then waits; still under reduced motion.\n * Use `count` for anything else.\n */\n countdown?: { readonly from: number; readonly to: number };\n /** Inside the screen, under the question: a heading, a line, links — the closing call itself. */\n children?: React.ReactNode;\n /** The action's words. */\n actionLabel: React.ReactNode;\n /** Runs the action (a client handler). Without `href`, the action is a `button`. */\n onAction?: React.MouseEventHandler<HTMLButtonElement>;\n /** Makes the action a link. */\n href?: string;\n /** A key-cap before the action's words (“Enter”, arcade “1P Start”). Decorative. */\n actionKey?: React.ReactNode;\n /** The action's glyph after its words; default an arrow. Decorative. */\n actionIcon?: React.ReactNode;\n /** A small line at the top of the card (where it comes from). */\n caption?: React.ReactNode;\n /** In the deck, in the accent: the call (“Last places”, arcade “Insert coin”). */\n highlight?: React.ReactNode;\n /** Beside the highlight: how (“One click, no card”). */\n hint?: React.ReactNode;\n /** A status with a green dot (“All features on”, “Credit 01”). */\n status?: React.ReactNode;\n /**\n * `default`: a calm card. `arcade`: the cabinet — screws, a dark CRT that switches on, a coin deck.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope (`krizaka` → `.brand-krizaka`). */\n brand?: string;\n};\n\nconst Arrow = () => (\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M5 12h14M13 6l6 6-6 6\" />\n </svg>\n);\n\n/** One countdown's keyframes, named by its range: the digit steps from `from` to `to`, once. */\nfunction countdownCss(from: number, to: number) {\n const steps = Math.max(1, Math.abs(from - to));\n const frames = Array.from({ length: steps + 1 }, (_, i) => {\n const n = from > to ? from - i : from + i;\n return `${Math.round((i / steps) * 100)}% { content: \"${n}\"; }`;\n }).join(\" \");\n return `@keyframes kzs-count-${from}-${to} { ${frames} }\n@media (prefers-reduced-motion: no-preference) {\n [data-in] .kzs-prompt-count[data-from=\"${from}\"][data-to=\"${to}\"] { color: transparent; }\n [data-in] .kzs-prompt-count[data-from=\"${from}\"][data-to=\"${to}\"]::after { content: \"${to}\"; animation: kzs-count-${from}-${to} ${steps}s steps(1) 1s both; }\n}`;\n}\n\n/** A last call: a question, what counts, the closing words, the one action that continues — a `button`, or a link. */\nexport function ContinuePrompt({\n title,\n count,\n countdown,\n children,\n actionLabel,\n onAction,\n href,\n actionKey,\n actionIcon,\n caption,\n highlight,\n hint,\n status,\n variant,\n brand,\n className,\n ...props\n}: ContinuePromptProps) {\n const arcade = variant === \"arcade\";\n const inner = (\n <>\n {actionKey && (\n <span className=\"kzs-prompt-key\" aria-hidden>\n {actionKey}\n </span>\n )}\n {actionLabel}\n <span className=\"kzs-prompt-icon\" aria-hidden>\n {actionIcon ?? <Arrow />}\n </span>\n </>\n );\n const button = { variant: arcade ? (\"secondary\" as const) : (\"primary\" as const), size: \"md\" as const, shape: arcade ? (\"cut\" as const) : undefined, className: \"kzs-prompt-action\" };\n return (\n <div data-kzs-scene=\"\" className={cn(\"kzs-prompt\", storyVariantClass(variant), brandClass(brand), className)} {...props}>\n {countdown && <style>{countdownCss(countdown.from, countdown.to)}</style>}\n {(caption || arcade) && (\n <div className=\"kzs-prompt-top\">\n <span className=\"kzs-prompt-screw\" aria-hidden />\n {caption && <span>{caption}</span>}\n <span className=\"kzs-prompt-screw\" aria-hidden />\n </div>\n )}\n <div className={cn(\"kzs-prompt-screen\", arcade && \"theme-dark\", brandClass(brand))}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n <span className=\"kzs-prompt-glass\" aria-hidden />\n <div className=\"kzs-prompt-content\">\n <div className=\"kzs-prompt-head\">\n <span className=\"kzs-prompt-title\">{title}</span>\n {countdown ? (\n <span className=\"kzs-prompt-count\" data-from={countdown.from} data-to={countdown.to} aria-hidden>\n {countdown.from}\n </span>\n ) : (\n count !== undefined && (\n <span className=\"kzs-prompt-count\" aria-hidden>\n {count}\n </span>\n )\n )}\n </div>\n {children}\n </div>\n </div>\n <div className=\"kzs-prompt-deck\">\n {(highlight || hint || status) && (\n <div className=\"kzs-prompt-coin\">\n {highlight && <span className=\"kzs-prompt-highlight\">{highlight}</span>}\n {hint && <span className=\"kzs-prompt-hint\">{hint}</span>}\n {status && (\n <span className=\"kzs-prompt-status\">\n <span className=\"kzs-prompt-led\" aria-hidden />\n {status}\n </span>\n )}\n </div>\n )}\n {href ? (\n <Button asChild {...button}>\n <a href={href}>{inner}</a>\n </Button>\n ) : (\n <Button type=\"button\" onClick={onAction} {...button}>\n {inner}\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","Fragment","jsx","jsxs"]}
@@ -9,10 +9,10 @@ import {
9
9
  dataTableCsv,
10
10
  dataTableLabels,
11
11
  useDataTable
12
- } from "./chunk-LYOPPBMC.js";
12
+ } from "./chunk-KIBICUZK.js";
13
13
  import "./chunk-7Z4KHPFC.js";
14
14
  import "./chunk-JXLDUDTD.js";
15
- import "./chunk-DZU6RMYD.js";
15
+ import "./chunk-3DHNN5V7.js";
16
16
  import "./chunk-KVDB4GXV.js";
17
17
  import "./chunk-2PNLHZLT.js";
18
18
  import "./chunk-7UCPGXKN.js";
package/dist/dialog.js CHANGED
@@ -10,10 +10,10 @@ import {
10
10
  Sheet,
11
11
  dialog,
12
12
  useReturnFocus
13
- } from "./chunk-HBZPJ3EP.js";
13
+ } from "./chunk-NJFCSVPT.js";
14
14
  import {
15
15
  Button
16
- } from "./chunk-CHOJUCVE.js";
16
+ } from "./chunk-SJS6RJIT.js";
17
17
  import "./chunk-D3T54RSL.js";
18
18
  import "./chunk-WEVYKZIF.js";
19
19
  import "./chunk-NSLXEDIS.js";
@@ -90,8 +90,31 @@ type EngineFlowProps = Omit<React.ComponentProps<"figure">, "children"> & {
90
90
  /** Photon speed, in units per second (the stage is 100 units wide).
91
91
  * @default 16 */
92
92
  speed?: number;
93
+ /** How many photons share a conduit: `sparse` one or two, `normal` two to four, `dense` four to eight.
94
+ * @default "normal" */
95
+ density?: FlowDensity;
96
+ /** When the photons travel: `always`; `hover` only while the pointer or focus is on the figure (they rest along the
97
+ * conduits otherwise); `active` only on the conduit of the chosen node (the others show nothing). Off screen they
98
+ * are always paused, and still under reduced motion.
99
+ * @default "always" */
100
+ trigger?: FlowTrigger;
101
+ /** The photons' timing function: `linear` (a steady stream), `ease-in-out` (a pulse that swells and settles), or any
102
+ * CSS `<easing-function>` (`cubic-bezier(.2,0,0,1)`, `steps(6)`).
103
+ * @default "linear" */
104
+ easing?: FlowEasing;
105
+ /** Milliseconds between one conduit's photons and the next's: 0 sends them all together.
106
+ * @default 300 */
107
+ stagger?: number;
108
+ /** The engine's mark swells slowly (a loop, still under reduced motion).
109
+ * @default true */
110
+ breathe?: boolean;
93
111
  };
112
+ type FlowDensity = "sparse" | "normal" | "dense";
113
+ type FlowTrigger = "always" | "hover" | "active";
114
+ type FlowEasing = "linear" | "ease-in-out" | (string & {});
115
+ /** How many photons a conduit of this length carries (evenly spaced, so the gap is `length / count`). */
116
+ declare function photonCount(length: number, density?: FlowDensity): number;
94
117
  /** An engine at the hub and the apps it serves, with what travels between them. */
95
- declare function EngineFlow({ label, hub, nodes, layout, compactLayout, particles, conduit, hint, defaultActive, speed, className, ...props }: EngineFlowProps): React.JSX.Element;
118
+ declare function EngineFlow({ label, hub, nodes, layout, compactLayout, particles, conduit, hint, defaultActive, speed, density, trigger, easing, stagger, breathe, className, ...props }: EngineFlowProps): React.JSX.Element;
96
119
 
97
- export { EngineFlow, type EngineFlowHub, type EngineFlowNode, type EngineFlowProps, FLOW_HEIGHT, type FlowConduit, type FlowGeometry, type FlowLayout, type FlowPoint, flowGeometry, flowPositions };
120
+ export { EngineFlow, type EngineFlowHub, type EngineFlowNode, type EngineFlowProps, FLOW_HEIGHT, type FlowConduit, type FlowDensity, type FlowEasing, type FlowGeometry, type FlowLayout, type FlowPoint, type FlowTrigger, flowGeometry, flowPositions, photonCount };
@@ -83,6 +83,12 @@ function flowGeometry(layout, count, conduit = "bezier") {
83
83
 
84
84
  // src/engine-flow/engine-flow.tsx
85
85
  import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
86
+ function photonCount(length, density = "normal") {
87
+ const base = Math.round(length / 16);
88
+ if (density === "sparse") return Math.min(2, Math.max(1, Math.round(base / 2)));
89
+ if (density === "dense") return Math.min(8, Math.max(4, base * 2));
90
+ return Math.min(4, Math.max(2, base));
91
+ }
86
92
  function Stage({
87
93
  layout,
88
94
  variant,
@@ -91,6 +97,10 @@ function Stage({
91
97
  conduit,
92
98
  particles,
93
99
  speed,
100
+ density,
101
+ easing,
102
+ stagger,
103
+ breathe,
94
104
  active,
95
105
  onActive,
96
106
  detailId
@@ -101,11 +111,14 @@ function Stage({
101
111
  /* @__PURE__ */ jsx("svg", { viewBox: `0 0 ${g.width} ${g.height}`, "aria-hidden": "true", focusable: "false", children: nodes.map((node, i) => {
102
112
  const flow = node.flow ?? "in";
103
113
  const length = g.lengths[i] ?? 0;
104
- const gap = length / Math.min(4, Math.max(2, Math.round(length / 16)));
114
+ const gap = length / photonCount(length, density);
115
+ const period = gap / speed;
105
116
  const timing = (dir) => ({
106
117
  "--kz-flow-gap": gap.toFixed(3),
107
- animationDuration: `${(gap / speed).toFixed(2)}s`,
108
- animationDelay: `${(-((i * 0.37 + (dir === "out" ? 0.5 : 0)) % 1) * (gap / speed)).toFixed(2)}s`
118
+ animationDuration: `${period.toFixed(2)}s`,
119
+ // Each conduit starts `stagger` ms after the previous (a negative delay: already under way); the way back is half a period behind.
120
+ animationDelay: `${(-((i * stagger / 1e3 + (dir === "out" ? period / 2 : 0)) % period)).toFixed(2)}s`,
121
+ ...easing !== "linear" ? { animationTimingFunction: easing } : {}
109
122
  });
110
123
  const lanes = node.planned || particles === "none" ? [] : flow === "both" ? ["in", "out"] : [flow];
111
124
  return /* @__PURE__ */ jsxs(
@@ -127,7 +140,7 @@ function Stage({
127
140
  );
128
141
  }) }),
129
142
  /* @__PURE__ */ jsxs("div", { className: cn("kz-flow-hub", hub.className), style: { left: pct(g.hub.x, g.width), top: pct(g.hub.y, g.height) }, children: [
130
- hub.mark ? /* @__PURE__ */ jsx("span", { className: "kz-flow-hub-mark", children: hub.mark }) : null,
143
+ hub.mark ? /* @__PURE__ */ jsx("span", { className: cn("kz-flow-hub-mark", breathe && "kz-loop"), children: hub.mark }) : null,
131
144
  /* @__PURE__ */ jsx("span", { className: "kz-flow-hub-label", children: hub.label }),
132
145
  hub.caption ? /* @__PURE__ */ jsx("span", { className: "kz-flow-hub-caption", children: hub.caption }) : null
133
146
  ] }),
@@ -166,6 +179,11 @@ function EngineFlow({
166
179
  hint,
167
180
  defaultActive,
168
181
  speed = 16,
182
+ density = "normal",
183
+ trigger = "always",
184
+ easing = "linear",
185
+ stagger = 300,
186
+ breathe = true,
169
187
  className,
170
188
  ...props
171
189
  }) {
@@ -173,7 +191,7 @@ function EngineFlow({
173
191
  const detailId = `${React.useId()}-detail`;
174
192
  const chosen = nodes.find((n) => n.id === active);
175
193
  const compact = compactLayout && compactLayout !== layout ? compactLayout : void 0;
176
- const stage = { nodes, hub, conduit, particles, speed: Math.max(1, speed), active, onActive: setActive, detailId };
194
+ const stage = { nodes, hub, conduit, particles, speed: Math.max(1, speed), density, easing, stagger: Math.max(0, stagger), breathe, active, onActive: setActive, detailId };
177
195
  return /* @__PURE__ */ jsxs(
178
196
  "figure",
179
197
  {
@@ -181,6 +199,8 @@ function EngineFlow({
181
199
  className: cn("kz-flow", className),
182
200
  "data-motion-scope": "",
183
201
  "data-active": chosen ? "" : void 0,
202
+ "data-trigger": trigger === "always" ? void 0 : trigger,
203
+ "data-density": density === "normal" ? void 0 : density,
184
204
  "data-compact": compact ? "" : void 0,
185
205
  ...props,
186
206
  children: [
@@ -209,6 +229,7 @@ export {
209
229
  EngineFlow,
210
230
  FLOW_HEIGHT,
211
231
  flowGeometry,
212
- flowPositions
232
+ flowPositions,
233
+ photonCount
213
234
  };
214
235
  //# sourceMappingURL=engine-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine-flow/engine-flow.tsx","../src/engine-flow/geometry.ts"],"sourcesContent":["// Client (the node a visitor points at or focuses). An engine at the hub and the apps it serves around it: one conduit\n// per app, and photons that travel it — towards the hub (`in`: requests), back (`out`: results) or both — in the app's\n// brand colour going in and the hub's coming back. A planned app is drawn dim, its conduit dashed and still.\n//\n// Motion is the Krizaka signature's (motion.css): CSS animations of `stroke-dashoffset`, no animation frame, no canvas;\n// paused off screen (`data-motion-scope` → MotionObserver's `data-offscreen`), held while the page settles (`kz-loop`),\n// a still frame under reduced motion (the photons rest along their conduit). The stage keeps its aspect ratio and the\n// detail line its height: no layout shift.\n//\n// Accessible: the drawing is hidden from assistive technology; every node is a real button named by its label, and the\n// detail line (polite live region) says the chosen node's description with its link. Pair it with a text version (a\n// list) in the page: the figure is a picture of it.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { type FlowConduit, flowGeometry, type FlowLayout } from \"./geometry\";\n\nexport interface EngineFlowNode {\n /** A stable id (`orochia`). */\n id: string;\n /** Its name, the button's accessible name (\"Orochia\"). */\n label: string;\n /** Its mark (a `ProductLogo`), decorative. */\n mark?: React.ReactNode;\n /** One line: what it uses the engine for — shown when the node is pointed at or focused. */\n description?: React.ReactNode;\n /** Where it lives (its site). */\n href?: string;\n /** The link's words (\"Visit dev.orochia.com\"); defaults to the label. */\n linkLabel?: React.ReactNode;\n /** Opens the link in a new tab. */\n external?: boolean;\n /** What travels: `in` towards the hub, `out` back from it, `both`.\n * @default \"in\" */\n flow?: \"in\" | \"out\" | \"both\";\n /** Not wired yet: drawn dim, its conduit dashed and still, no photon. */\n planned?: boolean;\n /** A word beside the name in the detail line (\"planned\"), passed translated. */\n status?: React.ReactNode;\n /** Its brand scope (`brand-orochia`): its conduit, photons and ring take its `--kz-accent`. */\n className?: string;\n}\n\nexport interface EngineFlowHub {\n /** The engine's name (\"Orazaka\"). */\n label: string;\n /** Its mark, decorative. */\n mark?: React.ReactNode;\n /** A line under the name (\"the engine\"). */\n caption?: React.ReactNode;\n /** Its brand scope; the photons coming back take its accent. */\n className?: string;\n}\n\nexport type EngineFlowProps = Omit<React.ComponentProps<\"figure\">, \"children\"> & {\n /** What the figure shows (\"Orazaka and the products it powers\"), passed translated. */\n label: string;\n /** The engine, at the hub. */\n hub: EngineFlowHub;\n /** The apps around it. */\n nodes: readonly EngineFlowNode[];\n /** How the nodes sit around the hub.\n * @default \"radial\" */\n layout?: FlowLayout;\n /** The layout under a 560 px wide container (a phone); `false` keeps `layout` everywhere.\n * @default \"top-to-bottom\" */\n compactLayout?: FlowLayout | false;\n /** `photons` travel the conduits; `none` draws them still.\n * @default \"photons\" */\n particles?: \"photons\" | \"none\";\n /** The conduits' shape.\n * @default \"bezier\" */\n conduit?: FlowConduit;\n /** The detail line before a node is chosen (\"Point at a product\"). */\n hint?: React.ReactNode;\n /** The node shown in the detail line at first. */\n defaultActive?: string;\n /** Photon speed, in units per second (the stage is 100 units wide).\n * @default 16 */\n speed?: number;\n};\n\nfunction Stage({\n layout,\n variant,\n nodes,\n hub,\n conduit,\n particles,\n speed,\n active,\n onActive,\n detailId,\n}: {\n layout: FlowLayout;\n variant: \"wide\" | \"compact\";\n nodes: readonly EngineFlowNode[];\n hub: EngineFlowHub;\n conduit: FlowConduit;\n particles: \"photons\" | \"none\";\n speed: number;\n active: string | undefined;\n onActive: (id: string) => void;\n detailId: string;\n}) {\n const g = flowGeometry(layout, nodes.length, conduit);\n const pct = (v: number, of: number) => `${((v / of) * 100).toFixed(3)}%`;\n return (\n <div className=\"kz-flow-stage\" data-variant={variant} data-layout={layout} style={{ aspectRatio: `${g.width} / ${g.height}` }}>\n <svg viewBox={`0 0 ${g.width} ${g.height}`} aria-hidden=\"true\" focusable=\"false\">\n {nodes.map((node, i) => {\n const flow = node.flow ?? \"in\";\n const length = g.lengths[i] ?? 0;\n // Two to four photons per conduit, evenly spaced; the same speed on every conduit.\n const gap = length / Math.min(4, Math.max(2, Math.round(length / 16)));\n const timing = (dir: \"in\" | \"out\") =>\n ({\n \"--kz-flow-gap\": gap.toFixed(3),\n animationDuration: `${(gap / speed).toFixed(2)}s`,\n animationDelay: `${(-((i * 0.37 + (dir === \"out\" ? 0.5 : 0)) % 1) * (gap / speed)).toFixed(2)}s`,\n }) as React.CSSProperties;\n const lanes = node.planned || particles === \"none\" ? [] : flow === \"both\" ? ([\"in\", \"out\"] as const) : [flow];\n return (\n <g\n key={node.id}\n className={cn(\"kz-flow-link\", node.className)}\n data-flow={flow}\n data-planned={node.planned ? \"\" : undefined}\n data-active={active === node.id ? \"\" : undefined}\n >\n <path className=\"kz-flow-wire\" d={g.paths[i]} />\n {lanes.map((dir) => (\n <React.Fragment key={dir}>\n <path className=\"kz-flow-photon kz-loop\" data-dir={dir} data-halo=\"\" d={g.paths[i]} style={timing(dir)} />\n <path className=\"kz-flow-photon kz-loop\" data-dir={dir} d={g.paths[i]} style={timing(dir)} />\n </React.Fragment>\n ))}\n </g>\n );\n })}\n </svg>\n <div className={cn(\"kz-flow-hub\", hub.className)} style={{ left: pct(g.hub.x, g.width), top: pct(g.hub.y, g.height) }}>\n {hub.mark ? <span className=\"kz-flow-hub-mark\">{hub.mark}</span> : null}\n <span className=\"kz-flow-hub-label\">{hub.label}</span>\n {hub.caption ? <span className=\"kz-flow-hub-caption\">{hub.caption}</span> : null}\n </div>\n <ul className=\"kz-flow-nodes\">\n {nodes.map((node, i) => {\n const p = g.nodes[i]!;\n const on = active === node.id;\n return (\n <li key={node.id} style={{ left: pct(p.x, g.width), top: pct(p.y, g.height) }}>\n <button\n type=\"button\"\n className={cn(\"kz-flow-node\", node.className)}\n data-active={on ? \"\" : undefined}\n data-planned={node.planned ? \"\" : undefined}\n aria-pressed={on}\n aria-controls={detailId}\n onPointerEnter={() => onActive(node.id)}\n onFocus={() => onActive(node.id)}\n onClick={() => onActive(node.id)}\n >\n {node.mark ? (\n <span className=\"kz-flow-node-mark\" aria-hidden=\"true\">\n {node.mark}\n </span>\n ) : null}\n <span className=\"kz-flow-node-label\">{node.label}</span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\n/** An engine at the hub and the apps it serves, with what travels between them. */\nexport function EngineFlow({\n label,\n hub,\n nodes,\n layout = \"radial\",\n compactLayout = \"top-to-bottom\",\n particles = \"photons\",\n conduit = \"bezier\",\n hint,\n defaultActive,\n speed = 16,\n className,\n ...props\n}: EngineFlowProps) {\n const [active, setActive] = React.useState<string | undefined>(defaultActive);\n const detailId = `${React.useId()}-detail`;\n const chosen = nodes.find((n) => n.id === active);\n const compact = compactLayout && compactLayout !== layout ? compactLayout : undefined;\n const stage = { nodes, hub, conduit, particles, speed: Math.max(1, speed), active, onActive: setActive, detailId };\n return (\n <figure\n aria-label={label}\n className={cn(\"kz-flow\", className)}\n data-motion-scope=\"\"\n data-active={chosen ? \"\" : undefined}\n data-compact={compact ? \"\" : undefined}\n {...props}\n >\n <Stage layout={layout} variant=\"wide\" {...stage} />\n {compact ? <Stage layout={compact} variant=\"compact\" {...stage} /> : null}\n <figcaption id={detailId} className={cn(\"kz-flow-detail\", chosen?.className)} aria-live=\"polite\">\n {chosen ? (\n <>\n <strong>{chosen.label}</strong>\n {chosen.status ? <span className=\"kz-flow-status\">{chosen.status}</span> : null}\n {chosen.description ? <span> {chosen.description}</span> : null}\n {chosen.href ? (\n <>\n {\" \"}\n <a href={chosen.href} {...(chosen.external ? { target: \"_blank\", rel: \"noopener\" } : {})}>\n {chosen.linkLabel ?? chosen.label}\n <span aria-hidden=\"true\"> →</span>\n </a>\n </>\n ) : null}\n </>\n ) : (\n hint\n )}\n </figcaption>\n </figure>\n );\n}\n","// Server-safe, pure. The geometry of EngineFlow: where the hub and the nodes sit in a box 100 units wide, and the\n// conduit from each node to the hub (an SVG path drawn node → hub, and its length, so photons travel at one speed on\n// every conduit). No DOM: the same numbers on the server and in the browser.\n\n/** How the nodes are placed around the hub. */\nexport type FlowLayout = \"radial\" | \"top-to-bottom\" | \"left-to-right\";\n/** The shape of a conduit: an S-shaped cubic Bézier, or a straight line. */\nexport type FlowConduit = \"bezier\" | \"straight\";\n\nexport interface FlowPoint {\n x: number;\n y: number;\n}\n\nexport interface FlowGeometry {\n /** The box: 100 units wide, `height` units high (the stage keeps this aspect ratio, so nothing is distorted). */\n width: number;\n height: number;\n hub: FlowPoint;\n nodes: FlowPoint[];\n /** One path per node, from the node to the hub. */\n paths: string[];\n /** The length of each path, in units. */\n lengths: number[];\n}\n\n/** The box height per layout (the width is always 100). */\nexport const FLOW_HEIGHT: Record<FlowLayout, number> = { radial: 60, \"top-to-bottom\": 92, \"left-to-right\": 56 };\n\nconst r2 = (n: number) => Math.round(n * 100) / 100;\nconst pt = (p: FlowPoint) => `${r2(p.x)} ${r2(p.y)}`;\n\nfunction cubicLength(a: FlowPoint, b: FlowPoint, c: FlowPoint, d: FlowPoint): number {\n let length = 0;\n let prev = a;\n for (let i = 1; i <= 32; i++) {\n const t = i / 32;\n const u = 1 - t;\n const p = {\n x: u * u * u * a.x + 3 * u * u * t * b.x + 3 * u * t * t * c.x + t * t * t * d.x,\n y: u * u * u * a.y + 3 * u * u * t * b.y + 3 * u * t * t * c.y + t * t * t * d.y,\n };\n length += Math.hypot(p.x - prev.x, p.y - prev.y);\n prev = p;\n }\n return length;\n}\n\n/** The positions of `count` nodes around the hub. */\nexport function flowPositions(layout: FlowLayout, count: number): { hub: FlowPoint; nodes: FlowPoint[] } {\n const height = FLOW_HEIGHT[layout];\n const n = Math.max(0, count);\n if (layout === \"top-to-bottom\") {\n return { hub: { x: 50, y: 72 }, nodes: Array.from({ length: n }, (_, i) => ({ x: ((i + 0.5) * 100) / n, y: 13 })) };\n }\n if (layout === \"left-to-right\") {\n return { hub: { x: 80, y: height / 2 }, nodes: Array.from({ length: n }, (_, i) => ({ x: 12, y: ((i + 0.5) * height) / n })) };\n }\n // Radial: on an ellipse around the centre; an even count puts two nodes level with the hub (more room for labels).\n const hub = { x: 50, y: height / 2 };\n const start = n % 2 === 0 ? -90 + 180 / Math.max(n, 1) : -90;\n return {\n hub,\n nodes: Array.from({ length: n }, (_, i) => {\n const a = ((start + (360 / n) * i) * Math.PI) / 180;\n return { x: hub.x + 37 * Math.cos(a), y: hub.y + 20 * Math.sin(a) };\n }),\n };\n}\n\n/** The whole geometry of a flow: positions, conduits (node → hub) and their lengths. */\nexport function flowGeometry(layout: FlowLayout, count: number, conduit: FlowConduit = \"bezier\"): FlowGeometry {\n const { hub, nodes } = flowPositions(layout, count);\n const paths: string[] = [];\n const lengths: number[] = [];\n for (const p of nodes) {\n // Each conduit lands on its own point of the hub (a fan), so the lines stay apart where they meet.\n const end =\n layout === \"top-to-bottom\"\n ? { x: hub.x + (p.x - hub.x) * 0.18, y: hub.y }\n : layout === \"left-to-right\"\n ? { x: hub.x, y: hub.y + (p.y - hub.y) * 0.18 }\n : hub;\n if (conduit === \"straight\") {\n paths.push(`M${pt(p)} L${pt(end)}`);\n lengths.push(Math.hypot(end.x - p.x, end.y - p.y));\n continue;\n }\n let c1: FlowPoint;\n let c2: FlowPoint;\n if (layout === \"top-to-bottom\") {\n const mid = (p.y + end.y) / 2;\n c1 = { x: p.x, y: mid };\n c2 = { x: end.x, y: mid };\n } else if (layout === \"left-to-right\") {\n const mid = (p.x + end.x) / 2;\n c1 = { x: mid, y: p.y };\n c2 = { x: mid, y: end.y };\n } else {\n // An S: leave the node bending one way, reach the hub bending the other.\n const dx = end.x - p.x;\n const dy = end.y - p.y;\n const len = Math.hypot(dx, dy) || 1;\n const k = 0.14 * len;\n const nx = -dy / len;\n const ny = dx / len;\n c1 = { x: p.x + dx * 0.35 + nx * k, y: p.y + dy * 0.35 + ny * k };\n c2 = { x: p.x + dx * 0.65 - nx * k, y: p.y + dy * 0.65 - ny * k };\n }\n paths.push(`M${pt(p)} C${pt(c1)} ${pt(c2)} ${pt(end)}`);\n lengths.push(cubicLength(p, c1, c2, end));\n }\n return { width: 100, height: FLOW_HEIGHT[layout], hub, nodes, paths, lengths };\n}\n"],"mappings":"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","names":["Fragment"]}
1
+ {"version":3,"sources":["../src/engine-flow/engine-flow.tsx","../src/engine-flow/geometry.ts"],"sourcesContent":["// Client (the node a visitor points at or focuses). An engine at the hub and the apps it serves around it: one conduit\n// per app, and photons that travel it — towards the hub (`in`: requests), back (`out`: results) or both — in the app's\n// brand colour going in and the hub's coming back. A planned app is drawn dim, its conduit dashed and still.\n//\n// Motion is the Krizaka signature's (motion.css): CSS animations of `stroke-dashoffset`, no animation frame, no canvas;\n// paused off screen (`data-motion-scope` → MotionObserver's `data-offscreen`), held while the page settles (`kz-loop`),\n// a still frame under reduced motion (the photons rest along their conduit). The stage keeps its aspect ratio and the\n// detail line its height: no layout shift.\n//\n// Accessible: the drawing is hidden from assistive technology; every node is a real button named by its label, and the\n// detail line (polite live region) says the chosen node's description with its link. Pair it with a text version (a\n// list) in the page: the figure is a picture of it.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { type FlowConduit, flowGeometry, type FlowLayout } from \"./geometry\";\n\nexport interface EngineFlowNode {\n /** A stable id (`orochia`). */\n id: string;\n /** Its name, the button's accessible name (\"Orochia\"). */\n label: string;\n /** Its mark (a `ProductLogo`), decorative. */\n mark?: React.ReactNode;\n /** One line: what it uses the engine for — shown when the node is pointed at or focused. */\n description?: React.ReactNode;\n /** Where it lives (its site). */\n href?: string;\n /** The link's words (\"Visit dev.orochia.com\"); defaults to the label. */\n linkLabel?: React.ReactNode;\n /** Opens the link in a new tab. */\n external?: boolean;\n /** What travels: `in` towards the hub, `out` back from it, `both`.\n * @default \"in\" */\n flow?: \"in\" | \"out\" | \"both\";\n /** Not wired yet: drawn dim, its conduit dashed and still, no photon. */\n planned?: boolean;\n /** A word beside the name in the detail line (\"planned\"), passed translated. */\n status?: React.ReactNode;\n /** Its brand scope (`brand-orochia`): its conduit, photons and ring take its `--kz-accent`. */\n className?: string;\n}\n\nexport interface EngineFlowHub {\n /** The engine's name (\"Orazaka\"). */\n label: string;\n /** Its mark, decorative. */\n mark?: React.ReactNode;\n /** A line under the name (\"the engine\"). */\n caption?: React.ReactNode;\n /** Its brand scope; the photons coming back take its accent. */\n className?: string;\n}\n\nexport type EngineFlowProps = Omit<React.ComponentProps<\"figure\">, \"children\"> & {\n /** What the figure shows (\"Orazaka and the products it powers\"), passed translated. */\n label: string;\n /** The engine, at the hub. */\n hub: EngineFlowHub;\n /** The apps around it. */\n nodes: readonly EngineFlowNode[];\n /** How the nodes sit around the hub.\n * @default \"radial\" */\n layout?: FlowLayout;\n /** The layout under a 560 px wide container (a phone); `false` keeps `layout` everywhere.\n * @default \"top-to-bottom\" */\n compactLayout?: FlowLayout | false;\n /** `photons` travel the conduits; `none` draws them still.\n * @default \"photons\" */\n particles?: \"photons\" | \"none\";\n /** The conduits' shape.\n * @default \"bezier\" */\n conduit?: FlowConduit;\n /** The detail line before a node is chosen (\"Point at a product\"). */\n hint?: React.ReactNode;\n /** The node shown in the detail line at first. */\n defaultActive?: string;\n /** Photon speed, in units per second (the stage is 100 units wide).\n * @default 16 */\n speed?: number;\n /** How many photons share a conduit: `sparse` one or two, `normal` two to four, `dense` four to eight.\n * @default \"normal\" */\n density?: FlowDensity;\n /** When the photons travel: `always`; `hover` only while the pointer or focus is on the figure (they rest along the\n * conduits otherwise); `active` only on the conduit of the chosen node (the others show nothing). Off screen they\n * are always paused, and still under reduced motion.\n * @default \"always\" */\n trigger?: FlowTrigger;\n /** The photons' timing function: `linear` (a steady stream), `ease-in-out` (a pulse that swells and settles), or any\n * CSS `<easing-function>` (`cubic-bezier(.2,0,0,1)`, `steps(6)`).\n * @default \"linear\" */\n easing?: FlowEasing;\n /** Milliseconds between one conduit's photons and the next's: 0 sends them all together.\n * @default 300 */\n stagger?: number;\n /** The engine's mark swells slowly (a loop, still under reduced motion).\n * @default true */\n breathe?: boolean;\n};\n\nexport type FlowDensity = \"sparse\" | \"normal\" | \"dense\";\nexport type FlowTrigger = \"always\" | \"hover\" | \"active\";\nexport type FlowEasing = \"linear\" | \"ease-in-out\" | (string & {});\n\n/** How many photons a conduit of this length carries (evenly spaced, so the gap is `length / count`). */\nexport function photonCount(length: number, density: FlowDensity = \"normal\"): number {\n const base = Math.round(length / 16);\n if (density === \"sparse\") return Math.min(2, Math.max(1, Math.round(base / 2)));\n if (density === \"dense\") return Math.min(8, Math.max(4, base * 2));\n return Math.min(4, Math.max(2, base));\n}\n\nfunction Stage({\n layout,\n variant,\n nodes,\n hub,\n conduit,\n particles,\n speed,\n density,\n easing,\n stagger,\n breathe,\n active,\n onActive,\n detailId,\n}: {\n layout: FlowLayout;\n variant: \"wide\" | \"compact\";\n nodes: readonly EngineFlowNode[];\n hub: EngineFlowHub;\n conduit: FlowConduit;\n particles: \"photons\" | \"none\";\n speed: number;\n density: FlowDensity;\n easing: FlowEasing;\n stagger: number;\n breathe: boolean;\n active: string | undefined;\n onActive: (id: string) => void;\n detailId: string;\n}) {\n const g = flowGeometry(layout, nodes.length, conduit);\n const pct = (v: number, of: number) => `${((v / of) * 100).toFixed(3)}%`;\n return (\n <div className=\"kz-flow-stage\" data-variant={variant} data-layout={layout} style={{ aspectRatio: `${g.width} / ${g.height}` }}>\n <svg viewBox={`0 0 ${g.width} ${g.height}`} aria-hidden=\"true\" focusable=\"false\">\n {nodes.map((node, i) => {\n const flow = node.flow ?? \"in\";\n const length = g.lengths[i] ?? 0;\n // Photons per conduit (`density`), evenly spaced; the same speed on every conduit.\n const gap = length / photonCount(length, density);\n const period = gap / speed;\n const timing = (dir: \"in\" | \"out\") =>\n ({\n \"--kz-flow-gap\": gap.toFixed(3),\n animationDuration: `${period.toFixed(2)}s`,\n // Each conduit starts `stagger` ms after the previous (a negative delay: already under way); the way back is half a period behind.\n animationDelay: `${(-(((i * stagger) / 1000 + (dir === \"out\" ? period / 2 : 0)) % period)).toFixed(2)}s`,\n ...(easing !== \"linear\" ? { animationTimingFunction: easing } : {}),\n }) as React.CSSProperties;\n const lanes = node.planned || particles === \"none\" ? [] : flow === \"both\" ? ([\"in\", \"out\"] as const) : [flow];\n return (\n <g\n key={node.id}\n className={cn(\"kz-flow-link\", node.className)}\n data-flow={flow}\n data-planned={node.planned ? \"\" : undefined}\n data-active={active === node.id ? \"\" : undefined}\n >\n <path className=\"kz-flow-wire\" d={g.paths[i]} />\n {lanes.map((dir) => (\n <React.Fragment key={dir}>\n <path className=\"kz-flow-photon kz-loop\" data-dir={dir} data-halo=\"\" d={g.paths[i]} style={timing(dir)} />\n <path className=\"kz-flow-photon kz-loop\" data-dir={dir} d={g.paths[i]} style={timing(dir)} />\n </React.Fragment>\n ))}\n </g>\n );\n })}\n </svg>\n <div className={cn(\"kz-flow-hub\", hub.className)} style={{ left: pct(g.hub.x, g.width), top: pct(g.hub.y, g.height) }}>\n {hub.mark ? <span className={cn(\"kz-flow-hub-mark\", breathe && \"kz-loop\")}>{hub.mark}</span> : null}\n <span className=\"kz-flow-hub-label\">{hub.label}</span>\n {hub.caption ? <span className=\"kz-flow-hub-caption\">{hub.caption}</span> : null}\n </div>\n <ul className=\"kz-flow-nodes\">\n {nodes.map((node, i) => {\n const p = g.nodes[i]!;\n const on = active === node.id;\n return (\n <li key={node.id} style={{ left: pct(p.x, g.width), top: pct(p.y, g.height) }}>\n <button\n type=\"button\"\n className={cn(\"kz-flow-node\", node.className)}\n data-active={on ? \"\" : undefined}\n data-planned={node.planned ? \"\" : undefined}\n aria-pressed={on}\n aria-controls={detailId}\n onPointerEnter={() => onActive(node.id)}\n onFocus={() => onActive(node.id)}\n onClick={() => onActive(node.id)}\n >\n {node.mark ? (\n <span className=\"kz-flow-node-mark\" aria-hidden=\"true\">\n {node.mark}\n </span>\n ) : null}\n <span className=\"kz-flow-node-label\">{node.label}</span>\n </button>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\n/** An engine at the hub and the apps it serves, with what travels between them. */\nexport function EngineFlow({\n label,\n hub,\n nodes,\n layout = \"radial\",\n compactLayout = \"top-to-bottom\",\n particles = \"photons\",\n conduit = \"bezier\",\n hint,\n defaultActive,\n speed = 16,\n density = \"normal\",\n trigger = \"always\",\n easing = \"linear\",\n stagger = 300,\n breathe = true,\n className,\n ...props\n}: EngineFlowProps) {\n const [active, setActive] = React.useState<string | undefined>(defaultActive);\n const detailId = `${React.useId()}-detail`;\n const chosen = nodes.find((n) => n.id === active);\n const compact = compactLayout && compactLayout !== layout ? compactLayout : undefined;\n const stage = { nodes, hub, conduit, particles, speed: Math.max(1, speed), density, easing, stagger: Math.max(0, stagger), breathe, active, onActive: setActive, detailId };\n return (\n <figure\n aria-label={label}\n className={cn(\"kz-flow\", className)}\n data-motion-scope=\"\"\n data-active={chosen ? \"\" : undefined}\n data-trigger={trigger === \"always\" ? undefined : trigger}\n data-density={density === \"normal\" ? undefined : density}\n data-compact={compact ? \"\" : undefined}\n {...props}\n >\n <Stage layout={layout} variant=\"wide\" {...stage} />\n {compact ? <Stage layout={compact} variant=\"compact\" {...stage} /> : null}\n <figcaption id={detailId} className={cn(\"kz-flow-detail\", chosen?.className)} aria-live=\"polite\">\n {chosen ? (\n <>\n <strong>{chosen.label}</strong>\n {chosen.status ? <span className=\"kz-flow-status\">{chosen.status}</span> : null}\n {chosen.description ? <span> {chosen.description}</span> : null}\n {chosen.href ? (\n <>\n {\" \"}\n <a href={chosen.href} {...(chosen.external ? { target: \"_blank\", rel: \"noopener\" } : {})}>\n {chosen.linkLabel ?? chosen.label}\n <span aria-hidden=\"true\"> →</span>\n </a>\n </>\n ) : null}\n </>\n ) : (\n hint\n )}\n </figcaption>\n </figure>\n );\n}\n","// Server-safe, pure. The geometry of EngineFlow: where the hub and the nodes sit in a box 100 units wide, and the\n// conduit from each node to the hub (an SVG path drawn node → hub, and its length, so photons travel at one speed on\n// every conduit). No DOM: the same numbers on the server and in the browser.\n\n/** How the nodes are placed around the hub. */\nexport type FlowLayout = \"radial\" | \"top-to-bottom\" | \"left-to-right\";\n/** The shape of a conduit: an S-shaped cubic Bézier, or a straight line. */\nexport type FlowConduit = \"bezier\" | \"straight\";\n\nexport interface FlowPoint {\n x: number;\n y: number;\n}\n\nexport interface FlowGeometry {\n /** The box: 100 units wide, `height` units high (the stage keeps this aspect ratio, so nothing is distorted). */\n width: number;\n height: number;\n hub: FlowPoint;\n nodes: FlowPoint[];\n /** One path per node, from the node to the hub. */\n paths: string[];\n /** The length of each path, in units. */\n lengths: number[];\n}\n\n/** The box height per layout (the width is always 100). */\nexport const FLOW_HEIGHT: Record<FlowLayout, number> = { radial: 60, \"top-to-bottom\": 92, \"left-to-right\": 56 };\n\nconst r2 = (n: number) => Math.round(n * 100) / 100;\nconst pt = (p: FlowPoint) => `${r2(p.x)} ${r2(p.y)}`;\n\nfunction cubicLength(a: FlowPoint, b: FlowPoint, c: FlowPoint, d: FlowPoint): number {\n let length = 0;\n let prev = a;\n for (let i = 1; i <= 32; i++) {\n const t = i / 32;\n const u = 1 - t;\n const p = {\n x: u * u * u * a.x + 3 * u * u * t * b.x + 3 * u * t * t * c.x + t * t * t * d.x,\n y: u * u * u * a.y + 3 * u * u * t * b.y + 3 * u * t * t * c.y + t * t * t * d.y,\n };\n length += Math.hypot(p.x - prev.x, p.y - prev.y);\n prev = p;\n }\n return length;\n}\n\n/** The positions of `count` nodes around the hub. */\nexport function flowPositions(layout: FlowLayout, count: number): { hub: FlowPoint; nodes: FlowPoint[] } {\n const height = FLOW_HEIGHT[layout];\n const n = Math.max(0, count);\n if (layout === \"top-to-bottom\") {\n return { hub: { x: 50, y: 72 }, nodes: Array.from({ length: n }, (_, i) => ({ x: ((i + 0.5) * 100) / n, y: 13 })) };\n }\n if (layout === \"left-to-right\") {\n return { hub: { x: 80, y: height / 2 }, nodes: Array.from({ length: n }, (_, i) => ({ x: 12, y: ((i + 0.5) * height) / n })) };\n }\n // Radial: on an ellipse around the centre; an even count puts two nodes level with the hub (more room for labels).\n const hub = { x: 50, y: height / 2 };\n const start = n % 2 === 0 ? -90 + 180 / Math.max(n, 1) : -90;\n return {\n hub,\n nodes: Array.from({ length: n }, (_, i) => {\n const a = ((start + (360 / n) * i) * Math.PI) / 180;\n return { x: hub.x + 37 * Math.cos(a), y: hub.y + 20 * Math.sin(a) };\n }),\n };\n}\n\n/** The whole geometry of a flow: positions, conduits (node → hub) and their lengths. */\nexport function flowGeometry(layout: FlowLayout, count: number, conduit: FlowConduit = \"bezier\"): FlowGeometry {\n const { hub, nodes } = flowPositions(layout, count);\n const paths: string[] = [];\n const lengths: number[] = [];\n for (const p of nodes) {\n // Each conduit lands on its own point of the hub (a fan), so the lines stay apart where they meet.\n const end =\n layout === \"top-to-bottom\"\n ? { x: hub.x + (p.x - hub.x) * 0.18, y: hub.y }\n : layout === \"left-to-right\"\n ? { x: hub.x, y: hub.y + (p.y - hub.y) * 0.18 }\n : hub;\n if (conduit === \"straight\") {\n paths.push(`M${pt(p)} L${pt(end)}`);\n lengths.push(Math.hypot(end.x - p.x, end.y - p.y));\n continue;\n }\n let c1: FlowPoint;\n let c2: FlowPoint;\n if (layout === \"top-to-bottom\") {\n const mid = (p.y + end.y) / 2;\n c1 = { x: p.x, y: mid };\n c2 = { x: end.x, y: mid };\n } else if (layout === \"left-to-right\") {\n const mid = (p.x + end.x) / 2;\n c1 = { x: mid, y: p.y };\n c2 = { x: mid, y: end.y };\n } else {\n // An S: leave the node bending one way, reach the hub bending the other.\n const dx = end.x - p.x;\n const dy = end.y - p.y;\n const len = Math.hypot(dx, dy) || 1;\n const k = 0.14 * len;\n const nx = -dy / len;\n const ny = dx / len;\n c1 = { x: p.x + dx * 0.35 + nx * k, y: p.y + dy * 0.35 + ny * k };\n c2 = { x: p.x + dx * 0.65 - nx * k, y: p.y + dy * 0.65 - ny * k };\n }\n paths.push(`M${pt(p)} C${pt(c1)} ${pt(c2)} ${pt(end)}`);\n lengths.push(cubicLength(p, c1, c2, end));\n }\n return { width: 100, height: FLOW_HEIGHT[layout], hub, nodes, paths, lengths };\n}\n"],"mappings":"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","names":["Fragment"]}
@@ -1,7 +1,7 @@
1
1
  import "./chunk-TDG7ED2W.js";
2
2
  import {
3
3
  Button
4
- } from "./chunk-6ZYRUOTA.js";
4
+ } from "./chunk-UV4HBVH7.js";
5
5
  import "./chunk-43PTCDTL.js";
6
6
  import "./chunk-2VNYHG4E.js";
7
7
  import "./chunk-W675RFOA.js";
@@ -27,7 +27,7 @@ function ForceUpdateScreen({ title, message, versionLabel, mark, updateLabel, on
27
27
  message && /* @__PURE__ */ jsx("p", { className: s.message(), children: message }),
28
28
  versionLabel && /* @__PURE__ */ jsx("p", { className: s.version(), children: versionLabel }),
29
29
  /* @__PURE__ */ jsxs("div", { className: s.actions(), children: [
30
- /* @__PURE__ */ jsx(Button, { variant: "primary", size: "lg", shape: "cut", shimmer: true, autoFocus: true, onClick: onUpdate, children: updateLabel }),
30
+ /* @__PURE__ */ jsx(Button, { variant: "primary", size: "lg", autoFocus: true, onClick: onUpdate, children: updateLabel }),
31
31
  retryLabel && onRetry && /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onRetry, children: retryLabel })
32
32
  ] })
33
33
  ] });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/force-update-screen/force-update-screen.tsx"],"sourcesContent":["// Server-safe. The blocking screen: this version can no longer run. It replaces the app, it is not laid over it —\n// nothing behind it is reachable. Every word is a prop; the store URL and the versions come from the backend.\nimport { Button } from \"@krizaka/ui/button\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const forceUpdateScreen = tv({\n slots: {\n root: \"mx-auto flex min-h-dvh w-full max-w-md flex-col items-center justify-center gap-4 px-6 py-12 text-center text-fg\",\n mark: \"flex h-24 w-24 items-center justify-center [&>svg]:h-24 [&>svg]:w-24\",\n title: \"text-2xl font-semibold text-fg\",\n message: \"text-fg-secondary\",\n version: \"font-mono text-xs text-fg-tertiary\",\n actions: \"mt-2 flex w-full flex-col gap-2\",\n },\n});\n\nexport type ForceUpdateScreenProps = Omit<React.ComponentProps<\"main\">, \"title\"> & {\n /** The headline (“Update to keep going”). */\n title: React.ReactNode;\n /** Why, in a sentence — the backend's localized `message`. */\n message?: React.ReactNode;\n /** The versions, in words and mono (“You have 1.1.0 · 1.2.0 or later is required”). */\n versionLabel?: React.ReactNode;\n /** The product's mark or mascot (decorative). */\n mark?: React.ReactNode;\n /** The button that updates (“Update the app”). */\n updateLabel: string;\n /** Opens the store page. */\n onUpdate: () => void;\n /** A secondary way (“Check again”) once the update is installed — optional. */\n retryLabel?: string;\n /** Checks the backend again. */\n onRetry?: () => void;\n};\n\n/** The forced update: one thing to do, and the way to do it. */\nexport function ForceUpdateScreen({ title, message, versionLabel, mark, updateLabel, onUpdate, retryLabel, onRetry, className, ...props }: ForceUpdateScreenProps) {\n const s = forceUpdateScreen();\n return (\n <main data-kind=\"update-force\" className={s.root({ className })} {...props}>\n {mark && (\n <div aria-hidden className={s.mark()}>\n {mark}\n </div>\n )}\n <h1 className={s.title()}>{title}</h1>\n {message && <p className={s.message()}>{message}</p>}\n {versionLabel && <p className={s.version()}>{versionLabel}</p>}\n <div className={s.actions()}>\n <Button variant=\"primary\" size=\"lg\" shape=\"cut\" shimmer autoFocus onClick={onUpdate}>\n {updateLabel}\n </Button>\n {retryLabel && onRetry && (\n <Button variant=\"ghost\" onClick={onRetry}>\n {retryLabel}\n </Button>\n )}\n </div>\n </main>\n );\n}\n"],"mappings":";;;;;;;;;AAIA,SAAS,UAAU;AAsCX,cAOF,YAPE;AApCD,IAAM,oBAAoB,GAAG;AAAA,EAClC,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACF,CAAC;AAsBM,SAAS,kBAAkB,EAAE,OAAO,SAAS,cAAc,MAAM,aAAa,UAAU,YAAY,SAAS,WAAW,GAAG,MAAM,GAA2B;AACjK,QAAM,IAAI,kBAAkB;AAC5B,SACE,qBAAC,UAAK,aAAU,gBAAe,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAClE;AAAA,YACC,oBAAC,SAAI,eAAW,MAAC,WAAW,EAAE,KAAK,GAChC,gBACH;AAAA,IAEF,oBAAC,QAAG,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,IAChC,WAAW,oBAAC,OAAE,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,IAC/C,gBAAgB,oBAAC,OAAE,WAAW,EAAE,QAAQ,GAAI,wBAAa;AAAA,IAC1D,qBAAC,SAAI,WAAW,EAAE,QAAQ,GACxB;AAAA,0BAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,OAAM,OAAM,SAAO,MAAC,WAAS,MAAC,SAAS,UACxE,uBACH;AAAA,MACC,cAAc,WACb,oBAAC,UAAO,SAAQ,SAAQ,SAAS,SAC9B,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/force-update-screen/force-update-screen.tsx"],"sourcesContent":["// Server-safe. The blocking screen: this version can no longer run. It replaces the app, it is not laid over it —\n// nothing behind it is reachable. Every word is a prop; the store URL and the versions come from the backend.\nimport { Button } from \"@krizaka/ui/button\";\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const forceUpdateScreen = tv({\n slots: {\n root: \"mx-auto flex min-h-dvh w-full max-w-md flex-col items-center justify-center gap-4 px-6 py-12 text-center text-fg\",\n mark: \"flex h-24 w-24 items-center justify-center [&>svg]:h-24 [&>svg]:w-24\",\n title: \"text-2xl font-semibold text-fg\",\n message: \"text-fg-secondary\",\n version: \"font-mono text-xs text-fg-tertiary\",\n actions: \"mt-2 flex w-full flex-col gap-2\",\n },\n});\n\nexport type ForceUpdateScreenProps = Omit<React.ComponentProps<\"main\">, \"title\"> & {\n /** The headline (“Update to keep going”). */\n title: React.ReactNode;\n /** Why, in a sentence — the backend's localized `message`. */\n message?: React.ReactNode;\n /** The versions, in words and mono (“You have 1.1.0 · 1.2.0 or later is required”). */\n versionLabel?: React.ReactNode;\n /** The product's mark or mascot (decorative). */\n mark?: React.ReactNode;\n /** The button that updates (“Update the app”). */\n updateLabel: string;\n /** Opens the store page. */\n onUpdate: () => void;\n /** A secondary way (“Check again”) once the update is installed — optional. */\n retryLabel?: string;\n /** Checks the backend again. */\n onRetry?: () => void;\n};\n\n/** The forced update: one thing to do, and the way to do it. */\nexport function ForceUpdateScreen({ title, message, versionLabel, mark, updateLabel, onUpdate, retryLabel, onRetry, className, ...props }: ForceUpdateScreenProps) {\n const s = forceUpdateScreen();\n return (\n <main data-kind=\"update-force\" className={s.root({ className })} {...props}>\n {mark && (\n <div aria-hidden className={s.mark()}>\n {mark}\n </div>\n )}\n <h1 className={s.title()}>{title}</h1>\n {message && <p className={s.message()}>{message}</p>}\n {versionLabel && <p className={s.version()}>{versionLabel}</p>}\n <div className={s.actions()}>\n <Button variant=\"primary\" size=\"lg\" autoFocus onClick={onUpdate}>\n {updateLabel}\n </Button>\n {retryLabel && onRetry && (\n <Button variant=\"ghost\" onClick={onRetry}>\n {retryLabel}\n </Button>\n )}\n </div>\n </main>\n );\n}\n"],"mappings":";;;;;;;;;AAIA,SAAS,UAAU;AAsCX,cAOF,YAPE;AApCD,IAAM,oBAAoB,GAAG;AAAA,EAClC,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACF,CAAC;AAsBM,SAAS,kBAAkB,EAAE,OAAO,SAAS,cAAc,MAAM,aAAa,UAAU,YAAY,SAAS,WAAW,GAAG,MAAM,GAA2B;AACjK,QAAM,IAAI,kBAAkB;AAC5B,SACE,qBAAC,UAAK,aAAU,gBAAe,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OAClE;AAAA,YACC,oBAAC,SAAI,eAAW,MAAC,WAAW,EAAE,KAAK,GAChC,gBACH;AAAA,IAEF,oBAAC,QAAG,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,IAChC,WAAW,oBAAC,OAAE,WAAW,EAAE,QAAQ,GAAI,mBAAQ;AAAA,IAC/C,gBAAgB,oBAAC,OAAE,WAAW,EAAE,QAAQ,GAAI,wBAAa;AAAA,IAC1D,qBAAC,SAAI,WAAW,EAAE,QAAQ,GACxB;AAAA,0BAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,WAAS,MAAC,SAAS,UACpD,uBACH;AAAA,MACC,cAAc,WACb,oBAAC,UAAO,SAAQ,SAAQ,SAAS,SAC9B,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
package/dist/genui.js CHANGED
@@ -4,13 +4,13 @@ import {
4
4
  CardRoot,
5
5
  CardTitle,
6
6
  Skeleton
7
- } from "./chunk-MQPC3P4T.js";
7
+ } from "./chunk-2DGLWTPS.js";
8
8
  import {
9
9
  DataTable
10
- } from "./chunk-LYOPPBMC.js";
10
+ } from "./chunk-KIBICUZK.js";
11
11
  import "./chunk-7Z4KHPFC.js";
12
12
  import "./chunk-JXLDUDTD.js";
13
- import "./chunk-DZU6RMYD.js";
13
+ import "./chunk-3DHNN5V7.js";
14
14
  import "./chunk-KVDB4GXV.js";
15
15
  import "./chunk-2PNLHZLT.js";
16
16
  import "./chunk-7UCPGXKN.js";
@@ -2,19 +2,20 @@ import * as React from 'react';
2
2
 
3
3
  type GlowCardProps = React.ComponentProps<"div"> & {
4
4
  /**
5
- * What answers: `border` (the turning gradient ring), `spotlight` (the bloom under the pointer), or `both`.
5
+ * `border` (a still hairline ring of the brand gradient) or `both`. `spotlight` (the bloom under the pointer) is
6
+ * deprecated since 3.31 (krizaka-ui#393) and draws nothing.
6
7
  * @default "both"
7
8
  */
8
9
  glow?: "border" | "spotlight" | "both";
9
10
  /** Renders your element (a link, an article) with the card's look and behaviour. */
10
11
  asChild?: boolean;
11
12
  /**
12
- * The ring turns slowly even at rest (a featured card). Otherwise it rests until hovered or focused.
13
+ * A featured card: the ring is fuller at rest. It never turns.
13
14
  * @default false
14
15
  */
15
16
  alive?: boolean;
16
17
  };
17
- /** A card lit by the brand: a bloom that follows the pointer, a gradient ring that turns. Content is yours. */
18
- declare function GlowCard({ glow, asChild, alive, className, onPointerMove, ...props }: GlowCardProps): React.JSX.Element;
18
+ /** A card ringed by the brand: a still hairline of its gradient, a step brighter under the pointer. Content is yours. */
19
+ declare function GlowCard({ glow, asChild, alive, className, ...props }: GlowCardProps): React.JSX.Element;
19
20
 
20
21
  export { GlowCard, type GlowCardProps };
package/dist/glow-card.js CHANGED
@@ -6,20 +6,14 @@ import {
6
6
  // src/glow-card/glow-card.tsx
7
7
  import { Slot } from "radix-ui";
8
8
  import { jsx } from "react/jsx-runtime";
9
- function GlowCard({ glow = "both", asChild, alive, className, onPointerMove, ...props }) {
9
+ function GlowCard({ glow = "both", asChild, alive, className, ...props }) {
10
10
  const Comp = asChild ? Slot.Root : "div";
11
11
  return /* @__PURE__ */ jsx(
12
12
  Comp,
13
13
  {
14
14
  "data-glow": glow,
15
15
  "data-alive": alive ? "" : void 0,
16
- className: cn("kz-glow kz-loop relative isolate rounded-2xl border border-border-default bg-surface-1 p-6", className),
17
- onPointerMove: (e) => {
18
- const box = e.currentTarget.getBoundingClientRect();
19
- e.currentTarget.style.setProperty("--kz-glow-x", `${e.clientX - box.left}px`);
20
- e.currentTarget.style.setProperty("--kz-glow-y", `${e.clientY - box.top}px`);
21
- onPointerMove?.(e);
22
- },
16
+ className: cn("kz-glow relative isolate rounded-2xl border border-border-default bg-surface-1 p-6", className),
23
17
  ...props
24
18
  }
25
19
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/glow-card/glow-card.tsx"],"sourcesContent":["// Client (the pointer). A card that answers light: a soft bloom of the brand accent follows the pointer across it, and\n// its border is a ring of the brand gradient that turns slowly and brightens under the pointer or the focus. Composited\n// properties only (CSS variables, opacity); no animation frame — the pointer writes two variables. Under reduced motion\n// the ring rests at a fixed angle and the light stays where it is: a designed still frame, not a switched-off one.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type GlowCardProps = React.ComponentProps<\"div\"> & {\n /**\n * What answers: `border` (the turning gradient ring), `spotlight` (the bloom under the pointer), or `both`.\n * @default \"both\"\n */\n glow?: \"border\" | \"spotlight\" | \"both\";\n /** Renders your element (a link, an article) with the card's look and behaviour. */\n asChild?: boolean;\n /**\n * The ring turns slowly even at rest (a featured card). Otherwise it rests until hovered or focused.\n * @default false\n */\n alive?: boolean;\n};\n\n/** A card lit by the brand: a bloom that follows the pointer, a gradient ring that turns. Content is yours. */\nexport function GlowCard({ glow = \"both\", asChild, alive, className, onPointerMove, ...props }: GlowCardProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n return (\n <Comp\n data-glow={glow}\n data-alive={alive ? \"\" : undefined}\n className={cn(\"kz-glow kz-loop relative isolate rounded-2xl border border-border-default bg-surface-1 p-6\", className)}\n onPointerMove={(e: React.PointerEvent<HTMLDivElement>) => {\n const box = e.currentTarget.getBoundingClientRect();\n e.currentTarget.style.setProperty(\"--kz-glow-x\", `${e.clientX - box.left}px`);\n e.currentTarget.style.setProperty(\"--kz-glow-y\", `${e.clientY - box.top}px`);\n onPointerMove?.(e);\n }}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;AAIA,SAAS,YAAY;AAwBjB;AAHG,SAAS,SAAS,EAAE,OAAO,QAAQ,SAAS,OAAO,WAAW,eAAe,GAAG,MAAM,GAAkB;AAC7G,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAW;AAAA,MACX,cAAY,QAAQ,KAAK;AAAA,MACzB,WAAW,GAAG,8FAA8F,SAAS;AAAA,MACrH,eAAe,CAAC,MAA0C;AACxD,cAAM,MAAM,EAAE,cAAc,sBAAsB;AAClD,UAAE,cAAc,MAAM,YAAY,eAAe,GAAG,EAAE,UAAU,IAAI,IAAI,IAAI;AAC5E,UAAE,cAAc,MAAM,YAAY,eAAe,GAAG,EAAE,UAAU,IAAI,GAAG,IAAI;AAC3E,wBAAgB,CAAC;AAAA,MACnB;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/glow-card/glow-card.tsx"],"sourcesContent":["// Client (the pointer). A card that answers light: a soft bloom of the brand accent follows the pointer across it, and\n// its border is a ring of the brand gradient that turns slowly and brightens under the pointer or the focus. Composited\n// properties only (CSS variables, opacity); no animation frame — the pointer writes two variables. Under reduced motion\n// the ring rests at a fixed angle and the light stays where it is: a designed still frame, not a switched-off one.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type GlowCardProps = React.ComponentProps<\"div\"> & {\n /**\n * `border` (a still hairline ring of the brand gradient) or `both`. `spotlight` (the bloom under the pointer) is\n * deprecated since 3.31 (krizaka-ui#393) and draws nothing.\n * @default \"both\"\n */\n glow?: \"border\" | \"spotlight\" | \"both\";\n /** Renders your element (a link, an article) with the card's look and behaviour. */\n asChild?: boolean;\n /**\n * A featured card: the ring is fuller at rest. It never turns.\n * @default false\n */\n alive?: boolean;\n};\n\n/** A card ringed by the brand: a still hairline of its gradient, a step brighter under the pointer. Content is yours. */\nexport function GlowCard({ glow = \"both\", asChild, alive, className, ...props }: GlowCardProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n return (\n <Comp\n data-glow={glow}\n data-alive={alive ? \"\" : undefined}\n className={cn(\"kz-glow relative isolate rounded-2xl border border-border-default bg-surface-1 p-6\", className)}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;;AAIA,SAAS,YAAY;AAyBjB;AAHG,SAAS,SAAS,EAAE,OAAO,QAAQ,SAAS,OAAO,WAAW,GAAG,MAAM,GAAkB;AAC9F,QAAM,OAAO,UAAU,KAAK,OAAO;AACnC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAW;AAAA,MACX,cAAY,QAAQ,KAAK;AAAA,MACzB,WAAW,GAAG,sFAAsF,SAAS;AAAA,MAC5G,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  Slider
4
- } from "./chunk-KM6VAKIE.js";
4
+ } from "./chunk-RE5WJ4QP.js";
5
5
  import "./chunk-HJFRHYCI.js";
6
6
  import "./chunk-NSLXEDIS.js";
7
7
  import {