tempest-react-sdk 0.24.0 → 0.26.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 +25 -4
  2. package/bin/lib/alias/collect.mjs +94 -0
  3. package/bin/lib/alias/collect.test.mjs +95 -0
  4. package/bin/lib/alias/discover.mjs +77 -0
  5. package/bin/lib/alias/discover.test.mjs +189 -0
  6. package/bin/lib/alias/index.mjs +88 -0
  7. package/bin/lib/alias/index.test.mjs +138 -0
  8. package/bin/lib/alias/rewrite-css.mjs +76 -0
  9. package/bin/lib/alias/rewrite-css.test.mjs +85 -0
  10. package/bin/lib/alias/rewrite.mjs +141 -0
  11. package/bin/lib/alias/rewrite.test.mjs +148 -0
  12. package/bin/lib/alias/specifier.mjs +49 -0
  13. package/bin/lib/alias/specifier.test.mjs +85 -0
  14. package/bin/lib/alias/tsconfig.mjs +116 -0
  15. package/bin/lib/alias/typescript.mjs +23 -0
  16. package/bin/lib/icons/generate.mjs +156 -0
  17. package/bin/lib/icons/generate.test.mjs +125 -0
  18. package/bin/tempest.mjs +158 -13
  19. package/dist/audio/use-audio.cjs +1 -1
  20. package/dist/audio/use-audio.cjs.map +1 -1
  21. package/dist/audio/use-audio.js +12 -12
  22. package/dist/audio/use-audio.js.map +1 -1
  23. package/dist/charts/AreaChart.cjs +1 -1
  24. package/dist/charts/AreaChart.cjs.map +1 -1
  25. package/dist/charts/AreaChart.js +7 -7
  26. package/dist/charts/AreaChart.js.map +1 -1
  27. package/dist/charts/BarChart.cjs +1 -1
  28. package/dist/charts/BarChart.cjs.map +1 -1
  29. package/dist/charts/BarChart.js +7 -7
  30. package/dist/charts/BarChart.js.map +1 -1
  31. package/dist/charts/LineChart.cjs +1 -1
  32. package/dist/charts/LineChart.cjs.map +1 -1
  33. package/dist/charts/LineChart.js +6 -6
  34. package/dist/charts/LineChart.js.map +1 -1
  35. package/dist/charts/PieChart.cjs +1 -1
  36. package/dist/charts/PieChart.cjs.map +1 -1
  37. package/dist/charts/PieChart.js +6 -6
  38. package/dist/charts/PieChart.js.map +1 -1
  39. package/dist/charts/RadarChart.cjs +1 -1
  40. package/dist/charts/RadarChart.cjs.map +1 -1
  41. package/dist/charts/RadarChart.js +6 -6
  42. package/dist/charts/RadarChart.js.map +1 -1
  43. package/dist/charts/palette.cjs +1 -1
  44. package/dist/charts/palette.cjs.map +1 -1
  45. package/dist/charts/palette.js +19 -2
  46. package/dist/charts/palette.js.map +1 -1
  47. package/dist/charts/use-chart-colors.cjs +2 -0
  48. package/dist/charts/use-chart-colors.cjs.map +1 -0
  49. package/dist/charts/use-chart-colors.js +29 -0
  50. package/dist/charts/use-chart-colors.js.map +1 -0
  51. package/dist/charts.cjs +1 -1
  52. package/dist/charts.d.ts +61 -10
  53. package/dist/charts.js +8 -7
  54. package/dist/components/AvatarGroup/AvatarGroup.cjs +2 -0
  55. package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -0
  56. package/dist/components/AvatarGroup/AvatarGroup.js +39 -0
  57. package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -0
  58. package/dist/components/AvatarGroup/AvatarGroup.module.cjs +2 -0
  59. package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -0
  60. package/dist/components/AvatarGroup/AvatarGroup.module.js +16 -0
  61. package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -0
  62. package/dist/components/ClickOutside/ClickOutside.cjs +1 -1
  63. package/dist/components/ClickOutside/ClickOutside.cjs.map +1 -1
  64. package/dist/components/ClickOutside/ClickOutside.js +3 -1
  65. package/dist/components/ClickOutside/ClickOutside.js.map +1 -1
  66. package/dist/components/DataTable/DataTable.cjs +1 -1
  67. package/dist/components/DataTable/DataTable.cjs.map +1 -1
  68. package/dist/components/DataTable/DataTable.js +21 -23
  69. package/dist/components/DataTable/DataTable.js.map +1 -1
  70. package/dist/components/Kanban/Kanban.cjs +2 -0
  71. package/dist/components/Kanban/Kanban.cjs.map +1 -0
  72. package/dist/components/Kanban/Kanban.js +102 -0
  73. package/dist/components/Kanban/Kanban.js.map +1 -0
  74. package/dist/components/Kanban/Kanban.module.cjs +2 -0
  75. package/dist/components/Kanban/Kanban.module.cjs.map +1 -0
  76. package/dist/components/Kanban/Kanban.module.js +19 -0
  77. package/dist/components/Kanban/Kanban.module.js.map +1 -0
  78. package/dist/components/Lightbox/Lightbox.cjs +2 -0
  79. package/dist/components/Lightbox/Lightbox.cjs.map +1 -0
  80. package/dist/components/Lightbox/Lightbox.js +148 -0
  81. package/dist/components/Lightbox/Lightbox.js.map +1 -0
  82. package/dist/components/Lightbox/Lightbox.module.cjs +2 -0
  83. package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -0
  84. package/dist/components/Lightbox/Lightbox.module.js +21 -0
  85. package/dist/components/Lightbox/Lightbox.module.js.map +1 -0
  86. package/dist/components/NotificationCenter/NotificationCenter.cjs +2 -0
  87. package/dist/components/NotificationCenter/NotificationCenter.cjs.map +1 -0
  88. package/dist/components/NotificationCenter/NotificationCenter.js +83 -0
  89. package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -0
  90. package/dist/components/NotificationCenter/NotificationCenter.module.cjs +2 -0
  91. package/dist/components/NotificationCenter/NotificationCenter.module.cjs.map +1 -0
  92. package/dist/components/NotificationCenter/NotificationCenter.module.js +21 -0
  93. package/dist/components/NotificationCenter/NotificationCenter.module.js.map +1 -0
  94. package/dist/components/NotificationCenter/use-notification-inbox.cjs +2 -0
  95. package/dist/components/NotificationCenter/use-notification-inbox.cjs.map +1 -0
  96. package/dist/components/NotificationCenter/use-notification-inbox.js +63 -0
  97. package/dist/components/NotificationCenter/use-notification-inbox.js.map +1 -0
  98. package/dist/components/RefreshIndicator/RefreshIndicator.cjs +1 -1
  99. package/dist/components/RefreshIndicator/RefreshIndicator.cjs.map +1 -1
  100. package/dist/components/RefreshIndicator/RefreshIndicator.js +17 -17
  101. package/dist/components/RefreshIndicator/RefreshIndicator.js.map +1 -1
  102. package/dist/components/SignaturePad/SignaturePad.cjs +2 -0
  103. package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -0
  104. package/dist/components/SignaturePad/SignaturePad.js +115 -0
  105. package/dist/components/SignaturePad/SignaturePad.js.map +1 -0
  106. package/dist/components/SignaturePad/SignaturePad.module.cjs +2 -0
  107. package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -0
  108. package/dist/components/SignaturePad/SignaturePad.module.js +11 -0
  109. package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -0
  110. package/dist/components/Stepper/Stepper.cjs +1 -1
  111. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  112. package/dist/components/Stepper/Stepper.js +43 -19
  113. package/dist/components/Stepper/Stepper.js.map +1 -1
  114. package/dist/components/Stepper/Stepper.module.cjs +1 -1
  115. package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
  116. package/dist/components/Stepper/Stepper.module.js +6 -3
  117. package/dist/components/Stepper/Stepper.module.js.map +1 -1
  118. package/dist/components/Tooltip/Tooltip.cjs +1 -1
  119. package/dist/components/Tooltip/Tooltip.cjs.map +1 -1
  120. package/dist/components/Tooltip/Tooltip.js +26 -20
  121. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  122. package/dist/components/TreeView/TreeView.cjs +2 -0
  123. package/dist/components/TreeView/TreeView.cjs.map +1 -0
  124. package/dist/components/TreeView/TreeView.js +124 -0
  125. package/dist/components/TreeView/TreeView.js.map +1 -0
  126. package/dist/components/TreeView/TreeView.module.cjs +2 -0
  127. package/dist/components/TreeView/TreeView.module.cjs.map +1 -0
  128. package/dist/components/TreeView/TreeView.module.js +17 -0
  129. package/dist/components/TreeView/TreeView.module.js.map +1 -0
  130. package/dist/components/VirtualTable/VirtualTable.cjs +2 -0
  131. package/dist/components/VirtualTable/VirtualTable.cjs.map +1 -0
  132. package/dist/components/VirtualTable/VirtualTable.js +116 -0
  133. package/dist/components/VirtualTable/VirtualTable.js.map +1 -0
  134. package/dist/components/VirtualTable/VirtualTable.module.cjs +2 -0
  135. package/dist/components/VirtualTable/VirtualTable.module.cjs.map +1 -0
  136. package/dist/components/VirtualTable/VirtualTable.module.js +20 -0
  137. package/dist/components/VirtualTable/VirtualTable.module.js.map +1 -0
  138. package/dist/components/Wizard/Wizard.cjs +2 -0
  139. package/dist/components/Wizard/Wizard.cjs.map +1 -0
  140. package/dist/components/Wizard/Wizard.js +111 -0
  141. package/dist/components/Wizard/Wizard.js.map +1 -0
  142. package/dist/components/Wizard/Wizard.module.cjs +2 -0
  143. package/dist/components/Wizard/Wizard.module.cjs.map +1 -0
  144. package/dist/components/Wizard/Wizard.module.js +10 -0
  145. package/dist/components/Wizard/Wizard.module.js.map +1 -0
  146. package/dist/geo/use-position-tracker.cjs +1 -1
  147. package/dist/geo/use-position-tracker.cjs.map +1 -1
  148. package/dist/geo/use-position-tracker.js +3 -1
  149. package/dist/geo/use-position-tracker.js.map +1 -1
  150. package/dist/hooks/use-async.cjs +1 -1
  151. package/dist/hooks/use-async.cjs.map +1 -1
  152. package/dist/hooks/use-async.js +3 -1
  153. package/dist/hooks/use-async.js.map +1 -1
  154. package/dist/hooks/use-click-outside.cjs +1 -1
  155. package/dist/hooks/use-click-outside.cjs.map +1 -1
  156. package/dist/hooks/use-click-outside.js +3 -1
  157. package/dist/hooks/use-click-outside.js.map +1 -1
  158. package/dist/hooks/use-deep-memo.cjs.map +1 -1
  159. package/dist/hooks/use-deep-memo.js.map +1 -1
  160. package/dist/hooks/use-event-listener.cjs +1 -1
  161. package/dist/hooks/use-event-listener.cjs.map +1 -1
  162. package/dist/hooks/use-event-listener.js +3 -1
  163. package/dist/hooks/use-event-listener.js.map +1 -1
  164. package/dist/hooks/use-interval.cjs +1 -1
  165. package/dist/hooks/use-interval.cjs.map +1 -1
  166. package/dist/hooks/use-interval.js +3 -1
  167. package/dist/hooks/use-interval.js.map +1 -1
  168. package/dist/hooks/use-is-first-render.cjs.map +1 -1
  169. package/dist/hooks/use-is-first-render.js.map +1 -1
  170. package/dist/hooks/use-long-press-handlers.cjs +1 -1
  171. package/dist/hooks/use-long-press-handlers.cjs.map +1 -1
  172. package/dist/hooks/use-long-press-handlers.js +25 -23
  173. package/dist/hooks/use-long-press-handlers.js.map +1 -1
  174. package/dist/hooks/use-long-press.cjs +1 -1
  175. package/dist/hooks/use-long-press.cjs.map +1 -1
  176. package/dist/hooks/use-long-press.js +3 -1
  177. package/dist/hooks/use-long-press.js.map +1 -1
  178. package/dist/hooks/use-online.cjs +1 -1
  179. package/dist/hooks/use-online.cjs.map +1 -1
  180. package/dist/hooks/use-online.js +6 -4
  181. package/dist/hooks/use-online.js.map +1 -1
  182. package/dist/hooks/use-previous.cjs.map +1 -1
  183. package/dist/hooks/use-previous.js.map +1 -1
  184. package/dist/hooks/use-service-worker-update.cjs +1 -1
  185. package/dist/hooks/use-service-worker-update.cjs.map +1 -1
  186. package/dist/hooks/use-service-worker-update.js +3 -1
  187. package/dist/hooks/use-service-worker-update.js.map +1 -1
  188. package/dist/hooks/use-sortable.cjs +2 -0
  189. package/dist/hooks/use-sortable.cjs.map +1 -0
  190. package/dist/hooks/use-sortable.js +169 -0
  191. package/dist/hooks/use-sortable.js.map +1 -0
  192. package/dist/hooks/use-stable-callback.cjs.map +1 -1
  193. package/dist/hooks/use-stable-callback.js.map +1 -1
  194. package/dist/hooks/use-timeout.cjs +1 -1
  195. package/dist/hooks/use-timeout.cjs.map +1 -1
  196. package/dist/hooks/use-timeout.js +3 -1
  197. package/dist/hooks/use-timeout.js.map +1 -1
  198. package/dist/icons/Icon.cjs +2 -0
  199. package/dist/icons/Icon.cjs.map +1 -0
  200. package/dist/icons/Icon.js +24 -0
  201. package/dist/icons/Icon.js.map +1 -0
  202. package/dist/icons/IconProvider.cjs +2 -0
  203. package/dist/icons/IconProvider.cjs.map +1 -0
  204. package/dist/icons/IconProvider.js +24 -0
  205. package/dist/icons/IconProvider.js.map +1 -0
  206. package/dist/icons/generated/aliases.cjs +2 -0
  207. package/dist/icons/generated/aliases.cjs.map +1 -0
  208. package/dist/icons/generated/aliases.js +255 -0
  209. package/dist/icons/generated/aliases.js.map +1 -0
  210. package/dist/icons/generated/icon-names.cjs +2 -0
  211. package/dist/icons/generated/icon-names.cjs.map +1 -0
  212. package/dist/icons/generated/icon-names.js +6 -0
  213. package/dist/icons/generated/icon-names.js.map +1 -0
  214. package/dist/icons/generated/loaders.cjs +2 -0
  215. package/dist/icons/generated/loaders.cjs.map +1 -0
  216. package/dist/icons/generated/loaders.js +32 -0
  217. package/dist/icons/generated/loaders.js.map +1 -0
  218. package/dist/icons/generated/shard-a.cjs +2 -0
  219. package/dist/icons/generated/shard-a.cjs.map +1 -0
  220. package/dist/icons/generated/shard-a.js +114 -0
  221. package/dist/icons/generated/shard-a.js.map +1 -0
  222. package/dist/icons/generated/shard-b.cjs +2 -0
  223. package/dist/icons/generated/shard-b.cjs.map +1 -0
  224. package/dist/icons/generated/shard-b.js +156 -0
  225. package/dist/icons/generated/shard-b.js.map +1 -0
  226. package/dist/icons/generated/shard-c.cjs +2 -0
  227. package/dist/icons/generated/shard-c.cjs.map +1 -0
  228. package/dist/icons/generated/shard-c.js +269 -0
  229. package/dist/icons/generated/shard-c.js.map +1 -0
  230. package/dist/icons/generated/shard-d.cjs +2 -0
  231. package/dist/icons/generated/shard-d.cjs.map +1 -0
  232. package/dist/icons/generated/shard-d.js +62 -0
  233. package/dist/icons/generated/shard-d.js.map +1 -0
  234. package/dist/icons/generated/shard-e.cjs +2 -0
  235. package/dist/icons/generated/shard-e.cjs.map +1 -0
  236. package/dist/icons/generated/shard-e.js +32 -0
  237. package/dist/icons/generated/shard-e.js.map +1 -0
  238. package/dist/icons/generated/shard-f.cjs +2 -0
  239. package/dist/icons/generated/shard-f.cjs.map +1 -0
  240. package/dist/icons/generated/shard-f.js +139 -0
  241. package/dist/icons/generated/shard-f.js.map +1 -0
  242. package/dist/icons/generated/shard-g.cjs +2 -0
  243. package/dist/icons/generated/shard-g.cjs.map +1 -0
  244. package/dist/icons/generated/shard-g.js +61 -0
  245. package/dist/icons/generated/shard-g.js.map +1 -0
  246. package/dist/icons/generated/shard-h.cjs +2 -0
  247. package/dist/icons/generated/shard-h.cjs.map +1 -0
  248. package/dist/icons/generated/shard-h.js +63 -0
  249. package/dist/icons/generated/shard-h.js.map +1 -0
  250. package/dist/icons/generated/shard-i.cjs +2 -0
  251. package/dist/icons/generated/shard-i.cjs.map +1 -0
  252. package/dist/icons/generated/shard-i.js +30 -0
  253. package/dist/icons/generated/shard-i.js.map +1 -0
  254. package/dist/icons/generated/shard-j.cjs +2 -0
  255. package/dist/icons/generated/shard-j.cjs.map +1 -0
  256. package/dist/icons/generated/shard-j.js +10 -0
  257. package/dist/icons/generated/shard-j.js.map +1 -0
  258. package/dist/icons/generated/shard-k.cjs +2 -0
  259. package/dist/icons/generated/shard-k.cjs.map +1 -0
  260. package/dist/icons/generated/shard-k.js +16 -0
  261. package/dist/icons/generated/shard-k.js.map +1 -0
  262. package/dist/icons/generated/shard-l.cjs +2 -0
  263. package/dist/icons/generated/shard-l.cjs.map +1 -0
  264. package/dist/icons/generated/shard-l.js +88 -0
  265. package/dist/icons/generated/shard-l.js.map +1 -0
  266. package/dist/icons/generated/shard-m.cjs +2 -0
  267. package/dist/icons/generated/shard-m.cjs.map +1 -0
  268. package/dist/icons/generated/shard-m.js +140 -0
  269. package/dist/icons/generated/shard-m.js.map +1 -0
  270. package/dist/icons/generated/shard-n.cjs +2 -0
  271. package/dist/icons/generated/shard-n.cjs.map +1 -0
  272. package/dist/icons/generated/shard-n.js +24 -0
  273. package/dist/icons/generated/shard-n.js.map +1 -0
  274. package/dist/icons/generated/shard-o.cjs +2 -0
  275. package/dist/icons/generated/shard-o.cjs.map +1 -0
  276. package/dist/icons/generated/shard-o.js +17 -0
  277. package/dist/icons/generated/shard-o.js.map +1 -0
  278. package/dist/icons/generated/shard-p.cjs +2 -0
  279. package/dist/icons/generated/shard-p.cjs.map +1 -0
  280. package/dist/icons/generated/shard-p.js +115 -0
  281. package/dist/icons/generated/shard-p.js.map +1 -0
  282. package/dist/icons/generated/shard-q.cjs +2 -0
  283. package/dist/icons/generated/shard-q.cjs.map +1 -0
  284. package/dist/icons/generated/shard-q.js +10 -0
  285. package/dist/icons/generated/shard-q.js.map +1 -0
  286. package/dist/icons/generated/shard-r.cjs +2 -0
  287. package/dist/icons/generated/shard-r.cjs.map +1 -0
  288. package/dist/icons/generated/shard-r.js +77 -0
  289. package/dist/icons/generated/shard-r.js.map +1 -0
  290. package/dist/icons/generated/shard-s.cjs +2 -0
  291. package/dist/icons/generated/shard-s.cjs.map +1 -0
  292. package/dist/icons/generated/shard-s.js +255 -0
  293. package/dist/icons/generated/shard-s.js.map +1 -0
  294. package/dist/icons/generated/shard-t.cjs +2 -0
  295. package/dist/icons/generated/shard-t.cjs.map +1 -0
  296. package/dist/icons/generated/shard-t.js +109 -0
  297. package/dist/icons/generated/shard-t.js.map +1 -0
  298. package/dist/icons/generated/shard-u.cjs +2 -0
  299. package/dist/icons/generated/shard-u.cjs.map +1 -0
  300. package/dist/icons/generated/shard-u.js +49 -0
  301. package/dist/icons/generated/shard-u.js.map +1 -0
  302. package/dist/icons/generated/shard-v.cjs +2 -0
  303. package/dist/icons/generated/shard-v.cjs.map +1 -0
  304. package/dist/icons/generated/shard-v.js +30 -0
  305. package/dist/icons/generated/shard-v.js.map +1 -0
  306. package/dist/icons/generated/shard-w.cjs +2 -0
  307. package/dist/icons/generated/shard-w.cjs.map +1 -0
  308. package/dist/icons/generated/shard-w.js +48 -0
  309. package/dist/icons/generated/shard-w.js.map +1 -0
  310. package/dist/icons/generated/shard-x.cjs +2 -0
  311. package/dist/icons/generated/shard-x.cjs.map +1 -0
  312. package/dist/icons/generated/shard-x.js +10 -0
  313. package/dist/icons/generated/shard-x.js.map +1 -0
  314. package/dist/icons/generated/shard-z.cjs +2 -0
  315. package/dist/icons/generated/shard-z.cjs.map +1 -0
  316. package/dist/icons/generated/shard-z.js +25 -0
  317. package/dist/icons/generated/shard-z.js.map +1 -0
  318. package/dist/icons/icon-context.cjs +2 -0
  319. package/dist/icons/icon-context.cjs.map +1 -0
  320. package/dist/icons/icon-context.js +13 -0
  321. package/dist/icons/icon-context.js.map +1 -0
  322. package/dist/icons/is-icon-name.cjs +2 -0
  323. package/dist/icons/is-icon-name.cjs.map +1 -0
  324. package/dist/icons/is-icon-name.js +10 -0
  325. package/dist/icons/is-icon-name.js.map +1 -0
  326. package/dist/icons/shard-cache.cjs +2 -0
  327. package/dist/icons/shard-cache.cjs.map +1 -0
  328. package/dist/icons/shard-cache.js +41 -0
  329. package/dist/icons/shard-cache.js.map +1 -0
  330. package/dist/icons/use-icon.cjs +2 -0
  331. package/dist/icons/use-icon.cjs.map +1 -0
  332. package/dist/icons/use-icon.js +20 -0
  333. package/dist/icons/use-icon.js.map +1 -0
  334. package/dist/icons-virtual.d.ts +22 -0
  335. package/dist/icons.cjs +1 -0
  336. package/dist/icons.d.ts +220 -0
  337. package/dist/icons.js +9 -0
  338. package/dist/offline/create-offline-sync.cjs +1 -1
  339. package/dist/offline/create-offline-sync.cjs.map +1 -1
  340. package/dist/offline/create-offline-sync.js +8 -2
  341. package/dist/offline/create-offline-sync.js.map +1 -1
  342. package/dist/offline/use-offline-sync.cjs +1 -1
  343. package/dist/offline/use-offline-sync.cjs.map +1 -1
  344. package/dist/offline/use-offline-sync.js +3 -1
  345. package/dist/offline/use-offline-sync.js.map +1 -1
  346. package/dist/push/use-push-subscription.cjs +1 -1
  347. package/dist/push/use-push-subscription.cjs.map +1 -1
  348. package/dist/push/use-push-subscription.js +3 -1
  349. package/dist/push/use-push-subscription.js.map +1 -1
  350. package/dist/sse/use-event-stream.cjs +1 -1
  351. package/dist/sse/use-event-stream.cjs.map +1 -1
  352. package/dist/sse/use-event-stream.js +3 -1
  353. package/dist/sse/use-event-stream.js.map +1 -1
  354. package/dist/styles.css +1 -1
  355. package/dist/tempest-react-sdk.cjs +1 -1
  356. package/dist/tempest-react-sdk.d.ts +1187 -2
  357. package/dist/tempest-react-sdk.js +261 -246
  358. package/dist/theme/ThemeProvider.cjs +1 -1
  359. package/dist/theme/ThemeProvider.cjs.map +1 -1
  360. package/dist/theme/ThemeProvider.js +6 -2
  361. package/dist/theme/ThemeProvider.js.map +1 -1
  362. package/dist/theme/apply-theme.cjs +2 -0
  363. package/dist/theme/apply-theme.cjs.map +1 -0
  364. package/dist/theme/apply-theme.js +24 -0
  365. package/dist/theme/apply-theme.js.map +1 -0
  366. package/dist/theme/color.cjs +2 -0
  367. package/dist/theme/color.cjs.map +1 -0
  368. package/dist/theme/color.js +161 -0
  369. package/dist/theme/color.js.map +1 -0
  370. package/dist/theme/create-theme.cjs +5 -0
  371. package/dist/theme/create-theme.cjs.map +1 -0
  372. package/dist/theme/create-theme.js +141 -0
  373. package/dist/theme/create-theme.js.map +1 -0
  374. package/dist/theme/theme-presets.cjs +2 -0
  375. package/dist/theme/theme-presets.cjs.map +1 -0
  376. package/dist/theme/theme-presets.js +82 -0
  377. package/dist/theme/theme-presets.js.map +1 -0
  378. package/dist/utilities.css +432 -0
  379. package/dist/utils/compare-values.cjs +2 -0
  380. package/dist/utils/compare-values.cjs.map +1 -0
  381. package/dist/utils/compare-values.js +8 -0
  382. package/dist/utils/compare-values.js.map +1 -0
  383. package/dist/vision/use-camera-stream.cjs +1 -1
  384. package/dist/vision/use-camera-stream.cjs.map +1 -1
  385. package/dist/vision/use-camera-stream.js +3 -1
  386. package/dist/vision/use-camera-stream.js.map +1 -1
  387. package/dist/vite/create-vite-config.cjs +1 -1
  388. package/dist/vite/create-vite-config.cjs.map +1 -1
  389. package/dist/vite/create-vite-config.js +30 -22
  390. package/dist/vite/create-vite-config.js.map +1 -1
  391. package/dist/vite/tempest-icons.cjs +9 -0
  392. package/dist/vite/tempest-icons.cjs.map +1 -0
  393. package/dist/vite/tempest-icons.js +99 -0
  394. package/dist/vite/tempest-icons.js.map +1 -0
  395. package/dist/vite.cjs +1 -1
  396. package/dist/vite.d.ts +79 -0
  397. package/dist/vite.js +6 -5
  398. package/dist/ws/use-web-socket.cjs +1 -1
  399. package/dist/ws/use-web-socket.cjs.map +1 -1
  400. package/dist/ws/use-web-socket.js +3 -1
  401. package/dist/ws/use-web-socket.js.map +1 -1
  402. package/package.json +14 -4
  403. package/template/package.json +1 -1
@@ -0,0 +1,148 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { useScrollLock as t } from "../../hooks/use-scroll-lock.js";
3
+ import { useFocusTrap as n } from "../../hooks/use-focus-trap.js";
4
+ import { Portal as r } from "../Portal/Portal.js";
5
+ import i from "./Lightbox.module.js";
6
+ import { useCallback as a, useEffect as o, useRef as s, useState as c } from "react";
7
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
8
+ import { ChevronLeft as d, ChevronRight as f, X as p } from "lucide-react";
9
+ //#region src/components/Lightbox/Lightbox.tsx
10
+ function m({ items: m, open: h, index: g = 0, onIndexChange: _, onClose: v, showThumbnails: y, showCounter: b = !0, loop: x = !0, closeLabel: S = "Close", previousLabel: C = "Previous image", nextLabel: w = "Next image", className: T }) {
11
+ let E = s(null), [D, O] = c(g), k = _ !== void 0, A = k ? g : D;
12
+ n(E, h), t(h);
13
+ let j = a((e) => {
14
+ if (m.length === 0) return;
15
+ let t = x ? (e + m.length) % m.length : Math.max(0, Math.min(e, m.length - 1));
16
+ k || O(t), _?.(t);
17
+ }, [
18
+ k,
19
+ m.length,
20
+ x,
21
+ _
22
+ ]);
23
+ if (o(() => {
24
+ k || O(g);
25
+ }, [g, k]), o(() => {
26
+ if (!h) return;
27
+ function e(e) {
28
+ switch (e.key) {
29
+ case "Escape":
30
+ v();
31
+ break;
32
+ case "ArrowRight":
33
+ j(A + 1);
34
+ break;
35
+ case "ArrowLeft":
36
+ j(A - 1);
37
+ break;
38
+ case "Home":
39
+ j(0);
40
+ break;
41
+ case "End":
42
+ j(m.length - 1);
43
+ break;
44
+ default: return;
45
+ }
46
+ e.preventDefault();
47
+ }
48
+ return document.addEventListener("keydown", e), () => document.removeEventListener("keydown", e);
49
+ }, [
50
+ A,
51
+ m.length,
52
+ j,
53
+ v,
54
+ h
55
+ ]), o(() => {
56
+ if (!(!h || typeof Image > "u")) for (let e of [-1, 1]) {
57
+ let t = m[(A + e + m.length) % m.length];
58
+ if (!t) continue;
59
+ let n = new Image();
60
+ n.src = t.src;
61
+ }
62
+ }, [
63
+ A,
64
+ m,
65
+ h
66
+ ]), !h || m.length === 0) return null;
67
+ let M = m[Math.max(0, Math.min(A, m.length - 1))], N = y ?? m.length > 1, P = m.length > 1;
68
+ return /* @__PURE__ */ l(r, { children: /* @__PURE__ */ u("div", {
69
+ ref: E,
70
+ role: "dialog",
71
+ "aria-modal": "true",
72
+ "aria-label": M.alt,
73
+ className: e(i.overlay, T),
74
+ children: [
75
+ /* @__PURE__ */ u("div", {
76
+ className: i.topBar,
77
+ children: [b && P ? /* @__PURE__ */ u("span", {
78
+ className: i.counter,
79
+ children: [
80
+ A + 1,
81
+ " / ",
82
+ m.length
83
+ ]
84
+ }) : /* @__PURE__ */ l("span", {}), /* @__PURE__ */ l("button", {
85
+ type: "button",
86
+ className: i.iconButton,
87
+ "aria-label": S,
88
+ onClick: v,
89
+ children: /* @__PURE__ */ l(p, { size: 20 })
90
+ })]
91
+ }),
92
+ /* @__PURE__ */ u("div", {
93
+ className: i.stage,
94
+ children: [
95
+ P ? /* @__PURE__ */ l("button", {
96
+ type: "button",
97
+ className: e(i.iconButton, i.nav),
98
+ "aria-label": C,
99
+ disabled: !x && A === 0,
100
+ onClick: () => j(A - 1),
101
+ children: /* @__PURE__ */ l(d, { size: 24 })
102
+ }) : null,
103
+ /* @__PURE__ */ u("figure", {
104
+ className: i.figure,
105
+ children: [/* @__PURE__ */ l("img", {
106
+ src: M.src,
107
+ alt: M.alt,
108
+ className: i.image
109
+ }), M.caption ? /* @__PURE__ */ l("figcaption", {
110
+ className: i.caption,
111
+ children: M.caption
112
+ }) : null]
113
+ }),
114
+ P ? /* @__PURE__ */ l("button", {
115
+ type: "button",
116
+ className: e(i.iconButton, i.nav),
117
+ "aria-label": w,
118
+ disabled: !x && A === m.length - 1,
119
+ onClick: () => j(A + 1),
120
+ children: /* @__PURE__ */ l(f, { size: 24 })
121
+ }) : null
122
+ ]
123
+ }),
124
+ N && P ? /* @__PURE__ */ l("div", {
125
+ className: i.thumbnails,
126
+ role: "tablist",
127
+ "aria-label": M.alt,
128
+ children: m.map((t, n) => /* @__PURE__ */ l("button", {
129
+ type: "button",
130
+ role: "tab",
131
+ "aria-selected": n === A,
132
+ "aria-label": t.alt,
133
+ className: e(i.thumbnail, n === A && i.thumbnailActive),
134
+ onClick: () => j(n),
135
+ children: /* @__PURE__ */ l("img", {
136
+ src: t.thumbnail ?? t.src,
137
+ alt: "",
138
+ className: i.thumbnailImage
139
+ })
140
+ }, `${t.src}-${n}`))
141
+ }) : null
142
+ ]
143
+ }) });
144
+ }
145
+ //#endregion
146
+ export { m as Lightbox };
147
+
148
+ //# sourceMappingURL=Lightbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lightbox.js","names":[],"sources":["../../../src/components/Lightbox/Lightbox.tsx"],"sourcesContent":["import { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useFocusTrap } from \"@/hooks/use-focus-trap\";\nimport { useScrollLock } from \"@/hooks/use-scroll-lock\";\nimport { cn } from \"@/utils/cn\";\nimport { Portal } from \"../Portal\";\nimport styles from \"./Lightbox.module.css\";\n\n/** One item of the gallery. */\nexport interface LightboxItem {\n /** Full-size image URL. */\n src: string;\n /** Alt text. Required: a gallery of unlabeled images is unusable with a screen reader. */\n alt: string;\n /** Caption rendered under the image. */\n caption?: string;\n /** Thumbnail URL for the strip. Falls back to `src`. */\n thumbnail?: string;\n}\n\nexport interface LightboxProps {\n items: LightboxItem[];\n /** Whether the overlay is open. */\n open: boolean;\n /** Index shown while open. Default `0`. */\n index?: number;\n onIndexChange?: (index: number) => void;\n onClose: () => void;\n /** Renders the thumbnail strip. Default `true` when there is more than one item. */\n showThumbnails?: boolean;\n /** Renders the `3 / 12` counter. Default `true`. */\n showCounter?: boolean;\n /**\n * Wrap around at the ends. Default `true` — in a photo viewer, hitting a dead\n * end at the last image reads as a bug more often than as a boundary.\n */\n loop?: boolean;\n closeLabel?: string;\n previousLabel?: string;\n nextLabel?: string;\n className?: string;\n}\n\n/**\n * Full-screen image viewer with keyboard navigation.\n *\n * `Esc` closes, `←`/`→` walk the gallery, `Home`/`End` jump to the ends. Focus is\n * trapped inside while open and the page behind is scroll-locked, so the overlay\n * behaves like the dialog it is instead of a fancy `<div>` the keyboard can escape.\n *\n * Only the current image is mounted; neighbours are **preloaded** via `Image()` so\n * pressing `→` does not flash an empty frame.\n *\n * @example\n * ```tsx\n * const [open, setOpen] = useState(false);\n * const [index, setIndex] = useState(0);\n *\n * <Lightbox\n * open={open}\n * items={photos.map((p) => ({ src: p.url, alt: p.description }))}\n * index={index}\n * onIndexChange={setIndex}\n * onClose={() => setOpen(false)}\n * />\n * ```\n */\nexport function Lightbox({\n items,\n open,\n index = 0,\n onIndexChange,\n onClose,\n showThumbnails,\n showCounter = true,\n loop = true,\n closeLabel = \"Close\",\n previousLabel = \"Previous image\",\n nextLabel = \"Next image\",\n className,\n}: LightboxProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [internalIndex, setInternalIndex] = useState(index);\n const isControlled = onIndexChange !== undefined;\n const current = isControlled ? index : internalIndex;\n\n useFocusTrap(containerRef, open);\n useScrollLock(open);\n\n const move = useCallback(\n (next: number): void => {\n if (items.length === 0) return;\n const target = loop\n ? (next + items.length) % items.length\n : Math.max(0, Math.min(next, items.length - 1));\n if (!isControlled) setInternalIndex(target);\n onIndexChange?.(target);\n },\n [isControlled, items.length, loop, onIndexChange],\n );\n\n useEffect(() => {\n if (!isControlled) setInternalIndex(index);\n }, [index, isControlled]);\n\n useEffect(() => {\n if (!open) return;\n function onKeyDown(event: KeyboardEvent): void {\n switch (event.key) {\n case \"Escape\":\n onClose();\n break;\n case \"ArrowRight\":\n move(current + 1);\n break;\n case \"ArrowLeft\":\n move(current - 1);\n break;\n case \"Home\":\n move(0);\n break;\n case \"End\":\n move(items.length - 1);\n break;\n default:\n return;\n }\n event.preventDefault();\n }\n document.addEventListener(\"keydown\", onKeyDown);\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [current, items.length, move, onClose, open]);\n\n useEffect(() => {\n if (!open || typeof Image === \"undefined\") return;\n for (const offset of [-1, 1]) {\n const neighbour = items[(current + offset + items.length) % items.length];\n if (!neighbour) continue;\n const preload = new Image();\n preload.src = neighbour.src;\n }\n }, [current, items, open]);\n\n if (!open || items.length === 0) return null;\n\n const item = items[Math.max(0, Math.min(current, items.length - 1))];\n const withThumbnails = showThumbnails ?? items.length > 1;\n const multiple = items.length > 1;\n\n return (\n <Portal>\n <div\n ref={containerRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={item.alt}\n className={cn(styles.overlay, className)}\n >\n <div className={styles.topBar}>\n {showCounter && multiple ? (\n <span className={styles.counter}>\n {current + 1} / {items.length}\n </span>\n ) : (\n <span />\n )}\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={closeLabel}\n onClick={onClose}\n >\n <X size={20} />\n </button>\n </div>\n\n <div className={styles.stage}>\n {multiple ? (\n <button\n type=\"button\"\n className={cn(styles.iconButton, styles.nav)}\n aria-label={previousLabel}\n disabled={!loop && current === 0}\n onClick={() => move(current - 1)}\n >\n <ChevronLeft size={24} />\n </button>\n ) : null}\n\n <figure className={styles.figure}>\n <img src={item.src} alt={item.alt} className={styles.image} />\n {item.caption ? (\n <figcaption className={styles.caption}>{item.caption}</figcaption>\n ) : null}\n </figure>\n\n {multiple ? (\n <button\n type=\"button\"\n className={cn(styles.iconButton, styles.nav)}\n aria-label={nextLabel}\n disabled={!loop && current === items.length - 1}\n onClick={() => move(current + 1)}\n >\n <ChevronRight size={24} />\n </button>\n ) : null}\n </div>\n\n {withThumbnails && multiple ? (\n <div className={styles.thumbnails} role=\"tablist\" aria-label={item.alt}>\n {items.map((entry, entryIndex) => (\n <button\n key={`${entry.src}-${entryIndex}`}\n type=\"button\"\n role=\"tab\"\n aria-selected={entryIndex === current}\n aria-label={entry.alt}\n className={cn(\n styles.thumbnail,\n entryIndex === current && styles.thumbnailActive,\n )}\n onClick={() => move(entryIndex)}\n >\n <img\n src={entry.thumbnail ?? entry.src}\n alt=\"\"\n className={styles.thumbnailImage}\n />\n </button>\n ))}\n </div>\n ) : null}\n </div>\n </Portal>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=`tempest_overlay_ZZFy5`,t=`tempest_overlay-in_xSy6S`,n=`tempest_topBar_KFfyo`,r=`tempest_counter_tVBEK`,i=`tempest_iconButton_475l0`,a=`tempest_stage_MkXLd`,o=`tempest_nav_9nijD`,s=`tempest_figure_pZz5C`,c=`tempest_image_fAx-S`,l=`tempest_caption_yB3pA`,u=`tempest_thumbnails_wROsn`,d=`tempest_thumbnail_Vyp-R`,f=`tempest_thumbnailActive_ucTff`,p=`tempest_thumbnailImage_mvEYb`,m={overlay:e,overlayIn:t,topBar:n,counter:r,iconButton:i,stage:a,nav:o,figure:s,image:c,caption:l,thumbnails:u,thumbnail:d,thumbnailActive:f,thumbnailImage:p};exports.caption=l,exports.counter=r,exports.default=m,exports.figure=s,exports.iconButton=i,exports.image=c,exports.nav=o,exports.overlay=e,exports.overlayIn=t,exports.stage=a,exports.thumbnail=d,exports.thumbnailActive=f,exports.thumbnailImage=p,exports.thumbnails=u,exports.topBar=n;
2
+ //# sourceMappingURL=Lightbox.module.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lightbox.module.cjs","names":[],"sources":["../../../src/components/Lightbox/Lightbox.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n z-index: var(--tempest-z-modal);\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3);\n padding-top: max(var(--tempest-space-3), var(--tempest-safe-area-top));\n padding-bottom: max(var(--tempest-space-3), var(--tempest-safe-area-bottom));\n background-color: rgb(0 0 0 / 0.88);\n animation: overlay-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@keyframes overlay-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.topBar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n flex: 0 0 auto;\n}\n\n.counter {\n color: #ffffff;\n font-size: var(--tempest-text-sm);\n font-variant-numeric: tabular-nums;\n}\n\n.iconButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: 0;\n border-radius: var(--tempest-radius-full);\n background-color: rgb(255 255 255 / 0.12);\n color: #ffffff;\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.iconButton:hover:not(:disabled) {\n background-color: rgb(255 255 255 / 0.24);\n}\n\n.iconButton:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.iconButton:focus-visible {\n outline: var(--tempest-focus-ring-width) solid #ffffff;\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.stage {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-3);\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.nav {\n flex: 0 0 auto;\n}\n\n.figure {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n min-width: 0;\n min-height: 0;\n}\n\n.image {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: var(--tempest-radius-sm);\n}\n\n.caption {\n color: rgb(255 255 255 / 0.82);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.thumbnails {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n flex: 0 0 auto;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n padding-bottom: var(--tempest-space-1);\n}\n\n.thumbnail {\n flex: 0 0 auto;\n width: 56px;\n height: 56px;\n padding: 0;\n border: 2px solid transparent;\n border-radius: var(--tempest-radius-sm);\n background: none;\n cursor: pointer;\n opacity: 0.55;\n transition:\n opacity var(--tempest-duration-fast) var(--tempest-ease-out),\n border-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.thumbnail:hover {\n opacity: 0.85;\n}\n\n.thumbnailActive {\n opacity: 1;\n border-color: #ffffff;\n}\n\n.thumbnail:focus-visible {\n outline: var(--tempest-focus-ring-width) solid #ffffff;\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.thumbnailImage {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: calc(var(--tempest-radius-sm) - 1px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay {\n animation: none;\n }\n\n .iconButton,\n .thumbnail {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,21 @@
1
+ //#region src/components/Lightbox/Lightbox.module.css
2
+ var e = "tempest_overlay_ZZFy5", t = "tempest_overlay-in_xSy6S", n = "tempest_topBar_KFfyo", r = "tempest_counter_tVBEK", i = "tempest_iconButton_475l0", a = "tempest_stage_MkXLd", o = "tempest_nav_9nijD", s = "tempest_figure_pZz5C", c = "tempest_image_fAx-S", l = "tempest_caption_yB3pA", u = "tempest_thumbnails_wROsn", d = "tempest_thumbnail_Vyp-R", f = "tempest_thumbnailActive_ucTff", p = "tempest_thumbnailImage_mvEYb", m = {
3
+ overlay: e,
4
+ overlayIn: t,
5
+ topBar: n,
6
+ counter: r,
7
+ iconButton: i,
8
+ stage: a,
9
+ nav: o,
10
+ figure: s,
11
+ image: c,
12
+ caption: l,
13
+ thumbnails: u,
14
+ thumbnail: d,
15
+ thumbnailActive: f,
16
+ thumbnailImage: p
17
+ };
18
+ //#endregion
19
+ export { l as caption, r as counter, m as default, s as figure, i as iconButton, c as image, o as nav, e as overlay, t as overlayIn, a as stage, d as thumbnail, f as thumbnailActive, p as thumbnailImage, u as thumbnails, n as topBar };
20
+
21
+ //# sourceMappingURL=Lightbox.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Lightbox.module.js","names":[],"sources":["../../../src/components/Lightbox/Lightbox.module.css"],"sourcesContent":[".overlay {\n position: fixed;\n inset: 0;\n z-index: var(--tempest-z-modal);\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3);\n padding-top: max(var(--tempest-space-3), var(--tempest-safe-area-top));\n padding-bottom: max(var(--tempest-space-3), var(--tempest-safe-area-bottom));\n background-color: rgb(0 0 0 / 0.88);\n animation: overlay-in var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n@keyframes overlay-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.topBar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n flex: 0 0 auto;\n}\n\n.counter {\n color: #ffffff;\n font-size: var(--tempest-text-sm);\n font-variant-numeric: tabular-nums;\n}\n\n.iconButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: 0;\n border-radius: var(--tempest-radius-full);\n background-color: rgb(255 255 255 / 0.12);\n color: #ffffff;\n cursor: pointer;\n transition: background-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.iconButton:hover:not(:disabled) {\n background-color: rgb(255 255 255 / 0.24);\n}\n\n.iconButton:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.iconButton:focus-visible {\n outline: var(--tempest-focus-ring-width) solid #ffffff;\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.stage {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-3);\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.nav {\n flex: 0 0 auto;\n}\n\n.figure {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n min-width: 0;\n min-height: 0;\n}\n\n.image {\n max-width: 100%;\n max-height: 100%;\n object-fit: contain;\n border-radius: var(--tempest-radius-sm);\n}\n\n.caption {\n color: rgb(255 255 255 / 0.82);\n font-size: var(--tempest-text-sm);\n text-align: center;\n}\n\n.thumbnails {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n flex: 0 0 auto;\n overflow-x: auto;\n overscroll-behavior-x: contain;\n padding-bottom: var(--tempest-space-1);\n}\n\n.thumbnail {\n flex: 0 0 auto;\n width: 56px;\n height: 56px;\n padding: 0;\n border: 2px solid transparent;\n border-radius: var(--tempest-radius-sm);\n background: none;\n cursor: pointer;\n opacity: 0.55;\n transition:\n opacity var(--tempest-duration-fast) var(--tempest-ease-out),\n border-color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.thumbnail:hover {\n opacity: 0.85;\n}\n\n.thumbnailActive {\n opacity: 1;\n border-color: #ffffff;\n}\n\n.thumbnail:focus-visible {\n outline: var(--tempest-focus-ring-width) solid #ffffff;\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.thumbnailImage {\n width: 100%;\n height: 100%;\n object-fit: cover;\n border-radius: calc(var(--tempest-radius-sm) - 1px);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .overlay {\n animation: none;\n }\n\n .iconButton,\n .thumbnail {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ const e=require("../../utils/cn.cjs"),t=require("../Badge/Badge.cjs"),n=require("../EmptyState/EmptyState.cjs"),r=require("../../utils/relative-time.cjs"),i=require("./NotificationCenter.module.cjs");let a=require("react/jsx-runtime");function o({items:o,title:s=`Notificações`,onSelect:c,onMarkRead:l,onMarkAllRead:u,onDismiss:d,renderIcon:f,locale:p=`pt-BR`,emptyState:m,now:h,className:g,..._}){let v=o.filter(e=>!e.read).length,y=h??new Date().getTime(),b=e=>{e.read||l?.(e.id),c?.(e)},x=!!(c||l);return(0,a.jsxs)(`div`,{className:e.cn(i.default.panel,g),..._,children:[(s||u&&v>0)&&(0,a.jsxs)(`header`,{className:i.default.header,children:[s?(0,a.jsxs)(`h2`,{className:i.default.title,children:[s,v>0&&(0,a.jsx)(t.Badge,{variant:`primary`,"aria-label":`${v} não lidas`,children:v})]}):(0,a.jsx)(`span`,{}),u&&v>0&&(0,a.jsx)(`button`,{type:`button`,className:i.default.headerAction,onClick:u,children:`Marcar todas como lidas`})]}),o.length===0?m??(0,a.jsx)(n.EmptyState,{title:`Nenhuma notificação`}):(0,a.jsx)(`ul`,{className:i.default.list,children:o.map(t=>(0,a.jsxs)(`li`,{className:e.cn(i.default.item,!t.read&&i.default.unread),"aria-current":t.read?void 0:`true`,children:[f&&(0,a.jsx)(`span`,{className:i.default.icon,children:f(t)}),(0,a.jsxs)(`div`,{className:i.default.body,children:[x?(0,a.jsxs)(`button`,{type:`button`,className:i.default.trigger,onClick:()=>b(t),children:[(0,a.jsx)(`span`,{className:i.default.itemTitle,children:t.title}),t.body&&(0,a.jsx)(`span`,{className:i.default.itemBody,children:t.body})]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(`span`,{className:i.default.itemTitle,children:t.title}),t.body&&(0,a.jsx)(`span`,{className:i.default.itemBody,children:t.body})]}),(0,a.jsx)(`time`,{className:i.default.time,dateTime:new Date(t.receivedAt).toISOString(),children:r.relativeTime(t.receivedAt,{locale:p,now:y})})]}),d&&(0,a.jsx)(`button`,{type:`button`,className:i.default.dismiss,onClick:()=>d(t.id),"aria-label":`Descartar: ${t.title}`,children:`×`})]},t.id))})]})}exports.NotificationCenter=o;
2
+ //# sourceMappingURL=NotificationCenter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationCenter.cjs","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"2OA6EA,SAAgB,EAAmB,CAC/B,QACA,QAAQ,eACR,WACA,aACA,gBACA,YACA,aACA,SAAS,QACT,aACA,MACA,YACA,GAAG,GACqB,CACxB,IAAM,EAAc,EAAM,OAAQ,GAAS,CAAC,EAAK,IAAI,CAAC,CAAC,OACjD,EAAY,GAAO,IAAI,KAAK,CAAA,CAAE,QAAQ,EAStC,EAAY,GAAiC,CAC1C,EAAK,MAAM,IAAa,EAAK,EAAE,EACpC,IAAW,CAAI,CACnB,EAEM,EAAc,GAAQ,GAAY,GAExC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,CAAS,EAAG,GAAI,WAAjD,EACM,GAAU,GAAiB,EAAc,KACvC,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAA,QAAO,gBAA1B,CACK,GACG,EAAA,EAAA,KAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,eAAtB,CACK,EACA,EAAc,IACX,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CAAO,QAAQ,UAAU,aAAY,GAAG,EAAY,qBAC/C,CACE,CAAA,CAEX,KAEJ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAO,CAAA,EAEV,GAAiB,EAAc,IAC5B,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,aAClB,QAAS,WACZ,yBAEO,CAAA,CAER,IAGX,EAAM,SAAW,EACb,IAAc,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAM,qBAAuB,CAAA,GAExD,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAA,QAAO,cACjB,EAAM,IAAK,IACR,EAAA,EAAA,KAAA,CAAC,KAAD,CAEI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAC,EAAK,MAAQ,EAAA,QAAO,MAAM,EACtD,eAAe,EAAK,KAAgB,IAAA,GAAT,gBAH/B,CAKK,IAAc,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,cAAO,EAAW,CAAI,CAAQ,CAAA,GAErE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,cAAvB,CACK,GACG,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,YAAe,EAAS,CAAI,WAHhC,EAKI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,mBAAY,EAAK,KAAY,CAAA,EACpD,EAAK,OACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAW,EAAK,IAAW,CAAA,CAEnD,KAER,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,mBAAY,EAAK,KAAY,CAAA,EACpD,EAAK,OACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBAAW,EAAK,IAAW,CAAA,CAEzD,CAAA,CAAA,GAEN,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,UAAW,EAAA,QAAO,KAClB,SAAU,IAAI,KAAK,EAAK,UAAU,CAAC,CAAC,YAAY,WAE/C,EAAA,aAAa,EAAK,WAAY,CAAE,SAAQ,IAAK,CAAU,CAAC,CACvD,CAAA,CACL,IAEJ,IACG,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,YAAe,EAAU,EAAK,EAAE,EAChC,aAAY,cAAc,EAAK,iBAClC,GAEO,CAAA,CAEZ,GA5CK,EAAK,EA4CV,CACP,CACD,CAAA,CAEP,GAEb"}
@@ -0,0 +1,83 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { Badge as t } from "../Badge/Badge.js";
3
+ import { EmptyState as n } from "../EmptyState/EmptyState.js";
4
+ import { relativeTime as r } from "../../utils/relative-time.js";
5
+ import i from "./NotificationCenter.module.js";
6
+ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/components/NotificationCenter/NotificationCenter.tsx
8
+ function c({ items: c, title: l = "Notificações", onSelect: u, onMarkRead: d, onMarkAllRead: f, onDismiss: p, renderIcon: m, locale: h = "pt-BR", emptyState: g, now: _, className: v, ...y }) {
9
+ let b = c.filter((e) => !e.read).length, x = _ ?? (/* @__PURE__ */ new Date()).getTime(), S = (e) => {
10
+ e.read || d?.(e.id), u?.(e);
11
+ }, C = !!(u || d);
12
+ return /* @__PURE__ */ s("div", {
13
+ className: e(i.panel, v),
14
+ ...y,
15
+ children: [(l || f && b > 0) && /* @__PURE__ */ s("header", {
16
+ className: i.header,
17
+ children: [l ? /* @__PURE__ */ s("h2", {
18
+ className: i.title,
19
+ children: [l, b > 0 && /* @__PURE__ */ o(t, {
20
+ variant: "primary",
21
+ "aria-label": `${b} não lidas`,
22
+ children: b
23
+ })]
24
+ }) : /* @__PURE__ */ o("span", {}), f && b > 0 && /* @__PURE__ */ o("button", {
25
+ type: "button",
26
+ className: i.headerAction,
27
+ onClick: f,
28
+ children: "Marcar todas como lidas"
29
+ })]
30
+ }), c.length === 0 ? g ?? /* @__PURE__ */ o(n, { title: "Nenhuma notificação" }) : /* @__PURE__ */ o("ul", {
31
+ className: i.list,
32
+ children: c.map((t) => /* @__PURE__ */ s("li", {
33
+ className: e(i.item, !t.read && i.unread),
34
+ "aria-current": t.read ? void 0 : "true",
35
+ children: [
36
+ m && /* @__PURE__ */ o("span", {
37
+ className: i.icon,
38
+ children: m(t)
39
+ }),
40
+ /* @__PURE__ */ s("div", {
41
+ className: i.body,
42
+ children: [C ? /* @__PURE__ */ s("button", {
43
+ type: "button",
44
+ className: i.trigger,
45
+ onClick: () => S(t),
46
+ children: [/* @__PURE__ */ o("span", {
47
+ className: i.itemTitle,
48
+ children: t.title
49
+ }), t.body && /* @__PURE__ */ o("span", {
50
+ className: i.itemBody,
51
+ children: t.body
52
+ })]
53
+ }) : /* @__PURE__ */ s(a, { children: [/* @__PURE__ */ o("span", {
54
+ className: i.itemTitle,
55
+ children: t.title
56
+ }), t.body && /* @__PURE__ */ o("span", {
57
+ className: i.itemBody,
58
+ children: t.body
59
+ })] }), /* @__PURE__ */ o("time", {
60
+ className: i.time,
61
+ dateTime: new Date(t.receivedAt).toISOString(),
62
+ children: r(t.receivedAt, {
63
+ locale: h,
64
+ now: x
65
+ })
66
+ })]
67
+ }),
68
+ p && /* @__PURE__ */ o("button", {
69
+ type: "button",
70
+ className: i.dismiss,
71
+ onClick: () => p(t.id),
72
+ "aria-label": `Descartar: ${t.title}`,
73
+ children: "×"
74
+ })
75
+ ]
76
+ }, t.id))
77
+ })]
78
+ });
79
+ }
80
+ //#endregion
81
+ export { c as NotificationCenter };
82
+
83
+ //# sourceMappingURL=NotificationCenter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationCenter.js","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\nimport { relativeTime, type RelativeTimeLocale } from \"@/utils/relative-time\";\n\nimport { Badge } from \"../Badge\";\nimport { EmptyState } from \"../EmptyState\";\nimport type { NotificationItem } from \"./use-notification-inbox\";\nimport styles from \"./NotificationCenter.module.css\";\n\n/**\n * DOM attributes this component redefines.\n *\n * `title` becomes a rendered heading node instead of a tooltip string, and\n * `onSelect` becomes \"an entry was activated\" instead of the DOM text-selection\n * event. Both would be type errors if merged, and silently confusing if allowed\n * through.\n */\ntype OverriddenDomProps = \"children\" | \"title\" | \"onSelect\";\n\nexport interface NotificationCenterProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n OverriddenDomProps\n> {\n /** Entries to show. Rendered in the order given — `useNotificationInbox` sorts newest first. */\n items: readonly NotificationItem[];\n /**\n * Panel heading. Pass `null` to render the list with no header.\n *\n * Widened from the DOM `title` attribute (a `string`) on purpose: this is a\n * rendered heading, not a tooltip, so it takes a node.\n */\n title?: ReactNode;\n /** Activate an entry: click, `Enter` or `Space`. Also marks it read when `onMarkRead` is set. */\n onSelect?: (item: NotificationItem) => void;\n /** Mark one entry as read. Enables the per-item read control. */\n onMarkRead?: (id: string) => void;\n /** Mark every entry as read. Enables the header action. */\n onMarkAllRead?: () => void;\n /** Remove one entry. Enables the per-item dismiss control. */\n onDismiss?: (id: string) => void;\n /** Icon rendered at the leading edge of each row — an `<Icon name={…} />`, say. */\n renderIcon?: (item: NotificationItem) => ReactNode;\n /** Locale for the relative timestamps. Default `\"pt-BR\"`. */\n locale?: RelativeTimeLocale;\n /** Shown when `items` is empty. */\n emptyState?: ReactNode;\n /** Reference point for the relative timestamps. Default: now, at render time. */\n now?: number;\n}\n\n/**\n * Inbox panel for notifications the app has received.\n *\n * Deliberately presentational and controlled: it takes a list and emits intent.\n * Where the list comes from — an API, a service-worker push, `localStorage` — and\n * where read state is written are app decisions, and a component that assumed any\n * of them would be wrong for most apps. `useNotificationInbox` is the companion\n * that holds the state, including the service-worker bridge.\n *\n * It is also just the panel, not a popover: apps mount it inside their own\n * `Popover`, `Drawer` or route. That keeps one component from owning both the\n * inbox and a positioning strategy.\n *\n * @example\n * const inbox = useNotificationInbox();\n *\n * <Popover trigger={<Button>Notificações ({inbox.unreadCount})</Button>}>\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * onSelect={(item) => item.url && navigate(item.url)}\n * />\n * </Popover>\n */\nexport function NotificationCenter({\n items,\n title = \"Notificações\",\n onSelect,\n onMarkRead,\n onMarkAllRead,\n onDismiss,\n renderIcon,\n locale = \"pt-BR\",\n emptyState,\n now,\n className,\n ...rest\n}: NotificationCenterProps) {\n const unreadCount = items.filter((item) => !item.read).length;\n const reference = now ?? new Date().getTime();\n\n /**\n * Activate an entry.\n *\n * Reading a notification is implied by opening it, so activation marks it read\n * as well — otherwise every app would have to remember to call both, and the\n * unread badge would keep counting something the user already saw.\n */\n const activate = (item: NotificationItem): void => {\n if (!item.read) onMarkRead?.(item.id);\n onSelect?.(item);\n };\n\n const interactive = Boolean(onSelect || onMarkRead);\n\n return (\n <div className={cn(styles.panel, className)} {...rest}>\n {(title || (onMarkAllRead && unreadCount > 0)) && (\n <header className={styles.header}>\n {title ? (\n <h2 className={styles.title}>\n {title}\n {unreadCount > 0 && (\n <Badge variant=\"primary\" aria-label={`${unreadCount} não lidas`}>\n {unreadCount}\n </Badge>\n )}\n </h2>\n ) : (\n <span />\n )}\n {onMarkAllRead && unreadCount > 0 && (\n <button\n type=\"button\"\n className={styles.headerAction}\n onClick={onMarkAllRead}\n >\n Marcar todas como lidas\n </button>\n )}\n </header>\n )}\n\n {items.length === 0 ? (\n (emptyState ?? <EmptyState title=\"Nenhuma notificação\" />)\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li\n key={item.id}\n className={cn(styles.item, !item.read && styles.unread)}\n aria-current={!item.read ? \"true\" : undefined}\n >\n {renderIcon && <span className={styles.icon}>{renderIcon(item)}</span>}\n\n <div className={styles.body}>\n {interactive ? (\n <button\n type=\"button\"\n className={styles.trigger}\n onClick={() => activate(item)}\n >\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </button>\n ) : (\n <>\n <span className={styles.itemTitle}>{item.title}</span>\n {item.body && (\n <span className={styles.itemBody}>{item.body}</span>\n )}\n </>\n )}\n <time\n className={styles.time}\n dateTime={new Date(item.receivedAt).toISOString()}\n >\n {relativeTime(item.receivedAt, { locale, now: reference })}\n </time>\n </div>\n\n {onDismiss && (\n <button\n type=\"button\"\n className={styles.dismiss}\n onClick={() => onDismiss(item.id)}\n aria-label={`Descartar: ${item.title}`}\n >\n ×\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AA6EA,SAAgB,EAAmB,EAC/B,UACA,WAAQ,gBACR,aACA,eACA,kBACA,cACA,eACA,YAAS,SACT,eACA,QACA,cACA,GAAG,KACqB;CACxB,IAAM,IAAc,EAAM,QAAQ,MAAS,CAAC,EAAK,IAAI,CAAC,CAAC,QACjD,IAAY,sBAAO,IAAI,KAAK,EAAA,CAAE,QAAQ,GAStC,KAAY,MAAiC;EAE/C,AADK,EAAK,QAAM,IAAa,EAAK,EAAE,GACpC,IAAW,CAAI;CACnB,GAEM,IAAc,GAAQ,KAAY;CAExC,OACI,kBAAC,OAAD;EAAK,WAAW,EAAG,EAAO,OAAO,CAAS;EAAG,GAAI;YAAjD,EACM,KAAU,KAAiB,IAAc,MACvC,kBAAC,UAAD;GAAQ,WAAW,EAAO;aAA1B,CACK,IACG,kBAAC,MAAD;IAAI,WAAW,EAAO;cAAtB,CACK,GACA,IAAc,KACX,kBAAC,GAAD;KAAO,SAAQ;KAAU,cAAY,GAAG,EAAY;eAC/C;IACE,CAAA,CAEX;QAEJ,kBAAC,QAAD,CAAO,CAAA,GAEV,KAAiB,IAAc,KAC5B,kBAAC,UAAD;IACI,MAAK;IACL,WAAW,EAAO;IAClB,SAAS;cACZ;GAEO,CAAA,CAER;MAGX,EAAM,WAAW,IACb,KAAc,kBAAC,GAAD,EAAY,OAAM,sBAAuB,CAAA,IAExD,kBAAC,MAAD;GAAI,WAAW,EAAO;aACjB,EAAM,KAAK,MACR,kBAAC,MAAD;IAEI,WAAW,EAAG,EAAO,MAAM,CAAC,EAAK,QAAQ,EAAO,MAAM;IACtD,gBAAe,EAAK,OAAgB,KAAA,IAAT;cAH/B;KAKK,KAAc,kBAAC,QAAD;MAAM,WAAW,EAAO;gBAAO,EAAW,CAAI;KAAQ,CAAA;KAErE,kBAAC,OAAD;MAAK,WAAW,EAAO;gBAAvB,CACK,IACG,kBAAC,UAAD;OACI,MAAK;OACL,WAAW,EAAO;OAClB,eAAe,EAAS,CAAI;iBAHhC,CAKI,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAY,EAAK;OAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;QAAM,WAAW,EAAO;kBAAW,EAAK;OAAW,CAAA,CAEnD;WAER,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAY,EAAK;MAAY,CAAA,GACpD,EAAK,QACF,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAW,EAAK;MAAW,CAAA,CAEzD,EAAA,CAAA,GAEN,kBAAC,QAAD;OACI,WAAW,EAAO;OAClB,UAAU,IAAI,KAAK,EAAK,UAAU,CAAC,CAAC,YAAY;iBAE/C,EAAa,EAAK,YAAY;QAAE;QAAQ,KAAK;OAAU,CAAC;MACvD,CAAA,CACL;;KAEJ,KACG,kBAAC,UAAD;MACI,MAAK;MACL,WAAW,EAAO;MAClB,eAAe,EAAU,EAAK,EAAE;MAChC,cAAY,cAAc,EAAK;gBAClC;KAEO,CAAA;IAEZ;MA5CK,EAAK,EA4CV,CACP;EACD,CAAA,CAEP;;AAEb"}
@@ -0,0 +1,2 @@
1
+ var e=`tempest_panel_FdsVm`,t=`tempest_header_hEQNb`,n=`tempest_title_UJyzl`,r=`tempest_headerAction_A0T8e`,i=`tempest_list_Q23Lz`,a=`tempest_item_e-qev`,o=`tempest_unread_5bHa-`,s=`tempest_icon_W0eML`,c=`tempest_body_m3hfl`,l=`tempest_trigger_y7SuR`,u=`tempest_itemTitle_o7OXC`,d=`tempest_itemBody_KL7uZ`,f=`tempest_time_NLUQU`,p=`tempest_dismiss_74KRm`,m={panel:e,header:t,title:n,headerAction:r,list:i,item:a,unread:o,icon:s,body:c,trigger:l,itemTitle:u,itemBody:d,time:f,dismiss:p};exports.body=c,exports.default=m,exports.dismiss=p,exports.header=t,exports.headerAction=r,exports.icon=s,exports.item=a,exports.itemBody=d,exports.itemTitle=u,exports.list=i,exports.panel=e,exports.time=f,exports.title=n,exports.trigger=l,exports.unread=o;
2
+ //# sourceMappingURL=NotificationCenter.module.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationCenter.module.cjs","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n}\n\n.headerAction {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-primary);\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.headerAction:hover {\n text-decoration: underline;\n}\n\n.headerAction:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n border-radius: var(--tempest-radius-sm);\n}\n\n.list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-y: auto;\n}\n\n.item {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.item:last-child {\n border-bottom: none;\n}\n\n/*\n * Unread is marked by a left bar plus a tinted background, never by colour alone\n * — the distinction has to survive a monochrome display and colour blindness.\n * `aria-current` on the row carries the same information non-visually.\n */\n.item.unread {\n background-color: var(--tempest-surface);\n box-shadow: inset 3px 0 0 0 var(--tempest-primary);\n}\n\n.icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface-2, var(--tempest-surface));\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex: 1;\n min-width: 0;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The whole title/body block is one button so the hit target matches what the\n * user perceives as \"the notification\", instead of just its title text.\n */\n.trigger {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n padding: 0;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.trigger:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n border-radius: var(--tempest-radius-sm);\n}\n\n.itemTitle {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n line-height: var(--tempest-leading-snug);\n}\n\n.itemBody {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.time {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.dismiss {\n flex-shrink: 0;\n width: 1.5rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: none;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-base);\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .dismiss:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.dismiss:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n"],"mappings":""}
@@ -0,0 +1,21 @@
1
+ //#region src/components/NotificationCenter/NotificationCenter.module.css
2
+ var e = "tempest_panel_FdsVm", t = "tempest_header_hEQNb", n = "tempest_title_UJyzl", r = "tempest_headerAction_A0T8e", i = "tempest_list_Q23Lz", a = "tempest_item_e-qev", o = "tempest_unread_5bHa-", s = "tempest_icon_W0eML", c = "tempest_body_m3hfl", l = "tempest_trigger_y7SuR", u = "tempest_itemTitle_o7OXC", d = "tempest_itemBody_KL7uZ", f = "tempest_time_NLUQU", p = "tempest_dismiss_74KRm", m = {
3
+ panel: e,
4
+ header: t,
5
+ title: n,
6
+ headerAction: r,
7
+ list: i,
8
+ item: a,
9
+ unread: o,
10
+ icon: s,
11
+ body: c,
12
+ trigger: l,
13
+ itemTitle: u,
14
+ itemBody: d,
15
+ time: f,
16
+ dismiss: p
17
+ };
18
+ //#endregion
19
+ export { c as body, m as default, p as dismiss, t as header, r as headerAction, s as icon, a as item, d as itemBody, u as itemTitle, i as list, e as panel, f as time, n as title, l as trigger, o as unread };
20
+
21
+ //# sourceMappingURL=NotificationCenter.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationCenter.module.js","names":[],"sources":["../../../src/components/NotificationCenter/NotificationCenter.module.css"],"sourcesContent":[".panel {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background-color: var(--tempest-bg);\n color: var(--tempest-text);\n font-family: var(--tempest-font-sans);\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.title {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n margin: 0;\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-semibold);\n}\n\n.headerAction {\n padding: 0;\n border: none;\n background: none;\n color: var(--tempest-primary);\n font: inherit;\n font-size: var(--tempest-text-xs);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.headerAction:hover {\n text-decoration: underline;\n}\n\n.headerAction:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n border-radius: var(--tempest-radius-sm);\n}\n\n.list {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n overflow-y: auto;\n}\n\n.item {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-3);\n padding: var(--tempest-space-3) var(--tempest-space-4);\n border-bottom: 1px solid var(--tempest-border);\n}\n\n.item:last-child {\n border-bottom: none;\n}\n\n/*\n * Unread is marked by a left bar plus a tinted background, never by colour alone\n * — the distinction has to survive a monochrome display and colour blindness.\n * `aria-current` on the row carries the same information non-visually.\n */\n.item.unread {\n background-color: var(--tempest-surface);\n box-shadow: inset 3px 0 0 0 var(--tempest-primary);\n}\n\n.icon {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border-radius: var(--tempest-radius-full);\n background-color: var(--tempest-surface-2, var(--tempest-surface));\n color: var(--tempest-text-muted);\n}\n\n.body {\n display: flex;\n flex: 1;\n min-width: 0;\n flex-direction: column;\n gap: var(--tempest-space-1);\n}\n\n/*\n * The whole title/body block is one button so the hit target matches what the\n * user perceives as \"the notification\", instead of just its title text.\n */\n.trigger {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n padding: 0;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.trigger:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n border-radius: var(--tempest-radius-sm);\n}\n\n.itemTitle {\n font-size: var(--tempest-text-sm);\n font-weight: var(--tempest-weight-medium);\n line-height: var(--tempest-leading-snug);\n}\n\n.itemBody {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-sm);\n line-height: var(--tempest-leading-normal);\n}\n\n.time {\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-xs);\n}\n\n.dismiss {\n flex-shrink: 0;\n width: 1.5rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n border-radius: var(--tempest-radius-full);\n background: none;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-base);\n line-height: 1;\n cursor: pointer;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .dismiss:hover {\n background-color: var(--tempest-surface);\n color: var(--tempest-text);\n }\n}\n\n.dismiss:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ let e=require("react");function t(e,t){let n=typeof e.title==`string`?e.title:null;return n?{id:typeof e.id==`string`?e.id:`sw-${e.tag??t}-${n}`,title:n,body:typeof e.body==`string`?e.body:void 0,receivedAt:typeof e.receivedAt==`number`?e.receivedAt:new Date().getTime(),url:typeof e.url==`string`?e.url:void 0,data:e.data??void 0,read:!1}:null}function n(n={}){let{initialItems:r=[],listenToServiceWorker:i=!0,messageType:a=`tempest:notification`,limit:o=100,onChange:s}=n,[c,l]=(0,e.useState)(()=>[...r].sort((e,t)=>t.receivedAt-e.receivedAt).slice(0,o)),u=(0,e.useCallback)(e=>{l(t=>{let n=e(t);return s?.(n),n})},[s]),d=(0,e.useCallback)(e=>{u(t=>[e,...t.filter(t=>t.id!==e.id)].sort((e,t)=>t.receivedAt-e.receivedAt).slice(0,o))},[u,o]),f=(0,e.useCallback)((e,t)=>{u(n=>n.map(n=>n.id===e?{...n,read:t}:n))},[u]),p=(0,e.useCallback)(e=>f(e,!0),[f]),m=(0,e.useCallback)(e=>f(e,!1),[f]),h=(0,e.useCallback)(()=>{u(e=>e.map(e=>({...e,read:!0})))},[u]),g=(0,e.useCallback)(e=>{u(t=>t.filter(t=>t.id!==e))},[u]),_=(0,e.useCallback)(()=>u(()=>[]),[u]);return(0,e.useEffect)(()=>{if(!i||typeof navigator>`u`||!navigator.serviceWorker)return;let e=navigator.serviceWorker,n=e=>{let n=e.data;if(!n||n.type!==a)return;let r=t(n.notification??n.payload??n,0);r&&d(r)};return e.addEventListener(`message`,n),()=>e.removeEventListener(`message`,n)},[i,a,d]),{items:c,unreadCount:(0,e.useMemo)(()=>c.filter(e=>!e.read).length,[c]),add:d,markRead:p,markUnread:m,markAllRead:h,remove:g,clear:_}}exports.useNotificationInbox=n;
2
+ //# sourceMappingURL=use-notification-inbox.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-notification-inbox.cjs","names":[],"sources":["../../../src/components/NotificationCenter/use-notification-inbox.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/** One entry in the inbox. */\nexport interface NotificationItem {\n /** Stable id. Re-adding an existing id updates that entry instead of duplicating it. */\n id: string;\n title: string;\n /** Body text. Optional — a title-only notification is a legitimate shape. */\n body?: string;\n /** Epoch milliseconds. Used for ordering and for the relative timestamp. */\n receivedAt: number;\n read?: boolean;\n /** Where activating the notification should take the user. */\n url?: string;\n /** Free-form payload the app passes through, e.g. the entity it refers to. */\n data?: Record<string, unknown>;\n}\n\nexport interface UseNotificationInboxOptions {\n /** Entries the inbox starts with — typically what the API returned. */\n initialItems?: readonly NotificationItem[];\n /**\n * Listen for `message` events from the service worker and add whatever\n * arrives. Default `true`.\n *\n * This is the missing half of web push: a service worker runs outside the\n * page and cannot touch React state, so a push that arrives while the app is\n * open shows an OS notification and then vanishes as far as the UI is\n * concerned. Have the worker `postMessage` the payload and it lands here.\n */\n listenToServiceWorker?: boolean;\n /**\n * Message `type` to accept from the worker. Default `\"tempest:notification\"`.\n *\n * Filtering by type matters because the SW message channel is shared — a\n * sync-progress ping or a cache-updated notice would otherwise show up in the\n * user's inbox.\n */\n messageType?: string;\n /**\n * Cap on stored entries; the oldest are dropped past it. Default `100`.\n *\n * An inbox fed by push grows without bound otherwise, and it lives in memory.\n */\n limit?: number;\n /** Called whenever the list changes — the hook for persisting it. */\n onChange?: (items: readonly NotificationItem[]) => void;\n}\n\nexport interface UseNotificationInboxResult {\n items: NotificationItem[];\n unreadCount: number;\n /** Add an entry, or update the existing one with the same id. */\n add: (item: NotificationItem) => void;\n markRead: (id: string) => void;\n markUnread: (id: string) => void;\n markAllRead: () => void;\n remove: (id: string) => void;\n clear: () => void;\n}\n\n/** Coerce an unknown service-worker payload into an inbox entry. */\nfunction toItem(payload: Record<string, unknown>, index: number): NotificationItem | null {\n const title = typeof payload.title === \"string\" ? payload.title : null;\n if (!title) return null;\n return {\n id: typeof payload.id === \"string\" ? payload.id : `sw-${payload.tag ?? index}-${title}`,\n title,\n body: typeof payload.body === \"string\" ? payload.body : undefined,\n receivedAt:\n typeof payload.receivedAt === \"number\" ? payload.receivedAt : new Date().getTime(),\n url: typeof payload.url === \"string\" ? payload.url : undefined,\n data: (payload.data as Record<string, unknown> | undefined) ?? undefined,\n read: false,\n };\n}\n\n/**\n * Client-side inbox state for received notifications.\n *\n * Newest first, deduplicated by `id`, capped at `limit`. Pairs with\n * `NotificationCenter` for the UI and with the `push` module for the source:\n * point a service worker's `postMessage` at it and a push that arrives while the\n * app is open shows up in the inbox instead of only as an OS notification.\n *\n * Persistence is deliberately left out — where an inbox belongs (server, Dexie,\n * `localStorage`) is an app decision. Use `onChange` to write it wherever it goes,\n * and `initialItems` to read it back.\n *\n * @example\n * const inbox = useNotificationInbox({\n * initialItems: await api.notifications.list(),\n * onChange: (items) => storage.set(\"inbox\", items),\n * });\n *\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * />\n */\nexport function useNotificationInbox(\n options: UseNotificationInboxOptions = {},\n): UseNotificationInboxResult {\n const {\n initialItems = [],\n listenToServiceWorker = true,\n messageType = \"tempest:notification\",\n limit = 100,\n onChange,\n } = options;\n\n const [items, setItems] = useState<NotificationItem[]>(() =>\n [...initialItems].sort((a, b) => b.receivedAt - a.receivedAt).slice(0, limit),\n );\n\n const update = useCallback(\n (next: (current: NotificationItem[]) => NotificationItem[]) => {\n setItems((current) => {\n const result = next(current);\n onChange?.(result);\n return result;\n });\n },\n [onChange],\n );\n\n const add = useCallback(\n (item: NotificationItem) => {\n update((current) => {\n const without = current.filter((entry) => entry.id !== item.id);\n return [item, ...without]\n .sort((a, b) => b.receivedAt - a.receivedAt)\n .slice(0, limit);\n });\n },\n [update, limit],\n );\n\n const setRead = useCallback(\n (id: string, read: boolean) => {\n update((current) =>\n current.map((entry) => (entry.id === id ? { ...entry, read } : entry)),\n );\n },\n [update],\n );\n\n const markRead = useCallback((id: string) => setRead(id, true), [setRead]);\n const markUnread = useCallback((id: string) => setRead(id, false), [setRead]);\n\n const markAllRead = useCallback(() => {\n update((current) => current.map((entry) => ({ ...entry, read: true })));\n }, [update]);\n\n const remove = useCallback(\n (id: string) => {\n update((current) => current.filter((entry) => entry.id !== id));\n },\n [update],\n );\n\n const clear = useCallback(() => update(() => []), [update]);\n\n useEffect(() => {\n if (!listenToServiceWorker) return;\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) return;\n\n /**\n * Captured, not re-read in the cleanup.\n *\n * Looking `navigator.serviceWorker` up again at teardown throws if it is\n * gone by then, and the listener would leak either way — the container has\n * to be the same object the listener was added to.\n */\n const container = navigator.serviceWorker;\n\n const handler = (event: MessageEvent) => {\n const payload = event.data as Record<string, unknown> | null;\n if (!payload || payload.type !== messageType) return;\n const raw = (payload.notification ?? payload.payload ?? payload) as Record<\n string,\n unknown\n >;\n const item = toItem(raw, 0);\n if (item) add(item);\n };\n\n container.addEventListener(\"message\", handler);\n return () => container.removeEventListener(\"message\", handler);\n }, [listenToServiceWorker, messageType, add]);\n\n const unreadCount = useMemo(() => items.filter((item) => !item.read).length, [items]);\n\n return { items, unreadCount, add, markRead, markUnread, markAllRead, remove, clear };\n}\n"],"mappings":"uBA8DA,SAAS,EAAO,EAAkC,EAAwC,CACtF,IAAM,EAAQ,OAAO,EAAQ,OAAU,SAAW,EAAQ,MAAQ,KAElE,OADK,EACE,CACH,GAAI,OAAO,EAAQ,IAAO,SAAW,EAAQ,GAAK,MAAM,EAAQ,KAAO,EAAM,GAAG,IAChF,QACA,KAAM,OAAO,EAAQ,MAAS,SAAW,EAAQ,KAAO,IAAA,GACxD,WACI,OAAO,EAAQ,YAAe,SAAW,EAAQ,WAAa,IAAI,KAAK,CAAA,CAAE,QAAQ,EACrF,IAAK,OAAO,EAAQ,KAAQ,SAAW,EAAQ,IAAM,IAAA,GACrD,KAAO,EAAQ,MAAgD,IAAA,GAC/D,KAAM,EACV,EAVmB,IAWvB,CA2BA,SAAgB,EACZ,EAAuC,CAAC,EACd,CAC1B,GAAM,CACF,eAAe,CAAC,EAChB,wBAAwB,GACxB,cAAc,uBACd,QAAQ,IACR,YACA,EAEE,CAAC,EAAO,IAAA,EAAA,EAAA,SAAA,KACV,CAAC,GAAG,CAAY,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,WAAa,EAAE,UAAU,CAAC,CAAC,MAAM,EAAG,CAAK,CAChF,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAA8D,CAC3D,EAAU,GAAY,CAClB,IAAM,EAAS,EAAK,CAAO,EAE3B,OADA,IAAW,CAAM,EACV,CACX,CAAC,CACL,EACA,CAAC,CAAQ,CACb,EAEM,GAAA,EAAA,EAAA,YAAA,CACD,GAA2B,CACxB,EAAQ,GAEG,CAAC,EAAM,GADE,EAAQ,OAAQ,GAAU,EAAM,KAAO,EAAK,EAC3C,CAAO,CAAC,CACpB,MAAM,EAAG,IAAM,EAAE,WAAa,EAAE,UAAU,CAAC,CAC3C,MAAM,EAAG,CAAK,CACtB,CACL,EACA,CAAC,EAAQ,CAAK,CAClB,EAEM,GAAA,EAAA,EAAA,YAAA,EACD,EAAY,IAAkB,CAC3B,EAAQ,GACJ,EAAQ,IAAK,GAAW,EAAM,KAAO,EAAK,CAAE,GAAG,EAAO,MAAK,EAAI,CAAM,CACzE,CACJ,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAA,EAAA,YAAA,CAAwB,GAAe,EAAQ,EAAI,EAAI,EAAG,CAAC,CAAO,CAAC,EACnE,GAAA,EAAA,EAAA,YAAA,CAA0B,GAAe,EAAQ,EAAI,EAAK,EAAG,CAAC,CAAO,CAAC,EAEtE,GAAA,EAAA,EAAA,YAAA,KAAgC,CAClC,EAAQ,GAAY,EAAQ,IAAK,IAAW,CAAE,GAAG,EAAO,KAAM,EAAK,EAAE,CAAC,CAC1E,EAAG,CAAC,CAAM,CAAC,EAEL,GAAA,EAAA,EAAA,YAAA,CACD,GAAe,CACZ,EAAQ,GAAY,EAAQ,OAAQ,GAAU,EAAM,KAAO,CAAE,CAAC,CAClE,EACA,CAAC,CAAM,CACX,EAEM,GAAA,EAAA,EAAA,YAAA,KAA0B,MAAa,CAAC,CAAC,EAAG,CAAC,CAAM,CAAC,EAgC1D,OA9BA,EAAA,EAAA,UAAA,KAAgB,CAEZ,GADI,CAAC,GACD,OAAO,UAAc,KAAe,CAAC,UAAU,cAAe,OASlE,IAAM,EAAY,UAAU,cAEtB,EAAW,GAAwB,CACrC,IAAM,EAAU,EAAM,KACtB,GAAI,CAAC,GAAW,EAAQ,OAAS,EAAa,OAK9C,IAAM,EAAO,EAJA,EAAQ,cAAgB,EAAQ,SAAW,EAI/B,CAAC,EACtB,GAAM,EAAI,CAAI,CACtB,EAGA,OADA,EAAU,iBAAiB,UAAW,CAAO,MAChC,EAAU,oBAAoB,UAAW,CAAO,CACjE,EAAG,CAAC,EAAuB,EAAa,CAAG,CAAC,EAIrC,CAAE,QAAO,aAAA,EAAA,EAAA,QAAA,KAFkB,EAAM,OAAQ,GAAS,CAAC,EAAK,IAAI,CAAC,CAAC,OAAQ,CAAC,CAAK,CAEnE,EAAa,MAAK,WAAU,aAAY,cAAa,SAAQ,OAAM,CACvF"}
@@ -0,0 +1,63 @@
1
+ import { useCallback as e, useEffect as t, useMemo as n, useState as r } from "react";
2
+ //#region src/components/NotificationCenter/use-notification-inbox.ts
3
+ function i(e, t) {
4
+ let n = typeof e.title == "string" ? e.title : null;
5
+ return n ? {
6
+ id: typeof e.id == "string" ? e.id : `sw-${e.tag ?? t}-${n}`,
7
+ title: n,
8
+ body: typeof e.body == "string" ? e.body : void 0,
9
+ receivedAt: typeof e.receivedAt == "number" ? e.receivedAt : (/* @__PURE__ */ new Date()).getTime(),
10
+ url: typeof e.url == "string" ? e.url : void 0,
11
+ data: e.data ?? void 0,
12
+ read: !1
13
+ } : null;
14
+ }
15
+ function a(a = {}) {
16
+ let { initialItems: o = [], listenToServiceWorker: s = !0, messageType: c = "tempest:notification", limit: l = 100, onChange: u } = a, [d, f] = r(() => [...o].sort((e, t) => t.receivedAt - e.receivedAt).slice(0, l)), p = e((e) => {
17
+ f((t) => {
18
+ let n = e(t);
19
+ return u?.(n), n;
20
+ });
21
+ }, [u]), m = e((e) => {
22
+ p((t) => [e, ...t.filter((t) => t.id !== e.id)].sort((e, t) => t.receivedAt - e.receivedAt).slice(0, l));
23
+ }, [p, l]), h = e((e, t) => {
24
+ p((n) => n.map((n) => n.id === e ? {
25
+ ...n,
26
+ read: t
27
+ } : n));
28
+ }, [p]), g = e((e) => h(e, !0), [h]), _ = e((e) => h(e, !1), [h]), v = e(() => {
29
+ p((e) => e.map((e) => ({
30
+ ...e,
31
+ read: !0
32
+ })));
33
+ }, [p]), y = e((e) => {
34
+ p((t) => t.filter((t) => t.id !== e));
35
+ }, [p]), b = e(() => p(() => []), [p]);
36
+ return t(() => {
37
+ if (!s || typeof navigator > "u" || !navigator.serviceWorker) return;
38
+ let e = navigator.serviceWorker, t = (e) => {
39
+ let t = e.data;
40
+ if (!t || t.type !== c) return;
41
+ let n = i(t.notification ?? t.payload ?? t, 0);
42
+ n && m(n);
43
+ };
44
+ return e.addEventListener("message", t), () => e.removeEventListener("message", t);
45
+ }, [
46
+ s,
47
+ c,
48
+ m
49
+ ]), {
50
+ items: d,
51
+ unreadCount: n(() => d.filter((e) => !e.read).length, [d]),
52
+ add: m,
53
+ markRead: g,
54
+ markUnread: _,
55
+ markAllRead: v,
56
+ remove: y,
57
+ clear: b
58
+ };
59
+ }
60
+ //#endregion
61
+ export { a as useNotificationInbox };
62
+
63
+ //# sourceMappingURL=use-notification-inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-notification-inbox.js","names":[],"sources":["../../../src/components/NotificationCenter/use-notification-inbox.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from \"react\";\n\n/** One entry in the inbox. */\nexport interface NotificationItem {\n /** Stable id. Re-adding an existing id updates that entry instead of duplicating it. */\n id: string;\n title: string;\n /** Body text. Optional — a title-only notification is a legitimate shape. */\n body?: string;\n /** Epoch milliseconds. Used for ordering and for the relative timestamp. */\n receivedAt: number;\n read?: boolean;\n /** Where activating the notification should take the user. */\n url?: string;\n /** Free-form payload the app passes through, e.g. the entity it refers to. */\n data?: Record<string, unknown>;\n}\n\nexport interface UseNotificationInboxOptions {\n /** Entries the inbox starts with — typically what the API returned. */\n initialItems?: readonly NotificationItem[];\n /**\n * Listen for `message` events from the service worker and add whatever\n * arrives. Default `true`.\n *\n * This is the missing half of web push: a service worker runs outside the\n * page and cannot touch React state, so a push that arrives while the app is\n * open shows an OS notification and then vanishes as far as the UI is\n * concerned. Have the worker `postMessage` the payload and it lands here.\n */\n listenToServiceWorker?: boolean;\n /**\n * Message `type` to accept from the worker. Default `\"tempest:notification\"`.\n *\n * Filtering by type matters because the SW message channel is shared — a\n * sync-progress ping or a cache-updated notice would otherwise show up in the\n * user's inbox.\n */\n messageType?: string;\n /**\n * Cap on stored entries; the oldest are dropped past it. Default `100`.\n *\n * An inbox fed by push grows without bound otherwise, and it lives in memory.\n */\n limit?: number;\n /** Called whenever the list changes — the hook for persisting it. */\n onChange?: (items: readonly NotificationItem[]) => void;\n}\n\nexport interface UseNotificationInboxResult {\n items: NotificationItem[];\n unreadCount: number;\n /** Add an entry, or update the existing one with the same id. */\n add: (item: NotificationItem) => void;\n markRead: (id: string) => void;\n markUnread: (id: string) => void;\n markAllRead: () => void;\n remove: (id: string) => void;\n clear: () => void;\n}\n\n/** Coerce an unknown service-worker payload into an inbox entry. */\nfunction toItem(payload: Record<string, unknown>, index: number): NotificationItem | null {\n const title = typeof payload.title === \"string\" ? payload.title : null;\n if (!title) return null;\n return {\n id: typeof payload.id === \"string\" ? payload.id : `sw-${payload.tag ?? index}-${title}`,\n title,\n body: typeof payload.body === \"string\" ? payload.body : undefined,\n receivedAt:\n typeof payload.receivedAt === \"number\" ? payload.receivedAt : new Date().getTime(),\n url: typeof payload.url === \"string\" ? payload.url : undefined,\n data: (payload.data as Record<string, unknown> | undefined) ?? undefined,\n read: false,\n };\n}\n\n/**\n * Client-side inbox state for received notifications.\n *\n * Newest first, deduplicated by `id`, capped at `limit`. Pairs with\n * `NotificationCenter` for the UI and with the `push` module for the source:\n * point a service worker's `postMessage` at it and a push that arrives while the\n * app is open shows up in the inbox instead of only as an OS notification.\n *\n * Persistence is deliberately left out — where an inbox belongs (server, Dexie,\n * `localStorage`) is an app decision. Use `onChange` to write it wherever it goes,\n * and `initialItems` to read it back.\n *\n * @example\n * const inbox = useNotificationInbox({\n * initialItems: await api.notifications.list(),\n * onChange: (items) => storage.set(\"inbox\", items),\n * });\n *\n * <NotificationCenter\n * items={inbox.items}\n * onMarkRead={inbox.markRead}\n * onMarkAllRead={inbox.markAllRead}\n * onDismiss={inbox.remove}\n * />\n */\nexport function useNotificationInbox(\n options: UseNotificationInboxOptions = {},\n): UseNotificationInboxResult {\n const {\n initialItems = [],\n listenToServiceWorker = true,\n messageType = \"tempest:notification\",\n limit = 100,\n onChange,\n } = options;\n\n const [items, setItems] = useState<NotificationItem[]>(() =>\n [...initialItems].sort((a, b) => b.receivedAt - a.receivedAt).slice(0, limit),\n );\n\n const update = useCallback(\n (next: (current: NotificationItem[]) => NotificationItem[]) => {\n setItems((current) => {\n const result = next(current);\n onChange?.(result);\n return result;\n });\n },\n [onChange],\n );\n\n const add = useCallback(\n (item: NotificationItem) => {\n update((current) => {\n const without = current.filter((entry) => entry.id !== item.id);\n return [item, ...without]\n .sort((a, b) => b.receivedAt - a.receivedAt)\n .slice(0, limit);\n });\n },\n [update, limit],\n );\n\n const setRead = useCallback(\n (id: string, read: boolean) => {\n update((current) =>\n current.map((entry) => (entry.id === id ? { ...entry, read } : entry)),\n );\n },\n [update],\n );\n\n const markRead = useCallback((id: string) => setRead(id, true), [setRead]);\n const markUnread = useCallback((id: string) => setRead(id, false), [setRead]);\n\n const markAllRead = useCallback(() => {\n update((current) => current.map((entry) => ({ ...entry, read: true })));\n }, [update]);\n\n const remove = useCallback(\n (id: string) => {\n update((current) => current.filter((entry) => entry.id !== id));\n },\n [update],\n );\n\n const clear = useCallback(() => update(() => []), [update]);\n\n useEffect(() => {\n if (!listenToServiceWorker) return;\n if (typeof navigator === \"undefined\" || !navigator.serviceWorker) return;\n\n /**\n * Captured, not re-read in the cleanup.\n *\n * Looking `navigator.serviceWorker` up again at teardown throws if it is\n * gone by then, and the listener would leak either way — the container has\n * to be the same object the listener was added to.\n */\n const container = navigator.serviceWorker;\n\n const handler = (event: MessageEvent) => {\n const payload = event.data as Record<string, unknown> | null;\n if (!payload || payload.type !== messageType) return;\n const raw = (payload.notification ?? payload.payload ?? payload) as Record<\n string,\n unknown\n >;\n const item = toItem(raw, 0);\n if (item) add(item);\n };\n\n container.addEventListener(\"message\", handler);\n return () => container.removeEventListener(\"message\", handler);\n }, [listenToServiceWorker, messageType, add]);\n\n const unreadCount = useMemo(() => items.filter((item) => !item.read).length, [items]);\n\n return { items, unreadCount, add, markRead, markUnread, markAllRead, remove, clear };\n}\n"],"mappings":";;AA8DA,SAAS,EAAO,GAAkC,GAAwC;CACtF,IAAM,IAAQ,OAAO,EAAQ,SAAU,WAAW,EAAQ,QAAQ;CAElE,OADK,IACE;EACH,IAAI,OAAO,EAAQ,MAAO,WAAW,EAAQ,KAAK,MAAM,EAAQ,OAAO,EAAM,GAAG;EAChF;EACA,MAAM,OAAO,EAAQ,QAAS,WAAW,EAAQ,OAAO,KAAA;EACxD,YACI,OAAO,EAAQ,cAAe,WAAW,EAAQ,8BAAa,IAAI,KAAK,EAAA,CAAE,QAAQ;EACrF,KAAK,OAAO,EAAQ,OAAQ,WAAW,EAAQ,MAAM,KAAA;EACrD,MAAO,EAAQ,QAAgD,KAAA;EAC/D,MAAM;CACV,IAVmB;AAWvB;AA2BA,SAAgB,EACZ,IAAuC,CAAC,GACd;CAC1B,IAAM,EACF,kBAAe,CAAC,GAChB,2BAAwB,IACxB,iBAAc,wBACd,WAAQ,KACR,gBACA,GAEE,CAAC,GAAO,KAAY,QACtB,CAAC,GAAG,CAAY,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,MAAM,GAAG,CAAK,CAChF,GAEM,IAAS,GACV,MAA8D;EAC3D,GAAU,MAAY;GAClB,IAAM,IAAS,EAAK,CAAO;GAE3B,OADA,IAAW,CAAM,GACV;EACX,CAAC;CACL,GACA,CAAC,CAAQ,CACb,GAEM,IAAM,GACP,MAA2B;EACxB,GAAQ,MAEG,CAAC,GAAM,GADE,EAAQ,QAAQ,MAAU,EAAM,OAAO,EAAK,EAC3C,CAAO,CAAC,CACpB,MAAM,GAAG,MAAM,EAAE,aAAa,EAAE,UAAU,CAAC,CAC3C,MAAM,GAAG,CAAK,CACtB;CACL,GACA,CAAC,GAAQ,CAAK,CAClB,GAEM,IAAU,GACX,GAAY,MAAkB;EAC3B,GAAQ,MACJ,EAAQ,KAAK,MAAW,EAAM,OAAO,IAAK;GAAE,GAAG;GAAO;EAAK,IAAI,CAAM,CACzE;CACJ,GACA,CAAC,CAAM,CACX,GAEM,IAAW,GAAa,MAAe,EAAQ,GAAI,EAAI,GAAG,CAAC,CAAO,CAAC,GACnE,IAAa,GAAa,MAAe,EAAQ,GAAI,EAAK,GAAG,CAAC,CAAO,CAAC,GAEtE,IAAc,QAAkB;EAClC,GAAQ,MAAY,EAAQ,KAAK,OAAW;GAAE,GAAG;GAAO,MAAM;EAAK,EAAE,CAAC;CAC1E,GAAG,CAAC,CAAM,CAAC,GAEL,IAAS,GACV,MAAe;EACZ,GAAQ,MAAY,EAAQ,QAAQ,MAAU,EAAM,OAAO,CAAE,CAAC;CAClE,GACA,CAAC,CAAM,CACX,GAEM,IAAQ,QAAkB,QAAa,CAAC,CAAC,GAAG,CAAC,CAAM,CAAC;CAgC1D,OA9BA,QAAgB;EAEZ,IADI,CAAC,KACD,OAAO,YAAc,OAAe,CAAC,UAAU,eAAe;EASlE,IAAM,IAAY,UAAU,eAEtB,KAAW,MAAwB;GACrC,IAAM,IAAU,EAAM;GACtB,IAAI,CAAC,KAAW,EAAQ,SAAS,GAAa;GAK9C,IAAM,IAAO,EAJA,EAAQ,gBAAgB,EAAQ,WAAW,GAI/B,CAAC;GAC1B,AAAI,KAAM,EAAI,CAAI;EACtB;EAGA,OADA,EAAU,iBAAiB,WAAW,CAAO,SAChC,EAAU,oBAAoB,WAAW,CAAO;CACjE,GAAG;EAAC;EAAuB;EAAa;CAAG,CAAC,GAIrC;EAAE;EAAO,aAFI,QAAc,EAAM,QAAQ,MAAS,CAAC,EAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAK,CAEnE;EAAa;EAAK;EAAU;EAAY;EAAa;EAAQ;CAAM;AACvF"}
@@ -1,2 +1,2 @@
1
- const e=require("../../utils/cn.cjs"),t=require("../Spinner/Spinner.cjs"),n=require("./RefreshIndicator.module.cjs");let r=require("react"),i=require("react/jsx-runtime");function a(e,t){let n=t*1.5;return Math.min(e/2,n)}function o({onRefresh:o,children:s,threshold:c=80,disabled:l,className:u}){let d=(0,r.useRef)(null),f=(0,r.useRef)(null),[p,m]=(0,r.useState)(0),[h,g]=(0,r.useState)(!1),_=f.current!==null,v=e=>{if(l||h)return;let t=d.current;if(!t||t.scrollTop>0)return;let n=e.touches[0];n&&(f.current=n.clientY)},y=e=>{if(l||h)return;let t=f.current;if(t===null)return;let n=e.touches[0];if(!n)return;let r=n.clientY-t;if(r<=0){m(0);return}m(a(r,c))},b=()=>{f.current=null,m(0)},x=async()=>{if(l||h){b();return}if(!(f.current!==null&&p>=c)){b();return}f.current=null,g(!0),m(c);try{await o()}finally{g(!1),m(0)}},S=h||p>0,C=Math.min(1,p/c);return(0,i.jsxs)(`div`,{ref:d,className:e.cn(n.default.wrapper,u),"data-refreshing":h,onTouchStart:v,onTouchMove:y,onTouchEnd:x,children:[(0,i.jsx)(`div`,{className:n.default.indicator,"aria-hidden":!S,style:{opacity:h?1:C,transform:`translateX(-50%) translateY(${S?p:0}px) rotate(${C*360}deg)`},children:(0,i.jsx)(t.Spinner,{size:`sm`,label:`Atualizando`})}),(0,i.jsx)(`div`,{className:e.cn(n.default.content,(_||h)&&n.default.dragging),style:{transform:`translateY(${S?p:0}px)`},children:s})]})}exports.RefreshIndicator=o;
1
+ const e=require("../../utils/cn.cjs"),t=require("../Spinner/Spinner.cjs"),n=require("./RefreshIndicator.module.cjs");let r=require("react"),i=require("react/jsx-runtime");function a(e,t){let n=t*1.5;return Math.min(e/2,n)}function o({onRefresh:o,children:s,threshold:c=80,disabled:l,className:u}){let d=(0,r.useRef)(null),f=(0,r.useRef)(null),[p,m]=(0,r.useState)(0),[h,g]=(0,r.useState)(!1),[_,v]=(0,r.useState)(!1),y=e=>{if(l||h)return;let t=d.current;if(!t||t.scrollTop>0)return;let n=e.touches[0];n&&(f.current=n.clientY,v(!0))},b=e=>{if(l||h)return;let t=f.current;if(t===null)return;let n=e.touches[0];if(!n)return;let r=n.clientY-t;if(r<=0){m(0);return}m(a(r,c))},x=()=>{f.current=null,v(!1),m(0)},S=async()=>{if(l||h){x();return}if(!(f.current!==null&&p>=c)){x();return}f.current=null,v(!1),g(!0),m(c);try{await o()}finally{g(!1),m(0)}},C=h||p>0,w=Math.min(1,p/c);return(0,i.jsxs)(`div`,{ref:d,className:e.cn(n.default.wrapper,u),"data-refreshing":h,onTouchStart:y,onTouchMove:b,onTouchEnd:S,children:[(0,i.jsx)(`div`,{className:n.default.indicator,"aria-hidden":!C,style:{opacity:h?1:w,transform:`translateX(-50%) translateY(${C?p:0}px) rotate(${w*360}deg)`},children:(0,i.jsx)(t.Spinner,{size:`sm`,label:`Atualizando`})}),(0,i.jsx)(`div`,{className:e.cn(n.default.content,(_||h)&&n.default.dragging),style:{transform:`translateY(${C?p:0}px)`},children:s})]})}exports.RefreshIndicator=o;
2
2
  //# sourceMappingURL=RefreshIndicator.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"RefreshIndicator.cjs","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["import { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n\n const engaged = startYRef.current !== null;\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"2KAkBA,SAAS,EAAgB,EAAkB,EAA2B,CAClE,IAAM,EAAM,EAAY,IACxB,OAAO,KAAK,IAAI,EAAW,EAAG,CAAG,CACrC,CASA,SAAgB,EAAiB,CAC7B,YACA,WACA,YAAY,GACZ,WACA,aACsB,CACtB,IAAM,GAAA,EAAA,EAAA,OAAA,CAAsC,IAAI,EAC1C,GAAA,EAAA,EAAA,OAAA,CAAkC,IAAI,EACtC,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAoB,CAAC,EAC5B,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAA0B,EAAK,EAE5C,EAAU,EAAU,UAAY,KAEhC,EAAoB,GAA4C,CAClE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,GAAa,EAAU,UAAY,EAAG,OAC3C,IAAM,EAAQ,EAAM,QAAQ,GACvB,IACL,EAAU,QAAU,EAAM,QAC9B,EAEM,EAAmB,GAA4C,CACjE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAS,EAAU,QACzB,GAAI,IAAW,KAAM,OACrB,IAAM,EAAQ,EAAM,QAAQ,GAC5B,GAAI,CAAC,EAAO,OACZ,IAAM,EAAQ,EAAM,QAAU,EAC9B,GAAI,GAAS,EAAG,CACZ,EAAQ,CAAC,EACT,MACJ,CACA,EAAQ,EAAgB,EAAO,CAAS,CAAC,CAC7C,EAEM,MAAoB,CACtB,EAAU,QAAU,KACpB,EAAQ,CAAC,CACb,EAEM,EAAiB,SAA2B,CAC9C,GAAI,GAAY,EAAY,CACxB,EAAM,EACN,MACJ,CAGA,GAAI,EAFW,EAAU,UACI,MAAQ,GAAQ,GAC7B,CACZ,EAAM,EACN,MACJ,CACA,EAAU,QAAU,KACpB,EAAc,EAAI,EAClB,EAAQ,CAAS,EACjB,GAAI,CACA,MAAM,EAAU,CACpB,QAAU,CACN,EAAc,EAAK,EACnB,EAAQ,CAAC,CACb,CACJ,EAEM,EAAgB,GAAc,EAAO,EACrC,EAAW,KAAK,IAAI,EAAG,EAAO,CAAS,EAE7C,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EACvC,kBAAiB,EACjB,aAAc,EACd,YAAa,EACb,WAAY,WANhB,EAQI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,UAClB,cAAa,CAAC,EACd,MAAO,CACH,QAAS,EAAa,EAAI,EAC1B,UAAW,+BAA+B,EAAgB,EAAO,EAAE,aAAa,EAAW,IAAI,KACnG,YAEA,EAAA,EAAA,IAAA,CAAC,EAAA,QAAD,CAAS,KAAK,KAAK,MAAM,aAAe,CAAA,CACvC,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAW,IAAe,EAAA,QAAO,QAAQ,EACxE,MAAO,CAAE,UAAW,cAAc,EAAgB,EAAO,EAAE,IAAK,EAE/D,UACA,CAAA,CACJ,GAEb"}
1
+ {"version":3,"file":"RefreshIndicator.cjs","names":[],"sources":["../../../src/components/RefreshIndicator/RefreshIndicator.tsx"],"sourcesContent":["import { useRef, useState, type ReactNode, type TouchEvent } from \"react\";\nimport { Spinner } from \"@/components/Spinner\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./RefreshIndicator.module.css\";\n\nexport interface RefreshIndicatorProps {\n /** Invoked when the user pulls past `threshold` and releases. May be async. */\n onRefresh: () => void | Promise<void>;\n /** Scrollable content to wrap. */\n children: ReactNode;\n /** Pixels the user must pull past to trigger a refresh. Defaults to `80`. */\n threshold?: number;\n /** When true, pull-to-refresh is inert. */\n disabled?: boolean;\n className?: string;\n}\n\n/** Apply resistance so the content lags behind the finger and the pull never runs away. */\nfunction applyResistance(distance: number, threshold: number): number {\n const cap = threshold * 1.5;\n return Math.min(distance / 2, cap);\n}\n\n/**\n * RefreshIndicator — pull-to-refresh wrapper for touch devices.\n *\n * Wraps scrollable `children` and listens for a downward drag that starts while the\n * container is scrolled to the top. Pulling past `threshold` and releasing triggers\n * `onRefresh`; the SDK {@link Spinner} is shown while pulling and during the refresh.\n */\nexport function RefreshIndicator({\n onRefresh,\n children,\n threshold = 80,\n disabled,\n className,\n}: RefreshIndicatorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const startYRef = useRef<number | null>(null);\n const [pull, setPull] = useState(0);\n const [refreshing, setRefreshing] = useState(false);\n /**\n * Whether a drag is in progress. Kept in state, not derived from\n * `startYRef.current`: a ref is not reactive, so reading it during render ties\n * the rendered class to a value React never re-renders for — it only looked\n * correct here because the touch handlers happen to call `setPull` too.\n */\n const [engaged, setEngaged] = useState(false);\n\n const handleTouchStart = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const container = containerRef.current;\n if (!container || container.scrollTop > 0) return;\n const touch = event.touches[0];\n if (!touch) return;\n startYRef.current = touch.clientY;\n setEngaged(true);\n };\n\n const handleTouchMove = (event: TouchEvent<HTMLDivElement>): void => {\n if (disabled || refreshing) return;\n const startY = startYRef.current;\n if (startY === null) return;\n const touch = event.touches[0];\n if (!touch) return;\n const delta = touch.clientY - startY;\n if (delta <= 0) {\n setPull(0);\n return;\n }\n setPull(applyResistance(delta, threshold));\n };\n\n const reset = (): void => {\n startYRef.current = null;\n setEngaged(false);\n setPull(0);\n };\n\n const handleTouchEnd = async (): Promise<void> => {\n if (disabled || refreshing) {\n reset();\n return;\n }\n const startY = startYRef.current;\n const triggered = startY !== null && pull >= threshold;\n if (!triggered) {\n reset();\n return;\n }\n startYRef.current = null;\n setEngaged(false);\n setRefreshing(true);\n setPull(threshold);\n try {\n await onRefresh();\n } finally {\n setRefreshing(false);\n setPull(0);\n }\n };\n\n const showIndicator = refreshing || pull > 0;\n const progress = Math.min(1, pull / threshold);\n\n return (\n <div\n ref={containerRef}\n className={cn(styles.wrapper, className)}\n data-refreshing={refreshing}\n onTouchStart={handleTouchStart}\n onTouchMove={handleTouchMove}\n onTouchEnd={handleTouchEnd}\n >\n <div\n className={styles.indicator}\n aria-hidden={!showIndicator}\n style={{\n opacity: refreshing ? 1 : progress,\n transform: `translateX(-50%) translateY(${showIndicator ? pull : 0}px) rotate(${progress * 360}deg)`,\n }}\n >\n <Spinner size=\"sm\" label=\"Atualizando\" />\n </div>\n <div\n className={cn(styles.content, (engaged || refreshing) && styles.dragging)}\n style={{ transform: `translateY(${showIndicator ? pull : 0}px)` }}\n >\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":"2KAkBA,SAAS,EAAgB,EAAkB,EAA2B,CAClE,IAAM,EAAM,EAAY,IACxB,OAAO,KAAK,IAAI,EAAW,EAAG,CAAG,CACrC,CASA,SAAgB,EAAiB,CAC7B,YACA,WACA,YAAY,GACZ,WACA,aACsB,CACtB,IAAM,GAAA,EAAA,EAAA,OAAA,CAAsC,IAAI,EAC1C,GAAA,EAAA,EAAA,OAAA,CAAkC,IAAI,EACtC,CAAC,EAAM,IAAA,EAAA,EAAA,SAAA,CAAoB,CAAC,EAC5B,CAAC,EAAY,IAAA,EAAA,EAAA,SAAA,CAA0B,EAAK,EAO5C,CAAC,EAAS,IAAA,EAAA,EAAA,SAAA,CAAuB,EAAK,EAEtC,EAAoB,GAA4C,CAClE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,GAAa,EAAU,UAAY,EAAG,OAC3C,IAAM,EAAQ,EAAM,QAAQ,GACvB,IACL,EAAU,QAAU,EAAM,QAC1B,EAAW,EAAI,EACnB,EAEM,EAAmB,GAA4C,CACjE,GAAI,GAAY,EAAY,OAC5B,IAAM,EAAS,EAAU,QACzB,GAAI,IAAW,KAAM,OACrB,IAAM,EAAQ,EAAM,QAAQ,GAC5B,GAAI,CAAC,EAAO,OACZ,IAAM,EAAQ,EAAM,QAAU,EAC9B,GAAI,GAAS,EAAG,CACZ,EAAQ,CAAC,EACT,MACJ,CACA,EAAQ,EAAgB,EAAO,CAAS,CAAC,CAC7C,EAEM,MAAoB,CACtB,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAQ,CAAC,CACb,EAEM,EAAiB,SAA2B,CAC9C,GAAI,GAAY,EAAY,CACxB,EAAM,EACN,MACJ,CAGA,GAAI,EAFW,EAAU,UACI,MAAQ,GAAQ,GAC7B,CACZ,EAAM,EACN,MACJ,CACA,EAAU,QAAU,KACpB,EAAW,EAAK,EAChB,EAAc,EAAI,EAClB,EAAQ,CAAS,EACjB,GAAI,CACA,MAAM,EAAU,CACpB,QAAU,CACN,EAAc,EAAK,EACnB,EAAQ,CAAC,CACb,CACJ,EAEM,EAAgB,GAAc,EAAO,EACrC,EAAW,KAAK,IAAI,EAAG,EAAO,CAAS,EAE7C,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,IAAK,EACL,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EACvC,kBAAiB,EACjB,aAAc,EACd,YAAa,EACb,WAAY,WANhB,EAQI,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,UAClB,cAAa,CAAC,EACd,MAAO,CACH,QAAS,EAAa,EAAI,EAC1B,UAAW,+BAA+B,EAAgB,EAAO,EAAE,aAAa,EAAW,IAAI,KACnG,YAEA,EAAA,EAAA,IAAA,CAAC,EAAA,QAAD,CAAS,KAAK,KAAK,MAAM,aAAe,CAAA,CACvC,CAAA,GACL,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,SAAU,GAAW,IAAe,EAAA,QAAO,QAAQ,EACxE,MAAO,CAAE,UAAW,cAAc,EAAgB,EAAO,EAAE,IAAK,EAE/D,UACA,CAAA,CACJ,GAEb"}